diff --git a/Fabric/src/main/java/vazkii/neat/NeatFiberConfig.java b/Fabric/src/main/java/vazkii/neat/NeatFiberConfig.java index 08b81ca..55cf6ba 100644 --- a/Fabric/src/main/java/vazkii/neat/NeatFiberConfig.java +++ b/Fabric/src/main/java/vazkii/neat/NeatFiberConfig.java @@ -81,6 +81,10 @@ private static class Client implements NeatConfig.ConfigAccess { private final PropertyMirror enableDebugInfo = PropertyMirror.create(BOOLEAN); private final PropertyMirror showEntityName = PropertyMirror.create(BOOLEAN); private final PropertyMirror disableNameTag = PropertyMirror.create(BOOLEAN); + private final PropertyMirror disableNameTagIfHealthbar = PropertyMirror.create(BOOLEAN); + private final PropertyMirror iconOffsetX = PropertyMirror.create(DOUBLE); + private final PropertyMirror iconOffsetY = PropertyMirror.create(DOUBLE); + private final PropertyMirror decimalFormat = PropertyMirror.create(STRING); private final PropertyMirror> blacklist = PropertyMirror.create(ConfigTypes.makeList(STRING)); public ConfigTree configure(ConfigTreeBuilder builder) { @@ -97,7 +101,7 @@ public ConfigTree configure(ConfigTreeBuilder builder) { .finishValue(renderInF1::mirror) .beginValue("heightAbove", DOUBLE, 0.6) - .withComment("How far above the mob health bars should render") + .withComment("How far above the mob the health bars should render") .finishValue(heightAbove::mirror) .beginValue("drawBackground", BOOLEAN, true) @@ -137,7 +141,7 @@ public ConfigTree configure(ConfigTreeBuilder builder) { .finishValue(groupArmor::mirror) .beginValue("colorByType", BOOLEAN, false) - .withComment("Color the bar differently depending on whether the entity is hostile or is a boss") + .withComment("Color health bar by mob type instead of health percentage") .finishValue(colorByType::mirror) .beginValue("textColor", STRING, "FFFFFF") @@ -196,6 +200,22 @@ public ConfigTree configure(ConfigTreeBuilder builder) { .withComment("Disables the rendering of the vanilla name tag") .finishValue(disableNameTag::mirror) + .beginValue("disableNameTagIfHealthbar", BOOLEAN, true) + .withComment("If this is enabled and the \"disableNameTag\" option is true, the vanilla nametag is only hidden if the mob has a Neat healthbar rendered") + .finishValue(disableNameTagIfHealthbar::mirror) + + .beginValue("iconOffsetX", DOUBLE, 0.0) + .withComment("Offsets the healtbar icons on the x axis") + .finishValue(iconOffsetX::mirror) + + .beginValue("iconOffsetY", DOUBLE, 0.0) + .withComment("Offsets the healtbar icons on the y axis") + .finishValue(iconOffsetY::mirror) + + .beginValue("decimalFormat", STRING, "#.##") + .withComment("This value changes the decimal format of the HP. Only change this value if you are familiar with how the decimal format works!") + .finishValue(decimalFormat::mirror) + .beginValue("blacklist", ConfigTypes.makeList(STRING), NeatConfig.DEFAULT_DISABLED) .withComment("Entity ID's that should not have bars rendered") .finishValue(blacklist::mirror); @@ -343,6 +363,26 @@ public boolean disableNameTag() { return disableNameTag.getValue(); } + @Override + public boolean disableNameTagIfHealthbar() { + return disableNameTagIfHealthbar.getValue(); + } + + @Override + public double iconOffsetX() { + return iconOffsetX.getValue(); + } + + @Override + public double iconOffsetY() { + return iconOffsetY.getValue(); + } + + @Override + public String decimalFormat() { + return decimalFormat.getValue(); + } + @Override public List blacklist() { return blacklist.getValue(); diff --git a/NeoForge/src/main/java/vazkii/neat/NeatNeoForgeConfig.java b/NeoForge/src/main/java/vazkii/neat/NeatNeoForgeConfig.java index 10d5dc1..46f168a 100644 --- a/NeoForge/src/main/java/vazkii/neat/NeatNeoForgeConfig.java +++ b/NeoForge/src/main/java/vazkii/neat/NeatNeoForgeConfig.java @@ -43,40 +43,48 @@ private static class ForgeNeatConfig implements NeatConfig.ConfigAccess { private final ModConfigSpec.ConfigValue showFullHealth; private final ModConfigSpec.ConfigValue showEntityName; private final ModConfigSpec.ConfigValue disableNameTag; + private final ModConfigSpec.ConfigValue disableNameTagIfHealthbar; + private final ModConfigSpec.ConfigValue iconOffsetX; + private final ModConfigSpec.ConfigValue iconOffsetY; + private final ModConfigSpec.ConfigValue decimalFormat; private final ModConfigSpec.ConfigValue enableDebugInfo; private final ModConfigSpec.ConfigValue> blacklist; public ForgeNeatConfig(ModConfigSpec.Builder builder) { builder.push("general"); - maxDistance = builder.define("max_distance", 24); - maxDistanceWithoutLineOfSight = builder.define("max_distance_without_line_of_sight", 8); - renderInF1 = builder.comment("Render if F1 is pressed").define("render_without_gui", false); - heightAbove = builder.define("height_above_mob", 0.6); - drawBackground = builder.define("draw_background", true); - backgroundPadding = builder.define("background_padding", 2); - backgroundHeight = builder.define("background_height", 6); - barHeight = builder.define("health_bar_height", 4); - plateSize = builder.define("plate_size", 25); - plateSizeBoss = builder.define("plate_size_boss", 50); - showAttributes = builder.define("show_attributes", true); - showArmor = builder.define("show_armor", true); - groupArmor = builder.comment("Condense 5 iron icons into 1 diamond icon").define("group_armor", true); - colorByType = builder.comment("Color health bar by type instead of health percentage").define("color_health_bar_by_type", false); + maxDistance = builder.comment("Maximum distance in blocks at which health bars should render").define("max_distance", 24); + maxDistanceWithoutLineOfSight = builder.comment("Maximum distance in blocks at which health bars should render without line of sight").define("max_distance_without_line_of_sight", 8); + renderInF1 = builder.comment("Whether health bars should render when the HUD is disabled with F1").define("render_without_gui", false); + heightAbove = builder.comment("How far above the mob the health bars should render").define("height_above_mob", 0.6); + drawBackground = builder.comment("Whether the gray background plate should be drawn").define("draw_background", true); + backgroundPadding = builder.comment("Amount of extra padding space around the background plate").define("background_padding", 2); + backgroundHeight = builder.comment("How tall the background plate should be").define("background_height", 6); + barHeight = builder.comment("How tall the health bar should be").define("health_bar_height", 4); + plateSize = builder.comment("How wide the health bar should be. If the entity has a long name, the bar will increase in size to match it.").define("plate_size", 25); + plateSizeBoss = builder.comment("plateSize but for bosses").define("plate_size_boss", 50); + showAttributes = builder.comment("Show mob attributes such as arthropod or undead").define("show_attributes", true); + showArmor = builder.comment("Show armor points").define("show_armor", true); + groupArmor = builder.comment("Group 5 iron icons into 1 diamond icon").define("group_armor", true); + colorByType = builder.comment("Color health bar by mob type instead of health percentage").define("color_health_bar_by_type", false); textColor = builder.comment("Text color in hex code format").define("text_color", "FFFFFF"); - hpTextHeight = builder.define("hp_text_height", 14); - showMaxHP = builder.define("show_max_hp", true); - showCurrentHP = builder.define("show_current_hp", true); - showPercentage = builder.define("show_hp_percentage", true); + hpTextHeight = builder.comment("Height of the text on the health bar").define("hp_text_height", 14); + showMaxHP = builder.comment("Whether the maximum health of the mob should be shown").define("show_max_hp", true); + showCurrentHP = builder.comment("Whether the current health of the mob should be shown").define("show_current_hp", true); + showPercentage = builder.comment("Whether the percentage health of the mob should be shown").define("show_hp_percentage", true); showOnPassive = builder.comment("Whether bars on passive mobs should be shown").define("show_on_passive", true); showOnHostile = builder.comment("Whether bars on hostile mobs should be shown (does not include bosses)").define("show_on_hostile", true); - showOnPlayers = builder.define("display_on_players", true); - showOnBosses = builder.define("display_on_bosses", true); - showOnlyFocused = builder.define("only_health_bar_for_target", false); - showFullHealth = builder.define("show_entity_full_health", true); - enableDebugInfo = builder.define("show_debug_with_f3", true); - showEntityName = builder.define("show_entity_name", true); + showOnPlayers = builder.comment("Whether bars on players should be shown").define("display_on_players", true); + showOnBosses = builder.comment("Whether bars on bosses should be shown").define("display_on_bosses", true); + showOnlyFocused = builder.comment("Only show bars for mobs you are targeting").define("only_health_bar_for_target", false); + showFullHealth = builder.comment("Show bars for mobs that are at full health").define("show_entity_full_health", true); + enableDebugInfo = builder.comment("Show extra debug info on the bar when F3 is enabled").define("show_debug_with_f3", true); + showEntityName = builder.comment("Show entity name").define("show_entity_name", true); disableNameTag = builder.comment("Disables the rendering of the vanilla name tag").define("disable_name_tag", false); + disableNameTagIfHealthbar = builder.comment("If this is enabled and the \"disableNameTag\" option is true, the vanilla nametag is only hidden if the mob has a Neat healthbar rendered").define("disable_name_tag_if_healthbar", true); + iconOffsetX = builder.comment("Offsets the healtbar icons on the x axis").define("icon_offset_x", 0.0); + iconOffsetY = builder.comment("Offsets the healtbar icons on the y axis").define("icon_offset_y", 0.0); + decimalFormat = builder.comment("This value changes the decimal format of the HP. Only change this value if you are familiar with how the decimal format works!").define("decimal_format", "#.##"); blacklist = builder.comment("Blacklist uses entity IDs, not their display names. Use F3 to see them in the Neat bar.") .defineList("blacklist", NeatConfig.DEFAULT_DISABLED, a -> true); @@ -223,6 +231,26 @@ public boolean disableNameTag() { return disableNameTag.get(); } + @Override + public boolean disableNameTagIfHealthbar() { + return disableNameTagIfHealthbar.get(); + } + + @Override + public double iconOffsetX() { + return iconOffsetX.get(); + } + + @Override + public double iconOffsetY() { + return iconOffsetY.get(); + } + + @Override + public String decimalFormat() { + return decimalFormat.get(); + } + @SuppressWarnings("unchecked") @Override public List blacklist() { diff --git a/Xplat/src/main/java/vazkii/neat/HealthBarRenderer.java b/Xplat/src/main/java/vazkii/neat/HealthBarRenderer.java index 9621fd4..e82efa7 100644 --- a/Xplat/src/main/java/vazkii/neat/HealthBarRenderer.java +++ b/Xplat/src/main/java/vazkii/neat/HealthBarRenderer.java @@ -34,7 +34,6 @@ import java.util.*; public class HealthBarRenderer { - private static final DecimalFormat HEALTH_FORMAT = new DecimalFormat("#.##"); private static Entity getEntityLookedAt(Entity e) { Entity foundEntity = null; @@ -128,7 +127,7 @@ private static int getColor(LivingEntity entity, boolean colorByType, boolean bo private static final TagKey> BOSS_TAG = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath("c", "bosses")); - private static boolean isBoss(Entity entity) { + public static boolean isBoss(Entity entity) { return entity.getType().is(BOSS_TAG); } @@ -310,13 +309,14 @@ public static void hookRender(Entity entity, PoseStack poseStack, MultiBufferSou poseStack.scale(healthValueTextScale, healthValueTextScale, healthValueTextScale); int h = NeatConfig.instance.hpTextHeight(); + DecimalFormat health_format = new DecimalFormat(NeatConfig.instance.decimalFormat()); if (NeatConfig.instance.showCurrentHP()) { - String hpStr = HEALTH_FORMAT.format(living.getHealth()); + String hpStr = health_format.format(living.getHealth()); mc.font.drawInBatch(hpStr, 2, h, textColor, false, poseStack.last().pose(), buffers, Font.DisplayMode.NORMAL, black, light); } if (NeatConfig.instance.showMaxHP()) { - String maxHpStr = ChatFormatting.BOLD + HEALTH_FORMAT.format(living.getMaxHealth()); + String maxHpStr = ChatFormatting.BOLD + health_format.format(living.getMaxHealth()); mc.font.drawInBatch(maxHpStr, (int) (halfSize / healthValueTextScale * 2) - mc.font.width(maxHpStr) - 2, h, textColor, false, poseStack.last().pose(), buffers, Font.DisplayMode.NORMAL, black, light); } if (NeatConfig.instance.showPercentage()) { @@ -388,11 +388,11 @@ private static void renderIcon(Level level, ItemStack icon, PoseStack poseStack, // halfSize and co. are units operating under the assumption of globalScale, // but in the icon rendering section we don't use globalScale, so we need // to manually multiply it in to ensure the units line up. - float dx = (halfSize - leftShift) * globalScale; - float dy = 3F * globalScale; - float dz = zShift * globalScale; + double dx = (halfSize - leftShift) * globalScale + NeatConfig.instance.iconOffsetX(); + double dy = 3F * globalScale; + double dz = zShift * globalScale; // Need to negate X due to our rotation below - poseStack.translate(-dx, dy, dz); + poseStack.translate(-dx, dy + NeatConfig.instance.iconOffsetY(), dz); poseStack.scale(iconScale, iconScale, iconScale); poseStack.mulPose(Axis.YP.rotationDegrees(180F)); Minecraft.getInstance().getItemRenderer() diff --git a/Xplat/src/main/java/vazkii/neat/NeatConfig.java b/Xplat/src/main/java/vazkii/neat/NeatConfig.java index fe39fd6..5d05417 100644 --- a/Xplat/src/main/java/vazkii/neat/NeatConfig.java +++ b/Xplat/src/main/java/vazkii/neat/NeatConfig.java @@ -36,6 +36,10 @@ public interface ConfigAccess { boolean enableDebugInfo(); boolean showEntityName(); boolean disableNameTag(); + boolean disableNameTagIfHealthbar(); + double iconOffsetX(); + double iconOffsetY(); + String decimalFormat(); List blacklist(); } diff --git a/Xplat/src/main/java/vazkii/neat/ToggleKeybind.java b/Xplat/src/main/java/vazkii/neat/ToggleKeybind.java index 3e3c096..ec5eacc 100644 --- a/Xplat/src/main/java/vazkii/neat/ToggleKeybind.java +++ b/Xplat/src/main/java/vazkii/neat/ToggleKeybind.java @@ -6,7 +6,7 @@ public class ToggleKeybind { - public static final KeyMapping KEY = new KeyMapping("neat.keybind.toggle", GLFW.GLFW_KEY_UNKNOWN, "key.categories.misc");; + public static final KeyMapping KEY = new KeyMapping("neat.keybind.toggle", GLFW.GLFW_KEY_UNKNOWN, "key.categories.misc"); public static void handle() { while (KEY.consumeClick()) { diff --git a/Xplat/src/main/java/vazkii/neat/mixin/EntityRendererMixin.java b/Xplat/src/main/java/vazkii/neat/mixin/EntityRendererMixin.java index 3a8f707..daf36e9 100644 --- a/Xplat/src/main/java/vazkii/neat/mixin/EntityRendererMixin.java +++ b/Xplat/src/main/java/vazkii/neat/mixin/EntityRendererMixin.java @@ -4,22 +4,44 @@ import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; import org.spongepowered.asm.mixin.Mixin; +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; +import vazkii.neat.HealthBarRenderer; import vazkii.neat.NeatConfig; @Mixin(EntityRenderer.class) public class EntityRendererMixin { @Inject(method = "render(Lnet/minecraft/world/entity/Entity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/entity/EntityRenderer;renderNameTag(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/network/chat/Component;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IF)V"), cancellable = true) - private void neat_disableNameTag(Entity $$0, float $$1, float $$2, PoseStack $$3, MultiBufferSource $$4, int $$5, CallbackInfo ci) { - if (NeatConfig.instance.disableNameTag()) { + private void neat_disableNameTag(Entity entity, float $$1, float $$2, PoseStack $$3, MultiBufferSource $$4, int $$5, CallbackInfo ci) { + if (NeatConfig.instance.disableNameTag() && (!NeatConfig.instance.disableNameTagIfHealthbar() || neat$allowNameTagDisable(entity))) { ci.cancel(); } } + + @Unique + public boolean neat$allowNameTagDisable(Entity entity) { + if (!(entity instanceof LivingEntity)) + return false; + if (entity instanceof Player && !NeatConfig.instance.showOnPlayers()) + return false; + if (HealthBarRenderer.isBoss(entity) && !NeatConfig.instance.showOnBosses()) + return false; + if (entity.getType().getCategory().isFriendly() && !NeatConfig.instance.showOnPassive()) + return false; + if ((!entity.getType().getCategory().isFriendly() && !HealthBarRenderer.isBoss(entity)) && !NeatConfig.instance.showOnHostile()) + return false; + + var id = BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()); + return !NeatConfig.instance.blacklist().contains(id.toString()) && NeatConfig.draw; + } } diff --git a/Xplat/src/main/resources/assets/neat/lang/en_us.json b/Xplat/src/main/resources/assets/neat/lang/en_us.json index 502d6c7..a071d40 100644 --- a/Xplat/src/main/resources/assets/neat/lang/en_us.json +++ b/Xplat/src/main/resources/assets/neat/lang/en_us.json @@ -23,5 +23,15 @@ "neat.configuration.show_attributes": "Show Attributes", "neat.configuration.color_health_bar_by_type": "Color Health Bar by Type", "neat.configuration.show_current_hp": "Show Current HP", + "neat.configuration.disable_name_tag": "Disable Name Tag", + "neat.configuration.show_on_hostile": "Show on Hostile", + "neat.configuration.text_color": "Text Color", + "neat.configuration.disable_name_tag_if_healthbar": "Disable Name Tag if Healthbar rendered", + "neat.configuration.max_distance_without_line_of_sight": "Max distance without LOS", + "neat.configuration.show_entity_name": "Show Entity Name", + "neat.configuration.icon_offset_y": "Icon Offset Y", + "neat.configuration.decimal_format": "Decimal Format", + "neat.configuration.show_on_passive": "Show on Passive", + "neat.configuration.icon_offset_x": "Icon Offset X", "neat.configuration.blacklist": "Blacklist" }