diff --git a/src/main/java/top/fpsmaster/features/impl/InterfaceModule.java b/src/main/java/top/fpsmaster/features/impl/InterfaceModule.java
index 3e55771c..ef99eb25 100644
--- a/src/main/java/top/fpsmaster/features/impl/InterfaceModule.java
+++ b/src/main/java/top/fpsmaster/features/impl/InterfaceModule.java
@@ -7,8 +7,33 @@
import top.fpsmaster.features.settings.impl.NumberSetting;
import java.awt.*;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Set;
+/**
+ * Base for HUD modules.
+ *
+ *
The shared appearance settings below are consumed by {@code Component.drawRect} and
+ * {@code Component.drawString} — by the base class, never by the subclass that inherits them.
+ * Registration therefore belongs here too. Subclasses used to call {@code addSettings(...)} for them
+ * by hand, which drifted badly: some registered none (the settings still took effect but were
+ * invisible in the ClickGUI and never persisted), several registered the same setting twice
+ * (duplicate rows bound to one value), and none of it changed behaviour either way.
+ *
+ *
Subclasses now declare their {@link Trait}s and register only their own settings;
+ * {@link #registerCommonSettings()} is applied centrally once every module is constructed.
+ */
public class InterfaceModule extends Module {
+ /** What a HUD module draws, which decides the shared settings that apply to it. */
+ public enum Trait {
+ /** Draws a background panel: {@code bg}, {@code backgroundColor}, {@code rounded}, {@code roundRadius}. */
+ BACKGROUND,
+ /** Draws text: {@code betterFont}, {@code fontShadow}. */
+ TEXT,
+ /** Lays out repeated items and honours {@code spacing}. */
+ SPACING
+ }
public BooleanSetting rounded = new BooleanSetting("Round", true);
public NumberSetting roundRadius = new NumberSetting("RoundRadius", 3, 0, 30, 1, () -> rounded.getValue());
@@ -16,13 +41,45 @@ public class InterfaceModule extends Module {
public BooleanSetting fontShadow = new BooleanSetting("FontShadow", true);
public BooleanSetting bg = new BooleanSetting("Background", true);
public ColorSetting backgroundColor = new ColorSetting("BackgroundColor", new Color(0, 0, 0, 0), () -> bg.getValue());
- public NumberSetting spacing = new NumberSetting("Spacing",0,0,3,1);
+ public NumberSetting spacing = new NumberSetting("Spacing", 0, 0, 3, 1);
+
+ /** For modules that draw neither a panel nor text — pass this rather than an empty arg list,
+ * which would resolve to the two-arg constructor and silently pick up the defaults. */
+ public static final Trait[] NONE = new Trait[0];
+ private final Set traits;
+ /** Most HUD modules draw a background panel with text on it. */
public InterfaceModule(String name, Category category) {
- super(name, category);
+ this(name, category, Trait.BACKGROUND, Trait.TEXT);
}
-}
+ public InterfaceModule(String name, Category category, Trait... traits) {
+ super(name, category);
+ this.traits = traits.length == 0
+ ? EnumSet.noneOf(Trait.class)
+ : EnumSet.copyOf(Arrays.asList(traits));
+ }
+ public boolean has(Trait trait) {
+ return traits.contains(trait);
+ }
+ /**
+ * Appends the shared settings this module's traits call for. Called once from
+ * {@code ModuleManager.init()} after every module is constructed, so a module's own settings stay
+ * at the top of its ClickGUI panel and the shared appearance ones follow. Idempotent —
+ * {@code addSettings} ignores anything already registered.
+ */
+ public void registerCommonSettings() {
+ if (has(Trait.BACKGROUND)) {
+ addSettings(bg, backgroundColor, rounded, roundRadius);
+ }
+ if (has(Trait.TEXT)) {
+ addSettings(betterFont, fontShadow);
+ }
+ if (has(Trait.SPACING)) {
+ addSettings(spacing);
+ }
+ }
+}
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ArmorDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ArmorDisplay.java
index f1c298ba..9568abd4 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ArmorDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ArmorDisplay.java
@@ -8,9 +8,8 @@ public class ArmorDisplay extends InterfaceModule {
public static ModeSetting mode = new ModeSetting("Mode", 0, "SimpleHoriz", "SimpleVertical", "Vertical");
public ArmorDisplay() {
- super("ArmorDisplay", Category.Interface);
- addSettings(rounded, backgroundColor, fontShadow, betterFont, spacing, mode, bg, rounded, roundRadius);
+ super("ArmorDisplay", Category.Interface, Trait.BACKGROUND, Trait.TEXT, Trait.SPACING);
+ addSettings(mode);
}
}
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/BetterChat.java b/src/main/java/top/fpsmaster/features/impl/interfaces/BetterChat.java
index 540b2dd2..f8237ca3 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/BetterChat.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/BetterChat.java
@@ -25,10 +25,9 @@ public class BetterChat extends InterfaceModule {
private static java.lang.reflect.Field chatLinesField;
private static java.lang.reflect.Field drawnChatLinesField;
-
public BetterChat() {
super("BetterChat", Category.Interface);
- addSettings(foldMessage, copyMessage, backgroundColor, fontShadow, betterFont, bg);
+ addSettings(foldMessage, copyMessage);
}
@Override
@@ -109,5 +108,3 @@ private static java.util.List getDrawnChatLines(GuiNewChat chat) {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/BlockIndicator.java b/src/main/java/top/fpsmaster/features/impl/interfaces/BlockIndicator.java
index 1c8dc3f0..bff56012 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/BlockIndicator.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/BlockIndicator.java
@@ -18,6 +18,6 @@ public class BlockIndicator extends InterfaceModule {
public BlockIndicator() {
super("BlockIndicator", Category.Interface);
backgroundColor.setColor(new Color(18, 20, 26, 190));
- addSettings(showId, showCoords, yOffset, bg, rounded, roundRadius, backgroundColor, panelColor, accentColor);
+ addSettings(showId, showCoords, yOffset, panelColor, accentColor);
}
}
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/CPSDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/CPSDisplay.java
index d8e26f00..f972db16 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/CPSDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/CPSDisplay.java
@@ -12,7 +12,6 @@
import java.util.LinkedList;
public class CPSDisplay extends InterfaceModule {
-
private static final LinkedList KEYS = new LinkedList<>();
private static final CPSCounterListener COUNTER_LISTENER = new CPSCounterListener();
private static boolean trackingRegistered = false;
@@ -21,7 +20,6 @@ public CPSDisplay() {
super("CPSDisplay", Category.Interface);
ensureTracking();
addSettings(textColor);
- addSettings(backgroundColor, fontShadow, betterFont, bg, rounded, roundRadius);
}
public static void ensureTracking() {
@@ -69,5 +67,3 @@ private static class Key {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ClockDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ClockDisplay.java
index 0a86240e..fad25134 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ClockDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ClockDisplay.java
@@ -17,6 +17,6 @@ public class ClockDisplay extends InterfaceModule {
public ClockDisplay() {
super("ClockDisplay", Category.Interface);
backgroundColor.setColor(new Color(18, 20, 26, 160));
- addSettings(showSeconds, hour24Mode, label, textColor, betterFont, fontShadow, bg, rounded, roundRadius, backgroundColor);
+ addSettings(showSeconds, hour24Mode, label, textColor);
}
}
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ComboDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ComboDisplay.java
index 5ce48888..daed2fa6 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ComboDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ComboDisplay.java
@@ -11,7 +11,6 @@
import java.awt.*;
public class ComboDisplay extends InterfaceModule {
-
private Entity target = null;
public static int combo = 0;
@@ -19,7 +18,7 @@ public class ComboDisplay extends InterfaceModule {
public ComboDisplay() {
super("ComboDisplay", Category.Interface);
- addSettings(textColor, backgroundColor, betterFont, fontShadow, rounded, bg, rounded, roundRadius);
+ addSettings(textColor);
}
@Subscribe
@@ -27,7 +26,7 @@ public void onTick(EventTick e) {
if (net.minecraft.client.Minecraft.getMinecraft().thePlayer == null) return;
net.minecraft.entity.player.EntityPlayer rawPlayer =
net.minecraft.client.Minecraft.getMinecraft().thePlayer;
-
+
if (rawPlayer.hurtTime == 1 || (target != null && rawPlayer.getDistanceToEntity(target) > 7)) {
combo = 0;
}
@@ -42,5 +41,3 @@ public void attack(EventAttack e) {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/CoordsDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/CoordsDisplay.java
index 33f916e3..b8ceebdd 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/CoordsDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/CoordsDisplay.java
@@ -6,16 +6,13 @@
import top.fpsmaster.features.settings.impl.NumberSetting;
public class CoordsDisplay extends InterfaceModule {
-
public BooleanSetting limitDisplay = new BooleanSetting("LimitDisplay", false);
public NumberSetting limitDisplayY = new NumberSetting("LimitDisplayY", 92, 0, 255, 1);
public CoordsDisplay() {
super("CoordsDisplay", Category.Interface);
- addSettings(rounded, backgroundColor, fontShadow, betterFont, bg, rounded, roundRadius);
+
addSettings(limitDisplay, limitDisplayY);
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/FPSDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/FPSDisplay.java
index e0ee2656..b4c1aa02 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/FPSDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/FPSDisplay.java
@@ -7,15 +7,11 @@
import java.awt.*;
public class FPSDisplay extends InterfaceModule {
-
public static ColorSetting textColor = new ColorSetting("TextColor", new Color(255, 255, 255));
public FPSDisplay() {
super("FPSDisplay", Category.Interface);
addSettings(textColor);
- addSettings(rounded, backgroundColor, fontShadow, betterFont, bg, rounded, roundRadius);
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/InventoryDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/InventoryDisplay.java
index 3814b843..085ebf77 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/InventoryDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/InventoryDisplay.java
@@ -6,9 +6,6 @@
public class InventoryDisplay extends InterfaceModule {
public InventoryDisplay() {
super("InventoryDisplay", Category.Interface);
- addSettings(backgroundColor, bg, rounded, roundRadius);
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ItemCountDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ItemCountDisplay.java
index 66fae6a9..662f5d4a 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ItemCountDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ItemCountDisplay.java
@@ -6,18 +6,14 @@
import top.fpsmaster.features.settings.impl.MultipleItemSetting;
public class ItemCountDisplay extends InterfaceModule {
-
//TODO: Custom 自定义物品数量,建议添加MultipleSetting,便于让用户自动添加,暂未实现
public ModeSetting modes = new ModeSetting("mode", 0, "potpvp", "uhc", "custom");
public MultipleItemSetting itemsSetting = new MultipleItemSetting("items",() -> modes.getValue() == 2);
public ItemCountDisplay() {
- super("ItemCountDisplay", Category.Interface);
- addSettings(bg, backgroundColor ,rounded, roundRadius, betterFont, fontShadow, spacing, modes, itemsSetting);
+ super("ItemCountDisplay", Category.Interface, Trait.BACKGROUND, Trait.TEXT, Trait.SPACING);
+ addSettings(modes, itemsSetting);
}
-
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/Keystrokes.java b/src/main/java/top/fpsmaster/features/impl/interfaces/Keystrokes.java
index 5639ad0e..5b5d8469 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/Keystrokes.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/Keystrokes.java
@@ -38,17 +38,10 @@ public class Keystrokes extends InterfaceModule {
public static ModeSetting spaceStyle = new ModeSetting("SpaceStyle", 0, () -> showSpace.getValue(), "Text", "Bar");
public Keystrokes() {
- super("Keystrokes", Category.Interface);
+ super("Keystrokes", Category.Interface, Trait.BACKGROUND, Trait.TEXT, Trait.SPACING);
CPSDisplay.ensureTracking();
roundRadius.setValue(2);
- addSettings(
- fontShadow, betterFont,
- pressedColor, fontColor, pressedFontColor,
- borderColor, borderWidth,
- pressAnimMode, pressAnimColor, pressAnimDuration,
- showSpace, cpsMode, wasdStyle, spaceStyle, spacing, bg, backgroundColor, rounded, roundRadius
- );
+ addSettings(pressedColor, fontColor, pressedFontColor, borderColor, borderWidth, pressAnimMode, pressAnimColor, pressAnimDuration, showSpace, cpsMode, wasdStyle, spaceStyle);
}
}
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/MiniMap.java b/src/main/java/top/fpsmaster/features/impl/interfaces/MiniMap.java
index cef066f7..22548e0e 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/MiniMap.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/MiniMap.java
@@ -8,7 +8,7 @@
public class MiniMap extends InterfaceModule {
public MiniMap() {
- super("MiniMap", Category.Interface);
+ super("MiniMap", Category.Interface, InterfaceModule.NONE);
}
public static boolean using = false;
@@ -34,5 +34,3 @@ public void onDisable() {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ModsList.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ModsList.java
index 3093e36c..240e1f17 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ModsList.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ModsList.java
@@ -9,7 +9,6 @@
import java.awt.*;
public class ModsList extends InterfaceModule {
-
public BooleanSetting showLogo = new BooleanSetting("ShowText", true);
public BooleanSetting english = new BooleanSetting("English", true);
public BooleanSetting rainbow = new BooleanSetting("Rainbow", true);
@@ -18,9 +17,7 @@ public class ModsList extends InterfaceModule {
public ModsList() {
super("ModsList", Category.Interface);
- addSettings(showLogo, text, english, color, rainbow, betterFont, spacing, backgroundColor, bg);
+ addSettings(showLogo, text, english, color, rainbow);
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/PingDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/PingDisplay.java
index d5a7fc12..0d7fcec0 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/PingDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/PingDisplay.java
@@ -10,11 +10,8 @@ public class PingDisplay extends InterfaceModule {
public PingDisplay() {
super("PingDisplay", Category.Interface);
addSettings(textColor);
- addSettings(rounded, backgroundColor, fontShadow, betterFont, bg, rounded, roundRadius);
}
public static ColorSetting textColor = new ColorSetting("TextColor", new Color(255, 255, 255));
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/PlayTime.java b/src/main/java/top/fpsmaster/features/impl/interfaces/PlayTime.java
index f52cf828..168dc51c 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/PlayTime.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/PlayTime.java
@@ -16,6 +16,6 @@ public class PlayTime extends InterfaceModule {
public PlayTime() {
super("PlayTime", Category.Interface);
backgroundColor.setColor(new Color(18, 20, 26, 160));
- addSettings(displayMode, label, textColor, betterFont, fontShadow, bg, rounded, roundRadius, backgroundColor);
+ addSettings(displayMode, label, textColor);
}
}
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/PlayerDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/PlayerDisplay.java
index 33a997c4..abb6d83b 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/PlayerDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/PlayerDisplay.java
@@ -2,13 +2,17 @@
import top.fpsmaster.features.impl.InterfaceModule;
import top.fpsmaster.features.manager.Category;
+import top.fpsmaster.features.settings.impl.ColorSetting;
+
+import java.awt.*;
public class PlayerDisplay extends InterfaceModule {
public PlayerDisplay() {
super("PlayerDisplay", Category.Interface);
- addSettings(betterFont, rounded, fontShadow, backgroundColor, bg, rounded, roundRadius);
+ // This HUD used to paint a hard-coded translucent black panel instead of going through
+ // drawRect, so its background ignored every appearance setting. Now that it uses drawRect,
+ // seed the shared setting with that same colour so the look is unchanged but adjustable.
+ backgroundColor = new ColorSetting("BackgroundColor", new Color(0, 0, 0, 60), () -> bg.getValue());
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java
index 17c27554..ff3afef4 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/PotionDisplay.java
@@ -12,8 +12,8 @@ public class PotionDisplay extends InterfaceModule {
public static NumberSetting reminderTime = new NumberSetting("ReminderTime", 20, 1, 120, 1, () -> noticeableReminder.getValue());
public PotionDisplay() {
- super("PotionDisplay", Category.Interface);
- addSettings(backgroundColor, fontShadow, betterFont, betterAnimation, noticeableReminder, reminderTime, spacing, bg, rounded, roundRadius);
+ super("PotionDisplay", Category.Interface, Trait.BACKGROUND, Trait.TEXT, Trait.SPACING);
+ addSettings(betterAnimation, noticeableReminder, reminderTime);
}
@Override
@@ -29,5 +29,3 @@ public void onDisable() {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ReachDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ReachDisplay.java
index a1731abf..baddca77 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ReachDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ReachDisplay.java
@@ -19,7 +19,7 @@ public class ReachDisplay extends InterfaceModule {
public ReachDisplay() {
super("ReachDisplay", Category.Interface);
- addSettings(rounded, backgroundColor, fontShadow, betterFont, textColor, bg, rounded, roundRadius);
+ addSettings(textColor);
}
@Subscribe
@@ -33,5 +33,3 @@ public void onAttack(EventAttack e) {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/Scoreboard.java b/src/main/java/top/fpsmaster/features/impl/interfaces/Scoreboard.java
index 0c811e7a..18ac4543 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/Scoreboard.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/Scoreboard.java
@@ -10,7 +10,7 @@ public class Scoreboard extends InterfaceModule {
public Scoreboard() {
super("Scoreboard", Category.Interface);
- addSettings(rounded, backgroundColor, fontShadow, betterFont, score, bg, rounded, roundRadius);
+ addSettings(score);
}
@Override
@@ -26,5 +26,3 @@ public void onDisable() {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/interfaces/ServerAddressDisplay.java b/src/main/java/top/fpsmaster/features/impl/interfaces/ServerAddressDisplay.java
index 3b7d52a8..578ac1d3 100644
--- a/src/main/java/top/fpsmaster/features/impl/interfaces/ServerAddressDisplay.java
+++ b/src/main/java/top/fpsmaster/features/impl/interfaces/ServerAddressDisplay.java
@@ -14,6 +14,6 @@ public class ServerAddressDisplay extends InterfaceModule {
public ServerAddressDisplay() {
super("ServerAddressDisplay", Category.Interface);
backgroundColor.setColor(new Color(18, 20, 26, 160));
- addSettings(label, textColor, betterFont, fontShadow, bg, rounded, roundRadius, backgroundColor);
+ addSettings(label, textColor);
}
}
diff --git a/src/main/java/top/fpsmaster/features/impl/utility/Sprint.java b/src/main/java/top/fpsmaster/features/impl/utility/Sprint.java
index eb418721..b924da19 100644
--- a/src/main/java/top/fpsmaster/features/impl/utility/Sprint.java
+++ b/src/main/java/top/fpsmaster/features/impl/utility/Sprint.java
@@ -15,11 +15,10 @@ public class Sprint extends InterfaceModule {
public static boolean sprint = true;
public Sprint() {
- super("Sprint", Category.Utility);
- addSettings(toggleSprint, betterFont);
+ super("Sprint", Category.Utility, Trait.TEXT);
+ addSettings(toggleSprint);
}
-
@Override
public void onEnable() {
super.onEnable();
@@ -56,5 +55,3 @@ public void onDisable() {
}
}
-
-
diff --git a/src/main/java/top/fpsmaster/features/impl/utility/ToggleSneak.java b/src/main/java/top/fpsmaster/features/impl/utility/ToggleSneak.java
index 03220e47..2d29aca3 100644
--- a/src/main/java/top/fpsmaster/features/impl/utility/ToggleSneak.java
+++ b/src/main/java/top/fpsmaster/features/impl/utility/ToggleSneak.java
@@ -17,8 +17,8 @@ public class ToggleSneak extends InterfaceModule {
public static boolean sneak = false;
public ToggleSneak() {
- super("ToggleSneak", Category.Utility);
- addSettings(toggleSneak, toggleKey, betterFont);
+ super("ToggleSneak", Category.Utility, Trait.TEXT);
+ addSettings(toggleSneak, toggleKey);
}
@Override
diff --git a/src/main/java/top/fpsmaster/features/manager/Module.java b/src/main/java/top/fpsmaster/features/manager/Module.java
index f187438f..5840c081 100644
--- a/src/main/java/top/fpsmaster/features/manager/Module.java
+++ b/src/main/java/top/fpsmaster/features/manager/Module.java
@@ -31,14 +31,27 @@ public Module(String name, Category category) {
this.category = category;
}
+ /**
+ * Registration is idempotent by identity. Several modules used to pass the same setting twice,
+ * which rendered a duplicate row in the ClickGUI bound to the same underlying value.
+ */
public void addSettings(Setting>... settings) {
for (Setting> setting : settings) {
- if (setting != null) {
+ if (setting != null && !containsSetting(setting)) {
this.settings.add(setting);
}
}
}
+ private boolean containsSetting(Setting> setting) {
+ for (Setting> existing : this.settings) {
+ if (existing == setting) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public void toggle() {
set(!isEnabled);
}
diff --git a/src/main/java/top/fpsmaster/features/manager/ModuleManager.java b/src/main/java/top/fpsmaster/features/manager/ModuleManager.java
index 11ae43b6..ede51dc8 100644
--- a/src/main/java/top/fpsmaster/features/manager/ModuleManager.java
+++ b/src/main/java/top/fpsmaster/features/manager/ModuleManager.java
@@ -6,6 +6,7 @@
import top.fpsmaster.event.EventDispatcher;
import top.fpsmaster.event.Subscribe;
import top.fpsmaster.event.events.EventKey;
+import top.fpsmaster.features.impl.InterfaceModule;
import top.fpsmaster.features.impl.interfaces.*;
import top.fpsmaster.features.impl.optimizes.*;
import top.fpsmaster.features.impl.render.*;
@@ -141,6 +142,14 @@ public void init() {
modules.add(new HideIndicator());
+ // Shared HUD appearance settings are appended centrally, after each module registered its own,
+ // so every InterfaceModule ends up with a consistent panel regardless of what its constructor did.
+ for (Module m : FPSMaster.moduleManager.modules) {
+ if (m instanceof InterfaceModule) {
+ ((InterfaceModule) m).registerCommonSettings();
+ }
+ }
+
for (Module m : FPSMaster.moduleManager.modules) {
mainPanel.mods.add(new ModuleRenderer(m));
}
diff --git a/src/main/java/top/fpsmaster/modules/logger/ClientLogger.java b/src/main/java/top/fpsmaster/modules/logger/ClientLogger.java
index b3c3b5a8..460fa9c8 100644
--- a/src/main/java/top/fpsmaster/modules/logger/ClientLogger.java
+++ b/src/main/java/top/fpsmaster/modules/logger/ClientLogger.java
@@ -37,6 +37,16 @@ public static void info(String from, String s) {
public static void error(String from, String s) {
logger.error("{} -> {}", from, s);
}
+
+ // Throwable overloads: without these, callers that catch an exception have no way to record it
+ // and the stack trace is silently dropped.
+ public static void error(String s, Throwable throwable) {
+ logger.error(s, throwable);
+ }
+
+ public static void warn(String s, Throwable throwable) {
+ logger.warn(s, throwable);
+ }
}
diff --git a/src/main/java/top/fpsmaster/ui/custom/Component.java b/src/main/java/top/fpsmaster/ui/custom/Component.java
index acdd0548..d7b0aa79 100644
--- a/src/main/java/top/fpsmaster/ui/custom/Component.java
+++ b/src/main/java/top/fpsmaster/ui/custom/Component.java
@@ -42,6 +42,9 @@ public class Component {
public boolean allowScale = false;
+ /** Consecutive render failures; reset on any successful frame. See ComponentsManager. */
+ public int renderFailures = 0;
+
public Position position = Position.LT;
@SuppressWarnings("unchecked")
@@ -91,25 +94,32 @@ public float[] getRealPosition(ScaledResolution sr) {
float guiWidth = sr.getScaledWidth() / 2f * scaleFactor;
float guiHeight = sr.getScaledHeight() / 2f * scaleFactor;
+ // Anchors offset by the component's *rendered* size. width/height are logical units; everything
+ // that touches the drawn box (drawRect, hover, drag clamping, blur mask) multiplies by scale,
+ // so these must too — otherwise a scaled-up right-anchored component overflows the screen edge
+ // by width * (scale - 1).
+ float scaledWidth = width * scale;
+ float scaledHeight = height * scale;
+
switch (position) {
case LT:
rX = x * guiWidth / 2f;
rY = y * guiHeight / 2f;
break;
case RT:
- rX = guiWidth - (x * guiWidth / 2f + width);
+ rX = guiWidth - (x * guiWidth / 2f + scaledWidth);
rY = y * guiHeight / 2f;
break;
case LB:
rX = x * guiWidth / 2f;
- rY = guiHeight - (y * guiHeight / 2f + height);
+ rY = guiHeight - (y * guiHeight / 2f + scaledHeight);
break;
case RB:
- rX = guiWidth - (x * guiWidth / 2f + width);
- rY = guiHeight - (y * guiHeight / 2f + height);
+ rX = guiWidth - (x * guiWidth / 2f + scaledWidth);
+ rY = guiHeight - (y * guiHeight / 2f + scaledHeight);
break;
case CT:
- rX = guiWidth / 2f - width * scale / 2f;
+ rX = guiWidth / 2f - scaledWidth / 2f;
rY = y * guiHeight / 2f;
break;
}
@@ -117,7 +127,7 @@ public float[] getRealPosition(ScaledResolution sr) {
}
public void drawBlurMask(ScaledResolution sr) {
- if (!mod.bg.getValue() || width <= 0f || height <= 0f) {
+ if (!hasBackground() || width <= 0f || height <= 0f) {
return;
}
float[] pos = getRealPosition(sr);
@@ -246,11 +256,20 @@ else if (y < guiHeight / 2f)
this.y = changeY / guiHeight * 2f;
}
+ /**
+ * A module only has a background if its traits say so. Checking {@code bg} alone is not enough:
+ * the field exists on every InterfaceModule and defaults to {@code true}, so a text-only module
+ * such as Sprint would otherwise have a blur mask stamped for a panel it never draws.
+ */
+ public boolean hasBackground() {
+ return mod.has(InterfaceModule.Trait.BACKGROUND) && mod.bg.getValue();
+ }
+
public void drawRect(float x, float y, float width, float height, Color color) {
float scaledWidth = width * scale;
float scaledHeight = height * scale;
- if (mod.bg.getValue()) {
+ if (hasBackground()) {
if (mod.rounded.getValue()) {
Rects.roundedImage(Math.round(x), Math.round(y), Math.round(scaledWidth), Math.round(scaledHeight), mod.roundRadius.getValue().intValue(), color);
} else {
diff --git a/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java b/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java
index 1a9f6152..76072c84 100644
--- a/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java
+++ b/src/main/java/top/fpsmaster/ui/custom/ComponentsManager.java
@@ -1,5 +1,6 @@
package top.fpsmaster.ui.custom;
+import net.minecraft.client.renderer.GlStateManager;
import org.lwjgl.opengl.GL11;
import top.fpsmaster.features.impl.InterfaceModule;
import top.fpsmaster.ui.custom.impl.*;
@@ -59,6 +60,40 @@ public Component getComponent(Class extends InterfaceModule> clazz) {
.orElse(null);
}
+ /** A component failing this many frames in a row is switched off rather than left to spin. */
+ private static final int DISABLE_AFTER_FAILURES = 60;
+
+ /**
+ * Per-frame failures are swallowed on purpose: {@code mc.thePlayer}/{@code theWorld} go null while
+ * changing worlds and several components dereference them unguarded, so without this one NPE would
+ * take down the whole EventRender2D dispatch. What must not happen is logging the same line 60
+ * times a second, so output is rate-limited and the exception itself is finally recorded.
+ */
+ private void onComponentFailure(Component component, String phase, Throwable throwable) {
+ int failures = ++component.renderFailures;
+ // Full detail for the first few, then only on powers of two.
+ if (failures <= 3 || Integer.bitCount(failures) == 1) {
+ ClientLogger.error("Failed to " + phase + " component " + component.mod.name
+ + " (failure #" + failures + ")", throwable);
+ }
+ if (failures == DISABLE_AFTER_FAILURES) {
+ ClientLogger.error("Disabling component " + component.mod.name
+ + " after " + failures + " consecutive failures");
+ component.mod.set(false);
+ }
+ // An exception can leave scissor/stencil/blend enabled and bleed into the rest of the frame.
+ resetRenderState();
+ }
+
+ private void resetRenderState() {
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+ GL11.glDisable(GL11.GL_STENCIL_TEST);
+ GlStateManager.enableTexture2D();
+ GlStateManager.enableBlend();
+ GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ }
+
public void drawBackgroundMasks() {
GL11.glPushMatrix();
net.minecraft.client.gui.ScaledResolution sr = new net.minecraft.client.gui.ScaledResolution(Utility.mc);
@@ -67,8 +102,8 @@ public void drawBackgroundMasks() {
if (component.shouldDisplay()) {
try {
component.drawBlurMask(sr);
- } catch (Exception e) {
- ClientLogger.error("Failed to render component blur mask: " + component.mod.name);
+ } catch (Throwable throwable) {
+ onComponentFailure(component, "mask", throwable);
}
}
});
@@ -97,8 +132,9 @@ public void draw(int mouseX, int mouseY) {
if (component.shouldDisplay()) {
try {
component.display(sr, finalMouseX, finalMouseY);
- } catch (Exception e) {
- ClientLogger.error("Failed to render component: " + component.mod.name);
+ component.renderFailures = 0;
+ } catch (Throwable throwable) {
+ onComponentFailure(component, "render", throwable);
}
}
});
diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/KeystrokesComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/KeystrokesComponent.java
index 1babb09c..40cc1e1a 100644
--- a/src/main/java/top/fpsmaster/ui/custom/impl/KeystrokesComponent.java
+++ b/src/main/java/top/fpsmaster/ui/custom/impl/KeystrokesComponent.java
@@ -257,16 +257,22 @@ private void drawBorderRect(float x, float y, float width, float height, float b
int radius = resolveKeyRadius();
Color border = resolveBorderColor(x, y);
+ // try/finally: bailing out mid-stencil would leave GL_STENCIL_TEST enabled and colorMask
+ // partially closed, which silently discards everything drawn after this component.
StencilUtil.initStencilToWrite();
- Rects.rounded(outerX, outerY, outerW, outerH, radius, new Color(0, 0, 0, 255).getRGB());
- org.lwjgl.opengl.GL11.glStencilFunc(org.lwjgl.opengl.GL11.GL_ALWAYS, 0, 0xFF);
- org.lwjgl.opengl.GL11.glStencilOp(org.lwjgl.opengl.GL11.GL_REPLACE, org.lwjgl.opengl.GL11.GL_REPLACE, org.lwjgl.opengl.GL11.GL_REPLACE);
- Rects.rounded(x, y, scaledW, scaledH, radius, new Color(0, 0, 0, 255).getRGB());
- org.lwjgl.opengl.GL11.glColorMask(true, true, true, true);
- org.lwjgl.opengl.GL11.glStencilFunc(org.lwjgl.opengl.GL11.GL_EQUAL, 1, 0xFF);
- org.lwjgl.opengl.GL11.glStencilOp(org.lwjgl.opengl.GL11.GL_KEEP, org.lwjgl.opengl.GL11.GL_KEEP, org.lwjgl.opengl.GL11.GL_KEEP);
- Rects.rounded(outerX, outerY, outerW, outerH, radius, border.getRGB());
- StencilUtil.uninitStencilBuffer();
+ try {
+ Rects.rounded(outerX, outerY, outerW, outerH, radius, new Color(0, 0, 0, 255).getRGB());
+ org.lwjgl.opengl.GL11.glStencilFunc(org.lwjgl.opengl.GL11.GL_ALWAYS, 0, 0xFF);
+ org.lwjgl.opengl.GL11.glStencilOp(org.lwjgl.opengl.GL11.GL_REPLACE, org.lwjgl.opengl.GL11.GL_REPLACE, org.lwjgl.opengl.GL11.GL_REPLACE);
+ Rects.rounded(x, y, scaledW, scaledH, radius, new Color(0, 0, 0, 255).getRGB());
+ org.lwjgl.opengl.GL11.glColorMask(true, true, true, true);
+ org.lwjgl.opengl.GL11.glStencilFunc(org.lwjgl.opengl.GL11.GL_EQUAL, 1, 0xFF);
+ org.lwjgl.opengl.GL11.glStencilOp(org.lwjgl.opengl.GL11.GL_KEEP, org.lwjgl.opengl.GL11.GL_KEEP, org.lwjgl.opengl.GL11.GL_KEEP);
+ Rects.rounded(outerX, outerY, outerW, outerH, radius, border.getRGB());
+ } finally {
+ org.lwjgl.opengl.GL11.glColorMask(true, true, true, true);
+ StencilUtil.uninitStencilBuffer();
+ }
}
private void updatePressAnims(float dt, float width, float height, boolean pressed) {
diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/MiniMapComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/MiniMapComponent.java
index 48bafb93..6e4c8bbb 100644
--- a/src/main/java/top/fpsmaster/ui/custom/impl/MiniMapComponent.java
+++ b/src/main/java/top/fpsmaster/ui/custom/impl/MiniMapComponent.java
@@ -32,12 +32,14 @@ public MiniMapComponent() {
public void draw(float x, float y) {
super.draw(x, y);
+ // Drawn raw rather than through drawRect (it is a texture, not a panel), so scale is applied
+ // to both the offset and the size here.
Images.draw(
new ResourceLocation("client/gui/minimapbg.png"),
- x + width / 2 - 179 / 4f,
- y + width / 2 - 179 / 4f,
- 179f / 2f,
- 178f / 2f,
+ x + (width / 2 - 179 / 4f) * scale,
+ y + (width / 2 - 179 / 4f) * scale,
+ 179f / 2f * scale,
+ 178f / 2f * scale,
-1
);
@@ -53,7 +55,7 @@ public void draw(float x, float y) {
GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
Minecraft.getMinecraft().entityRenderer.setupOverlayRendering();
float partialTicks = ((IMinecraft) Minecraft.getMinecraft()).arch$getTimer().renderPartialTicks;
- InterfaceHandler.drawInterfaces(width, height, partialTicks);
+ InterfaceHandler.drawInterfaces(width * scale, height * scale, partialTicks);
MinimapAnimation.tick();
GL11.glPopMatrix();
GuiScale.fixScale();
diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/PlayerDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/PlayerDisplayComponent.java
index b4782e03..8dfe0991 100644
--- a/src/main/java/top/fpsmaster/ui/custom/impl/PlayerDisplayComponent.java
+++ b/src/main/java/top/fpsmaster/ui/custom/impl/PlayerDisplayComponent.java
@@ -29,32 +29,32 @@ public void draw(float x, float y) {
for (Entity entity : mc.theWorld.loadedEntityList) {
if (entity instanceof EntityPlayer && !entity.isInvisible()) {
if (i > 10 || entity == mc.thePlayer) continue;
- UFontRenderer s16 = FPSMaster.fontManager.s16;
- String healthText = (int) (((EntityPlayer) entity).getHealth() * 10 / 10) + " hp";
- float hX = s16.getStringWidth(healthText);
- float nX = s16.getStringWidth(entity.getDisplayName().getFormattedText());
-
- Rects.rounded(Math.round(x), Math.round(y + i * 16), Math.round(10 + hX + nX), 14, new Color(0, 0, 0, 60));
- Rects.rounded(
- Math.round(x),
- Math.round(y + i * 16),
- Math.round((10 + hX + nX) * ((EntityPlayer) entity).getHealth() / ((EntityPlayer) entity).getMaxHealth()),
- 14,
- new Color(0, 0, 0, 60)
- );
-
- if (width < 10 + hX + nX) {
- width = 10 + hX + nX;
+ EntityPlayer player = (EntityPlayer) entity;
+ String name = entity.getDisplayName().getFormattedText();
+ String healthText = (int) (player.getHealth() * 10 / 10) + " hp";
+ // Logical (unscaled) widths — drawRect/drawString apply scale themselves.
+ float hX = getStringWidth(16, healthText);
+ float nX = getStringWidth(16, name);
+ float rowWidth = 10 + hX + nX;
+ // Row offsets are positions, so they scale here; sizes scale inside drawRect.
+ float rowY = y + i * 16 * scale;
+
+ drawRect(x, rowY, rowWidth, 14, mod.backgroundColor.getColor());
+ drawRect(x, rowY, rowWidth * player.getHealth() / player.getMaxHealth(), 14,
+ mod.backgroundColor.getColor());
+
+ if (width < rowWidth) {
+ width = rowWidth;
}
- float health = ((EntityPlayer) entity).getHealth();
- float maxHealth = ((EntityPlayer) entity).getMaxHealth();
+ float health = player.getHealth();
+ float maxHealth = player.getMaxHealth();
Color color = health >= maxHealth * 0.8f ? new Color(50, 255, 55) :
health > maxHealth * 0.5f ? new Color(255, 255, 55) :
new Color(255, 55, 55);
- s16.drawString(entity.getDisplayName().getFormattedText(), x + 2, y + i * 16 + 2, -1);
- s16.drawString(healthText, x + 8 + nX, y + i * 16 + 2, color.getRGB());
+ drawString(16, name, x + 2 * scale, rowY + 2 * scale, -1);
+ drawString(16, healthText, x + (8 + nX) * scale, rowY + 2 * scale, color.getRGB());
i++;
}
diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java
index 2b7eaa1d..c21f8915 100644
--- a/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java
+++ b/src/main/java/top/fpsmaster/ui/custom/impl/PotionDisplayComponent.java
@@ -75,13 +75,18 @@ private void drawAnimatedPotion(PotionEffect effect, String title, String durati
if (visible <= 0.01f) {
return;
}
+ // try/finally: if drawPotion throws, an un-popped scissor would clip the entire rest of the
+ // frame — including the whole game view — to this potion row's rectangle.
beginScissor(x, y, scaledWidth * visible, scaledHeight);
GlStateManager.pushMatrix();
- GlStateManager.translate((1f - visible) * -6f * scale, 0f, 0f);
- drawPotion(effect, title, duration, x, y, width);
- drawAccent(effect, x, y);
- GlStateManager.popMatrix();
- endScissor();
+ try {
+ GlStateManager.translate((1f - visible) * -6f * scale, 0f, 0f);
+ drawPotion(effect, title, duration, x, y, width);
+ drawAccent(effect, x, y);
+ } finally {
+ GlStateManager.popMatrix();
+ endScissor();
+ }
}
private void drawPotion(PotionEffect effect, String title, String duration, float x, float y, float width) {
diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/ScoreboardComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/ScoreboardComponent.java
index a53a0f5d..6ffe5df1 100644
--- a/src/main/java/top/fpsmaster/ui/custom/impl/ScoreboardComponent.java
+++ b/src/main/java/top/fpsmaster/ui/custom/impl/ScoreboardComponent.java
@@ -1,7 +1,5 @@
package top.fpsmaster.ui.custom.impl;
-import top.fpsmaster.utils.render.draw.Rects;
-
import top.fpsmaster.features.impl.interfaces.Scoreboard;
import top.fpsmaster.ui.custom.Component;
import net.minecraft.client.Minecraft;
@@ -15,6 +13,9 @@
public class ScoreboardComponent extends Component {
+ /** Matches the vanilla font metrics this HUD was originally laid out against. */
+ private static final int FONT_SIZE = 16;
+
public ScoreboardComponent() {
super(Scoreboard.class);
allowScale = true;
@@ -48,25 +49,29 @@ public void draw(float x, float y) {
filtered = filtered.subList(filtered.size() - 15, filtered.size());
}
- int maxWidth = mc.fontRendererObj.getStringWidth(objective.getDisplayName());
+ // Measure through the base class so BetterFont is honoured; these are logical widths, and
+ // drawRect/drawString apply scale themselves.
+ String title = objective.getDisplayName();
+ float maxWidth = getStringWidth(FONT_SIZE, title);
boolean showScore = Scoreboard.score.getValue();
List lines = new ArrayList<>();
for (Score score : filtered) {
String name = ScorePlayerTeam.formatPlayerName(mcScoreboard.getPlayersTeam(score.getPlayerName()), score.getPlayerName());
String line = showScore ? name + ": " + score.getScorePoints() : name;
lines.add(line);
- maxWidth = Math.max(maxWidth, mc.fontRendererObj.getStringWidth(line));
+ maxWidth = Math.max(maxWidth, getStringWidth(FONT_SIZE, line));
}
- int lineHeight = mc.fontRendererObj.FONT_HEIGHT + 1;
+ float lineHeight = mc.fontRendererObj.FONT_HEIGHT + 1;
width = maxWidth + 6;
height = (lines.size() + 1) * lineHeight + 4;
- Rects.fill(x, y, width, height, mod.backgroundColor.getColor());
- mc.fontRendererObj.drawStringWithShadow(objective.getDisplayName(), x + 3, y + 2, 0xFFFFFF);
- float offsetY = y + 2 + lineHeight;
+ drawRect(x, y, width, height, mod.backgroundColor.getColor());
+ drawString(FONT_SIZE, title, x + 3 * scale, y + 2 * scale, 0xFFFFFF);
+ // Row offsets are positions, so they scale here.
+ float offsetY = y + (2 + lineHeight) * scale;
for (String line : lines) {
- mc.fontRendererObj.drawStringWithShadow(line, x + 3, offsetY, 0xFFFFFF);
- offsetY += lineHeight;
+ drawString(FONT_SIZE, line, x + 3 * scale, offsetY, 0xFFFFFF);
+ offsetY += lineHeight * scale;
}
}
}
diff --git a/src/main/java/top/fpsmaster/ui/custom/impl/TargetHUDComponent.java b/src/main/java/top/fpsmaster/ui/custom/impl/TargetHUDComponent.java
index 8a1c1e0f..33360b9d 100644
--- a/src/main/java/top/fpsmaster/ui/custom/impl/TargetHUDComponent.java
+++ b/src/main/java/top/fpsmaster/ui/custom/impl/TargetHUDComponent.java
@@ -52,7 +52,7 @@ public void draw(float x, float y) {
healthPer = (float) AnimMath.base(healthPer, (health / maxHealth), 0.1);
if (TargetDisplay.targetHUD.getMode() == 0) {
- width = (30 + FPSMaster.fontManager.s16.getStringWidth(name));
+ width = (30 + getStringWidth(16, name));
height = 30f;
// Set color based on health percentage
@@ -66,13 +66,16 @@ public void draw(float x, float y) {
// Draw elements if animation is greater than 1
if (animation > 0.05) {
- Rects.rounded(Math.round(x), Math.round(y), Math.round(width), Math.round(height), new Color(0, 0, 0, (int) animation * 80));
- Rects.rounded(Math.round(x), Math.round(y), Math.round(healthPer * width), Math.round(height), colorAnimation.getColor());
- FPSMaster.fontManager.s16.drawStringWithShadow(name, x + 27, y + 5, -1);
- Images.playerHead((AbstractClientPlayer) target1, x + 5, y + 5, 20, 20);
+ // Panel goes through drawRect so it honours the Background toggle and scale; the health
+ // bar and head stay raw because they are content, not decoration, and must not vanish
+ // when the user turns the background off. Their sizes are scaled explicitly.
+ drawRect(x, y, width, height, new Color(0, 0, 0, (int) animation * 80));
+ Rects.rounded(Math.round(x), Math.round(y), Math.round(healthPer * width * scale), Math.round(height * scale), colorAnimation.getColor());
+ drawString(16, name, x + 27 * scale, y + 5 * scale, -1);
+ Images.playerHead((AbstractClientPlayer) target1, x + 5 * scale, y + 5 * scale, Math.round(20 * scale), Math.round(20 * scale));
}
} else if (TargetDisplay.targetHUD.getValue() == 1) {
- width = (50 + FPSMaster.fontManager.s16.getStringWidth(name));
+ width = (50 + getStringWidth(16, name));
height = 40f;
// Set color based on health percentage
@@ -86,10 +89,10 @@ public void draw(float x, float y) {
// Draw elements if animation is greater than 1
if (animation > 0.05) {
- Rects.roundedImage(Math.round(x), Math.round(y), Math.round(width), Math.round(height), 8, new Color(0, 0, 0, (int) (animation * 120)));
- Rects.roundedImage(Math.round(x + 10), Math.round(y + 30), Math.round(healthPer * (width - 20)), 4, 2, colorAnimation.getColor());
- FPSMaster.fontManager.s18.drawStringWithShadow(name, x + 24, y + 8, new Color(255, 255, 255, (int) (animation * 255)).getRGB());
- Images.playerHead((AbstractClientPlayer) target1, x + 10, y + 8, 12, 12);
+ drawRect(x, y, width, height, new Color(0, 0, 0, (int) (animation * 120)));
+ Rects.roundedImage(Math.round(x + 10 * scale), Math.round(y + 30 * scale), Math.round(healthPer * (width - 20) * scale), Math.round(4 * scale), 2, colorAnimation.getColor());
+ drawString(18, name, x + 24 * scale, y + 8 * scale, new Color(255, 255, 255, (int) (animation * 255)).getRGB());
+ Images.playerHead((AbstractClientPlayer) target1, x + 10 * scale, y + 8 * scale, Math.round(12 * scale), Math.round(12 * scale));
}
}
}
diff --git a/src/main/java/top/fpsmaster/ui/minimap/interfaces/InterfaceHandler.java b/src/main/java/top/fpsmaster/ui/minimap/interfaces/InterfaceHandler.java
index 1184405b..f99c6519 100644
--- a/src/main/java/top/fpsmaster/ui/minimap/interfaces/InterfaceHandler.java
+++ b/src/main/java/top/fpsmaster/ui/minimap/interfaces/InterfaceHandler.java
@@ -128,6 +128,11 @@ public void drawInterface(final int width, final int height, final float partial
GlStateManager.blendFunc(770, 771);
Component component = FPSMaster.componentsManager.getComponent(MiniMap.class);
+ if (component == null) {
+ // getComponent matches on the module's exact class; when the MiniMap module is not
+ // registered the component falls back to a plain InterfaceModule and never matches.
+ return;
+ }
float[] pos = component.getRealPosition();
mc.ingameGUI.drawTexturedModalRect(((int) pos[0]), ((int) pos[1]), 0, 0, (int) ((minimapWidth / 2f + 1) / sizeFix), (int) ((minimapWidth / 2f + 1) / sizeFix));
super.drawInterface(width, height, partial);