From 663abc4b0728cf0200c9493492bbfb946c393b25 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Mon, 27 May 2024 01:02:49 +0200 Subject: [PATCH 01/22] Fix: Bumped Custom Scoreboard Error Time to 1 second (#1900) --- .../features/gui/customscoreboard/ScoreboardElements.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt index cefa6e67ff98..4c37a3cf07ec 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt @@ -43,11 +43,11 @@ import at.hannibal2.skyhanni.utils.TimeLimitedSet import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.formatted import java.util.function.Supplier -import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds internal var confirmedUnknownLines = mutableListOf() internal var unconfirmedUnknownLines = listOf() -internal var unknownLinesSet = TimeLimitedSet(500.milliseconds) { onRemoval(it) } +internal var unknownLinesSet = TimeLimitedSet(1.seconds) { onRemoval(it) } private fun onRemoval(line: String) { if (!unconfirmedUnknownLines.contains(line)) return From 9ca1458eaeecebbd349fc6780c3f0d22b43dd05f Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Mon, 27 May 2024 08:32:31 +0200 Subject: [PATCH 02/22] added workarounds for profile data not loaded problems --- .../java/at/hannibal2/skyhanni/data/HypixelData.kt | 4 ++-- .../hannibal2/skyhanni/data/ProfileStorageData.kt | 5 +++-- .../java/at/hannibal2/skyhanni/utils/TabListData.kt | 13 +++++++++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index 638c2e0b849d..1662825826f6 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -329,8 +329,6 @@ class HypixelData { } } - if (!event.isMod(5)) return - if (!LorenzUtils.onHypixel) { checkHypixel() if (LorenzUtils.onHypixel) { @@ -340,6 +338,8 @@ class HypixelData { } if (!LorenzUtils.onHypixel) return + if (!event.isMod(5)) return + val inSkyBlock = checkScoreboard() if (inSkyBlock) { checkIsland() diff --git a/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt b/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt index 08dd89539462..c5f072587a7a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt @@ -39,7 +39,7 @@ object ProfileStorageData { val profileName = event.name if (playerSpecific == null) { DelayedRun.runDelayed(10.seconds) { - workaroundIn10Seconds(profileName) + workaroundIn10SecondsProfileStorage(profileName) } ErrorManager.skyHanniError("playerSpecific is null in ProfileJoinEvent!") } @@ -51,7 +51,8 @@ object ProfileStorageData { ConfigLoadEvent().postAndCatch() } - private fun workaroundIn10Seconds(profileName: String) { + private fun workaroundIn10SecondsProfileStorage(profileName: String) { + println("workaroundIn10SecondsProfileStorage") val playerSpecific = playerSpecific val sackPlayers = sackPlayers diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt b/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt index ea930bee4e66..22032ff84fb3 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/TabListData.kt @@ -20,6 +20,7 @@ import net.minecraft.world.WorldSettings import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import net.minecraftforge.fml.relauncher.Side import net.minecraftforge.fml.relauncher.SideOnly +import kotlin.time.Duration.Companion.seconds object TabListData { private var tablistCache = emptyList() @@ -126,6 +127,9 @@ object TabListData { if (tablistCache != tabList) { tablistCache = tabList TabListUpdateEvent(getTabList()).postAndCatch() + if (!LorenzUtils.onHypixel) { + workaroundDelayedTabListUpdateAgain() + } } val tabListOverlay = Minecraft.getMinecraft().ingameGUI.tabList as AccessorGuiPlayerTabOverlay @@ -137,4 +141,13 @@ object TabListData { } footer = tabFooter } + + private fun workaroundDelayedTabListUpdateAgain() { + DelayedRun.runDelayed(2.seconds) { + if (LorenzUtils.onHypixel) { + println("workaroundDelayedTabListUpdateAgain") + TabListUpdateEvent(getTabList()).postAndCatch() + } + } + } } From 239a7b17e15eaa5f3ff8509aecef714d8c277ee9 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Mon, 27 May 2024 08:59:02 +0200 Subject: [PATCH 03/22] added workarounds for profile data not loaded problems --- .../java/at/hannibal2/skyhanni/data/ProfileStorageData.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt b/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt index c5f072587a7a..e44c1089e582 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ProfileStorageData.kt @@ -41,7 +41,7 @@ object ProfileStorageData { DelayedRun.runDelayed(10.seconds) { workaroundIn10SecondsProfileStorage(profileName) } - ErrorManager.skyHanniError("playerSpecific is null in ProfileJoinEvent!") + return } if (sackPlayers == null) { ErrorManager.skyHanniError("sackPlayers is null in ProfileJoinEvent!") @@ -61,7 +61,7 @@ object ProfileStorageData { "failed to load your profile data a second time", "workaround in 10 seconds did not work" ) - ErrorManager.skyHanniError("playerSpecific is null in ProfileJoinEvent!") + ErrorManager.skyHanniError("playerSpecific is still null in ProfileJoinEvent!") } if (sackPlayers == null) { ErrorManager.skyHanniError("sackPlayers is null in ProfileJoinEvent!") From c09e75a41d628d6c90e0294e06ce8c26ed496405 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Mon, 27 May 2024 09:30:10 +0200 Subject: [PATCH 04/22] Version 0.26 Beta 2 --- build.gradle.kts | 2 +- docs/CHANGELOG.md | 47 +++++++++++++++++++ docs/FEATURES.md | 4 ++ .../java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 +- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7a8827a1d84f..1fb2fc67203f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -15,7 +15,7 @@ plugins { } group = "at.hannibal2.skyhanni" -version = "0.26.Beta.1" +version = "0.26.Beta.2" val gitHash by lazy { val baos = ByteArrayOutputStream() diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index b53e9b1fedb7..6476b3d55f5d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -12,6 +12,16 @@ + Show effective area (as a wireframe, filled or circle). + Show mana regeneration buff next to the GUI element. + Option to hide flare particles. ++ Added a "Line to Arachne" setting, just like with slayer minibosses. - azurejelly (https://github.com/hannibal002/SkyHanni/pull/1888) + +#### Garden Features + ++ New "Craftable!" message when Visitor Items Needed are craftable. - Paloys (https://github.com/hannibal002/SkyHanni/pull/1891) + +#### ChatFeatures + ++ Added new chat filters. - Mikecraft1224 (https://github.com/hannibal002/SkyHanni/pull/1750) + + Filters for rare dungeon chest rewards and sacrifice messages from other players. #### Misc Features @@ -36,6 +46,12 @@ + Highlight Treasure Hoarders during Treasure Hoarder Puncher commissions. - Luna (https://github.com/hannibal002/SkyHanni/pull/1852) +#### Commands Improvements + ++ Updated /shcommands. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/1720) + + Now has pages for better navigation. + + Improved visual appearance. + #### Misc Improvements + Added a toggle for 24-hour time. - seraid (https://github.com/hannibal002/SkyHanni/pull/1804) @@ -56,6 +72,37 @@ + Fixed farming contests showing in the election GUI. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1871) + Fixed wrong icon for the rat crop type in Stereo Harmony display. - raven (https://github.com/hannibal002/SkyHanni/pull/1849) +#### Chocolate Factory Fixes + ++ Fixed some Chocolate Factory issues caused by a Hypixel update. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1860) + +#### Custom Scoreboard Fixes + ++ Fixed scoreboard player count not displaying in dungeons. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/1894) + +#### Dungeon Fixes + ++ Fixed healer orb pickup hider. - Mikecraft1224 (https://github.com/hannibal002/SkyHanni/pull/1750) ++ Fixed Dungeon Rank Tab list color not showing the names of players with YouTube/Admin rank. - Empa (https://github.com/hannibal002/SkyHanni/pull/1878) + +#### Mining Fixes + ++ Fixed a typo in Tunnels Maps. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/1883) + +#### Performance Fixes + ++ Fixed small memory leaks when staying in one island for extended periods. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/1890) + +### Technical Details + ++ Use more simple time mark. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1777) ++ Removed all uses of ChatUtils.sendCommandToServer, replacing with HypixelCommands.. - Empa (https://github.com/hannibal002/SkyHanni/pull/1769) ++ Use fewer deprecated LorenzVec functions. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1556) ++ Cleanup of duplicate code in EntityUtils. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1556) ++ Move regex and pattern operations to RegexUtils. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1854) ++ Added Track Particles command. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1787) ++ Fixed stacked mob highlights. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/1856) + ## Version 0.25 ### New Features diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 95d1d781afc1..f143e448efc3 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -54,6 +54,8 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. - Powder Mining messages hider - Winter gift messages hider - Many other messages (Not separated into own categories yet) ++ Added new chat filters. - Mikecraft1224 (https://github.com/hannibal002/SkyHanni/pull/1750) + + Filters for rare dungeon chest rewards and sacrifice messages from other players.
@@ -491,6 +493,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Highlight corrupted mobs. + **Arachne Minis Hider** - Hides the nametag above arachne minis. + **Arachne Boss Highlighter** - Highlight the arachne boss in red and mini bosses and orange. ++ "Line to Arachne" setting, just like with slayer minibosses. - azurejelly (https://github.com/hannibal002/SkyHanni/pull/1888) + Countdown for Arachne spawn. - Cad + Supports quick spawns. + Option to hide the vanilla particles around enderman @@ -693,6 +696,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Added Super Craft button to visitors for ease of access. - Conutik (https://github.com/hannibal002/SkyHanni/pull/1173) + Checks if you have enough materials to craft the items and depending on that shows the button or not. + Overflow Garden crop milestones. - Luna & HiZe (https://github.com/hannibal002/SkyHanni/pull/997) ++ New "Craftable!" message when Visitor Items Needed are craftable. - Paloys (https://github.com/hannibal002/SkyHanni/pull/1891)
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index a668c928d91b..8258a58dd513 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -490,7 +490,7 @@ import org.apache.logging.log4j.Logger clientSideOnly = true, useMetadata = true, guiFactory = "at.hannibal2.skyhanni.config.ConfigGuiForgeInterop", - version = "0.26.Beta.1", + version = "0.26.Beta.2", ) class SkyHanniMod { From 00013413f63de6ce628a1060c792cdbb7f324042 Mon Sep 17 00:00:00 2001 From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Date: Wed, 29 May 2024 00:03:52 +1000 Subject: [PATCH 05/22] fix not found rabbit pattern (#1906) --- .../features/event/hoppity/HoppityCollectionStats.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt index a078ea9d25c1..ef45042396a7 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt @@ -36,9 +36,14 @@ object HoppityCollectionStats { "duplicates.found", "§7Duplicates Found: §a(?[\\d,]+)" ) + + /** + * REGEX-TEST: §7§8You cannot find this rabbit until you + * REGEX-TEST: §7§8You have not found this rabbit yet! + */ private val rabbitNotFoundPattern by patternGroup.pattern( "rabbit.notfound", - "(?:§.)+You have not found this rabbit yet!" + "(?:§.)+You (?:have not found this rabbit yet!|cannot find this rabbit until you)" ) private val rabbitsFoundPattern by patternGroup.pattern( "rabbits.found", From 88fc5b7514a69f8b8fc05d7b74104e2036b00c89 Mon Sep 17 00:00:00 2001 From: raaaaaven <168305416+raaaaaven@users.noreply.github.com> Date: Tue, 28 May 2024 16:45:14 +0100 Subject: [PATCH 06/22] Improvement: Adjusted Chocolate Factory Keybinds (#1907) Co-authored-by: raven --- .../ChocolateFactoryKeybindsConfig.java | 10 ++++++++++ .../chocolatefactory/ChocolateFactoryKeybinds.kt | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryKeybindsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryKeybindsConfig.java index 7e68a1d7a92e..bd42edbe15bd 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryKeybindsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryKeybindsConfig.java @@ -38,4 +38,14 @@ public class ChocolateFactoryKeybindsConfig { @ConfigOption(name = "Key 5", desc = "Key for Rabbit Granny.") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_5) public int key5 = Keyboard.KEY_5; + + @Expose + @ConfigOption(name = "Key 6", desc = "Key for Rabbit Uncle.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_6) + public int key6 = Keyboard.KEY_6; + + @Expose + @ConfigOption(name = "Key 7", desc = "Key for Rabbit Dog.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_7) + public int key7 = Keyboard.KEY_7; } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryKeybinds.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryKeybinds.kt index 2c0920db3bef..546e127c4c2b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryKeybinds.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryKeybinds.kt @@ -22,7 +22,7 @@ object ChocolateFactoryKeybinds { val chest = event.guiContainer as? GuiChest ?: return - for (index in 0..4) { + for (index in 0..6) { val key = getKey(index) ?: error("no key for index $index") if (!key.isKeyClicked()) continue if (lastClick.passedSince() < 200.milliseconds) break @@ -32,7 +32,7 @@ object ChocolateFactoryKeybinds { Minecraft.getMinecraft().playerController.windowClick( chest.inventorySlots.windowId, - 29 + index, + 28 + index, 2, 3, Minecraft.getMinecraft().thePlayer @@ -59,6 +59,8 @@ object ChocolateFactoryKeybinds { 2 -> config.key3 3 -> config.key4 4 -> config.key5 + 5 -> config.key6 + 6 -> config.key7 else -> null } } From c86c551a1da561b609b2ace62fe94a262435ca5b Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Tue, 28 May 2024 20:30:10 +0200 Subject: [PATCH 07/22] added error message when livid finder cant find livid --- .../features/dungeon/DungeonLividFinder.kt | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt index 4d4bb68047d4..becbb896bbc3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonLividFinder.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.mixins.hooks.RenderLivingEntityHelper import at.hannibal2.skyhanni.test.GriffinUtils.drawWaypointFilled +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.BlockUtils.getBlockStateAt import at.hannibal2.skyhanni.utils.ColorUtils.withAlpha import at.hannibal2.skyhanni.utils.EntityUtils @@ -50,13 +51,30 @@ object DungeonLividFinder { if (!config.enabled) return val dyeColor = blockLocation.getBlockStateAt().getValue(BlockStainedGlass.COLOR) - color = dyeColor.toLorenzColor() ?: error("No color found for dye color `$dyeColor`") + color = dyeColor.toLorenzColor() val color = color ?: return val chatColor = color.getChatColor() lividArmorStand = EntityUtils.getEntities() .firstOrNull { it.name.startsWith("${chatColor}﴾ ${chatColor}§lLivid") } + + if (event.isMod(20)) { + if (lividArmorStand == null) { + val amountArmorStands = EntityUtils.getEntities().filter { it.name.contains("Livid") }.count() + if (amountArmorStands >= 8) { + ErrorManager.logErrorStateWithData( + "Could not find livid", + "could not find lividArmorStand", + "dyeColor" to dyeColor, + "color" to color, + "chatColor" to chatColor, + "amountArmorStands" to amountArmorStands, + ) + } + } + } + val lividArmorStand = lividArmorStand ?: return val aabb = with(lividArmorStand) { From 36cea7d410a3f0cca792e1212cfb4d2536bb8f51 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 28 May 2024 21:20:09 +0200 Subject: [PATCH 08/22] Fix: Scoreboard Time Pattern (#1909) --- .../features/gui/customscoreboard/ScoreboardPattern.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt index e5637ab97e7c..ec4cf0c6f4f3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt @@ -38,9 +38,13 @@ object ScoreboardPattern { "date", "^\\s*(Late |Early )?(Spring|Summer|Autumn|Winter) \\d{1,2}(st|nd|rd|th)?.*" ) + /* + * REGEX-TEST: §78:50am + * REGEX-TEST: §75:50am §b☽ + */ val timePattern by mainSb.pattern( "time", - "^\\s*§7\\d{1,2}:\\d{2}(?:am|pm) (?(§b☽|§e☀|§.⚡|§.☔)).*$" + "^\\s*§7\\d{1,2}:\\d{2}(?:am|pm)\\s*(?(§b☽|§e☀|§.⚡|§.☔))?.*$" ) val footerPattern by mainSb.pattern( "footer", From 594164c67105eb6f03f92e31697d233a5b679f39 Mon Sep 17 00:00:00 2001 From: fabi <85846799+fahr-plan@users.noreply.github.com> Date: Tue, 28 May 2024 23:30:46 +0200 Subject: [PATCH 09/22] Fix: typo in shclearkismet command (#1912) --- src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index d0fd99dd0f38..881861ad3a49 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -387,7 +387,7 @@ object Commands { "Shows the status of all the mods constants" ) { SkyHanniMod.repo.displayRepoStatus(false) } registerCommand( - "shclearksimet", + "shclearkismet", "Cleares the saved values of the applied kismet feathers in Croesus" ) { CroesusChestTracker.resetChest() } registerCommand( From e6785c803b22a8595234bf4b07da40ddaedbec96 Mon Sep 17 00:00:00 2001 From: saga <45262877+saga-00@users.noreply.github.com> Date: Tue, 28 May 2024 18:32:39 -0300 Subject: [PATCH 10/22] Improvement: Teleport to Infested plot defaults to Warp Garden (#1910) --- .../config/features/garden/pests/PestFinderConfig.java | 5 +++++ .../hannibal2/skyhanni/features/garden/pests/PestFinder.kt | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/PestFinderConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/PestFinderConfig.java index ae2819317503..20f840084e54 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/PestFinderConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/pests/PestFinderConfig.java @@ -87,4 +87,9 @@ public String toString() { @ConfigOption(name = "Always Teleport", desc = "Allow teleporting with the Teleport Hotkey even when you're already in an infested plot.") @ConfigEditorBoolean public boolean alwaysTp = false; + + @Expose + @ConfigOption(name = "Back to Garden", desc = "Make the Teleport Hotkey warp you to Garden if you don't have any pests.") + @ConfigEditorBoolean + public boolean backToGarden = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestFinder.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestFinder.kt index d60ed737bb93..4656ef06273c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestFinder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestFinder.kt @@ -172,7 +172,10 @@ object PestFinder { if (!GardenAPI.inGarden()) { ChatUtils.userError("This command only works while on the Garden!") } + val plot = PestAPI.getNearestInfestedPlot() ?: run { + if (config.backToGarden) return HypixelCommands.warp("garden") + ChatUtils.userError("No infested plots detected to warp to!") return } From 093d18da6ec6f1ab7fb4391b4736164404eb2fae Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Wed, 29 May 2024 07:31:39 +0200 Subject: [PATCH 11/22] Avoid using deprecated functions --- CONTRIBUTING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 28142d32b7cf..6588b9a95bb7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,9 @@ format like "- #821" to illustrate the dependency. - All new classes should be written in Kotlin, with a few exceptions: - Config files in `at.hannibal2.skyhanni.config.features` - Mixin classes in `at.hannibal2.skyhanni.mixins.transformers` +- Avoid using deprecated functions. + - These functions are marked for removal in future versions. + - If you're unsure why a function is deprecated or how to replace it, please ask for guidance. - Future JSON data objects should be made in kotlin and placed in the directory `at.hannibal2.skyhanni.data.jsonobjects` - Config files should still be made in Java. - Please use the existing event system, or expand on it. Do not use Forge events. From a1801699f7191de07523c8d54359234645c20520 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal002@users.noreply.github.com> Date: Wed, 29 May 2024 07:34:13 +0200 Subject: [PATCH 12/22] Fix: Warping to Base in GUI (#1911) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt index 3a9f26cf0f9e..7aed4e607270 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt @@ -32,18 +32,19 @@ import at.hannibal2.skyhanni.utils.LorenzColor.Companion.toLorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches +import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst +import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils import at.hannibal2.skyhanni.utils.RenderUtils.draw3DPathWithWaypoint import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow -import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches -import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst -import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.client.Minecraft import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.awt.Color import kotlin.math.roundToInt @@ -112,6 +113,7 @@ class TunnelsMaps { private val commissionInvPattern by RepoPattern.pattern( "mining.commission.inventory", "Commissions" ) + /** * REGEX-TEST: §7- §b277 Glacite Powder * REGEX-TEST: §7- §b1,010 Glacite Powder @@ -414,6 +416,7 @@ class TunnelsMaps { @SubscribeEvent fun onKeyPress(event: LorenzKeyPressEvent) { if (!isEnabled()) return + if (Minecraft.getMinecraft().currentScreen != null) return campfireKey(event) nextSpotKey(event) } From 2250aa8b2a64ea1f1850b74c5f4f34ffa617609e Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal002@users.noreply.github.com> Date: Wed, 29 May 2024 07:43:22 +0200 Subject: [PATCH 13/22] Feature: Trophy Fish Display (#1754) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 + .../TrophyFishDisplayConfig.java | 202 +++++++++++++ .../trophyfishing/TrophyFishingConfig.java | 5 + .../hannibal2/skyhanni/data/GuiEditManager.kt | 2 +- .../events/fishing/TrophyFishCaughtEvent.kt | 7 + .../skyhanni/features/fishing/FishingAPI.kt | 19 ++ .../features/fishing/ShowFishingItemName.kt | 2 +- .../fishing/tracker/SeaCreatureTracker.kt | 25 +- .../features/fishing/trophy/TrophyFishAPI.kt | 31 ++ .../fishing/trophy/TrophyFishDisplay.kt | 272 ++++++++++++++++++ .../fishing/trophy/TrophyFishManager.kt | 25 +- .../fishing/trophy/TrophyFishMessages.kt | 6 +- .../skyhanni/features/slayer/HideMobNames.kt | 2 +- .../features/slayer/SlayerItemsOnGround.kt | 2 +- .../features/summonings/SummoningSoulsName.kt | 4 +- .../skyhanni/utils/CollectionUtils.kt | 4 + .../skyhanni/utils/TimeLimitedCache.kt | 11 +- .../skyhanni/utils/TimeLimitedSet.kt | 6 +- 18 files changed, 570 insertions(+), 57 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishDisplayConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/events/fishing/TrophyFishCaughtEvent.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishAPI.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 8258a58dd513..4cb09bfe97cb 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -177,6 +177,7 @@ import at.hannibal2.skyhanni.features.fishing.tracker.FishingProfitTracker import at.hannibal2.skyhanni.features.fishing.tracker.SeaCreatureTracker import at.hannibal2.skyhanni.features.fishing.trophy.GeyserFishing import at.hannibal2.skyhanni.features.fishing.trophy.OdgerWaypoint +import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishDisplay import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishFillet import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishManager import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishMessages @@ -734,6 +735,7 @@ class SkyHanniMod { loadModule(SharkFishCounter()) loadModule(PowerStoneGuideFeatures()) loadModule(OdgerWaypoint()) + loadModule(TrophyFishDisplay()) loadModule(TiaRelayHelper()) loadModule(TiaRelayWaypoints()) loadModule(BasketWaypoints()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishDisplayConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishDisplayConfig.java new file mode 100644 index 000000000000..a4fa9940fe39 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishDisplayConfig.java @@ -0,0 +1,202 @@ +package at.hannibal2.skyhanni.config.features.fishing.trophyfishing; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import com.google.gson.annotations.Expose; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDropdown; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorKeybind; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; +import org.lwjgl.input.Keyboard; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class TrophyFishDisplayConfig { + + @Expose + @ConfigOption( + name = "Enabled", + desc = "Show a display of all trophy fishes ever caught." + ) + @ConfigEditorBoolean + @FeatureToggle + public Property enabled = Property.of(false); + + @Expose + @ConfigOption(name = "When Show", desc = "Change when the trophy fish display should be visible in Crimson Isle.") + @ConfigEditorDropdown + public Property whenToShow = Property.of(WhenToShow.ALWAYS); + + public enum WhenToShow { + ALWAYS("Always"), + ONLY_IN_INVENTORY("In inventory"), + ONLY_WITH_ROD_IN_HAND("Rod in hand"), + ONLY_WITH_KEYBIND("On keybind"), + ; + + private final String str; + + WhenToShow(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigOption(name = "Keybind", desc = "") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) + public int keybind = Keyboard.KEY_NONE; + + @Expose + @ConfigOption( + name = "Hunter Armor", + desc = "Only show when wearing a full Hunter Armor." + ) + @ConfigEditorBoolean + public Property requireHunterArmor = Property.of(false); + + @Expose + @ConfigOption( + name = "Highlight New", + desc = "Highlight new trophies green for couple seconds." + ) + @ConfigEditorBoolean + public Property highlightNew = Property.of(true); + + @Expose + @ConfigOption(name = "Extra space", desc = "Space between each line of text.") + @ConfigEditorSlider( + minValue = 0, + maxValue = 10, + minStep = 1) + public Property extraSpace = Property.of(1); + + @Expose + @ConfigOption(name = "Sorted By", desc = "Sorting type of items in sack.") + @ConfigEditorDropdown + public Property sortingType = Property.of(TrophySorting.ITEM_RARITY); + + public enum TrophySorting { + ITEM_RARITY("Item Rarity"), + TOTAL_AMOUNT("Total Amount"), + BRONZE_AMOUNT("Bronze Amount"), + SILVER_AMOUNT("Silver Amount"), + GOLD_AMOUNT("Gold Amount"), + DIAMOND_AMOUNT("Diamond Amount"), + HIGHEST_RARITY("Highest Rariy"), + NAME("Name Alphabetical"), + ; + + private final String str; + + TrophySorting(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigOption( + name = "Reverse Order", + desc = "Reverse the sorting order." + ) + @ConfigEditorBoolean + public Property reverseOrder = Property.of(false); + + @Expose + @ConfigOption( + name = "Text Order", + desc = "Drag text to change the line format." + ) + @ConfigEditorDraggableList + public Property> textOrder = Property.of(new ArrayList<>(Arrays.asList( + TextPart.NAME, + TextPart.ICON, + TextPart.TOTAL, + TextPart.BRONZE, + TextPart.SILVER, + TextPart.GOLD, + TextPart.DIAMOND + ))); + + public enum TextPart { + ICON("Item Icon"), + NAME("Item Name"), + BRONZE("Amount Bronze"), + SILVER("Amount Silver"), + GOLD("Amount Gold"), + DIAMOND("Amount Diamond"), + TOTAL("Amount Total"), + ; + + private final String str; + + TextPart(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigOption( + name = "Show ✖", + desc = "instead of the number 0, show §c✖ §7 if not found." + ) + @ConfigEditorBoolean + public Property showCross = Property.of(false); + + @Expose + @ConfigOption( + name = "Show ✔", + desc = "instead of the exact numbers, show §e§l✔ §7 if found." + ) + @ConfigEditorBoolean + public Property showCheckmark = Property.of(false); + + @Expose + @ConfigOption(name = "Only Show Missing", desc = "Only show Trophy Fishes that are still missing at this rarity.") + @ConfigEditorDropdown + public Property onlyShowMissing = Property.of(HideCaught.NONE); + + public enum HideCaught { + NONE("Show All"), + BRONZE("Bronze"), + SILVER("Silver"), + GOLD("Gold"), + DIAMOND("Diamond"), + ; + + private final String str; + + HideCaught(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigLink(owner = TrophyFishDisplayConfig.class, field = "enabled") + public Position position = new Position(144, 139, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishingConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishingConfig.java index 25f54286376b..3449c7b5a1c0 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishingConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/fishing/trophyfishing/TrophyFishingConfig.java @@ -14,6 +14,11 @@ public class TrophyFishingConfig { @Accordion public ChatMessagesConfig chatMessages = new ChatMessagesConfig(); + @Expose + @ConfigOption(name = "Trophy Fishing Display", desc = "") + @Accordion + public TrophyFishDisplayConfig display = new TrophyFishDisplayConfig(); + @Expose @ConfigOption(name = "Geyser Fishing", desc = "") @Accordion diff --git a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt index af68cd84733e..f1056577641f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt @@ -79,7 +79,7 @@ class GuiEditManager { name = if (posLabel == "none") "none " + UUID.randomUUID() else posLabel position.internalName = name } - currentPositions.put(name, position) + currentPositions[name] = position currentBorderSize[posLabel] = Pair(x, y) } diff --git a/src/main/java/at/hannibal2/skyhanni/events/fishing/TrophyFishCaughtEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/fishing/TrophyFishCaughtEvent.kt new file mode 100644 index 000000000000..358b057bc422 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/fishing/TrophyFishCaughtEvent.kt @@ -0,0 +1,7 @@ +package at.hannibal2.skyhanni.events.fishing + +import at.hannibal2.skyhanni.events.LorenzEvent +import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity + +// trophyFishName is NO Neu Internal Name +class TrophyFishCaughtEvent(val trophyFishName: String, val rarity: TrophyRarity) : LorenzEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingAPI.kt index 3be2e00b8956..72a7cb13177d 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/FishingAPI.kt @@ -11,6 +11,7 @@ import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishManager import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishManager.getFilletValue import at.hannibal2.skyhanni.features.fishing.trophy.TrophyRarity import at.hannibal2.skyhanni.utils.BlockUtils.getBlockAt +import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemCategory import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull @@ -18,7 +19,9 @@ import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.StringUtils.matches import at.hannibal2.skyhanni.utils.getLorenzVec +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft import net.minecraft.entity.item.EntityArmorStand import net.minecraft.entity.projectile.EntityFishHook @@ -29,6 +32,11 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object FishingAPI { + private val trophyArmorNames by RepoPattern.pattern( + "fishing.trophyfishing.armor", + "(BRONZE|SILVER|GOLD|DIAMOND)_HUNTER_(HELMET|CHESTPLATE|LEGGINGS|BOOTS)" + ) + val lavaBlocks = listOf(Blocks.lava, Blocks.flowing_lava) private val waterBlocks = listOf(Blocks.water, Blocks.flowing_water) @@ -43,6 +51,8 @@ object FishingAPI { var bobber: EntityFishHook? = null var bobberHasTouchedWater = false + var wearingTrophyArmor = false + @SubscribeEvent fun onJoinWorld(event: EntityJoinWorldEvent) { if (!LorenzUtils.inSkyBlock || !holdingRod) return @@ -69,6 +79,11 @@ object FishingAPI { @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!LorenzUtils.inSkyBlock) return + + if (event.isMod(5)) { + wearingTrophyArmor = isWearingTrophyArmor() + } + val bobber = bobber ?: return if (bobber.isDead) { resetBobber() @@ -145,4 +160,8 @@ object FishingAPI { } return 1 } + + private fun isWearingTrophyArmor(): Boolean = InventoryUtils.getArmor().all { + trophyArmorNames.matches(it?.getInternalName()?.asString()) + } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/ShowFishingItemName.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/ShowFishingItemName.kt index 13bd451f7406..7587e5536af7 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/ShowFishingItemName.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/ShowFishingItemName.kt @@ -51,7 +51,7 @@ class ShowFishingItemName { text += name } - itemsOnGround.put(entityItem, text) + itemsOnGround[entityItem] = text } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/tracker/SeaCreatureTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/tracker/SeaCreatureTracker.kt index 3f86b5a420d6..ab9498b8c259 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/tracker/SeaCreatureTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/tracker/SeaCreatureTracker.kt @@ -4,7 +4,6 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.FishingBobberCastEvent import at.hannibal2.skyhanni.events.GuiRenderEvent -import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.SeaCreatureFishEvent import at.hannibal2.skyhanni.features.fishing.FishingAPI import at.hannibal2.skyhanni.features.fishing.SeaCreatureManager @@ -13,8 +12,6 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.addAsSingletonList import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.CollectionUtils.sumAllValues import at.hannibal2.skyhanni.utils.ConditionalUtils -import at.hannibal2.skyhanni.utils.InventoryUtils -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.addButton import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators @@ -26,21 +23,13 @@ import at.hannibal2.skyhanni.utils.tracker.SkyHanniTracker import at.hannibal2.skyhanni.utils.tracker.TrackerData import com.google.gson.annotations.Expose import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.time.Duration.Companion.seconds object SeaCreatureTracker { private val config get() = SkyHanniMod.feature.fishing.seaCreatureTracker - private val trophyArmorNames by RepoPattern.pattern( - "fishing.trophyfishing.armor", - "(BRONZE|SILVER|GOLD|DIAMOND)_HUNTER_(HELMET|CHESTPLATE|LEGGINGS|BOOTS)" - ) - private val tracker = SkyHanniTracker("Sea Creature Tracker", { Data() }, { it.fishing.seaCreatureTracker }) { drawDisplay(it) } - private var lastArmorCheck = SimpleTimeMark.farPast() - private var isTrophyFishing = false class Data : TrackerData() { @@ -171,16 +160,6 @@ object SeaCreatureTracker { tracker.resetCommand() } - private fun isEnabled() = LorenzUtils.inSkyBlock && config.enabled && !isTrophyFishing && !LorenzUtils.inKuudraFight - - private fun isWearingTrophyArmor(): Boolean = InventoryUtils.getArmor().all { - trophyArmorNames.matches(it?.getInternalName()?.asString()) - } - - @SubscribeEvent - fun onTick(event: LorenzTickEvent) { - if (lastArmorCheck.passedSince() < 3.seconds) return - lastArmorCheck = SimpleTimeMark.now() - isTrophyFishing = isWearingTrophyArmor() - } + private fun isEnabled() = + LorenzUtils.inSkyBlock && config.enabled && !FishingAPI.wearingTrophyArmor && !LorenzUtils.inKuudraFight } diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishAPI.kt new file mode 100644 index 000000000000..fec662f396a6 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishAPI.kt @@ -0,0 +1,31 @@ +package at.hannibal2.skyhanni.features.fishing.trophy + +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.StringUtils.splitLines + +object TrophyFishAPI { + + fun hoverInfo(internalName: String): String? { + val trophyFishes = TrophyFishManager.fish ?: return null + val info = TrophyFishManager.getInfo(internalName) ?: return null + val counts = trophyFishes[internalName] ?: emptyMap() + val bestFishObtained = counts.keys.maxOrNull() ?: TrophyRarity.BRONZE + val rateString = if (info.rate != null) "§8[§7${info.rate}%§8]" else "" + return """ + |${info.displayName} $rateString + |${info.description.splitLines(150)} + | + |${TrophyRarity.DIAMOND.formattedString}: ${formatCount(counts, TrophyRarity.DIAMOND)} + |${TrophyRarity.GOLD.formattedString}: ${formatCount(counts, TrophyRarity.GOLD)} + |${TrophyRarity.SILVER.formattedString}: ${formatCount(counts, TrophyRarity.SILVER)} + |${TrophyRarity.BRONZE.formattedString}: ${formatCount(counts, TrophyRarity.BRONZE)} + | + |§7Total: ${bestFishObtained.formatCode}${counts.values.sum().addSeparators()} + """.trimMargin() + } + + private fun formatCount(counts: Map, rarity: TrophyRarity): String { + val count = counts.getOrDefault(rarity, 0) + return if (count > 0) "§6${count.addSeparators()}" else "§c✖" + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt new file mode 100644 index 000000000000..a25f2d9c2465 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt @@ -0,0 +1,272 @@ +package at.hannibal2.skyhanni.features.fishing.trophy + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.features.fishing.trophyfishing.TrophyFishDisplayConfig.HideCaught +import at.hannibal2.skyhanni.config.features.fishing.trophyfishing.TrophyFishDisplayConfig.TextPart +import at.hannibal2.skyhanni.config.features.fishing.trophyfishing.TrophyFishDisplayConfig.TrophySorting +import at.hannibal2.skyhanni.config.features.fishing.trophyfishing.TrophyFishDisplayConfig.WhenToShow +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.ConfigLoadEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent +import at.hannibal2.skyhanni.events.ProfileJoinEvent +import at.hannibal2.skyhanni.events.fishing.TrophyFishCaughtEvent +import at.hannibal2.skyhanni.features.fishing.FishingAPI +import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValue +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.CollectionUtils.addSingleString +import at.hannibal2.skyhanni.utils.CollectionUtils.addString +import at.hannibal2.skyhanni.utils.CollectionUtils.sumAllValues +import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.ItemUtils.getItemRarityOrNull +import at.hannibal2.skyhanni.utils.ItemUtils.itemName +import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NEUItems +import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.TimeLimitedCache +import at.hannibal2.skyhanni.utils.renderables.Renderable +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.inventory.GuiInventory +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds + +class TrophyFishDisplay { + private val config get() = SkyHanniMod.feature.fishing.trophyFishing.display + + private var recentlyDroppedTrophies = TimeLimitedCache(5.seconds) + private val itemNameCache = mutableMapOf() + + private var display = emptyList() + + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + if (event.newIsland == IslandType.CRIMSON_ISLE) { + DelayedRun.runDelayed(200.milliseconds) { + update() + } + } + } + + @SubscribeEvent + fun onTrophyFishCaught(event: TrophyFishCaughtEvent) { + recentlyDroppedTrophies[getInternalName(event.trophyFishName)] = event.rarity + update() + DelayedRun.runDelayed(5.1.seconds) { + update() + } + } + + @SubscribeEvent + fun onProfileJoin(event: ProfileJoinEvent) { + display = emptyList() + update() + } + + @SubscribeEvent + fun onConfigReload(event: ConfigLoadEvent) { + with(config) { + ConditionalUtils.onToggle( + enabled, + highlightNew, + extraSpace, + sortingType, + reverseOrder, + textOrder, + showCross, + showCheckmark, + onlyShowMissing, + ) { + update() + } + } + } + + fun update() { + if (!isEnabled()) return + val list = mutableListOf() + list.addString("§e§lTrophy Fish Display") + list.add(Renderable.table(createTable(), yPadding = config.extraSpace.get())) + + display = list + } + + private fun createTable(): List> { + val trophyFishes = TrophyFishManager.fish ?: return emptyList() + val table = mutableListOf>() + for ((rawName, data) in getOrder(trophyFishes)) { + addRow(rawName, data, table) + } + if (table.isEmpty()) { + get(config.onlyShowMissing.get())?.let { rarity -> + val name = rarity.formattedString + table.addSingleString("§eYou caught all $name Trophy Fishes") + if (rarity != TrophyRarity.DIAMOND) { + table.addSingleString("§cChange §eOnly Show Missing §cin the config to show more.") + } + } + } + return table + } + + private fun addRow( + rawName: String, + data: MutableMap, + table: MutableList>, + ) { + get(config.onlyShowMissing.get())?.let { atLeast -> + val list = TrophyRarity.entries.filter { it <= atLeast } + if (list.all { (data[it] ?: 0) > 0 }) { + return + } + } + val hover = TrophyFishAPI.hoverInfo(rawName) + fun string(string: String): Renderable = hover?.let { + Renderable.hoverTips(Renderable.string(string), tips = it.split("\n")) + } ?: Renderable.string(string) + + val row = mutableMapOf() + row[TextPart.NAME] = string(getItemName(rawName)) + + val internalName = getInternalName(rawName) + row[TextPart.ICON] = Renderable.itemStack(internalName.getItemStack()) + + val recentlyDroppedRarity = recentlyDroppedTrophies.getOrNull(internalName).takeIf { config.highlightNew.get() } + + for (rarity in TrophyRarity.entries) { + val amount = data[rarity] ?: 0 + val recentlyDropped = rarity == recentlyDroppedRarity + val format = if (config.showCross.get() && amount == 0) "§c✖" else { + val color = if (recentlyDropped) "§a" else rarity.formatCode + val numberformat = if (config.showCheckmark.get()) "§l✔" else amount.addSeparators() + "$color$numberformat" + } + row[get(rarity)] = string(format) + } + val total = data.sumAllValues() + val color = if (recentlyDroppedRarity != null) "§a" else "§5" + row[TextPart.TOTAL] = string("$color${total.addSeparators()}") + + table.add(config.textOrder.get().mapNotNull { row[it] }) + } + + private fun get(value: TrophyRarity) = when (value) { + TrophyRarity.BRONZE -> TextPart.BRONZE + TrophyRarity.SILVER -> TextPart.SILVER + TrophyRarity.GOLD -> TextPart.GOLD + TrophyRarity.DIAMOND -> TextPart.DIAMOND + } + + private fun get(value: HideCaught) = when (value) { + HideCaught.NONE -> null + HideCaught.BRONZE -> TrophyRarity.BRONZE + HideCaught.SILVER -> TrophyRarity.SILVER + HideCaught.GOLD -> TrophyRarity.GOLD + HideCaught.DIAMOND -> TrophyRarity.DIAMOND + } + + private fun getOrder(trophyFishes: MutableMap>) = sort(trophyFishes).let { + if (config.reverseOrder.get()) it.reversed() else it + } + + private fun sort(trophyFishes: Map>): List>> = + when (config.sortingType.get()!!) { + TrophySorting.TOTAL_AMOUNT -> trophyFishes.entries.sortedBy { it.value.sumAllValues() } + + TrophySorting.BRONZE_AMOUNT -> count(trophyFishes, TrophyRarity.BRONZE) + TrophySorting.SILVER_AMOUNT -> count(trophyFishes, TrophyRarity.SILVER) + TrophySorting.GOLD_AMOUNT -> count(trophyFishes, TrophyRarity.GOLD) + TrophySorting.DIAMOND_AMOUNT -> count(trophyFishes, TrophyRarity.DIAMOND) + + TrophySorting.ITEM_RARITY -> { + trophyFishes.entries.sortedBy { data -> + val name = getInternalName(data.key) + name.getItemStack().getItemRarityOrNull() + } + } + + TrophySorting.HIGHEST_RARITY -> { + trophyFishes.entries.sortedBy { data -> + TrophyRarity.entries.filter { + data.value.contains(it) + }.maxByOrNull { it.ordinal } + } + } + + TrophySorting.NAME -> { + trophyFishes.entries.sortedBy { data -> + getItemName(data.key).removeColor() + } + } + } + + private fun count( + trophyFishes: Map>, rarity: TrophyRarity, + ) = trophyFishes.entries.sortedBy { it.value[rarity] ?: 0 } + + private fun getItemName(rawName: String): String { + val name = getInternalName(rawName).itemName + return name.split(" ").dropLast(1).joinToString(" ").replace("§k", "") + } + + private fun getInternalName(name: String): NEUInternalName { + itemNameCache[name]?.let { + return it + } + // getOrPut does not support our null check + readInternalName(name)?.let { + itemNameCache[name] = it + return it + } + + ErrorManager.skyHanniError( + "No Trophy Fishing name found", + "name" to name + ) + } + + private fun readInternalName(rawName: String): NEUInternalName? { + for ((name, internalName) in NEUItems.allItemsCache) { + val test = name.removeColor().replace(" ", "").replace("-", "") + if (test.startsWith(rawName)) { + return internalName + } + } + if (rawName.endsWith("1")) return "OBFUSCATED_FISH_1_BRONZE".asInternalName() + if (rawName.endsWith("2")) return "OBFUSCATED_FISH_2_BRONZE".asInternalName() + if (rawName.endsWith("3")) return "OBFUSCATED_FISH_3_BRONZE".asInternalName() + + return null + } + + @SubscribeEvent + fun onGuiRender(event: GuiRenderEvent) { + if (!isEnabled()) return + if (!canRender()) return + if (EstimatedItemValue.isCurrentlyShowing()) return + + if (config.requireHunterArmor.get() && !FishingAPI.wearingTrophyArmor) return + + config.position.renderRenderables( + display, + extraSpace = config.extraSpace.get(), + posLabel = "Trophy Fishing Display" + ) + } + + fun canRender(): Boolean = when (config.whenToShow.get()!!) { + WhenToShow.ALWAYS -> true + WhenToShow.ONLY_IN_INVENTORY -> Minecraft.getMinecraft().currentScreen is GuiInventory + WhenToShow.ONLY_WITH_ROD_IN_HAND -> FishingAPI.holdingLavaRod + WhenToShow.ONLY_WITH_KEYBIND -> config.keybind.isKeyHeld() + } + + fun isEnabled() = IslandType.CRIMSON_ISLE.isInIsland() && config.enabled.get() +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt index 564e56edfd7d..77701c1b06e7 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt @@ -8,8 +8,6 @@ import at.hannibal2.skyhanni.events.NeuProfileDataLoadedEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.StringUtils.splitLines import net.minecraft.event.HoverEvent import net.minecraft.util.ChatComponentText import net.minecraft.util.ChatStyle @@ -81,15 +79,10 @@ object TrophyFishManager { private var trophyFishInfo = mapOf() - fun getInfo(internalName: String) = trophyFishInfo[internalName] + fun getInfo(internalName: String): TrophyFishInfo? = trophyFishInfo[internalName] fun getInfoByName(name: String) = trophyFishInfo.values.find { it.displayName == name } - private fun formatCount(counts: Map, rarity: TrophyRarity): String { - val count = counts.getOrDefault(rarity, 0) - return if (count > 0) "§6${count.addSeparators()}" else "§c✖" - } - fun TrophyFishInfo.getFilletValue(rarity: TrophyRarity): Int { if (fillet == null) { ErrorManager.logErrorStateWithData( @@ -103,20 +96,8 @@ object TrophyFishManager { return fillet.getOrDefault(rarity, -1) } - fun TrophyFishInfo.getTooltip(counts: Map): ChatStyle { - val bestFishObtained = counts.keys.maxOrNull() ?: TrophyRarity.BRONZE - val rateString = if (rate != null) "§8[§7$rate%§8]" else "" - val display = """ - |$displayName $rateString - |${description.splitLines(150)} - | - |${TrophyRarity.DIAMOND.formattedString}: ${formatCount(counts, TrophyRarity.DIAMOND)} - |${TrophyRarity.GOLD.formattedString}: ${formatCount(counts, TrophyRarity.GOLD)} - |${TrophyRarity.SILVER.formattedString}: ${formatCount(counts, TrophyRarity.SILVER)} - |${TrophyRarity.BRONZE.formattedString}: ${formatCount(counts, TrophyRarity.BRONZE)} - | - |§7Total: ${bestFishObtained.formatCode}${counts.values.sum().addSeparators()} - """.trimMargin() + fun getTooltip(internalName: String): ChatStyle? { + val display = TrophyFishAPI.hoverInfo(internalName) ?: return null return ChatStyle().setChatHoverEvent( HoverEvent(HoverEvent.Action.SHOW_TEXT, ChatComponentText(display)) ) diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishMessages.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishMessages.kt index 601bfc89e006..d6cff8d69531 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishMessages.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishMessages.kt @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.config.features.fishing.trophyfishing.ChatMessagesConfig.DesignFormat import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.fishing.TrophyFishCaughtEvent import at.hannibal2.skyhanni.features.fishing.trophy.TrophyFishManager.getTooltip import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.CollectionUtils.sumAllValues @@ -44,6 +45,7 @@ class TrophyFishMessages { val trophyFishes = TrophyFishManager.fish ?: return val trophyFishCounts = trophyFishes.getOrPut(internalName) { mutableMapOf() } val amount = trophyFishCounts.addOrPut(rarity, 1) + TrophyFishCaughtEvent(internalName, rarity).postAndCatch() if (shouldBlockTrophyFish(rarity, amount)) { event.blockedReason = "low_trophy_fish" @@ -72,8 +74,8 @@ class TrophyFishMessages { } if (config.tooltip) { - TrophyFishManager.getInfo(internalName)?.let { - edited.chatStyle = it.getTooltip(trophyFishCounts) + getTooltip(internalName)?.let { + edited.chatStyle = it } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/slayer/HideMobNames.kt b/src/main/java/at/hannibal2/skyhanni/features/slayer/HideMobNames.kt index 75fe4b0ee65e..e6d0fe0f67eb 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/slayer/HideMobNames.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/slayer/HideMobNames.kt @@ -66,7 +66,7 @@ class HideMobNames { return } - lastMobName.put(id, name) + lastMobName[id] = name mobNamesHidden.remove(id) if (shouldNameBeHidden(name)) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemsOnGround.kt b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemsOnGround.kt index 7474b10886c1..bfb21cea5c40 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemsOnGround.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/slayer/SlayerItemsOnGround.kt @@ -31,7 +31,7 @@ class SlayerItemsOnGround { if (itemStack.getInternalName() == NEUInternalName.NONE) continue val (name, price) = SlayerAPI.getItemNameAndPrice(itemStack.getInternalName(), itemStack.stackSize) if (config.minimumPrice > price) continue - itemsOnGround.put(entityItem, name) + itemsOnGround[entityItem] = name } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/summonings/SummoningSoulsName.kt b/src/main/java/at/hannibal2/skyhanni/features/summonings/SummoningSoulsName.kt index cabd8dd4e6de..e04890620234 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/summonings/SummoningSoulsName.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/summonings/SummoningSoulsName.kt @@ -64,8 +64,8 @@ class SummoningSoulsName { val id = entity.entityId val consumer = entity.getNameTagWith(2, "§c❤") if (consumer != null && !consumer.name.contains("§e0")) { - mobsLastLocation.put(id, entity.getLorenzVec()) - mobsName.put(id, consumer.name) + mobsLastLocation[id] = entity.getLorenzVec() + mobsName[id] = consumer.name } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt index 915677bb63de..2e1237fe875e 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/CollectionUtils.kt @@ -156,6 +156,10 @@ object CollectionUtils { add(Collections.singletonList(text)) } + fun MutableList>.addSingleString(text: String) { + add(Collections.singletonList(Renderable.string(text))) + } + fun > List>.sorted(): List> { return sortedBy { (_, value) -> value } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt index 182b1381bfa7..caf5b773473a 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedCache.kt @@ -14,11 +14,14 @@ class TimeLimitedCache( .removalListener { removalListener(it.key, it.value) } .build() - fun put(key: K, value: V) = cache.put(key, value) + // TODO IntelliJ cant replace this, find another way? +// @Deprecated("outdated", ReplaceWith("[key] = value")) + @Deprecated("outdated", ReplaceWith("set(key, value)")) + fun put(key: K, value: V) = set(key, value) fun getOrNull(key: K): V? = cache.getIfPresent(key) - fun getOrPut(key: K, defaultValue: () -> V) = getOrNull(key) ?: defaultValue().also { put(key, it) } + fun getOrPut(key: K, defaultValue: () -> V) = getOrNull(key) ?: defaultValue().also { set(key, it) } fun clear() = cache.invalidateAll() @@ -31,4 +34,8 @@ class TimeLimitedCache( fun containsKey(key: K): Boolean = cache.getIfPresent(key) != null override fun iterator(): Iterator> = entries().iterator() + + operator fun set(key: K, value: V) { + cache.put(key, value) + } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedSet.kt b/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedSet.kt index fae86fac57cf..aab5595daae6 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedSet.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/TimeLimitedSet.kt @@ -2,14 +2,16 @@ package at.hannibal2.skyhanni.utils import kotlin.time.Duration -class TimeLimitedSet( +class TimeLimitedSet( expireAfterWrite: Duration, private val removalListener: (T) -> Unit = {}, ) { private val cache = TimeLimitedCache(expireAfterWrite) { key, _ -> key?.let { removalListener(it) } } - fun add(element: T) = cache.put(element, Unit) + fun add(element: T) { + cache[element] = Unit + } operator fun contains(element: T): Boolean = cache.containsKey(element) From 64f83ca3f4c70b6008ad269b958fae5515d3c67c Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Wed, 29 May 2024 08:03:19 +0200 Subject: [PATCH 14/22] fixed trophy fish display shows checks everywhere --- .../skyhanni/features/fishing/trophy/TrophyFishDisplay.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt index a25f2d9c2465..0845bf2615f1 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt @@ -145,8 +145,8 @@ class TrophyFishDisplay { val recentlyDropped = rarity == recentlyDroppedRarity val format = if (config.showCross.get() && amount == 0) "§c✖" else { val color = if (recentlyDropped) "§a" else rarity.formatCode - val numberformat = if (config.showCheckmark.get()) "§l✔" else amount.addSeparators() - "$color$numberformat" + val numberFormat = if (config.showCheckmark.get() && amount >= 1) "§l✔" else amount.addSeparators() + "$color$numberFormat" } row[get(rarity)] = string(format) } From 85fd32ffd2eb2501c65af3a1c093eea5a23483e0 Mon Sep 17 00:00:00 2001 From: David Cole <40234707+DavidArthurCole@users.noreply.github.com> Date: Wed, 29 May 2024 02:16:49 -0400 Subject: [PATCH 15/22] Improvement: Combine duplicate time comparison into compacted chat message (#1887) Co-authored-by: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Co-authored-by: Cal --- .../features/event/hoppity/HoppityEggsCompactChat.kt | 10 +++++++++- .../chocolatefactory/ChocolateFactoryBarnManager.kt | 3 ++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt index b66f06891e66..fdb029fa6c73 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt @@ -2,11 +2,13 @@ package at.hannibal2.skyhanni.features.event.hoppity import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager.getEggType +import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.NumberUtil import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow +import at.hannibal2.skyhanni.utils.TimeUtils.format import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -20,6 +22,7 @@ object HoppityEggsCompactChat { private var newRabbit = false private var lastChatMeal: HoppityEggType? = null private var lastDuplicateAmount: Long? = null + private val config get() = ChocolateFactoryAPI.config fun compactChat(event: LorenzChatEvent, lastDuplicateAmount: Long? = null) { lastDuplicateAmount?.let { @@ -57,7 +60,12 @@ object HoppityEggsCompactChat { return if (duplicate) { val format = lastDuplicateAmount?.let { NumberUtil.format(it) } ?: "?" - "$mealName Egg! §7Duplicate $lastName §7(§6+$format Chocolate§7)" + val timeFormatted = lastDuplicateAmount?.let { + ChocolateFactoryAPI.timeUntilNeed(it).format(maxUnits = 2) + } ?: "?" + + val timeStr = if (config.showDuplicateTime) ", §a+§b$timeFormatted§7" else "" + "$mealName Egg! §7Duplicate $lastName §7(§6+$format Chocolate§7$timeStr)" } else if (newRabbit) { "$mealName Egg! §d§lNEW $lastName §7(${lastProfit}§7)" } else "?" diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryBarnManager.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryBarnManager.kt index 356794b7e510..a8134cedf7ab 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryBarnManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryBarnManager.kt @@ -18,6 +18,7 @@ import kotlin.time.Duration.Companion.seconds object ChocolateFactoryBarnManager { private val config get() = ChocolateFactoryAPI.config + private val hoppityConfig get() = HoppityEggsManager.config private val profileStorage get() = ChocolateFactoryAPI.profileStorage private val newRabbitPattern by ChocolateFactoryAPI.patternGroup.pattern( @@ -54,7 +55,7 @@ object ChocolateFactoryBarnManager { rabbitDuplicatePattern.matchMatcher(event.message) { HoppityEggsManager.shareWaypointPrompt() val amount = group("amount").formatLong() - if (config.showDuplicateTime) { + if (config.showDuplicateTime && !hoppityConfig.compactChat) { val format = ChocolateFactoryAPI.timeUntilNeed(amount).format(maxUnits = 2) DelayedRun.runNextTick { ChatUtils.chat("§7(§a+§b$format §aof production§7)") From 3b093ff5b689a871ae7ceaf1bd56d047f32d4162 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Wed, 29 May 2024 08:35:24 +0200 Subject: [PATCH 16/22] fixed trophy fish onlyShowMissing logic --- .../skyhanni/features/fishing/trophy/TrophyFishDisplay.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt index 0845bf2615f1..847731c65357 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt @@ -122,7 +122,7 @@ class TrophyFishDisplay { table: MutableList>, ) { get(config.onlyShowMissing.get())?.let { atLeast -> - val list = TrophyRarity.entries.filter { it <= atLeast } + val list = TrophyRarity.entries.filter { it == atLeast } if (list.all { (data[it] ?: 0) > 0 }) { return } From c8043a2c0b4dbd0733a316f2ed9b4f8c8d605056 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Wed, 29 May 2024 08:39:06 +0200 Subject: [PATCH 17/22] auto updating trophy fish display on neu data load --- src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 +- .../skyhanni/features/fishing/trophy/TrophyFishDisplay.kt | 3 ++- .../skyhanni/features/fishing/trophy/TrophyFishManager.kt | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 4cb09bfe97cb..ff905b3b000e 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -735,7 +735,7 @@ class SkyHanniMod { loadModule(SharkFishCounter()) loadModule(PowerStoneGuideFeatures()) loadModule(OdgerWaypoint()) - loadModule(TrophyFishDisplay()) + loadModule(TrophyFishDisplay) loadModule(TiaRelayHelper()) loadModule(TiaRelayWaypoints()) loadModule(BasketWaypoints()) diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt index 847731c65357..447a7bf54a64 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishDisplay.kt @@ -38,7 +38,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds -class TrophyFishDisplay { +object TrophyFishDisplay { private val config get() = SkyHanniMod.feature.fishing.trophyFishing.display private var recentlyDroppedTrophies = TimeLimitedCache(5.seconds) @@ -89,6 +89,7 @@ class TrophyFishDisplay { } } + fun update() { if (!isEnabled()) return val list = mutableListOf() diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt index 77701c1b06e7..2d8a7cb0e37f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/trophy/TrophyFishManager.kt @@ -74,6 +74,7 @@ object TrophyFishManager { ChatUtils.debug("Updated trophy fishing data from NEU PV: $name $rarity: $current -> $newValue") } } + TrophyFishDisplay.update() ChatUtils.chat("Updated Trophy Fishing data via NEU PV!") } From f6a31d6a3f6caf1ad3476f9019b8bd278d7e1c3d Mon Sep 17 00:00:00 2001 From: appable Date: Tue, 28 May 2024 23:47:36 -0700 Subject: [PATCH 18/22] Feature: Last farmed location waypoint (#1335) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../garden/CropStartLocationConfig.java | 26 ++++++++++- .../storage/ProfileSpecificStorage.java | 3 ++ .../garden/farming/GardenStartLocation.kt | 45 +++++++++++++++++-- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java index dc81a0063e37..048ae4f89083 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java @@ -3,14 +3,38 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDropdown; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; public class CropStartLocationConfig { @Expose - @ConfigOption(name = "Enable", desc = "Show the start waypoint for the farm of your current tool in hand. Do §e/shcropstartlocation §7to change the waypoint again.") + @ConfigOption(name = "Enable", desc = "Show waypoints for the farm of your current tool in hand. ") @ConfigEditorBoolean @FeatureToggle public boolean enabled = false; + @Expose + @ConfigOption(name = "Crop Location Mode", desc = "Whether to show waypoint at start location (set with §e/shcropstartlocation §7) or last farmed location.") + @ConfigEditorDropdown + public CropLocationMode mode = CropLocationMode.START; + + public enum CropLocationMode { + START("Start Only"), + LAST_FARMED("Last Farmed Only"), + BOTH("Both"), + ; + + private final String str; + + CropLocationMode(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + } diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index 91484305efc6..e5127faf55c2 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -317,6 +317,9 @@ public static class PlotIcon { @Expose public Map cropStartLocations = new HashMap<>(); + @Expose + public Map cropLastFarmedLocations = new HashMap<>(); + @Expose public Map farmingLanes = new HashMap<>(); diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenStartLocation.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenStartLocation.kt index b746e03ea9d9..9188b66eb58c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenStartLocation.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenStartLocation.kt @@ -1,18 +1,23 @@ package at.hannibal2.skyhanni.features.garden.farming +import at.hannibal2.skyhanni.config.features.garden.CropStartLocationConfig.CropLocationMode +import at.hannibal2.skyhanni.data.ClickType import at.hannibal2.skyhanni.events.CropClickEvent import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.test.GriffinUtils.drawWaypointFilled import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LocationUtils +import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object GardenStartLocation { private val config get() = GardenAPI.config.cropStartLocation + private var shouldShowLastFarmedWaypoint = false fun setLocationCommand() { if (!GardenAPI.inGarden()) { @@ -46,7 +51,9 @@ object GardenStartLocation { @SubscribeEvent fun onCropClick(event: CropClickEvent) { if (!isEnabled()) return + if (event.clickType != ClickType.LEFT_CLICK || !GardenAPI.hasFarmingToolInHand()) return val startLocations = GardenAPI.storage?.cropStartLocations ?: return + val lastFarmedLocations = GardenAPI.storage?.cropLastFarmedLocations ?: return val crop = GardenAPI.getCurrentlyFarmedCrop() ?: return if (crop != GardenCropSpeed.lastBrokenCrop) return @@ -54,18 +61,48 @@ object GardenStartLocation { startLocations[crop] = LocationUtils.playerLocation() ChatUtils.chat("Auto updated your Crop Start Location for ${crop.cropName}") } + + lastFarmedLocations[crop] = LorenzVec.getBlockBelowPlayer().add(0.0, 1.0, 0.0) + shouldShowLastFarmedWaypoint = false } @SubscribeEvent fun onRenderWorld(event: LorenzRenderWorldEvent) { if (!isEnabled()) return - val startLocations = GardenAPI.storage?.cropStartLocations ?: return val crop = GardenAPI.cropInHand ?: return - val location = startLocations[crop]?.add(-0.5, 0.5, -0.5) ?: return - event.drawWaypointFilled(location, LorenzColor.WHITE.toColor()) - event.drawDynamicText(location, crop.cropName, 1.5) + if (showStartWaypoint()) { + GardenAPI.storage?.cropStartLocations?.get(crop) + ?.roundLocationToBlock() + ?.also { + event.drawWaypointFilled(it, LorenzColor.WHITE.toColor()) + event.drawDynamicText(it, "§b${crop.cropName}", 1.5) + if (shouldShowBoth()) { + event.drawDynamicText(it, "§aStart Location", 1.1, yOff = 12f) + } + } + } + + if (showLastFarmedWaypoint()) { + val location = GardenAPI.storage?.cropLastFarmedLocations?.get(crop) + if (location != null) { + if (location.distanceSqToPlayer() >= 100.0) { + shouldShowLastFarmedWaypoint = true + } + if (shouldShowLastFarmedWaypoint) { + event.drawWaypointFilled(location, LorenzColor.LIGHT_PURPLE.toColor(), seeThroughBlocks = true, beacon = true) + event.drawDynamicText(location, "§b${crop.cropName}", 1.5) + if (shouldShowBoth()) { + event.drawDynamicText(location, "§eLast Farmed", 1.1, yOff = 12f) + } + } + } + } } + private fun shouldShowBoth() = config.mode == CropLocationMode.BOTH + private fun showStartWaypoint() = config.mode != CropLocationMode.LAST_FARMED + private fun showLastFarmedWaypoint() = config.mode != CropLocationMode.START + fun isEnabled() = GardenAPI.inGarden() && config.enabled } From 3ea8208bb4ade935600242ed1aedaa80bc6ed6a8 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal00212@users.noreply.github.com> Date: Wed, 29 May 2024 08:48:12 +0200 Subject: [PATCH 19/22] typo --- .../config/features/garden/CropStartLocationConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java index 048ae4f89083..55ca181938e2 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/CropStartLocationConfig.java @@ -9,7 +9,7 @@ public class CropStartLocationConfig { @Expose - @ConfigOption(name = "Enable", desc = "Show waypoints for the farm of your current tool in hand. ") + @ConfigOption(name = "Enable", desc = "Show waypoints for the farm of your current tool in hand.") @ConfigEditorBoolean @FeatureToggle public boolean enabled = false; From 84b36cb1c0b89f42cc0613cfdbba275a78528fb2 Mon Sep 17 00:00:00 2001 From: appable Date: Wed, 29 May 2024 00:17:28 -0700 Subject: [PATCH 20/22] Improvement: Persistent HoppityCollectionStats display (#1836) --- .../java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 + .../skyhanni/config/commands/Commands.kt | 5 + .../storage/ProfileSpecificStorage.java | 4 + .../jsonobjects/repo/neu/NeuHoppityJson.kt | 23 +++ .../event/hoppity/HoppityCollectionData.kt | 60 ++++++ .../event/hoppity/HoppityCollectionStats.kt | 176 +++++++++--------- .../event/hoppity/HoppityEggsCompactChat.kt | 2 +- .../event/hoppity/HoppityEggsManager.kt | 6 +- 8 files changed, 191 insertions(+), 87 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuHoppityJson.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionData.kt diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index ff905b3b000e..44aa8dd7fcba 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -143,6 +143,7 @@ import at.hannibal2.skyhanni.features.event.diana.HighlightInquisitors import at.hannibal2.skyhanni.features.event.diana.InquisitorWaypointShare import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker import at.hannibal2.skyhanni.features.event.diana.SoopyGuessBurrow +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionData import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggDisplayManager import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggLocator @@ -680,6 +681,7 @@ class SkyHanniMod { loadModule(HoppityEggLocator) loadModule(HoppityEggsShared) loadModule(HoppityEggDisplayManager) + loadModule(HoppityCollectionData) loadModule(HoppityCollectionStats) loadModule(SpawnTimers()) loadModule(MarkedPlayerManager()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt index 881861ad3a49..884a2c140912 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -28,6 +28,7 @@ import at.hannibal2.skyhanni.features.event.diana.DianaProfitTracker import at.hannibal2.skyhanni.features.event.diana.GriffinBurrowHelper import at.hannibal2.skyhanni.features.event.diana.InquisitorWaypointShare import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats import at.hannibal2.skyhanni.features.event.jerry.frozentreasure.FrozenTreasureTracker import at.hannibal2.skyhanni.features.fishing.tracker.FishingProfitTracker import at.hannibal2.skyhanni.features.fishing.tracker.SeaCreatureTracker @@ -402,6 +403,10 @@ object Commands { "shUpdateBazaarPrices", "Forcefully updating the bazaar prices right now." ) { HypixelBazaarFetcher.fetchNow() } + registerCommand( + "shclearsavedrabbits", + "Clears the saved rabbits on this profile." + ) { HoppityCollectionStats.clearSavedRabbits() } } private fun developersDebugFeatures() { diff --git a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java index e5127faf55c2..d2a38831aa0e 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -9,6 +9,7 @@ import at.hannibal2.skyhanni.features.dungeon.DungeonFloor; import at.hannibal2.skyhanni.features.event.diana.DianaProfitTracker; import at.hannibal2.skyhanni.features.event.diana.MythologicalCreatureTracker; +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats; import at.hannibal2.skyhanni.features.event.jerry.frozentreasure.FrozenTreasureTracker; import at.hannibal2.skyhanni.features.fishing.tracker.FishingProfitTracker; import at.hannibal2.skyhanni.features.fishing.tracker.SeaCreatureTracker; @@ -123,6 +124,9 @@ public static class PositionChange { @Expose public String targetName = null; + + @Expose + public Map rabbitCounts = new HashMap(); } @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuHoppityJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuHoppityJson.kt new file mode 100644 index 000000000000..1c80f6ad3fda --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/neu/NeuHoppityJson.kt @@ -0,0 +1,23 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo.neu + +import com.google.gson.annotations.Expose + +data class NeuHoppityJson( + @Expose val hoppity: HoppityInfo +) + +data class HoppityInfo( + @Expose val rarities: Map, + @Expose val special: Map, +) + +data class HoppityRarityInfo( + @Expose val rabbits: List, + @Expose val chocolate: Int, + @Expose val multiplier: Double, +) + +data class MythicRabbitInfo( + @Expose val chocolate: Int, + @Expose val multiplier: Double, +) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionData.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionData.kt new file mode 100644 index 000000000000..4d44b9ca8480 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionData.kt @@ -0,0 +1,60 @@ +package at.hannibal2.skyhanni.features.event.hoppity + +import at.hannibal2.skyhanni.data.jsonobjects.repo.neu.NeuHoppityJson +import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats.RabbitCollectionRarity + +object HoppityCollectionData { + private val rabbitRarities = mutableMapOf() + private val rarityBonuses = mutableMapOf() + private val specialBonuses = mutableMapOf() + + val knownRabbitCount + get() = rabbitRarities.size + + fun getRarity(rabbit: String): RabbitCollectionRarity? { + val apiName = rabbit.toApiName() + return rabbitRarities[apiName] + } + + fun knownRabbitsOfRarity(rarity: RabbitCollectionRarity): Int = + rabbitRarities.filterValues { it == rarity }.count() + + fun isKnownRabbit(rabbit: String) = rabbitRarities.contains(rabbit.toApiName()) + + fun getChocolateBonuses(rabbit: String): ChocolateBonuses { + val apiName = rabbit.toApiName() + val rarity = rabbitRarities[apiName] + return specialBonuses[apiName] + ?: rarityBonuses[rarity] + ?: ChocolateBonuses(0, 0.0) + } + + private fun String.toApiName(): String = + lowercase().replace("[- ]".toRegex(), "_") + + @SubscribeEvent + fun onNeuRepoReload(event: NeuRepositoryReloadEvent) { + rabbitRarities.clear() + rarityBonuses.clear() + specialBonuses.clear() + + val data = event.readConstant("hoppity").hoppity + for ((rarityString, rarityData) in data.rarities.entries) { + val rarity = RabbitCollectionRarity.valueOf(rarityString.uppercase()) + + for (rabbit in rarityData.rabbits) { + rabbitRarities[rabbit] = rarity + } + + rarityBonuses[rarity] = ChocolateBonuses(rarityData.chocolate, rarityData.multiplier) + } + + data.special.forEach { (rabbit, data) -> + specialBonuses[rabbit] = ChocolateBonuses(data.chocolate, data.multiplier) + } + } + + data class ChocolateBonuses(val chocolate: Int, val multiplier: Double) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt index ef45042396a7..6807a712faf0 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityCollectionStats.kt @@ -1,10 +1,11 @@ package at.hannibal2.skyhanni.features.event.hoppity +import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent -import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI +import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.DisplayTableEntry import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils @@ -13,9 +14,11 @@ import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatInt -import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches +import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables +import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.renderables.Renderable import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -28,10 +31,6 @@ object HoppityCollectionStats { "page.current", "\\((?\\d+)/(?\\d+)\\) Hoppity's Collection" ) - private val rabbitRarityPattern by patternGroup.pattern( - "rabbit.rarity", - "§.§L(?\\w+) RABBIT" - ) private val duplicatesFoundPattern by patternGroup.pattern( "duplicates.found", "§7Duplicates Found: §a(?[\\d,]+)" @@ -45,16 +44,17 @@ object HoppityCollectionStats { "rabbit.notfound", "(?:§.)+You (?:have not found this rabbit yet!|cannot find this rabbit until you)" ) + private val rabbitsFoundPattern by patternGroup.pattern( "rabbits.found", "§.§l§m[ §a-z]+§r §.(?[0-9]+)§./§.(?[0-9]+)" ) private var display = emptyList() - private val loggedRabbits = mutableMapOf() - private var totalRabbits = 0 + private val loggedRabbits + get() = ProfileStorageData.profileSpecific?.chocolateFactory?.rabbitCounts ?: mutableMapOf() + var inInventory = false - private var currentPage = 0 @SubscribeEvent fun onInventoryOpen(event: InventoryFullyOpenedEvent) { @@ -63,19 +63,13 @@ object HoppityCollectionStats { inInventory = true display = buildDisplay(event) + checkSpecialRabbits() } @SubscribeEvent fun onInventoryClose(event: InventoryCloseEvent) { inInventory = false - } - - @SubscribeEvent - fun onProfileChange(event: ProfileJoinEvent) { display = emptyList() - loggedRabbits.clear() - currentPage = 0 - inInventory = false } @SubscribeEvent @@ -90,13 +84,16 @@ object HoppityCollectionStats { } private fun buildDisplay(event: InventoryFullyOpenedEvent): MutableList { - val totalAmount = logRabbits(event) + logRabbits(event) val newList = mutableListOf() newList.add(Renderable.string("§eHoppity Rabbit Collection§f:")) newList.add(LorenzUtils.fillTable(getRabbitStats(), padding = 5)) - if (totalAmount != totalRabbits) { + val loggedRabbitCount = loggedRabbits.size + val foundRabbitCount = getFoundRabbitsFromHypixel(event) + + if (loggedRabbitCount < foundRabbitCount) { newList.add(Renderable.string("")) newList.add( Renderable.wrappedString( @@ -114,32 +111,39 @@ object HoppityCollectionStats { var totalDuplicates = 0 var totalChocolatePerSecond = 0 var totalChocolateMultiplier = 0.0 - totalRabbits = 0 val table = mutableListOf() for (rarity in RabbitCollectionRarity.entries) { - val filtered = loggedRabbits.filter { it.value.rarity == rarity } - val isTotal = rarity == RabbitCollectionRarity.TOTAL - if (filtered.isEmpty() && !isTotal) continue + + val foundOfRarity = loggedRabbits.filterKeys { + HoppityCollectionData.getRarity(it) == rarity + } val title = "${rarity.displayName} Rabbits" - val amountFound = filtered.filter { it.value.found }.size - val totalOfRarity = filtered.size - val duplicates = filtered.values.sumOf { it.duplicates } - val chocolatePerSecond = rarity.chocolatePerSecond * amountFound - val chocolateMultiplier = (rarity.chocolateMultiplier * amountFound) + val amountFound = foundOfRarity.size + val duplicates = foundOfRarity.values.sum() - amountFound + + val chocolateBonuses = foundOfRarity.keys.map { + HoppityCollectionData.getChocolateBonuses(it) + } + + val chocolatePerSecond = chocolateBonuses.sumOf { it.chocolate } + val chocolateMultiplier = chocolateBonuses.sumOf { it.multiplier } if (!isTotal) { totalAmountFound += amountFound - totalRabbits += totalOfRarity totalDuplicates += duplicates totalChocolatePerSecond += chocolatePerSecond totalChocolateMultiplier += chocolateMultiplier } val displayFound = if (isTotal) totalAmountFound else amountFound - val displayTotal = if (isTotal) totalRabbits else totalOfRarity + val displayTotal = if (isTotal) { + HoppityCollectionData.knownRabbitCount + } else { + HoppityCollectionData.knownRabbitsOfRarity(rarity) + } val displayDuplicates = if (isTotal) totalDuplicates else duplicates val displayChocolatePerSecond = if (isTotal) totalChocolatePerSecond else chocolatePerSecond val displayChocolateMultiplier = if (isTotal) totalChocolateMultiplier else chocolateMultiplier @@ -158,7 +162,7 @@ object HoppityCollectionStats { DisplayTableEntry( title, "§a$displayFound§7/§a$displayTotal", - displayFound.toDouble(), + displayTotal.toDouble(), rarity.item, hover ) @@ -167,77 +171,79 @@ object HoppityCollectionStats { return table } - private fun logRabbits(event: InventoryFullyOpenedEvent): Int { - var totalAmount = 0 + fun incrementRabbit(name: String) { + val rabbit = name.removeColor() + if (!HoppityCollectionData.isKnownRabbit(rabbit)) return + loggedRabbits[rabbit] = (loggedRabbits[rabbit] ?: 0) + 1 + checkSpecialRabbits() + } + // Gets the found rabbits according to the Hypixel progress bar + // used to make sure that mod data is synchronized with Hypixel + private fun getFoundRabbitsFromHypixel(event: InventoryFullyOpenedEvent): Int { + return event.inventoryItems.firstNotNullOf { + it.value.getLore().matchFirst(rabbitsFoundPattern) { + group("current").formatInt() + } + } + } + + private fun logRabbits(event: InventoryFullyOpenedEvent) { for ((_, item) in event.inventoryItems) { - val itemName = item.displayName ?: continue + val itemName = item.displayName?.removeColor() ?: continue + val isRabbit = HoppityCollectionData.isKnownRabbit(itemName) + + if (!isRabbit) continue + val itemLore = item.getLore() + val found = !rabbitNotFoundPattern.anyMatches(itemLore) - var duplicatesFound = 0 - var rabbitRarity: RabbitCollectionRarity? = null - var found = true - - for (line in itemLore) { - rabbitRarityPattern.matchMatcher(line) { - rabbitRarity = RabbitCollectionRarity.fromDisplayName(group("rarity")) - } - duplicatesFoundPattern.matchMatcher(line) { - duplicatesFound = group("duplicates").formatInt() - } - if (rabbitNotFoundPattern.matches(line)) found = false - - rabbitsFoundPattern.matchMatcher(line) { - totalAmount = group("total").formatInt() - } - } + if (!found) continue - val rarity = rabbitRarity ?: continue + val duplicates = itemLore.matchFirst(duplicatesFoundPattern) { + group("duplicates").formatInt() + } ?: 0 - if (itemName == "§dEinstein" && found) { - ChocolateFactoryAPI.profileStorage?.timeTowerCooldown = 7 - } + loggedRabbits[itemName] = duplicates + 1 + } + } - if (itemName == "§dMu" && found) { - ChocolateFactoryAPI.profileStorage?.hasMuRabbit = true - } - val duplicates = duplicatesFound.coerceAtLeast(0) - loggedRabbits[itemName] = RabbitCollectionInfo(rarity, found, duplicates) + // bugfix for some weird potential user errors (e.g. if users play on alpha and get rabbits) + fun clearSavedRabbits() { + loggedRabbits.clear() + ChatUtils.chat("Cleared saved rabbit data.") + } + + + // checks special rabbits whenever loggedRabbits is modified to update misc stored values + // TODO: make this better than hard-coded checks + private fun checkSpecialRabbits() { + if (hasFoundRabbit("Einstein")) { + ChocolateFactoryAPI.profileStorage?.timeTowerCooldown = 7 + } + + if (hasFoundRabbit("Mu")) { + ChocolateFactoryAPI.profileStorage?.hasMuRabbit = true } - // For getting data for neu pv -// val rarityToRabbit = mutableMapOf>() -// loggedRabbits.forEach { (name, info) -> -// val formattedName = name.removeColor().lowercase().replace(" ", "_").replace("-", "_") -// rarityToRabbit.getOrPut(info.rarity) { mutableListOf() }.add("\"$formattedName\"") -// } -// println(rarityToRabbit) - return totalAmount } - private fun isEnabled() = LorenzUtils.inSkyBlock && config.hoppityCollectionStats + private fun hasFoundRabbit(rabbit: String): Boolean = loggedRabbits.containsKey(rabbit) - private data class RabbitCollectionInfo( - val rarity: RabbitCollectionRarity, - val found: Boolean, - val duplicates: Int, - ) + private fun isEnabled() = LorenzUtils.inSkyBlock && config.hoppityCollectionStats - // todo in future make the amount and multiplier work with mythic rabbits (can't until I have some) - private enum class RabbitCollectionRarity( + enum class RabbitCollectionRarity( val displayName: String, - val chocolatePerSecond: Int, - val chocolateMultiplier: Double, val item: NEUInternalName, ) { - COMMON("§fCommon", 1, 0.002, "STAINED_GLASS".asInternalName()), - UNCOMMON("§aUncommon", 2, 0.003, "STAINED_GLASS-5".asInternalName()), - RARE("§9Rare", 4, 0.004, "STAINED_GLASS-11".asInternalName()), - EPIC("§5Epic", 10, 0.005, "STAINED_GLASS-10".asInternalName()), - LEGENDARY("§6Legendary", 0, 0.02, "STAINED_GLASS-1".asInternalName()), - MYTHIC("§dMythic", 0, 0.0, "STAINED_GLASS-6".asInternalName()), - DIVINE("§bDivine", 0, 0.025, "STAINED_GLASS-3".asInternalName()), - TOTAL("§cTotal", 0, 0.0, "STAINED_GLASS-14".asInternalName()), + COMMON("§fCommon", "STAINED_GLASS".asInternalName()), + UNCOMMON("§aUncommon", "STAINED_GLASS-5".asInternalName()), + RARE("§9Rare", "STAINED_GLASS-11".asInternalName()), + EPIC("§5Epic", "STAINED_GLASS-10".asInternalName()), + LEGENDARY("§6Legendary", "STAINED_GLASS-1".asInternalName()), + MYTHIC("§dMythic", "STAINED_GLASS-6".asInternalName()), + DIVINE("§bDivine", "STAINED_GLASS-3".asInternalName()), + TOTAL("§cTotal", "STAINED_GLASS-14".asInternalName()), ; companion object { diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt index fdb029fa6c73..cfe229871de7 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsCompactChat.kt @@ -78,7 +78,7 @@ object HoppityEggsCompactChat { compactChat(event) } - HoppityEggsManager.rabbitFoundPatttern.matchMatcher(event.message) { + HoppityEggsManager.rabbitFoundPattern.matchMatcher(event.message) { lastName = group("name") lastRarity = group("rarity") compactChat(event) diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsManager.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsManager.kt index 05377116af5a..c085fcf16881 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggsManager.kt @@ -46,7 +46,7 @@ object HoppityEggsManager { * REGEX-TEST: §D§LHOPPITY'S HUNT §7You found §fArnie §7(§F§LCOMMON§7)! * REGEX-TEST: §D§LHOPPITY'S HUNT §7You found §aPenelope §7(§A§LUNCOMMON§7)! */ - val rabbitFoundPatttern by ChocolateFactoryAPI.patternGroup.pattern( + val rabbitFoundPattern by ChocolateFactoryAPI.patternGroup.pattern( "rabbit.found", "§D§LHOPPITY'S HUNT §7You found (?.*) §7\\((?.*)§7\\)!" ) @@ -142,6 +142,10 @@ object HoppityEggsManager { getEggType(event).markSpawned() return } + + rabbitFoundPattern.matchMatcher(event.message) { + HoppityCollectionStats.incrementRabbit(group("name")) + } } internal fun Matcher.getEggType(event: LorenzChatEvent): HoppityEggType = From c38ebf82a6f82ef66250710bb9b7513bc2ae732e Mon Sep 17 00:00:00 2001 From: Phoebe <77941535+catgirlseraid@users.noreply.github.com> Date: Wed, 29 May 2024 19:17:47 +1200 Subject: [PATCH 21/22] Feature: Auction outbid warning (#1818) Co-authored-by: SeRaid <77941535+SeRaid743@users.noreply.github.com> Co-authored-by: Cal --- .../java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 ++ .../inventory/AuctionHouseConfig.java | 6 ++++ .../inventory/AuctionOutbidWarning.kt | 28 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 src/main/java/at/hannibal2/skyhanni/features/inventory/AuctionOutbidWarning.kt diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 44aa8dd7fcba..f389feeea472 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -255,6 +255,7 @@ import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern import at.hannibal2.skyhanni.features.gui.quiver.QuiverDisplay import at.hannibal2.skyhanni.features.gui.quiver.QuiverWarning +import at.hannibal2.skyhanni.features.inventory.AuctionOutbidWarning import at.hannibal2.skyhanni.features.inventory.AuctionsHighlighter import at.hannibal2.skyhanni.features.inventory.ChestValue import at.hannibal2.skyhanni.features.inventory.DojoRankDisplay @@ -949,6 +950,7 @@ class SkyHanniMod { loadModule(ColdOverlay()) loadModule(QuiverDisplay()) loadModule(QuiverWarning()) + loadModule(AuctionOutbidWarning) // test stuff loadModule(SkyHanniDebugsAndTests()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/AuctionHouseConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/AuctionHouseConfig.java index 21108095b62c..65a21438a8f9 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/AuctionHouseConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/AuctionHouseConfig.java @@ -55,4 +55,10 @@ public class AuctionHouseConfig { @ConfigEditorBoolean @FeatureToggle public boolean openPriceWebsite = false; + + @Expose + @ConfigOption(name = "Outbid alert", desc = "Sends a warning when you're outbid on an auction.") + @ConfigEditorBoolean + @FeatureToggle + public boolean auctionOutbid = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/AuctionOutbidWarning.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/AuctionOutbidWarning.kt new file mode 100644 index 000000000000..eae258eeec04 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/AuctionOutbidWarning.kt @@ -0,0 +1,28 @@ +package at.hannibal2.skyhanni.features.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.TitleManager +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.SoundUtils +import at.hannibal2.skyhanni.utils.StringUtils.matches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.seconds + +object AuctionOutbidWarning { + private val outbidPattern by RepoPattern.pattern( + "auction.outbid", + "§6\\[Auction].*§eoutbid you by.*§e§lCLICK" + ) + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + if (!SkyHanniMod.feature.inventory.auctions.auctionOutbid) return + if (!outbidPattern.matches(event.message)) return + + TitleManager.sendTitle("§cYou have been outbid!", 5.seconds, 3.6, 7.0f) + SoundUtils.playBeepSound() + } +} From 9f4223a660043b6b246c58eeab0546005d03ed03 Mon Sep 17 00:00:00 2001 From: sayomaki Date: Wed, 29 May 2024 15:20:43 +0800 Subject: [PATCH 22/22] Fix: Chocolate factory position not showing when line overflows (#1918) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../inventory/chocolatefactory/ChocolateFactoryDataLoader.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryDataLoader.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryDataLoader.kt index 3204efbf9e29..3d052da7ab3e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryDataLoader.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryDataLoader.kt @@ -54,10 +54,11 @@ object ChocolateFactoryDataLoader { /** * REGEX-TEST: §7You are §8#§b114 * REGEX-TEST: §7§7You are §8#§b5,139 §7in all-time Chocolate. + * REGEX-TEST: §7§7You are §8#§b5,139 §7in all-time */ private val leaderboardPlacePattern by ChocolateFactoryAPI.patternGroup.pattern( "leaderboard.place", - "(?:§.)+You are §8#§b(?[\\d,]+)(?: §7in all-time Chocolate\\.)?" + "(?:§.)+You are §8#§b(?[\\d,]+)(?: §7in all-time)?(?: Chocolate\\.)?" ) private val leaderboardPercentilePattern by ChocolateFactoryAPI.patternGroup.pattern( "leaderboard.percentile",