diff --git a/build.gradle b/build.gradle index fcc7c11..db5acfe 100644 --- a/build.gradle +++ b/build.gradle @@ -14,21 +14,16 @@ archivesBaseName = project.archives_base_name version = project.mod_version group = project.maven_group +def ENV = System.getenv() + repositories { + maven { url 'https://jitpack.io'} + maven { url "https://maven.architectury.dev/" } maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } - maven { - url 'https://jitpack.io' - } - maven { - name = "TomTheGeek-repo" - url = "https://maven.tomthegeek.ml/releases/" - } } -def ENV = System.getenv() - dependencies { // To change the versions see the gradle.properties file minecraft "com.mojang:minecraft:${project.minecraft_version}" @@ -41,10 +36,8 @@ dependencies { // LuckPerms modImplementation 'me.lucko:fabric-permissions-api:0.1-SNAPSHOT' - // WDMNF - modRuntime("com.github.tom_the_geek:wdmnf:1.0.0+mc.1.17") - //modRuntime "com.github.CaffeineMC:hydrogen-fabric:mc1.16.5-v0.2.0" - //modRuntime "com.github.astei:lazydfu:0.1.2" + // Allows in game config editing + modImplementation(include("com.github.samolego.Config2Brigadier:config2brigadier-fabric:${project.c2b_version}")) } processResources { diff --git a/gradle.properties b/gradle.properties index 2afbecc..80925fa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,6 +10,9 @@ loader_version=0.11.6 fabric_version=0.40.0+1.17 # Mod Properties -mod_version = 1.0.8 +mod_version = 1.0.9 maven_group = org.samo_lego archives_base_name = healthcare + +# Config editing lib +c2b_version = 1.0.0 diff --git a/src/main/java/org/samo_lego/healthcare/HealthCare.java b/src/main/java/org/samo_lego/healthcare/HealthCare.java index 199ef83..1ce0ec8 100644 --- a/src/main/java/org/samo_lego/healthcare/HealthCare.java +++ b/src/main/java/org/samo_lego/healthcare/HealthCare.java @@ -14,6 +14,8 @@ public class HealthCare implements ModInitializer { public static final String MODID = "healthcare"; + public static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir() + "/health_config.json"); + public static boolean LUCKPERMS_LOADED; public static HealthConfig config; @@ -26,7 +28,7 @@ public void onInitialize() { EventHandler eventHandler = new EventHandler(); ServerPlayerEvents.COPY_FROM.register(eventHandler); - config = HealthConfig.loadConfigFile(new File(FabricLoader.getInstance().getConfigDir() + "/health_config.json")); + config = HealthConfig.loadConfigFile(CONFIG_FILE); LUCKPERMS_LOADED = FabricLoader.getInstance().isModLoaded("fabric-permissions-api-v0"); } } diff --git a/src/main/java/org/samo_lego/healthcare/command/HealthbarCommand.java b/src/main/java/org/samo_lego/healthcare/command/HealthbarCommand.java index 5a22dfb..0a449e0 100644 --- a/src/main/java/org/samo_lego/healthcare/command/HealthbarCommand.java +++ b/src/main/java/org/samo_lego/healthcare/command/HealthbarCommand.java @@ -12,6 +12,7 @@ import net.minecraft.command.suggestion.SuggestionProviders; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.LiteralText; +import net.minecraft.text.TranslatableText; import net.minecraft.util.Formatting; import net.minecraft.util.Identifier; import org.samo_lego.healthcare.healthbar.HealthbarPreferences; @@ -73,7 +74,7 @@ public static void register(CommandDispatcher dispatcher, b private static int toggleEntityType(CommandContext context) throws CommandSyntaxException { if(LUCKPERMS_LOADED && !PermissionHelper.checkPermission(context.getSource(), config.perms.healthbar_edit_showEntityType, 0)) { - context.getSource().sendError(new LiteralText(config.lang.noPermission).formatted(Formatting.RED)); + context.getSource().sendError(new TranslatableText("commands.help.failed").formatted(Formatting.RED)); return -1; } @@ -94,7 +95,7 @@ private static int toggleEntityType(CommandContext context) private static int editHealthbarLength(CommandContext context) throws CommandSyntaxException { if(LUCKPERMS_LOADED && !PermissionHelper.checkPermission(context.getSource(), config.perms.healthbar_edit_custom_length, 0)) { - context.getSource().sendError(new LiteralText(config.lang.noPermission).formatted(Formatting.RED)); + context.getSource().sendError(new TranslatableText("commands.help.failed").formatted(Formatting.RED)); return -1; } @@ -121,7 +122,7 @@ private static int editHealthbarLength(CommandContext conte private static int setSymbol(CommandContext context, boolean full) throws CommandSyntaxException { if(LUCKPERMS_LOADED && !PermissionHelper.checkPermission(context.getSource(), full ? config.perms.healthbar_edit_custom_symbols_full : config.perms.healthbar_edit_custom_symbols_empty, 0)) { - context.getSource().sendError(new LiteralText(config.lang.noPermission).formatted(Formatting.RED)); + context.getSource().sendError(new TranslatableText("commands.help.failed").formatted(Formatting.RED)); return -1; } @@ -152,7 +153,7 @@ private static int setSymbol(CommandContext context, boolea private static int changeVisibility(CommandContext context) throws CommandSyntaxException { if(LUCKPERMS_LOADED && !PermissionHelper.checkPermission(context.getSource(), config.perms.healthbar_edit_visibility, 0)) { - context.getSource().sendError(new LiteralText(config.lang.noPermission).formatted(Formatting.RED)); + context.getSource().sendError(new TranslatableText("commands.help.failed").formatted(Formatting.RED)); return -1; } @@ -173,12 +174,12 @@ private static int changeVisibility(CommandContext context) private static int editHealthbarStyle(CommandContext context) throws CommandSyntaxException { if(LUCKPERMS_LOADED && !PermissionHelper.checkPermission(context.getSource(), config.perms.healthbar_edit_style, 0)) { - context.getSource().sendError(new LiteralText(config.lang.noPermission).formatted(Formatting.RED)); + context.getSource().sendError(new TranslatableText("commands.help.failed").formatted(Formatting.RED)); return -1; } HealthbarPreferences preferences = (HealthbarPreferences) context.getSource().getPlayer(); - Enum style = HealthbarPreferences.HealthbarStyle.valueOf(StringArgumentType.getString(context, "style")); + HealthbarPreferences.HealthbarStyle style = HealthbarPreferences.HealthbarStyle.valueOf(StringArgumentType.getString(context, "style")); preferences.setHealthbarStyle(style); @@ -194,7 +195,7 @@ private static int editHealthbarStyle(CommandContext contex private static int toggleHealthBar(CommandContext context) throws CommandSyntaxException { if(LUCKPERMS_LOADED && !PermissionHelper.checkPermission(context.getSource(), config.perms.healthbar_toggle, 0)) { - context.getSource().sendError(new LiteralText(config.lang.noPermission).formatted(Formatting.RED)); + context.getSource().sendError(new TranslatableText("commands.help.failed").formatted(Formatting.RED)); return -1; } diff --git a/src/main/java/org/samo_lego/healthcare/command/HealthcareCommand.java b/src/main/java/org/samo_lego/healthcare/command/HealthcareCommand.java index eb0a665..fa67cf7 100644 --- a/src/main/java/org/samo_lego/healthcare/command/HealthcareCommand.java +++ b/src/main/java/org/samo_lego/healthcare/command/HealthcareCommand.java @@ -2,30 +2,42 @@ import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; -import net.fabricmc.loader.api.FabricLoader; +import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.LiteralText; import net.minecraft.util.Formatting; import org.samo_lego.healthcare.config.HealthConfig; import org.samo_lego.healthcare.permission.PermissionHelper; -import java.io.File; - import static net.minecraft.server.command.CommandManager.literal; -import static org.samo_lego.healthcare.HealthCare.LUCKPERMS_LOADED; -import static org.samo_lego.healthcare.HealthCare.config; +import static org.samo_lego.healthcare.HealthCare.*; public class HealthcareCommand { public static void register(CommandDispatcher dispatcher, boolean dedicated) { - dispatcher.register(literal("healthcare") - .requires(src -> LUCKPERMS_LOADED ? PermissionHelper.checkPermission(src, config.perms.healthcare_reloadConfig, 4) : src.hasPermissionLevel(4)) - .then(literal("reloadConfig").executes(HealthcareCommand::reloadConfig)) - ); + LiteralCommandNode healthcareNode = dispatcher.register(literal("healthcare") + .requires(src -> LUCKPERMS_LOADED ? PermissionHelper.checkPermission(src, config.perms.healthcare_config, 4) : src.hasPermissionLevel(4))); + + LiteralCommandNode configNode = literal("config") + .then(literal("reload") + .requires(src -> LUCKPERMS_LOADED ? PermissionHelper.checkPermission(src, config.perms.healthcare_config_reload, 4) : src.hasPermissionLevel(4)) + .executes(HealthcareCommand::reloadConfig) + ) + .build(); + + LiteralCommandNode editNode = literal("edit") + .requires(src -> LUCKPERMS_LOADED ? PermissionHelper.checkPermission(src, config.perms.healthcare_config_edit, 4) : src.hasPermissionLevel(4)) + .build(); + + config.generateCommand(editNode); + + configNode.addChild(editNode); + healthcareNode.addChild(configNode); } private static int reloadConfig(CommandContext ctx) { - config = HealthConfig.loadConfigFile(new File(FabricLoader.getInstance().getConfigDir() + "/config.json")); + HealthConfig newConfig = HealthConfig.loadConfigFile(CONFIG_FILE); + config.reload(newConfig); ctx.getSource().sendFeedback( new LiteralText(config.lang.configReloaded).formatted(Formatting.GREEN), diff --git a/src/main/java/org/samo_lego/healthcare/config/HealthConfig.java b/src/main/java/org/samo_lego/healthcare/config/HealthConfig.java index 54cebb3..5e32a61 100644 --- a/src/main/java/org/samo_lego/healthcare/config/HealthConfig.java +++ b/src/main/java/org/samo_lego/healthcare/config/HealthConfig.java @@ -3,17 +3,22 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; +import org.samo_lego.config2brigadier.IBrigadierConfigurator; +import org.samo_lego.config2brigadier.annotation.BrigadierDescription; +import org.samo_lego.config2brigadier.annotation.BrigadierExcluded; import org.samo_lego.healthcare.healthbar.HealthbarPreferences; import java.io.*; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import static org.apache.logging.log4j.LogManager.getLogger; +import static org.samo_lego.healthcare.HealthCare.CONFIG_FILE; import static org.samo_lego.healthcare.HealthCare.MODID; -public class HealthConfig { +public class HealthConfig implements IBrigadierConfigurator { private static final Gson gson = new GsonBuilder() .setPrettyPrinting() .serializeNulls() @@ -22,32 +27,57 @@ public class HealthConfig { public final String _comment_blacklistedEntities = "// Which entities shouldn't have a healthbar above their name."; @SerializedName("blacklisted_entities") - public ArrayList blacklistedEntities = new ArrayList<>(Arrays.asList( + @BrigadierDescription(defaultOption = "[\"taterzens:npc\",\"specialmobs:mob_with_hidden_health\"]") + public List blacklistedEntities = new ArrayList<>(Arrays.asList( "taterzens:npc", "specialmobs:mob_with_hidden_health" )); @SerializedName("// When to activate the healthbar.") public String _comment_activationRange = ""; + @BrigadierDescription(defaultOption = "8.0") public float activationRange = 8.0F; + @BrigadierExcluded public final Permissions perms = new Permissions(); @SerializedName("// Max length of healthbar a player can use.") public final String _comment_maxHealthbarLength = ""; + @BrigadierDescription(defaultOption = "20") public int maxHealthbarLength = 20; @SerializedName("// Whether to show entity type next to health.") public final String _comment_showType = ""; + @BrigadierDescription(defaultOption = "true") public boolean showType = true; @SerializedName("// The default style of healthbar. The following are available") public final String _comment_defaultStyle1 = Arrays.toString(HealthbarPreferences.HealthbarStyle.values()); + @BrigadierDescription(defaultOption = "PERCENTAGE") public HealthbarPreferences.HealthbarStyle defaultStyle = HealthbarPreferences.HealthbarStyle.PERCENTAGE; + @SerializedName("// Whether healthbar is enabled by default.") + public final String _comment_enabled = ""; + @BrigadierDescription(defaultOption = "true") + @SerializedName("enabled_by_default") + public boolean enabledByDefault = true; + + @SerializedName("// Whether healthbar should always be visible (not just on entity hover) by default.") + public final String _comment_alwaysVisibleDefault = ""; + @SerializedName("always_visible_by_default") + @BrigadierDescription(defaultOption = "false") + public boolean alwaysVisibleDefault = false; + + @Override + public void save() { + this.saveConfigFile(CONFIG_FILE); + } + public static final class Permissions { @SerializedName("// Enabled only if LuckPerms is loaded.") public final String _comment = ""; - public final String healthcare_reloadConfig = "healthcare.reloadConfig"; + public final String healthcare_config = "healthcare.config"; + public final String healthcare_config_edit = "healthcare.config.edit"; + public final String healthcare_config_reload = "healthcare.config.reload"; @SerializedName("// Player permissions") public final String _comment_playerPermissions = ""; @@ -62,7 +92,6 @@ public static final class Permissions { public Language lang = new Language(); public static class Language { - public String noPermission = "You don't have permission to run this command."; public String configReloaded = "Config was reloaded successfully."; public String customLengthSet = "Length of healthbar was set to %s."; public String customSymbolSet = "%s healthbar symbol was set to %s."; @@ -82,7 +111,7 @@ public static class Language { * @return HealthConfig object */ public static HealthConfig loadConfigFile(File file) { - HealthConfig config; + HealthConfig config = null; if (file.exists()) { try (BufferedReader fileReader = new BufferedReader( new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8) @@ -92,10 +121,10 @@ public static HealthConfig loadConfigFile(File file) { throw new RuntimeException(MODID + " Problem occurred when trying to load config: ", e); } } - else { + if (config == null) { config = new HealthConfig(); } - config.saveConfigFile(file); + config.save(); return config; } diff --git a/src/main/java/org/samo_lego/healthcare/event/EventHandler.java b/src/main/java/org/samo_lego/healthcare/event/EventHandler.java index 939a757..2921d0d 100644 --- a/src/main/java/org/samo_lego/healthcare/event/EventHandler.java +++ b/src/main/java/org/samo_lego/healthcare/event/EventHandler.java @@ -18,6 +18,7 @@ public void copyFromPlayer(ServerPlayerEntity oldPlayer, ServerPlayerEntity newP ((HealthbarPreferences) newPlayer).setHealthbarStyle(((HealthbarPreferences) oldPlayer).getHealthbarStyle()); ((HealthbarPreferences) newPlayer).setEnabled(((HealthbarPreferences) oldPlayer).isEnabled()); ((HealthbarPreferences) newPlayer).setAlwaysVisible(((HealthbarPreferences) oldPlayer).isAlwaysVisible()); + ((HealthbarPreferences) newPlayer).setShowEntityType(((HealthbarPreferences) oldPlayer).showEntityType()); ((HealthbarPreferences) newPlayer).setCustomFullChar(((HealthbarPreferences) oldPlayer).getCustomFullChar()); ((HealthbarPreferences) newPlayer).setCustomEmptyChar(((HealthbarPreferences) oldPlayer).getCustomEmptyChar()); diff --git a/src/main/java/org/samo_lego/healthcare/healthbar/HealthbarPreferences.java b/src/main/java/org/samo_lego/healthcare/healthbar/HealthbarPreferences.java index 5588798..c389307 100644 --- a/src/main/java/org/samo_lego/healthcare/healthbar/HealthbarPreferences.java +++ b/src/main/java/org/samo_lego/healthcare/healthbar/HealthbarPreferences.java @@ -7,8 +7,8 @@ public interface HealthbarPreferences { * Gets style of the healthbar. * @return healthbar style */ - Enum getHealthbarStyle(); - void setHealthbarStyle(Enum healthbarStyle); + HealthbarStyle getHealthbarStyle(); + void setHealthbarStyle(HealthbarStyle healthbarStyle); /** * Gets the health text from current health and max health depending on HealthbarStyle. diff --git a/src/main/java/org/samo_lego/healthcare/mixin/PlayerEntityMixinCast_Preferences.java b/src/main/java/org/samo_lego/healthcare/mixin/PlayerEntityMixinCast_Preferences.java index 0cdc4af..5a519c5 100644 --- a/src/main/java/org/samo_lego/healthcare/mixin/PlayerEntityMixinCast_Preferences.java +++ b/src/main/java/org/samo_lego/healthcare/mixin/PlayerEntityMixinCast_Preferences.java @@ -16,22 +16,22 @@ @Mixin(PlayerEntity.class) public class PlayerEntityMixinCast_Preferences implements HealthbarPreferences { - private Enum healthbarStyle = config.defaultStyle; - private boolean enabled = true; + private HealthbarStyle healthbarStyle = config.defaultStyle; + private boolean enabled = config.enabledByDefault; private boolean showType = config.showType; - private boolean alwaysVisible = false; + private boolean alwaysVisible = config.alwaysVisibleDefault; private int customFullChar = 9632; // '■' private int customEmptyChar = 9633; // '□' private int customLength = 10; @Override - public Enum getHealthbarStyle() { + public HealthbarStyle getHealthbarStyle() { return this.healthbarStyle; } @Override - public void setHealthbarStyle(Enum healthbarStyle) { + public void setHealthbarStyle(HealthbarStyle healthbarStyle) { this.healthbarStyle = healthbarStyle; } @@ -48,52 +48,56 @@ public MutableText getHealthbarText(float health, float maxHealth) { } String first, second; - if(this.healthbarStyle.equals(HealthbarStyle.SKYBLOCK)) { - // String.format("%.2f", health) for rounding - first = String.format("%.2f", health); - second = String.valueOf((int) Math.ceil(maxHealth)); - - // We return it here because of custom formatting - return new LiteralText(first) - .formatted(health > maxHealth / 2 ? Formatting.GREEN : Formatting.YELLOW) - .append(new LiteralText("/") - .formatted(Formatting.WHITE)) - .append(new LiteralText(second) - .formatted(Formatting.GREEN)) - .append(new LiteralText(String.valueOf((char) 10084)) // ❤ - .formatted(Formatting.RED)); - } else if(this.healthbarStyle.equals(HealthbarStyle.NUMBER)) { - // Number - // String.format("%.2f", health) for rounding - first = String.format("%.2f", health); - second = "/" + maxHealth; - } else if(HealthbarStyle.PERCENTAGE.equals(this.healthbarStyle)) { - first = String.format("%.2f", health * 100.0F / maxHealth).concat("%"); - second = ""; - } else { - int heartCount, fullHearts; - char full, empty; - if(this.healthbarStyle.equals(HealthbarStyle.LINES)) { - heartCount = maxHealth < 20 ? (int) Math.ceil(maxHealth) : 20; - - empty = '|'; - full = '|'; - } else { // Hearts - // We ceil the number to not show 0 hearts if entity has like 0.2f health - int length = this.healthbarStyle == HealthbarStyle.CUSTOM ? customLength : 10; - heartCount = maxHealth < length ? (int) Math.ceil(maxHealth) : length; - - full = (char) (this.healthbarStyle.equals(HealthbarStyle.HEARTS) ? 9829 : this.customFullChar); // ♥ or custom - empty = (char) (this.healthbarStyle.equals(HealthbarStyle.HEARTS) ? 9825 : this.customEmptyChar); // ♡ or custom + switch(this.healthbarStyle) { + case SKYBLOCK -> { + // String.format("%.2f", health) for rounding + first = String.format("%.2f", health); + second = String.valueOf((int) Math.ceil(maxHealth)); + + // We return it here because of custom formatting + return new LiteralText(first) + .formatted(health > maxHealth / 2 ? Formatting.GREEN : Formatting.YELLOW) + .append(new LiteralText("/") + .formatted(Formatting.WHITE)) + .append(new LiteralText(second) + .formatted(Formatting.GREEN)) + .append(new LiteralText(String.valueOf((char) 10084)) // ❤ + .formatted(Formatting.RED)); + } + case NUMBER -> { + // Number + // String.format("%.2f", health) for rounding + first = String.format("%.2f", health); + second = "/" + maxHealth; + } + case PERCENTAGE -> { + first = String.format("%.2f", health * 100.0F / maxHealth).concat("%"); + second = ""; + } + default -> { + int heartCount, fullHearts; + char full, empty; + if(this.healthbarStyle.equals(HealthbarStyle.LINES)) { + heartCount = maxHealth < 20 ? (int) Math.ceil(maxHealth) : 20; + + empty = '|'; + full = '|'; + } else { // Hearts + // We ceil the number to not show 0 hearts if entity has like 0.2f health + int length = this.healthbarStyle == HealthbarStyle.CUSTOM ? customLength : 10; + heartCount = maxHealth < length ? (int) Math.ceil(maxHealth) : length; + + full = (char) (this.healthbarStyle.equals(HealthbarStyle.HEARTS) ? 9829 : this.customFullChar); // ♥ or custom + empty = (char) (this.healthbarStyle.equals(HealthbarStyle.HEARTS) ? 9825 : this.customEmptyChar); // ♡ or custom + } + + // Hearts that should be colored red + fullHearts = (int) Math.ceil(health * heartCount / maxHealth); + + first = new String(new char[fullHearts]).replace('\0', full); + second = new String(new char[heartCount - fullHearts]).replace('\0', empty); } - - // Hearts that should be colored red - fullHearts = (int) Math.ceil(health * heartCount / maxHealth); - - first = new String(new char[fullHearts]).replace('\0', full); - second = new String(new char[heartCount - fullHearts]).replace('\0', empty); } - return new LiteralText(first) .formatted(Formatting.RED) /*health > maxHealth / 3 ? (health > maxHealth * 1.5F ? Formatting.YELLOW : Formatting.GOLD) : */ .append(new LiteralText(second).formatted(Formatting.GRAY)); @@ -165,6 +169,7 @@ private void writeCustomDataToTag(NbtCompound tag, CallbackInfo ci) { NbtCompound healthbar = new NbtCompound(); healthbar.putString("Style", this.healthbarStyle.toString()); healthbar.putBoolean("Enabled", this.enabled); + healthbar.putBoolean("ShowType", this.showType); healthbar.putBoolean("AlwaysVisible", this.alwaysVisible); if(this.healthbarStyle.equals(HealthbarStyle.CUSTOM)) { healthbar.putInt("CustomFullChar", this.customFullChar); @@ -181,6 +186,7 @@ private void readCustomDataFromTag(NbtCompound tag, CallbackInfo ci) { this.healthbarStyle = HealthbarStyle.valueOf(healthbar.getString("Style")); this.enabled = healthbar.getBoolean("Enabled"); this.alwaysVisible = healthbar.getBoolean("AlwaysVisible"); + this.showType = healthbar.getBoolean("ShowType"); if(this.healthbarStyle.equals(HealthbarStyle.CUSTOM)) { this.customFullChar = healthbar.getInt("CustomFullChar"); diff --git a/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java b/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java index d06cba4..942e84f 100644 --- a/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java +++ b/src/main/java/org/samo_lego/healthcare/mixin/ServerPlayNetworkHandlerMixin_HealthTag.java @@ -50,7 +50,7 @@ public class ServerPlayNetworkHandlerMixin_HealthTag { /** * Gets the current packet being sent and modifies - * it accordingly to player's preferences in the packet is + * it accordingly to player's preferences if it is * an {@link EntityTrackerUpdateS2CPacket}. * * @param packet packet being sent @@ -91,14 +91,14 @@ private void onPacketSend(Packet packet, GenericFutureListener> healthTag = new DataTracker.Entry<>(EntityAccessor.getCUSTOM_NAME(), Optional.of(name.append(" ").append(healthbar))); + MutableText healthbar = ((HealthbarPreferences) this.player).getHealthbarText(health, maxHealth); + DataTracker.Entry> healthTag = new DataTracker.Entry<>(EntityAccessor.getCUSTOM_NAME(), Optional.of(name.append(healthbar))); Collections.addAll(trackedValues, visibleTag, healthTag);