track active effects on other players via synced effect particles

Accessor mixins expose LivingEntity's DATA_EFFECT_PARTICLES and
ColorParticleOption's color; DamageSyncTracker maps the synced colors
to resistance/slowness/strength (turtle master = resistance + slowness)
for the nametag effect icons.
This commit is contained in:
froslanz
2026-10-24 19:14:07 -04:00
parent eed627a677
commit 291a9da53f
4 changed files with 86 additions and 0 deletions
@@ -0,0 +1,12 @@
package cc.fros.mixin.entity;
import net.minecraft.core.particles.ColorParticleOption;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ColorParticleOption.class)
public interface ColorParticleOptionAccessor {
@Accessor("color")
int fros$getColor();
}
@@ -0,0 +1,18 @@
package cc.fros.mixin.entity;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.world.entity.LivingEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(LivingEntity.class)
public interface LivingEntityEffectParticlesAccessor {
@Accessor("DATA_EFFECT_PARTICLES")
static EntityDataAccessor<List<ParticleOptions>> fros$getDataEffectParticles() {
throw new AssertionError();
}
}
@@ -0,0 +1,54 @@
package cc.fros.util;
import cc.fros.mixin.entity.ColorParticleOptionAccessor;
import cc.fros.mixin.entity.LivingEntityEffectParticlesAccessor;
import net.minecraft.core.particles.ColorParticleOption;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.LivingEntity;
import java.util.List;
/**
* Detects active effects on other players from the effect particle data the
* server syncs with them, ported from homovore's {@code DamageSyncTracker}.
*/
public final class DamageSyncTracker {
private DamageSyncTracker() {
throw new AssertionError();
}
private static final int RESISTANCE_COLOR = MobEffects.RESISTANCE.value().getColor() & 0xFFFFFF;
private static final int SLOWNESS_COLOR = MobEffects.SLOWNESS.value().getColor() & 0xFFFFFF;
private static final int STRENGTH_COLOR = MobEffects.STRENGTH.value().getColor() & 0xFFFFFF;
private static boolean hasEffectColor(LivingEntity entity, int rgb) {
List<ParticleOptions> particles = entity.getEntityData()
.get(LivingEntityEffectParticlesAccessor.fros$getDataEffectParticles());
if (particles.isEmpty()) return false;
for (int i = 0, n = particles.size(); i < n; i++) {
if (particles.get(i) instanceof ColorParticleOption color
&& (((ColorParticleOptionAccessor) (Object) color).fros$getColor() & 0xFFFFFF) == rgb) {
return true;
}
}
return false;
}
public static boolean hasResistance(LivingEntity entity) {
return hasEffectColor(entity, RESISTANCE_COLOR);
}
public static boolean hasSlowness(LivingEntity entity) {
return hasEffectColor(entity, SLOWNESS_COLOR);
}
public static boolean hasStrength(LivingEntity entity) {
return hasEffectColor(entity, STRENGTH_COLOR);
}
public static boolean isTurtleMaster(LivingEntity entity) {
return hasResistance(entity) && hasSlowness(entity);
}
}
+2
View File
@@ -7,6 +7,8 @@
"network.MixinConnection"
],
"client": [
"entity.ColorParticleOptionAccessor",
"entity.LivingEntityEffectParticlesAccessor",
"entity.MixinAbstractClientPlayer",
"entity.MixinClientPlayerEntity",
"input.MixinKeyboardHandler",