From d3302012f6907a9a9ba5e175644c349443b36eab Mon Sep 17 00:00:00 2001 From: Roman / Linnea Gräf Date: Mon, 17 Jul 2023 12:10:07 +0200 Subject: Add free rift infusion to timer (#766) --- .../notenoughupdates/miscgui/CalendarOverlay.java | 194 ++++++++++++++------- .../notenoughupdates/options/NEUConfig.java | 2 + .../options/seperateSections/MiscOverlays.java | 17 +- .../notenoughupdates/overlays/TimersOverlay.java | 56 ++++++ .../notenoughupdates/commands/help/HelpCommand.kt | 1 - 5 files changed, 203 insertions(+), 67 deletions(-) diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java index 451846eb..61c5915d 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java @@ -29,6 +29,8 @@ import io.github.moulberry.notenoughupdates.core.BackgroundBlur; import io.github.moulberry.notenoughupdates.util.ItemUtils; import io.github.moulberry.notenoughupdates.util.SkyBlockTime; import io.github.moulberry.notenoughupdates.util.Utils; +import kotlin.Pair; +import lombok.var; import net.minecraft.client.Minecraft; import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.client.gui.FontRenderer; @@ -37,6 +39,7 @@ import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.gui.inventory.GuiChest; import net.minecraft.client.gui.inventory.GuiContainer; import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.item.ItemStack; @@ -57,13 +60,16 @@ import org.lwjgl.opengl.GL11; import java.io.File; import java.time.Duration; import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -249,6 +255,51 @@ public class CalendarOverlay { } } + public void populateDefaultEvents() { + if (eventMap.isEmpty() || eventMap.size() <= 20) { + fillRepeatingEvents(25 - eventMap.size()); + fillSpecialMayors(4); + fillWeather(); + } + } + + private void fillWeather() { + long rainInterval = 4850 * 1000L; + long rainingTime = 1000 * 1000L; + long thunderStormEpoch = 1668551956000L - rainingTime; + long currentTime = System.currentTimeMillis(); + long timeSinceLastThunderStart = (currentTime - thunderStormEpoch) % (rainInterval * 4); + long lastThunderStart = currentTime - timeSinceLastThunderStart; + for (int i = 0; i < 11; i++) { + long eventTimer = lastThunderStart + rainInterval * i; + if (i % 4 == 0) { + addEvent(SkyBlockTime.Companion.fromInstant(Instant.ofEpochMilli(eventTimer)), new SBEvent( + "spiders_den_thunder", + "§9Spider's Den Thunder", + true, + new ItemStack(Blocks.slime_block), + Arrays.asList("§aIt will rain in the Spider's Den", "§aand Toxic Rain Slimes will spawn"), + rainingTime, + true + )); + } else { + addEvent( + SkyBlockTime.Companion.fromInstant(Instant.ofEpochMilli(eventTimer)), + new SBEvent( + "spiders_den_rain", + "§9Spider's Den Rain", + false, + new ItemStack(Items.slime_ball), + Arrays.asList("§aIt will rain in the Spider's Den", "§aand Rain Slimes will spawn"), + rainingTime, + true + ) + ); + } + + } + } + @SubscribeEvent public void tick(TickEvent.ClientTickEvent event) { if (event.phase != TickEvent.Phase.START) return; @@ -258,10 +309,7 @@ public class CalendarOverlay { if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) { jfFavouriteSelect = null; - if (eventMap.isEmpty() || eventMap.size() <= 20) { - fillRepeatingEvents(25 - eventMap.size()); - fillSpecialMayors(4); - } + populateDefaultEvents(); return; } @@ -274,10 +322,7 @@ public class CalendarOverlay { if (!enabled) { jfFavouriteSelect = null; - if (eventMap.isEmpty() || eventMap.size() <= 20) { - fillRepeatingEvents(25 - eventMap.size()); - fillSpecialMayors(4); - } + populateDefaultEvents(); return; } @@ -288,13 +333,13 @@ public class CalendarOverlay { eventMap.clear(); - fillRepeatingEvents(25); - fillSpecialMayors(4); + populateDefaultEvents(); scrapeOverviewPage(cc); } public void addEvent(SkyBlockTime time, SBEvent event) { - if (time.toInstant().isBefore(Instant.now())) return; + if (time.toInstant().isBefore(Instant.now())&& + time.toInstant().plus(event.lastsFor, ChronoUnit.MILLIS).isBefore(Instant.now())) return; getEventsAt(time.toMillis()).add(event); } @@ -316,7 +361,7 @@ public class CalendarOverlay { "ba2cd37d-a0e4-4dc5-b15c-d79ee1051aae", "ewogICJ0aW1lc3RhbXAiIDogMTU5Nzc4MTc1NzIxOSwKICAicHJvZmlsZUlkIiA6ICI0MWQzYWJjMmQ3NDk0MDBjOTA5MGQ1NDM0ZDAzODMxYiIsCiAgInByb2ZpbGVOYW1lIiA6ICJNZWdha2xvb24iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGYyNmZhMGM0NzUzNmU3OGUzMzcyNTdkODk4YWY4YjFlYmM4N2MwODk0NTAzMzc1MjM0MDM1ZmYyYzdlZjhmMCIKICAgIH0KICB9Cn0" ), - Arrays.asList("§eScorpius is a special Mayor candidate") + Arrays.asList("§eScorpius is a special Mayor candidate"), -1, true ) ); addEvent( @@ -330,7 +375,7 @@ public class CalendarOverlay { "ab36a707-96d3-3db1-ab36-a70796d3adb1", "e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQ1MGQxMjY5Mjg4NmM0N2IwNzhhMzhmNGQ0OTJhY2ZlNjEyMTZlMmQwMjM3YWI4MjQzMzQwOWIzMDQ2YjQ2NCJ9fX0" ), - Arrays.asList("§eDerpy is a special Mayor candidate") + Arrays.asList("§eDerpy is a special Mayor candidate"), -1, true ) ); addEvent( @@ -344,7 +389,7 @@ public class CalendarOverlay { "0a9e8efb-9191-4c81-80f5-e27ca5433156", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODIyZDhlNzUxYzhmMmZkNGM4OTQyYzQ0YmRiMmY1Y2E0ZDhhZThlNTc1ZWQzZWIzNGMxOGE4NmU5M2IifX19" ), - Arrays.asList("§eJerry is a special Mayor candidate") + Arrays.asList("§eJerry is a special Mayor candidate"), -1, true ) ); } @@ -593,6 +638,10 @@ public class CalendarOverlay { if (sbEvent.lastsFor >= 0) { tooltipToDisplay.add(EnumChatFormatting.GRAY + "Lasts for: " + EnumChatFormatting.YELLOW + prettyTime(sbEvent.lastsFor, true)); + if (timeUntilMillis < 0) { + tooltipToDisplay.add(EnumChatFormatting.GRAY + "Time left: " + EnumChatFormatting.YELLOW + + prettyTime(sbEvent.lastsFor + timeUntilMillis, true)); + } } if (sbEvent.desc != null) { tooltipToDisplay.add(""); @@ -689,6 +738,11 @@ public class CalendarOverlay { if (nextEvent.lastsFor >= 0) { tooltipToDisplay.add(EnumChatFormatting.GRAY + "Lasts for: " + EnumChatFormatting.YELLOW + prettyTime(nextEvent.lastsFor, true)); + if (timeUntilNext < 0) { + tooltipToDisplay.add(EnumChatFormatting.GRAY + "Time left: " + EnumChatFormatting.YELLOW + + prettyTime(nextEvent.lastsFor + timeUntilNext, true)); + } + } if (nextEvent.desc != null) { tooltipToDisplay.add(""); @@ -1028,6 +1082,43 @@ public class CalendarOverlay { } } + public Optional> getNextFavouriteEvent(boolean orGetFirst) { + populateDefaultEvents(); + long currentTime = System.currentTimeMillis(); + List eventFavourites = NotEnoughUpdates.INSTANCE.config.hidden.eventFavourites; + SBEvent nextAnyEvent = null; + long timeUntilNextAny = 0L; + //Daily Events + for (Map.Entry> sbEvents : eventMap.entrySet()) { + for (SBEvent sbEvent : sbEvents.getValue()) { + long timeUntilMillis = sbEvents.getKey() - currentTime; + + if (timeUntilMillis < -10 * SECOND) { + continue; + } + if (nextAnyEvent == null) { + timeUntilNextAny = timeUntilMillis; + nextAnyEvent = sbEvent; + } + + String[] split = sbEvent.id.split(":"); + boolean containsId = false; + for (int i = 1; i < split.length; i++) { + if (eventFavourites.contains(split[0] + ":" + split[i])) { + containsId = true; + break; + } + } + if (eventFavourites.isEmpty() || eventFavourites.contains(split[0]) || containsId) { + return Optional.of(new Pair<>(sbEvent, timeUntilMillis)); + } + } + } + if (orGetFirst && nextAnyEvent != null) + return Optional.of(new Pair<>(nextAnyEvent, timeUntilNextAny)); + return Optional.empty(); + } + @SubscribeEvent(priority = EventPriority.LOW) public void onGuiDraw(RenderGameOverlayEvent.Post event) { if (NotEnoughUpdates.INSTANCE.config.calendar.eventNotifications && @@ -1036,49 +1127,10 @@ public class CalendarOverlay { GlStateManager.translate(0, 0, 10); if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer) && NotEnoughUpdates.INSTANCE.isOnSkyblock()) { - long currentTime = System.currentTimeMillis(); - - long timeUntilNext = 0; - SBEvent nextEvent = null; - long timeUntilFirst = 0; - SBEvent firstEvent = null; - - List eventFavourites = NotEnoughUpdates.INSTANCE.config.hidden.eventFavourites; - - //Daily Events - out: - for (Map.Entry> sbEvents : eventMap.entrySet()) { - for (SBEvent sbEvent : sbEvents.getValue()) { - long timeUntilMillis = sbEvents.getKey() - currentTime; - - if (timeUntilMillis < -10 * SECOND) { - continue; - } - - if (firstEvent == null) { - firstEvent = sbEvent; - timeUntilFirst = timeUntilMillis; - } - - String[] split = sbEvent.id.split(":"); - boolean containsId = false; - for (int i = 1; i < split.length; i++) { - if (eventFavourites.contains(split[0] + ":" + split[i])) { - containsId = true; - break; - } - } - if (eventFavourites.isEmpty() || eventFavourites.contains(split[0]) || containsId) { - nextEvent = sbEvent; - timeUntilNext = timeUntilMillis; - break out; - } - } - } - - if (nextEvent != null) { - renderToast(nextEvent, timeUntilNext); - } + var nextFavouriteEvent = getNextFavouriteEvent(false); + nextFavouriteEvent.ifPresent((nextEvent) -> { + renderToast(nextEvent.component1(), nextEvent.component2()); + }); } GlStateManager.translate(0, 0, -10); GlStateManager.popMatrix(); @@ -1211,6 +1263,7 @@ public class CalendarOverlay { guiLeft = (width - xSize) / 2; guiTop = 5; + populateDefaultEvents(); //Daily Events out: for (Map.Entry> sbEvents : eventMap.entrySet()) { @@ -1228,7 +1281,7 @@ public class CalendarOverlay { } if (nextMayorEvent == null && !sbEvent.id.split(":")[0].equals("jacob_farming") && - !sbEvent.id.equals("dark_auction")) { + !sbEvent.id.equals("dark_auction") && !sbEvent.isArtificial) { nextMayorEvent = sbEvent; timeUntilMayor = timeUntilMillis; } @@ -1263,13 +1316,6 @@ public class CalendarOverlay { } } - if (nextEvent == null && firstEvent != null) { - String[] split = firstEvent.id.split(":"); - if (eventFavourites.contains(split[0])) { - nextEvent = firstEvent; - timeUntilNext = timeUntilFirst; - } - } if (nextEvent != null) { GlStateManager.translate(0, 0, 50); @@ -1334,6 +1380,10 @@ public class CalendarOverlay { if (sbEvent.lastsFor >= 0) { tooltipToDisplay.add(EnumChatFormatting.GRAY + "Lasts for: " + EnumChatFormatting.YELLOW + prettyTime(sbEvent.lastsFor, true)); + if (timeUntil < 0) { + tooltipToDisplay.add(EnumChatFormatting.GRAY + "Time left: " + EnumChatFormatting.YELLOW + + prettyTime(sbEvent.lastsFor + timeUntil, true)); + } } if (sbEvent.id.split(":")[0].equals("jacob_farming") && sbEvent.desc != null) { tooltipToDisplay.addAll(sbEvent.desc); @@ -1406,14 +1456,28 @@ public class CalendarOverlay { List desc; long lastsFor; boolean isSpecial; + boolean isArtificial; public SBEvent(String id, String display, boolean isSpecial, ItemStack stack, List desc) { this(id, display, isSpecial, stack, desc, -1); } public SBEvent(String id, String display, boolean isSpecial, ItemStack stack, List desc, long lastsFor) { + this(id, display, isSpecial, stack, desc, lastsFor, false); + } + + public SBEvent( + String id, + String display, + boolean isSpecial, + ItemStack stack, + List desc, + long lastsFor, + boolean isArtificial + ) { this.id = id; this.isSpecial = isSpecial; + this.isArtificial = isArtificial; this.display = display; this.stack = stack; this.desc = desc; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java index ece4b225..d431d862 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java @@ -540,6 +540,8 @@ public class NEUConfig extends Config { @Expose public long commissionsCompleted = 0L; @Expose + public long lastFreeRiftInfusionApplied = 0L; + @Expose public long experimentsCompleted = 0L; @Expose public long cookieBuffRemaining = 0L; diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java index 97b11d27..9a8c3514 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java @@ -87,10 +87,11 @@ public class MiscOverlays { "\u00a73Heavy Pearls: \u00a7e3h38m", "\u00a73Crimson Isle Quests: \u00a7e3h38m", "\u00a73NPC Buy Daily Limit: \u00a7e3h38m", + "§3Free Rift Infusion: §e3h38m", } ) @ConfigAccordionId(id = 0) - public List todoText2 = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); + public List todoText2 = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); @ConfigOption( name = "Show Only If Soon", @@ -245,6 +246,20 @@ public class MiscOverlays { ) public int shopLimitDisplay = 0; + @Expose + @ConfigOption( + name = "Free Rift Infusion Display", + desc = "Change the way the Free Rift infusion displays\n" + + "Only when ready, When very Soon, or always." + ) + @ConfigAccordionId(id = 1) + @ConfigEditorDropdown( + values = {"Only when ready", "When very Soon", "Always"} + ) + public int freeRiftInfusionDisplay = 0; + + + @ConfigOption( name = "Colours", desc = "", diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java index b8f1f6a3..44149582 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java @@ -21,9 +21,12 @@ package io.github.moulberry.notenoughupdates.overlays; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.core.config.Position; +import io.github.moulberry.notenoughupdates.events.SlotClickEvent; import io.github.moulberry.notenoughupdates.options.NEUConfig; +import io.github.moulberry.notenoughupdates.util.ItemUtils; import io.github.moulberry.notenoughupdates.util.SBInfo; import io.github.moulberry.notenoughupdates.util.Utils; +import lombok.var; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.inventory.GuiChest; import net.minecraft.client.renderer.GlStateManager; @@ -31,6 +34,7 @@ import net.minecraft.init.Blocks; import net.minecraft.init.Items; import net.minecraft.inventory.ContainerChest; import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.EnumChatFormatting; @@ -77,6 +81,19 @@ public class TimersOverlay extends TextTabOverlay { private static final Pattern DAILY_SHOP_LIMIT = Pattern.compile( "\u00a7r\u00a7cYou may only buy up to (640|6400) of this item each day!\u00a7r"); + @SubscribeEvent + public void onClickItem(SlotClickEvent event) { + NEUConfig.HiddenProfileSpecific hidden = NotEnoughUpdates.INSTANCE.config.getProfileSpecific(); + if (hidden == null) return; + + if (event.slot == null || !event.slot.getHasStack()) return; + var itemStack = event.slot.getStack(); + if (itemStack.getItem() != Item.getItemFromBlock(Blocks.double_plant) || itemStack.getItemDamage() != 1) return; + if (ItemUtils.getLore(itemStack).contains("§a§lFREE! §a(Every 4 hours)")) { + hidden.lastFreeRiftInfusionApplied = System.currentTimeMillis(); + } + } + @SubscribeEvent(priority = EventPriority.HIGHEST, receiveCanceled = true) public void onChatMessageReceived(ClientChatReceivedEvent event) { NEUConfig.HiddenProfileSpecific hidden = NotEnoughUpdates.INSTANCE.config.getProfileSpecific(); @@ -89,6 +106,10 @@ public class TimersOverlay extends TextTabOverlay { hidden.firstCakeAte = currentTime; return; } + if ("§r§d§lINFUSED! §r§7Used your free dimensional infusion!§r".equals(event.message.getFormattedText())) { + hidden.lastFreeRiftInfusionApplied = currentTime; + return; + } Matcher puzzlerMatcher = PUZZLER_PATTERN.matcher(event.message.getFormattedText()); if (puzzlerMatcher.matches()) { hidden.puzzlerCompleted = currentTime; @@ -220,6 +241,9 @@ public class TimersOverlay extends TextTabOverlay { .getItemInformation() .get("HEAVY_PEARL")); break; + case "Free Rift Infusion": + icon = new ItemStack(Blocks.double_plant, 1, 1); + break; case "Crimson Isle Quests": icon = QUEST_ICON; break; @@ -269,6 +293,18 @@ public class TimersOverlay extends TextTabOverlay { String containerName = lower.getDisplayName().getUnformattedText(); ItemStack stack = lower.getStackInSlot(0); switch (containerName.intern()) { + case "Dimensional Infusion": + if (lower.getSizeInventory() != 9 * 4) break; + var freeInfusionSlot = lower.getStackInSlot(13); + if (freeInfusionSlot == null || freeInfusionSlot.stackSize != 1 || + freeInfusionSlot.getItem() != Item.getItemFromBlock(Blocks.double_plant) || + freeInfusionSlot.getItemDamage() != 1) { + break; + } + if (ItemUtils.getLore(freeInfusionSlot).contains("§a§lFREE! §a(Every 4 hours)")) { + hidden.lastFreeRiftInfusionApplied = 0L; + } + break; case "Commissions": if (lower.getSizeInventory() < 18) { break; @@ -599,6 +635,26 @@ public class TimersOverlay extends TextTabOverlay { } } + // Free Rift Infusion + var miscOverlay = NotEnoughUpdates.INSTANCE.config.miscOverlays; + long riftAvailableAgainIn = hidden.lastFreeRiftInfusionApplied + 1000 * 60 * 60 * 4 - currentTime; + if (riftAvailableAgainIn < 0) { + map.put( + 12, + DARK_AQUA + "Free Rift Infusion: " + + EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.readyColour] + "Ready!" + ); + } else if ((miscOverlay.freeRiftInfusionDisplay == 1 && riftAvailableAgainIn < TimeEnums.HALFANHOUR.time) || + (miscOverlay.freeRiftInfusionDisplay == 2)) { + map.put( + 12, + DARK_AQUA + "Free Rift Infusion: " + + EnumChatFormatting.values()[riftAvailableAgainIn < TimeEnums.HALFANHOUR.time + ? miscOverlay.verySoonColour + : miscOverlay.defaultColour] + Utils.prettyTime(riftAvailableAgainIn) + ); + } + long puzzlerEnd = hidden.puzzlerCompleted + 1000 * 60 * 60 * 24 - currentTime; //Puzzler Display if ((hidden.puzzlerCompleted + TimeEnums.DAY.time) < currentTime) { diff --git a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.kt b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.kt index 1b4f817e..3ee5fdad 100644 --- a/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.kt +++ b/src/main/kotlin/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.kt @@ -41,7 +41,6 @@ class HelpCommand { "§6/cata §b?{name} §2ⴵ §r§7- Opens the profile viewer's Catacombs page.", "§6/neulinks §r§7- Shows links to NEU/Moulberry.", "§6/neuoverlay §r§7- Opens GUI Editor for quickcommands and searchbar.", - "§6/neuah §r§7- Opens NEU's custom auction house GUI.", "§6/neucalendar §r§7- Opens NEU's custom calendar GUI.", "§6/neucalc §r§7- Run calculations.", "", -- cgit