55
66package meteordevelopment .meteorclient .systems .hud .elements ;
77
8- import meteordevelopment .meteorclient .renderer .text .TextRenderer ;
98import meteordevelopment .meteorclient .settings .*;
109import meteordevelopment .meteorclient .systems .hud .Hud ;
1110import meteordevelopment .meteorclient .systems .hud .HudElement ;
@@ -33,7 +32,7 @@ public class ArmorHud extends HudElement {
3332 .name ("orientation" )
3433 .description ("How to display armor." )
3534 .defaultValue (Orientation .Horizontal )
36- .onChanged (_ -> calculateSize ())
35+ .onChanged (_ -> calculateSize (HudRenderer . INSTANCE ))
3736 .build ()
3837 );
3938
@@ -57,7 +56,7 @@ public class ArmorHud extends HudElement {
5756 .name ("durability" )
5857 .description ("How to display armor durability." )
5958 .defaultValue (Durability .Bar )
60- .onChanged (_ -> calculateSize ())
59+ .onChanged (_ -> calculateSize (HudRenderer . INSTANCE ))
6160 .build ()
6261 );
6362
@@ -83,7 +82,7 @@ public class ArmorHud extends HudElement {
8382 .name ("custom-scale" )
8483 .description ("Applies a custom scale to this hud element." )
8584 .defaultValue (false )
86- .onChanged (_ -> calculateSize ())
85+ .onChanged (_ -> calculateSize (HudRenderer . INSTANCE ))
8786 .build ()
8887 );
8988
@@ -92,7 +91,7 @@ public class ArmorHud extends HudElement {
9291 .description ("Custom scale." )
9392 .visible (customScale ::get )
9493 .defaultValue (2 )
95- .onChanged (_ -> calculateSize ())
94+ .onChanged (_ -> calculateSize (HudRenderer . INSTANCE ))
9695 .min (0.5 )
9796 .sliderRange (0.5 , 3 )
9897 .build ()
@@ -118,26 +117,94 @@ public class ArmorHud extends HudElement {
118117 public ArmorHud () {
119118 super (INFO );
120119
121- calculateSize ();
120+ calculateSize (HudRenderer . INSTANCE );
122121 }
123122
124- private void calculateSize () {
125- switch (orientation .get ()) {
126- // Four item stacks plus
127- case Horizontal -> setSize ((16 * 4 + 2 * 4 ) * getScale (), 16 * getScale ());
128- case Vertical -> setSize (16 * getScale (), (16 * 4 + 2 * 4 ) * getScale ());
129- }
123+ @ Override
124+ public void tick (HudRenderer renderer ) {
125+ calculateSize (renderer );
130126 }
131127
132- @ Override
133- public void render (HudRenderer renderer ) {
134- int emptySlots = 0 ;
128+ private boolean showsDurabilityText () {
129+ return durability .get () == Durability .Total || durability .get () == Durability .Percentage ;
130+ }
131+
132+ private double getIconSize () {
133+ return 16 * getScale ();
134+ }
135135
136+ private double getPadding () {
137+ return 2 * getScale ();
138+ }
139+
140+ // Durability text scale relative to the icon scale: 1x (normal HUD text scale) at the default
141+ // icon scale, growing/shrinking as the icon's custom scale changes. Uses a square root so the
142+ // text doesn't grow as aggressively as the icon does at the higher end of the scale slider.
143+ private double getTextScale () {
144+ return Math .sqrt (getScale () / scale .getDefaultValue ().floatValue ()) * Hud .get ().getTextScale ();
145+ }
146+
147+ // Spacing between items along the main layout axis: columns in Horizontal, rows in Vertical.
148+ // The durability text doesn't affect this since it's drawn on the cross axis (below in Horizontal,
149+ // to the right in Vertical), not between items.
150+ private double getItemStride () {
151+ return getIconSize () + getPadding ();
152+ }
153+
154+ private ItemStack [] getArmorItems () {
136155 // default order is from boots to helmet
137- ItemStack [] armor = flipOrder .get () ?
156+ return flipOrder .get () ?
138157 new ItemStack []{getItem (EquipmentSlot .HEAD ), getItem (EquipmentSlot .CHEST ), getItem (EquipmentSlot .LEGS ), getItem (EquipmentSlot .FEET )} :
139158 new ItemStack []{getItem (EquipmentSlot .FEET ), getItem (EquipmentSlot .LEGS ), getItem (EquipmentSlot .CHEST ), getItem (EquipmentSlot .HEAD )};
159+ }
160+
161+ private String getDurabilityText (ItemStack itemStack ) {
162+ return switch (durability .get ()) {
163+ case Total -> Integer .toString (itemStack .getMaxDamage () - itemStack .getDamageValue ());
164+ case Percentage ->
165+ Integer .toString (Math .round (((itemStack .getMaxDamage () - itemStack .getDamageValue ()) * 100f ) / (float ) itemStack .getMaxDamage ()));
166+ default -> "" ;
167+ };
168+ }
140169
170+ // Widest durability text among the currently displayed items, used to size the Vertical orientation's width.
171+ private double getMaxDurabilityTextWidth (HudRenderer renderer ) {
172+ double maxWidth = 0 ;
173+
174+ for (ItemStack stack : getArmorItems ()) {
175+ if (!stack .isDamageableItem ()) continue ;
176+ maxWidth = Math .max (maxWidth , renderer .textWidth (getDurabilityText (stack ), durabilityShadow .get (), getTextScale ()));
177+ }
178+
179+ return maxWidth ;
180+ }
181+
182+ private void calculateSize (HudRenderer renderer ) {
183+ double iconSize = getIconSize ();
184+ double stride = getItemStride ();
185+ boolean showsText = showsDurabilityText ();
186+
187+ switch (orientation .get ()) {
188+ case Horizontal -> {
189+ // Text sits below each icon, so it grows the box's height.
190+ double height = iconSize ;
191+ if (showsText ) height += getPadding () + renderer .textHeight (durabilityShadow .get (), getTextScale ());
192+ setSize (stride * 4 , height );
193+ }
194+ case Vertical -> {
195+ // Text sits to the right of each icon, so it grows the box's width instead of its height.
196+ double width = iconSize ;
197+ if (showsText ) width += getPadding () + getMaxDurabilityTextWidth (renderer );
198+ setSize (width , stride * 4 );
199+ }
200+ }
201+ }
202+
203+ @ Override
204+ public void render (HudRenderer renderer ) {
205+ ItemStack [] armor = getArmorItems ();
206+
207+ int emptySlots = 0 ;
141208 for (ItemStack stack : armor ) {
142209 if (stack .isEmpty ()) emptySlots ++;
143210 }
@@ -150,40 +217,42 @@ public void render(HudRenderer renderer) {
150217 double x = this .x ;
151218 double y = this .y ;
152219
220+ double iconSize = getIconSize ();
221+ double padding = getPadding ();
222+ double stride = getItemStride ();
223+ boolean showsText = showsDurabilityText ();
224+ boolean vertical = orientation .get () == Orientation .Vertical ;
225+
153226 double armorX , armorY ;
154227
155228 for (int position = 0 ; position < 4 ; position ++) {
156229 ItemStack itemStack = armor [position ];
157230
158- if (orientation . get () == Orientation . Vertical ) {
231+ if (vertical ) {
159232 armorX = x ;
160- armorY = y + position * 18 * getScale () ;
233+ armorY = y + position * stride ;
161234 } else {
162- armorX = x + position * 18 * getScale () ;
235+ armorX = x + position * stride ;
163236 armorY = y ;
164237 }
165238
166239 renderer .item (itemStack , (int ) armorX , (int ) armorY , getScale (), (itemStack .isDamageableItem () && durability .get () == Durability .Bar ));
167240
168- if (itemStack .isDamageableItem () && durability .get () != Durability .Bar && durability .get () != Durability .None ) {
169- String message = switch (durability .get ()) {
170- case Total -> Integer .toString (itemStack .getMaxDamage () - itemStack .getDamageValue ());
171- case Percentage ->
172- Integer .toString (Math .round (((itemStack .getMaxDamage () - itemStack .getDamageValue ()) * 100f ) / (float ) itemStack .getMaxDamage ()));
173- default -> "err" ;
174- };
175-
176- double messageWidth = renderer .textWidth (message );
241+ if (itemStack .isDamageableItem () && showsText && durability .get () != Durability .Bar ) {
242+ String message = getDurabilityText (itemStack );
243+ double messageWidth = renderer .textWidth (message , durabilityShadow .get (), getTextScale ());
244+ double textHeight = renderer .textHeight (durabilityShadow .get (), getTextScale ());
177245
178- if (orientation .get () == Orientation .Vertical ) {
179- armorX = x + 8 * getScale () - messageWidth / 2.0 ;
180- armorY = y + (18 * position * getScale ()) + (18 * getScale () - renderer .textHeight ());
246+ double textX , textY ;
247+ if (vertical ) {
248+ textX = armorX + iconSize + padding ;
249+ textY = armorY + iconSize / 2.0 - textHeight / 2.0 ;
181250 } else {
182- armorX = x + 18 * position * getScale () + 8 * getScale () - messageWidth / 2.0 ;
183- armorY = y + ( getHeight () - renderer . textHeight ()) ;
251+ textX = armorX + iconSize / 2.0 - messageWidth / 2.0 ;
252+ textY = armorY + iconSize + padding ;
184253 }
185254
186- TextRenderer . get (). render ( message , armorX , armorY , durabilityColor .get (), durabilityShadow .get ());
255+ renderer . text ( message , textX , textY , durabilityColor .get (), durabilityShadow .get (), getTextScale ());
187256 }
188257 }
189258 });
0 commit comments