From eb5edff3b2d705b87ed99516346b47bdac4b3d9c Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Sat, 7 Mar 2026 01:35:34 +0100 Subject: [PATCH 1/4] much cooler and awesomer event notifications --- .../config/SkyblockerConfigManager.java | 2 +- .../EventNotificationsCategory.java | 38 +++-- .../configs/EventNotificationsConfig.java | 17 +- .../config/datafixer/ConfigDataFixer.java | 2 + .../ConfigFix6EventNotifications.java | 34 ++++ .../EventConfigTimesEditScreen.java | 146 ++++++++++++++++++ .../eventnotifications/package-info.java | 4 + .../skyblock/events/EventNotifications.java | 14 +- .../utils/config/DurationController.java | 28 ++-- .../assets/skyblocker/lang/en_us.json | 9 +- 10 files changed, 251 insertions(+), 43 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java create mode 100644 src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/EventConfigTimesEditScreen.java create mode 100644 src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/package-info.java diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java index 3fcda39084..864a59c8b8 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java @@ -57,7 +57,7 @@ import org.slf4j.Logger; public class SkyblockerConfigManager { - public static final int CONFIG_VERSION = 6; + public static final int CONFIG_VERSION = 7; private static final Logger LOGGER = LogUtils.getLogger(); private static final Path CONFIG_DIR = FabricLoader.getInstance().getConfigDir(); private static final Path CONFIG_FILE = CONFIG_DIR.resolve("skyblocker.json"); diff --git a/src/main/java/de/hysky/skyblocker/config/categories/EventNotificationsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/EventNotificationsCategory.java index 40b2f762fa..d63d575c1b 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/EventNotificationsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/EventNotificationsCategory.java @@ -4,12 +4,11 @@ import de.hysky.skyblocker.config.ConfigUtils; import de.hysky.skyblocker.config.SkyblockerConfig; import de.hysky.skyblocker.config.configs.EventNotificationsConfig; +import de.hysky.skyblocker.config.screens.eventnotifications.EventConfigTimesEditScreen; import de.hysky.skyblocker.skyblock.events.EventNotifications; -import de.hysky.skyblocker.utils.config.DurationController; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import net.azureaaron.dandelion.api.ButtonOption; import net.azureaaron.dandelion.api.ConfigCategory; import net.azureaaron.dandelion.api.LabelOption; -import net.azureaaron.dandelion.api.ListOption; import net.azureaaron.dandelion.api.Option; import net.azureaaron.dandelion.api.OptionGroup; import net.azureaaron.dandelion.api.OptionListener.UpdateType; @@ -61,21 +60,28 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig } private static List createGroups(SkyblockerConfig config) { - Map eventsReminderTimes = config.eventNotifications.eventsReminderTimes; - List groups = new ArrayList<>(eventsReminderTimes.size()); + Map eventsReminderTimes = config.eventNotifications.events; if (eventsReminderTimes.isEmpty()) return List.of(OptionGroup.createBuilder().option(LabelOption.createBuilder().label(Component.translatable("skyblocker.config.eventNotifications.monologue")).build()).build()); - for (Map.Entry entry : eventsReminderTimes.entrySet()) { - groups.add(ListOption.createBuilder() + List groups = new ArrayList<>(eventsReminderTimes.size()); + for (Map.Entry entry : eventsReminderTimes.entrySet()) { + groups.add(OptionGroup.createBuilder() .name(Component.literal(entry.getKey())) - .binding(EventNotifications.DEFAULT_REMINDERS, entry::getValue, integers -> entry.setValue(new IntArrayList(integers))) - .controller(new DurationController()) - .description(Component.translatable("skyblocker.config.eventNotifications.@Tooltip[0]"), - Component.empty(), - Component.translatable("skyblocker.config.eventNotifications.@Tooltip[1]"), - Component.empty(), - Component.translatable("skyblocker.config.eventNotifications.@Tooltip[2]", entry.getKey())) - .initial(60) - .collapsed(true) + .option(Option.createBuilder() + .name(Component.translatable("skyblocker.config.eventNotifications.event.enabled", entry.getKey())) + .binding(EventNotifications.DEFAULT_REMINDERS.enabled, + () -> entry.getValue().enabled, + enabled -> entry.getValue().enabled = enabled + ) + .controller(ConfigUtils.createBooleanController()) + .build() + ) + .option(ButtonOption.createBuilder() + .name(Component.translatable("skyblocker.config.eventNotifications.event.editReminders", entry.getKey())) + .prompt(Component.translatable("skyblocker.config.eventNotifications.event.editReminders.prompt")) + .description(Component.translatable("skyblocker.config.eventNotifications.event.editReminders.tooltip")) + .action(s -> Minecraft.getInstance().setScreen(new EventConfigTimesEditScreen(s, entry.getKey(), entry.getValue()))) + .build() + ) .build() ); } diff --git a/src/main/java/de/hysky/skyblocker/config/configs/EventNotificationsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/EventNotificationsConfig.java index ff01851f11..fe59638b04 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/EventNotificationsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/EventNotificationsConfig.java @@ -1,5 +1,6 @@ package de.hysky.skyblocker.config.configs; +import de.hysky.skyblocker.annotations.GenToString; import it.unimi.dsi.fastutil.ints.IntArrayList; import java.util.HashMap; import java.util.Map; @@ -13,7 +14,7 @@ public class EventNotificationsConfig { public Sound reminderSound = Sound.PLING; - public Map eventsReminderTimes = new HashMap<>(); + public Map events = new HashMap<>(); public enum Criterion { NONE, @@ -27,6 +28,20 @@ public String toString() { } } + public static class EventConfig { + public boolean enabled; + public IntArrayList reminderTimes; + + public EventConfig() { + enabled = true; + reminderTimes = new IntArrayList(); + } + + @GenToString + @Override + public native String toString(); + } + public enum Sound { NONE(null), BELL(SoundEvents.BELL_BLOCK), diff --git a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java index f489e56482..1b8e7a8720 100644 --- a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java +++ b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java @@ -60,6 +60,8 @@ private static DataFixer build() { builder.addFixer(new ConfigFix4ChatRulesObject(schema5, true)); Schema schema6 = builder.addSchema(6, Schema::new); builder.addFixer(new ConfigFix5ChatRulesSeparateOutputs(schema6, true)); + Schema schema7 = builder.addSchema(7, Schema::new); + builder.addFixer(new ConfigFix6EventNotifications(schema7, true)); return dataFixer = builder.build().fixer(); } diff --git a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java new file mode 100644 index 0000000000..ba3824c2fd --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java @@ -0,0 +1,34 @@ +package de.hysky.skyblocker.config.datafixer; + +import com.mojang.datafixers.DSL; +import com.mojang.datafixers.TypeRewriteRule; +import com.mojang.datafixers.schemas.Schema; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Dynamic; + +import java.util.Map; +import java.util.function.Function; + +public class ConfigFix6EventNotifications extends ConfigDataFix { + public ConfigFix6EventNotifications(Schema outputSchema, boolean changesType) { + super(outputSchema, changesType); + } + + @Override + protected TypeRewriteRule makeRule() { + return fixTypeEverywhereTyped( + getClass().getSimpleName(), + getInputSchema().getType(ConfigDataFixer.CONFIG_TYPE), + typed -> typed.update(DSL.remainderFinder(), this::fix) + ); + } + + private Dynamic fix(Dynamic dynamic) { + return fixVersion(dynamic).update("eventNotifications", eventNotifications -> eventNotifications.renameAndFixField("eventsReminderTimes", "events", events -> events.updateMapValues(pair -> + Pair.of(pair.getFirst(), dynamic.createMap(Map.of( + dynamic.createString("enabled"), dynamic.createBoolean(!pair.getSecond().asList(Function.identity()).isEmpty()), + dynamic.createString("reminderTimes"), pair.getSecond() + )) + )))); + } +} diff --git a/src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/EventConfigTimesEditScreen.java b/src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/EventConfigTimesEditScreen.java new file mode 100644 index 0000000000..7b1e430bf9 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/EventConfigTimesEditScreen.java @@ -0,0 +1,146 @@ +package de.hysky.skyblocker.config.screens.eventnotifications; + +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.EventNotificationsConfig; +import de.hysky.skyblocker.utils.SkyblockTime; +import de.hysky.skyblocker.utils.config.DurationController; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.ContainerObjectSelectionList; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.SpriteIconButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; +import net.minecraft.client.gui.layouts.LinearLayout; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.CommonComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.Identifier; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; + +public class EventConfigTimesEditScreen extends Screen { + + private final EventNotificationsConfig.EventConfig eventConfig; + private final HeaderAndFooterLayout layout = new HeaderAndFooterLayout(this); + private final Screen parent; + private EntryList list; + + public EventConfigTimesEditScreen(Screen parent, String name, EventNotificationsConfig.EventConfig eventConfig) { + super(Component.translatable("skyblocker.config.eventNotifications.screen.title", name)); + this.eventConfig = eventConfig; + this.parent = parent; + } + + @Override + protected void init() { + super.init(); + layout.addTitleHeader(getTitle(), font); + list = layout.addToContents(new EntryList(width, layout.getContentHeight(), 0, 24)); + list.replaceEntries(eventConfig.reminderTimes.intStream().sorted().mapToObj(Entry::new).toList()); + + LinearLayout footerLayout = LinearLayout.horizontal().spacing(2); + footerLayout.addChild(Button.builder(Component.translatable("skyblocker.config.eventNotifications.screen.addReminder"), b -> list.addEntry(new Entry(5 * 60))).build()); + footerLayout.addChild(Button.builder(CommonComponents.GUI_DONE, b -> onClose()).build()); + layout.addToFooter(footerLayout); + layout.visitWidgets(this::addRenderableWidget); + repositionElements(); + } + + @Override + protected void repositionElements() { + list.updateSize(this.width, this.layout); + layout.arrangeElements(); + } + + @Override + public void onClose() { + SkyblockerConfigManager.update(c -> eventConfig.reminderTimes = list.children().stream() + .map(e -> e.box) + .filter(b -> b.valid) + .mapToInt(b -> b.seconds) + .sorted() + .collect(IntArrayList::new, IntArrayList::add, IntArrayList::addAll)); + minecraft.setScreen(parent); + } + + private class EntryList extends ContainerObjectSelectionList { + + private EntryList(int width, int height, int y, int itemHeight) { + super(EventConfigTimesEditScreen.this.minecraft, width, height, y, itemHeight); + } + + @Override + protected void removeEntry(EventConfigTimesEditScreen.Entry entry) { + super.removeEntry(entry); + } + + @Override + protected int addEntry(EventConfigTimesEditScreen.Entry entry) { + return super.addEntry(entry); + } + } + + private class Entry extends ContainerObjectSelectionList.Entry { + private static final Identifier DELETE_ICON = SkyblockerMod.id("trash_can"); + private static final int ICON_WIDTH = 12, ICON_HEIGHT = 15; + + private final TimeEditBox box; + private final List widgets; + private final LinearLayout entryLayout = LinearLayout.horizontal().spacing(4); + + private Entry(int seconds) { + box = new TimeEditBox(seconds); + Button buttonDelete = SpriteIconButton.builder(Component.translatable("selectServer.deleteButton"), ignored -> list.removeEntry(this), true).size(20, 20).sprite(DELETE_ICON, ICON_WIDTH, ICON_HEIGHT).build(); + entryLayout.addChild(box); + entryLayout.addChild(buttonDelete); + entryLayout.arrangeElements(); + widgets = List.of(box, buttonDelete); + } + + @Override + public List narratables() { + return widgets; + } + + @Override + public void renderContent(GuiGraphics guiGraphics, int i, int j, boolean bl, float f) { + entryLayout.setPosition(getContentRight() - entryLayout.getWidth(), getContentY()); + for (AbstractWidget widget : widgets) { + widget.render(guiGraphics, i, j, f); + } + } + + @Override + public List children() { + return widgets; + } + } + + private static class TimeEditBox extends EditBox { + + private int seconds; + private boolean valid = false; + + TimeEditBox(int seconds) { + super(Minecraft.getInstance().font, 150, 20, Component.empty()); + this.seconds = seconds; + setResponder(this::onUpdate); + setValue(SkyblockTime.formatTime(seconds).getString()); + addFormatter((string, _firstCharacterIndex) -> FormattedCharSequence.forward(string, valid ? Style.EMPTY : Style.EMPTY.applyFormat(ChatFormatting.RED))); + } + + private void onUpdate(String s) { + valid = DurationController.isValid(s); + if (valid) seconds = DurationController.fromString(s); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/package-info.java b/src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/package-info.java new file mode 100644 index 0000000000..b405b52a17 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/config/screens/eventnotifications/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package de.hysky.skyblocker.config.screens.eventnotifications; + +import org.jspecify.annotations.NullMarked; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java index bc98b0c4d8..0e8dc84947 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java @@ -10,12 +10,11 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.EventNotificationsConfig; import de.hysky.skyblocker.events.SkyblockEvents; import de.hysky.skyblocker.utils.Http; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; import net.minecraft.client.Minecraft; @@ -37,7 +36,7 @@ public class EventNotifications { private static final Logger LOGGER = LogUtils.getLogger(); public static final String JACOBS = "Jacob's Farming Contest"; - public static final IntArrayList DEFAULT_REMINDERS = new IntArrayList(IntList.of(60, 60 * 5)); + public static final EventNotificationsConfig.EventConfig DEFAULT_REMINDERS = new EventNotificationsConfig.EventConfig(); public static final Map eventIcons = Map.ofEntries( Map.entry("Dark Auction", new ItemStack(Items.NETHER_BRICK)), Map.entry("Bonus Fishing Festival", new ItemStack(Items.FISHING_ROD)), @@ -110,7 +109,7 @@ public static void refreshEvents() { SkyblockerConfigManager.update(config -> { for (String s : events.keySet()) { - config.eventNotifications.eventsReminderTimes.computeIfAbsent(s, s1 -> DEFAULT_REMINDERS); + config.eventNotifications.events.computeIfAbsent(s, s1 -> DEFAULT_REMINDERS); } }); }).exceptionally(EventNotifications::itBorked); @@ -137,11 +136,10 @@ private static void timeUpdate() { if (skyblockEvent == null) continue; } String eventName = entry.getKey(); - // Cannot be changed to fast util due to casting issues - List reminderTimes = SkyblockerConfigManager.get().eventNotifications.eventsReminderTimes.getOrDefault(eventName, DEFAULT_REMINDERS); - if (reminderTimes.isEmpty()) continue; + EventNotificationsConfig.EventConfig config = SkyblockerConfigManager.get().eventNotifications.events.getOrDefault(eventName, DEFAULT_REMINDERS); + if (!config.enabled) continue; - for (int reminderTime : reminderTimes) { + for (int reminderTime : config.reminderTimes) { if (criterionMet() && currentTime + reminderTime < skyblockEvent.start() && newTime + reminderTime >= skyblockEvent.start()) { Minecraft instance = Minecraft.getInstance(); if (eventName.equals(JACOBS)) { diff --git a/src/main/java/de/hysky/skyblocker/utils/config/DurationController.java b/src/main/java/de/hysky/skyblocker/utils/config/DurationController.java index 60a10e804b..f5a5de4743 100644 --- a/src/main/java/de/hysky/skyblocker/utils/config/DurationController.java +++ b/src/main/java/de/hysky/skyblocker/utils/config/DurationController.java @@ -18,9 +18,9 @@ import java.util.regex.Pattern; public class DurationController extends IntegerControllerImpl { - private static final Pattern secondsPattern = Pattern.compile("(^|\\s)(\\d+)s(\\s|$)"); - private static final Pattern minutesPattern = Pattern.compile("(^|\\s)(\\d+)m(\\s|$)"); - private static final Pattern hoursPattern = Pattern.compile("(^|\\s)(\\d+)h(\\s|$)"); + private static final Pattern SECONDS_PATTERN = Pattern.compile("(^|\\s)(\\d+)s(\\s|$)"); + private static final Pattern MINUTES_PATTERN = Pattern.compile("(^|\\s)(\\d+)m(\\s|$)"); + private static final Pattern HOURS_PATTERN = Pattern.compile("(^|\\s)(\\d+)h(\\s|$)"); public DurationController() { super(0, Integer.MAX_VALUE, 1, false); @@ -30,10 +30,10 @@ private static String toString(int duration) { return SkyblockTime.formatTime(duration).getString(); } - private static int fromString(String value) { - Matcher hoursMatcher = hoursPattern.matcher(value); - Matcher minutesMatcher = minutesPattern.matcher(value); - Matcher secondsMatcher = secondsPattern.matcher(value); + public static int fromString(String value) { + Matcher hoursMatcher = HOURS_PATTERN.matcher(value); + Matcher minutesMatcher = MINUTES_PATTERN.matcher(value); + Matcher secondsMatcher = SECONDS_PATTERN.matcher(value); int result = 0; if (hoursMatcher.find()) { @@ -48,10 +48,10 @@ private static int fromString(String value) { return result; } - private static boolean isValid(String s) { - Matcher hoursMatcher = hoursPattern.matcher(s); - Matcher minutesMatcher = minutesPattern.matcher(s); - Matcher secondsMatcher = secondsPattern.matcher(s); + public static boolean isValid(String s) { + Matcher hoursMatcher = HOURS_PATTERN.matcher(s); + Matcher minutesMatcher = MINUTES_PATTERN.matcher(s); + Matcher secondsMatcher = SECONDS_PATTERN.matcher(s); int hoursCount = 0; while (hoursMatcher.find()) hoursCount++; @@ -62,9 +62,9 @@ private static boolean isValid(String s) { if (hoursCount == 0 && minutesCount == 0 && secondsCount == 0) return false; if (hoursCount > 1 || minutesCount > 1 || secondsCount > 1) return false; - s = s.replaceAll(hoursPattern.pattern(), ""); - s = s.replaceAll(minutesPattern.pattern(), ""); - s = s.replaceAll(secondsPattern.pattern(), ""); + s = s.replaceAll(HOURS_PATTERN.pattern(), ""); + s = s.replaceAll(MINUTES_PATTERN.pattern(), ""); + s = s.replaceAll(SECONDS_PATTERN.pattern(), ""); return s.isBlank(); } diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 1400648292..31cbea1188 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -419,14 +419,15 @@ "skyblocker.config.dungeons.terminals.solveStartsWith": "Solve Starts With", "skyblocker.config.eventNotifications": "Event Notifications", - "skyblocker.config.eventNotifications.@Tooltip[0]": "Configure how much time before an event you will be reminded with a notification toast! For example if you set '5m' and '30s' in the list, you will receive a notification 5 minutes before and another 30 seconds before an event starts.", - "skyblocker.config.eventNotifications.@Tooltip[1]": "The order doesn't matter. If you want to disable notifications, just empty the list.", - "skyblocker.config.eventNotifications.@Tooltip[2]": "This list will modify the '%s' event", "skyblocker.config.eventNotifications.criterion": "Notification Criterion", "skyblocker.config.eventNotifications.criterion.EVERYWHERE": "Everywhere", "skyblocker.config.eventNotifications.criterion.HYPIXEL": "Hypixel", "skyblocker.config.eventNotifications.criterion.NONE": "None", "skyblocker.config.eventNotifications.criterion.SKYBLOCK": "SkyBlock", + "skyblocker.config.eventNotifications.event.editReminders": "Edit Reminders", + "skyblocker.config.eventNotifications.event.editReminders.prompt": "Edit", + "skyblocker.config.eventNotifications.event.editReminders.tooltip": "Configure how much time before an event you will be reminded with a notification toast! For example if you set '5m' and '30s' in the list, you will receive a notification 5 minutes before and another 30 seconds before an event starts.", + "skyblocker.config.eventNotifications.event.enabled": "Enable Reminders", "skyblocker.config.eventNotifications.monologue": "can you pls log onto skyblock rq pls? that would be cool cuz like if you are seeing dis then it means that ur config either got cleared or that this is ur first time using the mod if so then thanks for choosing it and hopefully you enjoy it! so yea this is where you will be able to set reminders for all events in skyblock they will be added as you encounter so you first need to log onto skyblock so yea hope you enjoy the mod and all that", "skyblocker.config.eventNotifications.notificationSound": "Notification Sound", "skyblocker.config.eventNotifications.notificationSound.sound.BELL": "Bell", @@ -434,6 +435,8 @@ "skyblocker.config.eventNotifications.notificationSound.sound.GOAT": "Goat", "skyblocker.config.eventNotifications.notificationSound.sound.NONE": "None", "skyblocker.config.eventNotifications.notificationSound.sound.PLING": "Pling", + "skyblocker.config.eventNotifications.screen.addReminder": "Add Reminder", + "skyblocker.config.eventNotifications.screen.title": "Edit %s's Reminder Times", "skyblocker.config.farming": "Farming", From e2d3ac4ed6531fc59ebf60becb3b94301095a206 Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:02:04 +0100 Subject: [PATCH 2/4] DFU --- .../de/hysky/skyblocker/config/SkyblockerConfigManager.java | 2 +- .../de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java | 2 +- ...ntNotifications.java => ConfigFix8EventNotifications.java} | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/de/hysky/skyblocker/config/datafixer/{ConfigFix6EventNotifications.java => ConfigFix8EventNotifications.java} (89%) diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java index b410a9fd0c..85dae72ccf 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfigManager.java @@ -57,7 +57,7 @@ import org.slf4j.Logger; public class SkyblockerConfigManager { - public static final int CONFIG_VERSION = 8; + public static final int CONFIG_VERSION = 9; private static final Logger LOGGER = LogUtils.getLogger(); private static final Path CONFIG_DIR = FabricLoader.getInstance().getConfigDir(); private static final Path CONFIG_FILE = CONFIG_DIR.resolve("skyblocker.json"); diff --git a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java index db11777b5e..d8c5fb1c4e 100644 --- a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java +++ b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigDataFixer.java @@ -65,7 +65,7 @@ private static DataFixer build() { Schema schema8 = builder.addSchema(8, Schema::new); builder.addFixer(new ConfigFix7Farming(schema8, true)); Schema schema9 = builder.addSchema(9, Schema::new); - builder.addFixer(new ConfigFix6EventNotifications(schema9, true)); + builder.addFixer(new ConfigFix8EventNotifications(schema9, true)); return dataFixer = builder.build().fixer(); } diff --git a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix8EventNotifications.java similarity index 89% rename from src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java rename to src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix8EventNotifications.java index ba3824c2fd..ab53ef3849 100644 --- a/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix6EventNotifications.java +++ b/src/main/java/de/hysky/skyblocker/config/datafixer/ConfigFix8EventNotifications.java @@ -9,8 +9,8 @@ import java.util.Map; import java.util.function.Function; -public class ConfigFix6EventNotifications extends ConfigDataFix { - public ConfigFix6EventNotifications(Schema outputSchema, boolean changesType) { +public class ConfigFix8EventNotifications extends ConfigDataFix { + public ConfigFix8EventNotifications(Schema outputSchema, boolean changesType) { super(outputSchema, changesType); } From 21d7ceb89a4b8ae91b5885d41b6c33ca47b1f0c2 Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:04:31 +0100 Subject: [PATCH 3/4] why was this in the loop --- .../hysky/skyblocker/skyblock/events/EventNotifications.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java index 9157955fd3..dbbb331217 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java @@ -155,12 +155,13 @@ private static void timeUpdate() { skyblockEvent = nextEvents.peekFirst(); if (skyblockEvent == null) continue; } + if (!criterionMet()) continue; String eventName = entry.getKey(); EventNotificationsConfig.EventConfig config = SkyblockerConfigManager.get().eventNotifications.events.getOrDefault(eventName, DEFAULT_REMINDERS); if (!config.enabled) continue; for (int reminderTime : config.reminderTimes) { - if (criterionMet() && currentTime + reminderTime < skyblockEvent.start() && newTime + reminderTime >= skyblockEvent.start()) { + if (currentTime + reminderTime < skyblockEvent.start() && newTime + reminderTime >= skyblockEvent.start()) { Minecraft instance = Minecraft.getInstance(); if (eventName.equals(JACOBS) && skyblockEvent.extras().left().isPresent()) { instance.getToastManager().addToast( From 77279faca42768cf4a1f7cb3a8bb06a0af61e999 Mon Sep 17 00:00:00 2001 From: viciscat <51047087+viciscat@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:09:32 +0100 Subject: [PATCH 4/4] reduce indentation --- .../skyblock/events/EventNotifications.java | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java index dbbb331217..bb969d33e5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java @@ -161,32 +161,31 @@ private static void timeUpdate() { if (!config.enabled) continue; for (int reminderTime : config.reminderTimes) { - if (currentTime + reminderTime < skyblockEvent.start() && newTime + reminderTime >= skyblockEvent.start()) { - Minecraft instance = Minecraft.getInstance(); - if (eventName.equals(JACOBS) && skyblockEvent.extras().left().isPresent()) { - instance.getToastManager().addToast( - new JacobEventToast( - skyblockEvent.start(), - skyblockEvent.start() + skyblockEvent.duration(), - eventName, - skyblockEvent.extras().left().get() - ) - ); - } else { - instance.getToastManager().addToast( - new EventToast( - skyblockEvent.start(), - skyblockEvent.start() + skyblockEvent.duration(), - eventName, - eventIcons.getOrDefault(eventName, new ItemStack(Items.PAPER)) - ) - ); - } - SoundEvent soundEvent = SkyblockerConfigManager.get().eventNotifications.reminderSound.getSoundEvent(); - if (soundEvent != null) - instance.getSoundManager().play(SimpleSoundInstance.forUI(soundEvent, 1f, 1f)); - break; + // Only show notification if last time we ticked was before the event, and we are now after the event start + if (newTime + reminderTime < skyblockEvent.start() || currentTime + reminderTime >= skyblockEvent.start()) continue; + Minecraft instance = Minecraft.getInstance(); + if (eventName.equals(JACOBS) && skyblockEvent.extras().left().isPresent()) { + instance.getToastManager().addToast( + new JacobEventToast( + skyblockEvent.start(), + skyblockEvent.start() + skyblockEvent.duration(), + eventName, + skyblockEvent.extras().left().get() + ) + ); + } else { + instance.getToastManager().addToast( + new EventToast( + skyblockEvent.start(), + skyblockEvent.start() + skyblockEvent.duration(), + eventName, + eventIcons.getOrDefault(eventName, new ItemStack(Items.PAPER)) + ) + ); } + SoundEvent soundEvent = SkyblockerConfigManager.get().eventNotifications.reminderSound.getSoundEvent(); + if (soundEvent != null) instance.getSoundManager().play(SimpleSoundInstance.forUI(soundEvent, 1f, 1f)); + break; } } currentTime = newTime;