From 2838d16f43c99a29f8ed848f747b62dd3b5a22aa Mon Sep 17 00:00:00 2001 From: NamelessJu Date: Mon, 2 Mar 2026 00:45:53 +0100 Subject: [PATCH 1/5] Add time input calculator --- .../categories/UIAndVisualsCategory.java | 22 +++ .../config/configs/UIAndVisualsConfig.java | 10 +- .../mixins/AbstractSignEditScreenMixin.java | 56 ++++++- .../calculators/SignTimeCalculator.java | 142 ++++++++++++++++++ .../assets/skyblocker/lang/en_us.json | 19 +++ 5 files changed, 240 insertions(+), 9 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java diff --git a/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java index f8adf23f860..4500a94eac1 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java @@ -801,6 +801,28 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .controller(ConfigUtils.createBooleanController()) .build()) .build()) + + //Time Input Calculator + .group(OptionGroup.createBuilder() + .name(Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator")) + .collapsed(true) + .option(Option.createBuilder() + .name(Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.enabled")) + .description(Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.enabled.@Tooltip")) + .binding(defaults.uiAndVisuals.timeInputCalculator.enabled, + () -> config.uiAndVisuals.timeInputCalculator.enabled, + newValue -> config.uiAndVisuals.timeInputCalculator.enabled = newValue) + .controller(ConfigUtils.createBooleanController()) + .build()) + .option(Option.createBuilder() + .name(Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter")) + .description(Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter.@Tooltip")) + .binding(defaults.uiAndVisuals.timeInputCalculator.closeSignsWithEnter, + () -> config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter, + newValue -> config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter = newValue) + .controller(ConfigUtils.createBooleanController()) + .build()) + .build()) //Flame Overlay .group(OptionGroup.createBuilder() diff --git a/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java index 6e0323c06d3..4d87b0b86e0 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java @@ -75,6 +75,8 @@ public class UIAndVisualsConfig { public BazaarQuickQuantities bazaarQuickQuantities = new BazaarQuickQuantities(); public InputCalculator inputCalculator = new InputCalculator(); + + public TimeInputCalculator timeInputCalculator = new TimeInputCalculator(); public FlameOverlay flameOverlay = new FlameOverlay(); @@ -410,7 +412,13 @@ public static class InputCalculator { public boolean closeSignsWithEnter = true; } - + + public static class TimeInputCalculator { + public boolean enabled = true; + + public boolean closeSignsWithEnter = true; + } + public static class FlameOverlay { public int flameHeight = 100; diff --git a/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java index 50c6b10149f..dcccb02b8b6 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java @@ -5,6 +5,7 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.bazaar.BazaarQuickQuantities; import de.hysky.skyblocker.skyblock.calculators.SignCalculator; +import de.hysky.skyblocker.skyblock.calculators.SignTimeCalculator; import de.hysky.skyblocker.skyblock.speedpreset.SpeedPresets; import de.hysky.skyblocker.utils.Utils; import net.minecraft.ChatFormatting; @@ -14,6 +15,7 @@ import net.minecraft.client.gui.screens.inventory.AbstractSignEditScreen; import net.minecraft.client.input.KeyEvent; import net.minecraft.network.chat.Component; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -59,18 +61,28 @@ protected AbstractSignEditScreenMixin(Component title) { context.guiWidth() / 2, 55, 0xFFFFFFFF); } } - //if the sign is being used to enter number send it to the sign calculator - else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { - SignCalculator.renderCalculator(context, messages[0], context.guiWidth() / 2, 55); + else { + SignTimeCalculator.TimeType timeInputType = getTimeInputType(); + if (timeInputType != null) { + if (config.uiAndVisuals.timeInputCalculator.enabled) { + SignTimeCalculator.renderTime(context, messages[0], timeInputType, context.guiWidth() / 2, 55); + } + } + //if the sign is being used to enter number send it to the sign calculator + else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { + SignCalculator.renderCalculator(context, messages[0], context.guiWidth() / 2, 55); + } } } } @Inject(method = "keyPressed", at = @At("HEAD")) private void skyblocker$keyPressed(KeyEvent input, CallbackInfoReturnable cir) { - if (SkyblockerConfigManager.get().uiAndVisuals.inputCalculator.closeSignsWithEnter - && Utils.isOnSkyblock() && isInputSign() - && (input.isConfirmation())) this.onClose(); + if (input.isConfirmation() && Utils.isOnSkyblock() + && ( + SkyblockerConfigManager.get().uiAndVisuals.timeInputCalculator.closeSignsWithEnter && getTimeInputType() != null + || SkyblockerConfigManager.get().uiAndVisuals.inputCalculator.closeSignsWithEnter && isInputSign() + )) this.onClose(); } @Inject(method = "onDone", at = @At("HEAD")) @@ -84,6 +96,12 @@ else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { messages[0] = String.valueOf(presets.getPreset(messages[0])); } } + else if (getTimeInputType() != null) { + if (config.uiAndVisuals.timeInputCalculator.enabled) { + String value = SignTimeCalculator.getNewValue(); + if (value != null) messages[0] = value; + } + } //if the sign is being used to enter number get number from calculator for if maths has been done else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { boolean isPrice = messages[2].contains("price"); @@ -99,6 +117,10 @@ else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { @Unique private static final String SPEED_INPUT_MARKER = "speed cap!"; @Unique + private static final String TIME_INPUT_MARKER_HOURS = "hours"; + @Unique + private static final String TIME_INPUT_MARKER_MINUTES = "minutes"; + @Unique private static final String INPUT_SIGN_MARKER = "^^^^^^^^^^^^^^^"; /** This is used for some things like the super craft amount input */ @Unique @@ -110,7 +132,21 @@ else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { private boolean isSpeedInputSign() { return messages[3].equals(SPEED_INPUT_MARKER); } - + + @Unique + private SignTimeCalculator.@Nullable TimeType getTimeInputType() { + if (messages[1].equals(INPUT_SIGN_MARKER)) { + if (messages[3].endsWith(TIME_INPUT_MARKER_HOURS)) { + return SignTimeCalculator.TimeType.HOURS; + } + if (messages[3].endsWith(TIME_INPUT_MARKER_MINUTES)) { + return SignTimeCalculator.TimeType.MINUTES; + } + } + + return null; + } + /** * Used to exclude search signs with {@link AbstractSignEditScreenMixin#INPUT_SIGN_MARKER}. *
Works for /recipes & /shards signs @@ -131,6 +167,10 @@ private boolean isAltInputSearchSign() { @Unique private boolean isInputSign() { - return messages[1].equals(INPUT_SIGN_MARKER) && !isInputSearchSign() || messages[1].equals(ALT_INPUT_SIGN_MARKER) && !isAltInputSearchSign() || messages[1].equals(BAZAAR_FLIP_MARKER); + return ( + messages[1].equals(INPUT_SIGN_MARKER) && !isInputSearchSign() + || messages[1].equals(ALT_INPUT_SIGN_MARKER) && !isAltInputSearchSign() + || messages[1].equals(BAZAAR_FLIP_MARKER) + ) && getTimeInputType() == null; } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java b/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java new file mode 100644 index 00000000000..f32f1b68e15 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java @@ -0,0 +1,142 @@ +package de.hysky.skyblocker.skyblock.calculators; + +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.VisibleForTesting; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SignTimeCalculator +{ + public enum TimeType { + HOURS, MINUTES + } + + private static final Minecraft CLIENT = Minecraft.getInstance(); + private static final Pattern TIME_CODE_PATTERN = Pattern.compile("(\\d+\\.\\d+|\\d+)(\\D+)?"); + private static final int SECONDS_PER_DAY = 86400; + private static final short SECONDS_PER_HOUR = 3600; + private static final byte SECONDS_PER_MINUTE = 60; + + private static @Nullable String lastInput; + private static long seconds; + private static @Nullable Component error = null; + + public static void renderTime(GuiGraphics context, String message, TimeType type, int renderX, int renderY) { + calculate(message, type); + render(context, renderX, renderY); + } + + @VisibleForTesting + public static void calculate(String message, TimeType type) { + //only update if new input + if (message.equals(lastInput)) return; + lastInput = message; + + if (message.isBlank()) { + seconds = -1; + error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.emptyInputError").withStyle(ChatFormatting.RED); + return; + } + + long newSeconds = 0; + for (String segment : message.trim().split(" +")) { + Matcher matcher = TIME_CODE_PATTERN.matcher(segment); + if (matcher.matches()) { + String numberString = matcher.group(1); + if (numberString.startsWith("-")) { + seconds = -1; + error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.invalidNumberError", numberString).withStyle(ChatFormatting.RED); + return; + } + double number; + try { + number = Double.parseDouble(numberString); + } catch (NumberFormatException e) { + seconds = -1; + error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.invalidNumberError", numberString).withStyle(ChatFormatting.RED); + return; + } + + String timeUnitString = matcher.group(2); + if (timeUnitString == null || timeUnitString.isEmpty()) { + newSeconds += switch (type) { + case HOURS -> Math.round(number * SECONDS_PER_HOUR); + case MINUTES -> Math.round(number * SECONDS_PER_MINUTE); + }; + } + //mimics how Hypixel parses numbers, except also allowing plurals + else if ("days".startsWith(timeUnitString.toLowerCase())) { + newSeconds += Math.round(number * SECONDS_PER_DAY); + } else if ("hours".startsWith(timeUnitString.toLowerCase())) { + newSeconds += Math.round(number * SECONDS_PER_HOUR); + } else if ("minutes".startsWith(timeUnitString.toLowerCase())) { + newSeconds += Math.round(number * SECONDS_PER_MINUTE); + } else if ("seconds".startsWith(timeUnitString.toLowerCase())) { + //note/fun fact: for some reason Hypixel only allows up to "secon", not "second" + newSeconds += Math.round(number); + } else { + seconds = -1; + error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.invalidTimeUnit", timeUnitString).withStyle(ChatFormatting.RED); + return; + } + } else { + seconds = -1; + error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.invalidInputSpecific", segment).withStyle(ChatFormatting.RED); + return; + } + } + + seconds = newSeconds; + error = null; + } + + public static @Nullable String getNewValue() { + if (seconds == -1) { + //if calculator is not activated or just invalid input return what the user typed in + return lastInput; + } + + //we can just return the total seconds, Hypixel converts it for us :) + return seconds + "s"; + } + + private static void render(GuiGraphics context, int renderX, int renderY) { + Component text; + if (seconds == -1) { + text = error != null ? error : Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.invalidInput").withStyle(ChatFormatting.RED); + } else { + long remainingSeconds = seconds; + MutableComponent timeText = Component.empty(); + remainingSeconds = appendTimeComponent(timeText, remainingSeconds, SECONDS_PER_DAY, "day"); + remainingSeconds = appendTimeComponent(timeText, remainingSeconds, SECONDS_PER_HOUR, "hour"); + remainingSeconds = appendTimeComponent(timeText, remainingSeconds, SECONDS_PER_MINUTE, "minute"); + appendTimeComponent(timeText, remainingSeconds, 1, "second"); + text = timeText.withStyle(ChatFormatting.GREEN); + } + + context.drawCenteredString(CLIENT.font, text, renderX, renderY, 0xFFFFFFFF); + } + + private static long appendTimeComponent(MutableComponent component, long seconds, int secondsPerUnit, String translationKeyUnit) + { + long units = seconds / secondsPerUnit; //long division -> cuts off decimal places automatically + if (units > 0) { + seconds -= units * secondsPerUnit; + if (!component.equals(CommonComponents.EMPTY)) { + component.append(" "); + } + component.append(Component.translatable( + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit." + translationKeyUnit + (units == 1 ? "" : "s"), + units + )); + } + return seconds; + } +} diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 127e947f957..8eaea96ac5d 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -1400,6 +1400,25 @@ "skyblocker.config.uiAndVisuals.titleContainer.direction.VERTICAL": "Vertical", "skyblocker.config.uiAndVisuals.titleContainer.titleContainerScale": "Title Container Scale", + "skyblocker.config.uiAndVisuals.timeInputCalculator": "Time Input Calculator", + "skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter": "Close signs with enter", + "skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter.@Tooltip": "Close the current open sign screen with the enter key", + "skyblocker.config.uiAndVisuals.timeInputCalculator.emptyInputError": "Input is empty", + "skyblocker.config.uiAndVisuals.timeInputCalculator.enabled": "Enable Time Input Calculator", + "skyblocker.config.uiAndVisuals.timeInputCalculator.enabled.@Tooltip": "Displays and converts time units when inputting time values such as duration for the ah.\nExample: '0.5d 2h' = 14 Hours\n Units:\n s(econds)\n m(inutes)\n h(ours)\n d(ays)", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidInput": "Invalid input", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidInputSpecific": "Invalid input '%s'", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidNumberError": "Invalid number '%s'", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidTimeUnit": "Invalid time unit '%s'", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.day": "%s Day", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.days": "%s Days", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.hour": "%s Hour", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.hours": "%s Hours", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.minute": "%s Minute", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.minutes": "%s Minutes", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.second": "%s Second", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.seconds": "%s Seconds", + "skyblocker.config.uiAndVisuals.trueQuiverCount": "Show True Quiver Count", "skyblocker.config.uiAndVisuals.trueQuiverCount.@Tooltip": "Shows the actual amount of arrows in your quiver instead of being capped at 64.", From 7f80207d2c5f4544f3f35557ef7ce603c77c0e4a Mon Sep 17 00:00:00 2001 From: NamelessJu Date: Mon, 2 Mar 2026 00:47:03 +0100 Subject: [PATCH 2/5] German translations for time input calculator --- .../assets/skyblocker/lang/de_de.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/resources/assets/skyblocker/lang/de_de.json b/src/main/resources/assets/skyblocker/lang/de_de.json index ce2e54ad27c..750a8f5660e 100644 --- a/src/main/resources/assets/skyblocker/lang/de_de.json +++ b/src/main/resources/assets/skyblocker/lang/de_de.json @@ -9,6 +9,24 @@ "skyblocker.config.uiAndVisuals.tabHud.tabHudScale.@Tooltip": "Wert in %, relativ zur Skalierung des Vanilla-GUIs", "skyblocker.config.uiAndVisuals.bars.enableBars": "Balken aktivieren", "skyblocker.config.uiAndVisuals.hideEmptyTooltips": "Leere Item-Tooltips in Menüs verstecken", + "skyblocker.config.uiAndVisuals.timeInputCalculator": "Zeiteingaberechner", + "skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter": "Schilder mit Eingabetaste schließen", + "skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter.@Tooltip": "Schließe das aktuell geöffnete Schildfenster mit der Eingabetaste", + "skyblocker.config.uiAndVisuals.timeInputCalculator.emptyInputError": "Eingabe ist leer", + "skyblocker.config.uiAndVisuals.timeInputCalculator.enabled": "Zeiteingaberechner aktivieren", + "skyblocker.config.uiAndVisuals.timeInputCalculator.enabled.@Tooltip": "Zeigt Zeiteinheiten an und konvertiert diese beim Eingeben von Zeitwerten wie Dauer für das Auktionshaus.\n(Beispiel: '0.5d 2h' = 14 Stunden)\n Einheiten:\n s(econds)\n m(inutes)\n h(ours)\n d(ays)", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidInput": "Ungültige Eingabe", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidInputSpecific": "Ungültige Eingabe '%s'", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidNumberError": "Ungültige Zahl '%s'", + "skyblocker.config.uiAndVisuals.timeInputCalculator.invalidTimeUnit": "Ungültige Zeiteinheit '%s'", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.day": "%s Tag", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.days": "%s Tage", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.hour": "%s Stunde", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.hours": "%s Stunden", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.minute": "%s Minute", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.minutes": "%s Minuten", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.second": "%s Sekunde", + "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.seconds": "%s Sekunden", "skyblocker.config.otherLocations": "Andere Orte", "skyblocker.config.dungeons": "Dungeons", "skyblocker.config.dungeons.map.enableMap": "Karte aktivieren", From 0e322e0c1aa315aa122ab5c78e5a1a195991507b Mon Sep 17 00:00:00 2001 From: NamelessJu Date: Mon, 2 Mar 2026 01:30:02 +0100 Subject: [PATCH 3/5] Fixed code style --- .../categories/UIAndVisualsCategory.java | 2 +- .../config/configs/UIAndVisualsConfig.java | 6 ++-- .../calculators/SignTimeCalculator.java | 36 +++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java index 4500a94eac1..eb940be7a86 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/UIAndVisualsCategory.java @@ -801,7 +801,7 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .controller(ConfigUtils.createBooleanController()) .build()) .build()) - + //Time Input Calculator .group(OptionGroup.createBuilder() .name(Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator")) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java index 4d87b0b86e0..4b0b2960150 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java @@ -75,7 +75,7 @@ public class UIAndVisualsConfig { public BazaarQuickQuantities bazaarQuickQuantities = new BazaarQuickQuantities(); public InputCalculator inputCalculator = new InputCalculator(); - + public TimeInputCalculator timeInputCalculator = new TimeInputCalculator(); public FlameOverlay flameOverlay = new FlameOverlay(); @@ -412,13 +412,13 @@ public static class InputCalculator { public boolean closeSignsWithEnter = true; } - + public static class TimeInputCalculator { public boolean enabled = true; public boolean closeSignsWithEnter = true; } - + public static class FlameOverlay { public int flameHeight = 100; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java b/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java index f32f1b68e15..f7db422fefb 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/calculators/SignTimeCalculator.java @@ -6,9 +6,9 @@ import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.VisibleForTesting; +import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -17,34 +17,34 @@ public class SignTimeCalculator public enum TimeType { HOURS, MINUTES } - + private static final Minecraft CLIENT = Minecraft.getInstance(); private static final Pattern TIME_CODE_PATTERN = Pattern.compile("(\\d+\\.\\d+|\\d+)(\\D+)?"); private static final int SECONDS_PER_DAY = 86400; private static final short SECONDS_PER_HOUR = 3600; private static final byte SECONDS_PER_MINUTE = 60; - - private static @Nullable String lastInput; + + private static String lastInput; private static long seconds; - private static @Nullable Component error = null; - + private static Component error = null; + public static void renderTime(GuiGraphics context, String message, TimeType type, int renderX, int renderY) { calculate(message, type); render(context, renderX, renderY); } - + @VisibleForTesting public static void calculate(String message, TimeType type) { //only update if new input if (message.equals(lastInput)) return; lastInput = message; - + if (message.isBlank()) { seconds = -1; error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.emptyInputError").withStyle(ChatFormatting.RED); return; } - + long newSeconds = 0; for (String segment : message.trim().split(" +")) { Matcher matcher = TIME_CODE_PATTERN.matcher(segment); @@ -63,7 +63,7 @@ public static void calculate(String message, TimeType type) { error = Component.translatable("skyblocker.config.uiAndVisuals.timeInputCalculator.invalidNumberError", numberString).withStyle(ChatFormatting.RED); return; } - + String timeUnitString = matcher.group(2); if (timeUnitString == null || timeUnitString.isEmpty()) { newSeconds += switch (type) { @@ -72,13 +72,13 @@ public static void calculate(String message, TimeType type) { }; } //mimics how Hypixel parses numbers, except also allowing plurals - else if ("days".startsWith(timeUnitString.toLowerCase())) { + else if ("days".startsWith(timeUnitString.toLowerCase(Locale.ENGLISH))) { newSeconds += Math.round(number * SECONDS_PER_DAY); - } else if ("hours".startsWith(timeUnitString.toLowerCase())) { + } else if ("hours".startsWith(timeUnitString.toLowerCase(Locale.ENGLISH))) { newSeconds += Math.round(number * SECONDS_PER_HOUR); - } else if ("minutes".startsWith(timeUnitString.toLowerCase())) { + } else if ("minutes".startsWith(timeUnitString.toLowerCase(Locale.ENGLISH))) { newSeconds += Math.round(number * SECONDS_PER_MINUTE); - } else if ("seconds".startsWith(timeUnitString.toLowerCase())) { + } else if ("seconds".startsWith(timeUnitString.toLowerCase(Locale.ENGLISH))) { //note/fun fact: for some reason Hypixel only allows up to "secon", not "second" newSeconds += Math.round(number); } else { @@ -92,17 +92,17 @@ else if ("days".startsWith(timeUnitString.toLowerCase())) { return; } } - + seconds = newSeconds; error = null; } - public static @Nullable String getNewValue() { + public static String getNewValue() { if (seconds == -1) { //if calculator is not activated or just invalid input return what the user typed in return lastInput; } - + //we can just return the total seconds, Hypixel converts it for us :) return seconds + "s"; } @@ -123,7 +123,7 @@ private static void render(GuiGraphics context, int renderX, int renderY) { context.drawCenteredString(CLIENT.font, text, renderX, renderY, 0xFFFFFFFF); } - + private static long appendTimeComponent(MutableComponent component, long seconds, int secondsPerUnit, String translationKeyUnit) { long units = seconds / secondsPerUnit; //long division -> cuts off decimal places automatically From 07aa59517c0e07ce00e2c94beb388a29dcfa3ad5 Mon Sep 17 00:00:00 2001 From: NamelessJu Date: Wed, 4 Mar 2026 00:09:10 +0100 Subject: [PATCH 4/5] Fixed code style (again) --- .../hysky/skyblocker/config/configs/UIAndVisualsConfig.java | 2 +- .../skyblocker/mixins/AbstractSignEditScreenMixin.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java index 4b0b2960150..787bc472f64 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/UIAndVisualsConfig.java @@ -415,7 +415,7 @@ public static class InputCalculator { public static class TimeInputCalculator { public boolean enabled = true; - + public boolean closeSignsWithEnter = true; } diff --git a/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java b/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java index dcccb02b8b6..c58d96a5af5 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/AbstractSignEditScreenMixin.java @@ -132,7 +132,7 @@ else if (isInputSign() && config.uiAndVisuals.inputCalculator.enabled) { private boolean isSpeedInputSign() { return messages[3].equals(SPEED_INPUT_MARKER); } - + @Unique private SignTimeCalculator.@Nullable TimeType getTimeInputType() { if (messages[1].equals(INPUT_SIGN_MARKER)) { @@ -143,10 +143,10 @@ private boolean isSpeedInputSign() { return SignTimeCalculator.TimeType.MINUTES; } } - + return null; } - + /** * Used to exclude search signs with {@link AbstractSignEditScreenMixin#INPUT_SIGN_MARKER}. *
Works for /recipes & /shards signs From 676dc7520a29e8cb2497ada5d587b26ca8bea255 Mon Sep 17 00:00:00 2001 From: NamelessJu Date: Wed, 4 Mar 2026 00:26:16 +0100 Subject: [PATCH 5/5] Fixed JSON style --- .../assets/skyblocker/lang/en_us.json | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 8eaea96ac5d..cce0f9659fe 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -1390,16 +1390,6 @@ "skyblocker.config.uiAndVisuals.teleportOverlay.showWhenInAir": "Show Overlay Mid Air", "skyblocker.config.uiAndVisuals.teleportOverlay.teleportOverlayColor": "Teleport Overlay Color", - "skyblocker.config.uiAndVisuals.titleContainer": "Title Container", - "skyblocker.config.uiAndVisuals.titleContainer.@Tooltip": "Used to display multiple titles at once, Example use: Vampire Slayer", - "skyblocker.config.uiAndVisuals.titleContainer.alignment.LEFT": "Left", - "skyblocker.config.uiAndVisuals.titleContainer.alignment.MIDDLE": "Middle", - "skyblocker.config.uiAndVisuals.titleContainer.alignment.RIGHT": "Right", - "skyblocker.config.uiAndVisuals.titleContainer.config": "Title Container Placement Config...", - "skyblocker.config.uiAndVisuals.titleContainer.direction.HORIZONTAL": "Horizontal", - "skyblocker.config.uiAndVisuals.titleContainer.direction.VERTICAL": "Vertical", - "skyblocker.config.uiAndVisuals.titleContainer.titleContainerScale": "Title Container Scale", - "skyblocker.config.uiAndVisuals.timeInputCalculator": "Time Input Calculator", "skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter": "Close signs with enter", "skyblocker.config.uiAndVisuals.timeInputCalculator.closeSignsWithEnter.@Tooltip": "Close the current open sign screen with the enter key", @@ -1419,6 +1409,16 @@ "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.second": "%s Second", "skyblocker.config.uiAndVisuals.timeInputCalculator.unit.seconds": "%s Seconds", + "skyblocker.config.uiAndVisuals.titleContainer": "Title Container", + "skyblocker.config.uiAndVisuals.titleContainer.@Tooltip": "Used to display multiple titles at once, Example use: Vampire Slayer", + "skyblocker.config.uiAndVisuals.titleContainer.alignment.LEFT": "Left", + "skyblocker.config.uiAndVisuals.titleContainer.alignment.MIDDLE": "Middle", + "skyblocker.config.uiAndVisuals.titleContainer.alignment.RIGHT": "Right", + "skyblocker.config.uiAndVisuals.titleContainer.config": "Title Container Placement Config...", + "skyblocker.config.uiAndVisuals.titleContainer.direction.HORIZONTAL": "Horizontal", + "skyblocker.config.uiAndVisuals.titleContainer.direction.VERTICAL": "Vertical", + "skyblocker.config.uiAndVisuals.titleContainer.titleContainerScale": "Title Container Scale", + "skyblocker.config.uiAndVisuals.trueQuiverCount": "Show True Quiver Count", "skyblocker.config.uiAndVisuals.trueQuiverCount.@Tooltip": "Shows the actual amount of arrows in your quiver instead of being capped at 64.",