diff --git a/src/main/java/org/saturnclient/modules/ModManager.java b/src/main/java/org/saturnclient/modules/ModManager.java index 13bd833..ba44238 100644 --- a/src/main/java/org/saturnclient/modules/ModManager.java +++ b/src/main/java/org/saturnclient/modules/ModManager.java @@ -22,7 +22,8 @@ public class ModManager { new DayCounter(), new Speedometer(), new Zoom(), - new HealthDisplay() + new HealthDisplay(), + new Nametags() }; public static void init() { diff --git a/src/main/java/org/saturnclient/modules/mods/Nametags.java b/src/main/java/org/saturnclient/modules/mods/Nametags.java new file mode 100644 index 0000000..e15bb8a --- /dev/null +++ b/src/main/java/org/saturnclient/modules/mods/Nametags.java @@ -0,0 +1,54 @@ +package org.saturnclient.modules.mods; + +import org.saturnclient.modules.Module; +import org.saturnclient.modules.ModuleDetails; +import org.saturnclient.modules.mods.utils.HealthRenderState; +import org.saturnclient.saturnclient.config.Property; + +import net.minecraft.client.render.entity.state.LivingEntityRenderState; + +public class Nametags extends Module { + private static Property enabled = Property.bool(false); + private static Property healthDisplay = Property.bool(false); + + public Nametags() { + super( + new ModuleDetails("Nametags", "zoom") + .description("Allows you to modify entity nametags") + .tags("Camera", "Utility") + .version("0.1.0"), + enabled.named("Enabled"), + healthDisplay.named("Display health") + ); + } + + @Override + public void tick() { + + } + + + public static String getNametagString(LivingEntityRenderState state) { + if (state.customName == null) return null; + if (!healthDisplay.value) return state.customName.getString(); // name only + if (!(state instanceof HealthRenderState hrs)) return null; + + return state.customName.getString() + + " §c" + String.format("%.1f", hrs.saturn$getHealth()) + + " / " + String.format("%.1f", hrs.saturn$getMaxHealth()) + " ❤"; + } + + public static boolean shouldReplaceName() { + return enabled.value; + } + + @Override + public void onEnabled(boolean e) { + enabled.value = e; + } + + @Override + public boolean isEnabled() { + return enabled.value; + } +} diff --git a/src/main/java/org/saturnclient/modules/mods/mixins/LivingEntityRenderStateMixin.java b/src/main/java/org/saturnclient/modules/mods/mixins/LivingEntityRenderStateMixin.java new file mode 100644 index 0000000..24e842d --- /dev/null +++ b/src/main/java/org/saturnclient/modules/mods/mixins/LivingEntityRenderStateMixin.java @@ -0,0 +1,19 @@ +package org.saturnclient.modules.mods.mixins; + +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(LivingEntityRenderState.class) +public class LivingEntityRenderStateMixin implements org.saturnclient.modules.mods.utils.HealthRenderState { + + @Unique private float saturn$health = 0f; + @Unique private float saturn$maxHealth = 1f; + + @Override public float saturn$getHealth() { return saturn$health; } + @Override public float saturn$getMaxHealth() { return saturn$maxHealth; } + @Override public void saturn$setHealth(float health, float maxHealth) { + this.saturn$health = health; + this.saturn$maxHealth = maxHealth; + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/modules/mods/mixins/LivingEntityRendererMixin.java b/src/main/java/org/saturnclient/modules/mods/mixins/LivingEntityRendererMixin.java new file mode 100644 index 0000000..9551d00 --- /dev/null +++ b/src/main/java/org/saturnclient/modules/mods/mixins/LivingEntityRendererMixin.java @@ -0,0 +1,21 @@ +package org.saturnclient.modules.mods.mixins; + +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import net.minecraft.entity.LivingEntity; +import org.saturnclient.modules.mods.utils.HealthRenderState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(LivingEntityRenderer.class) +public abstract class LivingEntityRendererMixin { + + @Inject(method = "updateRenderState", at = @At("TAIL")) + private void saturn$captureHealth(T entity, S state, float tickDelta, CallbackInfo ci) { + if (state instanceof HealthRenderState hrs) { + hrs.saturn$setHealth(entity.getHealth(), entity.getMaxHealth()); + } + } +} diff --git a/src/main/java/org/saturnclient/modules/mods/mixins/NametagsMixin.java b/src/main/java/org/saturnclient/modules/mods/mixins/NametagsMixin.java new file mode 100644 index 0000000..be17d91 --- /dev/null +++ b/src/main/java/org/saturnclient/modules/mods/mixins/NametagsMixin.java @@ -0,0 +1,48 @@ +package org.saturnclient.modules.mods.mixins; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import org.saturnclient.modules.mods.Nametags; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityRenderer.class) +public abstract class NametagsMixin { + + @Unique + private static final ThreadLocal saturn$rendering = ThreadLocal.withInitial(() -> false); + + @Shadow + protected abstract void renderLabelIfPresent( + S state, Text text, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light + ); + + @Inject(method = "renderLabelIfPresent", at = @At("HEAD"), cancellable = true) + private void saturn$replaceNametag(S state, Text text, + MatrixStack matrices, VertexConsumerProvider vertexConsumers, + int light, CallbackInfo ci) { + + if (saturn$rendering.get()) return; + if (!Nametags.shouldReplaceName()) return; + if (!(state instanceof LivingEntityRenderState living)) return; + + String replacement = Nametags.getNametagString(living); + if (replacement == null) return; + + ci.cancel(); + saturn$rendering.set(true); + try { + renderLabelIfPresent(state, Text.literal(replacement), matrices, vertexConsumers, light); + } finally { + saturn$rendering.set(false); + } + } +} diff --git a/src/main/java/org/saturnclient/modules/mods/utils/HealthRenderState.java b/src/main/java/org/saturnclient/modules/mods/utils/HealthRenderState.java new file mode 100644 index 0000000..1912170 --- /dev/null +++ b/src/main/java/org/saturnclient/modules/mods/utils/HealthRenderState.java @@ -0,0 +1,7 @@ +package org.saturnclient.modules.mods.utils; + +public interface HealthRenderState { + float saturn$getHealth(); + float saturn$getMaxHealth(); + void saturn$setHealth(float health, float maxHealth); +} diff --git a/src/main/resources/mods.mixins.json b/src/main/resources/mods.mixins.json index fea0c0c..0fd1f99 100644 --- a/src/main/resources/mods.mixins.json +++ b/src/main/resources/mods.mixins.json @@ -9,7 +9,10 @@ "RenderMixin", "LightmapTextureManagerMixin", "BackgroundRendererMixin", - "GameRendererMixin" + "GameRendererMixin", + "NametagsMixin", + "LivingEntityRenderStateMixin", + "LivingEntityRendererMixin" ], "injectors": { "defaultRequire": 1