diff --git a/common/src/main/java/io/github/axolotlclient/DolphinClientConfigCommon.java b/common/src/main/java/io/github/axolotlclient/DolphinClientConfigCommon.java index 95ac132f6..1aa21b5f5 100644 --- a/common/src/main/java/io/github/axolotlclient/DolphinClientConfigCommon.java +++ b/common/src/main/java/io/github/axolotlclient/DolphinClientConfigCommon.java @@ -69,6 +69,7 @@ public boolean showButton() { // options public final BooleanOption showOwnNametag = new BooleanOption("showOwnNametag", false); + public final BooleanOption alwaysRenderNametags = new BooleanOption("alwaysRenderNametags", false); public final BooleanOption useShadows = new BooleanOption("useShadows", false); public final BooleanOption nametagBackground = new BooleanOption("nametagBackground", true); @@ -127,6 +128,7 @@ public DolphinClientConfigCommon() { rendering.add(nametagOptions); nametagOptions.add(showOwnNametag); + nametagOptions.add(alwaysRenderNametags); nametagOptions.add(useShadows); nametagOptions.add(nametagBackground); diff --git a/common/src/main/java/io/github/axolotlclient/util/NametagRendering.java b/common/src/main/java/io/github/axolotlclient/util/NametagRendering.java new file mode 100644 index 000000000..0fe0de4ad --- /dev/null +++ b/common/src/main/java/io/github/axolotlclient/util/NametagRendering.java @@ -0,0 +1,40 @@ +/* + * Copyright © 2026 DSNS + * + * This file is part of DolphinClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.util; + +/** + * Helpers for nametag rendering options. + */ +public final class NametagRendering { + private NametagRendering() { + } + + /** + * Vanilla only draws custom-name nametags when {@code entity} is the + * crosshair target. When {@code alwaysRender} is true, substitute the + * entity itself so that comparison succeeds without looking at it. + */ + public static T lookTarget(T crosshairTarget, T entity, boolean alwaysRender) { + return alwaysRender ? entity : crosshairTarget; + } +} diff --git a/common/src/main/resources/assets/dolphinclient/lang/en_us.json b/common/src/main/resources/assets/dolphinclient/lang/en_us.json index a1dbde6f5..0d8daaa1d 100644 --- a/common/src/main/resources/assets/dolphinclient/lang/en_us.json +++ b/common/src/main/resources/assets/dolphinclient/lang/en_us.json @@ -65,6 +65,8 @@ "allocated": "Allocated", "alwaysCrit": "Always Show", "alwaysCrit.tooltip": "Whether to always emit these particles when hitting.", + "alwaysRenderNametags": "Always Render Name Tags", + "alwaysRenderNametags.tooltip": "Renders entity name tags even when you aren't looking at them.", "alwaysShowHeadLayer": "Always Show Hat Layer", "anchorpoint": "Anchor Point", "applyBlend": "Apply Blending", diff --git a/common/src/test/java/io/github/axolotlclient/util/NametagRenderingTest.java b/common/src/test/java/io/github/axolotlclient/util/NametagRenderingTest.java new file mode 100644 index 000000000..6e25c2745 --- /dev/null +++ b/common/src/test/java/io/github/axolotlclient/util/NametagRenderingTest.java @@ -0,0 +1,65 @@ +/* + * Copyright © 2026 DSNS + * + * This file is part of DolphinClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.util; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class NametagRenderingTest { + + private static final Object PLAYER = new Object(); + private static final Object MOB = new Object(); + + @Test + void usesCrosshairTargetWhenDisabled() { + assertSame(PLAYER, NametagRendering.lookTarget(PLAYER, MOB, false)); + } + + @Test + void treatsEntityAsLookedAtWhenEnabled() { + assertSame(MOB, NametagRendering.lookTarget(PLAYER, MOB, true)); + } + + @Test + void keepsMatchWhenAlreadyLookingAtEntity() { + assertSame(MOB, NametagRendering.lookTarget(MOB, MOB, false)); + assertSame(MOB, NametagRendering.lookTarget(MOB, MOB, true)); + } + + @Test + void langDefinesAlwaysRenderNametagsOption() throws Exception { + try (InputStream in = NametagRendering.class.getResourceAsStream("/assets/dolphinclient/lang/en_us.json")) { + assertNotNull(in, "en_us.json should be on the classpath"); + String json = new String(in.readAllBytes(), StandardCharsets.UTF_8); + assertTrue(json.contains("\"alwaysRenderNametags\": \"Always Render Name Tags\"")); + assertTrue(json.contains("\"alwaysRenderNametags.tooltip\"")); + assertTrue(json.contains("looking")); + } + } +} diff --git a/versions/1.8.9/src/main/java/io/github/axolotlclient/mixin/ItemFrameRendererMixin.java b/versions/1.8.9/src/main/java/io/github/axolotlclient/mixin/ItemFrameRendererMixin.java new file mode 100644 index 000000000..351efdbce --- /dev/null +++ b/versions/1.8.9/src/main/java/io/github/axolotlclient/mixin/ItemFrameRendererMixin.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2026 DSNS + * + * This file is part of DolphinClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.DolphinClient; +import io.github.axolotlclient.util.NametagRendering; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.ItemFrameRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.decoration.ItemFrameEntity; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(ItemFrameRenderer.class) +public class ItemFrameRendererMixin { + + @WrapOperation(method = "renderNameTag(Lnet/minecraft/entity/decoration/ItemFrameEntity;DDD)V", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/render/entity/EntityRenderDispatcher;targetEntity:Lnet/minecraft/entity/Entity;")) + private Entity axolotlclient$alwaysRenderNametags(EntityRenderDispatcher instance, Operation original, ItemFrameEntity entity) { + return NametagRendering.lookTarget(original.call(instance), entity, DolphinClient.config().alwaysRenderNametags.get()); + } +} diff --git a/versions/1.8.9/src/main/java/io/github/axolotlclient/mixin/MobRendererMixin.java b/versions/1.8.9/src/main/java/io/github/axolotlclient/mixin/MobRendererMixin.java new file mode 100644 index 000000000..5d1b61611 --- /dev/null +++ b/versions/1.8.9/src/main/java/io/github/axolotlclient/mixin/MobRendererMixin.java @@ -0,0 +1,44 @@ +/* + * Copyright © 2026 DSNS + * + * This file is part of DolphinClient. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * For more information, see the LICENSE file. + */ + +package io.github.axolotlclient.mixin; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import io.github.axolotlclient.DolphinClient; +import io.github.axolotlclient.util.NametagRendering; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.MobRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.entity.living.mob.MobEntity; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(MobRenderer.class) +public class MobRendererMixin { + + @WrapOperation(method = "shouldRenderNameTag(Lnet/minecraft/entity/living/mob/MobEntity;)Z", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/client/render/entity/EntityRenderDispatcher;targetEntity:Lnet/minecraft/entity/Entity;")) + private Entity axolotlclient$alwaysRenderNametags(EntityRenderDispatcher instance, Operation original, MobEntity entity) { + return NametagRendering.lookTarget(original.call(instance), entity, DolphinClient.config().alwaysRenderNametags.get()); + } +} diff --git a/versions/1.8.9/src/main/resources/axolotlclient.mixins.json b/versions/1.8.9/src/main/resources/axolotlclient.mixins.json index b5575b66e..1073fc35a 100644 --- a/versions/1.8.9/src/main/resources/axolotlclient.mixins.json +++ b/versions/1.8.9/src/main/resources/axolotlclient.mixins.json @@ -35,6 +35,7 @@ "InGameHudMixin", "ItemEntityMixin", "ItemEntityRendererMixin", + "ItemFrameRendererMixin", "KeyBindAccessor", "KeyBindingMixin", "KeyboardInputMixin", @@ -44,6 +45,7 @@ "LocalRemoteClientPlayerEntityMixin", "MinecraftClientAccessor", "MinecraftClientMixin", + "MobRendererMixin", "ParticleAccessor", "ParticleManagerMixin", "PlayerEntityMixin",