diff --git a/src/main/generated/assets/provihealth/lang/en_gb.json b/src/main/generated/assets/provihealth/lang/en_gb.json index c28ee03..ace440c 100644 --- a/src/main/generated/assets/provihealth/lang/en_gb.json +++ b/src/main/generated/assets/provihealth/lang/en_gb.json @@ -1,13 +1,18 @@ { - "entry.provihealth.barEndColour": "Low Health Colour", - "entry.provihealth.barStartColour": "Full Health Colour", "entry.provihealth.damageColour": "Damage Particle Colour", - "entry.provihealth.damageParticleTextColour": "Damage Text Colour", "entry.provihealth.healingColour": "Healing Particle Colour", + "entry.provihealth.damageParticleTextColour": "Damage Text Colour", "entry.provihealth.healingParticleTextColour": "Healing Text Colour", + "entry.provihealth.barDefaultStartColour": "Full Default/Passive Mob Health Colour", + "entry.provihealth.barNeutralStartColour": "Full Neutral Mob Health Colour", + "entry.provihealth.barHostileStartColour": "Full Hostile Mob Health Colour", + "entry.provihealth.barEndColour": "Low Health Colour", "entry.provihealth.teamColours": "Use Team Colours", - "tooltip.provihealth.compatWorld": "Uses a different rendering program for in-world health bars. Only turn this on if shaders are preventing the bars from rendering.\nWarning: This option disables any colour-related settings for in-world health bars.", + "entry.provihealth.aggressionColours": "Use Entity Aggression Colours", + "tooltip.provihealth.gradient": "Whether or not the health bar will change colour as it gets lower.\nTurning this off sets the bar colour to the starting value.", + "tooltip.provihealth.compatWorld": "Uses a different rendering program for in-world health bars. Only turn this on if shaders are preventing the bars from rendering.\nWarning: This option disables any colour-related settings for in-world health bars.", + "tooltip.provihealth.tintBackground": "Applies the bar colour to the background as well.", "tooltip.provihealth.teamColours": "Matches health bar colour to the entity's team if applicable.\nTeam colours will override colours from other settings.", - "tooltip.provihealth.tintBackground": "Applies the bar colour to the background as well." + "tooltip.provihealth.aggressionColours": "Matches health bar colour to the entity aggression type/level.\nAngered and Hostile mobs will use the Hostile aggression colours.\nNon-angered and Untamed Neutral/Angerable mobs will use the Neutral aggression colours\nPassive mobs will use the default colour.\nIf turned off, all mobs use the default colour." } \ No newline at end of file diff --git a/src/main/generated/assets/provihealth/lang/en_us.json b/src/main/generated/assets/provihealth/lang/en_us.json index 7887e73..9356677 100644 --- a/src/main/generated/assets/provihealth/lang/en_us.json +++ b/src/main/generated/assets/provihealth/lang/en_us.json @@ -1,90 +1,107 @@ { - "category.provihealth.compat": "Compatibility", + "title.provihealth.config": "Provi's Health Bars", + "category.provihealth.general": "General", - "category.provihealth.health": "In-World", "category.provihealth.hud": "HUD", + "category.provihealth.health": "In-World", "category.provihealth.particles": "Particles", - "entity.provihealth.unknownPlayer": "[Invisible Player]", - "entry.provihealth.barEndColour": "Low Health Colour", - "entry.provihealth.barScale": "Bar Size", - "entry.provihealth.barStartColour": "Full Health Colour", + "category.provihealth.compat": "Compatibility", + + "subcategory.provihealth.boss": "Bosses", + "subcategory.provihealth.hostile": "Hostile Mobs", + "subcategory.provihealth.player": "Players", + "subcategory.provihealth.other": "Non-Hostile Mobs", + + "entry.provihealth.hudDuration": "HUD Duration", "entry.provihealth.blacklist": "Blacklist", "entry.provihealth.boss": "Boss Display", - "entry.provihealth.compatHud": "HUD Paperdoll Render Mode", - "entry.provihealth.compatText": "In-World Health Bar SeeThrough Text Mode", - "entry.provihealth.compatWorld": "In-World Health Bar Shader Compatibility", - "entry.provihealth.damageAlpha": "Damage Particle Alpha", - "entry.provihealth.damageColour": "Damage Particle Color", - "entry.provihealth.damageParticleTextColour": "Damage Text Color", - "entry.provihealth.damageParticles": "Show Damage Particles", - "entry.provihealth.gradient": "Dynamic Bar Color", - "entry.provihealth.healingAlpha": "Healing Particle Alpha", - "entry.provihealth.healingColour": "Healing Particle Color", - "entry.provihealth.healingParticleTextColour": "Healing Text Color", - "entry.provihealth.healingParticles": "Show Healing Particles", - "entry.provihealth.healthBar": "Health Bar Visibility", "entry.provihealth.hostile": "Hostile Mob Display", - "entry.provihealth.hudDuration": "HUD Duration", + "entry.provihealth.player": "Player Display", + "entry.provihealth.other": "Non-Hostile Mob Display", + "entry.provihealth.healthBar": "Health Bar Visibility", + "entry.provihealth.targetOverride": "Show On Target", "entry.provihealth.hudGlide": "Glide Speed", - "entry.provihealth.hudOffsetX": "HUD Position", - "entry.provihealth.hudOffsetY": "HUD Offset Y", + "entry.provihealth.showIcon": "Show Group Icon", "entry.provihealth.hudPortraits": "Use Custom HUD Portraits", - "entry.provihealth.hudStatuses": "Show Status Effects", - "entry.provihealth.hudTitles": "Show Titles On HUD", + "entry.provihealth.worldText": "Show Health Value", "entry.provihealth.maxDistance": "Maximum Render Distance", - "entry.provihealth.maxParticleDistance": "Particle Render Distance", - "entry.provihealth.other": "Non-Hostile Mob Display", - "entry.provihealth.overrideLabels": "Replace Nameplates", + "entry.provihealth.barScale": "Bar Size", + "entry.provihealth.hudOffsetY": "HUD Offset Y", + "entry.provihealth.hudTitles": "Show Titles On HUD", + "entry.provihealth.damageParticles": "Show Damage Particles", + "entry.provihealth.healingParticles": "Show Healing Particles", + "entry.provihealth.killText": "Spawn Kill/Insta-kill text", + "entry.provihealth.damageColour": "Damage Particle Color", + "entry.provihealth.healingColour": "Healing Particle Color", "entry.provihealth.particleScale": "Particle Size", "entry.provihealth.particleTextShadow": "Text Shadow", + "entry.provihealth.damageParticleTextColour": "Damage Text Color", + "entry.provihealth.healingParticleTextColour": "Healing Text Color", "entry.provihealth.particleType": "Particle Movement", - "entry.provihealth.player": "Player Display", - "entry.provihealth.showIcon": "Show Group Icon", - "entry.provihealth.targetOverride": "Show On Target", - "entry.provihealth.teamColours": "Use Team Colors", - "entry.provihealth.tintBackground": "Tint Background", - "entry.provihealth.worldOffsetY": "Health Bar Offset Y", + "entry.provihealth.maxParticleDistance": "Particle Render Distance", + "entry.provihealth.hudOffsetX": "HUD Position", + "entry.provihealth.gradient": "Dynamic Bar Color", + "entry.provihealth.barDefaultStartColour": "Full Default/Passive Mob Health Color", + "entry.provihealth.barNeutralStartColour": "Full Neutral Mob Health Color", + "entry.provihealth.barHostileStartColour": "Full Hostile Mob Health Color", + "entry.provihealth.barEndColour": "Low Health Color", + "entry.provihealth.overrideLabels": "Replace Nameplates", "entry.provihealth.worldShadows": "Text Shadow", - "entry.provihealth.worldText": "Show Health Value", + "entry.provihealth.compatText": "In-World Health Bar SeeThrough Text Mode", + "entry.provihealth.compatWorld": "In-World Health Bar Shader Compatibility", + "entry.provihealth.worldOffsetY": "Health Bar Offset Y", "entry.provihealth.worldTitles": "Show Titles In World", - "enum.provihealth.always_hide": "Hide", - "enum.provihealth.always_show": "Show", + "entry.provihealth.damageAlpha": "Damage Particle Alpha", + "entry.provihealth.healingAlpha": "Healing Particle Alpha", + "entry.provihealth.compatHud": "HUD Paperdoll Render Mode", + "entry.provihealth.hudStatuses": "Show Status Effects", + "entry.provihealth.tintBackground": "Tint Background", + "entry.provihealth.teamColours": "Use Team Colors", + "entry.provihealth.aggressionColours": "Use Entity Aggression Colors", + "enum.provihealth.full": "Full", - "enum.provihealth.gravity": "Has Gravity", + "enum.provihealth.portrait_only": "Portrait Only", + "enum.provihealth.none": "None", + + "enum.provihealth.always_show": "Show", "enum.provihealth.hide_if_full": "Hide When Full", - "enum.provihealth.hudportraitcompatmode.compat": "Compatibility", - "enum.provihealth.hudportraitcompatmode.none": "None", - "enum.provihealth.hudportraitcompatmode.standard": "Standard", + "enum.provihealth.always_hide": "Hide", + + "enum.provihealth.rising": "Rising", + "enum.provihealth.gravity": "Has Gravity", + "enum.provihealth.static": "None", + "enum.provihealth.left": "Left", - "enum.provihealth.none": "None", - "enum.provihealth.portrait_only": "Portrait Only", "enum.provihealth.right": "Right", - "enum.provihealth.rising": "Rising", - "enum.provihealth.seethroughtext.full": "SeeThrough Text/Shadows", - "enum.provihealth.seethroughtext.none": "Normal Text/Shadows", + "enum.provihealth.seethroughtext.standard": "SeeThrough Text, Normal Shadows", - "enum.provihealth.static": "None", - "resource.provihealth.rounded_bars": "Rounded Bars", - "resource.provihealth.rounded_bars.description": "Round-styled healthbars.", - "resource.provihealth.square_bars": "Square Bars", - "resource.provihealth.square_bars.description": "Square-styled healthbars.", - "subcategory.provihealth.boss": "Bosses", - "subcategory.provihealth.hostile": "Hostile Mobs", - "subcategory.provihealth.other": "Non-Hostile Mobs", - "subcategory.provihealth.player": "Players", - "title.provihealth.config": "Provi's Health Bars", - "tooltip.provihealth.compatText": "SeeThrough Text is any text that is visible through walls, this includes player nameplates.\nThis setting only applies when Replace Nameplates is active.\nSeeThrough Text-Shadows break easily in both vanilla and heavily modded environments. Change this setting if overridden nameplates render wrong.\nIf this setting does not solve the shadow issue, then disable text-shadows in the In-World menu.", - "tooltip.provihealth.compatWorld": "Uses a different rendering program for in-world health bars. Only turn this on if shaders are preventing the bars from rendering.\nWarning, This option disables any color-related settings for in-world health bars.", - "tooltip.provihealth.glide": "Determines how quickly the health bar will slide from its old value to new values.\nWarning, Very low values will prevent the health bar visual from catching up with the true value.", - "tooltip.provihealth.gradient": "Whether or not the health bar will change color as it gets lower.\nTurning this off sets the bar color to the starting value.", + "enum.provihealth.seethroughtext.none": "Normal Text/Shadows", + "enum.provihealth.seethroughtext.full": "SeeThrough Text/Shadows", + + "enum.provihealth.hudportraitcompatmode.standard": "Standard", + "enum.provihealth.hudportraitcompatmode.compat": "Compatibility", + "enum.provihealth.hudportraitcompatmode.none": "None", + "tooltip.provihealth.hudDuration": "How many ticks the HUD display will linger for when not targeting a mob.", - "tooltip.provihealth.hudOffsetY": "As a percentage of the window height.", + "tooltip.provihealth.targetOverride": "Always render health bar when targeting a mob of this type.", + "tooltip.provihealth.glide": "Determines how quickly the health bar will slide from its old value to new values.\nWarning: Very low values will prevent the health bar visual from catching up with the true value.", "tooltip.provihealth.hudPortraits": "Allows mobs to have different HUD portraits based on their group or type.", - "tooltip.provihealth.hudTitles": "Allows other mods to show text under the HUD portrait.", "tooltip.provihealth.maxDistance": "Mobs beyond this distance will not render health bars.", - "tooltip.provihealth.overrideLabels": "When true health bar text will include the name of the mob and nameplates will not be rendered.\nWhen false health bar text will only show the health values, and the bar will move upwards when a nameplate is being rendered.\nWarning, Only the name of the mob is added to the health bar, if a mod/plugin/scoreboard adds additional lines of text to the nameplate then that text will be lost.", - "tooltip.provihealth.targetOverride": "Always render health bar when targeting a mob of this type.", - "tooltip.provihealth.teamColours": "Matches health bar color to the entity's team if applicable.\nTeam colors will override colors from other settings.", + "tooltip.provihealth.hudOffsetY": "As a percentage of the window height.", + "tooltip.provihealth.gradient": "Whether or not the health bar will change color as it gets lower.\nTurning this off sets the bar color to the starting value.", + "tooltip.provihealth.overrideLabels": "When true health bar text will include the name of the mob and nameplates will not be rendered.\nWhen false health bar text will only show the health values, and the bar will move upwards when a nameplate is being rendered.\nWarning: Only the name of the mob is added to the health bar, if a mod/plugin/scoreboard adds additional lines of text to the nameplate then that text will be lost.", + "tooltip.provihealth.compatText": "SeeThrough Text is any text that is visible through walls, this includes player nameplates.\nThis setting only applies when Replace Nameplates is active.\nSeeThrough Text-Shadows break easily in both vanilla and heavily modded environments. Change this setting if overridden nameplates render wrong.\nIf this setting does not solve the shadow issue, then disable text-shadows in the In-World menu.", + "tooltip.provihealth.compatWorld": "Uses a different rendering program for in-world health bars. Only turn this on if shaders are preventing the bars from rendering.\nWarning: This option disables any color-related settings for in-world health bars.", + "tooltip.provihealth.hudTitles": "Allows other mods to show text under the HUD portrait.", + "tooltip.provihealth.worldTitles": "Allows other mods to show text above the in-world health bars.", "tooltip.provihealth.tintBackground": "Applies the bar color to the background as well.", - "tooltip.provihealth.worldTitles": "Allows other mods to show text above the in-world health bars." + "tooltip.provihealth.teamColours": "Matches health bar color to the entity's team if applicable.\nTeam colors will override colors from other settings.", + "tooltip.provihealth.aggressionColours": "Matches health bar color to the entity aggression type/level.\nAngered and Hostile mobs will use the Hostile aggression colors.\nNon-angered and Untamed Neutral/Angerable mobs will use the Neutral aggression colors\nPassive mobs will use the default color.\nIf turned off, all mobs use the default color.", + + "entity.provihealth.unknownPlayer": "[Invisible Player]", + + "resource.provihealth.rounded_bars": "Rounded Bars", + "resource.provihealth.rounded_bars.description": "Round-styled healthbars.", + "resource.provihealth.square_bars": "Square Bars", + "resource.provihealth.square_bars.description": "Square-styled healthbars." } \ No newline at end of file diff --git a/src/main/java/com/provismet/provihealth/compat/ProviHealthConfigScreen.java b/src/main/java/com/provismet/provihealth/compat/ProviHealthConfigScreen.java index 96b7eef..19530a6 100644 --- a/src/main/java/com/provismet/provihealth/compat/ProviHealthConfigScreen.java +++ b/src/main/java/com/provismet/provihealth/compat/ProviHealthConfigScreen.java @@ -97,17 +97,42 @@ public static Screen build (Screen parent) { .build() ); - hud.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barStartColour"), Options.hudStartColour) + hud.addEntry(entryBuilder.startBooleanToggle(Text.translatable("entry.provihealth.aggressionColours"), Options.useHudAggressionColours) + .setDefaultValue(true) + .setTooltip(Text.translatable("tooltip.provihealth.aggressionColours")) + .setSaveConsumer(newValue -> Options.useHudAggressionColours = newValue) + .build() + ); + + hud.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barDefaultStartColour"), Options.hudDefaultStartColour) .setDefaultValue(0x00C100) .setSaveConsumer(newValue -> { - Options.hudStartColour = newValue; - Options.unpackedStartHud = Vec3d.unpackRgb(newValue).toVector3f(); + Options.hudDefaultStartColour = newValue; + Options.unpackedDefaultStartHud = Vec3d.unpackRgb(newValue).toVector3f(); }) .build() ); - hud.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barEndColour"), Options.hudEndColour) + hud.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barNeutralStartColour"), Options.hudNeutralStartColour) + .setDefaultValue(0xF2D00C) + .setSaveConsumer(newValue -> { + Options.hudNeutralStartColour = newValue; + Options.unpackedNeutralStartHud = Vec3d.unpackRgb(newValue).toVector3f(); + }) + .build() + ); + + hud.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barHostileStartColour"), Options.hudHostileStartColour) .setDefaultValue(0xFF0000) + .setSaveConsumer(newValue -> { + Options.hudHostileStartColour = newValue; + Options.unpackedHostileStartHud = Vec3d.unpackRgb(newValue).toVector3f(); + }) + .build() + ); + + hud.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barEndColour"), Options.hudEndColour) + .setDefaultValue(0xBB0000) .setSaveConsumer(newValue -> { Options.hudEndColour = newValue; Options.unpackedEndHud = Vec3d.unpackRgb(newValue).toVector3f(); @@ -214,17 +239,42 @@ public static Screen build (Screen parent) { .build() ); - health.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barStartColour"), Options.worldStartColour) + health.addEntry(entryBuilder.startBooleanToggle(Text.translatable("entry.provihealth.aggressionColours"), Options.useWorldAggressionColours) + .setDefaultValue(true) + .setTooltip(Text.translatable("tooltip.provihealth.aggressionColours")) + .setSaveConsumer(newValue -> Options.useWorldAggressionColours = newValue) + .build() + ); + + health.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barDefaultStartColour"), Options.worldDefaultStartColour) .setDefaultValue(0x00C100) .setSaveConsumer(newValue -> { - Options.worldStartColour = newValue; - Options.unpackedStartWorld = Vec3d.unpackRgb(newValue).toVector3f(); + Options.worldDefaultStartColour = newValue; + Options.unpackedDefaultStartWorld = Vec3d.unpackRgb(newValue).toVector3f(); }) .build() ); - health.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barEndColour"), Options.worldEndColour) + health.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barNeutralStartColour"), Options.worldNeutralStartColour) + .setDefaultValue(0xF2D00C) + .setSaveConsumer(newValue -> { + Options.worldNeutralStartColour = newValue; + Options.unpackedNeutralStartWorld = Vec3d.unpackRgb(newValue).toVector3f(); + }) + .build() + ); + + health.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barHostileStartColour"), Options.worldHostileStartColour) .setDefaultValue(0xFF0000) + .setSaveConsumer(newValue -> { + Options.worldHostileStartColour = newValue; + Options.unpackedHostileStartWorld = Vec3d.unpackRgb(newValue).toVector3f(); + }) + .build() + ); + + health.addEntry(entryBuilder.startColorField(Text.translatable("entry.provihealth.barEndColour"), Options.worldEndColour) + .setDefaultValue(0xBB0000) .setSaveConsumer(newValue -> { Options.worldEndColour = newValue; Options.unpackedEndWorld = Vec3d.unpackRgb(newValue).toVector3f(); @@ -306,6 +356,12 @@ public static Screen build (Screen parent) { .build() ); + particles.addEntry(entryBuilder.startBooleanToggle(Text.translatable("entry.provihealth.killText"), Options.spawnKillText) + .setDefaultValue(true) + .setSaveConsumer(newValue -> Options.spawnKillText = newValue) + .build() + ); + particles.addEntry(entryBuilder.startEnumSelector(Text.translatable("entry.provihealth.particleType"), DamageParticleType.class, Options.particleType) .setDefaultValue(DamageParticleType.RISING) .setSaveConsumer(newValue -> Options.particleType = newValue) diff --git a/src/main/java/com/provismet/provihealth/config/Options.java b/src/main/java/com/provismet/provihealth/config/Options.java index 9cec198..c2fd256 100644 --- a/src/main/java/com/provismet/provihealth/config/Options.java +++ b/src/main/java/com/provismet/provihealth/config/Options.java @@ -56,20 +56,29 @@ public class Options { public static boolean useCustomHudPortraits = true; public static int hudOffsetPercent = 0; public static HUDPosition hudPosition = HUDPosition.LEFT; - public static int hudStartColour = 0x00C100; - public static int hudEndColour = 0xFF0000; - public static Vector3f unpackedStartHud = Vec3d.unpackRgb(hudStartColour).toVector3f(); + public static int hudDefaultStartColour = 0x00C100; // Renamed to default for clarity with other types. Passive mobs use default + public static int hudNeutralStartColour = 0xF2D00C; + public static int hudHostileStartColour = 0xFF0000; + public static int hudEndColour = 0xBB0000; // Darkened end colour slightly to account for hostile mob bars being dynamic, albeit mildly + public static Vector3f unpackedDefaultStartHud = Vec3d.unpackRgb(hudDefaultStartColour).toVector3f(); + public static Vector3f unpackedNeutralStartHud = Vec3d.unpackRgb(hudNeutralStartColour).toVector3f(); + public static Vector3f unpackedHostileStartHud = Vec3d.unpackRgb(hudHostileStartColour).toVector3f(); public static Vector3f unpackedEndHud = Vec3d.unpackRgb(hudEndColour).toVector3f(); public static boolean hudGradient = false; public static boolean hudTitles = true; public static boolean hudStatuses = true; + public static boolean useHudAggressionColours = true; public static boolean showTextInWorld = true; public static float maxRenderDistance = 24f; public static float worldHealthBarScale = 1.5f; - public static int worldStartColour = 0x00C100; - public static int worldEndColour = 0xFF0000; - public static Vector3f unpackedStartWorld = Vec3d.unpackRgb(worldStartColour).toVector3f(); + public static int worldDefaultStartColour = 0x00C100; // Renamed to default for clarity with other types. Passive mobs use default + public static int worldNeutralStartColour = 0xF2D00C; + public static int worldHostileStartColour = 0xFF0000; + public static int worldEndColour = 0xBB0000; // Darkened end colour slightly to account for hostile mob bars being dynamic, albeit mildly + public static Vector3f unpackedDefaultStartWorld = Vec3d.unpackRgb(worldDefaultStartColour).toVector3f(); + public static Vector3f unpackedNeutralStartWorld = Vec3d.unpackRgb(worldNeutralStartColour).toVector3f(); + public static Vector3f unpackedHostileStartWorld = Vec3d.unpackRgb(worldHostileStartColour).toVector3f(); public static Vector3f unpackedEndWorld = Vec3d.unpackRgb(worldEndColour).toVector3f(); public static boolean worldGradient = false; public static boolean overrideLabels = false; @@ -78,9 +87,11 @@ public class Options { public static boolean worldTitles = true; public static boolean tintBackground = false; public static boolean useTeamColours = false; + public static boolean useWorldAggressionColours = true; public static boolean spawnDamageParticles = true; public static boolean spawnHealingParticles = false; + public static boolean spawnKillText = true; public static int damageColour = 0xFF0000; public static int healingColour = 0x00FF00; public static Vector3f unpackedDamage = Vec3d.unpackRgb(damageColour).toVector3f(); @@ -149,7 +160,10 @@ public static void save () { .append("hudPosition", hudPosition.name()) .append("hudOffsetY", hudOffsetPercent) .append("hudGradient", hudGradient) - .append("hudStartColour", hudStartColour) + .append("hudDefaultStartColour", hudDefaultStartColour) + .append("hudNeutralStartColour", hudNeutralStartColour) + .append("hudHostileStartColour", hudHostileStartColour) + .append("useHudAggressionColours", useHudAggressionColours) .append("hudEndColour", hudEndColour) .append("bossHUD", bossHUD.name()) .append("hostileHUD", hostileHUD.name()) @@ -167,7 +181,9 @@ public static void save () { .append("barScale", worldHealthBarScale) .append("worldOffsetY", worldOffsetY) .append("worldGradient", worldGradient) - .append("worldStartColour", worldStartColour) + .append("worldDefaultStartColour", worldDefaultStartColour) + .append("worldNeutralStartColour", worldNeutralStartColour) + .append("worldHostileStartColour", worldHostileStartColour) .append("worldEndColour", worldEndColour) .append("bossHealth", bosses.name()) .append("bossTarget", bossesVisibilityOverride) @@ -180,11 +196,13 @@ public static void save () { .append("worldTitles", worldTitles) .append("tintBackground", tintBackground) .append("useTeamColours", useTeamColours) + .append("useWorldAggressionColours", useWorldAggressionColours) .appendArray("healthBlacklist", blacklist) ) .append("particles", new JsonBuilder() .append("damageParticles", spawnDamageParticles) .append("healingParticles", spawnHealingParticles) + .append("killText", spawnKillText) .append("damageColour", damageColour) .append("damageAlpha", damageAlpha) .append("healingColour", healingColour) @@ -229,7 +247,10 @@ public static void load () { json.getString("hudPosition").ifPresent(val -> hudPosition = HUDPosition.valueOf(val)); json.getInteger("hudOffsetY").ifPresent(val -> hudOffsetPercent = val); json.getBoolean("hudGradient").ifPresent(val -> hudGradient = val); - json.getInteger("hudStartColour").ifPresent(val -> hudStartColour = val); + json.getBoolean("useHudAggressionColours").ifPresent(val -> useHudAggressionColours = val); + json.getInteger("hudDefaultStartColour").ifPresent(val -> hudDefaultStartColour = val); + json.getInteger("hudNeutralStartColour").ifPresent(val -> hudNeutralStartColour = val); + json.getInteger("hudHostileStartColour").ifPresent(val -> hudHostileStartColour = val); json.getInteger("hudEndColour").ifPresent(val -> hudEndColour = val); json.getString("bossHUD").ifPresent(val -> bossHUD = HUDType.valueOf(val)); json.getString("hostileHUD").ifPresent(val -> hostileHUD = HUDType.valueOf(val)); @@ -251,7 +272,10 @@ public static void load () { json.getFloat("barScale").ifPresent(val -> worldHealthBarScale = val); json.getFloat("worldOffsetY").ifPresent(val -> worldOffsetY = val); json.getBoolean("worldGradient").ifPresent(val -> worldGradient = val); - json.getInteger("worldStartColour").ifPresent(val -> worldStartColour = val); + json.getBoolean("useWorldAggressionColours").ifPresent(val -> useWorldAggressionColours = val); + json.getInteger("worldDefaultStartColour").ifPresent(val -> worldDefaultStartColour = val); + json.getInteger("worldNeutralStartColour").ifPresent(val -> worldNeutralStartColour = val); + json.getInteger("worldHostileStartColour").ifPresent(val -> worldHostileStartColour = val); json.getInteger("worldEndColour").ifPresent(val -> worldEndColour = val); json.getString("bossHealth").ifPresent(val -> bosses = VisibilityType.valueOf(val)); json.getBoolean("bossTarget").ifPresent(val -> bossesVisibilityOverride = val); @@ -273,6 +297,7 @@ public static void load () { }).ifPresent(json -> { json.getBoolean("damageParticles").ifPresent(val -> spawnDamageParticles = val); json.getBoolean("healingParticles").ifPresent(val -> spawnHealingParticles = val); + json.getBoolean("killText").ifPresent(val -> spawnKillText = val); json.getInteger("damageColour").ifPresent(val -> damageColour = val); json.getFloat("damageAlpha").ifPresent(val -> damageAlpha = val); json.getInteger("healingColour").ifPresent(val -> healingColour = val); diff --git a/src/main/java/com/provismet/provihealth/hud/TargetHealthBar.java b/src/main/java/com/provismet/provihealth/hud/TargetHealthBar.java index a4d5b31..2bee2fb 100644 --- a/src/main/java/com/provismet/provihealth/hud/TargetHealthBar.java +++ b/src/main/java/com/provismet/provihealth/hud/TargetHealthBar.java @@ -2,6 +2,7 @@ import com.provismet.provihealth.config.resources.EntityOptions; import com.provismet.provihealth.interfaces.IMixinLivingEntity; +import com.provismet.provihealth.util.FunctionalUtilities; import com.provismet.provihealth.util.HealthCalculator; import com.provismet.provihealth.util.HealthContainer; import net.fabricmc.fabric.api.client.rendering.v1.HudLayerRegistrationCallback; @@ -309,17 +310,33 @@ private int glideVehicleHealth (int trueValue, float glideFactor) { this.currentVehicleHealthWidth += (int)((float)(trueValue - this.currentVehicleHealthWidth) * MathHelper.clamp(glideFactor, 0.001f, 1f)); return this.currentVehicleHealthWidth; } - + private void renderBar (DrawContext drawContext, Identifier texture, int width, int barIndex) { - Vector3f barColour = Options.lerpBarColour((float)width / (float)BAR_WIDTH, barIndex == 1 ? Options.WHITE : Options.unpackedStartHud, Options.unpackedEndHud, barIndex == 0 && Options.hudGradient); + + Vector3f startColour; + LivingEntity entity = this.target; + + // System.out.println(((IMixinLivingEntity)this.target).provi_Health$getAnger()); + + // CommandManager commandManager = Objects.requireNonNull(player.getServer()).getCommandManager(); + // ServerCommandSource commandSource = player.getServer().getCommandSource(); + // commandManager.executeWithPrefix(commandSource, command); + + + if (barIndex == 1) startColour = Options.WHITE; + + else startColour = FunctionalUtilities.deduceColour(entity, true); + + Vector3f barColour = Options.lerpBarColour((float)width / (float)BAR_WIDTH, startColour, Options.unpackedEndHud, barIndex == 0 && Options.hudGradient); if (Options.hudPosition == HUDPosition.LEFT) this.drawTexturedQuad(texture, drawContext, BAR_X, BAR_X + width, BAR_Y, BAR_Y + BAR_HEIGHT, 0, 0f, (float)width / (float)BAR_WIDTH, barIndex / 2f, BAR_V2 + barIndex / 2f, barColour); else this.drawHorizontallyMirroredTexturedQuad(texture, drawContext, BAR_X + (BAR_WIDTH - width), BAR_X + BAR_WIDTH, BAR_Y, BAR_Y + BAR_HEIGHT, 0, 0f, (float)width / (float)BAR_WIDTH, barIndex / 2f, BAR_V2 + barIndex / 2f, barColour); } private void renderMountBar (DrawContext drawContext, Identifier texture, int width, int barIndex) { - Vector3f barColour = Options.lerpBarColour((float)width / (float)MOUNT_BAR_WIDTH, barIndex == 1 ? Options.WHITE : Options.unpackedStartHud, Options.unpackedEndHud, barIndex == 0 && Options.hudGradient); + Vector3f barColour = Options.lerpBarColour((float)width / (float)MOUNT_BAR_WIDTH, barIndex == 1 ? Options.WHITE : Options.unpackedDefaultStartHud, Options.unpackedEndHud, barIndex == 0 && Options.hudGradient); if (Options.hudPosition == HUDPosition.LEFT) this.drawTexturedQuad(texture, drawContext, BAR_X, BAR_X + width, BAR_Y + BAR_HEIGHT, BAR_Y + BAR_HEIGHT + MOUNT_BAR_HEIGHT, 0, 0f, ((float)width / (float)MOUNT_BAR_WIDTH) * MOUNT_BAR_U2, MOUNT_BAR_V1 + barIndex / 2f, MOUNT_BAR_V2 + barIndex / 2f, barColour); else this.drawHorizontallyMirroredTexturedQuad(texture, drawContext, BAR_X + (MOUNT_BAR_WIDTH - width) + BAR_WIDTH_DIFF, BAR_X + BAR_WIDTH_DIFF + MOUNT_BAR_WIDTH, BAR_Y + BAR_HEIGHT, BAR_Y + BAR_HEIGHT + MOUNT_BAR_HEIGHT, 0, 0f, ((float)width / (float)MOUNT_BAR_WIDTH) * MOUNT_BAR_U2, MOUNT_BAR_V1 + barIndex / 2f, MOUNT_BAR_V2 + barIndex / 2f, barColour); + } private void reset () { diff --git a/src/main/java/com/provismet/provihealth/interfaces/IMixinEntityRenderState.java b/src/main/java/com/provismet/provihealth/interfaces/IMixinEntityRenderState.java index 6089fde..eec89ff 100644 --- a/src/main/java/com/provismet/provihealth/interfaces/IMixinEntityRenderState.java +++ b/src/main/java/com/provismet/provihealth/interfaces/IMixinEntityRenderState.java @@ -2,6 +2,8 @@ import com.provismet.provihealth.util.HealthContainer; import net.minecraft.text.Text; +import net.minecraft.entity.Entity; + import org.jetbrains.annotations.Nullable; import java.util.List; @@ -15,6 +17,7 @@ public interface IMixinEntityRenderState { void provi_Health$setShouldRenderLabel (boolean value); void provi_Health$setLabel (Text label); void provi_Health$setTeamColour (Integer colour); + void provi_Health$setEntityType (Entity entity); boolean provi_Health$shouldRenderHealth (); HealthContainer provi_Health$getHealth (); @@ -23,5 +26,6 @@ public interface IMixinEntityRenderState { List provi_Health$getTitles (); boolean provi_Health$shouldRenderLabel (); Text provi_Health$getLabel (); + Entity provi_Health$getEntityType (); @Nullable Integer provi_Health$getTeamColour (); } diff --git a/src/main/java/com/provismet/provihealth/interfaces/IMixinLivingEntity.java b/src/main/java/com/provismet/provihealth/interfaces/IMixinLivingEntity.java index 1f78cf2..d83753a 100644 --- a/src/main/java/com/provismet/provihealth/interfaces/IMixinLivingEntity.java +++ b/src/main/java/com/provismet/provihealth/interfaces/IMixinLivingEntity.java @@ -10,4 +10,5 @@ public interface IMixinLivingEntity { HealthContainer provi_Health$getHealthContainer (); HealthContainer provi_Health$getMountHealthContainer (); List> provi_Health$getClientSideStatusEffects (); + int provi_Health$getAnger (); } diff --git a/src/main/java/com/provismet/provihealth/mixin/EntityRenderStateMixin.java b/src/main/java/com/provismet/provihealth/mixin/EntityRenderStateMixin.java index 883a68c..1a2f08a 100644 --- a/src/main/java/com/provismet/provihealth/mixin/EntityRenderStateMixin.java +++ b/src/main/java/com/provismet/provihealth/mixin/EntityRenderStateMixin.java @@ -3,6 +3,7 @@ import com.provismet.provihealth.interfaces.IMixinEntityRenderState; import com.provismet.provihealth.util.HealthContainer; import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.entity.Entity; import net.minecraft.text.Text; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; @@ -36,6 +37,9 @@ public abstract class EntityRenderStateMixin implements IMixinEntityRenderState @Unique private Integer teamColour = null; + @Unique + private Entity entityType; + @Override public void provi_Health$setShouldRenderHealth (boolean value) { this.shouldRenderHealth = value; @@ -76,6 +80,11 @@ public abstract class EntityRenderStateMixin implements IMixinEntityRenderState this.teamColour = colour; } + @Override + public void provi_Health$setEntityType (Entity entity) { + this.entityType = entity; + } + @Override public boolean provi_Health$shouldRenderHealth () { return this.shouldRenderHealth; @@ -111,6 +120,11 @@ public abstract class EntityRenderStateMixin implements IMixinEntityRenderState return this.healthBarLabel; } + @Override + public Entity provi_Health$getEntityType () { + return this.entityType; + } + @Override @Nullable public Integer provi_Health$getTeamColour () { diff --git a/src/main/java/com/provismet/provihealth/mixin/EntityRendererMixin.java b/src/main/java/com/provismet/provihealth/mixin/EntityRendererMixin.java index dc784bd..f750824 100644 --- a/src/main/java/com/provismet/provihealth/mixin/EntityRendererMixin.java +++ b/src/main/java/com/provismet/provihealth/mixin/EntityRendererMixin.java @@ -68,6 +68,7 @@ private void modifyRenderState (Entity entity, EntityRenderState state, float ti mixinState.provi_Health$setShouldRenderHealth(Options.shouldRenderHealthFor(living)); mixinState.provi_Health$setIsLiving(true); mixinState.provi_Health$setShouldRenderLabel(this.hasLabel(entity, state.squaredDistanceToCamera)); + mixinState.provi_Health$setEntityType(entity); if (entity.getDisplayName() != null) mixinState.provi_Health$setLabel(entity.getDisplayName()); else mixinState.provi_Health$setLabel(entity.getName()); diff --git a/src/main/java/com/provismet/provihealth/mixin/LivingEntityMixin.java b/src/main/java/com/provismet/provihealth/mixin/LivingEntityMixin.java index 8c8ea85..ff84336 100644 --- a/src/main/java/com/provismet/provihealth/mixin/LivingEntityMixin.java +++ b/src/main/java/com/provismet/provihealth/mixin/LivingEntityMixin.java @@ -28,6 +28,7 @@ import java.util.Comparator; import java.util.List; import java.util.Objects; +import java.util.Random; @Mixin(LivingEntity.class) public abstract class LivingEntityMixin extends Entity implements IMixinLivingEntity { @@ -41,6 +42,12 @@ protected LivingEntityMixin (EntityType type, World world) { @Unique private HealthContainer mountContainer; + @Unique + private String[] instantKillMessages = {"INSTA-KILL!", "INSTANT KILL!", "DECIMATED!", "VAPORISED!", "ONE-HIT KILL!", "FATALITY!"}; + + @Unique + private String[] deathMessages = {"Killed", "Boom", "Dead", "Eliminated", "Removed from Equation", "Finished"}; + @Shadow public abstract float getHealth(); @@ -48,6 +55,7 @@ protected LivingEntityMixin (EntityType type, World world) { public abstract float getMaxHealth(); @Shadow @Final private static TrackedData> POTION_SWIRLS; + // @Shadow protected int lastAttackTimer; @Override public HealthContainer provi_Health$getHealthContainer () { @@ -74,6 +82,16 @@ protected LivingEntityMixin (EntityType type, World world) { .toList(); } + // @Override + // public boolean provi_Health$isAngryAtPlayer () { + // return this.lastAttackTimer > 0; + // } + + // @Override + // public int provi_Health$getAnger () { + // return this.lastAttackTimer; + // } + @Inject(method="tick", at=@At("TAIL")) private void spawnParticles (CallbackInfo info) { if (this.container == null) this.container = new HealthContainer(this.getHealth()); @@ -86,7 +104,13 @@ private void spawnParticles (CallbackInfo info) { final Entity cameraEntity = MinecraftClient.getInstance().getCameraEntity(); if (cameraEntity != null && this != cameraEntity && this.distanceTo(MinecraftClient.getInstance().getCameraEntity()) <= Options.maxParticleDistance) { - if (this.container.getCurrent() < this.container.getPrevious() && Options.spawnDamageParticles) { + if (this.container.getCurrent() <= 0 && this.container.getPrevious() == this.container.getMax() && Options.spawnDamageParticles && Options.spawnKillText) { + this.getWorld().addParticleClient(new HealthParticleEffect(Options.unpackedDamage, Options.damageAlpha, Options.particleScale, Options.damageParticleTextColour, instantKillMessages[new Random().nextInt(instantKillMessages.length)]), this.getX(), this.getEyeY(), this.getZ(), 0f, 0f, 0f); + } + else if (this.container.getCurrent() <= 0 && this.container.getCurrent() < this.container.getPrevious() && Options.spawnDamageParticles && Options.spawnKillText) { + this.getWorld().addParticleClient(new HealthParticleEffect(Options.unpackedDamage, Options.damageAlpha, Options.particleScale * 1.5f, Options.damageParticleTextColour, deathMessages[new Random().nextInt(deathMessages.length)]), this.getX(), this.getEyeY(), this.getZ(), 0f, 0f, 0f); + } + else if (this.container.getCurrent() < this.container.getPrevious() && Options.spawnDamageParticles) { this.getWorld().addParticleClient(new HealthParticleEffect(Options.unpackedDamage, Options.damageAlpha, Options.particleScale, Options.damageParticleTextColour, String.format("%d", (int)this.container.getPrevious() - (int)this.container.getCurrent())), this.getX(), this.getEyeY(), this.getZ(), 0f, 0f, 0f); } else if (this.container.getCurrent() > this.container.getPrevious() && Options.spawnHealingParticles) { diff --git a/src/main/java/com/provismet/provihealth/particle/TextParticleEffect.java b/src/main/java/com/provismet/provihealth/particle/TextParticleEffect.java index ede7255..6e883de 100644 --- a/src/main/java/com/provismet/provihealth/particle/TextParticleEffect.java +++ b/src/main/java/com/provismet/provihealth/particle/TextParticleEffect.java @@ -15,7 +15,8 @@ public record TextParticleEffect (float scale, int textColour, String text) implements ParticleEffect { private final static Codec TEXT_CODEC = Codec.string(1, 8).validate(text -> { try { - Integer.valueOf(text); + // Integer.valueOf(text); + // String.valueOf(text); return DataResult.success(text); } catch (Exception e) { return DataResult.error(() -> "Text must be an integer: " + text); diff --git a/src/main/java/com/provismet/provihealth/util/FunctionalUtilities.java b/src/main/java/com/provismet/provihealth/util/FunctionalUtilities.java new file mode 100644 index 0000000..624c044 --- /dev/null +++ b/src/main/java/com/provismet/provihealth/util/FunctionalUtilities.java @@ -0,0 +1,65 @@ +package com.provismet.provihealth.util; + +import org.joml.Vector3f; + +import com.provismet.provihealth.config.Options; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.mob.Angerable; +import net.minecraft.entity.mob.EndermanEntity; +import net.minecraft.entity.mob.HoglinEntity; +import net.minecraft.entity.mob.HostileEntity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.entity.mob.PiglinEntity; +import net.minecraft.entity.passive.LlamaEntity; +import net.minecraft.entity.passive.TameableEntity; + +public class FunctionalUtilities { + public static Vector3f deduceColour (LivingEntity entity, boolean inHud) { + + // ? Llamas are neutral in behaviour but do not extend Angerable, so they need their own checks + // ? If a neutral mob is angered, the bar changes colours to hostile colours. + // ? Neutrality is checked first, because Endermen, Zombie Piglins, and other Angerable AND HostileEntity mobs should be checked here + // ? before hostility, as they are not hostile unless provoked. + // ? Tameable Angerable mobs only appear with neutral colours if they are untamed. Once tamed they are passive + + // ~ Neutral Aggression Level + if (Options.useHudAggressionColours && ( + // * If the target is a *non-angered* but angerable tameable mob and is not tamed + (entity instanceof Angerable && entity instanceof TameableEntity && !(((TameableEntity)(entity)).isTamed() && !((Angerable)entity).hasAngerTime())) + // * If the target is a LlamaEntity + || (entity instanceof LlamaEntity) + // * If the target is a *non-angered* Enderman - Endermen have their own Anger TrackedData + || (entity instanceof EndermanEntity && !((EndermanEntity)entity).isAngry()) + // * If the target is a *non-angered* PiglinEntity (these entities are not Angerable, only HostileEntities) + || (entity instanceof PiglinEntity && !((MobEntity)entity).isAttacking()) + // * If the target is a generic *non-angered* but angerable untameable mob (not an Enderman) + || (entity instanceof Angerable && !(entity instanceof TameableEntity) && !(entity instanceof EndermanEntity) && !((Angerable)entity).hasAngerTime() && !((MobEntity)entity).isAttacking()) + )) { + if (inHud) return Options.unpackedNeutralStartHud; + else return Options.unpackedNeutralStartWorld; + } + + // ~ Aggressive/Hostile Aggression Level + else if (Options.useWorldAggressionColours && ( + // * If the target is a Hostile Entity, or a Hoglin (which are passive in the code) + (entity instanceof HostileEntity || entity instanceof HoglinEntity) + // * If the target is an angered tameable mob and is not tamed + || (entity instanceof Angerable && entity instanceof TameableEntity && !(((TameableEntity)(entity)).isTamed() && ((Angerable)entity).hasAngerTime())) + // * If the target is an angered Enderman + || (entity instanceof EndermanEntity && ((EndermanEntity)entity).isAngry()) + // * If the target is a generic angered untameable mob + || (entity instanceof Angerable && !(entity instanceof TameableEntity) && (((Angerable)entity).hasAngerTime() || ((MobEntity)entity).isAttacking())) + + )) { + if (inHud) return Options.unpackedHostileStartHud; + else return Options.unpackedHostileStartWorld; + } + + // ~ Passive and Default Aggression Level (all passive mobs and modded mobs that do not extend vanilla classes) + if (inHud) return Options.unpackedDefaultStartHud; + else return Options.unpackedDefaultStartWorld; + } + + +} diff --git a/src/main/java/com/provismet/provihealth/world/EntityHealthBar.java b/src/main/java/com/provismet/provihealth/world/EntityHealthBar.java index 88488e5..3940283 100644 --- a/src/main/java/com/provismet/provihealth/world/EntityHealthBar.java +++ b/src/main/java/com/provismet/provihealth/world/EntityHealthBar.java @@ -1,27 +1,35 @@ package com.provismet.provihealth.world; +import com.mojang.blaze3d.opengl.GlStateManager; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.provismet.provihealth.interfaces.IMixinEntityRenderState; +import com.provismet.provihealth.interfaces.IMixinLivingEntity; +import com.provismet.provihealth.util.FunctionalUtilities; + +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.entity.state.LivingEntityRenderState; +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +import net.minecraft.util.math.Vec3d; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import com.provismet.provihealth.ProviHealthClient; import com.provismet.provihealth.config.Options; import com.provismet.provihealth.config.Options.SeeThroughText; -import com.provismet.provihealth.interfaces.IMixinEntityRenderState; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.font.TextRenderer.TextLayerType; import net.minecraft.client.render.LightmapTextureManager; -import net.minecraft.client.render.RenderLayer; import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.state.EntityRenderState; -import net.minecraft.client.render.entity.state.LivingEntityRenderState; -import net.minecraft.client.render.entity.state.PlayerEntityRenderState; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import org.joml.Matrix4f; -import org.joml.Quaternionf; -import org.joml.Vector3f; import java.util.List; @@ -167,6 +175,10 @@ private static void renderBar (IMixinEntityRenderState state, Matrix4f model, Ve final float Z = (float)index * -0.0001f; + + Entity entity = state.provi_Health$getEntityType(); // Store to avoid constant calls in checks + + Vector3f colour; if (!Options.tintBackground && index == 1) { colour = Options.WHITE; @@ -174,9 +186,8 @@ private static void renderBar (IMixinEntityRenderState state, Matrix4f model, Ve else if (Options.useTeamColours && state.provi_Health$getTeamColour() instanceof Integer teamColour) { colour = Vec3d.unpackRgb(teamColour).toVector3f(); } - else { - colour = Options.lerpBarColour(healthPercentage, Options.unpackedStartWorld, Options.unpackedEndWorld, Options.worldGradient); - } + + else colour = Options.lerpBarColour(healthPercentage, FunctionalUtilities.deduceColour((LivingEntity)entity, false), Options.unpackedEndWorld, isMount); int maxLight = 0xF000F0; vertexConsumer.vertex(model, MIN_X, MIN_Y, Z).texture(MIN_U, MIN_V).light(maxLight).color(colour.x, colour.y, colour.z, 1f); // Top-Left