diff --git a/.github/workflows/illegal-imports.txt b/.github/workflows/illegal-imports.txt index f53a5da78e25..83354f622960 100644 --- a/.github/workflows/illegal-imports.txt +++ b/.github/workflows/illegal-imports.txt @@ -5,7 +5,8 @@ at/hannibal2/skyhanni/ scala. at/hannibal2/skyhanni/ jline. -at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.util.Constants at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.events.SlotClickEvent at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.events.ReplaceItemEvent +at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.util.Constants +at/hannibal2/skyhanni/ io.github.moulberry.notenoughupdates.util.Utils at/hannibal2/skyhanni/ java.util.function.Supplier diff --git a/.gitignore b/.gitignore index d77f4bd8b6f0..7f4081e02e52 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ !.idea/icon.svg !.idea/dictionaries/default_user.xml !.idea/scopes/Mixins.xml +!.idea/liveTemplates/SkyHanni.xml .vscode/ run/ build/ diff --git a/.idea/dictionaries/default_user.xml b/.idea/dictionaries/default_user.xml index cb91301718f0..a0017ca5e3e0 100644 --- a/.idea/dictionaries/default_user.xml +++ b/.idea/dictionaries/default_user.xml @@ -254,6 +254,7 @@ superpairs tablist terracottas + tessellator thaumaturgist thaumaturgy townsquare @@ -277,4 +278,4 @@ yolkar - + \ No newline at end of file diff --git a/.idea/liveTemplates/SkyHanni.xml b/.idea/liveTemplates/SkyHanni.xml new file mode 100644 index 000000000000..08c6737b5ce2 --- /dev/null +++ b/.idea/liveTemplates/SkyHanni.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index e8464ada27e8..add2df4e77e2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,6 +18,7 @@ plugins { kotlin("plugin.power-assert") `maven-publish` id("moe.nea.shot") version "1.0.0" + id("net.kyori.blossom") } val target = ProjectTarget.values().find { it.projectPath == project.path }!! @@ -159,9 +160,9 @@ dependencies { exclude(module = "unspecified") isTransitive = false } - // June 3, 2024, 9:30 PM AEST - // https://github.com/NotEnoughUpdates/NotEnoughUpdates/tree/2.3.0 - devenvMod("com.github.NotEnoughUpdates:NotEnoughUpdates:2.3.0:all") { + // August 27, 2024, 4:30 PM AEST + // https://github.com/NotEnoughUpdates/NotEnoughUpdates/tree/2.3.3 + devenvMod("com.github.NotEnoughUpdates:NotEnoughUpdates:2.3.3:all") { exclude(module = "unspecified") isTransitive = false } @@ -312,12 +313,18 @@ if (!MultiVersionStage.activeState.shouldCompile(target)) { onlyIf { false } } } + preprocess { vars.put("MC", target.minecraftVersion.versionNumber) vars.put("FORGE", if (target.forgeDep != null) 1 else 0) vars.put("JAVA", target.minecraftVersion.javaVersion) patternAnnotation.set("at.hannibal2.skyhanni.utils.compat.Pattern") } + +blossom { + replaceToken("@MOD_VERSION@", version) +} + val sourcesJar by tasks.creating(Jar::class) { destinationDirectory.set(layout.buildDirectory.dir("badjars")) archiveClassifier.set("src") diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f42ddfffc477..33d0b77c7433 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -16,6 +16,7 @@ + Added a "Get from Sack" button in the forge recipe menu to retrieve ingredients. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2106) + Added Tracker for Glacite Corpses. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2306) + Tracks overall loot and loot per type. ++ Hides tooltips of items inside the Fossil Excavator in Glacite Tunnels. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2539) #### Rift Features @@ -46,6 +47,12 @@ + Use /shhoppitystats for live stats. + Added optional warning when Hoppity calls you with a rabbit to sell. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) + Added hotkey for picking up Abiphone calls from Hoppity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) ++ Added a draggable list for Hoppity's Collection menu rabbit highlighting. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) + + Factory/Shop milestones = Yellow/Gold. + + Stray rabbits = Dark Aqua. + + Abi = Dark Green. ++ Added a toggle to highlight found rabbits in Hoppity's Collection menu. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) ++ Added the ability to change the color of missing rabbit dyes in Hoppity's Collection to reflect rabbit rarity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2522) #### The Carnival Features @@ -80,6 +87,12 @@ + Added Accessory magical power display as stack size. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2243) + Only works inside the Accessory Bag and Auction House. + Added `/gfs` to fix a broken Piggy Bank. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2150) ++ Added Superpair Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Displays found and matched pairs, power-ups, and missing pairs/normals. ++ Added Experiments Dry-Streak Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Shows attempts and XP since the last ULTRA-RARE. ++ Added Experiments Profit Tracker. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Tracks profits in Coins and Enchanting XP. #### Chat Features @@ -110,6 +123,10 @@ + Added Broodmother spawn alert, countdown and stage change messages. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) + Countdown will not show until a spawning stage change is observed, and may be off by a few seconds. + Added Broodmother support to the Damage Indicator. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) ++ Added Carry Tracker. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2185) + + Use `/shcarry` to add carries to a customer, and set a price for a slayer boss. + + Automatically counts slayer bosses you carry. + + Automatically tracks coins received from customers via `/trade`. #### Fishing Features @@ -133,6 +150,13 @@ + Added option to hide pet nametag text. - Empa + j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/1880) + Added Transfer Cooldown Prevention. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/1751) + Wait for the transfer cooldown to complete before sending commands like warp/is/hub. ++ Added highlighting for the active Beacon Effect. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2546) ++ Added navigation command. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2575) + + Use `/shnavigate ` to find interesting locations on your current SkyBlock island by searching for them. + + Displays a pathfinder to the location. + + Works with NPCs, points of interest, areas, slayer spots, emissaries, crimson mini-bosses, spots to mine ores, break crops, and kill mobs. + + Does not yet work with Spider's Den and Dungeon Hub (still needs to be mapped out). ++ Added a message to warp to Winter Island spawn when a Reindrake spawns. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2569) ### Improvements @@ -144,6 +168,9 @@ + Some icons in the Mining Event Display now use the texture of the item they represent. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2425) + E.g., Raffle Event -> Raffle Ticket. + Changed how Powder Tracker works to account for powder buffs. - Jordyrat + Empa (https://github.com/hannibal002/SkyHanni/pull/2394) ++ Added an option to hide all tooltips inside the Fossil Excavator. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2579) ++ Added support for using the Pickobulus ability for the Mineshaft Pity Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/2540) ++ Added Area Navigation support to Glacite Tunnels. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2544) #### Diana Improvements @@ -151,6 +178,7 @@ + Added per-election season Diana Trackers. - !nea (https://github.com/hannibal002/SkyHanni/pull/2487) + This includes the Diana Profit Tracker and the Mythological Creature Tracker. + The data is stored moving forward, but there is currently no way to view anything other than the current year. ++ Changed the Diana Profit Tracker and Mythological Creature Tracker to always be visible when holding the Ancestral Spade in hand, even if Diana is not the mayor. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2496) #### Scoreboard Improvements @@ -190,6 +218,9 @@ + Added config option to disable rarity in Compact Hoppity messages. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2383) + Chocolate Factory: Shows "time to next milestone" instead of "max milestone" when you are at Prestige 6. - minhperry (https://github.com/hannibal002/SkyHanni/pull/2503) ++ Added the required chocolate amount to the tooltip of milestone rabbits in Hoppity's Collection. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2523) ++ Improved the responsiveness of Hoppity Chat Compacting. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2488) ++ Added the ability to see how many duplicates you have previously found in Hoppity messages. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2556) #### Combat Improvements @@ -209,21 +240,30 @@ + Changed suggested cactus speed to 464 again. - DarkDash (https://github.com/hannibal002/SkyHanni/pull/2424) + Since the cactus knife now allows 500 max speed. + Made the waypoint to the middle of the plot for Pest Waypoint optional (off by default). - Luna (https://github.com/hannibal002/SkyHanni/pull/2469) ++ Reduced one click for supercrafting visitor materials by using `/viewrecipe` instead of `/recipe` when using the Shopping List button. - Miestiek (https://github.com/hannibal002/SkyHanni/pull/2505) #### Rift Improvements + Updated the description of the config for Enigma Soul Waypoints to help find the Rift Guide in the game. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2433) ++ Added Path Finder to Enigma Soul waypoints in the Rift. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2515) #### Dungeon Improvements + Added dungeon stars and crimson stars to estimated item value. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2492) +#### The Carnival Improvements + ++ Updated the Zombie Shootout Diamond color to be a deeper blue. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2511) + #### Misc Improvements + Updated Last Server to also alert for servers you have just left. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2494) + Added search functionality to some SkyHanni GUIs. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2477) + Search works in all SkyHanni Trackers and the Sack Display. + In your inventory, hover over the GUI with your mouse, then start typing to search. ++ Improved the performance of pathfinding logic in Area Navigation. - nea (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Added a toggle to force the `en_US` locale for number formatting. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2563) ++ Queued GfS will now always fall back to a default amount if one is not specified. - Luna (https://github.com/hannibal002/SkyHanni/pull/2584) ### Fixes @@ -253,6 +293,9 @@ + Fixed the Auction House Price Comparison appearing in your own inventory as well. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2483) + Fixed "click to show tunnel map" from the Glacite Mines commission menu appearing in the inventory. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2485) + Fixed Mouse Keys not working as Wardrobe Slot Hotkeys. - j10a1n15, ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2506) ++ Fixed Estimated Item Value incorrectly showing all Kuudra armor as starred. - Luna (https://github.com/hannibal002/SkyHanni/pull/2550) ++ Fixed Experiments Profit Tracker & Superpair Data. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2560) ++ Fixed price per unit for Stonk of Stonks auction not working for the bracket you are in. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2572) #### Mining Fixes @@ -262,6 +305,21 @@ + Fixed Powder for 10 Levels overflowing over the max level. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2422) + Fixed Glacite Tunnel Maps repeatedly showing the last commission goal even when there is no new commission. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2432) + Fixed Mineshaft Pity Counter not working with some ore types. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2436) ++ Fixed Tungsten Ore and Hardstone detection after the mining update. - Empa (https://github.com/hannibal002/SkyHanni/pull/2437) ++ Fixed item category errors after the new mining update. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2529) ++ Fixed blocks mined by Efficient Miner not being detected. - Empa (https://github.com/hannibal002/SkyHanni/pull/2526) ++ Fixed Corpse Tracker resetting items between restarts. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2528) ++ Fixed the Corpse Tracker not displaying while in the Mineshaft. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2516) ++ Fixed Hardstone and Tungsten not being properly detected in Mineshafts. - Empa (https://github.com/hannibal002/SkyHanni/pull/2536) ++ Fixed Heart of the Mountain showing outdated perks and powder information. - Tryp0xd (https://github.com/hannibal002/SkyHanni/pull/2543) ++ Fixed Sky Mall perks not being read correctly after the Hypixel update. - Luna (https://github.com/hannibal002/SkyHanni/pull/2551) ++ Fixed Mining Commission Blocks Color not working properly with Connected Textures. - Empa (https://github.com/hannibal002/SkyHanni/pull/2553) ++ Fixed Gemstone Gauntlet item category. - Luna (https://github.com/hannibal002/SkyHanni/pull/2534) ++ Fixed Glacite powder being tracked as Glacite in Corpse Tracker. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2557) ++ Fixed "Mining Commissions Block Color" disabling OptiFine connected textures. - nopo (https://github.com/hannibal002/SkyHanni/pull/2559) ++ Fixed some blocks in the Crystal Hollows being detected as Mithril instead of Hard Stone. - Luna (https://github.com/hannibal002/SkyHanni/pull/2580) ++ Fixed "Mining Commissions Block Color" causing OptiFine connected textures not to connect properly. - nopo (https://github.com/hannibal002/SkyHanni/pull/2577) ++ Fixed the Mineshaft Pity Counter not working in the Great Glacite Lake. - martimavocado (https://github.com/hannibal002/SkyHanni/pull/2565) #### Scoreboard Fixes @@ -280,6 +338,10 @@ + Fixed Custom Scoreboard errors while doing Carnival activities. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2455) + Fixed Custom Scoreboard error while in a Dungeon Queue. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2441) + Fixed Custom Scoreboard Error during the Barry Protestors Quest. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2480) ++ Fixed a Custom Scoreboard error during the Magma Boss Fight and Goblin Raid. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2531) ++ Fixed a Custom Scoreboard error while in the Dojo. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2519) ++ Fixed a Custom Scoreboard error during M7 Dragons. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2510) ++ Fixed Custom Scoreboard error during the Raffle Event. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2545) #### Hoppity Fixes @@ -288,6 +350,7 @@ + Fixed "Highlight Requirement Rabbits" requiring "Hoppity Collection Stats" to function. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2398) + Fixed minor formatting issues with Hoppity Event Summary. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2416) + Fixed Hoppity Event stats resetting. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2489) ++ Fixed an issue where Fish the Rabbit and El Dorado did not have compacted chat messages. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2488) #### Chat Fixes @@ -312,6 +375,22 @@ #### Garden Fixes + Fixed outdated Dicer gemstone fortune in FF guide. - Not_a_cow (https://github.com/hannibal002/SkyHanni/pull/2499) ++ Fixed some garden messages not being blocked. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2532) ++ Fixed active sprays not being removed from the GUI when using a washer. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2532) + +#### Combat Fixes + ++ Updated Ghost Counter bestiary tiers to reflect Hypixel reducing the max kills needed from 250K to 100K. - Luna (https://github.com/hannibal002/SkyHanni/pull/2533) ++ Fixed a case where the Broodmother countdown could be wildly inaccurate. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2513) + +#### The Carnival Fixes + ++ Fixed two "Catch a Fish" carnival goals not being properly detected from chat. - Luna (https://github.com/hannibal002/SkyHanni/pull/2517) ++ Fixed the bounding box of baby zombies in Zombie Shootout. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2512) + +#### Fishing Fixes + ++ Fixed error messages while using the Chum Bucket Hider feature. - nea89 (https://github.com/hannibal002/SkyHanni/pull/2587) #### Misc Fixes @@ -327,6 +406,12 @@ + Fixed performance issues with a high number of dungeon runs in one session. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2504) + Fixed `/shedittracker duplex` not working. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2501) + Fixed "Last Server Joined" spamming the chat. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2495) ++ Fixed lag spikes in Path Finder. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2525) ++ Fixed old mayor perks not being marked as inactive when the mayor changes. - Luna (https://github.com/hannibal002/SkyHanni/pull/2524) ++ Fixed direct GitHub downloads triggering the source checker. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2548) ++ Fixed reforge display not working with new mining stats. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2555) ++ Fixed Totem of Corruption expiry warning not working in some cases. - Luna (https://github.com/hannibal002/SkyHanni/pull/2554) ++ Fixed a few typos in the config. - rdbt (https://github.com/hannibal002/SkyHanni/pull/2585) ### Technical Details @@ -366,6 +451,44 @@ + Updated HandleEvent onlyOnIslands to handle multiple islands. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2502) + Added an abstract "bucketed" tracker that can store where items came from. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2306) + Takes an enum in instantiation and has built-in logic for swapping display types. ++ Graph Editor improvements. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2515) + + Code cleanup in Graph Editor, moving node lists into their own class. + + Fixed searchable tag list. + + Added more graph node tags; only display certain tags on specific islands in the editor. + + Added an option to limit the maximum render range of nodes and edges in the Graph Editor for better performance. ++ Hoppity's Collection highlighting now updates on event triggers instead of every frame. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) ++ Added `select near look` keybind in Graph Editor. - nea (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Added checks to avoid creating bugs with the area structure in Graph Editor. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Added options to the graph node list to hide nodes with certain tags. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2537) ++ Removed the use of `LorenzChatEvent()` for 'manually' adding data to Hoppity Chat Compact. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2488) + + Now uses `EggFoundEvent()`. ++ The Renderable Wrapped String now has an option to align text inside the wrapped string box. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2372) ++ Improved handling of unknown stats for ReforgeAPI. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2562) ++ Added `AreaChangeEvent`. - Empa (https://github.com/hannibal002/SkyHanni/pull/2535) ++ Updated `HandleEvent` to allow `onlyOnIsland` usage for a single island without brackets. - Empa (https://github.com/hannibal002/SkyHanni/pull/2535) ++ Created a Text method to display a paginated list. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2583) + + Moved existing paged lists in `/shcommands` and `/shremind` to use this. ++ Node Tags filter list in Graph Editor now sorts by nodes per tag. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2575) ++ Additional code cleanup around ingredients. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2576) ++ Removed duplicate rounding functions. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1931) ++ Added HTTP Request Patching. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2578) ++ Removed references to NEU code, especially code from the Utils class in NEU. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2419) ++ Banned importing `io.github.moulberry.notenoughupdates.util.Utils`. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2419) ++ Added common live templates. - Thunderblade73 (https://github.com/hannibal002/SkyHanni/pull/2463) + + These can be automatically imported via the plugin "Live Templates Sharing". ++ Created and used primitive recipe and ingredient classes. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/2460) + + These are added as a layer between SkyHanni and NEU so that we are not reliant on NEU functions. ++ Added Blossom Gradle plugin for token replacement in code. - ThatGravyBoat (https://github.com/hannibal002/SkyHanni/pull/2558) + + `@MOD_VERSION@` is now a token that will be replaced. + +### Removed Features + ++ Removed Wild Strawberry Dye notification. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2520) + + Artist's Abode now sends a lobby-wide message for dye drops, making the notification obsolete. ++ Removed `Only Requirement Not Met` and `Highlight Requirement Rabbits` config options. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) + + Replaced then with a draggable list of different Hoppity collection highlight options. ++ Removed "Forge GfS". - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2564) + + Hypixel now pulls directly from sacks when using the forge. ## Version 0.26 diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 9c67c0de1246..0783d9e09f82 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -864,6 +864,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Option to show the walls also when inside the Nucleus. + Fossil Excavator Solver. - CalMWolfs (https://github.com/hannibal002/SkyHanni/pull/1427) + Shows where to next click for optimal chance of solving the fossil. If there is a fossil this will find it within 18 moves. ++ Hides tooltips of items inside the Fossil Excavator in Glacite Tunnels. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2539) + Excavation Profit Tracker. - hannibal2 + Empa (https://github.com/hannibal002/SkyHanni/pull/1432) + Count all drops you gain while excavating in the Fossil Research Center. + Track Glacite Powder gained as well (no profit, but progress). @@ -989,6 +990,12 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Use /shhoppitystats for live stats. + Added optional warning when Hoppity calls you with a rabbit to sell. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) + Added hotkey for picking up Abiphone calls from Hoppity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2272) ++ Added a draggable list for Hoppity's Collection menu rabbit highlighting. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) + + Factory/Shop milestones = Yellow/Gold. + + Stray rabbits = Dark Aqua. + + Abi = Dark Green. ++ Added a toggle to highlight found rabbits in Hoppity's Collection menu. - the1divider (https://github.com/hannibal002/SkyHanni/pull/2438) ++ Added the ability to change the color of missing rabbit dyes in Hoppity's Collection to reflect rabbit rarity. - Daveed (https://github.com/hannibal002/SkyHanni/pull/2522) ### The Carnival @@ -1150,6 +1157,7 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Customizable GUI + Option to hide the chat messages + While on the Winter Island, show a timer until Jerry's Workshop closes. - hannibal2 ++ Added a message to warp to Winter Island spawn when a Reindrake spawns. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2569) + **Custom Text Box** - CalMWolfs + Write fancy text into a gui element to show on your screen at all time + Supports color codes @@ -1322,9 +1330,16 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Added to the Item Number list. + Added Compact Experimentation Table chat rewards. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2209) + Uses a compact chat message of rewards gained from Add-ons/Experiments. ++ Added Superpair Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Displays found and matched pairs, power-ups, and missing pairs/normals. ++ Added Experiments Dry-Streak Display. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Shows attempts and XP since the last ULTRA-RARE. ++ Added Experiments Profit Tracker. - ILike2WatchMemes (https://github.com/hannibal002/SkyHanni/pull/2171) + + Tracks profits in Coins and Enchanting XP. + In-Water Display. - Stella (https://github.com/hannibal002/SkyHanni/pull/1892) + Useful when using a Prismarine Blade in Stranded Mode. + Added Beacon Power Display. - Empa (https://github.com/hannibal002/SkyHanni/pull/1901) ++ Added highlighting for the active Beacon Effect. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/2546) + Added Hide Useless Armor Stands. - Empa (https://github.com/hannibal002/SkyHanni/pull/1962) + Hides armor stands that briefly appear on Hypixel. + **Custom Wardrobe**, a new look for the wardrobe. - j10an15, Empa (https://github.com/hannibal002/SkyHanni/pull/2039) @@ -1361,12 +1376,21 @@ Use `/sh` or `/skyhanni` to open the SkyHanni config in game. + Get a title warning when entering an area. + See area names in the world. + Does not yet work with Spider's Den and Dungeon Hub. Only partial support for Farming Islands and the Rift. ++ Added navigation command. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2575) + + Use `/shnavigate ` to find interesting locations on your current SkyBlock island by searching for them. + + Displays a pathfinder to the location. + + Works with NPCs, points of interest, areas, slayer spots, emissaries, crimson mini-bosses, spots to mine ores, break crops, and kill mobs. + + Does not yet work with Spider's Den and Dungeon Hub (still needs to be mapped out). + Added `/gfs` to fix a broken Piggy Bank. - j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/2150) + Added Broodmother spawn alert, countdown and stage change messages. - MTOnline (https://github.com/hannibal002/SkyHanni/pull/2325) + Countdown will not show until a spawning stage change is observed, and may be off by a few seconds. + Added option to hide pet nametag text. - Empa + j10a1n15 (https://github.com/hannibal002/SkyHanni/pull/1880) + Added Transfer Cooldown Prevention. - Cuz_Im_Clicks (https://github.com/hannibal002/SkyHanni/pull/1751) + Wait for the transfer cooldown to complete before sending commands like warp/is/hub. ++ Added Carry Tracker. - hannibal2 (https://github.com/hannibal002/SkyHanni/pull/2185) + + Use `/shcarry` to add carries to a customer, and set a price for a slayer boss. + + Automatically counts slayer bosses you carry. + + Automatically tracks coins received from customers via `/trade`.
diff --git a/root.gradle.kts b/root.gradle.kts index ebdebe043c9b..5baae39e2ba7 100644 --- a/root.gradle.kts +++ b/root.gradle.kts @@ -3,6 +3,7 @@ import com.replaymod.gradle.preprocess.Node plugins { id("dev.deftu.gradle.preprocess") version "0.6.1" + id("net.kyori.blossom") version "1.3.2" apply false id("gg.essential.loom") version "1.6.+" apply false kotlin("jvm") version "2.0.0" apply false kotlin("plugin.power-assert") version "2.0.0" apply false @@ -12,7 +13,7 @@ plugins { allprojects { group = "at.hannibal2.skyhanni" - version = "0.27.Beta.8" + version = "0.27.Beta.12" } preprocess { diff --git a/settings.gradle.kts b/settings.gradle.kts index aaf0f02cf6d6..adee2acba161 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,6 +14,7 @@ pluginManagement { maven("https://repo.nea.moe/releases") maven("https://repo.sk1er.club/repository/maven-releases/") maven("https://maven.deftu.dev/releases") + maven("https://maven.teamresourceful.com/repository/maven-private/") // Blossom maven("https://jitpack.io") { content { includeGroupByRegex("(com|io)\\.github\\..*") diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 09a293829e25..45d02f5445f6 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -42,7 +42,7 @@ import org.apache.logging.log4j.Logger clientSideOnly = true, useMetadata = true, guiFactory = "at.hannibal2.skyhanni.config.ConfigGuiForgeInterop", - version = "0.27.Beta.8", + version = "@MOD_VERSION@", ) class SkyHanniMod { diff --git a/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt index 7407dd66053a..89ccfd656f07 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/GetFromSackAPI.kt @@ -173,8 +173,6 @@ object GetFromSackAPI { // The last parameter could be "2*3". This does not support ending with ")", but it is good enough val argsNull = !args.last().last().isDigit() val arguments = if (argsNull) { - if (!config.defaultGFS) return CommandResult.WRONG_ARGUMENT to null - args + config.defaultAmountGFS.toString() } else args diff --git a/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt index 97e041a89475..6217c56c21d0 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/HotmAPI.kt @@ -91,10 +91,10 @@ object HotmAPI { var mineshaftMayhem: MayhemPerk? = null enum class SkymallPerk(chat: String, itemString: String) { - MINING_SPEED("Gain §r§a\\+100 §r§6⸕ Mining Speed§r§f\\.", "Gain §a\\+100 §6⸕ Mining Speed§7\\."), - MINING_FORTUNE("Gain §r§a\\+50 §r§6☘ Mining Fortune§r§f\\.", "Gain §a\\+50 §6☘ Mining Fortune§7\\."), + MINING_SPEED("Gain §r§6\\+100⸕ Mining Speed§r§f\\.", "Gain §6\\+100⸕ Mining Speed§7\\."), + MINING_FORTUNE("Gain §r§6\\+50☘ Mining Fortune§r§f\\.", "Gain §6\\+50☘ Mining Fortune§7\\."), EXTRA_POWDER("Gain §r§a\\+15% §r§fmore Powder while mining\\.", "Gain §a\\+15% §7more Powder while mining\\."), - ABILITY_COOLDOWN("Reduce Pickaxe Ability cooldown by §r§a20%§r§f\\.", "Reduce Pickaxe Ability cooldown by"), + ABILITY_COOLDOWN("§r§a-20%§r§f Pickaxe Ability cooldowns\\.", "§a-20%§7 Pickaxe Ability cooldowns\\."), GOBLIN_CHANCE("§r§a10x §r§fchance to find Golden and Diamond Goblins\\.", "§a10x §7chance to find Golden and"), TITANIUM("Gain §r§a5x §r§9Titanium §r§fdrops", "Gain §a5x §9Titanium §7drops\\.") ; diff --git a/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt index 987a864af77e..534d38d47c82 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/ReforgeAPI.kt @@ -5,6 +5,7 @@ import at.hannibal2.skyhanni.data.model.SkyblockStat import at.hannibal2.skyhanni.data.model.SkyblockStatList import at.hannibal2.skyhanni.events.NeuRepositoryReloadEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ItemCategory import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull @@ -176,7 +177,18 @@ object ReforgeAPI { while (reader.hasNext()) { val name = reader.nextName() val value = reader.nextDouble() - list[SkyblockStat.valueOf(name.uppercase())] = value + + val stat = SkyblockStat.getValueOrNull(name.uppercase()) ?: run { + ErrorManager.logErrorStateWithData( + "Unknown stat: '${name.uppercase()}'", + "Stat list could not parse stat", + "failed" to name.uppercase(), + betaOnly = true, + ) + continue + } + + list[stat] = value } reader.endObject() return list diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt index 78769060accf..4b4c008523e2 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt @@ -130,6 +130,13 @@ class EventHandler private constructor(val name: String, priv val invoker: Consumer, val options: HandleEvent, val generic: Class<*>?, - val onlyOnIslandTypes: Set = options.onlyOnIslands.toSet(), - ) + ) { + val onlyOnIslandTypes: Set = getIslands(options) + + companion object { + private fun getIslands(options: HandleEvent): Set = + if (options.onlyOnIslands.isEmpty()) setOf(options.onlyOnIsland) + else options.onlyOnIslands.toSet() + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt index c07239dc2ae9..a88f7f33724c 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/HandleEvent.kt @@ -12,8 +12,15 @@ annotation class HandleEvent( /** * If the event should only be received while on a specific skyblock island. + * To specify multiple islands, use [onlyOnIslands] instead. */ - vararg val onlyOnIslands: IslandType = [IslandType.ANY], + val onlyOnIsland: IslandType = IslandType.ANY, + + /** + * If the event should only be received while being on specific skyblock islands. + * To specify only one island, use [onlyOnIsland] instead. + */ + vararg val onlyOnIslands: IslandType = [], /** * The priority of when the event will be called, lower priority will be called first, see the companion object. diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt index 4f3685c8bdff..c05b438cde20 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/SkyHanniEvent.kt @@ -1,5 +1,8 @@ package at.hannibal2.skyhanni.api.event +/** + * Use @[HandleEvent] + */ abstract class SkyHanniEvent protected constructor() { var isCancelled: Boolean = false diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt index 4ac3f7925ce5..bf0f2ba0a4a4 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt @@ -104,6 +104,7 @@ class ConfigManager { // commands "features.garden.GardenConfig.cropSpeedMeterPos", "features.misc.MiscConfig.collectionCounterPos", + "features.misc.MiscConfig.carryPosition", "features.misc.MiscConfig.lockedMouseDisplay", // debug features diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index c881cc578ba4..b9f21ca2255c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt @@ -12,7 +12,7 @@ import com.google.gson.JsonPrimitive object ConfigUpdaterMigrator { val logger = LorenzLogger("ConfigMigration") - const val CONFIG_VERSION = 57 + const val CONFIG_VERSION = 59 fun JsonElement.at(chain: List, init: Boolean): JsonElement? { if (chain.isEmpty()) return this if (this !is JsonObject) return null 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 d0f58f0829d9..9f2e3cc3fd71 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/commands/Commands.kt @@ -57,12 +57,14 @@ import at.hannibal2.skyhanni.features.garden.pests.PestFinder import at.hannibal2.skyhanni.features.garden.pests.PestProfitTracker import at.hannibal2.skyhanni.features.garden.visitor.GardenVisitorDropStatistics import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker import at.hannibal2.skyhanni.features.mining.KingTalismanHelper import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker import at.hannibal2.skyhanni.features.mining.glacitemineshaft.CorpseTracker import at.hannibal2.skyhanni.features.mining.powdertracker.PowderTracker import at.hannibal2.skyhanni.features.minion.MinionFeatures +import at.hannibal2.skyhanni.features.misc.CarryTracker import at.hannibal2.skyhanni.features.misc.CollectionTracker import at.hannibal2.skyhanni.features.misc.LockMouseLook import at.hannibal2.skyhanni.features.misc.MarkedPlayerManager @@ -70,6 +72,7 @@ import at.hannibal2.skyhanni.features.misc.TpsCounter import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager import at.hannibal2.skyhanni.features.misc.limbo.LimboTimeTracker import at.hannibal2.skyhanni.features.misc.massconfiguration.DefaultConfigFeatures +import at.hannibal2.skyhanni.features.misc.pathfind.NavigationHelper import at.hannibal2.skyhanni.features.misc.reminders.ReminderManager import at.hannibal2.skyhanni.features.misc.update.UpdateManager import at.hannibal2.skyhanni.features.misc.visualwords.VisualWordGui @@ -77,7 +80,6 @@ import at.hannibal2.skyhanni.features.rift.area.westvillage.VerminTracker import at.hannibal2.skyhanni.features.rift.everywhere.PunchcardHighlight import at.hannibal2.skyhanni.features.slayer.SlayerProfitTracker import at.hannibal2.skyhanni.test.DebugCommand -import at.hannibal2.skyhanni.test.GraphEditor import at.hannibal2.skyhanni.test.PacketTest import at.hannibal2.skyhanni.test.SkyBlockIslandTest import at.hannibal2.skyhanni.test.SkyHanniConfigSearchResetCommand @@ -92,7 +94,8 @@ import at.hannibal2.skyhanni.test.command.CopyScoreboardCommand import at.hannibal2.skyhanni.test.command.TestChatCommand import at.hannibal2.skyhanni.test.command.TrackParticlesCommand import at.hannibal2.skyhanni.test.command.TrackSoundsCommand -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.test.graph.GraphEditor +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ExtendedChatColor import at.hannibal2.skyhanni.utils.ItemPriceUtils @@ -180,9 +183,9 @@ object Commands { ) registerCommand("shremind", "Set a reminder for yourself") { ReminderManager.command(it) } registerCommand("shwords", "Opens the config list for modifying visual words") { openVisualWords() } + registerCommand("shnavigate", "Using path finder to go to locatons") { NavigationHelper.onCommand(it) } } - private fun usersNormal() { registerCommand( "shmarkplayer", @@ -191,8 +194,7 @@ object Commands { registerCommand("shtrackcollection", "Tracks your collection gain over time") { CollectionTracker.command(it) } registerCommand( "shcroptime", - "Calculates with your current crop per second speed " + - "how long you need to farm a crop to collect this amount of items", + "Calculates with your current crop per second speed how long you need to farm a crop to collect this amount of items", ) { GardenCropTimeCommand.onCommand(it) } registerCommand( "shcropsin", @@ -249,8 +251,7 @@ object Commands { ) { FarmingWeightDisplay.lookUpCommand(it) } registerCommand( "shcopytranslation", - "Copy the English translation of a message in another language to the clipboard.\n" + - "Uses a 2 letter language code that can be found at the end of a translation message.", + "Copy the English translation of a message in another language to the clipboard.\n" + "Uses a 2 letter language code that can be found at the end of a translation message.", ) { Translator.fromEnglish(it) } registerCommand( "shtranslate", @@ -276,6 +277,10 @@ object Commands { "shresetpestprofittracker", "Resets the Pest Profit Tracker", ) { PestProfitTracker.resetCommand() } + registerCommand( + "shresetexperimentsprofittracker", + "Resets the Experiments Profit Tracker", + ) { ExperimentsProfitTracker.resetCommand() } registerCommand( "shresetmythologicalcreaturetracker", "Resets the Mythological Creature Tracker", @@ -362,8 +367,12 @@ object Commands { ) { ColorFormattingHelper.printColorCodeList() } registerCommand( "shtps", - "Informs in chat about the server ticks per second (TPS)." + "Informs in chat about the server ticks per second (TPS).", ) { TpsCounter.tpsCommand() } + registerCommand( + "shcarry", + "Keep track of carries you do.", + ) { CarryTracker.onCommand(it) } } private fun usersBugFix() { @@ -375,7 +384,7 @@ object Commands { registerCommand( "shtogglehypixelapierrors", "Show/hide hypixel api error messages in chat", - ) { APIUtil.toggleApiErrorMessages() } + ) { APIUtils.toggleApiErrorMessages() } registerCommand( "shclearcropspeed", "Reset garden crop speed data and best crop time data", @@ -485,7 +494,7 @@ object Commands { ) { SkyBlockIslandTest.onCommand(it) } registerCommand( "shdebugprice", - "Debug different price sources for an item." + "Debug different price sources for an item.", ) { ItemPriceUtils.debugItemPrice(it) } registerCommand( "shdebugscoreboard", @@ -580,9 +589,7 @@ object Commands { ) { TitleManager.command(it) } registerCommand( "shresetconfig", - "Reloads the config manager and rendering processors of MoulConfig. " + - "This §cWILL RESET §7your config, but also updating the java config files " + - "(names, description, orderings and stuff).", + "Reloads the config manager and rendering processors of MoulConfig. " + "This §cWILL RESET §7your config, but also updating the java config files " + "(names, description, orderings and stuff).", ) { SkyHanniDebugsAndTests.resetConfigCommand() } registerCommand( "shreadcropmilestonefromclipboard", @@ -659,8 +666,7 @@ object Commands { else -> currentStream } - val switchingToBeta = updateStream == UpdateStream.BETA && - (currentStream != UpdateStream.BETA || !UpdateManager.isCurrentlyBeta()) + val switchingToBeta = updateStream == UpdateStream.BETA && (currentStream != UpdateStream.BETA || !UpdateManager.isCurrentlyBeta()) if (switchingToBeta) { ChatUtils.clickableChat( "Are you sure you want to switch to beta? These versions may be less stable.", diff --git a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt index 3e64d5f5abff..ba3a576754dc 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt @@ -27,11 +27,10 @@ import at.hannibal2.skyhanni.data.OtherInventoryData import at.hannibal2.skyhanni.mixins.transformers.gui.AccessorGuiContainer import at.hannibal2.skyhanni.utils.GuiRenderUtils import at.hannibal2.skyhanni.utils.KeyboardManager -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.compat.GuiScreenUtils import at.hannibal2.skyhanni.utils.compat.SkyhanniBaseScreen import net.minecraft.client.Minecraft -import net.minecraft.client.gui.ScaledResolution import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager import org.lwjgl.input.Keyboard @@ -100,7 +99,7 @@ class GuiPositionEditor( } val pos = positions[displayPos] - val location = "§7x: §e${pos.rawX}§7, y: §e${pos.rawY}§7, scale: §e${pos.scale.round(2)}" + val location = "§7x: §e${pos.rawX}§7, y: §e${pos.rawY}§7, scale: §e${pos.scale.roundTo(2)}" GuiRenderUtils.drawStringCentered("§b" + pos.internalName, getScaledWidth() / 2, 18) GuiRenderUtils.drawStringCentered(location, getScaledWidth() / 2, 28) if (pos.canJumpToConfigOptions()) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java index 46a02e9b21e3..ac9f6e0b210a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/combat/ghostcounter/textformatting/BestiaryFormattingConfig.java @@ -30,7 +30,7 @@ public class BestiaryFormattingConfig { @ConfigOption(name = "Progress to Max", desc = "Text to show progress when the §eMaxed Bestiary §7option is §aON\n" + "§e%currentKill% §7is replaced with your current total kill.") @ConfigEditorText - public String showMax_progress = "%currentKill%/250k (%percentNumber%%)"; + public String showMax_progress = "%currentKill%/100k (%percentNumber%%)"; @Expose @ConfigOption(name = "Progress", desc = "Text to show progress when the §eMaxed Bestiary §7option is §cOFF\n" + diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java index b62c88efc61f..6daf37cfda74 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java @@ -108,6 +108,13 @@ public class DevConfig { @ConfigEditorBoolean public boolean fancySbaContributors = false; + @Expose + @ConfigOption( + name = "Number Format Override", + desc = "Forces the number format to use the en_US locale.") + @ConfigEditorBoolean + public boolean numberFormatOverride = false; + @Expose @Category(name = "Minecraft Console", desc = "Minecraft Console Settings") public MinecraftConsoleConfig minecraftConsoles = new MinecraftConsoleConfig(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java index 9eed8233c995..dda1ddb1e50c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/GraphConfig.java @@ -4,6 +4,7 @@ import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; 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 org.lwjgl.input.Keyboard; @@ -31,6 +32,11 @@ public class GraphConfig { @ConfigEditorKeybind(defaultKey = -98) // Middle Mouse public int selectKey = -98; + @Expose + @ConfigOption(name = "Select near look", desc = "Select the node closest to where you are looking.") + @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE) + public int selectRaycastKey = Keyboard.KEY_NONE; + @Expose @ConfigOption(name = "Connect Key", desc = "Connect the nearest node with the active node. If the nodes are already connected removes the connection.") @ConfigEditorKeybind(defaultKey = Keyboard.KEY_C) @@ -99,6 +105,17 @@ public class GraphConfig { @ConfigLink(owner = GraphConfig.class, field = "enabled") public Position namedNodesList = new Position(20, 20); + @Expose + @ConfigOption( + name = "Max Node Distance", + desc = "Only render nodes below this distance to the player.") + @ConfigEditorSlider( + minValue = 10, + maxValue = 500, + minStep = 10 + ) + public int maxNodeDistance = 50; + @Expose @ConfigOption(name = "Shows Stats", desc = "Show funny extra statistics on save. May lag the game a bit.") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java index 385c162c6623..a1c29cd4482f 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dungeon/ObjectHighlighterConfig.java @@ -14,13 +14,13 @@ public class ObjectHighlighterConfig { // TODO move some stuff from DungeonConfig into this @Expose - @ConfigOption(name = "Stared", desc = "") + @ConfigOption(name = "Starred Mobs", desc = "") @Accordion public StarredConfig starred = new StarredConfig(); public static class StarredConfig { @Expose - @ConfigOption(name = "Highlight Starred", desc = "Highlights all starred mobs in one colour.") + @ConfigOption(name = "Highlight Starred", desc = "Highlights starred mobs in a color.") @ConfigEditorBoolean @FeatureToggle public Property highlight = Property.of(true); @@ -40,7 +40,7 @@ public static class StarredConfig { public String info; @Expose - @ConfigOption(name = "Colour", desc = "Color in which the stared mobs are highlighted.") + @ConfigOption(name = "Color", desc = "The color used to highlight starred mobs.") @ConfigEditorColour public Property colour = Property.of("0:60:255:255:0"); } @@ -53,18 +53,18 @@ public static class StarredConfig { public static class FelConfig { @Expose - @ConfigOption(name = "Highlight Fels Skull", desc = "Highlights fels that are not yet active.") + @ConfigOption(name = "Highlight Fels Skull", desc = "Highlights fels that are not active.") @ConfigEditorBoolean @FeatureToggle public Property highlight = Property.of(true); @Expose - @ConfigOption(name = "Draw Line", desc = "Draws a line to fels skulls. Works only if the highlight is enabled.") + @ConfigOption(name = "Draw Line", desc = "Draws a line to fels skulls. Requires highlight to be enabled.") @ConfigEditorBoolean public Boolean line = false; @Expose - @ConfigOption(name = "Colour", desc = "Color for the fel skull and line.") + @ConfigOption(name = "Color", desc = "The color used to highlight fel skulls and draw the line.") @ConfigEditorColour public Property colour = Property.of("0:200:255:0:255"); } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java index b438d83f5c3b..8bbaa962ca26 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/hoppity/HoppityEggsConfig.java @@ -197,6 +197,11 @@ public String toString() { } } + @Expose + @ConfigOption(name = "Show Duplicate Count", desc = "Show the number of previous finds of a duplicate Hoppity rabbit in chat messages.") + @ConfigEditorBoolean + public boolean showDuplicateNumber = false; + @Expose @ConfigOption( name = "Rabbit Pet Warning", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java index 837f4c7ea811..550ceaeee0ec 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/event/winter/WinterConfig.java @@ -46,4 +46,10 @@ public class WinterConfig { @FeatureToggle public boolean newYearCakeReminder = true; + @Expose + @ConfigOption(name = "Reindrake Warp Helper", desc = "Sends a clickable message in chat to warp to the Winter Island spawn when a Reindrake spawns.") + @ConfigEditorBoolean + @FeatureToggle + public boolean reindrakeWarpHelper = true; + } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java index b39f5f01ce63..8aa9aa6a1124 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/garden/GardenConfig.java @@ -158,12 +158,6 @@ public class GardenConfig { @FeatureToggle public boolean burrowingSporesNotification = true; - @Expose - @ConfigOption(name = "Wild Strawberry", desc = "Show a notification when a Wild Strawberry Dye drops while farming.") - @ConfigEditorBoolean - @FeatureToggle - public boolean wildStrawberryDyeNotification = true; - @Expose @ConfigOption( name = "FF for Contest", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java index 74ab755c9940..37f3d3c42037 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java @@ -36,7 +36,7 @@ public class GUIConfig { @Accordion public ChromaConfig chroma = new ChromaConfig(); - @ConfigOption(name = "Edit GUI Locations", desc = "Change the position of SkyHanni's overlays.") + @ConfigOption(name = "Edit GUI Locations", desc = "Opens the Position Editor, allows changing the position of SkyHanni's overlays.") @ConfigEditorButton(buttonText = "Edit") public Runnable positions = () -> GuiEditManager.openGuiPositionEditor(true); diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java index ee77d6664317..f4b16343fef0 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/GetFromSackConfig.java @@ -25,11 +25,6 @@ public class GetFromSackConfig { @FeatureToggle public boolean superCraftGFS = true; - @Expose - @ConfigOption(name = "Default GfS", desc = "If you don't provide an amount, a default one will be used instead. Queued GfS needs to be on in order for this to work.") - @ConfigEditorBoolean - public boolean defaultGFS = false; - @Expose @ConfigOption(name = "Default Amount GfS", desc = "The default amount of items used when an amount isn't provided.") @ConfigEditorSlider(minValue = 1, maxValue = 64, minStep = 1) diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java index cf162ad7b6a8..510f953ca2f9 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/InventoryConfig.java @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.config.HasLegacyId; import at.hannibal2.skyhanni.config.features.inventory.chocolatefactory.ChocolateFactoryConfig; import at.hannibal2.skyhanni.config.features.inventory.customwardrobe.CustomWardrobeConfig; +import at.hannibal2.skyhanni.config.features.inventory.experimentationtable.ExperimentationTableConfig; import at.hannibal2.skyhanni.config.features.inventory.helper.HelperConfig; import at.hannibal2.skyhanni.config.features.itemability.ItemAbilityConfig; import at.hannibal2.skyhanni.config.features.misc.EstimatedItemValueConfig; @@ -38,6 +39,10 @@ public class InventoryConfig { @Category(name = "Bazaar", desc = "Be smart when buying or selling many items in the Bazaar.") public BazaarConfig bazaar = new BazaarConfig(); + @Expose + @Category(name = "Experimentation Table", desc = "QOL features for the Experimentation Table.") + public ExperimentationTableConfig experimentationTable = new ExperimentationTableConfig(); + @Expose @Category(name = "Enchant Parsing", desc = "Settings for SkyHanni's Enchant Parsing") public EnchantParsingConfig enchantParsing = new EnchantParsingConfig(); @@ -61,6 +66,7 @@ public class InventoryConfig { @Expose @ConfigOption(name = "Item Pickup Log", desc = "Logs all the picked up and dropped items") @Accordion + // TODO remove the suffix "config" public ItemPickupLogConfig itemPickupLogConfig = new ItemPickupLogConfig(); @Expose @@ -286,4 +292,10 @@ public String toString() { @ConfigEditorBoolean @FeatureToggle public boolean hexAsColorInLore = true; + + @Expose + @ConfigOption(name = "Highlight Active Beacon Effect", desc = "Highlights the currently selected beacon effect in the beacon inventory.") + @ConfigEditorBoolean + @FeatureToggle + public boolean highlightActiveBeaconEffect = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java index e35bc4d7e790..5d1c63f8d7e1 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/chocolatefactory/ChocolateFactoryConfig.java @@ -2,6 +2,7 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats.HighlightRabbitTypes; import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStats.ChocolateFactoryStat; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.Accordion; @@ -174,18 +175,27 @@ public class ChocolateFactoryConfig { public boolean hoppityMenuShortcut = true; @Expose - @ConfigOption(name = "Highlight Requirement Rabbits", desc = "Highlight rabbits that have requirements.\n" + - "§cRed: Requirement not met.\n" + - "§aGreen: Requirement met.") + @ConfigOption(name = "Highlight Found Rabbits", desc = "Highlight rabbits that have already been found.") @ConfigEditorBoolean @FeatureToggle - public boolean highlightRabbitsWithRequirement = false; + public boolean highlightFoundRabbits = false; @Expose - @ConfigOption(name = "Only Requirement Not Met", desc = "Only highlight the rabbits you don't have the requirement for.") + @ConfigOption(name = "Highlight Rabbits", desc = "Highlight specific rabbit types in Hoppity's Collection.") + @ConfigEditorDraggableList + public List highlightRabbits = new ArrayList<>(Arrays.asList( + HighlightRabbitTypes.ABI, + HighlightRabbitTypes.FACTORY, + HighlightRabbitTypes.MET, + HighlightRabbitTypes.NOT_MET, + HighlightRabbitTypes.SHOP, + HighlightRabbitTypes.STRAYS + )); + + @Expose + @ConfigOption(name = "Re-color Missing Rabbit Dyes", desc = "Replace the gray dye in Hoppity's Collection with a color for the rarity of the rabbit.") @ConfigEditorBoolean - @FeatureToggle - public boolean onlyHighlightRequirementNotMet = true; + public boolean rarityDyeRecolor = true; @Expose @ConfigOption( diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java new file mode 100644 index 000000000000..dfdad248256e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentationTableConfig.java @@ -0,0 +1,50 @@ +package at.hannibal2.skyhanni.config.features.inventory.experimentationtable; + +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.Accordion; +import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class ExperimentationTableConfig { + + @Expose + @ConfigOption(name = "Profit Tracker", desc = "") + @Accordion + public ExperimentsProfitTrackerConfig experimentsProfitTracker = new ExperimentsProfitTrackerConfig(); + + @Expose + @ConfigOption(name = "Dry-Streak Display", desc = "") + @Accordion + public ExperimentsDryStreakConfig dryStreak = new ExperimentsDryStreakConfig(); + + @Expose + @ConfigOption(name = "Superpair Data", desc = "Shows a display with useful information while doing the Superpair experiment.") + @ConfigEditorBoolean + @FeatureToggle + public boolean superpairDisplay = false; + + @Expose + @ConfigLink(owner = ExperimentationTableConfig.class, field = "superpairDisplay") + public Position superpairDisplayPosition = new Position(-372, 161, false, true); + + @Expose + @ConfigOption(name = "Superpairs Clicks Alert", desc = "Display an alert when you reach the maximum clicks gained from Chronomatron or Ultrasequencer.") + @ConfigEditorBoolean + @FeatureToggle + public boolean superpairsClicksAlert = false; + + @Expose + @ConfigOption(name = "ULTRA-RARE Book Alert", desc = "Send a chat message, title and sound when you find an ULTRA-RARE book.") + @ConfigEditorBoolean + @FeatureToggle + public boolean ultraRareBookAlert = false; + + @Expose + @ConfigOption(name = "Guardian Reminder", desc = "Sends a warning when opening the Experimentation Table without a §9§lGuardian Pet §7equipped.") + @ConfigEditorBoolean + @FeatureToggle + public boolean guardianReminder = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java new file mode 100644 index 000000000000..dfba626a764f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsDryStreakConfig.java @@ -0,0 +1,31 @@ +package at.hannibal2.skyhanni.config.features.inventory.experimentationtable; + +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.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +public class ExperimentsDryStreakConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Display attempts and or XP since your last ULTRA-RARE.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Attempts", desc = "Display Attempts since.") + @ConfigEditorBoolean + public boolean attemptsSince = true; + + @Expose + @ConfigOption(name = "XP", desc = "Display XP since.") + @ConfigEditorBoolean + public boolean xpSince = true; + + @Expose + @ConfigLink(owner = ExperimentsDryStreakConfig.class, field = "enabled") + public Position position = new Position(200, -187, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java new file mode 100644 index 000000000000..62ee4f5407ba --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/experimentationtable/ExperimentsProfitTrackerConfig.java @@ -0,0 +1,37 @@ +package at.hannibal2.skyhanni.config.features.inventory.experimentationtable; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentMessages; +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.ConfigEditorSlider; +import io.github.notenoughupdates.moulconfig.annotations.ConfigLink; +import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.List; + +public class ExperimentsProfitTrackerConfig { + + @Expose + @ConfigOption(name = "Enabled", desc = "Tracker for drops/XP you get from experiments.") + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption(name = "Hide Messages", desc = "Change the messages to be hidden after completing Add-on/Main experiments.") + @ConfigEditorDraggableList + public List hideMessages = new ArrayList<>(); + + @Expose + @ConfigOption(name = "Time displayed", desc = "Time displayed after completing an experiment.") + @ConfigEditorSlider(minValue = 5, maxValue = 60, minStep = 1) + public int timeDisplayed = 30; + + @Expose + @ConfigLink(owner = ExperimentsProfitTrackerConfig.class, field = "enabled") + public Position position = new Position(20, 20, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java index 5f54e707d010..717dd76591de 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/inventory/helper/HelperConfig.java @@ -56,30 +56,4 @@ public static class HarpConfig { @ConfigOption(name = "Reforge Helper", desc = "") @Accordion public ReforgeHelperConfig reforge = new ReforgeHelperConfig(); - - @Expose - @ConfigOption(name = "Enchanting", desc = "") - @Accordion - public EnchantingConfig enchanting = new EnchantingConfig(); - - public static class EnchantingConfig { - @Expose - @ConfigOption(name = "Superpairs Clicks Alert", desc = "Display an alert when you reach the maximum clicks gained from Chronomatron or Ultrasequencer.") - @ConfigEditorBoolean - @FeatureToggle - public boolean superpairsClicksAlert = false; - - @Expose - @ConfigOption(name = "ULTRA-RARE Book Alert", desc = "Send a chat message, title and sound when you find an ULTRA-RARE book.") - @ConfigEditorBoolean - @FeatureToggle - public boolean ultraRareBookAlert = false; - - @Expose - @ConfigOption(name = "Guardian Reminder", desc = "Sends a warning when opening the Experimentation Table without a §9§lGuardian Pet §7equipped.") - @ConfigEditorBoolean - @FeatureToggle - public boolean guardianReminder = false; - } - } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java index 61d3b19594a7..229883c83352 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/CorpseTrackerConfig.java @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.config.features.mining; +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; @@ -11,6 +12,7 @@ public class CorpseTrackerConfig { @Expose @ConfigOption(name = "Enabled", desc = "Enable the Corpse Tracker overlay for Glacite Mineshafts.") @ConfigEditorBoolean + @FeatureToggle public boolean enabled = false; @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/ExcavatorTooltipHiderConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/ExcavatorTooltipHiderConfig.java new file mode 100644 index 000000000000..b1489ace876a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/ExcavatorTooltipHiderConfig.java @@ -0,0 +1,21 @@ +package at.hannibal2.skyhanni.config.features.mining; + +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.ConfigOption; + +public class ExcavatorTooltipHiderConfig { + + @Expose + @ConfigOption(name = "Hide Dirt", desc = "Hides tooltips of the Dirt inside of the Fossil Excavator.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideDirt = true; + + @Expose + @ConfigOption(name = "Hide Everything", desc = "Hide all tooltips inside of the Fossil Excavator.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideEverything = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java index 176c8f3bda35..8445afe5336a 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/FossilExcavatorConfig.java @@ -18,6 +18,11 @@ public class FossilExcavatorConfig { @Accordion public ExcavatorProfitTrackerConfig profitTracker = new ExcavatorProfitTrackerConfig(); + @Expose + @ConfigOption(name = "Excavator Tooltip Hider", desc = "") + @Accordion + public ExcavatorTooltipHiderConfig tooltipHider = new ExcavatorTooltipHiderConfig(); + @Expose @ConfigOption( name = "Profit per Excavation", diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java index 5f242ecd5f47..08c8ec894a71 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/mining/MiningConfig.java @@ -96,10 +96,4 @@ public class MiningConfig { @ConfigEditorBoolean @FeatureToggle public boolean highlightYourGoldenGoblin = true; - - @Expose - @ConfigOption(name = "Forge GfS", desc = "Get Forge ingredients of a recipe.") - @ConfigEditorBoolean - @FeatureToggle - public boolean forgeGfs = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java index 03b0bf779f61..9d503c3986be 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java @@ -144,6 +144,9 @@ public class MiscConfig { @Expose public Position collectionCounterPos = new Position(10, 10, false, true); + @Expose + public Position carryPosition = new Position(10, 10, false, true); + @Expose @ConfigOption(name = "Brewing Stand Overlay", desc = "Display the item names directly inside the Brewing Stand.") @ConfigEditorBoolean diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java index 96c721539c1c..f64a42506043 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/rift/EnigmaSoulConfig.java @@ -15,6 +15,11 @@ public class EnigmaSoulConfig { @FeatureToggle public boolean enabled = true; + @Expose + @ConfigOption(name = "Show Path Finder", desc = "Additionally show a pathfind to the Enigma Soul.") + @ConfigEditorBoolean + public boolean showPathFinder = true; + @ConfigOption( name = "§aRift Guide", desc = "Type §e/riftguide §7in chat or navigate through the SkyBlock Menu to open the §aRift Guide§7. " + @@ -26,6 +31,5 @@ public class EnigmaSoulConfig { @Expose @ConfigOption(name = "Color", desc = "Color of the Enigma Souls.") @ConfigEditorColour - public String color = "0:120:13:49:255"; - + public String color = "0:245:219:27:198"; } 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 83e7ea47c254..754eea3bba59 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/storage/ProfileSpecificStorage.java @@ -31,6 +31,7 @@ import at.hannibal2.skyhanni.features.garden.pests.VinylType; import at.hannibal2.skyhanni.features.garden.visitor.VisitorReward; import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker; +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentsProfitTracker; import at.hannibal2.skyhanni.features.inventory.wardrobe.WardrobeAPI; import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay; import at.hannibal2.skyhanni.features.mining.fossilexcavator.ExcavatorProfitTracker; @@ -65,6 +66,29 @@ private static SimpleTimeMark SimpleTimeMarkFarPast() { @Expose public String currentPet = ""; + @Expose + public ExperimentationStorage experimentation = new ExperimentationStorage(); + + public static class ExperimentationStorage { + + @Expose + public LorenzVec tablePos = new LorenzVec(); + + @Expose + public ExperimentsDryStreakStorage dryStreak = new ExperimentsDryStreakStorage(); + + public static class ExperimentsDryStreakStorage { + @Expose + public int attemptsSince = 0; + + @Expose + public int xpSince = 0; + } + + @Expose + public ExperimentsProfitTracker.Data experimentsProfitTracker = new ExperimentsProfitTracker.Data(); + } + @Expose public ChocolateFactoryStorage chocolateFactory = new ChocolateFactoryStorage(); diff --git a/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt b/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt index 0392eab25af8..1d8182328b6e 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HotmData.kt @@ -26,22 +26,21 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.formatLong +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.indexOfFirstMatch -import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.allLettersFirstUppercase import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.inventory.Slot import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.math.ceil import kotlin.math.pow -private fun calculatePeakOfTheMountainLoot(level: Int): Map = buildMap { +private fun calculateCoreOfTheMountainLoot(level: Int): Map = buildMap { for (i in 1..level) { when (i) { 1, 5, 7 -> addOrPut(HotmReward.EXTRA_TOKENS, 1.0) - 2 -> addOrPut(HotmReward.EXTRA_FORGE_SLOTS, 1.0) + 2 -> addOrPut(HotmReward.ABILITY_LEVEL, 1.0) 3 -> addOrPut(HotmReward.EXTRA_COMMISSION_SLOTS, 1.0) 4 -> addOrPut(HotmReward.MORE_BASE_MITHRIL_POWER, 1.0) 6 -> addOrPut(HotmReward.MORE_BASE_GEMSTONE_POWER, 2.0) @@ -62,20 +61,14 @@ enum class HotmData( MINING_SPEED( "Mining Speed", 50, - { level -> (level + 1.0).pow(3) }, + { level -> (level + 1.0).pow(3.0) }, { level -> mapOf(HotmReward.MINING_SPEED to level * 20.0) }, ), MINING_FORTUNE( "Mining Fortune", 50, { level -> (level + 1.0).pow(3.05) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to level * 5.0) }, - ), - QUICK_FORGE( - "Quick Forge", - 20, - { level -> (level + 1.0).pow(4) }, - { level -> mapOf(HotmReward.FORGE_TIME_DECREASE to if (level >= 20) 30.0 else 10.0 + (level * 0.5)) }, + { level -> mapOf(HotmReward.MINING_FORTUNE to level * 2.0) }, ), TITANIUM_INSANIUM( "Titanium Insanium", @@ -83,40 +76,47 @@ enum class HotmData( { level -> (level + 1.0).pow(3.1) }, { level -> mapOf(HotmReward.TITANIUM_CHANCE to 2.0 + (level * 0.1)) }, ), - DAILY_POWDER( - "Daily Powder", - 100, - { level -> 200 + ((level - 1) * 18.0) }, - { level -> mapOf(HotmReward.DAILY_POWDER to (200.0 + ((level - 1.0) * 18.0)) * 2.0) }, - ), LUCK_OF_THE_CAVE( "Luck of the Cave", 45, { level -> (level + 1.0).pow(3.07) }, { level -> mapOf(HotmReward.EXTRA_CHANCE_TRIGGER_RARE_OCCURRENCES to 5.0 + level) }, ), - CRYSTALLIZED( - "Crystallized", - 30, - { level -> (level + 1.0).pow(3.4) }, - { level -> - mapOf( - HotmReward.MINING_SPEED to 20.0 + ((level - 1.0) * 6.0), - HotmReward.MINING_FORTUNE to 20.0 + ((level - 1.0) * 5.0), - ) - }, - ), EFFICIENT_MINER( "Efficient Miner", 100, { level -> (level + 1.0).pow(2.6) }, - { level -> mapOf(HotmReward.AVERAGE_BLOCK_BREAKS to (10.0 + (level * 0.4)) * (1.0 + (level * 0.05))) }, + { level -> mapOf(HotmReward.MINING_SPREAD to 3.0 * level) }, ), - ORBITER( - "Orbiter", - 80, - { level -> level * 70.0 }, - { level -> mapOf(HotmReward.CHANCE_EXTRA_XP_ORBS to 0.2 + (level * 0.01)) }, + QUICK_FORGE( + "Quick Forge", + 20, + { level -> (level + 1.0).pow(3.2) }, + { level -> mapOf(HotmReward.FORGE_TIME_DECREASE to if (level >= 20) 30.0 else 10.0 + (level * 0.5)) }, + ), + OLD_SCHOOL( + "Old-School", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.ORE_FORTUNE to level * 5.0) }, + ), + PROFESSIONAL( + "Professional", + 140, + { level -> (level + 1.0).pow(2.3) }, + { level -> mapOf(HotmReward.MINING_SPEED to 50.0 + (level * 5.0)) }, + ), + MOLE( + "Mole", + 200, + { level -> (level + 1.0).pow(2.17883) }, + { level -> mapOf(HotmReward.MINING_SPREAD to 50.0 + ((level - 1) * (350 / 199))) }, + ), + GEM_LOVER( + "Gem Lover", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.GEMSTONE_FORTUNE to 20.0 + (level * 4.0)) }, ), SEASONED_MINEMAN( "Seasoned Mineman", @@ -124,18 +124,25 @@ enum class HotmData( { level -> (level + 1.0).pow(2.3) }, { level -> mapOf(HotmReward.MINING_WISDOM to 5.0 + (level * 0.1)) }, ), - MOLE( - "Mole", - 190, - { level -> (level + 1.0).pow(2.2) }, - { level -> mapOf(HotmReward.AVERAGE_BLOCK_BREAKS to 1.0 + ((level + 9.0) * 0.05 * ((level + 8) % 20))) }, + FORTUNATE_MINEMAN( + "Fortunate Mineman", + 50, + { level -> (level + 1.0).pow(3.2) }, + { level -> mapOf(HotmReward.MINING_FORTUNE to level * 3.0) }, ), - PROFESSIONAL( - "Professional", - 140, - { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_SPEED to 50.0 + (level * 5.0)) }, + BLOCKHEAD( + "Blockhead", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.BLOCK_FORTUNE to level * 5.0) }, + ), + KEEP_IT_COOL( + "Keep It Cool", + 50, + { level -> (level + 1.0).pow(3.07) }, + { level -> mapOf(HotmReward.HEAT_RESISTANCE to level * 0.4) }, ), + LONESOME_MINER( "Lonesome Miner", 45, @@ -153,12 +160,7 @@ enum class HotmData( ) }, ), - FORTUNATE( - "Fortunate", - 20, - { level -> (level + 1.0).pow(3.05) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to 20.0 + (level * 4.0)) }, - ), + POWDER_BUFF( "Powder Buff", 50, @@ -170,32 +172,32 @@ enum class HotmData( ) }, ), - MINING_SPEED_II( - "Mining Speed II", + SPEEDY_MINEMAN( + "Speedy Mineman", 50, { level -> (level + 1.0).pow(3.2) }, { level -> mapOf(HotmReward.MINING_SPEED to level * 40.0) }, ), - MINING_FORTUNE_II( - "Mining Fortune II", - 50, - { level -> (level + 1.0).pow(3.2) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to level * 5.0) }, - ), - // Static - MINING_MADNESS( - "Mining Madness", - 1, - { null }, - { + + + SUBTERRANEAN_FISHER( + "Subterranean Fisher", + 40, + { level -> (level + 1.0).pow(3.07) }, + { level -> mapOf( - HotmReward.MINING_SPEED to 50.0, - HotmReward.MINING_FORTUNE to 50.0, + HotmReward.FISHING_SPEED to 5 + (level * 0.5), + HotmReward.SEA_CREATURE_CHANCE to 1 + (level * 0.1), ) }, + ), + + + // Static + SKY_MALL("Sky Mall", 1, { null }, { emptyMap() }), PRECISION_MINING("Precision Mining", 1, { null }, { mapOf(HotmReward.MINING_SPEED_BOOST to 30.0) }), FRONT_LOADED( @@ -204,16 +206,14 @@ enum class HotmData( { null }, { mapOf( - HotmReward.MINING_SPEED to 100.0, - HotmReward.MINING_FORTUNE to 100.0, - HotmReward.MORE_BASE_MITHRIL_POWER to 2.0, - HotmReward.MORE_BASE_GEMSTONE_POWER to 2.0, + HotmReward.MINING_SPEED to 250.0, + HotmReward.GEMSTONE_FORTUNE to 150.0, + HotmReward.MORE_GEMSTONE_POWER to 200.0, ) }, ), - STAR_POWDER("Star Powder", 1, { null }, { mapOf(HotmReward.MORE_MITHRIL_POWER to 300.0) }), - GOBLIN_KILLER("Goblin Killer", 1, { null }, { emptyMap() }), - + DAILY_GRIND("Daily Grind", 1, { null }, { emptyMap() }), + DAILY_POWDER("Daily Powder", 1, { null }, { emptyMap() }), // Abilities PICKOBULUS( @@ -222,8 +222,8 @@ enum class HotmData( { null }, { level -> mapOf( - HotmReward.ABILITY_RADIUS to ceil(level * 0.5) + 1.0, - HotmReward.ABILITY_COOLDOWN to 130.0 - 10.0 * level, + HotmReward.ABILITY_RADIUS to 3.0, + HotmReward.ABILITY_COOLDOWN to 60.0 - 10.0 * (level - 1), ) }, ), @@ -233,66 +233,57 @@ enum class HotmData( { null }, { level -> mapOf( - HotmReward.ABILITY_DURATION to level + 1.0, - HotmReward.ABILITY_COOLDOWN to 10.0 + 5.0 * level, + HotmReward.MINING_SPEED_BOOST to 200.0 + 50.0 * (level - 1), + HotmReward.ABILITY_DURATION to 10.0 + 5 * (level - 1), + HotmReward.ABILITY_COOLDOWN to 120.0, ) }, ), - VEIN_SEEKER( - "Vein Seeker", + MANIAC_MINER( + "Maniac Miner", 3, { null }, { level -> mapOf( - HotmReward.ABILITY_RADIUS to level + 1.0, - HotmReward.ABILITY_DURATION to 10.0 + 2.0 * level, + HotmReward.ABILITY_DURATION to 20.0 + level * 5.0, HotmReward.ABILITY_COOLDOWN to 60.0, + HotmReward.BREAKING_POWER to 1.0, ) }, ), - MANIAC_MINER( - "Maniac Miner", + + SHEER_FORCE( + "Sheer Force", 3, { null }, { level -> mapOf( - HotmReward.ABILITY_DURATION to 5.0 + level * 5.0, - HotmReward.ABILITY_COOLDOWN to 60.0 - level, + HotmReward.ABILITY_DURATION to 20.0 + 5 * (level - 1), + HotmReward.MINING_SPREAD to 200.0, ) }, ), - PEAK_OF_THE_MOUNTAIN( - "Peak of the Mountain", 10, { null }, - { level -> calculatePeakOfTheMountainLoot(level) }, + ANOMALOUS_DESIRE( + "Anomalous Desire", + 3, + { null }, + { level -> + mapOf( + HotmReward.EXTRA_CHANCE_TRIGGER_RARE_OCCURRENCES to 30.0 + (level - 1) * 10.0, + HotmReward.ABILITY_COOLDOWN to 120.0 - (level - 1) * 10.0, + HotmReward.ABILITY_DURATION to 30.0, + ) + }, ), - // Mining V3 - DAILY_GRIND( - "Daily Grind", - 100, - { level -> 218 + (18 * (level - 1.0)) }, - { level -> mapOf(HotmReward.DAILY_POWDER to 50.0 * level) }, - ), - DUST_COLLECTOR( - "Dust Collector", - 20, - { level -> (level + 1.0).pow(4) }, - { level -> mapOf(HotmReward.FOSSIL_DUST to 1.0 * level) }, - ), - WARM_HEARTED( - "Warm Hearted", - 50, - { level -> (level + 1.0).pow(3.1) }, - { level -> mapOf(HotmReward.COLD_RESISTANCE to 0.2 * level) }, + CORE_OF_THE_MOUNTAIN( + "Core of the Mountain", 10, { null }, + { level -> calculateCoreOfTheMountainLoot(level) }, ), - STRONG_ARM( - "Strong Arm", - 100, - { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_SPEED to 5.0 * level) }, - ), + // Mining V3 + NO_STONE_UNTURNED( "No Stone Unturned", 50, @@ -300,63 +291,87 @@ enum class HotmData( { level -> mapOf(HotmReward.UNKNOWN to 0.5 * level) }, ), - SUB_ZERO_MINING( - "SubZero Mining", + STRONG_ARM( + "Strong Arm", 100, { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to 1.0 * level) }, + { level -> mapOf(HotmReward.MINING_SPEED to 5.0 * level) }, + ), + STEADY_HAND( + "Steady Hand", + 100, + { level -> (level + 1.0).pow(2.6) }, + { level -> mapOf(HotmReward.GEMSTONE_SPREAD to 0.1 * level) }, + ), + WARM_HEART( + "Warm Heart", + 50, + { level -> (level + 1.0).pow(3.1) }, + { level -> mapOf(HotmReward.COLD_RESISTANCE to 0.4 * level) }, ), SURVEYOR( "Surveyor", 20, - { level -> (level + 1.0).pow(4) }, + { level -> (level + 1.0).pow(4.0) }, { level -> mapOf(HotmReward.MINESHAFT_CHANCE to 0.75 * level) }, ), + METAL_HEAD( + "Metal Head", + 20, + { level -> (level + 1.0).pow(4.0) }, + { level -> mapOf(HotmReward.DWARVEN_METAL_FORTUNE to 5.0 * level) }, + ), + RAGS_TO_RICHES( + "Rags to Riches", + 50, + { level -> (level + 1.0).pow(3.05) }, + { level -> mapOf(HotmReward.MINING_FORTUNE to 4.0 * level) }, + ), EAGER_ADVENTURER( "Eager Adventurer", 100, { level -> (level + 1.0).pow(2.3) }, - { level -> mapOf(HotmReward.MINING_SPEED to 2.0 * level) }, + { level -> mapOf(HotmReward.MINING_SPEED to 4.0 * level) }, ), - - DEAD_MANS_CHEST( - "Dead Man's Chest", + CRYSTALLINE( + "Crystalline", 50, - { level -> (level + 1.0).pow(3.2) }, - { level -> mapOf(HotmReward.UNKNOWN to 1.0 * level) }, + { level -> (level + 1.0).pow(3.3) }, + { level -> mapOf(HotmReward.UNKNOWN to 0.5 * level) }, ), - GIFTS_FROM_THE_DEPARTED( "Gifts from the Departed", 100, { level -> (level + 1.0).pow(2.45) }, { level -> mapOf(HotmReward.UNKNOWN to 0.2 * level) }, ), - - EXCAVATOR( - "Excavator", + MINING_MASTER( + "Mining Master", + 10, + { level -> (level + 7.0).pow(5.0) }, + { level -> mapOf(HotmReward.PRISTINE to 0.1 * level) }, + ), + DEAD_MANS_CHEST( + "Dead Man's Chest", 50, - { level -> (level + 1.0).pow(3) }, - { level -> mapOf(HotmReward.UNKNOWN to 0.5 * level) }, + { level -> (level + 1.0).pow(3.2) }, + { level -> mapOf(HotmReward.UNKNOWN to 1.0 * level) }, ), - RAGS_TO_RICHES( - "Rags to Riches", + VANGUARD_SEEKER( + "Vanguard Seeker", 50, - { level -> (level + 1.0).pow(3.05) }, - { level -> mapOf(HotmReward.MINING_FORTUNE to 2.0 * level) }, + { level -> (level + 1.0).pow(3.1) }, + { level -> mapOf(HotmReward.UNKNOWN to 1.0 * level) }, ), - KEEN_EYE("Keen Eye", 1, { null }, { emptyMap() }), MINESHAFT_MAYHEM("Mineshaft Mayhem", 1, { null }, { emptyMap() }), - FROZEN_SOLID("Frozen Solid", 1, { null }, { emptyMap() }), GEMSTONE_INFUSION("Gemstone Infusion", 1, { null }, { emptyMap() }), - HAZARDOUS_MINER("Hazardous Miner", 1, { null }, { emptyMap() }), - + MINERS_BLESSING("Miner's Blessing", 1, { null }, { mapOf(HotmReward.MAGIC_FIND to 30.0) }), ; private val guiNamePattern by patternGroup.pattern("perk.name.${name.lowercase().replace("_", "")}", "§.$guiName") - val printName = name.allLettersFirstUppercase() + val printName get() = name.allLettersFirstUppercase() /** Level which are actually paid with powder (does exclude [blueEgg])*/ var rawLevel: Int @@ -367,15 +382,15 @@ enum class HotmData( /** Level for which the effect that is present (considers [enabled] and [blueEgg])*/ val activeLevel: Int - get() = if (enabled) effectivLevel else 0 + get() = if (enabled) effectiveLevel else 0 /** Level that considering [blueEgg]*/ - val effectivLevel: Int get() = storage?.perks?.get(this.name)?.level?.plus(blueEgg()) ?: 0 + val effectiveLevel: Int get() = storage?.perks?.get(this.name)?.level?.plus(blueEgg()) ?: 0 val isMaxLevel: Boolean - get() = effectivLevel >= maxLevel // >= to account for +1 from Blue Cheese + get() = effectiveLevel >= maxLevel // >= to account for +1 from Blue Cheese - private fun blueEgg() = if (this != PEAK_OF_THE_MOUNTAIN && maxLevel != 1 && HotmAPI.isBlueEggActive) 1 else 0 + private fun blueEgg() = if (this != CORE_OF_THE_MOUNTAIN && maxLevel != 1 && HotmAPI.isBlueEggActive) 1 else 0 var enabled: Boolean get() = storage?.perks?.get(this.name)?.enabled ?: false @@ -406,7 +421,7 @@ enum class HotmData( val storage get() = ProfileStorageData.profileSpecific?.mining?.hotmTree - val abilities = listOf(PICKOBULUS, MINING_SPEED_BOOST, VEIN_SEEKER, MANIAC_MINER, HAZARDOUS_MINER, GEMSTONE_INFUSION) + val abilities = listOf(PICKOBULUS, MINING_SPEED_BOOST, MANIAC_MINER, GEMSTONE_INFUSION, ANOMALOUS_DESIRE, SHEER_FORCE) private val inventoryPattern by patternGroup.pattern( "inventory", @@ -514,10 +529,10 @@ enum class HotmData( HotmAPI.MayhemPerk.entries.forEach { it.chatPattern } - (0..PEAK_OF_THE_MOUNTAIN.maxLevel).forEach { level -> + (0..CORE_OF_THE_MOUNTAIN.maxLevel).forEach { level -> val map = mutableMapOf() if (level >= 1) map.addOrPut(HotmReward.EXTRA_TOKENS, 1.0) - if (level >= 2) map.addOrPut(HotmReward.EXTRA_FORGE_SLOTS, 1.0) + if (level >= 2) map.addOrPut(HotmReward.ABILITY_LEVEL, 1.0) if (level >= 3) map.addOrPut(HotmReward.EXTRA_COMMISSION_SLOTS, 1.0) if (level >= 4) map.addOrPut(HotmReward.MORE_BASE_MITHRIL_POWER, 1.0) if (level >= 5) map.addOrPut(HotmReward.EXTRA_TOKENS, 1.0) @@ -527,7 +542,7 @@ enum class HotmData( if (level >= 9) map.addOrPut(HotmReward.MINESHAFT_CHANCE, 10.0) if (level >= 10) map.addOrPut(HotmReward.EXTRA_TOKENS, 2.0) - peakOfTheMountainPerks[level] = map + coreOfTheMountainPerks[level] = map } } @@ -551,7 +566,7 @@ enum class HotmData( val lore = item.getLore().takeIf { it.isNotEmpty() } ?: return - if (entry != PEAK_OF_THE_MOUNTAIN && notUnlockedPattern.matches(lore.last())) { + if (entry != CORE_OF_THE_MOUNTAIN && notUnlockedPattern.matches(lore.last())) { entry.rawLevel = 0 entry.enabled = false entry.isUnlocked = false @@ -574,7 +589,7 @@ enum class HotmData( ) } - if (entry == PEAK_OF_THE_MOUNTAIN) { + if (entry == CORE_OF_THE_MOUNTAIN) { entry.enabled = entry.rawLevel != 0 return } @@ -663,7 +678,7 @@ enum class HotmData( fun onScoreboardUpdate(event: ScoreboardUpdateEvent) { if (!LorenzUtils.inSkyBlock) return - event.scoreboard.matchFirst(ScoreboardPattern.powderPattern) { + ScoreboardPattern.powderPattern.firstMatcher(event.scoreboard) { val type = HotmAPI.PowderType.entries.firstOrNull { it.displayName == group("type") } ?: return val amount = group("amount").formatLong() val difference = amount - type.getCurrent() @@ -690,7 +705,7 @@ enum class HotmData( DelayedRun.runNextTick { InventoryUtils.getItemsInOpenChest().forEach { it.parse() } abilities.filter { it.isUnlocked }.forEach { - it.rawLevel = if (PEAK_OF_THE_MOUNTAIN.rawLevel >= 1) 2 else 1 + it.rawLevel = if (CORE_OF_THE_MOUNTAIN.rawLevel >= 1) 2 else 1 } } } @@ -791,7 +806,7 @@ enum class HotmData( } } -private val peakOfTheMountainPerks = mutableMapOf>() +private val coreOfTheMountainPerks = mutableMapOf>() private val patternGroup = RepoPattern.group("mining.hotm") @@ -801,7 +816,6 @@ enum class HotmReward { MINING_WISDOM, FORGE_TIME_DECREASE, TITANIUM_CHANCE, - DAILY_POWDER, MORE_BASE_MITHRIL_POWER, MORE_BASE_GEMSTONE_POWER, MORE_BASE_GLACITE_POWER, @@ -811,17 +825,26 @@ enum class HotmReward { CHANCE_OF_TREASURE_CHEST, LOCKS_OF_TREASURE_CHEST, EXTRA_CHANCE_TRIGGER_RARE_OCCURRENCES, - AVERAGE_BLOCK_BREAKS, - CHANCE_EXTRA_XP_ORBS, MINING_SPEED_BOOST, ABILITY_DURATION, ABILITY_RADIUS, ABILITY_COOLDOWN, - FOSSIL_DUST, + ABILITY_LEVEL, MINESHAFT_CHANCE, EXTRA_TOKENS, - EXTRA_FORGE_SLOTS, EXTRA_COMMISSION_SLOTS, UNKNOWN, - COLD_RESISTANCE + COLD_RESISTANCE, + MINING_SPREAD, + GEMSTONE_SPREAD, + ORE_FORTUNE, + BLOCK_FORTUNE, + GEMSTONE_FORTUNE, + DWARVEN_METAL_FORTUNE, + HEAT_RESISTANCE, + MAGIC_FIND, + PRISTINE, + FISHING_SPEED, + SEA_CREATURE_CHANCE, + BREAKING_POWER, } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index 0cd806f577c7..b48805ef5bf5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -13,6 +13,7 @@ import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.events.ScoreboardUpdateEvent import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.events.minecraft.ClientDisconnectEvent +import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent import at.hannibal2.skyhanni.features.bingo.BingoAPI import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.rift.RiftAPI @@ -319,8 +320,13 @@ object HypixelData { loop@ for (line in ScoreboardData.sidebarLinesFormatted) { skyblockAreaPattern.matchMatcher(line) { val originalLocation = group("area").removeColor() - skyBlockArea = LocationFixData.fixLocation(skyBlockIsland) ?: originalLocation + val area = LocationFixData.fixLocation(skyBlockIsland) ?: originalLocation skyBlockAreaWithSymbol = line.trim() + if (area != skyBlockArea) { + val previousArea = skyBlockArea + skyBlockArea = area + ScoreboardAreaChangeEvent(area, previousArea).post() + } break@loop } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt index 02a065abe63a..1f8e45afb749 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/IslandGraphs.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.model.Graph import at.hannibal2.skyhanni.data.model.GraphNode import at.hannibal2.skyhanni.data.model.findShortestPathAsGraphWithDistance @@ -10,45 +11,53 @@ import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent import at.hannibal2.skyhanni.features.misc.IslandAreas import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.SkyHanniDebugsAndTests +import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.LocationUtils import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen import at.hannibal2.skyhanni.utils.LocationUtils.distanceSqToPlayer import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine import at.hannibal2.skyhanni.utils.RenderUtils.draw3DPathWithWaypoint import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.awt.Color import java.io.File import kotlin.math.abs +import kotlin.time.Duration.Companion.milliseconds /** * TODO * benefits of every island graphs: * global: * NEU's fairy souls - * point of interest - * slayer area - * NEU's NPC's + * slayer area (not all there yet) + * NEU's NPC's (auto acitvate when searching via neu) * races (end, park, winter, dungeon hub) * jump pads between servers * ring of love/romeo juliet quest * death location + * % of island discvovered (every node was most closest node at least once) * hub: * 12 starter NPC's * diana * farming: - * pelt farming + * pelt farming area * rift: - * enigma souls * eyes * big quests + * montezuma souls + * blood effigies + * avoid area around enderman * spider: * relicts + throw spot * dwarven mines: @@ -56,7 +65,7 @@ import kotlin.math.abs * commssion areas * events: raffle, goblin slayer, donpieresso * deep - * path to the bottom + * path to the bottom (Rhys NPC) * end * golem spawn * dragon death spot @@ -65,8 +74,17 @@ import kotlin.math.abs * area mini bosses * daily quests * intro tutorials with elle + * fishing spots + * mineshaft + * different types mapped out + * paths to ladder and possible corpse locations, and known corpse locations * - * graph todo: + * Additional global things: + * use custom graphs for your island/garden + * suggest using warp points if closer + * support cross island paths (have a list of all node names in all islands) + * + * Changes in graph editor: * fix rename not using tick but input event we have (+ create the input event in the first place) * toggle distance to node by node path lengh, instead of eye of sight lenght * press test button again to enable "true test mode", with graph math and hiding other stuff @@ -94,26 +112,73 @@ object IslandGraphs { private var fastestPath: Graph? = null private var condition: () -> Boolean = { true } + private var inGlaciteTunnels: Boolean? = null + + private val patternGroup = RepoPattern.group("data.island.navigation") + + /** + * REGEX-TEST: Dwarven Base Camp + * REGEX-TEST: Forge + * REGEX-TEST: Fossil Research Center + */ + private val glaciteTunnelsPattern by patternGroup.pattern( + "glacitetunnels", + "(Glacite Tunnels|Dwarven Base Camp|Great Glacite Lake|Fossil Research Center)", + ) @SubscribeEvent fun onRepoReload(event: RepositoryReloadEvent) { if (!LorenzUtils.inSkyBlock) return - reloadFromJson(LorenzUtils.skyBlockIsland) + loadIsland(LorenzUtils.skyBlockIsland) } @SubscribeEvent fun onIslandChange(event: IslandChangeEvent) { - reloadFromJson(event.newIsland) + if (currentIslandGraph != null) return + if (event.newIsland == IslandType.NONE) return + loadIsland(event.newIsland) } @SubscribeEvent fun onWorldChange(event: LorenzWorldChangeEvent) { + currentIslandGraph = null reset() } - private fun reloadFromJson(newIsland: IslandType) { - val islandName = newIsland.name + fun isGlaciteTunnelsArea(area: String?): Boolean = glaciteTunnelsPattern.matches(area) + + @HandleEvent + fun onAreaChange(event: ScoreboardAreaChangeEvent) { + if (!IslandType.DWARVEN_MINES.isInIsland()) { + inGlaciteTunnels = null + return + } + + val now = isGlaciteTunnelsArea(LorenzUtils.skyBlockArea) + if (inGlaciteTunnels != now) { + inGlaciteTunnels = now + loadDwarvenMines() + } + } + + private fun loadDwarvenMines() { + if (isGlaciteTunnelsArea(LorenzUtils.skyBlockArea)) { + reloadFromJson("GLACITE_TUNNELS") + } else { + reloadFromJson("DWARVEN_MINES") + } + } + + private fun loadIsland(newIsland: IslandType) { + if (newIsland == IslandType.DWARVEN_MINES) { + loadDwarvenMines() + } else { + reloadFromJson(newIsland.name) + } + } + + private fun reloadFromJson(islandName: String) { val constant = "island_graphs/$islandName" val name = "constants/$constant.json" val jsonFile = File(SkyHanniMod.repo.repoLocation, name) @@ -127,8 +192,16 @@ object IslandGraphs { } fun setNewGraph(graph: Graph) { + IslandAreas.display = null reset() currentIslandGraph = graph + + // calling various update functions to make swtiching between deep caverns and glacite tunnels bareable + handleTick() + IslandAreas.noteMoved() + DelayedRun.runDelayed(150.milliseconds) { + IslandAreas.updatePosition() + } } private fun reset() { @@ -141,6 +214,10 @@ object IslandGraphs { @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!LorenzUtils.inSkyBlock) return + handleTick() + } + + private fun handleTick() { val prevClosed = closedNote val graph = currentIslandGraph ?: return @@ -287,8 +364,7 @@ object IslandGraphs { val nodes = graph.nodes val potentialSkip = - nodes.lastOrNull { it.position.canBeSeen(maxSkipDistance, -1.0) && abs(it.position.y - playerY) <= 2 } - ?: return null + nodes.lastOrNull { it.position.canBeSeen(maxSkipDistance, -1.0) && abs(it.position.y - playerY) <= 2 } ?: return null val angleSkip = if (potentialSkip == nodes.first()) { false diff --git a/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt b/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt index 129e1cd956ec..20dfbb615722 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/LocationFixData.kt @@ -11,9 +11,9 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object LocationFixData { - private var locationFixes = mutableListOf() + private var locationFixes = mutableMapOf>() - class LocationFix(val island: IslandType, val area: AxisAlignedBB, val realLocation: String) + private data class LocationFix(val area: AxisAlignedBB, val realLocation: String) // priority set to low so that IslandType can load their island names from repo earlier @SubscribeEvent(priority = EventPriority.LOW) @@ -26,11 +26,18 @@ object LocationFixData { val area = fix.a.axisAlignedTo(fix.b) val realLocation = fix.realLocation - locationFixes.add(LocationFix(island, area, realLocation)) + val list = locationFixes[island] + + val locationFix = LocationFix(area, realLocation) + + if (list == null) locationFixes[island] = listOf(locationFix) + else locationFixes[island] = list + locationFix } } - fun fixLocation(skyBlockIsland: IslandType) = locationFixes - .firstOrNull { skyBlockIsland == it.island && it.area.isPlayerInside() } - ?.realLocation + fun fixLocation(skyBlockIsland: IslandType): String? = + locationFixes[skyBlockIsland] + ?.find { it.area.isPlayerInside() } + ?.realLocation + } diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt index b4fb7eaa2dc8..469c48489245 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt @@ -16,7 +16,7 @@ import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.SecondPassedEvent import at.hannibal2.skyhanni.features.fame.ReminderUtils import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter import at.hannibal2.skyhanni.utils.CollectionUtils.put @@ -216,7 +216,7 @@ object MayorAPI { SkyHanniMod.coroutineScope.launch { val url = "https://api.hypixel.net/v2/resources/skyblock/election" - val jsonObject = withContext(dispatcher) { APIUtil.getJSONResponse(url) } + val jsonObject = withContext(dispatcher) { APIUtils.getJSONResponse(url) } rawMayorData = ConfigManager.gson.fromJson(jsonObject) val data = rawMayorData ?: return@launch val map = mutableMapOf() diff --git a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt index 78647944c9a0..335648dc5116 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt @@ -146,6 +146,7 @@ enum class Mayor( fun Mayor.addPerks(perks: List) { perks.forEach { it.isActive = false } + activePerks.forEach { it.isActive = false } activePerks.clear() for (perk in perks.filter { perks.contains(it) }) { perk.isActive = true diff --git a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt index ecf90172dc79..9d635b1b9a22 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt @@ -1,8 +1,10 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.events.BlockClickEvent import at.hannibal2.skyhanni.events.ColdUpdateEvent import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent @@ -11,8 +13,10 @@ import at.hannibal2.skyhanni.events.ScoreboardUpdateEvent import at.hannibal2.skyhanni.events.ServerBlockChangeEvent import at.hannibal2.skyhanni.events.mining.OreMinedEvent import at.hannibal2.skyhanni.events.player.PlayerDeathEvent +import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern import at.hannibal2.skyhanni.features.mining.OreBlock +import at.hannibal2.skyhanni.features.mining.isTitanium import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.countBy import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer @@ -20,7 +24,9 @@ import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.inAnyIsland import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.TimeUtils.format @@ -37,27 +43,71 @@ import kotlin.time.Duration.Companion.seconds object MiningAPI { private val group = RepoPattern.group("data.miningapi") - private val glaciteAreaPattern by group.pattern("area.glacite", "Glacite Tunnels|Glacite Lake") + private val glaciteAreaPattern by group.pattern("area.glacite", "Glacite Tunnels|Great Glacite Lake") private val dwarvenBaseCampPattern by group.pattern("area.basecamp", "Dwarven Base Camp") - // TODO rename to include suffix "pattern", add regex test - private val coldReset by group.pattern( + // TODO add regex test + private val coldResetPattern by group.pattern( "cold.reset", - "§6The warmth of the campfire reduced your §r§b❄ Cold §r§6to §r§a0§r§6!|§c ☠ §r§7You froze to death§r§7.", + "§6The warmth of the campfire reduced your §r§b❄ Cold §r§6to §r§a0§r§6!|§c ☠ §r§7You froze to death§r§7\\.", ) - private data class MinedBlock(val ore: OreBlock, var confirmed: Boolean, val time: SimpleTimeMark = SimpleTimeMark.now()) + private val pickbobulusGroup = group.group("pickobulus") + + /** + * REGEX-TEST: §aYou used your §r§6Pickobulus §r§aPickaxe Ability! + */ + + private val pickobulusUsePattern by pickbobulusGroup.pattern( + "use", + "§aYou used your §r§6Pickobulus §r§aPickaxe Ability!", + ) + + // TODO add regex test + private val pickobulusEndPattern by pickbobulusGroup.pattern( + "end", + "§7Your §r§aPickobulus §r§7destroyed §r§e(?[\\d,.]+) §r§7blocks!", + ) + + /** + * REGEX-TEST: §7Your §r§aPickobulus §r§7didn't destroy any blocks! + */ + private val pickobulusFailPattern by pickbobulusGroup.pattern( + "fail", + "§7Your §r§aPickobulus §r§7didn't destroy any blocks!" + ) + + private data class MinedBlock(val ore: OreBlock, var confirmed: Boolean) { + val time: SimpleTimeMark = SimpleTimeMark.now() + } + + // normal mining + private val recentClickedBlocks = ConcurrentSet>() + private val surroundingMinedBlocks = ConcurrentLinkedQueue>() private var lastInitSound = SimpleTimeMark.farPast() - private var waitingForInitBlock = false - private var waitingForInitBlockPos: LorenzVec? = null + private var initBlockPos: LorenzVec? = null private var waitingForInitSound = true private var waitingForEffMinerSound = false private var waitingForEffMinerBlock = false + // pickobulus + private var lastPickobulusUse = SimpleTimeMark.farPast() + private var lastPickobulusExplosion = SimpleTimeMark.farPast() + private var pickobulusExplosionPos: LorenzVec? = null + private val pickobulusMinedBlocks = ConcurrentLinkedQueue>() + + private val pickobulusActive get() = lastPickobulusUse.passedSince() < 2.seconds + + private var pickobulusWaitingForSound = false + private var pickobulusWaitingForBlock = false + + // oreblock data var inGlacite = false + var inTunnels = false + var inMineshaft = false var inDwarvenMines = false var inCrystalHollows = false var inCrimsonIsle = false @@ -65,18 +115,17 @@ object MiningAPI { var inSpidersDen = false var currentAreaOreBlocks = setOf() + private set - private var lastSkyblockArea: String? = null - - private val recentClickedBlocks = ConcurrentSet>() - private val surroundingMinedBlocks = ConcurrentLinkedQueue>() - private val allowedSoundNames = listOf("dig.glass", "dig.stone", "dig.gravel", "dig.cloth", "random.orb") + private val allowedSoundNames = setOf("dig.glass", "dig.stone", "dig.gravel", "dig.cloth", "random.orb") var cold: Int = 0 private set var lastColdUpdate = SimpleTimeMark.farPast() + private set var lastColdReset = SimpleTimeMark.farPast() + private set fun inGlaciteArea() = inGlacialTunnels() || IslandType.MINESHAFT.isInIsland() @@ -116,6 +165,7 @@ object MiningAPI { fun onBlockClick(event: BlockClickEvent) { if (!inCustomMiningIsland()) return if (event.clickType != ClickType.LEFT_CLICK) return + //println(event.getBlockState.properties) if (OreBlock.getByStateOrNull(event.getBlockState) == null) return recentClickedBlocks += event.position to SimpleTimeMark.now() } @@ -123,10 +173,29 @@ object MiningAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (!inColdIsland()) return - if (coldReset.matches(event.message)) { + if (coldResetPattern.matches(event.message)) { updateCold(0) lastColdReset = SimpleTimeMark.now() + return } + if (pickobulusUsePattern.matches(event.message)) { + lastPickobulusUse = SimpleTimeMark.now() + return + } + if (pickobulusFailPattern.matches(event.message)) { + resetPickobulusEvent() + pickobulusMinedBlocks.clear() + return + } + pickobulusEndPattern.matchMatcher(event.message) { + val amount = group("amount").formatInt() + resetPickobulusEvent() + val blocks = pickobulusMinedBlocks.take(amount).countBy { it.second } + if (blocks.isNotEmpty()) OreMinedEvent(null, blocks).post() + pickobulusMinedBlocks.clear() + return + } + } @SubscribeEvent @@ -140,14 +209,25 @@ object MiningAPI { @SubscribeEvent fun onPlaySound(event: PlaySoundEvent) { if (!inCustomMiningIsland()) return + if (event.soundName == "random.explode" && lastPickobulusUse.passedSince() < 5.seconds) { + lastPickobulusExplosion = SimpleTimeMark.now() + pickobulusExplosionPos = event.location + pickobulusWaitingForSound = true + return + } if (event.soundName !in allowedSoundNames) return + if (pickobulusActive && pickobulusWaitingForSound) { + pickobulusWaitingForSound = false + pickobulusWaitingForBlock = true + return + } if (waitingForInitSound) { if (event.soundName != "random.orb" && event.pitch == 0.7936508f) { val pos = event.location.roundLocationToBlock() if (recentClickedBlocks.none { it.first == pos }) return waitingForInitSound = false - waitingForInitBlock = true - waitingForInitBlockPos = event.location.roundLocationToBlock() + waitingForEffMinerBlock = true + initBlockPos = event.location.roundLocationToBlock() lastInitSound = SimpleTimeMark.now() } return @@ -164,21 +244,35 @@ object MiningAPI { @SubscribeEvent fun onBlockChange(event: ServerBlockChangeEvent) { if (!inCustomMiningIsland()) return - if (event.newState.block.let { it != Blocks.air && it != Blocks.bedrock }) return - if (event.oldState.block.let { it == Blocks.air || it == Blocks.bedrock }) return - if (event.oldState.block == Blocks.air) return + val oldState = event.oldState + val newState = event.newState + val oldBlock = oldState.block + val newBlock = newState.block + + if (oldState == newState) return + if (oldBlock == Blocks.air || oldBlock == Blocks.bedrock) return + if (newBlock != Blocks.air && newBlock != Blocks.bedrock && !isTitanium(newState)) return + val pos = event.location - if (pos.distanceToPlayer() > 7) return + if (pickobulusActive && pickobulusWaitingForBlock) { + val explosionPos = pickobulusExplosionPos ?: return + if (explosionPos.distance(pos) > 15) return + val ore = OreBlock.getByStateOrNull(oldState) ?: return + if (pickobulusMinedBlocks.any { it.first == pos }) return + pickobulusMinedBlocks += pos to ore + pickobulusWaitingForBlock = false + pickobulusWaitingForSound = true + return + } if (lastInitSound.passedSince() > 100.milliseconds) return + if (pos.distanceToPlayer() > 7) return - val ore = OreBlock.getByStateOrNull(event.oldState) ?: return + val ore = OreBlock.getByStateOrNull(oldState) ?: return - if (waitingForInitBlock) { - if (waitingForInitBlockPos != pos) return - waitingForInitBlock = false + if (initBlockPos == pos) { surroundingMinedBlocks += MinedBlock(ore, true) to pos - waitingForEffMinerBlock = true + runEvent() return } if (waitingForEffMinerBlock) { @@ -193,19 +287,33 @@ object MiningAPI { @SubscribeEvent fun onTick(event: LorenzTickEvent) { if (!inCustomMiningIsland()) return - - if (LorenzUtils.lastWorldSwitch.passedSince() < 4.seconds) return - updateLocation() - if (currentAreaOreBlocks.isEmpty()) return // if somehow you take more than 20 seconds to mine a single block, congrats recentClickedBlocks.removeIf { it.second.passedSince() >= 20.seconds } surroundingMinedBlocks.removeIf { it.first.time.passedSince() >= 20.seconds } - if (waitingForInitSound) return - if (lastInitSound.passedSince() < 200.milliseconds) return + if (!waitingForInitSound && lastInitSound.passedSince() > 200.milliseconds) { + resetOreEvent() + } + if (!lastPickobulusUse.isFarPast() && lastPickobulusUse.passedSince() > 5.seconds) { + resetPickobulusEvent() + pickobulusMinedBlocks.clear() + } + } + + @HandleEvent + fun onAreaChange(event: ScoreboardAreaChangeEvent) { + if (!inCustomMiningIsland()) return + updateLocation() + } + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + updateLocation() + } + + private fun runEvent() { resetOreEvent() if (surroundingMinedBlocks.isEmpty()) return @@ -230,19 +338,28 @@ object MiningAPI { lastColdReset = SimpleTimeMark.now() recentClickedBlocks.clear() surroundingMinedBlocks.clear() + pickobulusMinedBlocks.clear() currentAreaOreBlocks = setOf() resetOreEvent() + resetPickobulusEvent() } private fun resetOreEvent() { lastInitSound = SimpleTimeMark.farPast() waitingForInitSound = true - waitingForInitBlock = false - waitingForInitBlockPos = null + initBlockPos = null waitingForEffMinerSound = false waitingForEffMinerBlock = false } + private fun resetPickobulusEvent() { + lastPickobulusUse = SimpleTimeMark.farPast() + lastPickobulusExplosion = SimpleTimeMark.farPast() + pickobulusExplosionPos = null + pickobulusWaitingForSound = false + pickobulusWaitingForBlock = false + } + @SubscribeEvent fun onDebugDataCollect(event: DebugDataCollectEvent) { event.title("Mining API") @@ -258,8 +375,7 @@ object MiningAPI { add("lastInitSound: ${lastInitSound.passedSince().format()}") } add("waitingForInitSound: $waitingForInitSound") - add("waitingForInitBlock: $waitingForInitBlock") - add("waitingForInitBlockPos: $waitingForInitBlockPos") + add("waitingForInitBlockPos: $initBlockPos") add("waitingForEffMinerSound: $waitingForEffMinerSound") add("waitingForEffMinerBlock: $waitingForEffMinerBlock") add("recentlyClickedBlocks: ${recentClickedBlocks.joinToString { "(${it.first.toCleanString()}" }}") @@ -275,12 +391,9 @@ object MiningAPI { } private fun updateLocation() { - val currentArea = LorenzUtils.skyBlockArea - // TODO add area change event with HypixelData.skyBlockArea instead - if (currentArea == lastSkyblockArea) return - lastSkyblockArea = currentArea - inGlacite = inGlaciteArea() + inTunnels = inGlacialTunnels() + inMineshaft = inMineshaft() inDwarvenMines = inRegularDwarven() inCrystalHollows = inCrystalHollows() inCrimsonIsle = IslandType.CRIMSON_ISLE.isInIsland() diff --git a/src/main/java/at/hannibal2/skyhanni/data/OtherPlayersSlayerAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/OtherPlayersSlayerAPI.kt new file mode 100644 index 000000000000..0401746c4edb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/OtherPlayersSlayerAPI.kt @@ -0,0 +1,36 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.mob.Mob +import at.hannibal2.skyhanni.events.MobEvent +import at.hannibal2.skyhanni.events.entity.slayer.SlayerDeathEvent +import at.hannibal2.skyhanni.features.slayer.SlayerType +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object OtherPlayersSlayerAPI { + + @SubscribeEvent + fun onMobDespawn(event: MobEvent.DeSpawn.SkyblockMob) { + val mob = event.mob + + // no death, rather despawn because too far away + if (mob.baseEntity.health != 0f) return + + if (mob.mobType != Mob.Type.SLAYER) return + + val owner = mob.owner?.ownerName + val tier = mob.levelOrTier + val name = mob.name + val slayerType = SlayerType.getByName(name) ?: run { + ErrorManager.logErrorStateWithData( + "Unknown slayer type found", "unknown slayer", + "name" to name, + ) + return + } + + SlayerDeathEvent(slayerType, tier, owner).post() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt index 88daf40b9520..2f516610ca51 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt @@ -16,10 +16,10 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getItemCategoryOrNull import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getExtraAttributes @@ -236,7 +236,7 @@ object QuiverAPI { } } - fun Int.asArrowPercentage() = ((this.toFloat() / MAX_ARROW_AMOUNT) * 100).round(1) + fun Int.asArrowPercentage() = ((this.toFloat() / MAX_ARROW_AMOUNT) * 100).roundTo(1) fun hasBowInInventory() = hasBow diff --git a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt index 378fe03c6953..a8cafcf3d981 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/ScoreboardData.kt @@ -51,16 +51,13 @@ object ScoreboardData { val lastColor = start.lastColorCode() ?: "" // Generate the list of color suffixes - val colorSuffixes = generateSequence(lastColor) { it.dropLast(2) } - .takeWhile { it.isNotEmpty() } - .toMutableList() + val colorSuffixes = lastColor.chunked(2).toMutableList() // Iterate through the colorSuffixes to remove matching prefixes from 'end' for (suffix in colorSuffixes.toList()) { if (end.startsWith(suffix)) { end = end.removePrefix(suffix) colorSuffixes.remove(suffix) - break } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt index 29a16944c3d3..13044b7c3151 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/bazaar/HypixelBazaarFetcher.kt @@ -6,7 +6,7 @@ import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.features.inventory.bazaar.BazaarData import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzUtils @@ -46,7 +46,7 @@ object HypixelBazaarFetcher { val fetchType = if (nextFetchIsManual) "manual" else "automatic" nextFetchIsManual = false try { - val jsonResponse = withContext(Dispatchers.IO) { APIUtil.getJSONResponse(URL) }.asJsonObject + val jsonResponse = withContext(Dispatchers.IO) { APIUtils.getJSONResponse(URL) }.asJsonObject val response = ConfigManager.gson.fromJson(jsonResponse) if (response.success) { latestProductInformation = process(response.products) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/CarryTrackerJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/CarryTrackerJson.kt new file mode 100644 index 000000000000..1819b36b9517 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/CarryTrackerJson.kt @@ -0,0 +1,8 @@ +package at.hannibal2.skyhanni.data.jsonobjects.repo + +import com.google.gson.annotations.Expose +import com.google.gson.annotations.SerializedName + +data class CarryTrackerJson( + @Expose @SerializedName("slayer_names") val slayerNames: Map>, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt index 4ad81b06a663..ead4eb83c298 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/HoppityEggLocationsJson.kt @@ -23,6 +23,13 @@ data class HoppityEggLocationsJson( @Expose val maxRabbits: Int, @Expose val maxPrestige: Int, @Expose val chocolateMilestones: TreeSet, + @Expose val chocolateShopMilestones: List, + @Expose val chocolateFactoryMilestones: List, @Expose val apiEggLocations: Map>, @Expose val specialRabbits: List, ) + +data class MilestoneJson( + @Expose val amount: Long, + @Expose val rabbit: String, +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt index 8c63be891fb3..bc4be57a16d4 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/Graph.kt @@ -1,7 +1,7 @@ package at.hannibal2.skyhanni.data.model -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.json.SkyHanniTypeAdapters.registerTypeAdapter import at.hannibal2.skyhanni.utils.json.fromJson import com.google.gson.GsonBuilder @@ -10,6 +10,7 @@ import com.google.gson.annotations.Expose import com.google.gson.stream.JsonToken import java.util.PriorityQueue +// TODO: This class should be disambiguated into a NodePath and a Graph class @JvmInline value class Graph( @Expose val nodes: List, @@ -49,7 +50,7 @@ value class Graph( out.name("Name").value(it) } - it.tagNames?.takeIf { it.isNotEmpty() }?.let { + it.tagNames.takeIf { list -> list.isNotEmpty() }?.let { out.name("Tags") out.beginArray() for (tagName in it) { @@ -62,7 +63,7 @@ value class Graph( out.beginObject() for ((node, weight) in it.neighbours) { val id = node.id.toString() - out.name(id).value(weight.round(2)) + out.name(id).value(weight.roundTo(2)) } out.endObject() @@ -79,8 +80,8 @@ value class Graph( reader.beginObject() var position: LorenzVec? = null var name: String? = null - var tags: List? = null - var neighbors = mutableListOf>() + var tags = emptyList() + val neighbors = mutableListOf>() while (reader.hasNext()) { if (reader.peek() != JsonToken.NAME) { reader.skipValue() @@ -140,10 +141,10 @@ value class Graph( } // The node object that gets parsed from/to json -class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, val tagNames: List? = null) { +class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, val tagNames: List = emptyList()) { val tags: List by lazy { - tagNames?.mapNotNull { GraphNodeTag.byId(it) } ?: emptyList() + tagNames.mapNotNull { GraphNodeTag.byId(it) } } /** Keys are the neighbours and value the edge weight (e.g. Distance) */ @@ -167,18 +168,50 @@ class GraphNode(val id: Int, val position: LorenzVec, val name: String? = null, fun Graph.findShortestPathAsGraph(start: GraphNode, end: GraphNode): Graph = this.findShortestPathAsGraphWithDistance(start, end).first -fun Graph.findShortestPathAsGraphWithDistance(start: GraphNode, end: GraphNode): Pair { +data class DijkstraTree( + val origin: GraphNode, + /** + * A map of distances between the [origin] and each node in a graph. This distance map is only accurate for nodes closer to the + * origin than the [lastVisitedNode]. In case there is no early bailout, this map will be accurate for all nodes in the graph. + */ + val distances: Map, + /** + * A map of nodes to the neighbouring node that is the quickest path towards the origin (the neighbouring node that has the lowest value + * in [distances]) + */ + val towardsOrigin: Map, + /** + * This is either the furthest away node in the graph, or the node that was bailed out on early because it fulfilled the search + * condition. In case the search condition matches nothing, this will *still* be the furthest away node, so an additional check might be + * necessary. + */ + val lastVisitedNode: GraphNode, +) + +/** + * Find a tree of distances to the [start] node using dijkstra's algorithm. + */ +fun Graph.findDijkstraDistances( + start: GraphNode, + /** + * Bail out early before collecting all the distances to all nodes in the graph. This will not collect valid distance data for *all* + * nodes for which bailout matches, but only the closest one. + */ + bailout: (GraphNode) -> Boolean, +): DijkstraTree { val distances = mutableMapOf() val previous = mutableMapOf() val visited = mutableSetOf() val queue = PriorityQueue(compareBy { distances.getOrDefault(it, Double.MAX_VALUE) }) + var lastVisitedNode: GraphNode = start distances[start] = 0.0 queue.add(start) while (queue.isNotEmpty()) { val current = queue.poll() - if (current == end) break + lastVisitedNode = current + if (bailout(current)) break visited.add(current) @@ -194,16 +227,34 @@ fun Graph.findShortestPathAsGraphWithDistance(start: GraphNode, end: GraphNode): } } - return Graph( - buildList { - var current = end - while (current != start) { - add(current) - current = previous[current] ?: return Graph(emptyList()) to 0.0 - } - add(start) - }.reversed(), - ) to distances[end]!! + return DijkstraTree( + start, + distances, + previous, + lastVisitedNode, + ) +} + +fun Graph.findAllShortestDistances(start: GraphNode): DijkstraTree { + return findDijkstraDistances(start) { false } +} + +fun DijkstraTree.findPathToDestination(end: GraphNode): Pair { + val distances = this + val reversePath = buildList { + var current = end + while (true) { + add(current) + if (current == distances.origin) break + current = distances.towardsOrigin[current] ?: return Graph(emptyList()) to 0.0 + } + } + return Graph(reversePath.reversed()) to distances.distances[end]!! +} + +fun Graph.findShortestPathAsGraphWithDistance(start: GraphNode, end: GraphNode): Pair { + val distances = findDijkstraDistances(start) { it == end } + return distances.findPathToDestination(end) } fun Graph.findShortestPath(start: GraphNode, end: GraphNode): List = this.findShortestPathAsGraph(start, end).toPositionsList() diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt b/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt index a7349801324a..6bf00edafcf6 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/GraphNodeTag.kt @@ -1,46 +1,87 @@ package at.hannibal2.skyhanni.data.model +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.utils.LorenzColor -enum class GraphNodeTag(val internalName: String?, val color: LorenzColor, val cleanName: String, val description: String) { +enum class GraphNodeTag( + val internalName: String, + val color: LorenzColor, + val cleanName: String, + val description: String, + val onlyIsland: IslandType? = null, +) { DEV("dev", LorenzColor.WHITE, "Dev", "Intentionally marked as dev."), // E.g. Spawn points, todos, etc // Everywhere - NPC("npc", LorenzColor.YELLOW, "NPC", "A NPC entity."), // also take from neu repo + NPC("npc", LorenzColor.YELLOW, "NPC", "A NPC to talk to."), // also take from neu repo AREA("area", LorenzColor.DARK_GREEN, "Area", "A big SkyBlock area."), SMALL_AREA("small_area", LorenzColor.GREEN, "Small Area", "A small SkyBlock area, e.g. a house."), - POI("poi", LorenzColor.WHITE, "PoI", "Point of interest."), - LAUNCH_PAD("launch", LorenzColor.WHITE, "Launch Pad", "Slime blocks sending you to another server."), + POI("poi", LorenzColor.WHITE, "Point of Interest", "A relevant spot or a landmark on the map."), + // LAUNCH_PAD("launch", LorenzColor.WHITE, "Launch Pad", "Slime blocks sending you to another server."), + TELEPORT("teleport", LorenzColor.BLUE, "Teleport", "A spot from/to teleport."), // on multiple islands - ROMEO("romeo", LorenzColor.WHITE, "Romeo & Juliette Quest", "Blocks related to the Romeo and Juliette/Ring of Love quest line."), + ROMEO("romeo", LorenzColor.WHITE, "Romeo & Juliette Quest", "Spots related to the Romeo and Juliette/Ring of Love quest line."), RACE("race", LorenzColor.WHITE, "Race Start/Stop", "A race start or stop point."), - SLAYER("slayer", LorenzColor.WHITE, "Slayer", "A Slayer area"), + SLAYER("slayer", LorenzColor.RED, "Slayer", "A Slayer area."), + HOPPITY("hoppity", LorenzColor.AQUA, "Hoppity Egg", "An egg location in Hoppity's Hunt."), + GRIND_MOBS("grind_mobs", LorenzColor.RED, "Mob Spawn Area", "An area where mobs spawn that can be killed."), + GRIND_ORES("grind_ores", LorenzColor.DARK_AQUA, "Ore Vein", "A regenerating ore vein that can be mined."), + GRIND_CROPS("grind_crops", LorenzColor.DARK_GREEN, "Crop Area", "An area where crops grow that can be farmed."), // hoppity // Hub - HUB_12_STARTER("starter_npc", LorenzColor.WHITE, "Starter NPC", "One of the 12 starter NPC's you need to talk to."), + HUB_12_STARTER( + "starter_npc", LorenzColor.WHITE, "Starter NPC", "One of the 12 starter NPC's you need to talk to.", + onlyIsland = IslandType.HUB, + ), // diana // Farming Islands: Pelts - FARMING_CROP("farming_crop", LorenzColor.WHITE, "Farming Crop", "A spot where you can break crops on farming islands."), +// FARMING_CROP("farming_crop", LorenzColor.WHITE, "Farming Crop", "A spot where you can break crops on farming islands."), // Rift - RIFT_ENIGMA("rift_enigma", LorenzColor.DARK_PURPLE, "Enigma Soul", "Enigma Souls in the rift."), - RIFT_EYE("rift_eye", LorenzColor.DARK_RED, "Eye", "An Eye in the rift to teleport to."), + RIFT_ENIGMA("rift_enigma", LorenzColor.DARK_PURPLE, "Enigma Soul", "Enigma Souls in the Rift.", onlyIsland = IslandType.THE_RIFT), + RIFT_EYE("rift_eye", LorenzColor.DARK_RED, "Rift Eye", "An Eye in the Rift to teleport to.", onlyIsland = IslandType.THE_RIFT), + RIFT_MONTEZUMA( + "rift_montezuma", + LorenzColor.GRAY, + "Montezuma Soul Piece", + "A piece of the Montezuma Soul.", + onlyIsland = IslandType.THE_RIFT, + ), + RIFT_EFFIGY("rift_effigy", LorenzColor.RED, "Blood Effigies", "Locations of the Blood Effigies.", onlyIsland = IslandType.THE_RIFT), // Spider's Den - SPIDER_RELIC("SPIDER_RELIC", LorenzColor.DARK_PURPLE, "Relic", "An relic in the Spider's Den."), + SPIDER_RELIC( + "SPIDER_RELIC", + LorenzColor.DARK_PURPLE, + "Spider's Relic", + "An relic in the Spider's Den.", + onlyIsland = IslandType.SPIDER_DEN, + ), // Dwarven Mines - MINES_EMISSARY("mines_emissary", LorenzColor.GOLD, "Emissary", "A Emissary from the king."), + MINES_EMISSARY("mines_emissary", LorenzColor.GOLD, "Mines Emissary", "An Emissary to the king.", onlyIsland = IslandType.DWARVEN_MINES), // commission areas + // Crimson Isles + CRIMSON_MINIBOSS( + "crimson_miniboss", + LorenzColor.RED, + "Crimson Miniboss", + "A Miniboss in the Crimson Isle.", + onlyIsland = IslandType.CRIMSON_ISLE, + ), + + // The End + END_GOLEM("end_golem", LorenzColor.RED, "Golem Spawn", "A spot where the golem can spawn in the End.", onlyIsland = IslandType.THE_END), + ; val displayName: String = color.getChatColor() + cleanName companion object { - fun byId(internalName: String?): GraphNodeTag? = values().firstOrNull { it.internalName == internalName } + fun byId(internalName: String?): GraphNodeTag? = entries.firstOrNull { it.internalName == internalName } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt b/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt index 6fd65778ecfb..f31c95958659 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/SkyblockStat.kt @@ -43,8 +43,18 @@ enum class SkyblockStat(val icon: String) { PRISTINE("§5✧"), FORAGING_FORTUNE("§☘"), FARMING_FORTUNE("§6☘"), + + MINING_SPREAD("§e▚"), MINING_FORTUNE("§6☘"), - FEAR("§a☠") + ORE_FORTUNE("§6☘"), + DWARVEN_METAL_FORTUNE("§6☘"), + BLOCK_FORTUNE("§6☘"), + GEMSTONE_FORTUNE("§6☘"), + + FEAR("§a☠"), + HEAT_RESISTANCE("§c♨"), + + UNKNOWN("§c?") ; val capitalizedName = name.lowercase().allLettersFirstUppercase() @@ -57,6 +67,10 @@ enum class SkyblockStat(val icon: String) { val fontSizeOfLargestIcon by lazy { entries.maxOf { Minecraft.getMinecraft().fontRendererObj.getStringWidth(it.icon) } + 1 } + + fun getValueOrNull(string: String): SkyblockStat? = entries.firstOrNull { it.name == string } + + fun getValue(string: String): SkyblockStat = getValueOrNull(string) ?: UNKNOWN } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt index 0646b884cdec..15fcbe8a9a62 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TextInput.kt @@ -111,7 +111,7 @@ class TextInput { } if (KeyboardManager.isPastingKeysDown()) { runBlocking { - textBox = OSUtils.readFromClipboard() ?: return@runBlocking + textBox = OSUtils.readFromClipboard()?.take(2024) ?: return@runBlocking updated() } return diff --git a/src/main/java/at/hannibal2/skyhanni/events/InventoryFullyOpenedEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/InventoryFullyOpenedEvent.kt index d786445fbf5e..5374b95d3c2e 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/InventoryFullyOpenedEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/InventoryFullyOpenedEvent.kt @@ -26,6 +26,17 @@ open class InventoryOpenEvent(private val inventory: OtherInventoryData.Inventor val fullyOpenedOnce: Boolean get() = inventory.fullyOpenedOnce } +/** + * This event is getting fired after every slot in the newly opened inventory has item data. + * + * New inventory data gets first sent as an empty inventory from the server. + * Item stack slot information is sent afterwards, sometimes with a short delay. + * + * This approach is faster than to wait a fix duration after the inventory open packet is detected. + * + * Since this logic only works via packets, and the player inventory (pressing E) is client side, + * this event does not get fired when opening the invenotory via pressingE. + */ class InventoryFullyOpenedEvent(inventory: OtherInventoryData.Inventory) : InventoryOpenEvent(inventory) class InventoryUpdatedEvent(inventory: OtherInventoryData.Inventory) : InventoryOpenEvent(inventory) diff --git a/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt index c895b1058d7c..4a294a6779ca 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/LorenzEvent.kt @@ -12,6 +12,11 @@ import at.hannibal2.skyhanni.utils.system.PlatformUtils import net.minecraftforge.common.MinecraftForge import net.minecraftforge.fml.common.eventhandler.Event import net.minecraftforge.fml.common.eventhandler.IEventListener +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +/** + * Use @[SubscribeEvent] + */ @Deprecated("Use SkyHanniEvent instead") abstract class LorenzEvent : Event() { diff --git a/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt index c2bd261ca0a1..9feb170c1f08 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/NeuRepositoryReloadEvent.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.data.repo.RepoUtils import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.NEUItems.manager import at.hannibal2.skyhanni.utils.json.fromJson +import at.hannibal2.skyhanni.utils.json.getJson import com.google.gson.Gson import com.google.gson.JsonObject import com.google.gson.JsonSyntaxException @@ -14,9 +15,7 @@ import java.io.File import java.lang.reflect.Type class NeuRepositoryReloadEvent : LorenzEvent() { - fun getConstant(file: String): JsonObject? { - return manager.getJsonFromFile(File(manager.repoLocation, "constants/$file.json")) - } + fun getConstant(file: String): JsonObject? = File(manager.repoLocation, "constants/$file.json").getJson() inline fun readConstant(file: String, gson: Gson = ConfigManager.gson): T { val data = getConstant(file) ?: ErrorManager.skyHanniError("$file failed to load from neu repo!") diff --git a/src/main/java/at/hannibal2/skyhanni/events/PlaySoundEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/PlaySoundEvent.kt index 2f793ff28860..96f228a6ba85 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/PlaySoundEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/PlaySoundEvent.kt @@ -1,8 +1,8 @@ package at.hannibal2.skyhanni.events import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import net.minecraftforge.fml.common.eventhandler.Cancelable @Cancelable @@ -11,10 +11,8 @@ class PlaySoundEvent(val soundName: String, val location: LorenzVec, val pitch: val distanceToPlayer by lazy { location.distanceToPlayer() } override fun toString(): String { - return "PlaySoundEvent(soundName='$soundName', pitch=$pitch, volume=$volume, location=${location.round(1)}, distanceToPlayer=${ - distanceToPlayer.round( - 1 - ) + return "PlaySoundEvent(soundName='$soundName', pitch=$pitch, volume=$volume, location=${location.roundTo(1)}, distanceToPlayer=${ + distanceToPlayer.roundTo(1) })" } } diff --git a/src/main/java/at/hannibal2/skyhanni/events/ReceiveParticleEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/ReceiveParticleEvent.kt index ef296326da84..75fe8af8a3c2 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/ReceiveParticleEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/ReceiveParticleEvent.kt @@ -1,8 +1,8 @@ package at.hannibal2.skyhanni.events import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import net.minecraft.util.EnumParticleTypes import net.minecraftforge.fml.common.eventhandler.Cancelable @@ -21,12 +21,12 @@ class ReceiveParticleEvent( val distanceToPlayer by lazy { location.distanceToPlayer() } override fun toString(): String { - return "ReceiveParticleEvent(type='$type', location=${location.round(1)}, count=$count, speed=$speed, offset=${ - offset.round( + return "ReceiveParticleEvent(type='$type', location=${location.roundTo(1)}, count=$count, speed=$speed, offset=${ + offset.roundTo( 1 ) }, longDistance=$longDistance, particleArgs=${particleArgs.contentToString()}, distanceToPlayer=${ - distanceToPlayer.round( + distanceToPlayer.roundTo( 1 ) })" diff --git a/src/main/java/at/hannibal2/skyhanni/events/ServerBlockChangeEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/ServerBlockChangeEvent.kt index 07aa7630ed37..106ee2821cb3 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/ServerBlockChangeEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/ServerBlockChangeEvent.kt @@ -7,7 +7,7 @@ import at.hannibal2.skyhanni.utils.toLorenzVec import net.minecraft.block.state.IBlockState import net.minecraft.util.BlockPos -class ServerBlockChangeEvent(private val blockPos: BlockPos, private val blockState: IBlockState) : LorenzEvent() { +class ServerBlockChangeEvent(blockPos: BlockPos, blockState: IBlockState) : LorenzEvent() { val location by lazy { blockPos.toLorenzVec() } val old by lazy { location.getBlockAt().toString().getName() } @@ -17,7 +17,7 @@ class ServerBlockChangeEvent(private val blockPos: BlockPos, private val blockSt companion object { - val pattern = "Block\\{minecraft:(?.*)}".toPattern() + private val pattern = "Block\\{minecraft:(?.*)}".toPattern() private fun String.getName() = pattern.matchMatcher(this) { group("name") diff --git a/src/main/java/at/hannibal2/skyhanni/events/entity/slayer/SlayerDeathEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/entity/slayer/SlayerDeathEvent.kt new file mode 100644 index 000000000000..620e4fb3e703 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/entity/slayer/SlayerDeathEvent.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.entity.slayer + +import at.hannibal2.skyhanni.api.event.SkyHanniEvent +import at.hannibal2.skyhanni.features.slayer.SlayerType + +class SlayerDeathEvent(val slayerType: SlayerType, val tier: Int, val owner: String?) : SkyHanniEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/events/hoppity/EggFoundEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/hoppity/EggFoundEvent.kt new file mode 100644 index 000000000000..2cd81811f272 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/hoppity/EggFoundEvent.kt @@ -0,0 +1,10 @@ +package at.hannibal2.skyhanni.events.hoppity + +import at.hannibal2.skyhanni.api.event.SkyHanniEvent +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType + +class EggFoundEvent( + val type: HoppityEggType, + val slotIndex: Int?, + val note: String?, +) : SkyHanniEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/events/mining/OreMinedEvent.kt b/src/main/java/at/hannibal2/skyhanni/events/mining/OreMinedEvent.kt index a97402a4179a..d74e65eced2a 100644 --- a/src/main/java/at/hannibal2/skyhanni/events/mining/OreMinedEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/events/mining/OreMinedEvent.kt @@ -3,4 +3,4 @@ package at.hannibal2.skyhanni.events.mining import at.hannibal2.skyhanni.api.event.SkyHanniEvent import at.hannibal2.skyhanni.features.mining.OreBlock -class OreMinedEvent(val originalOre: OreBlock, val extraBlocks: Map) : SkyHanniEvent() +class OreMinedEvent(val originalOre: OreBlock?, val extraBlocks: Map) : SkyHanniEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/events/skyblock/AreaChangeEvents.kt b/src/main/java/at/hannibal2/skyhanni/events/skyblock/AreaChangeEvents.kt new file mode 100644 index 000000000000..b262ea9fbe44 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/events/skyblock/AreaChangeEvents.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.events.skyblock + +import at.hannibal2.skyhanni.api.event.SkyHanniEvent + +// Detect area changes by looking at the scoreboard. +class ScoreboardAreaChangeEvent(val area: String, val previousArea: String?) : SkyHanniEvent() diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/FirstMinionTier.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/FirstMinionTier.kt index e4bae4f05f8d..e94fb8d840d0 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/FirstMinionTier.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/FirstMinionTier.kt @@ -1,13 +1,12 @@ package at.hannibal2.skyhanni.features.bingo import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.ItemUtils.name 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.getCachedIngredients +import at.hannibal2.skyhanni.utils.NEUItems.getItemStackOrNull +import at.hannibal2.skyhanni.utils.PrimitiveRecipe import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe object FirstMinionTier { @@ -30,20 +29,20 @@ object FirstMinionTier { ) { for (minionId in tierOneMinionsFiltered) { for (recipe in NEUItems.getRecipes(minionId)) { - if (recipe !is CraftingRecipe) continue + if (!recipe.isCraftingRecipe()) continue checkOne(recipe, help, minions, minionId) } } } private fun checkOne( - recipe: CraftingRecipe, + recipe: PrimitiveRecipe, help: Map, minions: MutableMap, minionId: NEUInternalName, ) { - if (recipe.getCachedIngredients().any { help.contains(it.internalItemId.asInternalName()) }) { - val name = recipe.output.itemStack.name.removeColor() + if (recipe.getCachedIngredients().any { help.contains(it.internalName) }) { + val name = recipe.output?.internalName?.getItemStackOrNull()?.displayName?.removeColor() ?: return val abc = name.replace(" I", " 0") minions[abc] = minionId.replace("_1", "_0") } diff --git a/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt index c12bafc39ea3..6f7a062f85e5 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/bingo/MinionCraftHelper.kt @@ -7,6 +7,7 @@ import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.hasEnchantments import at.hannibal2.skyhanni.utils.ItemUtils.itemName @@ -18,13 +19,13 @@ import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.NEUItems.getCachedIngredients import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNecessary +import at.hannibal2.skyhanni.utils.PrimitiveIngredient.Companion.toPrimitiveItemStacks import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.JsonArray import com.google.gson.JsonObject -import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe import net.minecraft.client.Minecraft import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -139,7 +140,7 @@ object MinionCraftHelper { for (recipe in recipes) { for (ingredient in recipe.getCachedIngredients()) { - val ingredientInternalName = ingredient.internalItemId.asInternalName() + val ingredientInternalName = ingredient.internalName if (ingredientInternalName == internalName) return true val ingredientPrimitive = NEUItems.getPrimitiveMultiplier(ingredientInternalName) @@ -169,10 +170,10 @@ object MinionCraftHelper { if (internalName.contains("_GENERATOR_")) { for (recipe in NEUItems.getRecipes(internalName)) { - if (recipe !is CraftingRecipe) continue + if (!recipe.isCraftingRecipe()) continue for (ingredient in recipe.getCachedIngredients()) { - val id = ingredient.internalItemId.asInternalName() + val id = ingredient.internalName if (!id.contains("_GENERATOR_") && !allIngredients.contains(id)) { allIngredients.add(id) } @@ -194,17 +195,13 @@ object MinionCraftHelper { newDisplay.add(minionName) val nextMinionId = minionId.addOneToId() for (recipe in NEUItems.getRecipes(nextMinionId)) { - if (recipe !is CraftingRecipe) continue - val output = recipe.output - val internalItemId = output.internalItemId.asInternalName() - if (!internalItemId.contains("_GENERATOR_")) continue + if (!recipe.isCraftingRecipe()) continue + val output = recipe.output ?: continue + if (!output.internalName.contains("_GENERATOR_")) continue val map = mutableMapOf() - for (input in recipe.inputs) { - val itemId = input.internalItemId.asInternalName() + for ((itemId, count) in recipe.ingredients.toPrimitiveItemStacks()) { if (minionId != itemId) { - val count = input.count.toInt() - val old = map.getOrDefault(itemId, 0) - map[itemId] = old + count + map.addOrPut(itemId, count) } } var allDone = true diff --git a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt index 0fee71849b4f..6a5f22b6635a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/chat/ChatFilterGui.kt @@ -5,7 +5,8 @@ import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.KeyboardManager import at.hannibal2.skyhanni.utils.OSUtils import at.hannibal2.skyhanni.utils.StringUtils.stripHypixelMessage -import io.github.moulberry.notenoughupdates.util.Utils +import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.renderables.RenderableTooltips import io.github.notenoughupdates.moulconfig.internal.GlScissorStack import io.github.notenoughupdates.moulconfig.internal.RenderUtils import net.minecraft.client.Minecraft @@ -42,7 +43,7 @@ class ChatFilterGui(private val history: List + RenderableTooltips.setTooltipForRender(tooltip.map { Renderable.string(it) }) } GlStateManager.color(1f, 1f, 1f, 1f) } @@ -98,7 +99,7 @@ class ChatFilterGui(private val history: List mob.killNeededForNextLevel else -> 0 } - val percentage = ((currentKill.toDouble() / killNeeded) * 100).roundToPrecision(2) + val percentage = ((currentKill.toDouble() / killNeeded) * 100).roundTo(2) val suffix = if (type == DisplayTypeEntry.GLOBAL_NEXT) "§ato level ${mob.getNextLevel()}" else "" "§7(§b${currentKill.formatNumber()}§7/§b${killNeeded.formatNumber()}§7) §a$percentage§6% $suffix" } diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt index e087fdd1934e..dd7c088b0b7e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/BroodmotherFeatures.kt @@ -60,9 +60,7 @@ object BroodmotherFeatures { private fun onStageUpdate() { ChatUtils.debug("New Broodmother stage: $currentStage") - if (lastStage == null) { - if (onServerJoin()) return - } + if (lastStage == null && onServerJoin()) return // ignore Hypixel bug where the stage may temporarily revert to Imminent after the Broodmother's death if (currentStage == StageEntry.IMMINENT && lastStage == StageEntry.ALIVE) return @@ -72,23 +70,23 @@ object BroodmotherFeatures { return } - val timeUntilSpawn = currentStage?.minutes?.minutes - broodmotherSpawnTime = SimpleTimeMark.now() + timeUntilSpawn!! - if (currentStage == StageEntry.IMMINENT && config.imminentWarning) { playImminentWarning() return } - if (config.stages.contains(currentStage) && lastStage != null) { - if (currentStage == StageEntry.SLAIN) { - onBroodmotherSlain() - } else { - val pluralize = StringUtils.pluralize(timeUntilSpawn.toInt(DurationUnit.MINUTES), "minute") - ChatUtils.chat( - "Broodmother: $lastStage §e-> $currentStage§e. §b${timeUntilSpawn.inWholeMinutes} $pluralize §euntil it spawns!" - ) - } + val lastStage = lastStage ?: return + val timeUntilSpawn = currentStage?.minutes?.minutes ?: return + broodmotherSpawnTime = SimpleTimeMark.now() + timeUntilSpawn + + if (currentStage !in config.stages) return + if (currentStage == StageEntry.SLAIN) { + onBroodmotherSlain() + } else { + val pluralize = StringUtils.pluralize(timeUntilSpawn.toInt(DurationUnit.MINUTES), "minute") + ChatUtils.chat( + "Broodmother: $lastStage §e-> $currentStage§e. §b${timeUntilSpawn.inWholeMinutes} $pluralize §euntil it spawns!" + ) } } @@ -99,7 +97,7 @@ object BroodmotherFeatures { val pluralize = StringUtils.pluralize(currentStage?.minutes ?: 0, "minute") var message = "The Broodmother's current stage in this server is ${currentStage.toString().replace("!", "")}§e." if (currentStage?.minutes != 0) { - message += " It will spawn within §b${currentStage?.minutes} $pluralize§e." + message += " It will spawn §bwithin ${currentStage?.minutes} $pluralize§e." } ChatUtils.chat(message) return true @@ -161,7 +159,7 @@ object BroodmotherFeatures { if (!isCountdownEnabled()) return if (broodmotherSpawnTime.isFarPast()) { - if (lastStage != null) { + if (lastStage != null && currentStage == StageEntry.ALIVE) { display = "§4Broodmother spawned!" } } else { diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/DamageIndicatorManager.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/DamageIndicatorManager.kt index b7af2d72b2d4..0391e40a3697 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/DamageIndicatorManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/damageindicator/DamageIndicatorManager.kt @@ -34,10 +34,10 @@ import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.baseMaxHealth -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.NumberUtil import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText @@ -718,7 +718,7 @@ object DamageIndicatorManager { if (existed > 40) { val end = (20 * 26) - existed val time = end.toDouble() / 20 - entityData.nameAbove = "Mania Circles: §b${time.round(1)}s" + entityData.nameAbove = "Mania Circles: §b${time.roundTo(1)}s" return "" } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostCounter.kt index 3bc3c85d4b2a..b337d58b1487 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostCounter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostCounter.kt @@ -48,14 +48,14 @@ import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.NumberUtil.formatLong import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal -import at.hannibal2.skyhanni.utils.NumberUtil.roundToPrecision +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.OSUtils import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import io.github.moulberry.notenoughupdates.util.Utils +import com.google.gson.JsonPrimitive import io.github.moulberry.notenoughupdates.util.XPInformation import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import org.apache.commons.io.FilenameUtils @@ -76,27 +76,27 @@ object GhostCounter { private val patternGroup = RepoPattern.group("combat.ghostcounter") private val skillXPPattern by patternGroup.pattern( "skillxp", - "[+](?[0-9,.]+) \\((?[0-9,.]+)(?:/(?[0-9,.]+))?\\)" + "[+](?[0-9,.]+) \\((?[0-9,.]+)(?:/(?[0-9,.]+))?\\)", ) private val combatSectionPattern by patternGroup.pattern( "combatsection", - ".*[+](?[0-9,.]+) (?[A-Za-z]+) \\((?(?[0-9.,]+)/(?[0-9.,]+)|(?[0-9.]+)%)\\).*" + ".*[+](?[0-9,.]+) (?[A-Za-z]+) \\((?(?[0-9.,]+)/(?[0-9.,]+)|(?[0-9.]+)%)\\).*", ) private val killComboExpiredPattern by patternGroup.pattern( "killcomboexpired", - "§cYour Kill Combo has expired! You reached a (?.*) Kill Combo!" + "§cYour Kill Combo has expired! You reached a (?.*) Kill Combo!", ) private val ghostXPPattern by patternGroup.pattern( "ghostxp", - "(?\\d+(?:\\.\\d+)?(?:,\\d+)?[kK]?)/(?\\d+(?:\\.\\d+)?(?:,\\d+)?[kKmM]?)" + "(?\\d+(?:\\.\\d+)?(?:,\\d+)?[kK]?)/(?\\d+(?:\\.\\d+)?(?:,\\d+)?[kKmM]?)", ) private val bestiaryPattern by patternGroup.pattern( "bestiary", - ".*(?:§\\d|§\\w)+BESTIARY (?:§\\d|§\\w)+Ghost (?:§\\d|§\\w)(?\\d+)➜(?:§\\d|§\\w)(?\\d+).*" + ".*(?:§\\d|§\\w)+BESTIARY (?:§\\d|§\\w)+Ghost (?:§\\d|§\\w)(?\\d+)➜(?:§\\d|§\\w)(?\\d+).*", ) private val skillLevelPattern by patternGroup.pattern( "skilllevel", - ".*§e§lSkills: §r§a(?.*) (?\\d+).*" + ".*§e§lSkills: §r§a(?.*) (?\\d+).*", ) private val format = NumberFormat.getInstance() @@ -127,7 +127,7 @@ object GhostCounter { config.position.renderStringsAndItems( display, extraSpace = config.extraSpace, - posLabel = "Ghost Counter" + posLabel = "Ghost Counter", ) } @@ -154,7 +154,7 @@ object GhostCounter { 0.0 -> "0" else -> { val mf = (((storage?.totalMF!! / Option.TOTALDROPS.get()) + Math.ulp(1.0)) * 100) / 100 - mf.roundToPrecision(2).toString() + mf.roundTo(2).toString() } } @@ -205,7 +205,7 @@ object GhostCounter { val etaFormatting = textFormatting.etaFormatting val remaining: Int = when (config.showMax) { - true -> 250_000 - bestiaryCurrentKill + true -> 100_000 - bestiaryCurrentKill false -> killNeeded - currentKill } @@ -222,7 +222,7 @@ object GhostCounter { "%days%" to "days", "%hours%" to "hours", "%minutes%" to "minutes", - "%seconds%" to "seconds" + "%seconds%" to "seconds", ) for ((format, key) in formatMap) { if (etaFormatting.time.contains(format)) { @@ -240,7 +240,7 @@ object GhostCounter { } } - addAsSingletonList(Utils.chromaStringByColourCode(textFormatting.titleFormat.replace("&", "§"))) + addAsSingletonList(textFormatting.titleFormat.replace("&", "§")) addAsSingletonList(textFormatting.ghostKilledFormat.formatText(KILLS)) addAsSingletonList(textFormatting.sorrowsFormat.formatText(Option.SORROWCOUNT)) addAsSingletonList(textFormatting.ghostSinceSorrowFormat.formatText(Option.GHOSTSINCESORROW.getInt())) @@ -255,8 +255,7 @@ object GhostCounter { addAsSingletonList(textFormatting.highestKillComboFormat.formatText(Option.MAXKILLCOMBO)) addAsSingletonList(textFormatting.skillXPGainFormat.formatText(Option.SKILLXPGAINED)) addAsSingletonList( - bestiaryFormatting.base.preFormat(bestiary, nextLevel - 1, nextLevel) - .formatBestiary(currentKill, killNeeded) + bestiaryFormatting.base.preFormat(bestiary, nextLevel - 1, nextLevel).formatBestiary(currentKill, killNeeded), ) addAsSingletonList(xpHourFormatting.base.formatText(xp)) @@ -275,7 +274,7 @@ object GhostCounter { Triple("Volta", Option.VOLTACOUNT.getInt(), voltaValue), Triple("Bag Of Cash", Option.BAGOFCASH.getInt(), 1_000_000), Triple("Scavenger Coins", Option.SCAVENGERCOINS.getInt(), 1), - Triple("Ghostly Boots", Option.GHOSTLYBOOTS.getInt(), 77_777) + Triple("Ghostly Boots", Option.GHOSTLYBOOTS.getInt(), 77_777), ) val moneyMadeTips = buildList { for ((name, count, value) in priceMap) { @@ -288,7 +287,7 @@ object GhostCounter { val moneyMadeWithClickableTips = Renderable.clickAndHover( textFormatting.moneyMadeFormat.formatText(moneyMade.addSeparators()), moneyMadeTips, - onClick = { OSUtils.copyToClipboard(moneyMadeTips.joinToString("\n").removeColor()) } + onClick = { OSUtils.copyToClipboard(moneyMadeTips.joinToString("\n").removeColor()) }, ) addAsSingletonList(textFormatting.moneyHourFormat.formatText(final)) addAsSingletonList(moneyMadeWithClickableTips) @@ -327,7 +326,7 @@ object GhostCounter { }, "§eClick to import data!", prefixColor = "§6", - oneTimeClick = true + oneTimeClick = true, ) } } @@ -365,9 +364,8 @@ object GhostCounter { var parse = true if (skillPercent) { percent = nf.parse(group("percent")).toFloat() - val level = - if (currentSkill == "Combat" && currentSkillLevel != -1) currentSkillLevel else XPInformation.getInstance() - .getSkillInfo(skillName)?.level ?: 0 + val level = if (currentSkill == "Combat" && currentSkillLevel != -1) currentSkillLevel else XPInformation.getInstance() + .getSkillInfo(skillName)?.level ?: 0 if (level > 0) { totalSkillXp = SkillExperience.getExpForNextLevel(level) currentSkillXp = totalSkillXp * percent / 100 @@ -419,11 +417,10 @@ object GhostCounter { Option.SORROWCOUNT, Option.VOLTACOUNT, Option.PLASMACOUNT, Option.GHOSTLYBOOTS -> { opt.add(1.0) opt.add(1.0, true) - storage?.totalMF = storage?.totalMF?.plus(group("mf").substring(4).toDouble()) - ?: group("mf").substring(4).toDouble() + storage?.totalMF = + storage?.totalMF?.plus(group("mf").substring(4).toDouble()) ?: group("mf").substring(4).toDouble() Option.TOTALDROPS.add(1.0) - if (opt == Option.SORROWCOUNT) - Option.GHOSTSINCESORROW.set(0.0) + if (opt == Option.SORROWCOUNT) Option.GHOSTSINCESORROW.set(0.0) update() } @@ -459,7 +456,7 @@ object GhostCounter { when (val nextLevel = if (currentLevel >= 25) 26 else currentLevel + 1) { 26 -> { storage?.bestiaryNextLevel = 26.0 - storage?.bestiaryCurrentKill = 250_000.0 + storage?.bestiaryCurrentKill = 100_000.0 storage?.bestiaryKillNeeded = 0.0 } @@ -491,8 +488,7 @@ object GhostCounter { val stacks = event.inventoryItems val ghostStack = stacks.values.find { it.displayName.contains("Ghost") } ?: return val bestiaryNextLevel = - if ("§\\wGhost".toRegex().matches(ghostStack.displayName)) 1 else ghostStack.displayName.substring(8) - .romanToDecimal() + 1 + if ("§\\wGhost".toRegex().matches(ghostStack.displayName)) 1 else ghostStack.displayName.substring(8).romanToDecimal() + 1 storage?.bestiaryNextLevel = bestiaryNextLevel.toDouble() var kills = 0.0 for (line in ghostStack.getLore()) { @@ -523,6 +519,10 @@ object GhostCounter { event.transform(11, "combat.ghostCounter.ghostDisplayText") { element -> ConfigUtils.migrateIntArrayListToEnumArrayList(element, GhostDisplayEntry::class.java) } + + event.transform(58, "combat.ghostCounter.textFormatting.bestiaryFormatting.showMax_progress") { + JsonPrimitive("%currentKill%/100k (%percentNumber%%)") + } } fun isEnabled() = IslandType.DWARVEN_MINES.isInIsland() && config.enabled diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostData.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostData.kt index abcf2dbba722..fde0f51dac1c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostData.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostData.kt @@ -18,27 +18,23 @@ object GhostData { Option.SKILLXPGAINED to 0.0 ) + // TODO repo val bestiaryData = mutableMapOf().apply { for (i in 1..25) { this[i] = when (i) { - 1 -> 5 - 2 -> 5 - 3 -> 5 - 4 -> 10 - 5 -> 25 - 6 -> 50 - 7 -> 100 - 8 -> 150 - 9 -> 150 - 10 -> 250 - 11 -> 750 - 12 -> 1_500 - 13 -> 2_000 - 14, 15, 16, 17 -> 2_500 - 18 -> 3_000 - 19, 20 -> 3_500 - 21 -> 25_000 - 22, 23, 24, 25 -> 50_000 + 1, 2, 3, 4, 5 -> 4 + 6 -> 20 + 7 -> 40 + 8, 9 -> 60 + 10 -> 100 + 11 -> 300 + 12 -> 600 + 13 -> 800 + 14, 15, 16, 17 -> 1_000 + 18 -> 1_200 + 19, 20 -> 1_400 + 21 -> 10_000 + 22, 23, 24, 25 -> 20_000 else -> 0 } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostFormatting.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostFormatting.kt index 183753e51c63..b58201899bc4 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostFormatting.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostFormatting.kt @@ -160,7 +160,7 @@ object GhostFormatting { base = " &6Bestiary %currentLevel%->%nextLevel%: &b%value%" openMenu = "§cOpen Bestiary Menu !" maxed = "%currentKill% (&c&lMaxed!)" - showMax_progress = "%currentKill%/250k (%percentNumber%%)" + showMax_progress = "%currentKill%/100k (%percentNumber%%)" progress = "%currentKill%/%killNeeded%" } with(killHourFormatting) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostUtil.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostUtil.kt index baacbfa43ed8..36a4edfb3cd4 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostUtil.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/ghostcounter/GhostUtil.kt @@ -6,9 +6,8 @@ import at.hannibal2.skyhanni.data.ProfileStorageData 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.NumberUtil.roundToPrecision +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat -import io.github.moulberry.notenoughupdates.util.Utils import java.io.FileReader object GhostUtil { @@ -71,7 +70,7 @@ object GhostUtil { } val json = ConfigManager.gson.fromJson( FileReader(GhostCounter.ghostCounterV3File), - com.google.gson.JsonObject::class.java + com.google.gson.JsonObject::class.java, ) GhostData.Option.GHOSTSINCESORROW.add(json["ghostsSinceSorrow"].asDouble) GhostData.Option.SORROWCOUNT.add(json["sorrowCount"].asDouble) @@ -91,34 +90,25 @@ object GhostUtil { fun String.formatText(option: GhostData.Option) = formatText(option.getInt(), option.getInt(true)) - fun String.formatText(value: Int, session: Int = -1) = Utils.chromaStringByColourCode( - this.replace("%value%", value.addSeparators()) - .replace("%session%", session.addSeparators()) - .replace("&", "§") - ) + fun String.formatText(value: Int, session: Int = -1) = this.replace("%value%", value.addSeparators()) + .replace("%session%", session.addSeparators()) + .replace("&", "§") - fun String.formatText(t: String) = Utils.chromaStringByColourCode(this.replace("%value%", t).replace("&", "§")) + fun String.formatText(t: String) = this.replace("%value%", t).replace("&", "§") fun String.preFormat(t: String, level: Int, nextLevel: Int) = if (nextLevel == 26) { - Utils.chromaStringByColourCode( - replace("%value%", t) - .replace("%display%", "25") - ) + replace("%value%", t).replace("%display%", "25") } else { - Utils.chromaStringByColourCode( - this.replace("%value%", t) - .replace( - "%display%", - "$level->${if (SkyHanniMod.feature.combat.ghostCounter.showMax) "25" else nextLevel}" - ) - ) + this.replace("%value%", t) + .replace( + "%display%", + "$level->${if (SkyHanniMod.feature.combat.ghostCounter.showMax) "25" else nextLevel}", + ) } - fun String.formatText(value: Double, session: Double) = Utils.chromaStringByColourCode( - this.replace("%value%", value.roundToPrecision(2).addSeparators()) - .replace("%session%", session.roundToPrecision(2).addSeparators()) - .replace("&", "§") - ) + fun String.formatText(value: Double, session: Double) = this.replace("%value%", value.roundTo(2).addSeparators()) + .replace("%session%", session.roundTo(2).addSeparators()) + .replace("&", "§") fun String.formatBestiary(currentKill: Int, killNeeded: Int): String { val bestiaryNextLevel = GhostCounter.storage?.bestiaryNextLevel @@ -127,19 +117,17 @@ object GhostUtil { val nextLevel = bestiaryNextLevel?.let { if (GhostCounter.config.showMax) "25" else "${it.toInt()}" } ?: "§cNo Bestiary Level data!" - return Utils.chromaStringByColourCode( - this.replace( - "%currentKill%", - if (GhostCounter.config.showMax) GhostCounter.bestiaryCurrentKill.addSeparators() else currentKill.addSeparators() - ) - .replace("%percentNumber%", percent(GhostCounter.bestiaryCurrentKill.toDouble())) - .replace("%killNeeded%", killNeeded.shortFormat()) - .replace("%currentLevel%", currentLevel) - .replace("%nextLevel%", nextLevel) - .replace("&", "§") + return this.replace( + "%currentKill%", + if (GhostCounter.config.showMax) GhostCounter.bestiaryCurrentKill.addSeparators() else currentKill.addSeparators(), ) + .replace("%percentNumber%", percent(GhostCounter.bestiaryCurrentKill.toDouble())) + .replace("%killNeeded%", killNeeded.shortFormat()) + .replace("%currentLevel%", currentLevel) + .replace("%nextLevel%", nextLevel) + .replace("&", "§") } private fun percent(number: Double) = - 100.0.coerceAtMost(((number / 250_000) * 100).roundToPrecision(4)).toString() + 100.0.coerceAtMost(((number / 100_000) * 100).roundTo(4)).toString() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/mobs/ArachneSpawnTimer.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/mobs/ArachneSpawnTimer.kt index b3c9be188752..d2e6f7ed67e5 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/mobs/ArachneSpawnTimer.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/mobs/ArachneSpawnTimer.kt @@ -80,7 +80,7 @@ object ArachneSpawnTimer { } } - @HandleEvent(onlyOnIslands = [IslandType.SPIDER_DEN], priority = HandleEvent.LOW, receiveCancelled = true) + @HandleEvent(onlyOnIsland = IslandType.SPIDER_DEN, priority = HandleEvent.LOW, receiveCancelled = true) fun onPacketReceive(event: PacketReceivedEvent) { if (!saveNextTickParticles) return if (searchTime.passedSince() < 3.seconds) return @@ -99,7 +99,7 @@ object ArachneSpawnTimer { val packet = event.packet if (packet is S2APacketParticles) { - val location = packet.toLorenzVec().round(2) + val location = packet.toLorenzVec().roundTo(2) if (arachneAltarLocation.distance(location) > 30) return if (packet.particleType == EnumParticleTypes.REDSTONE && packet.particleSpeed == 1.0f) { particleCounter += 1 diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt index 1890c62930d1..2eb5dc3fb893 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/commands/HelpCommand.kt @@ -3,28 +3,15 @@ package at.hannibal2.skyhanni.features.commands import at.hannibal2.skyhanni.config.commands.Commands import at.hannibal2.skyhanni.utils.StringUtils.splitLines import at.hannibal2.skyhanni.utils.chat.Text -import at.hannibal2.skyhanni.utils.chat.Text.asComponent -import at.hannibal2.skyhanni.utils.chat.Text.center -import at.hannibal2.skyhanni.utils.chat.Text.fitToChat import at.hannibal2.skyhanni.utils.chat.Text.hover -import at.hannibal2.skyhanni.utils.chat.Text.onClick -import at.hannibal2.skyhanni.utils.chat.Text.send -import at.hannibal2.skyhanni.utils.chat.Text.style import at.hannibal2.skyhanni.utils.chat.Text.suggest -import net.minecraft.util.EnumChatFormatting import net.minecraft.util.IChatComponent -import kotlin.math.ceil object HelpCommand { private const val COMMANDS_PER_PAGE = 15 private const val HELP_ID = -6457563 - private fun createDivider() = Text.HYPHEN.fitToChat().style { - strikethrough = true - color = EnumChatFormatting.BLUE - } - private fun createCommandEntry(command: Commands.CommandInfo): IChatComponent { val category = command.category val color = category.color @@ -43,57 +30,21 @@ object HelpCommand { } } - private fun showPage( - page: Int, - search: String, - commands: List, - ) { + private fun showPage(page: Int, search: String, commands: List) { val filtered = commands.filter { it.name.contains(search, ignoreCase = true) || it.description.contains(search, ignoreCase = true) } - val maxPage = if (filtered.isNotEmpty()) { - ceil(filtered.size.toDouble() / COMMANDS_PER_PAGE).toInt() - } else 1 - val page = page.coerceIn(1, maxPage) - val title = if (search.isEmpty()) "§6SkyHanni Commands" else "§6SkyHanni Commands matching '$search'" - - val text = mutableListOf() - - text.add(createDivider()) - text.add(title.asComponent().center()) - text.add( - Text.join( - if (page > 1) "§6§l<<".asComponent { - this.hover = "§eClick to view page ${page - 1}".asComponent() - this.onClick { showPage(page - 1, search, commands) } - } else null, - " ", - "§6(Page $page of $maxPage)", - " ", - if (page < maxPage) "§6§l>>".asComponent { - this.hover = "§eClick to view page ${page + 1}".asComponent() - this.onClick { showPage(page + 1, search, commands) } - } else null, - ).center(), - ) - text.add(createDivider()) - - if (filtered.isEmpty()) { - text.add(Text.EMPTY) - text.add("§cNo commands found.".asComponent().center()) - text.add(Text.EMPTY) - } else { - val start = (page - 1) * COMMANDS_PER_PAGE - val end = (page * COMMANDS_PER_PAGE).coerceAtMost(filtered.size) - for (i in start until end) { - text.add(createCommandEntry(filtered[i])) - } - } - - text.add(createDivider()) + val title = if (search.isBlank()) "SkyHanni Commands" else "SkyHanni Commands Matching: \"$search\"" - Text.multiline(text).send(HELP_ID) + Text.displayPaginatedList( + title, + filtered, + chatLineId = HELP_ID, + emptyMessage = "No commands found.", + currentPage = page, + maxPerPage = COMMANDS_PER_PAGE, + ) { createCommandEntry(it) } } fun onCommand(args: Array, commands: List) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/PlayerTabComplete.kt b/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/PlayerTabComplete.kt index bf44282114e2..070ab478e083 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/PlayerTabComplete.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/commands/tabcomplete/PlayerTabComplete.kt @@ -15,6 +15,24 @@ object PlayerTabComplete { private val config get() = SkyHanniMod.feature.misc.commands.tabComplete private var vipVisits = listOf() + private val ignoredCommandCategories = mapOf( + "f" to listOf(PlayerCategory.FRIENDS), + "friend" to listOf(PlayerCategory.FRIENDS), + + "msg" to listOf(), + "w" to listOf(), + "tell" to listOf(), + "boop" to listOf(), + + "visit" to listOf(), + "invite" to listOf(), + "ah" to listOf(), + + "pv" to listOf(), // NEU's Profile Viewer + "shmarkplayer" to listOf(), // SkyHanni's Mark Player + + "trade" to listOf(PlayerCategory.FRIENDS, PlayerCategory.PARTY), + ) @SubscribeEvent fun onRepoReload(event: RepositoryReloadEvent) { @@ -34,41 +52,21 @@ object PlayerTabComplete { } fun handleTabComplete(command: String): List? { - val commands = mapOf( - "f" to listOf(PlayerCategory.FRIENDS), - "friend" to listOf(PlayerCategory.FRIENDS), - - "msg" to listOf(), - "w" to listOf(), - "tell" to listOf(), - "boop" to listOf(), - - "visit" to listOf(), - "invite" to listOf(), - "ah" to listOf(), - - "pv" to listOf(), // NEU's Profile Viewer - "shmarkplayer" to listOf(), // SkyHanni's Mark Player - - "trade" to listOf(PlayerCategory.FRIENDS, PlayerCategory.PARTY) - ) - val ignored = commands[command] ?: return null + val ignoredCategories = ignoredCommandCategories[command] ?: return null return buildList { - if (config.friends && PlayerCategory.FRIENDS !in ignored) { - FriendAPI.getAllFriends() - .filter { it.bestFriend || !config.onlyBestFriends } - .forEach { add(it.name) } + if (config.friends && PlayerCategory.FRIENDS !in ignoredCategories) { + FriendAPI.getAllFriends().filter { it.bestFriend || !config.onlyBestFriends }.forEach { add(it.name) } } - if (config.islandPlayers && PlayerCategory.ISLAND_PLAYERS !in ignored) { + if (config.islandPlayers && PlayerCategory.ISLAND_PLAYERS !in ignoredCategories) { for (entity in EntityUtils.getPlayerEntities()) { add(entity.name) } } - if (config.party && PlayerCategory.PARTY !in ignored) { + if (config.party && PlayerCategory.PARTY !in ignoredCategories) { for (member in PartyAPI.partyMembers) { add(member) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt index 508296d4974c..a710e4fd0e94 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonFinderFeatures.kt @@ -275,6 +275,7 @@ object DungeonFinderFeatures { if (!partyFinderTitlePattern.matches(inventoryName)) return map inInventory = true for ((slot, stack) in event.inventoryItems) { + // TODO use enum val classNames = mutableListOf("Healer", "Mage", "Berserk", "Archer", "Tank") val toolTip = stack.getLore().toMutableList() for ((index, line) in stack.getLore().withIndex()) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonShadowAssassinNotification.kt b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonShadowAssassinNotification.kt index abe83df8cbd4..ca888392f35c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonShadowAssassinNotification.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/dungeon/DungeonShadowAssassinNotification.kt @@ -16,7 +16,7 @@ object DungeonShadowAssassinNotification { private val config get() = SkyHanniMod.feature.dungeon - @HandleEvent(onlyOnIslands = [IslandType.CATACOMBS]) + @HandleEvent(onlyOnIsland = IslandType.CATACOMBS) fun onWorldBorderChange(event: PacketReceivedEvent) { if (!isEnabled()) return if (DungeonAPI.dungeonFloor?.contains("3") == true && DungeonAPI.inBossRoom) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalGoal.kt b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalGoal.kt index c36212a22d8b..beedfd6a5676 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalGoal.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalGoal.kt @@ -69,13 +69,13 @@ enum class CarnivalGoal( CATCH_A_FISH_SCORE( GoalType.CATCH_A_FISH, "§7Reach §a3,000 score §7in a single game", - "(§8 - §r)?§7Catch §r§a30 Fish §r§7in a single game of §r§3Catch a Fish§r§7.", + "(§8 - §r)?§7Reach §r§a3,000 score §r§7in a single game of §r§3Catch a Fish§r§7.", "Reach §a3,000 score", ), CATCH_FISH( GoalType.CATCH_A_FISH, "§7Catch §a30 Fish §7in a single game of", - "(§8 - §r)?§7Reach §r§a3,000 score §r§7in a single game of §r§3Catch a Fish§r§7.", + "(§8 - §r)?§7Catch §r§a30 Fish §r§7in a single game of §r§3Catch a Fish§r§7.", "Catch §a30 Fish", ), CATCH_YELLOW_FISH( diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt index d57903a57949..ec18d016b561 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/carnival/CarnivalZombieShootout.kt @@ -64,7 +64,7 @@ object CarnivalZombieShootout { LEATHER(30, "Leather Cap", Color(165, 42, 42)), //Brown IRON(50, "Iron Helmet", Color(192, 192, 192)), //Silver GOLD(80, "Golden Helmet", Color(255, 215, 0)), //Gold - DIAMOND(120, "Diamond Helmet", Color(185, 242, 255)) //Diamond + DIAMOND(120, "Diamond Helmet", Color(44, 214, 250)) //Diamond } @SubscribeEvent @@ -95,9 +95,13 @@ object CarnivalZombieShootout { for ((zombie, type) in drawZombies) { val entity = EntityUtils.getEntityByID(zombie.entityId) ?: continue + val isSmall = (entity as? EntityZombie)?.isChild ?: false + + val boundingBox = if (isSmall) entity.entityBoundingBox.expand(0.0, -0.4, 0.0).offset(0.0, -0.4, 0.0) + else entity.entityBoundingBox event.drawHitbox( - entity.entityBoundingBox.expand(0.1, 0.05, 0.0).offset(0.0, 0.05, 0.0), + boundingBox.expand(0.1, 0.05, 0.0).offset(0.0, 0.05, 0.0), lineWidth = 3, type.color, depth = false, diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/BurrowWarpHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/BurrowWarpHelper.kt index 34dab01e6ce1..4074b465de33 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/BurrowWarpHelper.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/BurrowWarpHelper.kt @@ -12,8 +12,8 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.sorted import at.hannibal2.skyhanni.utils.HypixelCommands import at.hannibal2.skyhanni.utils.LocationUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.SimpleTimeMark import net.minecraft.client.Minecraft import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -104,11 +104,11 @@ object BurrowWarpHelper { debug?.add("warpPoint: ${warpPoint.displayName}") val playerDistance = playerLocation.distance(target) - debug?.add("playerDistance: ${playerDistance.round(1)}") + debug?.add("playerDistance: ${playerDistance.roundTo(1)}") val warpDistance = warpPoint.distance(target) - debug?.add("warpDistance: ${warpDistance.round(1)}") + debug?.add("warpDistance: ${warpDistance.roundTo(1)}") val difference = playerDistance - warpDistance - debug?.add("difference: ${difference.round(1)}") + debug?.add("difference: ${difference.roundTo(1)}") val setWarpPoint = difference > 10 debug?.add("setWarpPoint: $setWarpPoint") currentWarp = if (setWarpPoint) warpPoint else null diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaProfitTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaProfitTracker.kt index b6ec4d0a62e9..fb90de9e118e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaProfitTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/DianaProfitTracker.kt @@ -8,9 +8,11 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.ItemAddEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.features.event.diana.DianaAPI.isDianaSpade import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString +import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators @@ -107,7 +109,7 @@ object DianaProfitTracker { @SubscribeEvent fun onItemAdd(event: ItemAddEvent) { - if (!isEnabled()) return + if (!(DianaAPI.isDoingDiana() && config.enabled)) return tryAddItem(event.internalName, event.amount, event.source == ItemAddManager.Source.COMMAND) } @@ -137,9 +139,7 @@ object DianaProfitTracker { tryHide(event) } - if (message == "§6§lRARE DROP! §r§eYou dug out a §r§9Griffin Feather§r§e!" || - message == "§eFollow the arrows to find the §r§6treasure§r§e!" - ) { + if (message == "§6§lRARE DROP! §r§eYou dug out a §r§9Griffin Feather§r§e!" || message == "§eFollow the arrows to find the §r§6treasure§r§e!") { BurrowAPI.lastBurrowRelatedChatMessage = SimpleTimeMark.now() tryHide(event) } @@ -153,7 +153,13 @@ object DianaProfitTracker { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent) { - if (!isEnabled()) return + if (!LorenzUtils.inSkyBlock) return + if (!config.enabled) return + val spadeInHand = InventoryUtils.getItemInHand()?.isDianaSpade ?: false + if (!DianaAPI.isDoingDiana() && !spadeInHand) return + if (spadeInHand) { + tracker.firstUpdate() + } tracker.renderDisplay(config.position) } @@ -168,6 +174,4 @@ object DianaProfitTracker { fun resetCommand() { tracker.resetCommand() } - - private fun isEnabled() = DianaAPI.isDoingDiana() && config.enabled } diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt index 0f0220a76208..80d6ea0e0df9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/GriffinBurrowParticleFinder.kt @@ -58,7 +58,7 @@ object GriffinBurrowParticleFinder { } } - @HandleEvent(onlyOnIslands = [IslandType.HUB], priority = HandleEvent.LOW, receiveCancelled = true) + @HandleEvent(onlyOnIsland = IslandType.HUB, priority = HandleEvent.LOW, receiveCancelled = true) fun onPacketReceive(event: PacketReceivedEvent) { if (!isEnabled()) return if (!config.burrowsSoopyGuess) return diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/InquisitorWaypointShare.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/InquisitorWaypointShare.kt index fbb599d68f90..2d0e2a809e81 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/InquisitorWaypointShare.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/InquisitorWaypointShare.kt @@ -222,7 +222,7 @@ object InquisitorWaypointShare { HypixelCommands.partyChat("x: $x, y: $y, z: $z ") } - @HandleEvent(onlyOnIslands = [IslandType.HUB], priority = HandleEvent.LOW, receiveCancelled = true) + @HandleEvent(onlyOnIsland = IslandType.HUB, priority = HandleEvent.LOW, receiveCancelled = true) fun onFirstChatEvent(event: PacketReceivedEvent) { if (!isEnabled()) return val packet = event.packet diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/diana/MythologicalCreatureTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/event/diana/MythologicalCreatureTracker.kt index 3c512d4c4389..55e422caba5f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/diana/MythologicalCreatureTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/diana/MythologicalCreatureTracker.kt @@ -5,11 +5,13 @@ import at.hannibal2.skyhanni.data.MayorAPI.getElectionYear import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.event.diana.DianaAPI.isDianaSpade import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString import at.hannibal2.skyhanni.utils.CollectionUtils.sumAllValues import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RegexUtils.matches @@ -90,19 +92,18 @@ object MythologicalCreatureTracker { @SubscribeEvent fun onChat(event: LorenzChatEvent) { for (creatureType in MythologicalCreatureType.entries) { - if (creatureType.pattern.matches(event.message)) { - BurrowAPI.lastBurrowRelatedChatMessage = SimpleTimeMark.now() - tracker.modify { - it.count.addOrPut(creatureType, 1) - - // TODO migrate to abstract feature in the future - if (creatureType == MythologicalCreatureType.MINOS_INQUISITOR) { - event.chatComponent = ChatComponentText(event.message + " §e(${it.creaturesSinceLastInquisitor})") - it.creaturesSinceLastInquisitor = 0 - } else it.creaturesSinceLastInquisitor++ - } - if (config.hideChat) event.blockedReason = "mythological_creature_dug" + if (!creatureType.pattern.matches(event.message)) continue + BurrowAPI.lastBurrowRelatedChatMessage = SimpleTimeMark.now() + tracker.modify { + it.count.addOrPut(creatureType, 1) + + // TODO migrate to abstract feature in the future + if (creatureType == MythologicalCreatureType.MINOS_INQUISITOR) { + event.chatComponent = ChatComponentText(event.message + " §e(${it.creaturesSinceLastInquisitor})") + it.creaturesSinceLastInquisitor = 0 + } else it.creaturesSinceLastInquisitor++ } + if (config.hideChat) event.blockedReason = "mythological_creature_dug" } } @@ -133,7 +134,13 @@ object MythologicalCreatureTracker { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent) { - if (!isEnabled()) return + if (!LorenzUtils.inSkyBlock) return + if (!config.enabled) return + val spadeInHand = InventoryUtils.getItemInHand()?.isDianaSpade ?: false + if (!DianaAPI.isDoingDiana() && !spadeInHand) return + if (spadeInHand) { + tracker.firstUpdate() + } tracker.renderDisplay(config.position) } @@ -142,5 +149,4 @@ object MythologicalCreatureTracker { tracker.resetCommand() } - private fun isEnabled() = DianaAPI.isDoingDiana() && config.enabled } diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityAPI.kt index 5c63fe3a800a..93c9efc04021 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityAPI.kt @@ -3,50 +3,57 @@ package at.hannibal2.skyhanni.features.event.hoppity import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.events.hoppity.EggFoundEvent import at.hannibal2.skyhanni.events.hoppity.RabbitFoundEvent +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.CHOCOLATE_FACTORY_MILESTONE +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.CHOCOLATE_SHOP_MILESTONE +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.SIDE_DISH +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager.eggFoundPattern import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager.getEggType import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI +import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryStrayTracker import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.LorenzRarity.DIVINE +import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getMinecraftId import at.hannibal2.skyhanni.utils.SkyblockSeason -import net.minecraft.util.ChatComponentText import net.minecraftforge.fml.common.eventhandler.EventPriority import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object HoppityAPI { - private var hoppityEggChat = mutableListOf() + private var messageCount = 0 private var duplicate = false private var lastRarity = "" private var lastName = "" + private var lastNameCache = "" private var newRabbit = false - private var lastChatMeal: HoppityEggType? = null + private var lastMeal: HoppityEggType? = null private var lastDuplicateAmount: Long? = null - private var rabbitBought = false val hoppityRarities by lazy { LorenzRarity.entries.filter { it <= DIVINE } } - private fun resetChatData() { - this.hoppityEggChat = mutableListOf() + private fun resetRabbitData() { + this.messageCount = 0 this.duplicate = false this.newRabbit = false this.lastRarity = "" this.lastName = "" - this.lastChatMeal = null + this.lastMeal = null this.lastDuplicateAmount = null - this.rabbitBought = false } + fun getLastRabbit(): String = this.lastNameCache fun isHoppityEvent() = (SkyblockSeason.currentSeason == SkyblockSeason.SPRING || SkyHanniMod.feature.dev.debug.alwaysHoppitys) - fun rarityByRabbit(rabbit: String): LorenzRarity? = hoppityRarities.firstOrNull { it.chatColorCode == rabbit.substring(0, 2) } /** @@ -59,6 +66,14 @@ object HoppityAPI { "(?:§.)*?(?\\d{1,2})[a-z]{2} Chocolate Milestone", ) + /** + * REGEX-TEST: §6§lGolden Rabbit §8- §aSide Dish + */ + private val sideDishNamePattern by ChocolateFactoryAPI.patternGroup.pattern( + "rabbit.sidedish", + "(?:§.)*?Golden Rabbit (?:§.)?- (?:§.)?Side Dish", + ) + /** * REGEX-TEST: §7Reach §6300B Chocolate §7all-time to * REGEX-TEST: §7Reach §61k Chocolate §7all-time to unlock @@ -77,99 +92,101 @@ object HoppityAPI { "§7Spend §6(?[\\d.MBk]*) Chocolate §7in.*", ) - fun fireSideDishMessage() { - LorenzChatEvent( - "§d§lHOPPITY'S HUNT §r§dYou found a §r§6§lSide Dish §r§6Egg §r§din the Chocolate Factory§r§d!", - ChatComponentText(""), - ).postAndCatch() + @SubscribeEvent(priority = EventPriority.HIGH) + fun onTick(event: SecondPassedEvent) { + if (!ChocolateFactoryAPI.inChocolateFactory) return + InventoryUtils.getItemsInOpenChest().filter { + it.stack.hasDisplayName() && + it.stack.getMinecraftId().toString() == "minecraft:skull" && + it.stack.getLore().isNotEmpty() + }.forEach { + ChocolateFactoryStrayTracker.strayCaughtPattern.matchMatcher(it.stack.displayName) { + ChocolateFactoryStrayTracker.handleStrayClicked(it) + when (groupOrNull("name") ?: return@matchMatcher) { + "Fish the Rabbit" -> EggFoundEvent(HoppityEggType.STRAY, it.slotNumber, null).post() + "El Dorado" -> EggFoundEvent(HoppityEggType.STRAY, it.slotNumber, null).post() + else -> return@matchMatcher + } + } + } } @SubscribeEvent(priority = EventPriority.HIGH) fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { - val index = event.slot?.slotIndex ?: return - if (index == -999) return + val index = event.slot?.slotIndex?.takeIf { it != -999 } ?: return val clickedStack = InventoryUtils.getItemsInOpenChest() .find { it.slotNumber == event.slot.slotNumber && it.hasStack } ?.stack ?: return val nameText = (if (clickedStack.hasDisplayName()) clickedStack.displayName else clickedStack.itemName) + sideDishNamePattern.matchMatcher(nameText) { + EggFoundEvent(SIDE_DISH, index, null).post() + lastMeal = SIDE_DISH + attemptFireRabbitFound() + } milestoneNamePattern.matchMatcher(nameText) { - val itemLore = clickedStack.getLore() - if (!itemLore.any { it == "§eClick to claim!" }) return - - // Will never match both all time and shop patterns together - allTimeLorePattern.firstMatcher(clickedStack.getLore()) { - LorenzChatEvent( - "§d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§lChocolate Milestone Rabbit §r§din the Chocolate Factory§r§d!", - ChatComponentText(""), - ).postAndCatch() - } - - shopLorePattern.firstMatcher(clickedStack.getLore()) { - LorenzChatEvent( - "§d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§lShop Milestone Rabbit §r§din the Chocolate Factory§r§d!", - ChatComponentText(""), - ).postAndCatch() + clickedStack.getLore().let { + if (!it.any { line -> line == "§eClick to claim!" }) return + allTimeLorePattern.firstMatcher(it) { + EggFoundEvent(CHOCOLATE_FACTORY_MILESTONE, index, null).post() + lastMeal = CHOCOLATE_FACTORY_MILESTONE + attemptFireRabbitFound() + } + shopLorePattern.firstMatcher(it) { + EggFoundEvent(CHOCOLATE_SHOP_MILESTONE, index, null).post() + lastMeal = CHOCOLATE_SHOP_MILESTONE + attemptFireRabbitFound() + } } } } - // Dumbed down version of the Compact Chat for Hoppity's, - // with the additional native context of side dishes - fun handleChat(event: LorenzChatEvent) { - HoppityEggsManager.eggFoundPatterns.forEach { - it.matchMatcher(event.message) { - resetChatData() - lastChatMeal = getEggType(event) - attemptFire(event) - } + @SubscribeEvent(priority = EventPriority.HIGH) + fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + + eggFoundPattern.matchMatcher(event.message) { + resetRabbitData() + lastMeal = getEggType(event) + lastMeal?.let { EggFoundEvent(it, null, groupOrNull("note")).post() } + attemptFireRabbitFound() } HoppityEggsManager.eggBoughtPattern.matchMatcher(event.message) { if (group("rabbitname").equals(lastName)) { - rabbitBought = true - lastChatMeal = HoppityEggType.BOUGHT - attemptFire(event) + lastMeal = HoppityEggType.BOUGHT + EggFoundEvent(HoppityEggType.BOUGHT, null, null).post() + attemptFireRabbitFound() } } HoppityEggsManager.rabbitFoundPattern.matchMatcher(event.message) { - // The only cases where "You found ..." will come in with more than 1 message, - // or empty for hoppityEggChat, is where the rabbit was purchased from hoppity, - // In the case of buying, we want to reset variables to a clean state during this capture, - // as the important capture for the purchased message is the final message in - // the chain; "You found [rabbit]" -> "Dupe/New Rabbit" -> "You bought [rabbit]" - if ((hoppityEggChat.isEmpty() || hoppityEggChat.size > 1)) { - resetChatData() - } - lastName = group("name") + lastNameCache = lastName lastRarity = group("rarity") - attemptFire(event) + attemptFireRabbitFound() } HoppityEggsManager.newRabbitFound.matchMatcher(event.message) { newRabbit = true groupOrNull("other")?.let { - attemptFire(event) + attemptFireRabbitFound() return } - attemptFire(event) + attemptFireRabbitFound() } } - fun attemptFire(event: LorenzChatEvent, lastDuplicateAmount: Long? = null) { + fun attemptFireRabbitFound(lastDuplicateAmount: Long? = null) { lastDuplicateAmount?.let { this.lastDuplicateAmount = it - } - hoppityEggChat.add(event.message) - if (lastDuplicateAmount != null) { this.duplicate = true } - val lastChatMeal = lastChatMeal ?: return - if (hoppityEggChat.size == 3) { - RabbitFoundEvent(lastChatMeal, duplicate, lastName, lastDuplicateAmount ?: 0).post() - } + messageCount++ + val lastChatMeal = lastMeal ?: return + if (messageCount != 3) return + RabbitFoundEvent(lastChatMeal, duplicate, lastName, lastDuplicateAmount ?: 0).post() + resetRabbitData() } } 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 a06b3dcbc202..e84d93dfa6a3 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 @@ -6,33 +6,41 @@ import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.CollectionUtils.addString import at.hannibal2.skyhanni.utils.CollectionUtils.collectWhile import at.hannibal2.skyhanni.utils.CollectionUtils.consumeWhile import at.hannibal2.skyhanni.utils.DisplayTableEntry import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.ItemUtils.setLore import at.hannibal2.skyhanni.utils.KSerializable import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round 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.NumberUtil.roundTo +import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches -import at.hannibal2.skyhanni.utils.RegexUtils.find import at.hannibal2.skyhanni.utils.RegexUtils.findMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst +import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils.highlight import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.init.Items +import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Pattern @SkyHanniModule object HoppityCollectionStats { @@ -48,7 +56,7 @@ object HoppityCollectionStats { */ private val pagePattern by patternGroup.pattern( "page.current", - "(?:\\((?\\d+)\\/(?\\d+)\\) )?Hoppity's Collection", + "(?:\\((?\\d+)/(?\\d+)\\) )?Hoppity's Collection", ) private val duplicatesFoundPattern by patternGroup.pattern( "duplicates.found", @@ -97,6 +105,30 @@ object HoppityCollectionStats { "§c✖ §7Requirement §e(?[\\d,]+)§7/§a(?[\\d,]+)", ) + /** + * REGEX-TEST: §6Factory Milestones§7. + */ + private val factoryMilestone by RepoPattern.pattern( + "rabbit.requirement.factory", + "§6Factory Milestones§7.", + ) + + /** + * REGEX-TEST: §6Shop Milestones§7. + */ + private val shopMilestone by RepoPattern.pattern( + "rabbit.requirement.shop", + "§6Shop Milestones§7.", + ) + + /** + * REGEX-TEST: §7§7Obtained by finding the §aStray Rabbit + */ + private val strayRabbit by RepoPattern.pattern( + "rabbit.requirement.stray", + "§7§7Obtained by finding the §aStray Rabbit", + ) + /** * REGEX-TEST: Find 15 unique egg locations in the Deep Caverns. */ @@ -109,6 +141,21 @@ object HoppityCollectionStats { private val loggedRabbits get() = ProfileStorageData.profileSpecific?.chocolateFactory?.rabbitCounts ?: mutableMapOf() + enum class HighlightRabbitTypes( + private val displayName: String, + val color: LorenzColor, + ) { + ABI("§2Abi", LorenzColor.DARK_GREEN), + FACTORY("§eFactory Milestones", LorenzColor.YELLOW), + MET("§aRequirement Met", LorenzColor.GREEN), + NOT_MET("§cRequirement Not Met.", LorenzColor.RED), + SHOP("§6Shop Milestones", LorenzColor.GOLD), + STRAYS("§3Stray Rabbits", LorenzColor.DARK_AQUA), + ; + + override fun toString(): String = displayName + } + @KSerializable data class LocationRabbit( val locationName: String, @@ -133,21 +180,127 @@ object HoppityCollectionStats { var inInventory = false + private val highlightConfigMap: Map = mapOf( + factoryMilestone to HighlightRabbitTypes.FACTORY, + requirementMet to HighlightRabbitTypes.MET, + requirementNotMet to HighlightRabbitTypes.NOT_MET, + shopMilestone to HighlightRabbitTypes.SHOP, + strayRabbit to HighlightRabbitTypes.STRAYS, + ) + + private fun missingRabbitStackNeedsFix(stack: ItemStack): Boolean = + stack.item == Items.dye && (stack.metadata == 8 || stack.getLore().any { it.lowercase().contains("milestone") }) + + private val replacementCache: MutableMap = mutableMapOf() + + @SubscribeEvent + fun replaceItem(event: ReplaceItemEvent) { + replacementCache[event.originalItem.displayName]?.let { event.replace(it) } + } + @SubscribeEvent fun onInventoryOpen(event: InventoryFullyOpenedEvent) { if (!(LorenzUtils.inSkyBlock)) return - if (!pagePattern.matches(event.inventoryName)) return + if (!pagePattern.matches(event.inventoryName)) { + // Clear highlight cache in case options are toggled + highlightMap.clear() + return + } + + event.inventoryItems.values.filter { it.hasDisplayName() && missingRabbitStackNeedsFix(it) }.forEach { stack -> + val rarity = HoppityAPI.rarityByRabbit(stack.displayName) + // Add NBT for the dye color itself + val newItemStack = if (config.rarityDyeRecolor) ItemStack( + Items.dye, 1, + when (rarity) { + LorenzRarity.COMMON -> 7 // Light gray dye + LorenzRarity.UNCOMMON -> 10 // Lime dye + LorenzRarity.RARE -> 4 // Lapis lazuli + LorenzRarity.EPIC -> 5 // Purple dye + LorenzRarity.LEGENDARY -> 14 // Orange dye + LorenzRarity.MYTHIC -> 13 // Magenta dye + LorenzRarity.DIVINE -> 12 // Light blue dye + LorenzRarity.SPECIAL -> 1 // Rose Red - Covering bases for future (?) + else -> return + }, + ) else ItemStack(Items.dye, 8) + + newItemStack.setLore(buildDescriptiveMilestoneLore(stack)) + newItemStack.setStackDisplayName(stack.displayName) + replacementCache[stack.displayName] = newItemStack + } inInventory = true if (config.hoppityCollectionStats) { display = buildDisplay(event) } + + if (config.highlightRabbits.isNotEmpty()) { + for ((_, stack) in event.inventoryItems) filterRabbitToHighlight(stack) + } + } + + private fun buildDescriptiveMilestoneLore(itemStack: ItemStack): List { + val existingLore = itemStack.getLore().toMutableList() + var replaceIndex: Int? = null + var milestoneType: HoppityEggType = HoppityEggType.BREAKFAST + + if (factoryMilestone.anyMatches(existingLore)) { + milestoneType = HoppityEggType.CHOCOLATE_FACTORY_MILESTONE + replaceIndex = existingLore.indexOfFirst { loreMatch -> factoryMilestone.matches(loreMatch) } + } else if (shopMilestone.anyMatches(existingLore)) { + milestoneType = HoppityEggType.CHOCOLATE_SHOP_MILESTONE + replaceIndex = existingLore.indexOfFirst { loreMatch -> shopMilestone.matches(loreMatch) } + } + + replaceIndex?.let { + ChocolateFactoryAPI.milestoneByRabbit(itemStack.displayName)?.let { + val displayAmount = it.amount.shortFormat() + val operationFormat = when (milestoneType) { + HoppityEggType.CHOCOLATE_SHOP_MILESTONE -> "spending" + HoppityEggType.CHOCOLATE_FACTORY_MILESTONE -> "reaching" + else -> "" // Never happens + } + + //List indexing is weird + existingLore[replaceIndex - 1] = "§7Obtained by $operationFormat §6$displayAmount" + existingLore[replaceIndex] = "§7all-time §6Chocolate." + return existingLore + } + } + + return existingLore } + private fun filterRabbitToHighlight(stack: ItemStack) { + val lore = stack.getLore() + + if (lore.isEmpty()) return + if (!rabbitNotFoundPattern.anyMatches(lore) && !config.highlightFoundRabbits) return + + if (highlightMap.containsKey(stack.displayName)) return + + if (stack.displayName == "§aAbi" && config.highlightRabbits.contains(HighlightRabbitTypes.ABI)) { + highlightMap[stack.displayName] = HighlightRabbitTypes.ABI.color + return + } + + // cache rabbits until collection is closed + for ((pattern, rabbitType) in highlightConfigMap) { + if (pattern.anyMatches(lore) && config.highlightRabbits.contains(rabbitType)) { + highlightMap[stack.displayName] = rabbitType.color + break + } + } + } + + private var highlightMap = mutableMapOf() + @SubscribeEvent fun onInventoryClose(event: InventoryCloseEvent) { inInventory = false display = emptyList() + replacementCache.clear() } @SubscribeEvent @@ -162,22 +315,17 @@ object HoppityCollectionStats { ) } - // TODO cache with inventory update event @SubscribeEvent fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) { - if (!config.highlightRabbitsWithRequirement) return if (!inInventory) return + if (config.highlightRabbits.isEmpty()) return for (slot in InventoryUtils.getItemsInOpenChest()) { - val lore = slot.stack.getLore() - if (lore.any { requirementMet.find(it) } && !config.onlyHighlightRequirementNotMet) - slot highlight LorenzColor.GREEN - if (lore.any { requirementNotMet.find(it) }) { - val found = !rabbitNotFoundPattern.anyMatches(lore) - // Hypixel allows purchasing Rabbits from Hoppity NPC even when the requirement is not yet met. - if (!found) { - slot highlight LorenzColor.RED - } + val name = slot.stack.displayName + + if (name.isEmpty()) continue + highlightMap[name]?.let { + slot highlight it } } } @@ -186,9 +334,10 @@ object HoppityCollectionStats { if (!config.showLocationRequirementsRabbitsInHoppityStats) return val missingLocationRabbits = locationRabbitRequirements.values.filter { !it.hasMetRequirements() } - val tips = locationRabbitRequirements.map { - it.key + " §7(§e" + it.value.locationName + "§7): " + (if (it.value.hasMetRequirements()) "§a" else "§c") + - it.value.foundCount + "§7/§a" + it.value.requiredCount + val tips = locationRabbitRequirements.map { (name, rabbit) -> + "$name §7(§e${rabbit.locationName}§7): ${ + if (rabbit.hasMetRequirements()) "§a" else "§c" + }${rabbit.foundCount}§7/§a${rabbit.requiredCount}" } newList.add( @@ -286,7 +435,7 @@ object HoppityCollectionStats { add("§7Total Rabbits Found: §a${displayFound + displayDuplicates}") add("") add("§7Chocolate Per Second: §a${displayChocolatePerSecond.addSeparators()}") - add("§7Chocolate Multiplier: §a${displayChocolateMultiplier.round(3)}") + add("§7Chocolate Multiplier: §a${displayChocolateMultiplier.roundTo(3)}") } table.add( DisplayTableEntry( @@ -301,17 +450,21 @@ object HoppityCollectionStats { return table } - fun incrementRabbit(name: String) { + fun getRabbitCount(name: String): Int = name.removeColor().run { + loggedRabbits[this]?.takeIf { HoppityCollectionData.isKnownRabbit(this) } ?: 0 + } + + fun incrementRabbitCount(name: String) { val rabbit = name.removeColor() if (!HoppityCollectionData.isKnownRabbit(rabbit)) return - loggedRabbits[rabbit] = (loggedRabbits[rabbit] ?: 0) + 1 + loggedRabbits.addOrPut(rabbit, 1) } // 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) { + rabbitsFoundPattern.firstMatcher(it.value.getLore()) { group("current").formatInt() } } @@ -354,7 +507,7 @@ object HoppityCollectionStats { if (!found) continue - val duplicates = itemLore.matchFirst(duplicatesFoundPattern) { + val duplicates = duplicatesFoundPattern.firstMatcher(itemLore) { group("duplicates").formatInt() } ?: 0 @@ -362,7 +515,6 @@ object HoppityCollectionStats { } } - // bugfix for some weird potential user errors (e.g. if users play on alpha and get rabbits) fun clearSavedRabbits() { loggedRabbits.clear() diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt index 0d5bfefa8878..468fecbcb480 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggLocator.kt @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.features.event.hoppity +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.data.ClickType import at.hannibal2.skyhanni.data.IslandGraphs import at.hannibal2.skyhanni.events.DebugDataCollectEvent @@ -8,6 +9,7 @@ import at.hannibal2.skyhanni.events.LorenzRenderWorldEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.ReceiveParticleEvent +import at.hannibal2.skyhanni.events.hoppity.EggFoundEvent import at.hannibal2.skyhanni.features.fame.ReminderUtils import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -17,10 +19,10 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RecalculatingValue import at.hannibal2.skyhanni.utils.RenderUtils.draw3DLine import at.hannibal2.skyhanni.utils.RenderUtils.drawColor @@ -59,6 +61,11 @@ object HoppityEggLocator { var currentEggType: HoppityEggType? = null var currentEggNote: String? = null + @HandleEvent + fun onEggFound(event: EggFoundEvent) { + if (event.type.isResetting) resetData() + } + @SubscribeEvent fun onWorldChange(event: LorenzWorldChangeEvent) { resetData() @@ -168,10 +175,6 @@ object HoppityEggLocator { private fun shouldShowAllEggs() = config.showAllWaypoints && !locatorInHotbar && HoppityEggType.eggsRemaining() - fun eggFound() { - resetData() - } - @SubscribeEvent fun onReceiveParticle(event: ReceiveParticleEvent) { if (!isEnabled()) return @@ -246,7 +249,7 @@ object HoppityEggLocator { }.sortedBy { it.second } eggLocationWeights = sortedEggs.map { - it.second.round(3) + it.second.roundTo(3) }.take(5) val filteredEggs = sortedEggs.filter { diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggType.kt b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggType.kt index 23e00cf88cdb..5371816e1319 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggType.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/event/hoppity/HoppityEggType.kt @@ -17,7 +17,8 @@ enum class HoppityEggType( SIDE_DISH("Side Dish", "§6§l", -1), BOUGHT("Bought", "§a", -1), CHOCOLATE_SHOP_MILESTONE("Shop Milestone", "§6", -1), - CHOCOLATE_FACTORY_MILESTONE("Chocolate Milestone", "§6", -1) + CHOCOLATE_FACTORY_MILESTONE("Chocolate Milestone", "§6", -1), + STRAY("Stray Rabbit", "§a", -1) ; fun timeUntil(): Duration { @@ -39,6 +40,7 @@ enum class HoppityEggType( } fun isClaimed() = claimed + val isResetting get() = resettingEntries.contains(this) val formattedName get() = "${if (isClaimed()) "§7§m" else mealColor}$mealName:$mealColor" val coloredName get() = "$mealColor$mealName" 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 6bc1c8dfc276..4a33820d8d55 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 @@ -1,25 +1,34 @@ package at.hannibal2.skyhanni.features.event.hoppity +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.features.event.hoppity.HoppityEggsConfig import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.hoppity.EggFoundEvent +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.BOUGHT import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.CHOCOLATE_FACTORY_MILESTONE import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.CHOCOLATE_SHOP_MILESTONE import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.SIDE_DISH -import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager.eggFoundPatterns +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType.STRAY +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager.eggFoundPattern import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager.getEggType import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow import at.hannibal2.skyhanni.utils.TimeUtils.format +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds typealias RarityType = HoppityEggsConfig.CompactRarityTypes +@SkyHanniModule object HoppityEggsCompactChat { private var hoppityEggChat = mutableListOf() @@ -30,31 +39,32 @@ object HoppityEggsCompactChat { private var newRabbit = false private var lastChatMeal: HoppityEggType? = null private var lastDuplicateAmount: Long? = null - private var rabbitBought = false private val config get() = ChocolateFactoryAPI.config + private val eventConfig get() = SkyHanniMod.feature.event.hoppityEggs - fun compactChat(event: LorenzChatEvent, lastDuplicateAmount: Long? = null) { + fun compactChat(event: LorenzChatEvent? = null, lastDuplicateAmount: Long? = null) { + if (!HoppityEggsManager.config.compactChat) return lastDuplicateAmount?.let { this.lastDuplicateAmount = it - } - if (!HoppityEggsManager.config.compactChat) return - event.blockedReason = "compact_hoppity" - hoppityEggChat.add(event.message) - if (lastDuplicateAmount != null) { this.duplicate = true } - if (hoppityEggChat.size == 3) { - DelayedRun.runDelayed(200.milliseconds) { - sendCompact() - } + event?.let { + it.blockedReason = "compact_hoppity" + hoppityEggChat.add(it.message) } + if (hoppityEggChat.size == 3) sendCompact() } private fun sendCompact() { - if (hoppityEggChat.isNotEmpty()) { + if (lastChatMeal.let { HoppityEggType.resettingEntries.contains(it) } && eventConfig.sharedWaypoints) { + DelayedRun.runDelayed(5.milliseconds) { + clickableCompact(HoppityEggsManager.getAndDisposeWaypointOnclick()) + resetCompactData() + } + } else { ChatUtils.hoverableChat(createCompactMessage(), hover = hoppityEggChat, prefix = false) + resetCompactData() } - resetCompactData() } private fun resetCompactData() { @@ -66,15 +76,16 @@ object HoppityEggsCompactChat { this.lastProfit = "" this.lastChatMeal = null this.lastDuplicateAmount = null - this.rabbitBought = false } private fun createCompactMessage(): String { - val mealName = lastChatMeal?.coloredName ?: "" - val mealNameFormatted = if (rabbitBought) "§aBought Rabbit" - else if (lastChatMeal == SIDE_DISH) "§6§lSide Dish §r§6Egg" - else if (lastChatMeal == CHOCOLATE_SHOP_MILESTONE || lastChatMeal == CHOCOLATE_FACTORY_MILESTONE) "§6§lMilestone Rabbit" - else "$mealName Egg" + val mealNameFormat = when (lastChatMeal) { + BOUGHT -> "§aBought Rabbit" + SIDE_DISH -> "§6§lSide Dish §r§6Egg" + CHOCOLATE_SHOP_MILESTONE, CHOCOLATE_FACTORY_MILESTONE -> "§6§lMilestone Rabbit" + STRAY -> "§aStray Rabbit" + else -> "${lastChatMeal?.coloredName ?: ""} Egg" + } val rarityConfig = HoppityEggsManager.config.rarityInCompact return if (duplicate) { @@ -83,41 +94,80 @@ object HoppityEggsCompactChat { ChocolateFactoryAPI.timeUntilNeed(it).format(maxUnits = 2) } ?: "?" + val dupeNumberFormat = if (eventConfig.showDuplicateNumber) { + (HoppityCollectionStats.getRabbitCount(this.lastName) - 1).takeIf { it > 1}?.let { + " §7(§b#$it§7)" + } ?: "" + } else "" + val showDupeRarity = rarityConfig.let { it == RarityType.BOTH || it == RarityType.DUPE } val timeStr = if (config.showDuplicateTime) ", §a+§b$timeFormatted§7" else "" - "$mealNameFormatted! §7Duplicate ${if (showDupeRarity) "$lastRarity " else ""}$lastName §7(§6+$format Chocolate§7$timeStr)" + "$mealNameFormat! §7Duplicate ${if (showDupeRarity) "$lastRarity " else ""}$lastName$dupeNumberFormat §7(§6+$format Chocolate§7$timeStr)" } else if (newRabbit) { val showNewRarity = rarityConfig.let { it == RarityType.BOTH || it == RarityType.NEW } - "$mealNameFormatted! §d§lNEW ${if (showNewRarity) "$lastRarity " else ""}$lastName §7(${lastProfit}§7)" + "$mealNameFormat! §d§lNEW ${if (showNewRarity) "$lastRarity " else ""}$lastName §7(${lastProfit}§7)" } else "?" } - fun handleChat(event: LorenzChatEvent) { - eggFoundPatterns.forEach { - it.matchMatcher(event.message) { - resetCompactData() - lastChatMeal = getEggType(event) - compactChat(event) - } + private fun clickableCompact(onClick: () -> Unit) { + val hover = hoppityEggChat.joinToString("\n") + " \n§eClick here to share the location of this chocolate egg with the server!" + hoppityEggChat.clear() + ChatUtils.clickableChat( + createCompactMessage(), + hover = hover, + onClick = onClick, + expireAt = 30.seconds.fromNow(), + oneTimeClick = true, + prefix = false, + ) + } + + @HandleEvent + fun onEggFound(event: EggFoundEvent) { + if (!HoppityEggsManager.config.compactChat || HoppityEggType.resettingEntries.contains(event.type) || event.type == BOUGHT) return + lastChatMeal = event.type + hoppityEggChat.add( + when (event.type) { + SIDE_DISH -> + "§d§lHOPPITY'S HUNT §r§dYou found a §r§6§lSide Dish §r§6Egg §r§din the Chocolate Factory§r§d!" + + CHOCOLATE_FACTORY_MILESTONE -> + "§d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§lChocolate Milestone Rabbit §r§din the Chocolate Factory§r§d!" + + CHOCOLATE_SHOP_MILESTONE -> + "§d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§lShop Milestone Rabbit §r§din the Chocolate Factory§r§d!" + + STRAY -> { + "§d§lHOPPITY'S HUNT §r§dYou found a §r§aStray Rabbit§r§d!".also { + // If it was an El Dorado dupe stray, we don't want hanging data + DelayedRun.runDelayed(300.milliseconds) { resetCompactData() } + } + } + + else -> + "§d§lHOPPITY'S HUNT §r§7Unknown Egg Type?" + }, + ) + if (hoppityEggChat.size == 3) sendCompact() + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!LorenzUtils.inSkyBlock) return + eggFoundPattern.matchMatcher(event.message) { + resetCompactData() + lastChatMeal = getEggType(event) + compactChat(event) } HoppityEggsManager.eggBoughtPattern.matchMatcher(event.message) { if (group("rabbitname").equals(lastName)) { - rabbitBought = true + lastChatMeal = BOUGHT compactChat(event) } } HoppityEggsManager.rabbitFoundPattern.matchMatcher(event.message) { - // The only cases where "You found ..." will come in with more than 1 message, - // or empty for hoppityEggChat, is where the rabbit was purchased from hoppity, - // In the case of buying, we want to reset variables to a clean state during this capture, - // as the important capture for the purchased message is the final message in - // the chain; "You found [rabbit]" -> "Dupe/New Rabbit" -> "You bought [rabbit]" - if ((hoppityEggChat.isEmpty() || hoppityEggChat.size > 1)) { - resetCompactData() - } - lastName = group("name") lastRarity = group("rarity") compactChat(event) @@ -138,20 +188,4 @@ object HoppityEggsCompactChat { compactChat(event) } } - - fun clickableCompact(onClick: () -> Unit): Boolean = if (hoppityEggChat.isNotEmpty() && !rabbitBought && lastChatMeal != null && - HoppityEggType.resettingEntries.contains(lastChatMeal) - ) { - val hover = hoppityEggChat.joinToString("\n") + " \n§eClick here to share the location of this chocolate egg with the server!" - hoppityEggChat.clear() - ChatUtils.clickableChat( - createCompactMessage(), - hover = hover, - onClick = onClick, - expireAt = 30.seconds.fromNow(), - oneTimeClick = true, - prefix = false, - ) - true - } else false } 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 bec966128dd3..b8143d311cf2 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 @@ -1,10 +1,13 @@ package at.hannibal2.skyhanni.features.event.hoppity import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.events.hoppity.EggFoundEvent +import at.hannibal2.skyhanni.events.hoppity.RabbitFoundEvent import at.hannibal2.skyhanni.features.fame.ReminderUtils import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -21,11 +24,9 @@ import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.now import at.hannibal2.skyhanni.utils.SkyBlockTime import at.hannibal2.skyhanni.utils.SoundUtils -import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TimeUtils.format import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import java.util.regex.Matcher -import java.util.regex.Pattern import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds @@ -38,36 +39,12 @@ object HoppityEggsManager { * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou found a §r§9Chocolate Lunch Egg §r§don a ledge next to the stairs up§r§d! * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou found a §r§aChocolate Dinner Egg §r§dbehind Emissary Sisko§r§d! * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou found a §r§9Chocolate Lunch Egg §r§dnear the Diamond Essence Shop§r§d! - * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou found a §r§6§lSide Dish §r§6Egg §r§din the Chocolate Factory§r§d! */ - private val eggFoundPattern by ChocolateFactoryAPI.patternGroup.pattern( + val eggFoundPattern by ChocolateFactoryAPI.patternGroup.pattern( "egg.found", "§d§lHOPPITY'S HUNT §r§dYou found a §r§.Chocolate (?\\w+) Egg §r§d(?.*)§r§d!", ) - /** - * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou found a §r§6§lSide Dish §r§6Egg §r§din the Chocolate Factory§r§d! - */ - private val sideDishEggFoundPattern by ChocolateFactoryAPI.patternGroup.pattern( - "sidedish.found", - "§d§lHOPPITY'S HUNT §r§dYou found a §r§6§l(?.*) §r§6Egg §r§din the Chocolate Factory§r§d!", - ) - - /** - * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§lShop Milestone Rabbit §r§din the Chocolate Factory§r§d! - * REGEX-TEST: §d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§lChocolate Milestone Rabbit §r§din the Chocolate Factory§r§d! - */ - private val milestoneRabbitFoundPattern by ChocolateFactoryAPI.patternGroup.pattern( - "milestone.claimed", - "§d§lHOPPITY'S HUNT §r§dYou claimed a §r§6§l(?[\\w ]+) Rabbit §r§din the Chocolate Factory§r§d!", - ) - - val eggFoundPatterns: List = listOf( - eggFoundPattern, - sideDishEggFoundPattern, - milestoneRabbitFoundPattern, - ) - /** * REGEX-TEST: §aYou bought §r§9Casanova §r§afor §r§6970,000 Coins§r§a! * REGEX-TEST: §aYou bought §r§fHeidie §r§afor §r§6194,000 Coins§r§a! @@ -126,12 +103,28 @@ object HoppityEggsManager { private var warningActive = false private var lastWarnTime = SimpleTimeMark.farPast() + private var latestWaypointOnclick: () -> Unit = {} + @SubscribeEvent fun onWorldChange(event: LorenzWorldChangeEvent) { lastMeal = null lastNote = null } + @HandleEvent + fun onEggFound(event: EggFoundEvent) { + if (!HoppityAPI.isHoppityEvent() || !event.type.isResetting) return + HoppityEggLocations.saveNearestEgg() + event.type.markClaimed() + lastMeal = event.type + lastNote = event.note + } + + @HandleEvent + fun onRabbitFound(event: RabbitFoundEvent) { + HoppityCollectionStats.incrementRabbitCount(event.rabbitName) + } + @SubscribeEvent fun onChat(event: LorenzChatEvent) { if (!LorenzUtils.inSkyBlock) return @@ -147,22 +140,8 @@ object HoppityEggsManager { return } - HoppityEggsCompactChat.handleChat(event) - HoppityAPI.handleChat(event) - if (!HoppityAPI.isHoppityEvent()) return - eggFoundPattern.matchMatcher(event.message) { - HoppityEggLocations.saveNearestEgg() - HoppityEggLocator.eggFound() - val meal = getEggType(event) - val note = group("note").removeColor() - meal.markClaimed() - lastMeal = meal - lastNote = note - return - } - noEggsLeftPattern.matchMatcher(event.message) { HoppityEggType.allFound() @@ -188,10 +167,6 @@ object HoppityEggsManager { getEggType(event).markSpawned() return } - - rabbitFoundPattern.matchMatcher(event.message) { - HoppityCollectionStats.incrementRabbit(group("name")) - } } internal fun Matcher.getEggType(event: LorenzChatEvent): HoppityEggType = @@ -202,6 +177,12 @@ object HoppityEggsManager { ) } + fun getAndDisposeWaypointOnclick(): () -> Unit { + val onClick = latestWaypointOnclick + latestWaypointOnclick = {} + return onClick + } + fun shareWaypointPrompt() { if (!config.sharedWaypoints) return val meal = lastMeal ?: return @@ -211,16 +192,16 @@ object HoppityEggsManager { val currentLocation = LocationUtils.playerLocation() DelayedRun.runNextTick { - val onClick = { HoppityEggsShared.shareNearbyEggLocation(currentLocation, meal, note) } - if (!HoppityEggsCompactChat.clickableCompact(onClick)) { - ChatUtils.clickableChat( - "Click here to share the location of this chocolate egg with the server!", - onClick = onClick, - "§eClick to share!", - expireAt = 30.seconds.fromNow(), - oneTimeClick = true, - ) - } + latestWaypointOnclick = { HoppityEggsShared.shareNearbyEggLocation(currentLocation, meal, note) } + if (config.compactChat) return@runNextTick + ChatUtils.clickableChat( + "Click here to share the location of this chocolate egg with the server!", + onClick = latestWaypointOnclick, + "§eClick to share!", + expireAt = 30.seconds.fromNow(), + oneTimeClick = true, + ) + latestWaypointOnclick = {} } } @@ -252,7 +233,7 @@ object HoppityEggsManager { val message = "All $amount Hoppity Eggs are ready to be found!" if (config.warpUnclaimedEggs) { val (action, actionName) = if (LorenzUtils.inSkyBlock) { - { HypixelCommands.warp(config.warpDestination) } to "${"warp to ${config.warpDestination}".trim()}" + { HypixelCommands.warp(config.warpDestination) } to "warp to ${config.warpDestination}".trim() } else { { HypixelCommands.skyblock() } to "join /skyblock!" } diff --git a/src/main/java/at/hannibal2/skyhanni/features/event/winter/ReindrakeWarpHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/event/winter/ReindrakeWarpHelper.kt new file mode 100644 index 000000000000..30a1b87e8682 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/event/winter/ReindrakeWarpHelper.kt @@ -0,0 +1,43 @@ +package at.hannibal2.skyhanni.features.event.winter + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object ReindrakeWarpHelper { + + private val config get() = SkyHanniMod.feature.event.winter + + private val patternGroup = RepoPattern.group("event.winter.reindrakewarphelper") + + /** + * REGEX-TEST: §c§lWOAH! §cA §4Reindrake §cwas summoned from the depths! + * REGEX-TEST: §c§lWOAH! §r§cA §r§4Reindrake §r§cwas summoned from the depths! + */ + private val spawnPattern by patternGroup.pattern( + "spawn.message", + "§c§lWOAH! (?:§r)?§cA (?:§r)?§4Reindrake (?:§r)?§cwas summoned from the depths!", + ) + + @SubscribeEvent + fun onMessage(event: LorenzChatEvent) { + if (!isEnabled()) return + if (!spawnPattern.matches(event.message)) return + ChatUtils.clickToActionOrDisable( + "A Reindrake was detected. Click to warp to the Winter Island spawn!", + config::reindrakeWarpHelper, + actionName = "warp to winter island spawn", + action = { HypixelCommands.warp("winter") } + ) + } + + fun isEnabled() = IslandType.WINTER.isInIsland() && config.reindrakeWarpHelper +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt b/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt index 0410a04a91d0..9896580c6b2b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/fishing/TotemOfCorruption.kt @@ -22,6 +22,7 @@ import at.hannibal2.skyhanni.utils.RenderUtils.drawSphereInWorld import at.hannibal2.skyhanni.utils.RenderUtils.drawSphereWireframeInWorld import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings import at.hannibal2.skyhanni.utils.SoundUtils.playPlingSound +import at.hannibal2.skyhanni.utils.TimeLimitedSet import at.hannibal2.skyhanni.utils.TimeUnit import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.getLorenzVec @@ -29,7 +30,9 @@ import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.entity.item.EntityArmorStand import net.minecraft.util.EnumParticleTypes import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.UUID import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.seconds @SkyHanniModule @@ -39,6 +42,7 @@ object TotemOfCorruption { private var display = emptyList() private var totems: List = emptyList() + private val warnedTotems = TimeLimitedSet(2.minutes) private val patternGroup = RepoPattern.group("fishing.totemofcorruption") private val totemNamePattern by patternGroup.pattern( @@ -154,9 +158,10 @@ object TotemOfCorruption { val owner = getOwner(totem) ?: return@mapNotNull null val timeToWarn = config.warnWhenAboutToExpire.seconds - if (timeToWarn > 0.seconds && timeRemaining == timeToWarn) { + if (timeToWarn > 0.seconds && timeRemaining <= timeToWarn && totem.uniqueID !in warnedTotems) { playPlingSound() sendTitle("§c§lTotem of Corruption §eabout to expire!", 5.seconds) + warnedTotems.add(totem.uniqueID) } Totem(totem.getLorenzVec(), timeRemaining, owner) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt index 29b92f24afd8..55898266e440 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/FarmingFortuneDisplay.kt @@ -17,9 +17,9 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter import at.hannibal2.skyhanni.utils.HypixelCommands import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables @@ -167,7 +167,7 @@ object FarmingFortuneDisplay { list.add( Renderable.string( "§6Farming Fortune§7: §e" + if (!recentlySwitchedTool && farmingFortune != -1.0) { - farmingFortune.round(0).addSeparators() + farmingFortune.roundTo(0).addSeparators() } else "§7" + (displayCrop.getLatestTrueFarmingFortune()?.addSeparators() ?: "?"), ), ) diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt index e188dcfd0d56..4e80bdbea678 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenAPI.kt @@ -90,7 +90,7 @@ object GardenAPI { "BINGHOE", ) - @HandleEvent(onlyOnIslands = [IslandType.GARDEN]) + @HandleEvent(onlyOnIsland = IslandType.GARDEN) fun onSendPacket(event: PacketSentEvent) { if (event.packet !is C09PacketHeldItemChange) return checkItemInHand() diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt index 8c2dc9a95e08..4285a24af969 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenNextJacobContest.kt @@ -15,7 +15,7 @@ import at.hannibal2.skyhanni.events.TabListUpdateEvent import at.hannibal2.skyhanni.features.garden.GardenAPI.addCropIcon import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ConfigUtils import at.hannibal2.skyhanni.utils.HypixelCommands @@ -32,10 +32,10 @@ import at.hannibal2.skyhanni.utils.SoundUtils import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TabListData import at.hannibal2.skyhanni.utils.TimeUtils.format +import at.hannibal2.skyhanni.utils.json.toJsonArray import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import com.google.gson.Gson import com.google.gson.JsonPrimitive -import io.github.moulberry.notenoughupdates.util.toJsonArray import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -543,7 +543,7 @@ object GardenNextJacobContest { suspend fun fetchUpcomingContests() { try { val url = "https://api.elitebot.dev/contests/at/now" - val result = withContext(dispatcher) { APIUtil.getJSONResponse(url) }.asJsonObject + val result = withContext(dispatcher) { APIUtils.getJSONResponse(url) }.asJsonObject val newContests = mutableMapOf() @@ -613,7 +613,7 @@ object GardenNextJacobContest { val url = "https://api.elitebot.dev/contests/at/now" val body = Gson().toJson(formatted) - val result = withContext(dispatcher) { APIUtil.postJSONIsSuccessful(url, body) } + val result = withContext(dispatcher) { APIUtils.postJSONIsSuccessful(url, body) } if (result) { ChatUtils.chat("Successfully submitted this years upcoming contests, thank you for helping everyone out!") diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt index 3ae865ac82a1..8ad8d21dab1a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenPlotAPI.kt @@ -72,9 +72,14 @@ object GardenPlotAPI { "spray.target", "§a§lSPRAYONATOR! §r§7You sprayed §r§aPlot §r§7- §r§b(?.*) §r§7with §r§a(?.*)§r§7!" ) + + /** + * REGEX-TEST: §9§lSPLASH! §r§6Your §r§aGarden §r§6was cleared of all active §r§aSprayonator §r§6effects! + * REGEX-TEST: §9§lSPLASH! §r§6Your §r§bGarden §r§6was cleared of all active §r§aSprayonator §r§6effects! + */ private val portableWasherPattern by patternGroup.pattern( "spray.cleared.portablewasher", - "§9§lSPLASH! §r§6Your §r§bGarden §r§6was cleared of all active §r§aSprayonator §r§6effects!" + "§9§lSPLASH! §r§6Your §r§[ba]Garden §r§6was cleared of all active §r§aSprayonator §r§6effects!" ) var plots = listOf() diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenYawAndPitch.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenYawAndPitch.kt index cdbb07963d8d..171df87e70ab 100755 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/GardenYawAndPitch.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/GardenYawAndPitch.kt @@ -7,7 +7,7 @@ import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LocationUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings import at.hannibal2.skyhanni.utils.SimpleTimeMark import net.minecraft.client.Minecraft @@ -30,7 +30,7 @@ object GardenYawAndPitch { if (GardenAPI.toolInHand == null && !config.showWithoutTool) return val player = Minecraft.getMinecraft().thePlayer - var yaw = LocationUtils.calculatePlayerYaw() + val yaw = LocationUtils.calculatePlayerYaw() val pitch = player.rotationPitch if (yaw != lastYaw || pitch != lastPitch) { @@ -41,8 +41,8 @@ object GardenYawAndPitch { if (!config.showAlways && lastChange.passedSince() > config.timeout.seconds) return - val yawText = yaw.round(config.yawPrecision).toBigDecimal().toPlainString() - val pitchText = pitch.round(config.pitchPrecision).toBigDecimal().toPlainString() + val yawText = yaw.roundTo(config.yawPrecision).toBigDecimal().toPlainString() + val pitchText = pitch.roundTo(config.pitchPrecision).toBigDecimal().toPlainString() val displayList = listOf( "§aYaw: §f$yawText", "§aPitch: §f$pitchText", diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt index cebbeef08a71..058ae15909f9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterDisplay.kt @@ -180,7 +180,7 @@ object ComposterDisplay { val outsideSb = !LorenzUtils.inSkyBlock && OutsideSbFeature.COMPOSTER_TIME.isSelected() if (!GardenAPI.inGarden() && (inSb || outsideSb)) { val list = Collections.singletonList(listOf(bucket, "§b$format")) - config.outsideGardenPos.renderStringsAndItems(list, posLabel = "Composter Outside Garden Display") + config.outsideGardenPos.renderStringsAndItems(list, posLabel = "Composter Outside Garden") } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt index aee2a93f428f..fa45e579dfa3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/composter/ComposterOverlay.kt @@ -31,7 +31,6 @@ import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.KeyboardManager import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.addSelector -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.NONE import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName @@ -41,6 +40,7 @@ import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNecessary import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -338,10 +338,10 @@ object ComposterOverlay { val multiplier = multiDropFactor * timeMultiplier val multiplierPreview = multiDropFactorPreview * timeMultiplierPreview val compostPerTitlePreview = - if (multiplier != multiplierPreview) " §c➜ §e" + multiplierPreview.round(2) else "" + if (multiplier != multiplierPreview) " §c➜ §e" + multiplierPreview.roundTo(2) else "" val compostPerTitle = if (currentTimeType == TimeType.COMPOST) "Compost multiplier" else "Composts per $timeText" - newList.addAsSingletonList(" §7$compostPerTitle: §e${multiplier.round(2)}$compostPerTitlePreview") + newList.addAsSingletonList(" §7$compostPerTitle: §e${multiplier.roundTo(2)}$compostPerTitlePreview") val organicMatterPrice = getPrice(organicMatterItem) val organicMatterFactor = organicMatterFactors[organicMatterItem]!! diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt index 7d009629b7c9..a2e8a859f703 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/FarmingPersonalBestGain.kt @@ -6,8 +6,8 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.DelayedRun -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -88,7 +88,7 @@ object FarmingPersonalBestGain { val oldFF = oldCollected / collectionPerFF val ffDiff = newFF - oldFF - ChatUtils.chat("This is §6${ffDiff.round(2)}☘ $crop Fortune §emore than previously!") + ChatUtils.chat("This is §6${ffDiff.roundTo(2)}☘ $crop Fortune §emore than previously!") } fun isEnabled() = GardenAPI.inGarden() && config.contestPersonalBestIncreaseFF diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestFFNeededDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestFFNeededDisplay.kt index 963193c4ba74..5d9b7f92f34e 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestFFNeededDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestFFNeededDisplay.kt @@ -12,8 +12,8 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.addAsSingletonList import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.SimpleTimeMark import net.minecraft.item.ItemStack @@ -81,7 +81,7 @@ object JacobContestFFNeededDisplay { addAsSingletonList("§cassuming 19.9 instead.") } else { if (blocksPerSecond < 15.0) { - add(listOf("§7Your latest ", crop.icon, "§7blocks/second: §e${blocksPerSecond.round(2)}")) + add(listOf("§7Your latest ", crop.icon, "§7blocks/second: §e${blocksPerSecond.roundTo(2)}")) add(listOf("§cThis is too low, showing 19.9 Blocks/second instead!")) blocksPerSecond = 19.9 } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestStatsSummary.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestStatsSummary.kt index 3d4fef9a3c66..144abc0c2486 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestStatsSummary.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestStatsSummary.kt @@ -6,8 +6,8 @@ import at.hannibal2.skyhanni.events.FarmingContestEvent import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.TimeUtils.format import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -41,7 +41,7 @@ object JacobContestStatsSummary { FarmingContestPhase.STOP -> { val duration = startTime.passedSince() - val blocksPerSecond = (blocksBroken.toDouble() / duration.inWholeSeconds).round(2) + val blocksPerSecond = (blocksBroken.toDouble() / duration.inWholeSeconds).roundTo(2) val cropName = event.crop.cropName ChatUtils.chat("Stats for $cropName Contest:") val time = duration.format() diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestTimeNeeded.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestTimeNeeded.kt index 3e99c2683fd2..bb9f9ea21773 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestTimeNeeded.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/contest/JacobContestTimeNeeded.kt @@ -11,8 +11,8 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.addAsSingletonList import at.hannibal2.skyhanni.utils.CollectionUtils.sorted import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.addSelector -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.renderables.Renderable @@ -102,7 +102,7 @@ object JacobContestTimeNeeded { return } - val speed = (ff * crop.baseDrops * bps / 100).round(1).toInt() + val speed = (ff * crop.baseDrops * bps / 100).roundTo(1).toInt() renderCrop(speed, crop, averages, sorted, map) } @@ -174,7 +174,7 @@ object JacobContestTimeNeeded { add("") val latestFF = crop.getLatestTrueFarmingFortune() ?: 0.0 add("§7Latest FF: §e${(latestFF).addSeparators()}") - val bps = crop.getBps()?.round(1) ?: 0 + val bps = crop.getBps()?.roundTo(1) ?: 0 add("§7${addBpsTitle()}§e${bps.addSeparators()}") addAll(lowBPSWarning) }) diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt index aa977b65a575..74c59674f580 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/CropSpeedMeter.kt @@ -9,8 +9,8 @@ import at.hannibal2.skyhanni.features.garden.CropType import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -91,7 +91,7 @@ object CropSpeedMeter { currentCrop?.let { val crops = it.getCounter() - startCrops[it]!! val blocks = currentBlocks - val cropsPerBlocks = (crops.toDouble() / blocks.toDouble()).round(3) + val cropsPerBlocks = (crops.toDouble() / blocks.toDouble()).roundTo(3) val list = mutableListOf() list.add("") @@ -101,7 +101,7 @@ object CropSpeedMeter { list.add(" §7Crops per Block: " + cropsPerBlocks.addSeparators()) val baseDrops = it.baseDrops - val farmingFortune = (cropsPerBlocks * 100 / baseDrops).round(3) + val farmingFortune = (cropsPerBlocks * 100 / baseDrops).roundTo(3) list.add(" §7Calculated farming Fortune: §e" + farmingFortune.addSeparators()) list.add("§cOpen /cropmilestones again to recalculate!") diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt index 222e75f4f296..da461d749604 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/FarmingWeightDisplay.kt @@ -20,11 +20,11 @@ import at.hannibal2.skyhanni.features.garden.farming.GardenCropSpeed.getSpeed import at.hannibal2.skyhanni.features.garden.pests.PestType import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.OSUtils import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -234,7 +234,7 @@ object FarmingWeightDisplay { } val totalWeight = (localWeight + weight) - return "§e" + totalWeight.round(2).addSeparators() + return "§e" + totalWeight.roundTo(2).addSeparators() } private fun getRankGoal(): Int { @@ -326,7 +326,7 @@ object FarmingWeightDisplay { " §7(§b$format§7)" } else "" - val weightFormat = weightUntilOvertake.round(2).addSeparators() + val weightFormat = weightUntilOvertake.roundTo(2).addSeparators() val text = "§e$weightFormat$timeFormat §7behind §b$nextName" return if (showRankGoal) { Renderable.string(text) @@ -447,7 +447,7 @@ object FarmingWeightDisplay { val atRank = if (isEtaEnabled() && goalRank != 10001) "&atRank=$goalRank" else "" val url = "https://api.elitebot.dev/leaderboard/rank/farmingweight/$uuid/$profileId$includeUpcoming$atRank" - val apiResponse = APIUtil.getJSONResponse(url) + val apiResponse = APIUtils.getJSONResponse(url) try { val apiData = toEliteLeaderboardJson(apiResponse).data @@ -477,7 +477,7 @@ object FarmingWeightDisplay { private fun loadWeight(localProfile: String) { val uuid = LorenzUtils.getPlayerUuid() val url = "https://api.elitebot.dev/weight/$uuid" - val apiResponse = APIUtil.getJSONResponse(url) + val apiResponse = APIUtils.getJSONResponse(url) var error: Throwable? = null @@ -573,7 +573,7 @@ object FarmingWeightDisplay { if (attemptingCropWeightFetch || hasFetchedCropWeights) return attemptingCropWeightFetch = true val url = "https://api.elitebot.dev/weights/all" - val apiResponse = APIUtil.getJSONResponse(url) + val apiResponse = APIUtils.getJSONResponse(url) try { val apiData = eliteWeightApiGson.fromJson(apiResponse) diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt index c37eb41b7cdf..7189199a9987 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/GardenCropMilestoneDisplay.kt @@ -26,8 +26,8 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.addString import at.hannibal2.skyhanni.utils.ConditionalUtils import at.hannibal2.skyhanni.utils.ConfigUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -187,7 +187,7 @@ object GardenCropMilestoneDisplay { val farmingFortune = FarmingFortuneDisplay.getCurrentFarmingFortune() val speed = GardenCropSpeed.averageBlocksPerSecond - val farmingFortuneSpeed = ((100.0 + farmingFortune) * crop.baseDrops * speed / 100).round(1).toInt() + val farmingFortuneSpeed = ((100.0 + farmingFortune) * crop.baseDrops * speed / 100).roundTo(1).toInt() if (farmingFortuneSpeed > 0) { crop.setSpeed(farmingFortuneSpeed) @@ -219,7 +219,7 @@ object GardenCropMilestoneDisplay { val hourFormat = (farmingFortuneSpeed * 60 * 60).addSeparators() lineMap[MilestoneTextEntry.CROPS_PER_HOUR] = Renderable.string("§7Crops/Hour§8: §e$hourFormat") - val formatBps = speed.round(config.blocksBrokenPrecision).addSeparators() + val formatBps = speed.roundTo(config.blocksBrokenPrecision).addSeparators() lineMap[MilestoneTextEntry.BLOCKS_PER_SECOND] = Renderable.string("§7Blocks/Second§8: §e$formatBps") } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/WildStrawberryDyeNotification.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/WildStrawberryDyeNotification.kt deleted file mode 100644 index 34b4191d4e46..000000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/WildStrawberryDyeNotification.kt +++ /dev/null @@ -1,48 +0,0 @@ -package at.hannibal2.skyhanni.features.garden.farming - -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.OwnInventoryItemUpdateEvent -import at.hannibal2.skyhanni.features.garden.GardenAPI -import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.ChatUtils -import at.hannibal2.skyhanni.utils.ItemBlink -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName -import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName -import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.SoundUtils -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.time.Duration.Companion.seconds - -@SkyHanniModule -object WildStrawberryDyeNotification { - - private var lastCloseTime = SimpleTimeMark.farPast() - - val item by lazy { "DYE_WILD_STRAWBERRY".asInternalName() } - - @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - lastCloseTime = SimpleTimeMark.now() - } - - @SubscribeEvent - fun onOwnInventoryItemUpdate(event: OwnInventoryItemUpdateEvent) { - if (!GardenAPI.inGarden()) return - if (!GardenAPI.config.wildStrawberryDyeNotification) return - // Prevent false positives when buying the item in ah or moving it from a storage - if (lastCloseTime.passedSince() < 1.seconds) return - - val itemStack = event.itemStack - - val internalName = itemStack.getInternalName() - if (internalName == item) { - val name = itemStack.name - LorenzUtils.sendTitle(name, 5.seconds) - ChatUtils.chat("You found a $name§e!") - SoundUtils.playBeepSound() - ItemBlink.setBlink(itemStack, 5_000) - } - } -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneFeatures.kt index cb63d40de1d8..e407d0ad4deb 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/farming/lane/FarmingLaneFeatures.kt @@ -14,8 +14,8 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.LocationUtils import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText import at.hannibal2.skyhanni.utils.RenderUtils.drawWaypointFilled import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings @@ -76,7 +76,7 @@ object FarmingLaneFeatures { if (config.distanceDisplay) { display = buildList { - add("§7Distance until switch: §e${currentDistance.round(1)}") + add("§7Distance until switch: §e${currentDistance.roundTo(1)}") val normal = movementState == MovementState.NORMAL val color = if (normal) "§b" else "§8" @@ -152,7 +152,7 @@ object FarmingLaneFeatures { private var sameSpeedCounter = 0 private fun calculateSpeed(): Boolean { - val speed = MovementSpeedDisplay.speed.round(2) + val speed = MovementSpeedDisplay.speed.roundTo(2) movementState = calculateMovementState(speed) if (movementState != MovementState.NORMAL) return false diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt index 7a2f8d415584..e0cb070739b9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/GardenCropMilestoneInventory.kt @@ -12,8 +12,8 @@ import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.indexOfFirst import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat import at.hannibal2.skyhanni.utils.StringUtils import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -35,7 +35,7 @@ object GardenCropMilestoneInventory { val tier = GardenCropMilestones.getTierForCropCount(counter, cropType, allowOverflow) tiers.add(tier.toDouble()) } - average = (tiers.sum() / CropType.entries.size).round(2) + average = (tiers.sum() / CropType.entries.size).roundTo(2) } @SubscribeEvent diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt index 5ef15090739a..078ef16724d2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/SkyMartCopperPrice.kt @@ -12,12 +12,12 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.ItemUtils.loreCosts import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NEUItems.getPriceOrNull import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatInt import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.renderables.Renderable @@ -115,7 +115,7 @@ object SkyMartCopperPrice { event.move(3, "garden.skyMartCopperPriceAdvancedStats", "garden.skyMart.copperPriceAdvancedStats") event.move(3, "garden.skyMartCopperPricePos", "garden.skyMart.copperPricePos") event.transform(32, "garden.skyMart.itemScale") { - JsonPrimitive((it.asDouble / 1.851).round(1)) + JsonPrimitive((it.asDouble / 1.851).roundTo(1)) } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/plots/GardenPlotIcon.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/plots/GardenPlotIcon.kt index 1fc378b7e890..01e9f87fb4df 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/plots/GardenPlotIcon.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/inventory/plots/GardenPlotIcon.kt @@ -8,10 +8,10 @@ import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.features.garden.GardenAPI import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ItemUtils.editItemInfo import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.NEUItems.getItemStack -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.client.player.inventory.ContainerLocalMenu import net.minecraft.init.Items import net.minecraft.item.ItemStack @@ -51,7 +51,7 @@ object GardenPlotIcon { for ((index, internalName) in plotList) { val old = originalStack[index]!! val new = internalName.getItemStack() - cachedStack[index] = Utils.editItemStackInfo(new, old.displayName, true, *old.getLore().toTypedArray()) + cachedStack[index] = new.editItemInfo(old.displayName, true, old.getLore()) } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestAPI.kt index 7aefb74cd37c..d49de324c851 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestAPI.kt @@ -158,7 +158,7 @@ object PestAPI { PestUpdateEvent().post() } - @HandleEvent(onlyOnIslands = [IslandType.GARDEN]) + @HandleEvent(onlyOnIsland = IslandType.GARDEN) fun onPestSpawn(event: PestSpawnEvent) { PestSpawnTimer.lastSpawnTime = SimpleTimeMark.now() val plotNames = event.plotNames diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleWaypoint.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleWaypoint.kt index d3dd8a27ba10..d07e55816732 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleWaypoint.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/pests/PestParticleWaypoint.kt @@ -86,7 +86,7 @@ object PestParticleWaypoint { val yellow = LorenzVec(0.8, 0.8, 0.0) val redPest = LorenzVec(0.8, 0.4, 0.0) val redPlot = LorenzVec(0.8, 0.0, 0.0) - isPointingToPest = when (event.offset.round(5)) { + isPointingToPest = when (event.offset.roundTo(5)) { redPlot -> false redPest, yellow, darkYellow -> true else -> return @@ -121,7 +121,7 @@ object PestParticleWaypoint { ++particles } - @HandleEvent(onlyOnIslands = [IslandType.GARDEN]) + @HandleEvent(onlyOnIsland = IslandType.GARDEN) fun onFireWorkSpawn(event: PacketReceivedEvent) { if (event.packet !is S0EPacketSpawnObject) return if (!config.hideParticles) return @@ -150,7 +150,7 @@ object PestParticleWaypoint { waypoint, color, 3, - false + false, ) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt index fef28450f719..70392bb46d78 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorFeatures.kt @@ -29,6 +29,7 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.CollectionUtils.addAsSingletonList +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.ConfigUtils import at.hannibal2.skyhanni.utils.EntityUtils import at.hannibal2.skyhanni.utils.HypixelCommands @@ -46,12 +47,12 @@ 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.allIngredients import at.hannibal2.skyhanni.utils.NEUItems.getItemStack import at.hannibal2.skyhanni.utils.NEUItems.getPrice import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatInt import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.PrimitiveIngredient.Companion.toPrimitiveItemStacks import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.drawString import at.hannibal2.skyhanni.utils.RenderUtils.renderStringsAndItems @@ -80,9 +81,14 @@ object GardenVisitorFeatures { private var display = emptyList>() private val patternGroup = RepoPattern.group("garden.visitor") + + /** + * REGEX-TEST: §a§r§aBanker Broadjaw §r§ehas arrived on your §r§aGarden§r§e! + * REGEX-TEST: §a§r§aBanker Broadjaw §r§ehas arrived on your §r§bGarden§r§e! + */ private val visitorArrivePattern by patternGroup.pattern( "visitorarrive", - ".* §r§ehas arrived on your §r§bGarden§r§e!", + ".* §r§ehas arrived on your §r§[ba]Garden§r§e!", ) private val copperPattern by patternGroup.pattern( "copper", @@ -245,19 +251,17 @@ object GardenVisitorFeatures { val ingredients = NEUItems.getRecipes(internalName) // TODO describe what this line does - .firstOrNull() { !it.allIngredients().first().internalItemId.contains("PEST") } - ?.allIngredients() ?: emptySet() + .firstOrNull { !it.ingredients.first().internalName.contains("PEST") } + ?.ingredients ?: emptySet() if (ingredients.isEmpty()) return - val requiredIngredients = mutableMapOf() - for (ingredient in ingredients) { - val key = ingredient.internalItemId - requiredIngredients[key] = - requiredIngredients.getOrDefault(key, 0) + ingredient.count.toInt() + val requiredIngredients = mutableMapOf() + for ((key, count) in ingredients.toPrimitiveItemStacks()) { + requiredIngredients.addOrPut(key, count) } var hasIngredients = true for ((key, value) in requiredIngredients) { - val sackItem = key.asInternalName().getAmountInSacks() + val sackItem = key.getAmountInSacks() if (sackItem < value * (amount - amountInSacks)) { hasIngredients = false break diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorSupercraft.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorSupercraft.kt index e10d1be36da4..9b14483dc476 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorSupercraft.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/GardenVisitorSupercraft.kt @@ -7,16 +7,15 @@ import at.hannibal2.skyhanni.events.garden.visitor.VisitorOpenEvent import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut import at.hannibal2.skyhanni.utils.HypixelCommands -import at.hannibal2.skyhanni.utils.ItemUtils.itemName +import at.hannibal2.skyhanni.utils.ItemUtils 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.allIngredients import at.hannibal2.skyhanni.utils.NEUItems.getItemStack +import at.hannibal2.skyhanni.utils.PrimitiveIngredient.Companion.toPrimitiveItemStacks import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.entity.player.InventoryPlayer import net.minecraftforge.fml.common.eventhandler.EventPriority import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -33,11 +32,11 @@ object GardenVisitorSupercraft { private val superCraftItem by lazy { val neuItem = "GOLD_PICKAXE".asInternalName().getItemStack() - Utils.createItemStack( + ItemUtils.createItemStack( neuItem.item, "§bSuper Craft", "§7You have the items to craft", - "§7Click me to open the super crafter!" + "§7Click me to open the super crafter!", ) } @@ -74,17 +73,16 @@ object GardenVisitorSupercraft { private fun getSupercraftForSacks(internalName: NEUInternalName, amount: Int) { val ingredients = NEUItems.getRecipes(internalName) // TODO describe what this line does - .firstOrNull { !it.allIngredients().first().internalItemId.contains("PEST") } - ?.allIngredients() ?: return - val ingredientReqs = mutableMapOf() - for (ingredient in ingredients) { - val key = ingredient.internalItemId - ingredientReqs[key] = ingredientReqs.getOrDefault(key, 0) + ingredient.count.toInt() + .firstOrNull { !it.ingredients.first().internalName.contains("PEST") } + ?.ingredients ?: return + val requiredIngredients = mutableMapOf() + for ((key, count) in ingredients.toPrimitiveItemStacks()) { + requiredIngredients.addOrPut(key, count) } hasIngredients = true - for ((key, value) in ingredientReqs) { - val sackItem = key.asInternalName().getAmountInSacks() - lastSuperCraftMaterial = internalName.itemName.removeColor() + for ((key, value) in requiredIngredients) { + val sackItem = key.getAmountInSacks() + lastSuperCraftMaterial = internalName.asString() if (sackItem < value * amount) { hasIngredients = false break @@ -109,7 +107,7 @@ object GardenVisitorSupercraft { if (event.slotId != 31) return event.cancel() if (lastClick.passedSince() > 0.3.seconds) { - HypixelCommands.recipe(lastSuperCraftMaterial) + HypixelCommands.viewRecipe(lastSuperCraftMaterial) lastClick = SimpleTimeMark.now() } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/HighlightVisitorsOutsideOfGarden.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/HighlightVisitorsOutsideOfGarden.kt index 88ea75b572b9..8a8c11165564 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/HighlightVisitorsOutsideOfGarden.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/HighlightVisitorsOutsideOfGarden.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.features.garden.visitor import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.features.garden.visitor.VisitorConfig.VisitorBlockBehaviour +import at.hannibal2.skyhanni.data.HypixelData import at.hannibal2.skyhanni.data.jsonobjects.repo.GardenJson import at.hannibal2.skyhanni.data.jsonobjects.repo.GardenVisitor import at.hannibal2.skyhanni.events.RepositoryReloadEvent @@ -19,7 +20,6 @@ import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzVec import at.hannibal2.skyhanni.utils.getLorenzVec import at.hannibal2.skyhanni.utils.toLorenzVec -import io.github.moulberry.notenoughupdates.util.SBInfo import net.minecraft.client.Minecraft import net.minecraft.entity.Entity import net.minecraft.entity.EntityLivingBase @@ -57,7 +57,8 @@ object HighlightVisitorsOutsideOfGarden { } private fun isVisitor(entity: Entity): Boolean { - val mode = SBInfo.getInstance().getLocation() + // todo migrate to Skyhanni IslandType + val mode = HypixelData.mode val possibleJsons = visitorJson[mode] ?: return false val skinOrType = getSkinOrTypeFor(entity) return possibleJsons.any { diff --git a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt index e709fcda7633..66d03745f372 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/garden/visitor/VisitorListener.kt @@ -56,7 +56,7 @@ object VisitorListener { } // TODO make event - @HandleEvent(onlyOnIslands = [IslandType.GARDEN]) + @HandleEvent(onlyOnIsland = IslandType.GARDEN) fun onSendEvent(event: PacketSentEvent) { val packet = event.packet if (packet !is C02PacketUseEntity) return @@ -136,7 +136,7 @@ object VisitorListener { inventory.handleMouseClick_skyhanni(slot, slot.slotIndex, 0, 0) } - @HandleEvent(onlyOnIslands = [IslandType.GARDEN]) + @HandleEvent(onlyOnIsland = IslandType.GARDEN) fun onTooltip(event: ItemHoverEvent) { if (!GardenAPI.onBarnPlot) return if (!VisitorAPI.inInventory) return 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 9e2694ec0d88..fb014cc29243 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 @@ -246,13 +246,17 @@ object ScoreboardPattern { "raffleuseless", "^(Find tickets on the|ground and bring them|to the raffle box)$", ) + + /** + * REGEX-TEST: Tickets: §a8 §7(17.4%) + */ val raffleTicketsPattern by miningSb.pattern( "raffletickets", - "^Tickets: §a\\d+ §7\\(\\d{1,3}\\.\\d%\\)$", + "Tickets: §a\\d+ §7\\(\\d+(\\.\\d)?%\\)", ) val rafflePoolPattern by miningSb.pattern( "rafflepool", - "^Pool: §6\\d+§8/500$", + "Pool: §6\\d+", ) val mithrilUselessPattern by miningSb.pattern( "mithriluseless", @@ -274,8 +278,13 @@ object ScoreboardPattern { "uselessgoblin", "^§7Kill goblins!$", ) + + /** + * REGEX-TEST: Remaining: §a1 goblin + * REGEX-TEST: Remaining: §a2 goblins + */ val remainingGoblinPattern by miningSb.pattern( - "remaininggoblin", "^Remaining: §a\\d+ goblins$", + "remaininggoblin", "^Remaining: §a\\d+ goblins?$", ) val yourGoblinKillsPattern by miningSb.pattern( "yourgoblin", "^Your kills: §c\\d+ ☠( §a\\(\\+\\d+\\))?$", @@ -303,9 +312,13 @@ object ScoreboardPattern { "magmaboss", "^§7Boss: §[c6e]\\d{1,3}%$", ) + + /** + * REGEX-TEST: §7Damage Soaked:§629,446 §e(+271 + */ val damageSoakedPattern by combatSb.pattern( "damagesoaked", - "^§7Damage Soaked:", + "^§7Damage Soaked:.*", ) val killMagmasPattern by combatSb.pattern( "killmagmas", @@ -364,23 +377,28 @@ object ScoreboardPattern { ) val dojoChallengePattern by miscSb.pattern( "dojochallenge", - "^(§.)*Challenge: (§.)*(?[\\w ]+)$", + "(§.)*Challenge: (§.)*(?[\\w ]+)", ) val dojoDifficultyPattern by miscSb.pattern( "dojodifficulty", - "^(§.)*Difficulty: (§.)*(?[\\w ]+)$", + "(§.)*Difficulty: (§.)*(?[\\w ]+)", ) val dojoPointsPattern by miscSb.pattern( "dojopoints", - "^(§.)*Points: (§.)*[\\w.]+ ?(§7\\(§.*§7\\))?\$", + "(§.)*Points: (§.)*[\\w.]+.*", ) + + /** + * There should be a space at the end of the test, Intellij keeps removing it + * REGEX-TEST: Time: §a20s + */ val dojoTimePattern by miscSb.pattern( "dojotime", - "^(§.)*Time: (§.)*[\\w.]+( §7\\(§.*§7\\))?$", + "(§.)*Time: (§.)*[\\w.]+.*", ) val objectivePattern by miscSb.pattern( "objective", - "^(§.)*(Objective|Quest).*", + "(§.)*(Objective|Quest).*", ) val queuePattern by miscSb.pattern( "queued", diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/ActiveBeaconEffect.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/ActiveBeaconEffect.kt new file mode 100644 index 000000000000..d0bc67fde543 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/ActiveBeaconEffect.kt @@ -0,0 +1,69 @@ +package at.hannibal2.skyhanni.features.inventory + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzColor +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.highlight +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object ActiveBeaconEffect { + + val config get() = SkyHanniMod.feature.inventory + + private val patternGroup = RepoPattern.group("inventory.activebeaconeffect") + + /** + * REGEX-TEST: Profile Stat Upgrades + */ + private val inventoryPattern by patternGroup.pattern( + "inventory", + "Profile Stat Upgrades", + ) + + /** + * REGEX-TEST: §aActive stat boost! + */ + private val slotPattern by patternGroup.pattern( + "slot.active", + "§aActive stat boost!", + ) + + private var slot: Int? = null + + @SubscribeEvent + fun onInventoryFullyOpened(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + if (!inventoryPattern.matches(event.inventoryName)) { + slot = null + return + } + + slot = event.inventoryItems.filter { (_, stack) -> + stack.getLore().any { slotPattern.matches(it) } + }.firstNotNullOfOrNull { it.key } + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + slot = null + } + + @SubscribeEvent + fun onBackgroundDrawn(event: GuiContainerEvent.BackgroundDrawnEvent) { + if (!isEnabled()) return + val slot = slot ?: return + + event.gui.inventorySlots.getSlot(slot) highlight LorenzColor.GREEN + } + + fun isEnabled() = IslandType.PRIVATE_ISLAND.isInIsland() && config.highlightActiveBeaconEffect +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/HarpFeatures.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/HarpFeatures.kt index 75b1d6ad3cd3..d6d79b31a710 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/HarpFeatures.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/HarpFeatures.kt @@ -44,15 +44,15 @@ object HarpFeatures { private val patternGroup = RepoPattern.group("harp") private val inventoryTitlePattern by patternGroup.pattern( "inventory", - "Harp.*" + "Harp.*", ) private val menuTitlePattern by patternGroup.pattern( "menu", - "Melody.*" + "Melody.*", ) private val songSelectedPattern by patternGroup.pattern( "song.selected", - "§aSong is selected!" + "§aSong is selected!", ) private fun isHarpGui(chestName: String) = inventoryTitlePattern.matches(chestName) @@ -77,7 +77,7 @@ object HarpFeatures { 37 + index, 2, 3, - Minecraft.getMinecraft().thePlayer + Minecraft.getMinecraft().thePlayer, ) // middle clicks > left clicks lastClick = SimpleTimeMark.now() break @@ -181,7 +181,7 @@ object HarpFeatures { it, event.clickedButton, event.clickType, - Minecraft.getMinecraft().thePlayer + Minecraft.getMinecraft().thePlayer, ) } } @@ -213,6 +213,6 @@ object HarpFeatures { if (!config.hideMelodyTooltip) return if (!isHarpGui(InventoryUtils.openInventoryName())) return if (event.slot.inventory !is ContainerLocalMenu) return - event.cancel() + event.cancel() } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/StockOfStonkFeature.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/StockOfStonkFeature.kt index 4bc8af1e3e56..f905eb5a532c 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/StockOfStonkFeature.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/StockOfStonkFeature.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.events.InventoryOpenEvent import at.hannibal2.skyhanni.events.LorenzToolTipEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.transformAt +import at.hannibal2.skyhanni.utils.ConditionalUtils.transformIf import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher @@ -20,7 +21,6 @@ object StockOfStonkFeature { private val repoGroup = RepoPattern.group("inventory.stockofstonks") - /** * REGEX-TEST: Stonks Auction */ @@ -42,7 +42,7 @@ object StockOfStonkFeature { */ private val topPattern by repoGroup.pattern( "top", - "§5§o§7§7▶ §c§lTOP (?[\\d,]+)§7 - §5Stock of Stonks §8x(?\\d+)", + "§5§o§7§.▶ §c§lTOP (?[\\d,]+)§7 - §5Stock of Stonks §8x(?\\d+)", ) /** @@ -85,7 +85,7 @@ object StockOfStonkFeature { } bidPattern.matchMatcher(line) { val cost = group("amount").replace(",", "").toLong() - val ratio = cost / stonksReward + val ratio = cost / stonksReward.transformIf({ this == 0 }, { 1 }) event.toolTip[index - 1] = line + " §7(§6§6${ratio.addSeparators()} §7per)" // double §6 for the replacement at the end if (ratio < bestRatio) { bestValueIndex = index - 1 diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/auctionhouse/AuctionHouseOpenPriceWebsite.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/auctionhouse/AuctionHouseOpenPriceWebsite.kt index b253e01911f2..7229283ca9c9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/auctionhouse/AuctionHouseOpenPriceWebsite.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/auctionhouse/AuctionHouseOpenPriceWebsite.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ItemUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUItems.getItemStack @@ -13,7 +14,6 @@ import at.hannibal2.skyhanni.utils.OSUtils import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.entity.player.InventoryPlayer import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.EventPriority @@ -48,7 +48,7 @@ object AuctionHouseOpenPriceWebsite { } } - private fun createDisplayItem() = Utils.createItemStack( + private fun createDisplayItem() = ItemUtils.createItemStack( "PAPER".asInternalName().getItemStack().item, "§bPrice History", "§7Click here to open", diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt index 3d7867ad9540..cf9cb6d2ec06 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarDataHolder.kt @@ -5,7 +5,7 @@ import at.hannibal2.skyhanni.config.ConfigManager import at.hannibal2.skyhanni.data.jsonobjects.other.SkyblockItemsDataJson import at.hannibal2.skyhanni.features.rift.RiftAPI import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUItems import at.hannibal2.skyhanni.utils.json.fromJson @@ -22,7 +22,7 @@ class BazaarDataHolder { private fun loadNpcPrices(): MutableMap { val list = mutableMapOf() - val apiResponse = APIUtil.getJSONResponse("https://api.hypixel.net/v2/resources/skyblock/items") + val apiResponse = APIUtils.getJSONResponse("https://api.hypixel.net/v2/resources/skyblock/items") try { val itemsData = ConfigManager.gson.fromJson(apiResponse) diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarOpenPriceWebsite.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarOpenPriceWebsite.kt index 61606346ad9e..216d3e10872a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarOpenPriceWebsite.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/bazaar/BazaarOpenPriceWebsite.kt @@ -4,12 +4,12 @@ import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.events.GuiContainerEvent import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ItemUtils import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUItems.getItemStack import at.hannibal2.skyhanni.utils.OSUtils import at.hannibal2.skyhanni.utils.SimpleTimeMark -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.entity.player.InventoryPlayer import net.minecraftforge.fml.common.eventhandler.EventPriority import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -23,12 +23,12 @@ object BazaarOpenPriceWebsite { private val item by lazy { val neuItem = "PAPER".asInternalName().getItemStack() - Utils.createItemStack( + ItemUtils.createItemStack( neuItem.item, "§bPrice History", "§7Click here to open", "§7the price history", - "§7on §cskyblock.bz" + "§7on §cskyblock.bz", ) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryAPI.kt index 40cd700c4eb4..112e8a7a7383 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryAPI.kt @@ -6,6 +6,7 @@ import at.hannibal2.skyhanni.config.features.inventory.chocolatefactory.Chocolat import at.hannibal2.skyhanni.config.storage.ProfileSpecificStorage.ChocolateFactoryStorage import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.data.jsonobjects.repo.HoppityEggLocationsJson +import at.hannibal2.skyhanni.data.jsonobjects.repo.MilestoneJson import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats @@ -80,7 +81,9 @@ object ChocolateFactoryAPI { var shrineIndex = 41 var coachRabbitIndex = 42 var maxRabbits = 395 - var chocolateMilestones = TreeSet() + private var chocolateMilestones = TreeSet() + private var chocolateFactoryMilestones: MutableList = mutableListOf() + private var chocolateShopMilestones: MutableList = mutableListOf() private var maxPrestige = 5 var inChocolateFactory = false @@ -143,6 +146,8 @@ object ChocolateFactoryAPI { maxRabbits = data.maxRabbits maxPrestige = data.maxPrestige chocolateMilestones = data.chocolateMilestones + chocolateFactoryMilestones = data.chocolateFactoryMilestones.toMutableList() + chocolateShopMilestones = data.chocolateShopMilestones.toMutableList() specialRabbitTextures = data.specialRabbits ChocolateFactoryUpgrade.updateIgnoredSlots() @@ -226,4 +231,12 @@ object ChocolateFactoryAPI { val basePerSecond = rawChocolatePerSecond * baseMultiplier return (needed / basePerSecond + secondsUntilTowerExpires).seconds } + + fun milestoneByRabbit(rabbitName: String): MilestoneJson? { + return chocolateFactoryMilestones.firstOrNull { + it.rabbit.removeColor() == rabbitName.removeColor() + } ?: chocolateShopMilestones.firstOrNull { + it.rabbit.removeColor() == rabbitName.removeColor() + } + } } 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 bd1fc87174e1..a2b264b358f5 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 @@ -4,6 +4,7 @@ import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.features.event.hoppity.HoppityAPI import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionData +import at.hannibal2.skyhanni.features.event.hoppity.HoppityCollectionStats import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsCompactChat import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggsManager import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -15,6 +16,7 @@ import at.hannibal2.skyhanni.utils.NumberUtil.formatLong import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SoundUtils import at.hannibal2.skyhanni.utils.TimeUtils.format +import net.minecraft.util.ChatComponentText import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule @@ -40,7 +42,7 @@ object ChocolateFactoryBarnManager { if (!LorenzUtils.inSkyBlock) return HoppityEggsManager.newRabbitFound.matchMatcher(event.message) { - val profileStorage = profileStorage ?: return + val profileStorage = profileStorage ?: return@matchMatcher profileStorage.currentRabbits += 1 trySendBarnFullMessage(inventory = false) HoppityEggsManager.shareWaypointPrompt() @@ -57,7 +59,15 @@ object ChocolateFactoryBarnManager { } ChocolateAmount.addToAll(amount) HoppityEggsCompactChat.compactChat(event, lastDuplicateAmount = amount) - HoppityAPI.attemptFire(event, lastDuplicateAmount = amount) + HoppityAPI.attemptFireRabbitFound(lastDuplicateAmount = amount) + + if (hoppityConfig.showDuplicateNumber && !hoppityConfig.compactChat) { + (HoppityCollectionStats.getRabbitCount(HoppityAPI.getLastRabbit()) - 1).takeIf { it > 1 }?.let { + event.chatComponent = ChatComponentText( + event.message.replace("§7§lDUPLICATE RABBIT!", "§7§lDUPLICATE RABBIT! §7(Duplicate §b#$it§7)§r"), + ) + } + } } rabbitCrashedPattern.matchMatcher(event.message) { 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 3724dbc53576..eebbb19e93a7 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 @@ -14,11 +14,11 @@ import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.getSkullTexture import at.hannibal2.skyhanni.utils.ItemUtils.name -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.NumberUtil.formatInt import at.hannibal2.skyhanni.utils.NumberUtil.formatLong import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimal +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchFirst import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches @@ -334,7 +334,7 @@ object ChocolateFactoryDataLoader { val itemName = item.name.removeColor() val lore = item.getLore() val upgradeCost = ChocolateFactoryAPI.getChocolateBuyCost(lore) - val averageChocolate = ChocolateAmount.averageChocPerSecond().round(2) + val averageChocolate = ChocolateAmount.averageChocPerSecond().roundTo(2) val isMaxed = upgradeCost == null if (slotIndex in ChocolateFactoryAPI.rabbitSlots) { @@ -415,8 +415,8 @@ object ChocolateFactoryDataLoader { newAverageChocolate: Double, isRabbit: Boolean, ) { - val extra = (newAverageChocolate - averageChocolate).round(2) - val effectiveCost = (upgradeCost!! / extra).round(2) + val extra = (newAverageChocolate - averageChocolate).roundTo(2) + val effectiveCost = (upgradeCost!! / extra).roundTo(2) val upgrade = ChocolateFactoryUpgrade(slotIndex, level, upgradeCost, extra, effectiveCost, isRabbit = isRabbit) list.add(upgrade) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryStrayTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryStrayTracker.kt index 5c964c639122..805d2c8617b2 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryStrayTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryStrayTracker.kt @@ -1,24 +1,29 @@ package at.hannibal2.skyhanni.features.inventory.chocolatefactory -import at.hannibal2.skyhanni.events.GuiContainerEvent +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent import at.hannibal2.skyhanni.events.SecondPassedEvent +import at.hannibal2.skyhanni.events.hoppity.EggFoundEvent import at.hannibal2.skyhanni.features.event.hoppity.HoppityAPI +import at.hannibal2.skyhanni.features.event.hoppity.HoppityEggType import at.hannibal2.skyhanni.features.event.hoppity.HoppityEventSummary import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut +import at.hannibal2.skyhanni.utils.CollectionUtils.sortedDesc import at.hannibal2.skyhanni.utils.DelayedRun import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore -import at.hannibal2.skyhanni.utils.ItemUtils.itemName import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzRarity +import at.hannibal2.skyhanni.utils.LorenzRarity.LEGENDARY import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.NumberUtil.formatLong import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.StringUtils.removeResets import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.renderables.Renderable @@ -26,8 +31,10 @@ import at.hannibal2.skyhanni.utils.renderables.Searchable import at.hannibal2.skyhanni.utils.renderables.toSearchable import at.hannibal2.skyhanni.utils.tracker.SkyHanniTracker import at.hannibal2.skyhanni.utils.tracker.TrackerData +import com.google.gson.JsonElement +import com.google.gson.JsonObject import com.google.gson.annotations.Expose -import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraft.inventory.Slot import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds @@ -43,14 +50,14 @@ object ChocolateFactoryStrayTracker { * REGEX-TEST: §6§lGolden Rabbit §d§lCAUGHT! * REGEX-TEST: §fAudi §d§lCAUGHT! */ - private val strayCaughtPattern by ChocolateFactoryAPI.patternGroup.pattern( + val strayCaughtPattern by ChocolateFactoryAPI.patternGroup.pattern( "stray.caught", - "^§[a-f0-9].* §d§lCAUGHT!", + "^(?:§.)*(?.*) §d§lCAUGHT!", ) /** * REGEX-TEST: §7You caught a stray §fMandy §7and §7gained §6+283,574 Chocolate§7! - * REGEX-TEST: §7You caught a stray §aSven §7and gained §7§6+397,004 Chocolate§7!' + * REGEX-TEST: §7You caught a stray §aSven §7and gained §7§6+397,004 Chocolate§7! */ private val strayLorePattern by ChocolateFactoryAPI.patternGroup.pattern( "stray.loreinfo", @@ -101,14 +108,6 @@ object ChocolateFactoryStrayTracker { "§7You caught a stray (?§.)Fish the Rabbit§7! §7You have already found (?:§.)?Fish the (?:§.)?Rabbit§7, so you received §6(?[\\d,]*) (?:§6)?Chocolate§7!", ) - private val rarityFormatMap = mapOf( - "common" to "§f", - "uncommon" to "§a", - "rare" to "§9", - "epic" to "§5", - "legendary" to "§6", - ) - private val tracker = SkyHanniTracker("Stray Tracker", { Data() }, { it.chocolateFactory.strayTracker }) { drawDisplay(it) } @@ -120,10 +119,10 @@ object ChocolateFactoryStrayTracker { } @Expose - var straysCaught: MutableMap = mutableMapOf() + var straysCaught: MutableMap = mutableMapOf() @Expose - var straysExtraChocMs: MutableMap = mutableMapOf() + var straysExtraChocMs: MutableMap = mutableMapOf() @Expose var goldenTypesCaught: MutableMap = mutableMapOf() @@ -134,15 +133,12 @@ object ChocolateFactoryStrayTracker { return notEmptyLines.joinToString(" ") } - private fun incrementRarity(rarity: String, chocAmount: Long = 0) { + private fun incrementRarity(rarity: LorenzRarity, chocAmount: Long = 0) { tracker.modify { it.straysCaught.addOrPut(rarity, 1) } val extraTime = ChocolateFactoryAPI.timeUntilNeed(chocAmount + 1) tracker.modify { it.straysExtraChocMs.addOrPut(rarity, extraTime.inWholeMilliseconds) } - if (HoppityAPI.isHoppityEvent()) { - LorenzRarity.getByName(rarity)?.let { - HoppityEventSummary.addStrayCaught(it, chocAmount) - } - } + if (!HoppityAPI.isHoppityEvent()) return + HoppityEventSummary.addStrayCaught(rarity, chocAmount) } private fun incrementGoldenType(typeCaught: String, amount: Int = 1) { @@ -159,107 +155,99 @@ object ChocolateFactoryStrayTracker { tips = listOf("§a+§b${formattedExtraTime} §afrom strays§7"), ).toSearchable(), ) - rarityFormatMap.keys.forEach { rarity -> + HoppityAPI.hoppityRarities.forEach { rarity -> extractHoverableOfRarity(rarity, data)?.let { add(it) } } } - private fun extractHoverableOfRarity(rarity: String, data: Data): Searchable? { + private fun extractHoverableOfRarity(rarity: LorenzRarity, data: Data): Searchable? { val caughtOfRarity = data.straysCaught[rarity] val caughtString = caughtOfRarity?.toString() ?: return null val rarityExtraChocMs = data.straysExtraChocMs[rarity]?.milliseconds val extraChocFormat = rarityExtraChocMs?.format() ?: "" - val colorCode = rarityFormatMap[rarity] ?: "" - val lineHeader = "$colorCode${rarity.substring(0, 1).uppercase()}${rarity.substring(1)}§7: §r$colorCode" + val colorCode = rarity.chatColorCode + val lineHeader = "$colorCode${rarity.toString().lowercase().replaceFirstChar { it.uppercase() }}§7: §r$colorCode" val lineFormat = "${lineHeader}${caughtString}" val renderable = rarityExtraChocMs?.let { - val tip = - "§a+§b$extraChocFormat §afrom $colorCode$rarity strays§7${if (rarity == "legendary") extractGoldenTypesCaught(data) else ""}" + var tip = "§a+§b$extraChocFormat §afrom $colorCode${rarity.toString().lowercase()} strays§7" + if (rarity == LEGENDARY) tip += extractGoldenTypesCaught(data) Renderable.hoverTips(Renderable.string(lineFormat), tips = tip.split("\n")) } ?: Renderable.string(lineFormat) - return renderable.toSearchable(rarity) + return renderable.toSearchable(rarity.toString()) + } + + private val goldenTypesMap: Map) -> Unit> by lazy { + mapOf( + "sidedish" to { count, list -> list.add("§b$count §6Side ${StringUtils.pluralize(count, "Dish", "Dishes")}") }, + "jackpot" to { count, list -> list.add("§b$count §6Chocolate ${StringUtils.pluralize(count, "Jackpot")}") }, + "mountain" to { count, list -> list.add("§b$count §6Chocolate ${StringUtils.pluralize(count, "Mountain")}") }, + "dorado" to { count, list -> list.add("§b$count §6El Dorado ${StringUtils.pluralize(count, "Sighting")}") }, + "stampede" to { count, list -> list.add("§b$count §6${StringUtils.pluralize(count, "Stampede")}") }, + "goldenclick" to { count, list -> list.add("§b$count §6Golden ${StringUtils.pluralize(count, "Click")}") } + ) } private fun extractGoldenTypesCaught(data: Data): String { val goldenList = mutableListOf() - data.goldenTypesCaught["sidedish"]?.let { - goldenList.add("§b$it §6Side Dish" + if (it > 1) "es" else "") + data.goldenTypesCaught.sortedDesc().forEach { (key, count) -> goldenTypesMap[key]?.invoke(count, goldenList) } + return if (goldenList.isEmpty()) "" else ("\n" + goldenList.joinToString("\n")) + } + + fun handleStrayClicked(slot: Slot) { + if (!isEnabled() || claimedStraysSlots.contains(slot.slotNumber)) return + + claimedStraysSlots.add(slot.slotIndex) + val loreLine = formLoreToSingleLine(slot.stack.getLore()) + + // "Base" strays - Common -> Epic, raw choc only reward. + strayLorePattern.matchMatcher(loreLine) { + //Pretty sure base strays max at Epic, but... + val rarity = HoppityAPI.rarityByRabbit(group("rabbit")) ?: return@matchMatcher + incrementRarity(rarity, group("amount").formatLong()) } - data.goldenTypesCaught["jackpot"]?.let { - goldenList.add("§b$it §6Chocolate Jackpot" + if (it > 1) "s" else "") + + // Fish the Rabbit + fishTheRabbitPattern.matchMatcher(loreLine) { + //Also fairly sure that Fish maxes out at Rare, but... + val rarity = HoppityAPI.rarityByRabbit(group("color")) ?: return@matchMatcher + incrementRarity(rarity, group("amount").formatLong()) } - data.goldenTypesCaught["mountain"]?.let { - goldenList.add("§b$it §6Chocolate Mountain" + if (it > 1) "s" else "") + + // Golden Strays, Jackpot and Mountain, raw choc only reward. + goldenStrayJackpotMountainPattern.matchMatcher(loreLine) { + val amount = group("amount").formatLong().also { am -> incrementRarity(LEGENDARY, am) } + val multiplier = amount / ChocolateFactoryAPI.chocolatePerSecond + when (multiplier) { + in 479.0..481.0 -> incrementGoldenType("jackpot") + in 1499.0..1501.0 -> incrementGoldenType("mountain") + } } - data.goldenTypesCaught["dorado"]?.let { - goldenList.add((if (it >= 3) "§a" else "§b") + "$it§7/§a3 §6El Dorado §7Sighting" + if (it > 1) "s" else "") + + // Golden Strays, "Golden Click" + goldenStrayClick.matchMatcher(loreLine) { + incrementGoldenType("goldenclick") } - data.goldenTypesCaught["stampede"]?.let { - goldenList.add("§b$it §6Stampede" + if (it > 1) "s" else "") + + // Golden Strays, hoard/stampede + strayHoardPattern.matchMatcher(loreLine.removeResets()) { + incrementGoldenType("stampede") } - data.goldenTypesCaught["goldenclick"]?.let { - goldenList.add("§b$it §6Golden Click" + if (it > 1) "s" else "") + + // El Dorado - all catches + strayDoradoPattern.matchMatcher(loreLine) { + groupOrNull("amount")?.let { amount -> + incrementRarity(LEGENDARY, amount.formatLong()) + } + incrementGoldenType("dorado") } - return if (goldenList.size == 0) "" else ("\n" + goldenList.joinToString("\n")) } @SubscribeEvent fun onTick(event: SecondPassedEvent) { if (!isEnabled()) return - InventoryUtils.getItemsInOpenChest().filter { - !claimedStraysSlots.contains(it.slotIndex) - }.forEach { - strayCaughtPattern.matchMatcher(it.stack.name) { - if (it.stack.getLore().isEmpty()) return - claimedStraysSlots.add(it.slotIndex) - val loreLine = formLoreToSingleLine(it.stack.getLore()) - - // "Base" strays - Common -> Epic, raw choc only reward. - strayLorePattern.matchMatcher(loreLine) { - //Pretty sure base strays max at Epic, but... - val rarity = rarityFormatMap.entries.find { e -> e.value == group("rabbit").substring(0, 2) }?.key ?: "common" - incrementRarity(rarity, group("amount").formatLong()) - } - - // Fish the Rabbit - fishTheRabbitPattern.matchMatcher(loreLine) { - //Also fairly sure that Fish maxes out at Rare, but... - val rarity = rarityFormatMap.entries.find { e -> e.value == group("color").substring(0, 2) }?.key ?: "common" - incrementRarity(rarity, group("amount").formatLong()) - } - - // Golden Strays, Jackpot and Mountain, raw choc only reward. - goldenStrayJackpotMountainPattern.matchMatcher(loreLine) { - val amount = group("amount").formatLong().also { am -> incrementRarity("legendary", am) } - val multiplier = amount / ChocolateFactoryAPI.chocolatePerSecond - when (multiplier) { - in 479.0..481.0 -> incrementGoldenType("jackpot") - in 1499.0..1501.0 -> incrementGoldenType("mountain") - } - } - - // Golden Strays, "Golden Click" - goldenStrayClick.matchMatcher(loreLine) { - incrementGoldenType("goldenclick") - } - - // Golden Strays, hoard/stampede - strayHoardPattern.matchMatcher(loreLine.removeResets()) { - incrementGoldenType("stampede") - } - - // El Dorado - all catches - strayDoradoPattern.matchMatcher(loreLine) { - groupOrNull("amount")?.let { amount -> - incrementRarity("legendary", amount.formatLong()) - } - incrementGoldenType("dorado") - } - } - } InventoryUtils.getItemsInOpenChest().filter { claimedStraysSlots.contains(it.slotIndex) }.forEach { @@ -269,27 +257,17 @@ object ChocolateFactoryStrayTracker { } } - @SubscribeEvent(priority = EventPriority.HIGH) - fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { - val index = event.slot?.slotIndex ?: return - if (index == -999) return - if (claimedStraysSlots.contains(index)) return - - val clickedStack = InventoryUtils.getItemsInOpenChest() - .find { it.slotNumber == event.slot.slotNumber && it.hasStack } - ?.stack ?: return - val nameText = (if (clickedStack.hasDisplayName()) clickedStack.displayName else clickedStack.itemName) - if (!nameText.equals("§6§lGolden Rabbit §8- §aSide Dish")) return - - HoppityAPI.fireSideDishMessage() - if (!isEnabled()) return - - claimedStraysSlots.add(index) - incrementGoldenType("sidedish") - incrementRarity("legendary", 0) - DelayedRun.runDelayed(1.seconds) { - claimedStraysSlots.remove(claimedStraysSlots.indexOf(index)) + @HandleEvent + fun onEggFound(event: EggFoundEvent) { + if (!isEnabled() || event.type != HoppityEggType.SIDE_DISH) return + event.slotIndex?.let { + claimedStraysSlots.add(it) + DelayedRun.runDelayed(1.seconds) { + claimedStraysSlots.remove(claimedStraysSlots.indexOf(it)) + } } + incrementRarity(LEGENDARY, 0) + incrementGoldenType("sidedish") } @SubscribeEvent @@ -304,6 +282,32 @@ object ChocolateFactoryStrayTracker { tracker.firstUpdate() } + private fun migrateJsonStringKeyToRarityKey(jElement: JsonElement, enumClass: Class): JsonElement { + if (!jElement.isJsonObject) return jElement + val newElement = JsonObject() + + for ((key, value) in jElement.asJsonObject.entrySet()) { + val enum = try { + enumClass.javaClass.enumConstants.first { it.name.equals(key, ignoreCase = true) } + } catch (e: IllegalArgumentException) { + continue + } + value?.asInt?.let { newElement.addProperty(enum.toString(), it) } + } + + return newElement + } + + @SubscribeEvent + fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { + event.transform(58, "chocolateFactory.strayTracker.straysCaught") { element -> + migrateJsonStringKeyToRarityKey(element, LorenzRarity::class.java) + } + event.transform(58, "chocolateFactory.strayTracker.straysExtraChocMs") { element -> + migrateJsonStringKeyToRarityKey(element, LorenzRarity::class.java) + } + } + fun resetCommand() { tracker.resetCommand() } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryTooltip.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryTooltip.kt index 8973bc1e4fbe..88ac9d4747ae 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryTooltip.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/chocolatefactory/ChocolateFactoryTooltip.kt @@ -3,8 +3,8 @@ package at.hannibal2.skyhanni.features.inventory.chocolatefactory import at.hannibal2.skyhanni.events.LorenzToolTipEvent import at.hannibal2.skyhanni.features.inventory.chocolatefactory.ChocolateFactoryAPI.profileStorage import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import net.minecraftforge.fml.common.eventhandler.EventPriority import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -35,7 +35,7 @@ object ChocolateFactoryTooltip { if (upgradeInfo.effectiveCost == null) return - event.toolTip.add("§7Extra: §6${upgradeInfo.extraPerSecond?.round(2) ?: "N/A"} §7choc/s") + event.toolTip.add("§7Extra: §6${upgradeInfo.extraPerSecond?.roundTo(2) ?: "N/A"} §7choc/s") event.toolTip.add("§7Effective Cost: §6${upgradeInfo.effectiveCost.addSeparators() ?: "N/A"}") if (slotIndex == ChocolateFactoryAPI.timeTowerIndex) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/craft/CraftableItemList.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/craft/CraftableItemList.kt index 6b841f5a40d0..8612c9795cfc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/craft/CraftableItemList.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/craft/CraftableItemList.kt @@ -20,12 +20,12 @@ import at.hannibal2.skyhanni.utils.NEUItems.isVanillaItem import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat import at.hannibal2.skyhanni.utils.PrimitiveItemStack.Companion.toPrimitiveStackOrNull +import at.hannibal2.skyhanni.utils.PrimitiveRecipe import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.math.floor @@ -71,7 +71,7 @@ object CraftableItemList { val recipes = NEUItems.getRecipes(internalName) for (recipe in recipes) { - if (recipe !is CraftingRecipe) continue + if (!recipe.isCraftingRecipe()) continue val renderable = createItemRenderable(recipe, availableMaterial, pricePer, internalName) ?: continue lines[internalName] = renderable } @@ -79,7 +79,7 @@ object CraftableItemList { } private fun createItemRenderable( - recipe: CraftingRecipe, + recipe: PrimitiveRecipe, availableMaterial: Map, pricePer: MutableMap, internalName: NEUInternalName, diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt new file mode 100644 index 000000000000..80433b68e665 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableAPI.kt @@ -0,0 +1,157 @@ +package at.hannibal2.skyhanni.features.inventory.experimentationtable + +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.ProfileStorageData +import at.hannibal2.skyhanni.events.InventoryUpdatedEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.EntityUtils +import at.hannibal2.skyhanni.utils.EntityUtils.hasSkullTexture +import at.hannibal2.skyhanni.utils.InventoryUtils.openInventoryName +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.getLorenzVec +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.entity.item.EntityArmorStand +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object ExperimentationTableAPI { + + private val storage get() = ProfileStorageData.profileSpecific?.experimentation + + val inTable get() = inventoriesPattern.matches(openInventoryName()) + + fun inDistanceToTable(vec: LorenzVec, max: Double): Boolean = + storage?.tablePos?.let { it.distance(vec) <= max } ?: false + + fun getCurrentExperiment(): Experiment? = + superpairsPattern.matchMatcher(openInventoryName()) { + Experiment.entries.find { it.nameString == group("experiment") } + } + + @SubscribeEvent + fun onInventoryUpdated(event: InventoryUpdatedEvent) { + if (LorenzUtils.skyBlockIsland != IslandType.PRIVATE_ISLAND || !inTable) return + + val entity = EntityUtils.getEntities().find { it.hasSkullTexture(experimentationTableSkull) } ?: return + val vec = entity.getLorenzVec() + if (storage?.tablePos != vec) storage?.tablePos = vec + } + + private val experimentationTableSkull = + "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTUyOWF" + + "iYzg4MzA5NTNmNGQ5MWVkZmZmMjQ2OTVhOWY2Mjc1OGZhNGM1MWIyOWFjMjQ2YzM3NDllYWFlODliMyJ9fX0=" + + private val patternGroup = RepoPattern.group("enchanting.experiments") + + /** + * REGEX-TEST: Superpairs (Metaphysical) + */ + private val superpairsPattern by patternGroup.pattern( + "superpairs", + "Superpairs \\((?\\w+)\\)", + ) + + /** + * REGEX-TEST: Gained +3 Clicks + */ + val powerUpPattern by patternGroup.pattern( + "powerups", + "Gained \\+\\d Clicks?|Instant Find|\\+\\S* XP", + ) + + /** + * REGEX-TEST: 123k Enchanting Exp + * REGEX-TEST: Titanic Experience Bottle + */ + val rewardPattern by patternGroup.pattern( + "rewards", + "\\d{1,3}k Enchanting Exp|Enchanted Book|(?:Titanic |Grand |\\b)Experience Bottle|Metaphysical Serum|Experiment The Fish", + ) + + /** + * REGEX-TEST: Superpairs (Metaphysical) + * REGEX-TEST: Chronomatron (Metaphysical) + */ + val inventoriesPattern by patternGroup.pattern( + "inventories", + "(?:Superpairs|Chronomatron|Ultrasequencer) (?:\\(.+\\)|➜ Stakes|Rewards)|Experimentation Table", + ) + + /** + * REGEX-TEST: +42,000 Enchanting Exp + */ + val enchantingExpChatPattern by patternGroup.pattern( + "chatexp", + "^ \\+(?\\d+|\\d+,\\d+)k? Enchanting Exp$", + ) + + /** + * REGEX-TEST: +Smite VII + * REGEX-TEST: +42,000 Enchanting Exp + */ + val experimentsDropPattern by patternGroup.pattern( + "drop", + "^ \\+(?.*)\$", + ) + + /** + * REGEX-TEST: You claimed the Superpairs rewards! + */ + val claimMessagePattern by patternGroup.pattern( + "claim", + "You claimed the \\S+ rewards!", + ) + + /** + * REGEX-TEST: 131k Enchanting Exp + * REGEX-TEST: 42,000 Enchanting Exp + */ + val enchantingExpPattern by patternGroup.pattern( + "exp", + "(?\\d+|\\d+,\\d+)k? Enchanting Exp", + ) + + /** + * REGEX-TEST: Titanic Experience Bottle + */ + val experienceBottlePattern by patternGroup.pattern( + "xpbottle", + "(?:Titanic |Grand |\\b)Experience Bottle", + ) + + /** + * REGEX-TEST: ☕ You renewed the experiment table! (1/3) + */ + val experimentRenewPattern by patternGroup.pattern( + "renew", + "^☕ You renewed the experiment table! \\((?\\d)/3\\)$", + ) + + /** + * REGEX-TEST: §d§kXX§5 ULTRA-RARE BOOK! §d§kXX + */ + val ultraRarePattern by patternGroup.pattern( + "ultrarare", + "§d§kXX§5 ULTRA-RARE BOOK! §d§kXX", + ) + + /** + * REGEX-TEST: §9Smite VII + */ + val bookPattern by patternGroup.pattern( + "book", + "§9(?.*)", + ) + + /** + * REGEX-TEST: §dGuardian + * REGEX-TEST: §9Guardian§e + */ + val petNamePattern by patternGroup.pattern( + "guardianpet", + "§[956d]Guardian.*", + ) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt new file mode 100644 index 000000000000..0071d3af35fa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentationTableEnums.kt @@ -0,0 +1,28 @@ +package at.hannibal2.skyhanni.features.inventory.experimentationtable + +enum class ExperimentMessages(private val str: String) { + DONE("§eYou claimed the §dSuperpairs §erewards! §8(§7Claim§8)"), + EXPERIENCE("§8 +§3141k Experience §8(§7Experience Drops§8)"), + ENCHANTMENTS("§8 +§9Smite VII §8(§7Enchantment Drops§8)"), + BOTTLES("§8 +§9Titanic Experience Bottle §8(§7Bottle Drops§8)"), + MISC("§8 +§5Metaphysical Serum §8(§7Misc Drops§8)"); + + override fun toString(): String { + return str + } +} + +enum class Experiment(val nameString: String, val gridSize: Int, val startSlot: Int, val endSlot: Int, val sideSpace: Int) { + NONE("", 0, 0, 0, 0), + BEGINNER("Beginner", 14, 18, 35, 1), + HIGH("High", 20, 10, 43, 2), + GRAND("Grand", 20, 10, 43, 2), + SUPREME("Supreme", 28, 9, 44, 1), + TRANSCENDENT("Transcendent", 28, 9, 44, 1), + METAPHYSICAL("Metaphysical", 28, 9, 44, 1), + ; + + override fun toString(): String { + return nameString + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt new file mode 100644 index 000000000000..50d033842792 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsDryStreakDisplay.kt @@ -0,0 +1,113 @@ +package at.hannibal2.skyhanni.features.inventory.experimentationtable + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.ProfileStorageData +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryOpenEvent +import at.hannibal2.skyhanni.events.InventoryUpdatedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.bookPattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.ultraRarePattern +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object ExperimentsDryStreakDisplay { + + private val config get() = SkyHanniMod.feature.inventory.experimentationTable.dryStreak + private val storage get() = ProfileStorageData.profileSpecific?.experimentation?.dryStreak + + private var display = emptyList() + + private var didJustFind = false + + @SubscribeEvent + fun onChestGuiOverlayRendered(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { + if (!isEnabled()) return + if (!ExperimentationTableAPI.inventoriesPattern.matches(InventoryUtils.openInventoryName())) return + + display = drawDisplay() + config.position.renderStrings( + display, + posLabel = "Experimentation Table Dry Streak", + ) + } + + @SubscribeEvent + fun onInventoryOpen(event: InventoryOpenEvent) { + if (event.inventoryName == "Experimentation Table" && didJustFind) didJustFind = false + } + + @SubscribeEvent + fun onInventoryUpdated(event: InventoryUpdatedEvent) { + if (!isEnabled() || didJustFind || ExperimentationTableAPI.getCurrentExperiment() == null) return + + for (lore in event.inventoryItems.map { it.value.getLore() }) { + val firstLine = lore.firstOrNull() ?: continue + if (!ultraRarePattern.matches(firstLine)) continue + val bookNameLine = lore.getOrNull(2) ?: continue + bookPattern.matchMatcher(bookNameLine) { + val storage = storage ?: return + ChatUtils.chat( + "§a§lDRY-STREAK ENDED! §eYou have (finally) " + + "found a §5ULTRA-RARE §eafter §3${storage.xpSince.shortFormat()} Enchanting Exp " + + "§e and §2${storage.attemptsSince} attempts§e!", + ) + storage.attemptsSince = 0 + storage.xpSince = 0 + didJustFind = true + } + } + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + if (didJustFind || ExperimentationTableAPI.getCurrentExperiment() == null) return + + val storage = storage ?: return + storage.attemptsSince += 1 + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled() || didJustFind) return + + ExperimentationTableAPI.enchantingExpChatPattern.matchMatcher(event.message.removeColor()) { + val storage = storage ?: return + storage.xpSince += group("amount").substringBefore(",").toInt() * 1000 + } + } + + private fun drawDisplay() = buildList { + val storage = storage ?: return@buildList + + add("§cDry-Streak since last §5ULTRA-RARE") + + val colorPrefix = "§e" + val attemptsSince = storage.attemptsSince + val xpSince = storage.xpSince.shortFormat() + val attemptsSuffix = if (attemptsSince == 1) "" else "s" + + if (config.attemptsSince && config.xpSince) { + add("$colorPrefix ├ $attemptsSince Attempt$attemptsSuffix") + add("$colorPrefix └ $xpSince XP") + } else if (config.attemptsSince) { + add("$colorPrefix └ $attemptsSince Attempt$attemptsSuffix") + } else { + add("$colorPrefix └ $xpSince XP") + } + } + + private fun isEnabled() = + LorenzUtils.inSkyBlock && config.enabled && (config.xpSince || config.attemptsSince) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt new file mode 100644 index 000000000000..6e755d874018 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/ExperimentsProfitTracker.kt @@ -0,0 +1,262 @@ +package at.hannibal2.skyhanni.features.inventory.experimentationtable + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.ClickType +import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.events.InventoryUpdatedEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent +import at.hannibal2.skyhanni.events.ItemClickEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.claimMessagePattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.enchantingExpPattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.experienceBottlePattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.experimentRenewPattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.experimentsDropPattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.inventoriesPattern +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut +import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString +import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getNpcPriceOrNull +import at.hannibal2.skyhanni.utils.ItemPriceUtils.getPrice +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName +import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NEUInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo +import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.renderables.Searchable +import at.hannibal2.skyhanni.utils.renderables.toSearchable +import at.hannibal2.skyhanni.utils.tracker.ItemTrackerData +import at.hannibal2.skyhanni.utils.tracker.SkyHanniItemTracker +import com.google.gson.annotations.Expose +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.math.absoluteValue +import kotlin.time.Duration.Companion.milliseconds + +@SkyHanniModule +object ExperimentsProfitTracker { + + private val config get() = SkyHanniMod.feature.inventory.experimentationTable.experimentsProfitTracker + + private val tracker = SkyHanniItemTracker( + "Experiments Profit Tracker", + { Data() }, + { it.experimentation.experimentsProfitTracker }, + ) { drawDisplay(it) } + + private var lastSplashes = mutableListOf() + private var lastSplashTime = SimpleTimeMark.farPast() + private var lastBottlesInInventory = mutableMapOf() + private var currentBottlesInInventory = mutableMapOf() + + class Data : ItemTrackerData() { + override fun resetItems() { + experimentsDone = 0L + xpGained = 0L + bitCost = 0L + startCost = 0L + } + + override fun getDescription(timesGained: Long): List { + val percentage = timesGained.toDouble() / experimentsDone + val dropRate = LorenzUtils.formatPercentage(percentage.coerceAtMost(1.0)) + return listOf( + "§7Dropped §e${timesGained.addSeparators()} §7times.", + "§7Your drop rate: §c$dropRate.", + ) + } + + override fun getCoinName(item: TrackedItem) = "" + + override fun getCoinDescription(item: TrackedItem) = listOf() + + @Expose + var experimentsDone = 0L + + @Expose + var xpGained = 0L + + @Expose + var bitCost = 0L + + @Expose + var startCost = 0L + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + + val message = event.message.removeColor() + if (claimMessagePattern.matches(message) && ExperimentMessages.DONE.isSelected()) { + event.blockedReason = "CLAIM_MESSAGE" + } + + experimentsDropPattern.matchMatcher(message) { + event.handleDrop(group("reward")) + return + } + + experimentRenewPattern.matchMatcher(message) { + val increments = mapOf(1 to 150, 2 to 300, 3 to 500) + tracker.modify { + it.bitCost += increments.getValue(group("current").toInt()) + } + } + } + + private fun LorenzChatEvent.handleDrop(reward: String) { + blockedReason = when { + enchantingExpPattern.matches(reward) && ExperimentMessages.EXPERIENCE.isSelected() -> "EXPERIENCE_DROP" + experienceBottlePattern.matches(reward) && ExperimentMessages.BOTTLES.isSelected() -> "BOTTLE_DROP" + listOf("Metaphysical Serum", "Experiment The Fish").contains(reward) && ExperimentMessages.MISC.isSelected() -> "MISC_DROP" + ExperimentMessages.ENCHANTMENTS.isSelected() -> "ENCHANT_DROP" + else -> "" + } + + enchantingExpPattern.matchMatcher(reward) { + tracker.modify { + it.xpGained += group("amount").substringBefore(",").toInt() * 1000 + } + return + } + + val internalName = NEUInternalName.fromItemNameOrNull(reward) ?: return + if (!experienceBottlePattern.matches(reward)) tracker.addItem(internalName, 1, false) + else DelayedRun.runDelayed(100.milliseconds) { handleExpBottles(true) } + } + + @SubscribeEvent + fun onItemClick(event: ItemClickEvent) { + if (event.clickType == ClickType.RIGHT_CLICK) { + val item = event.itemInHand ?: return + if (experienceBottlePattern.matches(item.displayName.removeColor())) { + lastSplashTime = SimpleTimeMark.now() + lastSplashes.add(item) + } + } + } + + @SubscribeEvent + fun onInventoryUpdated(event: InventoryUpdatedEvent) { + if (!isEnabled()) return + + if (inventoriesPattern.matches(event.inventoryName)) { + var startCostTemp = 0 + val iterator = lastSplashes.iterator() + while (iterator.hasNext()) { + val item = iterator.next() + val internalName = item.getInternalName() + val price = internalName.getPrice() + val npcPrice = internalName.getNpcPriceOrNull() ?: 0.0 + val maxPrice = npcPrice.coerceAtLeast(price) + startCostTemp += maxPrice.roundTo(0).toInt() + iterator.remove() + } + tracker.modify { + it.startCost -= startCostTemp + } + lastSplashTime = SimpleTimeMark.farPast() + } + + handleExpBottles(false) + } + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + if (!isEnabled()) return + + if (ExperimentationTableAPI.getCurrentExperiment() != null) { + tracker.modify { + it.experimentsDone++ + } + } + } + + private fun drawDisplay(data: Data): List = buildList { + addSearchString("§e§lExperiments Profit Tracker") + val profit = tracker.drawItems(data, { true }, this) + data.startCost + + val experimentsDone = data.experimentsDone + addSearchString("") + addSearchString("§eExperiments Done: §a${experimentsDone.addSeparators()}") + val startCostFormat = data.startCost.absoluteValue.shortFormat() + val bitCostFormat = data.bitCost.shortFormat() + add( + Renderable.hoverTips( + "§eTotal Cost: §c-$startCostFormat§e/§b-$bitCostFormat", + listOf( + "§7You paid §c$startCostFormat §7coins and", "§b$bitCostFormat §7bits for starting", + "§7experiments.", + ), + ).toSearchable(), + ) + add(tracker.addTotalProfit(profit, data.experimentsDone, "experiment")) + addSearchString("§eTotal Enchanting Exp: §b${data.xpGained.shortFormat()}") + + tracker.addPriceFromButton(this) + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent) { + if (!isEnabled()) return + + tracker.renderDisplay(config.position) + } + + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + if (event.newIsland == IslandType.PRIVATE_ISLAND) { + tracker.firstUpdate() + } + } + + fun resetCommand() { + tracker.resetCommand() + } + + private fun handleExpBottles(addToTracker: Boolean) { + for (item in InventoryUtils.getItemsInOwnInventory()) { + val internalName = item.getInternalNameOrNull() ?: continue + if (internalName.asString() !in listOf("EXP_BOTTLE", "GRAND_EXP_BOTTLE", "TITANIC_EXP_BOTTLE")) continue + currentBottlesInInventory.addOrPut(internalName, item.stackSize) + } + + for ((internalName, amount) in currentBottlesInInventory) { + val lastInInv = lastBottlesInInventory.getOrDefault(internalName, 0) + if (lastInInv >= amount) { + currentBottlesInInventory[internalName] = 0 + lastBottlesInInventory[internalName] = amount + continue + } + + if (lastInInv == 0) { + currentBottlesInInventory[internalName] = 0 + lastBottlesInInventory[internalName] = amount + if (addToTracker) tracker.addItem(internalName, amount, false) + continue + } + + currentBottlesInInventory[internalName] = 0 + lastBottlesInInventory[internalName] = amount + if (addToTracker) tracker.addItem(internalName, amount - lastInInv, false) + } + } + + private fun ExperimentMessages.isSelected() = config.hideMessages.contains(this) + + private fun isEnabled() = + LorenzUtils.inSkyBlock && config.enabled && ExperimentationTableAPI.inDistanceToTable(LorenzVec.getBlockBelowPlayer(), 5.0) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/GuardianReminder.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt similarity index 78% rename from src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/GuardianReminder.kt rename to src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt index 9ae93f22717f..216cbf7c6ba8 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/GuardianReminder.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/GuardianReminder.kt @@ -1,6 +1,7 @@ -package at.hannibal2.skyhanni.features.inventory.experiments +package at.hannibal2.skyhanni.features.inventory.experimentationtable import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent @@ -16,7 +17,6 @@ import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.SoundUtils import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXYAligned -import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager @@ -28,31 +28,16 @@ import kotlin.time.Duration.Companion.seconds @SkyHanniModule object GuardianReminder { - private val config get() = SkyHanniMod.feature.inventory.helper.enchanting + private val config get() = SkyHanniMod.feature.inventory.experimentationTable private var lastInventoryOpen = SimpleTimeMark.farPast() private var lastWarn = SimpleTimeMark.farPast() private var lastErrorSound = SimpleTimeMark.farPast() - private val patternGroup = RepoPattern.group("data.enchanting.inventory.experimentstable") - private val inventoryNamePattern by patternGroup.pattern( - "mainmenu", - "Experimentation Table", - ) - - /** - * REGEX-TEST: §dGuardian - * REGEX-TEST: §9Guardian§e - */ - private val petNamePattern by patternGroup.pattern( - "guardianpet", - "§[956d]Guardian.*", - ) - @SubscribeEvent fun onInventory(event: InventoryFullyOpenedEvent) { if (!isEnabled()) return - if (!inventoryNamePattern.matches(event.inventoryName)) return - if (petNamePattern.matches(PetAPI.currentPet)) return + if (event.inventoryName != "Experimentation Table") return + if (ExperimentationTableAPI.petNamePattern.matches(PetAPI.currentPet)) return lastInventoryOpen = SimpleTimeMark.now() @@ -69,7 +54,7 @@ object GuardianReminder { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { if (!isEnabled()) return - if (!inventoryNamePattern.matches(InventoryUtils.openInventoryName())) return + if (InventoryUtils.openInventoryName() != "Experimentation Table") return if (lastInventoryOpen.passedSince() > 2.seconds) return val gui = Minecraft.getMinecraft().currentScreen as? GuiContainer ?: return @@ -95,5 +80,10 @@ object GuardianReminder { GlStateManager.popMatrix() } + @SubscribeEvent + fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { + event.move(59, "inventory.helper.enchanting.guardianReminder", "inventory.experimentationTable.guardianReminder") + } + private fun isEnabled() = LorenzUtils.inSkyBlock && config.guardianReminder } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt new file mode 100644 index 000000000000..86d7fca50ad9 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairExperimentInformationDisplay.kt @@ -0,0 +1,277 @@ +package at.hannibal2.skyhanni.features.inventory.experimentationtable + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.GuiContainerEvent.SlotClickEvent +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.InventoryCloseEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.InventoryUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.milliseconds + +@SkyHanniModule +// TODO important: all use cases of listOf in combination with string needs to be gone. no caching, constant new list creation, and bad design. +object SuperpairExperimentInformationDisplay { + + private val config get() = SkyHanniMod.feature.inventory.experimentationTable + + private var display = emptyList() + + private var uncoveredAt = 0 + private var uncoveredItems = mutableListOf>() + private var possiblePairs = 0 + + data class Item(val index: Int, val name: String) + data class ItemPair(val first: Item, val second: Item) + + // TODO remove string. use enum instead! maybe even create new data type instaed of map of pairs + private var found = mutableMapOf, String>() + + private var toCheck = mutableListOf>() + private var lastClicked = mutableListOf>() + private var lastClick = SimpleTimeMark.farPast() + private var currentExperiment = Experiment.NONE + private var instantFind = 0 + + private val sideSpaces1 = listOf(17, 18, 26, 27, 35, 36) + private val sideSpaces2 = listOf(16, 17, 18, 19, 25, 26, 27, 28, 34, 35, 36, 37) + + @SubscribeEvent + fun onInventoryClose(event: InventoryCloseEvent) { + display = emptyList() + + uncoveredAt = 0 + uncoveredItems.clear() + possiblePairs = 0 + + found.clear() + toCheck.clear() + lastClicked.clear() + lastClick = SimpleTimeMark.farPast() + currentExperiment = Experiment.NONE + instantFind = 0 + } + + @SubscribeEvent + fun onChestGuiOverlayRendered(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { + if (!isEnabled()) return + config.superpairDisplayPosition.renderStrings(display, posLabel = "Superpair Experiment Information") + display = checkItems(toCheck) + } + + @SubscribeEvent + fun onSlotClick(event: SlotClickEvent) { + if (!isEnabled()) return + currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return + + if (isOutOfBounds(event.slotId, currentExperiment)) return + val item = event.item ?: return + if (item.displayName.removeColor() == "?") return + val clicksItem = InventoryUtils.getItemAtSlotIndex(4) + + if (lastClicked.none { it.first == event.slotId && it.second == uncoveredAt } && lastClick.passedSince() > 100.milliseconds) { + if (clicksItem != null && clicksItem.displayName.removeColor().split(" ")[1] == "0") return + lastClicked.add(Pair(event.slotId, uncoveredAt)) + lastClick = SimpleTimeMark.now() + toCheck.add(event.slotId to uncoveredAt) + uncoveredAt += 1 + } + } + + private fun checkItems(check: MutableList>): List { + currentExperiment = ExperimentationTableAPI.getCurrentExperiment() ?: return listOf() + if (check.isEmpty()) return drawDisplay() + + for ((slot, uncovered) in check) { + val itemNow = InventoryUtils.getItemAtSlotIndex(slot) ?: return drawDisplay() + val itemName = itemNow.displayName.removeColor() + + if (isWaiting(itemName) || isOutOfBounds(slot, currentExperiment)) return drawDisplay() + + val reward = convertToReward(itemNow) + if (uncoveredItems.none { it.first == slot }) uncoveredItems.add(Pair(slot, reward)) + + when { + isPowerUp(reward) -> handlePowerUp(slot, reward) + isReward(itemName) -> handleReward(slot, uncovered, reward) + } + + possiblePairs = calculatePossiblePairs() + + val since = clicksSinceSeparator(lastClicked) + + if ((since >= 2 || (since == -1 && lastClicked.size >= 2)) && instantFind == 0) { + lastClicked.add(-1 to uncoveredAt) + uncoveredAt += 1 + } + toCheck.removeIf { it.first == slot } + + return drawDisplay() + } + possiblePairs = calculatePossiblePairs() + return drawDisplay() + } + + private fun handlePowerUp(slot: Int, reward: String) { + val item = toEither(Item(slot, reward)) + + found[item] = "Powerup" + possiblePairs-- + lastClicked.removeIf { it.first == slot } + uncoveredAt -= 1 + if (reward == "Instant Find") instantFind += 1 + } + + private fun handleReward(slot: Int, uncovered: Int, reward: String) { + val lastSlotClicked = + if (instantFind == 0 && lastClicked.none { it.first == -1 && it.second == uncovered - 1 } && lastClicked.size != 1) lastClicked.find { it.second == uncovered - 1 } + ?: return else lastClicked.find { it.second == uncovered } ?: return + + val lastItem = InventoryUtils.getItemAtSlotIndex(lastSlotClicked.first) ?: return + val itemClicked = InventoryUtils.getItemAtSlotIndex(slot) ?: return + + val lastItemName = convertToReward(lastItem) + + if (isWaiting(lastItemName)) return + + when { + instantFind >= 1 -> { + handleFoundPair(slot, reward, lastSlotClicked.first) + instantFind -= 1 + lastClicked.add(-1 to uncoveredAt) + uncoveredAt += 1 + } + + hasFoundPair(slot, lastSlotClicked.first, reward, lastItemName) && lastItem.itemDamage == itemClicked.itemDamage -> handleFoundPair( + slot, + reward, + lastSlotClicked.first, + ) + + hasFoundMatch(slot, reward) -> handleFoundMatch(slot, reward) + else -> handleNormalReward(slot, reward) + } + + } + + private fun handleFoundPair( + slot: Int, + reward: String, + lastSlotClicked: Int, + ) { + val pair = toEither(ItemPair(Item(slot, reward), Item(lastSlotClicked, reward))) + + found[pair] = "Pair" + found.entries.removeIf { + it.value == "Match" && right(it.key).first.index == slot + } + found.entries.removeIf { + it.value == "Normal" && (left(it.key).index == slot || left(it.key).index == lastSlotClicked) + } + } + + private fun handleFoundMatch(slot: Int, reward: String) { + val match = uncoveredItems.find { it.second == reward }?.first ?: return + val pair = toEither(ItemPair(Item(slot, reward), Item(match, reward))) + + if (found.none { + listOf("Pair", "Match").contains(it.value) && (right(it.key).first.index == slot) + }) found[pair] = "Match" + found.entries.removeIf { it.value == "Normal" && (left(it.key).index == slot || left(it.key).index == match) } + } + + private fun handleNormalReward(slot: Int, reward: String) { + val item = toEither(Item(slot, reward)) + + if (found.none { + listOf("Match", "Pair").contains(it.value) && (right(it.key).first.index == slot || right(it.key).second.index == slot) + } && found.none { it.value == "Normal" && left(it.key).index == slot }) found[item] = "Normal" + } + + private fun calculatePossiblePairs() = + ((currentExperiment.gridSize - 2) / 2) - found.filter { listOf("Pair", "Match", "Normal").contains(it.value) }.size + + private fun drawDisplay() = buildList { + add("§6Superpair Experimentation Data") + add("") + + val pairs = found.entries.filter { it.value == "Pair" } + val matches = found.entries.filter { it.value == "Match" } + val powerups = found.entries.filter { it.value == "Powerup" } + val normals = found.entries.filter { it.value == "Normal" } + + if (pairs.isNotEmpty()) add("§2Found") + for (pair in pairs) { + val prefix = determinePrefix(pairs.indexOf(pair), pairs.lastIndex) + add(" $prefix §a${right(pair.key).first.name}") + } + if (matches.isNotEmpty()) add("§eMatched") + for (match in matches) { + val prefix = determinePrefix(matches.indexOf(match), matches.lastIndex) + add(" $prefix §e${right(match.key).first.name}") + } + if (powerups.isNotEmpty()) add("§bPowerUp") + for (powerup in powerups) { + val prefix = determinePrefix(powerups.indexOf(powerup), powerups.size - 1) + add(" $prefix §b${left(powerup.key).name}") + } + val toAdd = mutableListOf() + if (possiblePairs >= 1) toAdd.add("§ePairs - $possiblePairs") + if (2 - powerups.size >= 1) toAdd.add("§bPowerUps - ${2 - powerups.size}") + if (normals.isNotEmpty()) toAdd.add("§7Normals - ${normals.size}") + + if (toAdd.isNotEmpty()) { + add("") + add("§4Not found") + } + for (string in toAdd) if (string != toAdd.last()) add(" ├ $string") else add(" └ $string") + } + + private fun convertToReward(item: ItemStack) = if (item.displayName.removeColor() == "Enchanted Book") item.getLore()[2].removeColor() + else item.displayName.removeColor() + + private fun determinePrefix(index: Int, lastIndex: Int) = if (index == lastIndex) "└" else "├" + + private fun hasFoundPair( + firstSlot: Int, + secondSlot: Int, + firstName: String, + secondName: String, + ) = firstSlot != secondSlot && firstName == secondName + + private fun hasFoundMatch(itemSlot: Int, reward: String) = + uncoveredItems.any { (slot, name) -> slot != itemSlot && name == reward } && found.none { + listOf("Pair", "Match").contains(it.value) && (right(it.key).first.index == itemSlot || right(it.key).second.index == itemSlot) + } + + private fun isPowerUp(reward: String) = ExperimentationTableAPI.powerUpPattern.matches(reward) + + private fun isReward(reward: String) = ExperimentationTableAPI.rewardPattern.matches(reward) + + private fun isWaiting(itemName: String) = + listOf("Click any button!", "Click a second button!", "Next button is instantly rewarded!").contains(itemName) + + private fun clicksSinceSeparator(list: MutableList>): Int { + val lastIndex = list.indexOfLast { it.first == -1 } + return if (lastIndex != -1) list.size - 1 - lastIndex else -1 + } + + private fun isOutOfBounds(slot: Int, experiment: Experiment): Boolean = + slot <= experiment.startSlot || slot >= experiment.endSlot || (if (experiment.sideSpace == 1) slot in sideSpaces1 else slot in sideSpaces2) + + // TODO remove left and right, use custom data type instead + private fun left(it: Pair): Item = it.first ?: Item(-1, "") + + private fun right(it: Pair): ItemPair = it.second ?: ItemPair(Item(-1, ""), Item(-1, "")) + + private fun toEither(it: Any): Pair = if (it is Item) it to null else null to it as ItemPair + + private fun isEnabled() = LorenzUtils.inSkyBlock && config.superpairDisplay && ExperimentationTableAPI.getCurrentExperiment() != null +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/SuperpairsClicksAlert.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairsClicksAlert.kt similarity index 91% rename from src/main/java/at/hannibal2/skyhanni/features/inventory/SuperpairsClicksAlert.kt rename to src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairsClicksAlert.kt index 5c5011c85b1c..ef99c40bab97 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/SuperpairsClicksAlert.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/SuperpairsClicksAlert.kt @@ -1,4 +1,4 @@ -package at.hannibal2.skyhanni.features.inventory +package at.hannibal2.skyhanni.features.inventory.experimentationtable import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator @@ -14,7 +14,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @SkyHanniModule object SuperpairsClicksAlert { - private val config get() = SkyHanniMod.feature.inventory.helper.enchanting + private val config get() = SkyHanniMod.feature.inventory.experimentationTable private var roundsNeeded = -1 private val roundsNeededRegex = Regex("""(?:Chain|Series) of (\d+):""") @@ -66,5 +66,7 @@ object SuperpairsClicksAlert { @SubscribeEvent fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { event.move(46, "misc.superpairsClicksAlert", "inventory.helper.enchanting.superpairsClicksAlert") + + event.move(59, "inventory.helper.enchanting.superpairsClicksAlert", "inventory.experimentationTable.superpairsClicksAlert") } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/UltraRareBookAlert.kt b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/UltraRareBookAlert.kt similarity index 75% rename from src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/UltraRareBookAlert.kt rename to src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/UltraRareBookAlert.kt index 1cc849cad60a..e6a9dda426e9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/inventory/experiments/UltraRareBookAlert.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/inventory/experimentationtable/UltraRareBookAlert.kt @@ -1,13 +1,15 @@ -package at.hannibal2.skyhanni.features.inventory.experiments +package at.hannibal2.skyhanni.features.inventory.experimentationtable import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.InventoryUpdatedEvent +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.bookPattern +import at.hannibal2.skyhanni.features.inventory.experimentationtable.ExperimentationTableAPI.ultraRarePattern import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ColorUtils.withAlpha -import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher @@ -18,7 +20,6 @@ import at.hannibal2.skyhanni.utils.SoundUtils.createSound import at.hannibal2.skyhanni.utils.SoundUtils.playSound import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.renderables.RenderableUtils.renderXYAligned -import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft import net.minecraft.client.gui.inventory.GuiContainer import net.minecraft.client.renderer.GlStateManager @@ -29,23 +30,9 @@ import kotlin.time.Duration.Companion.seconds @SkyHanniModule object UltraRareBookAlert { - private val config get() = SkyHanniMod.feature.inventory.helper.enchanting + private val config get() = SkyHanniMod.feature.inventory.experimentationTable private val dragonSound by lazy { createSound("mob.enderdragon.growl", 1f) } - private val patternGroup = RepoPattern.group("data.enchanting") - private val superpairsGui by patternGroup.pattern( - "inventory.experimentstable.gui", - "Superpairs.*" - ) - private val ultraRarePattern by patternGroup.pattern( - "inventory.experimentstable.ultrarare", - "§d§kXX§5 ULTRA-RARE BOOK! §d§kXX" - ) - private val bookPattern by patternGroup.pattern( - "inventory.experimentstable.book", - "§9(?.*)" - ) - private var enchantsFound = false private var lastNotificationTime = SimpleTimeMark.farPast() @@ -58,9 +45,7 @@ object UltraRareBookAlert { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.ChestGuiOverlayRenderEvent) { - if (!LorenzUtils.inSkyBlock) return - if (!config.ultraRareBookAlert) return - if (!superpairsGui.matches(InventoryUtils.openInventoryName())) return + if (!isEnabled()) return if (lastNotificationTime.passedSince() > 5.seconds) return val gui = Minecraft.getMinecraft().currentScreen as? GuiContainer ?: return @@ -80,10 +65,8 @@ object UltraRareBookAlert { @SubscribeEvent fun onInventoryUpdated(event: InventoryUpdatedEvent) { - if (!LorenzUtils.inSkyBlock) return - if (!config.ultraRareBookAlert) return + if (!isEnabled()) return if (enchantsFound) return - if (!superpairsGui.matches(event.inventoryName)) return for (lore in event.inventoryItems.map { it.value.getLore() }) { val firstLine = lore.firstOrNull() ?: continue @@ -101,4 +84,12 @@ object UltraRareBookAlert { fun onInventoryClose(event: InventoryCloseEvent) { enchantsFound = false } + + @SubscribeEvent + fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { + event.move(59, "inventory.helper.enchanting.ultraRareBookAlert", "inventory.experimentationTable.ultraRareBookAlert") + } + + private fun isEnabled() = + LorenzUtils.inSkyBlock && config.ultraRareBookAlert && ExperimentationTableAPI.getCurrentExperiment() != null } diff --git a/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbility.kt b/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbility.kt index de7bc8bdf77f..020feba76976 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbility.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbility.kt @@ -2,10 +2,10 @@ package at.hannibal2.skyhanni.features.itemabilities.abilitycooldown import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.utils.LorenzColor -import at.hannibal2.skyhanni.utils.LorenzUtils.round 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.roundTo import kotlin.math.floor enum class ItemAbility( @@ -106,7 +106,7 @@ enum class ItemAbility( duration /= 100 var d = duration.toDouble() d /= 10.0 - d.round(1).addSeparators() + d.roundTo(1).addSeparators() } else { duration /= 1000 duration++ diff --git a/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbilityCooldown.kt b/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbilityCooldown.kt index 567adb251af5..5748220c5e38 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbilityCooldown.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/itemabilities/abilitycooldown/ItemAbilityCooldown.kt @@ -23,8 +23,8 @@ import at.hannibal2.skyhanni.utils.ItemUtils.getInternalName import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.between -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.highlight import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getAbilityScrolls @@ -168,7 +168,7 @@ object ItemAbilityCooldown { ItemAbility.STAFF_OF_THE_VOLCANO.sound() } // Holy Ice - event.soundName == "random.drink" && event.pitch.round(1) == 1.8f && event.volume == 1.0f -> { + event.soundName == "random.drink" && event.pitch.roundTo(1) == 1.8f && event.volume == 1.0f -> { ItemAbility.HOLY_ICE.sound() } // Royal Pigeon diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/ColdOverlay.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/ColdOverlay.kt index 8af757f6e074..58ef41ce7e8b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/ColdOverlay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/ColdOverlay.kt @@ -6,8 +6,8 @@ import at.hannibal2.skyhanni.events.ColdUpdateEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.DelayedRun +import at.hannibal2.skyhanni.utils.GuiRenderUtils import at.hannibal2.skyhanni.utils.NumberUtil -import at.hannibal2.skyhanni.utils.RenderUtils import at.hannibal2.skyhanni.utils.SimpleTimeMark import net.minecraft.client.Minecraft import net.minecraft.client.renderer.GlStateManager @@ -42,7 +42,7 @@ object ColdOverlay { GlStateManager.translate(0f, 0f, -500f) GlStateManager.color(1f, 1f, 1f, alpha) - RenderUtils.drawTexturedRect(0f, 0f) + GuiRenderUtils.drawTexturedRect(0f, 0f) GL11.glDepthMask(true) GlStateManager.popMatrix() diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/DeepCavernsGuide.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/DeepCavernsGuide.kt index 9600fbc20dd1..a1d8f43a8d5b 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/DeepCavernsGuide.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/DeepCavernsGuide.kt @@ -16,12 +16,12 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.ItemUtils 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.NEUItems.getItemStack import at.hannibal2.skyhanni.utils.ParkourHelper -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.client.player.inventory.ContainerLocalMenu import net.minecraftforge.fml.common.eventhandler.EventPriority import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -37,7 +37,7 @@ object DeepCavernsGuide { private val startIcon by lazy { val neuItem = "MAP".asInternalName().getItemStack() - Utils.createItemStack( + ItemUtils.createItemStack( neuItem.item, "§bDeep Caverns Guide", "§8(From SkyHanni)", diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/ForgeGfs.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/ForgeGfs.kt deleted file mode 100644 index 995198674334..000000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/ForgeGfs.kt +++ /dev/null @@ -1,94 +0,0 @@ -package at.hannibal2.skyhanni.features.mining - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.api.GetFromSackAPI -import at.hannibal2.skyhanni.data.SackAPI -import at.hannibal2.skyhanni.events.GuiContainerEvent -import at.hannibal2.skyhanni.events.InventoryCloseEvent -import at.hannibal2.skyhanni.events.InventoryUpdatedEvent -import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent -import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.CollectionUtils -import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut -import at.hannibal2.skyhanni.utils.ItemUtils -import at.hannibal2.skyhanni.utils.ItemUtils.getInternalNameOrNull -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.NEUInternalName -import at.hannibal2.skyhanni.utils.PrimitiveItemStack.Companion.makePrimitiveStack -import at.hannibal2.skyhanni.utils.RegexUtils.matches -import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import net.minecraft.client.player.inventory.ContainerLocalMenu -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent - -@SkyHanniModule -object ForgeGfs { - - private val patternGroup = RepoPattern.group("mining.forge") - - private val confirmScreenPattern by patternGroup.pattern( - "recipe.confirm", - "Confirm Process", - ) - - private val config get() = SkyHanniMod.feature.mining - - private val gfsFakeItem by lazy { - ItemUtils.createSkull( - displayName = "§aGet items from sacks", - uuid = "75ea8094-5152-4457-8c23-1ad9b3c176c0", - value = "ewogICJ0aW1lc3RhbXAiIDogMTU5MTMxMDU4NTYwOSwKICAicHJvZmlsZUlkIiA6ICI0MWQzYWJjMmQ3NDk0MDBjOTA5MGQ1NDM0ZDAzODMxYiIsC" + - "iAgInByb2ZpbGVOYW1lIiA6ICJNZWdha2xvb24iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogI" + - "CJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3" + - "RleHR1cmUvODBhMDc3ZTI0OGQxNDI3NzJlYTgwMDg2NGY4YzU3OGI5ZDM2ODg1YjI5ZGFmODM2YjY0YTcwNjg4MmI2ZWMxMCIKICAgIH0KICB9Cn0=", - "§8(from SkyHanni)", - "§7Click here to try to get all of this", - "§7recipe's ingredients from sacks.", - ) - } - - private var showFakeItem = false - - @SubscribeEvent - fun onInventoryOpen(event: InventoryUpdatedEvent) { - if (!isEnabled()) return - if (!confirmScreenPattern.matches(event.inventoryName)) return - - showFakeItem = true - } - - @SubscribeEvent - fun onInventoryClose(event: InventoryCloseEvent) { - showFakeItem = false - } - - @SubscribeEvent - fun replaceItem(event: ReplaceItemEvent) { - if (event.inventory is ContainerLocalMenu && showFakeItem && event.slot == 53) { - event.replace(gfsFakeItem) - } - } - - @SubscribeEvent - fun onSlotClick(event: GuiContainerEvent.SlotClickEvent) { - if (!isEnabled()) return - if (!showFakeItem || event.slotId != 53) return - - event.cancel() - - val itemMap: MutableMap = LinkedHashMap() - // Search for the first 4 columns only - // Normally would be 3, but the gemstone mixture is the only one that overflows to 4 - - for (i in CollectionUtils.takeColumn(0, 53, 0, 4)) { - val currentItem = event.container.getSlot(i).stack - val currItemInternalName = currentItem.getInternalNameOrNull() ?: continue - if (SackAPI.sackListInternalNames.contains(currItemInternalName.asString())) { - itemMap.addOrPut(currItemInternalName, currentItem.stackSize) - } - } - - GetFromSackAPI.getFromSack(itemMap.map { it.key.makePrimitiveStack(it.value) }) - } - - fun isEnabled() = LorenzUtils.inSkyBlock && config.forgeGfs -} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt index 77d580a0b194..4415b59f5872 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/MineshaftPityDisplay.kt @@ -15,11 +15,10 @@ import at.hannibal2.skyhanni.events.mining.OreMinedEvent import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay.PityBlock.Companion.getPity import at.hannibal2.skyhanni.features.mining.MineshaftPityDisplay.PityBlock.Companion.getPityBlock import at.hannibal2.skyhanni.features.mining.OreType.Companion.getOreType -import at.hannibal2.skyhanni.features.mining.OreType.Companion.isGemstone import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables import at.hannibal2.skyhanni.utils.SimpleTimeMark @@ -86,9 +85,12 @@ object MineshaftPityDisplay { fun onOreMined(event: OreMinedEvent) { if (!MiningAPI.inGlacialTunnels()) return - event.originalOre.getPityBlock()?.let { it.blocksBroken++ } + val originalOre = event.originalOre + originalOre?.getPityBlock()?.let { it.blocksBroken++ } event.extraBlocks.toMutableMap() - .apply { addOrPut(event.originalOre, -1) } + .apply { + if (originalOre != null) addOrPut(originalOre, -1) + } .map { (block, amount) -> block.getPityBlock()?.let { it.efficientMiner += amount } } @@ -116,7 +118,7 @@ object MineshaftPityDisplay { add("§7Pity Counter: §e$pityCounter") add( "§7Chance: " + - "§e1§6/§e${chance.round(1)} " + + "§e1§6/§e${chance.roundTo(1)} " + "§7(§b${((1.0 / chance) * 100).addSeparators()}%§7)", ) minedBlocks.forEach { @@ -164,7 +166,7 @@ object MineshaftPityDisplay { // if the chance is 1/1500, it will return 1500 private fun calculateChance(counter: Int): Double { val surveyorPercent = HotmData.SURVEYOR.getReward()[HotmReward.MINESHAFT_CHANCE] ?: 0.0 - val peakMountainPercent = HotmData.PEAK_OF_THE_MOUNTAIN.getReward()[HotmReward.MINESHAFT_CHANCE] ?: 0.0 + val peakMountainPercent = HotmData.CORE_OF_THE_MOUNTAIN.getReward()[HotmReward.MINESHAFT_CHANCE] ?: 0.0 val chance = counter / (1 + surveyorPercent / 100 + peakMountainPercent / 100) return chance } @@ -212,7 +214,7 @@ object MineshaftPityDisplay { MineshaftPityLine.COUNTER to Renderable.string("§3Pity Counter: §e$counterUntilPity§6/§e$MAX_COUNTER"), MineshaftPityLine.CHANCE to Renderable.string( "§3Chance: §e1§6/§e${ - chance.round(1).addSeparators() + chance.roundTo(1).addSeparators() } §7(§b${((1.0 / chance) * 100).addSeparators()}%§7)", ), MineshaftPityLine.NEEDED_TO_PITY to neededToPityRenderable, diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/MiningCommissionsBlocksColor.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/MiningCommissionsBlocksColor.kt index bf7c8c2ac81f..5de75e5d1364 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/MiningCommissionsBlocksColor.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/MiningCommissionsBlocksColor.kt @@ -10,8 +10,10 @@ import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.TabListUpdateEvent -import at.hannibal2.skyhanni.features.mining.OreType.Companion.isGemstone +import at.hannibal2.skyhanni.features.mining.MiningCommissionsBlocksColor.CommissionBlock.Companion.onColor +import at.hannibal2.skyhanni.features.mining.OreType.Companion.isOreType import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ConditionalUtils.onToggle import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.TimeLimitedSet @@ -29,8 +31,8 @@ object MiningCommissionsBlocksColor { private val config get() = SkyHanniMod.feature.mining.commissionsBlocksColor - var enabled = false - var active = false + private var enabled = false + private var active = false private val patternGroup = RepoPattern.group("mining.commissions") @@ -42,14 +44,13 @@ object MiningCommissionsBlocksColor { "§a§l(?.*) §r§eCommission Complete! Visit the King §r§eto claim your rewards!", ) - var color: EnumDyeColor = EnumDyeColor.RED + private var color = EnumDyeColor.RED - private fun glass(state: IBlockState, result: Boolean): IBlockState = - if (result) { - state.withProperty(BlockCarpet.COLOR, color) - } else { - state.withProperty(BlockCarpet.COLOR, EnumDyeColor.GRAY) - } + private fun glass(state: IBlockState, result: Boolean): IBlockState = if (result) { + state.withProperty(BlockCarpet.COLOR, color) + } else { + state.withProperty(BlockCarpet.COLOR, EnumDyeColor.GRAY) + } private fun block(result: Boolean): IBlockState { val wool = Blocks.wool.defaultState @@ -65,7 +66,7 @@ object MiningCommissionsBlocksColor { private var dirty = false private var forceDirty = false - var replaceBlocksMapCache = mutableMapOf() + private var replaceBlocksMapCache = mutableMapOf() // TODO Commission API @SubscribeEvent @@ -245,4 +246,19 @@ object MiningCommissionsBlocksColor { if (oreType.isGemstone()) glass(state, highlight) else block(highlight) } } + + fun processState(state: IBlockState?): IBlockState? { + if (!enabled || !active) return state + if (state == null) return null + try { + return replaceBlocksMapCache.getOrPut(state) { + CommissionBlock.entries.firstOrNull { + state.isOreType(it.oreType) + }?.onColor(state) ?: state + } + } catch (e: Exception) { + ErrorManager.logErrorWithData(e, "Error in MiningCommissionsBlocksColor") + return state + } + } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/OreBlock.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/OreBlock.kt index 7f5582036dfd..4275a809ca92 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/OreBlock.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/OreBlock.kt @@ -6,18 +6,23 @@ import at.hannibal2.skyhanni.data.MiningAPI.inCrystalHollows import at.hannibal2.skyhanni.data.MiningAPI.inDwarvenMines import at.hannibal2.skyhanni.data.MiningAPI.inEnd import at.hannibal2.skyhanni.data.MiningAPI.inGlacite +import at.hannibal2.skyhanni.data.MiningAPI.inMineshaft import at.hannibal2.skyhanni.data.MiningAPI.inSpidersDen +import at.hannibal2.skyhanni.data.MiningAPI.inTunnels import at.hannibal2.skyhanni.utils.CollectionUtils.equalsOneOf import net.minecraft.block.BlockColored import net.minecraft.block.BlockSand +import net.minecraft.block.BlockSilverfish import net.minecraft.block.BlockStainedGlass import net.minecraft.block.BlockStainedGlassPane import net.minecraft.block.BlockStone +import net.minecraft.block.BlockStoneSlab import net.minecraft.block.BlockStoneSlabNew import net.minecraft.block.state.IBlockState import net.minecraft.init.Blocks import net.minecraft.item.EnumDyeColor + enum class OreBlock( val checkBlock: (IBlockState) -> Boolean, val checkArea: () -> Boolean, @@ -25,7 +30,7 @@ enum class OreBlock( // MITHRIL LOW_TIER_MITHRIL( checkBlock = ::isLowTierMithril, - checkArea = { inDwarvenMines || inCrystalHollows || inGlacite }, + checkArea = { inDwarvenMines || inGlacite }, ), MID_TIER_MITHRIL( checkBlock = { it.block == Blocks.prismarine }, @@ -127,9 +132,13 @@ enum class OreBlock( checkBlock = ::isHardStoneHollows, checkArea = { inCrystalHollows }, ), - HARD_STONE_GLACIAL( - checkBlock = ::isHardstoneGlacite, - checkArea = { inGlacite }, + HARD_STONE_TUNNELS( + checkBlock = ::isHardstoneTunnels, + checkArea = { inTunnels }, + ), + HARD_STONE_MINESHAFT( + checkBlock = ::isHardstoneMineshaft, + checkArea = { inMineshaft }, ), // DWARVEN BLOCKS @@ -138,10 +147,12 @@ enum class OreBlock( checkArea = { inDwarvenMines || inCrystalHollows }, ), PURE_IRON( + // currently not detected checkBlock = { it.block == Blocks.iron_block }, checkArea = { inDwarvenMines || inCrystalHollows }, ), PURE_GOLD( + // currently not detected checkBlock = { it.block == Blocks.gold_block }, checkArea = { inDwarvenMines || inCrystalHollows }, ), @@ -150,14 +161,17 @@ enum class OreBlock( checkArea = { inDwarvenMines || inCrystalHollows }, ), PURE_REDSTONE( + // currently not detected checkBlock = { it.block == Blocks.redstone_block }, checkArea = { inDwarvenMines || inCrystalHollows }, ), PURE_EMERALD( + // currently not detected checkBlock = { it.block == Blocks.emerald_block }, checkArea = { inDwarvenMines || inCrystalHollows }, ), PURE_DIAMOND( + // currently not detected checkBlock = { it.block == Blocks.diamond_block }, checkArea = { inDwarvenMines || inCrystalHollows }, ), @@ -221,14 +235,20 @@ enum class OreBlock( checkBlock = ::isHighTierUmber, checkArea = { inGlacite }, ), - LOW_TIER_TUNGSTEN( - checkBlock = { it.block == Blocks.cobblestone }, - checkArea = { inGlacite }, + + LOW_TIER_TUNGSTEN_TUNNELS( + checkBlock = ::isLowTierTungstenTunnels, + checkArea = { inTunnels }, + ), + LOW_TIER_TUNGSTEN_MINESHAFT( + checkBlock = ::isLowTierTungstenMineshaft, + checkArea = { inMineshaft }, ), HIGH_TIER_TUNGSTEN( checkBlock = { it.block == Blocks.clay }, checkArea = { inGlacite }, ), + GLACITE( checkBlock = { it.block == Blocks.packed_ice }, checkArea = { inGlacite }, @@ -240,19 +260,17 @@ enum class OreBlock( } } -private fun isLowTierMithril(state: IBlockState): Boolean { - return when (state.block) { - Blocks.wool -> state.getValue(BlockColored.COLOR) == EnumDyeColor.GRAY - Blocks.stained_hardened_clay -> state.getValue(BlockColored.COLOR) == EnumDyeColor.CYAN - else -> false - } +private fun isLowTierMithril(state: IBlockState): Boolean = when (state.block) { + Blocks.wool -> state.getValue(BlockColored.COLOR) == EnumDyeColor.GRAY + Blocks.stained_hardened_clay -> state.getValue(BlockColored.COLOR) == EnumDyeColor.CYAN + else -> false } private fun isHighTierMithril(state: IBlockState): Boolean { return (state.block == Blocks.wool && state.getValue(BlockColored.COLOR) == EnumDyeColor.LIGHT_BLUE) } -private fun isTitanium(state: IBlockState): Boolean { +fun isTitanium(state: IBlockState): Boolean { return (state.block == Blocks.stone && state.getValue(BlockStone.VARIANT) == BlockStone.EnumType.DIORITE_SMOOTH) } @@ -262,30 +280,50 @@ private fun isStone(state: IBlockState): Boolean { private fun isHardStoneHollows(state: IBlockState): Boolean { return when (state.block) { - Blocks.wool -> (state.getValue(BlockColored.COLOR) == EnumDyeColor.GRAY) - Blocks.stained_hardened_clay -> (state.getValue(BlockColored.COLOR) == EnumDyeColor.CYAN) - Blocks.stone -> (state.getValue(BlockStone.VARIANT) == BlockStone.EnumType.STONE) + Blocks.wool -> { + val color = state.getValue(BlockColored.COLOR) + color == EnumDyeColor.GRAY || color == EnumDyeColor.GREEN + } + Blocks.stained_hardened_clay -> when (state.getValue(BlockColored.COLOR)) { + EnumDyeColor.CYAN, EnumDyeColor.BROWN, EnumDyeColor.GRAY, EnumDyeColor.BLACK, + EnumDyeColor.LIME, EnumDyeColor.GREEN, EnumDyeColor.BLUE, EnumDyeColor.RED, + EnumDyeColor.SILVER -> true + else -> false + } + Blocks.clay, Blocks.stonebrick, Blocks.stone -> true else -> false } } -private fun isHardstoneGlacite(state: IBlockState): Boolean = +private fun isHardstoneTunnels(state: IBlockState): Boolean = + (state.block == Blocks.monster_egg && state.getValue(BlockSilverfish.VARIANT) == BlockSilverfish.EnumType.STONE) || + (state.block == Blocks.wool && state.getValue(BlockColored.COLOR) == EnumDyeColor.SILVER) + +private fun isHardstoneMineshaft(state: IBlockState): Boolean = (state.block == Blocks.stone && state.getValue(BlockStone.VARIANT) == BlockStone.EnumType.STONE) || - (state.block == Blocks.wool && state.getValue(BlockColored.COLOR) == EnumDyeColor.GRAY) + (state.block == Blocks.wool && state.getValue(BlockColored.COLOR) == EnumDyeColor.SILVER) private fun isRedSand(state: IBlockState): Boolean = (state.block == Blocks.sand && state.getValue(BlockSand.VARIANT) == BlockSand.EnumType.RED_SAND) -private fun isLowTierUmber(state: IBlockState): Boolean = state.block == Blocks.hardened_clay || - (state.block == Blocks.stained_hardened_clay && state.getValue(BlockColored.COLOR) == EnumDyeColor.BROWN) +private fun isLowTierUmber(state: IBlockState): Boolean = + state.block == Blocks.hardened_clay || + (state.block == Blocks.stained_hardened_clay && state.getValue(BlockColored.COLOR) == EnumDyeColor.BROWN) private fun isHighTierUmber(state: IBlockState): Boolean = (state.block == Blocks.double_stone_slab2 && state.getValue(BlockStoneSlabNew.VARIANT) == BlockStoneSlabNew.EnumType.RED_SANDSTONE) -private fun IBlockState.isGemstoneWithColor(color: EnumDyeColor): Boolean { - return when (this.block) { - Blocks.stained_glass -> color == this.getValue(BlockStainedGlass.COLOR) - Blocks.stained_glass_pane -> color == this.getValue(BlockStainedGlassPane.COLOR) - else -> false - } +private fun isLowTierTungstenTunnels(state: IBlockState): Boolean = + state.block == Blocks.monster_egg && state.getValue(BlockSilverfish.VARIANT) == BlockSilverfish.EnumType.COBBLESTONE + +private fun isLowTierTungstenMineshaft(state: IBlockState): Boolean = when (state.block) { + Blocks.stone_slab -> state.getValue(BlockStoneSlab.VARIANT) == BlockStoneSlab.EnumType.COBBLESTONE + Blocks.cobblestone, Blocks.stone_stairs -> true + else -> false +} + +private fun IBlockState.isGemstoneWithColor(color: EnumDyeColor): Boolean = when (block) { + Blocks.stained_glass -> color == getValue(BlockStainedGlass.COLOR) + Blocks.stained_glass_pane -> color == getValue(BlockStainedGlassPane.COLOR) + else -> false } diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/OreType.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/OreType.kt index 5f9743b68a0e..66c12837114a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/OreType.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/OreType.kt @@ -7,187 +7,190 @@ import net.minecraft.block.state.IBlockState enum class OreType( val oreName: String, - private val internalNameString: String, - val oreBlocks: List, - val internalName: NEUInternalName = internalNameString.asInternalName(), + internalName: String, + vararg val oreBlocks: OreBlock, ) { MITHRIL( "Mithril", "MITHRIL_ORE", - listOf(OreBlock.LOW_TIER_MITHRIL, OreBlock.MID_TIER_MITHRIL, OreBlock.HIGH_TIER_MITHRIL), + OreBlock.LOW_TIER_MITHRIL, OreBlock.MID_TIER_MITHRIL, OreBlock.HIGH_TIER_MITHRIL, ), TITANIUM( "Titanium", "TITANIUM_ORE", - listOf(OreBlock.TITANIUM), + OreBlock.TITANIUM, ), COBBLESTONE( "Cobblestone", "COBBLESTONE", - listOf(OreBlock.STONE, OreBlock.COBBLESTONE), + OreBlock.STONE, OreBlock.COBBLESTONE, ), COAL( "Coal", "COAL", - listOf(OreBlock.COAL_ORE, OreBlock.PURE_COAL), + OreBlock.COAL_ORE, OreBlock.PURE_COAL, ), IRON( "Iron", "IRON_INGOT", - listOf(OreBlock.IRON_ORE, OreBlock.PURE_IRON), + OreBlock.IRON_ORE, OreBlock.PURE_IRON, ), GOLD( "Gold", "GOLD_INGOT", - listOf(OreBlock.GOLD_ORE, OreBlock.PURE_GOLD), + OreBlock.GOLD_ORE, OreBlock.PURE_GOLD, ), LAPIS( "Lapis Lazuli", "INK_SACK-4", - listOf(OreBlock.LAPIS_ORE, OreBlock.PURE_LAPIS), + OreBlock.LAPIS_ORE, OreBlock.PURE_LAPIS, ), REDSTONE( "Redstone", "REDSTONE", - listOf(OreBlock.REDSTONE_ORE, OreBlock.PURE_REDSTONE), + OreBlock.REDSTONE_ORE, OreBlock.PURE_REDSTONE, ), EMERALD( "Emerald", "EMERALD", - listOf(OreBlock.EMERALD_ORE, OreBlock.PURE_EMERALD), + OreBlock.EMERALD_ORE, OreBlock.PURE_EMERALD, ), DIAMOND( "Diamond", "DIAMOND", - listOf(OreBlock.DIAMOND_ORE, OreBlock.PURE_DIAMOND), + OreBlock.DIAMOND_ORE, OreBlock.PURE_DIAMOND, ), NETHERRACK( "Netherrack", "NETHERRACK", - listOf(OreBlock.NETHERRACK), + OreBlock.NETHERRACK, ), QUARTZ( "Nether Quartz", "QUARTZ", - listOf(OreBlock.QUARTZ_ORE), + OreBlock.QUARTZ_ORE, ), GLOWSTONE( "Glowstone", "GLOWSTONE_DUST", - listOf(OreBlock.GLOWSTONE), + OreBlock.GLOWSTONE, ), MYCELIUM( "Mycelium", "MYCEL", - listOf(OreBlock.MYCELIUM), + OreBlock.MYCELIUM, ), RED_SAND( "Red Sand", "SAND-1", - listOf(OreBlock.RED_SAND), + OreBlock.RED_SAND, ), SULPHUR( "Sulphur", "SULPHUR_ORE", - listOf(OreBlock.SULPHUR), + OreBlock.SULPHUR, ), GRAVEL( "Gravel", "GRAVEL", - listOf(OreBlock.GRAVEL), + OreBlock.GRAVEL, ), END_STONE( "End Stone", "ENDER_STONE", - listOf(OreBlock.END_STONE), + OreBlock.END_STONE, ), OBSIDIAN( "Obsidian", "OBSIDIAN", - listOf(OreBlock.OBSIDIAN), + OreBlock.OBSIDIAN, ), HARD_STONE( "Hard Stone", "HARD_STONE", - listOf(OreBlock.HARD_STONE_HOLLOWS, OreBlock.HARD_STONE_GLACIAL), + OreBlock.HARD_STONE_HOLLOWS, OreBlock.HARD_STONE_TUNNELS, OreBlock.HARD_STONE_MINESHAFT, ), RUBY( "Ruby", "ROUGH_RUBY_GEM", - listOf(OreBlock.RUBY), + OreBlock.RUBY, ), AMBER( "Amber", "ROUGH_AMBER_GEM", - listOf(OreBlock.AMBER), + OreBlock.AMBER, ), AMETHYST( "Amethyst", "ROUGH_AMETHYST_GEM", - listOf(OreBlock.AMETHYST), + OreBlock.AMETHYST, ), JADE( "Jade", "ROUGH_JADE_GEM", - listOf(OreBlock.JADE), + OreBlock.JADE, ), SAPPHIRE( "Sapphire", "ROUGH_SAPPHIRE_GEM", - listOf(OreBlock.SAPPHIRE), + OreBlock.SAPPHIRE, ), TOPAZ( "Topaz", "ROUGH_TOPAZ_GEM", - listOf(OreBlock.TOPAZ), + OreBlock.TOPAZ, ), JASPER( "Jasper", "ROUGH_JASPER_GEM", - listOf(OreBlock.JASPER), + OreBlock.JASPER, ), OPAL( "Opal", "ROUGH_OPAL_GEM", - listOf(OreBlock.OPAL), + OreBlock.OPAL, ), AQUAMARINE( "Aquamarine", "ROUGH_AQUAMARINE_GEM", - listOf(OreBlock.AQUAMARINE), + OreBlock.AQUAMARINE, ), CITRINE( "Citrine", "ROUGH_CITRINE_GEM", - listOf(OreBlock.CITRINE), + OreBlock.CITRINE, ), ONYX( "Onyx", "ROUGH_ONYX_GEM", - listOf(OreBlock.ONYX), + OreBlock.ONYX, ), PERIDOT( "Peridot", "ROUGH_PERIDOT_GEM", - listOf(OreBlock.PERIDOT), + OreBlock.PERIDOT, ), UMBER( "Umber", "UMBER", - listOf(OreBlock.LOW_TIER_UMBER, OreBlock.HIGH_TIER_UMBER), + OreBlock.LOW_TIER_UMBER, OreBlock.HIGH_TIER_UMBER, ), TUNGSTEN( "Tungsten", "TUNGSTEN", - listOf(OreBlock.LOW_TIER_TUNGSTEN, OreBlock.HIGH_TIER_TUNGSTEN), + OreBlock.LOW_TIER_TUNGSTEN_TUNNELS, OreBlock.LOW_TIER_TUNGSTEN_MINESHAFT, OreBlock.HIGH_TIER_TUNGSTEN, ), GLACITE( "Glacite", "GLACITE", - listOf(OreBlock.GLACITE), + OreBlock.GLACITE, ), ; + val internalName: NEUInternalName = internalName.asInternalName() + + fun isGemstone(): Boolean = this in gemstones + companion object { private val gemstones = setOf( @@ -197,12 +200,15 @@ enum class OreType( ) fun IBlockState.isOreType(oreType: OreType): Boolean { - return oreType.oreBlocks.intersect(MiningAPI.currentAreaOreBlocks) - .any { it.checkBlock.invoke(this) } + for (oreBlock in oreType.oreBlocks) { + if (oreBlock !in MiningAPI.currentAreaOreBlocks) continue + if (oreBlock.checkBlock(this)) { + return true + } + } + return false } - fun OreType.isGemstone(): Boolean = this in gemstones - fun OreBlock.getOreType(): OreType? { return OreType.entries.firstOrNull { this in it.oreBlocks } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/PowderPerHotmPerk.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/PowderPerHotmPerk.kt index 58fa83753fe9..e268beb16f94 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/PowderPerHotmPerk.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/PowderPerHotmPerk.kt @@ -6,9 +6,9 @@ import at.hannibal2.skyhanni.events.LorenzToolTipEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.KeyboardManager.isKeyHeld import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.fractionOf +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.StringUtils.removeColor import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -48,7 +48,7 @@ object PowderPerHotmPerk { private fun handlePowderSpend(perk: HotmData): String { val currentPowderSpend = perk.calculateTotalCost(perk.rawLevel) val maxPowderNeeded = perk.totalCostMaxLevel - val percentage = (currentPowderSpend.fractionOf(maxPowderNeeded) * 100).round(2) + val percentage = (currentPowderSpend.fractionOf(maxPowderNeeded) * 100).roundTo(2) return when (config.powderSpentDesign) { PowderSpentDesign.NUMBER -> { 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 8d7f771b7223..5214ff162eb5 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/TunnelsMaps.kt @@ -81,6 +81,7 @@ object TunnelsMaps { private var active: String = "" private lateinit var fairySouls: Map + // TODO what is this? why is there a difference? can this be replaced with GraphNodeTag.GRIND_ORES? private lateinit var newGemstones: Map> private lateinit var oldGemstones: Map> private lateinit var normalLocations: Map> @@ -221,7 +222,7 @@ object TunnelsMaps { @SubscribeEvent fun onRepoReload(event: RepositoryReloadEvent) { - graph = event.getConstant("TunnelsGraph", gson = Graph.gson) + graph = event.getConstant("island_graphs/GLACITE_TUNNELS", gson = Graph.gson) possibleLocations = graph.groupBy { it.name }.filterNotNullKeys().mapValues { (_, value) -> value } @@ -235,7 +236,12 @@ object TunnelsMaps { key.contains("Fairy") -> fairy[key] = value.first() newGemstonePattern.matches(key) -> newGemstone[key] = value oldGemstonePattern.matches(key) -> oldGemstone[key] = value - else -> other[key] = value + else -> { + // ignore node names without color codes + if (key.removeColor() != key) { + other[key] = value + } + } } } fairySouls = fairy @@ -524,7 +530,7 @@ object TunnelsMaps { goal = getNext() } - private val areas = setOf("Glacite Tunnels", "Dwarven Base Camp", "Glacite Lake", "Fossil Research Center") + private val areas = setOf("Glacite Tunnels", "Dwarven Base Camp", "Great Glacite Lake", "Fossil Research Center") private fun isEnabled() = IslandType.DWARVEN_MINES.isInIsland() && config.enable && LorenzUtils.skyBlockArea in areas } diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventDisplay.kt index 26f41c799b32..a5c34850a2dc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventDisplay.kt @@ -33,7 +33,7 @@ object MiningEventDisplay { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!shouldDisplay()) return - config.position.renderRenderables(display, posLabel = "Upcoming Events Display") + config.position.renderRenderables(display, posLabel = "Upcoming Mining Events") } private fun updateDisplay() { diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt index 97806b6fb0ad..a076ba68f0c3 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/eventtracker/MiningEventTracker.kt @@ -13,7 +13,7 @@ import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.SecondPassedEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.APIUtils import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland @@ -160,7 +160,7 @@ object MiningEventTracker { private fun sendData(json: String) { val response = try { - APIUtil.postJSON("https://api.soopy.dev/skyblock/chevents/set", json) + APIUtils.postJSON("https://api.soopy.dev/skyblock/chevents/set", json) } catch (e: IOException) { if (LorenzUtils.debug) { ErrorManager.logErrorWithData( @@ -194,7 +194,7 @@ object MiningEventTracker { canRequestAt = SimpleTimeMark.now() + defaultCooldown SkyHanniMod.coroutineScope.launch { val data = try { - APIUtil.getJSONResponse("https://api.soopy.dev/skyblock/chevents/get") + APIUtils.getJSONResponse("https://api.soopy.dev/skyblock/chevents/get") } catch (e: Exception) { apiErrorCount++ canRequestAt = SimpleTimeMark.now() + 20.minutes diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/ExcavatorTooltipHider.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/ExcavatorTooltipHider.kt new file mode 100644 index 000000000000..0b0469b91675 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/ExcavatorTooltipHider.kt @@ -0,0 +1,44 @@ +package at.hannibal2.skyhanni.features.mining.fossilexcavator + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.LorenzToolTipEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ItemUtils.name +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.client.player.inventory.ContainerLocalMenu +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object ExcavatorTooltipHider { + + private val config get() = SkyHanniMod.feature.mining.fossilExcavator.tooltipHider + + /** + * REGEX-TEST: §6Dirt + */ + private val dirtPattern by RepoPattern.pattern( + "excavator.dirt.name", + "§6Dirt", + ) + + @SubscribeEvent + fun onTooltip(event: LorenzToolTipEvent) { + if (!isEnabled()) return + + if (event.slot.inventory !is ContainerLocalMenu) return + if (config.hideEverything) { + event.cancel() + return + } + + if (config.hideDirt) { + val isDirt = dirtPattern.matches(event.itemStack.name) + if (isDirt) { + event.cancel() + } + } + } + + fun isEnabled() = FossilExcavatorAPI.inInventory && !FossilExcavatorAPI.inExcavatorMenu +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/solver/FossilSolverDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/solver/FossilSolverDisplay.kt index 82fc73030a45..cb50e3c85459 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/solver/FossilSolverDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/fossilexcavator/solver/FossilSolverDisplay.kt @@ -17,7 +17,7 @@ import at.hannibal2.skyhanni.utils.InventoryUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.RenderUtils.highlight import at.hannibal2.skyhanni.utils.RenderUtils.renderString @@ -218,7 +218,7 @@ object FossilSolverDisplay { } fun nextData(slotToClick: FossilTile, correctPercentage: Double, fossilsRemaining: Int) { - val formattedPercentage = (correctPercentage * 100).round(1) + val formattedPercentage = (correctPercentage * 100).roundTo(1) possibleFossilsRemaining = fossilsRemaining FossilSolverDisplay.slotToClick = slotToClick.toSlotIndex() diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseTracker.kt index c54315d7e430..3e81a01a9588 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/CorpseTracker.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.features.mining.glacitemineshaft import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.data.MiningAPI import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.mining.CorpseLootedEvent @@ -16,6 +17,7 @@ import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.NEUInternalName import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.renderables.Searchable import at.hannibal2.skyhanni.utils.renderables.toSearchable @@ -64,9 +66,10 @@ object CorpseTracker { private fun addLootedCorpse(type: CorpseType) = tracker.modify { it.corpsesLooted.addOrPut(type, 1) } @SubscribeEvent - fun onCorpseLoot(event: CorpseLootedEvent) { + fun onCorpseLooted(event: CorpseLootedEvent) { addLootedCorpse(event.corpseType) for ((itemName, amount) in event.loot) { + if (itemName.removeColor().trim() == "Glacite Powder") continue NEUInternalName.fromItemNameOrNull(itemName)?.let { item -> tracker.modify { it.addItem(event.corpseType, item, amount) @@ -82,8 +85,8 @@ object CorpseTracker { if (bucketData.getCorpseCount() == 0L) return@buildList var profit = tracker.drawItems(bucketData, { true }, this) - val applicableKeys: List = bucketData.getSelectedBucket()?.let { listOf(it) } - ?: enumValues().toList().filter { bucketData.corpsesLooted[it] != null } + val applicableKeys: List = bucketData.getSelectedBucket()?.let { listOf(it) } ?: enumValues().toList() + .filter { bucketData.corpsesLooted[it] != null } var totalKeyCost = 0.0 var totalKeyCount = 0 val keyCostStrings = buildList { @@ -138,5 +141,5 @@ object CorpseTracker { } fun isEnabled() = - config.enabled && IslandType.DWARVEN_MINES.isInIsland() && (!config.onlyInMineshaft || IslandType.MINESHAFT.isInIsland()) + LorenzUtils.inSkyBlock && config.enabled && (IslandType.MINESHAFT.isInIsland() || (!config.onlyInMineshaft && MiningAPI.inGlacialTunnels())) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt index 7476e212b455..ae17e783bb16 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/MineshaftWaypoints.kt @@ -38,7 +38,7 @@ object MineshaftWaypoints { fun onIslandChange(event: IslandChangeEvent) { if (event.newIsland != IslandType.MINESHAFT) return - val playerLocation = LocationUtils.playerLocation().round(0).add(y = -1) + val playerLocation = LocationUtils.playerLocation().roundTo(0).add(y = -1) if (config.mineshaftWaypoints.entranceLocation) { waypoints.add(MineshaftWaypoint(waypointType = MineshaftWaypointType.ENTRANCE, location = playerLocation)) diff --git a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/ProfitPerMineshaftCorpse.kt b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/ProfitPerMineshaftCorpse.kt index 7eebeeaab890..78f4b07eda74 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/ProfitPerMineshaftCorpse.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/mining/glacitemineshaft/ProfitPerMineshaftCorpse.kt @@ -18,7 +18,7 @@ object ProfitPerMineshaftCorpse { private val config get() = SkyHanniMod.feature.mining.mineshaft @SubscribeEvent - fun onFossilExcavation(event: CorpseLootedEvent) { + fun onCorpseLooted(event: CorpseLootedEvent) { if (!config.profitPerCorpseLoot) return val loot = event.loot diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/CarryTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/CarryTracker.kt new file mode 100644 index 000000000000..bfecbc48f57f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/CarryTracker.kt @@ -0,0 +1,326 @@ +package at.hannibal2.skyhanni.features.misc + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.HandleEvent +import at.hannibal2.skyhanni.data.jsonobjects.repo.CarryTrackerJson +import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.events.entity.slayer.SlayerDeathEvent +import at.hannibal2.skyhanni.features.slayer.SlayerType +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.addString +import at.hannibal2.skyhanni.utils.HypixelCommands +import at.hannibal2.skyhanni.utils.KeyboardManager +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.NumberUtil.formatDoubleOrUserError +import at.hannibal2.skyhanni.utils.NumberUtil.formatIntOrUserError +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderables +import at.hannibal2.skyhanni.utils.StringUtils.cleanPlayerName +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration.Companion.seconds + +/** + * TODO more carry features + * save on restart + * support for Dungeon, Kuudra, crimson minibosses + * average spawn time per slayer customer + * change customer name color if offline, onlilne, on your island + * show time since last boss died next to slayer customer name + * highlight slayer bosses for slayer customers + * automatically mark customers with /shmarkplaayers + * show a line behind them + */ + +@SkyHanniModule +object CarryTracker { + private val config get() = SkyHanniMod.feature.misc + + private val customers = mutableListOf() + private val carryTypes = mutableMapOf() + private var slayerNames = emptyMap>() + + private var display = listOf() + + private val patternGroup = RepoPattern.group("carry") + + /** + * REGEX-TEST: + * §6Trade completed with §r§b[MVP§r§c+§r§b] ClachersHD§r§f§r§6! + */ + private val tradeCompletedPattern by patternGroup.pattern( + "trade.completed", + "§6Trade completed with (?.*)§r§6!", + ) + + /** + * REGEX-TEST: + * §r§a§l+ §r§6500k coins + */ + private val rawNamePattern by patternGroup.pattern( + "trade.coins.gained", + " §r§a§l\\+ §r§6(?.*) coins", + ) + + @HandleEvent + fun onSlayerDeath(event: SlayerDeathEvent) { + val slayerType = event.slayerType + val tier = event.tier + val owner = event.owner + for (customer in customers) { + if (!customer.name.equals(owner, ignoreCase = true)) continue + for (carry in customer.carries) { + val type = carry.type as? SlayerCarryType ?: return + if (type.slayerType != slayerType) continue + if (type.tier != tier) continue + carry.done++ + if (carry.done == carry.requested) { + ChatUtils.chat("Carry done for ${customer.name}!") + LorenzUtils.sendTitle("§eCarry done!", 3.seconds) + } + update() + } + } + } + + // TODO create trade event with player name, coins and items + var lastTradedPlayer = "" + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + tradeCompletedPattern.matchMatcher(event.message) { + lastTradedPlayer = group("name").cleanPlayerName() + } + + rawNamePattern.matchMatcher(event.message) { + val coinsGained = group("coins").formatDouble() + getCustomer(lastTradedPlayer).alreadyPaid += coinsGained + update() + } + } + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val data = event.getConstant("CarryTracker") + slayerNames = data.slayerNames.mapKeys { SlayerType.valueOf(it.key) } + } + + @SubscribeEvent + fun onRenderOverlay(event: GuiRenderEvent) { + if (!LorenzUtils.inSkyBlock) return + + config.carryPosition.renderRenderables(display, posLabel = "Carry Tracker") + } + + fun onCommand(args: Array) { + if (args.size < 2 || args.size > 3) { + ChatUtils.userError("Usage:\n§c/shcarry \n§c/shcarry ") + return + } + if (args.size == 2) { + setPrice(args[0], args[1]) + return + } + + val customerName = args[0] + + val rawType = args[1] + val carryType = getCarryType(rawType) ?: return + + val amountRequested = args[2].formatIntOrUserError() ?: return + + val newCarry = Carry(carryType, amountRequested) + + for (customer in customers) { + if (!customer.name.equals(customerName, ignoreCase = true)) continue + val carries = customer.carries + for (carry in carries.toList()) { + if (!newCarry.type.sameType(carry.type)) continue + val newAmountRequested = carry.requested + amountRequested + if (newAmountRequested < 1) { + ChatUtils.userError("New carry amount requested must be positive!") + return + } + carries.remove(carry) + val updatedCarry = Carry(carryType, newAmountRequested) + updatedCarry.done = carry.done + carries.add(updatedCarry) + update() + ChatUtils.chat("Updated carry: §b$customerName §8x$newAmountRequested ${newCarry.type}") + return + } + } + if (amountRequested < 1) { + ChatUtils.userError("Carry amount requested must be positive!") + return + } + + val customer = getCustomer(customerName) + customer.carries.add(newCarry) + update() + ChatUtils.chat("Started carry: §b$customerName §8x$amountRequested ${newCarry.type}") + } + + private fun getCarryType(rawType: String): CarryType? = carryTypes.getOrPut(rawType) { + createCarryType(rawType) ?: run { + ChatUtils.userError("Unknown carry type: '$rawType'! Use e.g. rev5, sven4, eman3, blaze2..") + return null + } + } + + private fun setPrice(rawType: String, rawPrice: String) { + val carryType = getCarryType(rawType) ?: return + + val price = rawPrice.formatDoubleOrUserError() ?: return + carryType.pricePer = price + update() + ChatUtils.chat("Set carry price for $carryType §eto §6${price.shortFormat()} coins.") + } + + private fun getCustomer(customerName: String): Customer { + for (customer in customers) { + if (customer.name.equals(customerName, ignoreCase = true)) { + return customer + } + } + val customer = Customer(customerName) + customers.add(customer) + return customer + } + + private fun CarryType.sameType(other: CarryType): Boolean = name == other.name && tier == other.tier + + private fun update() { + val list = mutableListOf() + if (customers.none { it.carries.isNotEmpty() }) { + display = emptyList() + return + } + list.addString("§c§lCarries") + for (customer in customers) { + if (customer.carries.isEmpty()) continue + addCustomerName(customer, list) + + val carries = customer.carries + for (carry in carries) { + val requested = carry.requested + val done = carry.done + val missing = requested - done + + val color = if (done > requested) "§c" else if (done == requested) "§a" else "§e" + val cost = formatCost(carry.type.pricePer?.let { it * requested }) + val text = "$color$done§8/$color$requested $cost" + list.add( + Renderable.clickAndHover( + Renderable.string(" ${carry.type} $text"), + tips = buildList { + add("§b${customer.name}' ${carry.type} §cCarry") + add("") + add("§7Requested: §e$requested") + add("§7Done: §e$done") + add("§7Missing: §e$missing") + add("") + if (cost != "") { + add("§7Total cost: §e${cost}") + add("§7Cost per carry: §e${formatCost(carry.type.pricePer)}") + } else { + add("§cNo price set for this carry!") + add("§7Set a price with §e/shcarry ") + } + add("") + add("§eClick to send current progress in the party chat!") + add("§eControl-click to remove this carry!") + }, + onClick = { + if (KeyboardManager.isModifierKeyDown()) { + carries.remove(carry) + update() + } else { + HypixelCommands.partyChat( + "${customer.name} ${carry.type.toString().removeColor()} carry: $done/$requested", + ) + } + }, + ), + ) + } + } + display = list + } + + private fun addCustomerName(customer: Customer, list: MutableList) { + val customerName = customer.name + val totalCost = customer.carries.sumOf { it.getCost() ?: 0.0 } + val totalCostFormat = formatCost(totalCost) + if (totalCostFormat != "") { + val paidFormat = "§6${customer.alreadyPaid.shortFormat()}" + val missingFormat = formatCost(totalCost - customer.alreadyPaid) + list.add( + Renderable.clickAndHover( + Renderable.string("§b$customerName $paidFormat§8/${totalCostFormat}"), + tips = listOf( + "§7Carries for §b$customerName", + "", + "§7Total cost: $totalCostFormat", + "§7Already paid: $paidFormat", + "§7Still missing: $missingFormat", + "", + "§eClick to send missing coins in party chat!", + ), + onClick = { + HypixelCommands.partyChat( + "$customerName Carry: already paid: ${paidFormat.removeColor()}, " + "still missing: ${missingFormat.removeColor()}", + ) + }, + ), + ) + + } else { + list.addString("§b$customerName$totalCostFormat") + } + } + + private fun Carry.getCost(): Double? { + return type.pricePer?.let { + requested * it + }?.takeIf { it != 0.0 } + } + + private fun formatCost(totalCost: Double?): String = if (totalCost == 0.0 || totalCost == null) "" else "§6${totalCost.shortFormat()}" + + private fun createCarryType(input: String): CarryType? { + if (input.length == 1) return null + val rawName = input.dropLast(1).lowercase() + val tier = input.last().digitToIntOrNull() ?: return null + + getSlayerType(rawName)?.let { + return SlayerCarryType(it, tier) + } + + return null + } + + private fun getSlayerType(name: String): SlayerType? = slayerNames.entries.find { name in it.value }?.key + + class Customer( + val name: String, + var alreadyPaid: Double = 0.0, + val carries: MutableList = mutableListOf(), + ) + + class Carry(val type: CarryType, val requested: Int, var done: Int = 0) + + abstract class CarryType(val name: String, val tier: Int, var pricePer: Double? = null) { + override fun toString(): String = "§d$name $tier" + } + + class SlayerCarryType(val slayerType: SlayerType, tier: Int) : CarryType(slayerType.displayName, tier) +// class DungeonCarryType(val floor: DungeonFloor, masterMode: Boolean) : CarryType(floor.name, tier) +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt index c5c0071f95da..5ece5897c5df 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/IslandAreas.kt @@ -6,7 +6,6 @@ import at.hannibal2.skyhanni.data.model.Graph import at.hannibal2.skyhanni.data.model.GraphNode import at.hannibal2.skyhanni.data.model.GraphNodeTag import at.hannibal2.skyhanni.data.model.TextInput -import at.hannibal2.skyhanni.data.model.findShortestPathAsGraphWithDistance import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.EntityMoveEvent import at.hannibal2.skyhanni.events.GuiRenderEvent @@ -19,17 +18,19 @@ import at.hannibal2.skyhanni.utils.CollectionUtils.addSearchString import at.hannibal2.skyhanni.utils.CollectionUtils.sorted import at.hannibal2.skyhanni.utils.ColorUtils.toChromaColor import at.hannibal2.skyhanni.utils.ConditionalUtils +import at.hannibal2.skyhanni.utils.GraphUtils import at.hannibal2.skyhanni.utils.LocationUtils.canBeSeen import at.hannibal2.skyhanni.utils.LocationUtils.distanceToPlayer import at.hannibal2.skyhanni.utils.LorenzColor import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.drawDynamicText import at.hannibal2.skyhanni.utils.RenderUtils.renderRenderable import at.hannibal2.skyhanni.utils.renderables.Renderable import at.hannibal2.skyhanni.utils.renderables.Searchable import at.hannibal2.skyhanni.utils.renderables.buildSearchBox import at.hannibal2.skyhanni.utils.renderables.toSearchable +import kotlinx.coroutines.launch import net.minecraft.client.Minecraft import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration.Companion.seconds @@ -40,9 +41,9 @@ object IslandAreas { private var nodes = mapOf() private var paths = mapOf() - private var display: Renderable? = null + var display: Renderable? = null private var targetNode: GraphNode? = null - private var currentAreaName = "" + var currentAreaName = "" private val textInput = TextInput() @SubscribeEvent @@ -54,7 +55,9 @@ object IslandAreas { } fun noteMoved() { - updateNodes() + SkyHanniMod.coroutineScope.launch { + updateNodes() + } } private fun updateNodes() { @@ -62,19 +65,10 @@ object IslandAreas { val graph = IslandGraphs.currentIslandGraph ?: return val closedNote = IslandGraphs.closedNote ?: return - val paths = mutableMapOf() - - val map = mutableMapOf() - for (graphNode in graph.nodes) { - if (graphNode.getAreaTag() == null) continue - val (path, distance) = graph.findShortestPathAsGraphWithDistance(closedNote, graphNode) - paths[graphNode] = path - map[graphNode] = distance - } + val (paths, map) = GraphUtils.findFastestPaths(graph, closedNote) { it.getAreaTag() != null } this.paths = paths val finalNodes = mutableMapOf() - val alreadyFoundAreas = mutableListOf() for ((node, distance) in map.sorted()) { val areaName = node.name ?: continue @@ -109,7 +103,7 @@ object IslandAreas { } } - private fun updatePosition() { + fun updatePosition() { display = buildDisplay().buildSearchBox(textInput) } @@ -170,7 +164,7 @@ object IslandAreas { } } - val distance = difference.round(1) + val distance = difference.roundTo(1) val text = "${coloredName}§7: §e$distance$suffix" if (!foundCurrentArea) { @@ -268,8 +262,8 @@ object IslandAreas { private val allAreas = listOf(GraphNodeTag.AREA, GraphNodeTag.SMALL_AREA) private val onlyLargeAreas = listOf(GraphNodeTag.AREA) - private fun GraphNode.getAreaTag(): GraphNodeTag? = tags.firstOrNull { - it in (if (config.includeSmallAreas) allAreas else onlyLargeAreas) + fun GraphNode.getAreaTag(ignoreConfig: Boolean = false): GraphNodeTag? = tags.firstOrNull { + it in (if (config.includeSmallAreas || ignoreConfig) allAreas else onlyLargeAreas) } private fun setTarget(node: GraphNode) { diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/MovementSpeedDisplay.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/MovementSpeedDisplay.kt index 50148f031878..685ffa3cdc25 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/MovementSpeedDisplay.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/MovementSpeedDisplay.kt @@ -7,8 +7,8 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.BlockUtils.getBlockAt import at.hannibal2.skyhanni.utils.LocationUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.LorenzVec +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderString import net.minecraft.client.Minecraft import net.minecraft.init.Blocks @@ -59,7 +59,7 @@ object MovementSpeedDisplay { } usingSoulsandSpeed = movingOnSoulsand && soulsandSpeeds.size == 6 if (isEnabled()) { - display = "Movement Speed: ${speed.round(2)}" + display = "Movement Speed: ${speed.roundTo(2)}" } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/PrivateIslandNoPickaxeAbility.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/PrivateIslandNoPickaxeAbility.kt index a29bcecc5ba7..dc55af349d14 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/PrivateIslandNoPickaxeAbility.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/PrivateIslandNoPickaxeAbility.kt @@ -21,12 +21,10 @@ object PrivateIslandNoPickaxeAbility { if (!config.privateIslandNoPickaxeAbility) return if (event.clickType != ClickType.RIGHT_CLICK) return - when (event.itemInHand?.getItemCategoryOrNull()) { - ItemCategory.GAUNTLET, ItemCategory.PICKAXE, ItemCategory.DRILL -> { - event.cancel() - } - - else -> {} + if (event.itemInHand?.getItemCategoryOrNull()?.let { + ItemCategory.miningTools.contains(it) + } == true) { + event.cancel() } } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/TpsCounter.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/TpsCounter.kt index 0a3a60295371..01d84daa3fdc 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/TpsCounter.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/TpsCounter.kt @@ -10,7 +10,7 @@ import at.hannibal2.skyhanni.events.minecraft.packet.PacketReceivedEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderString import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.concurrent.fixedRateTimer @@ -55,7 +55,7 @@ object TpsCounter { "§eTPS: §f(${current}s)" } else { val sum = tpsList.sum().toDouble() - var tps = (sum / tpsList.size).round(1) + var tps = (sum / tpsList.size).roundTo(1) if (tps > 20) tps = 20.0 val color = getColor(tps) "§eTPS: $color$tps" diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/UserLuckBreakdown.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/UserLuckBreakdown.kt index d4532a77527a..f1fad4e63aca 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/UserLuckBreakdown.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/UserLuckBreakdown.kt @@ -10,17 +10,17 @@ import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.features.skillprogress.SkillType import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.CollectionUtils.addOrPut +import at.hannibal2.skyhanni.utils.ItemUtils import at.hannibal2.skyhanni.utils.ItemUtils.getLore import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUItems.getItemStack import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.client.player.inventory.ContainerLocalMenu import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -160,7 +160,7 @@ object UserLuckBreakdown { skillCalcCoolDown = SimpleTimeMark.now() calcSkillLuck() } - val limboLuck = storage?.limbo?.userLuck?.round(1) ?: 0.0f + val limboLuck = storage?.limbo?.userLuck?.roundTo(1) ?: 0.0f when (event.slot.inventory.name) { "Your Equipment and Stats" -> equipmentMenuTooltip(event, limboLuck) "Your Stats Breakdown" -> statsBreakdownLoreTooltip(event, limboLuck) @@ -237,9 +237,11 @@ object UserLuckBreakdown { } private fun createItems() { - fillerItem = Utils.createItemStack( + fillerItem = ItemUtils.createItemStack( fillerID.getItemStack().item, fillerName, + listOf(), + 1, 15, ) @@ -247,17 +249,17 @@ object UserLuckBreakdown { val skillLuck = skillOverflowLuck.values.sum() val totalLuck = skillLuck + limboLuck - mainLuckItem = Utils.createItemStack( + mainLuckItem = ItemUtils.createItemStack( mainLuckID.getItemStack().item, "$mainLuckName §f${tryTruncateFloat(totalLuck)}", *createItemLore("mainMenu", totalLuck), ) - limboItem = Utils.createItemStack( + limboItem = ItemUtils.createItemStack( limboID.getItemStack().item, limboName, *createItemLore("limbo", limboLuck), ) - skillsItem = Utils.createItemStack( + skillsItem = ItemUtils.createItemStack( skillsID.getItemStack().item, skillsName, *createItemLore("skills"), @@ -268,7 +270,7 @@ object UserLuckBreakdown { calcSkillLuck() return when (type) { "mainMenu" -> { - val luckString = tryTruncateFloat(luckInput.round(2)) + val luckString = tryTruncateFloat(luckInput.roundTo(2)) if (luckInput == 0.0f) { arrayOf( "§7SkyHanni User Luck is the best stat.", @@ -291,7 +293,7 @@ object UserLuckBreakdown { } "limbo" -> { - val luckString = tryTruncateFloat(luckInput.round(2)) + val luckString = tryTruncateFloat(luckInput.roundTo(2)) arrayOf( "§8Action", "", diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordLocationKey.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordLocationKey.kt index 96759bc7d2e5..895a04688f80 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordLocationKey.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/discordrpc/DiscordLocationKey.kt @@ -159,7 +159,7 @@ object DiscordLocationKey { "Dwarven Base Camp" to "glacite-tunnels", "Fossil Research Center" to "glacite-tunnels", - "Glacite Lake" to "glacite-tunnels", + "Great Glacite Lake" to "glacite-tunnels", "Glacite Mineshafts" to "glacite-tunnels", ) // maps sublocations to their broader image diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt index 6842ccc77620..b0fbc2f31f83 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/items/EstimatedItemValueCalculator.kt @@ -20,13 +20,13 @@ import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.LorenzRarity 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.getItemStackOrNull import at.hannibal2.skyhanni.utils.NEUItems.getNpcPriceOrNull import at.hannibal2.skyhanni.utils.NEUItems.getPriceOrNull import at.hannibal2.skyhanni.utils.NEUItems.getRawCraftCostOrNull import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat +import at.hannibal2.skyhanni.utils.PrimitiveIngredient import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getAbilityScrolls import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getArmorDye @@ -58,7 +58,6 @@ import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.hasJalapenoBook import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.hasWoodSingularity import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.isRecombobulated import at.hannibal2.skyhanni.utils.StringUtils.allLettersFirstUppercase -import io.github.moulberry.notenoughupdates.recipes.Ingredient import io.github.notenoughupdates.moulconfig.observer.Property import net.minecraft.item.ItemStack import java.util.Locale @@ -499,11 +498,6 @@ object EstimatedItemValueCalculator { if (remainingStars <= 0) continue val price = getPriceFor(prices, remainingStars) ?: return null - println(" ") - println("price for $id ($remainingStars)") - println("price.itemPrice: ${price.itemPrice}") - println("essencePrice: ${price.essencePrice}") - println("itemPrice: ${price.itemPrice}") finalPrice = finalPrice?.let { it + price } ?: price remainingStars -= prices.size } @@ -528,7 +522,7 @@ object EstimatedItemValueCalculator { return kuudraUpgradeTiers.indexOf(tier) } } - return 0 + return -1 } // private fun getKuudraTier(internalName: NEUInternalName): Int? = // kuudraUpgradeTiers.firstOrNull { it in internalName.toString() }?.let { kuudraUpgradeTiers.indexOf(it) } @@ -889,12 +883,12 @@ object EstimatedItemValueCalculator { val previousTotal = totalPrice for (ingredients in slot.value) { - val ingredient = Ingredient(NEUItems.manager, ingredients) + val ingredient = PrimitiveIngredient(ingredients) - totalPrice += if (ingredient.isCoins) { + totalPrice += if (ingredient.isCoin()) { ingredient.count } else { - ingredient.internalItemId.asInternalName().getPrice() * ingredient.count + ingredient.internalName.getPrice() * ingredient.count } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboPlaytime.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboPlaytime.kt index 0996701f23ca..1c46b40d6529 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboPlaytime.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboPlaytime.kt @@ -6,15 +6,15 @@ import at.hannibal2.skyhanni.events.InventoryOpenEvent import at.hannibal2.skyhanni.events.LorenzToolTipEvent import at.hannibal2.skyhanni.events.render.gui.ReplaceItemEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.ItemUtils import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NEUInternalName.Companion.asInternalName import at.hannibal2.skyhanni.utils.NEUItems.getItemStack import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RegexUtils.matches import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern -import io.github.moulberry.notenoughupdates.util.Utils import net.minecraft.client.player.inventory.ContainerLocalMenu import net.minecraft.item.ItemStack import net.minecraftforge.fml.common.eventhandler.SubscribeEvent @@ -58,7 +58,7 @@ object LimboPlaytime { if (lastCreateCooldown.passedSince() > 3.seconds) { lastCreateCooldown = SimpleTimeMark.now() - limboItem = Utils.createItemStack( + limboItem = ItemUtils.createItemStack( itemID.getItemStack().item, itemName, *createItemLore() @@ -105,7 +105,7 @@ object LimboPlaytime { if ((wholeMinutes % 60) == 0) { hoursString = "$wholeHours" } else { - val minutes: Float = ((wholeMinutes - wholeHours * 60).toFloat() / 60).round(1) + val minutes: Float = ((wholeMinutes - wholeHours * 60).toFloat() / 60).roundTo(1) hoursString = wholeHours.addSeparators() if (findFloatDecimalPlace(minutes) != 0) { val minutesString = minutes.toString() diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboTimeTracker.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboTimeTracker.kt index 62f4c46561c6..bfb8ce715d2f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboTimeTracker.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/limbo/LimboTimeTracker.kt @@ -15,7 +15,7 @@ import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LocationUtils.isPlayerInside import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.RenderUtils.renderString import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.TimeUtils.format @@ -116,7 +116,7 @@ object LimboTimeTracker { if (passedSince > currentPB) { oldPB = currentPB storage?.personalBest = passedSince.toInt(DurationUnit.SECONDS) - userLuck = ((storage?.personalBest ?: 0) * USER_LUCK_MULTIPLIER).round(2) + userLuck = ((storage?.personalBest ?: 0) * USER_LUCK_MULTIPLIER).roundTo(2) if (onFire) userLuck *= FIRE_MULTIPLIER ChatUtils.chat("§fYou were in Limbo for §e$duration§f! §d§lPERSONAL BEST§r§f!") if (oldPB != 0.seconds) { @@ -126,9 +126,9 @@ object LimboTimeTracker { } else ChatUtils.chat("§fYou were in Limbo for §e$duration§f.") if (userLuck > oldLuck) { if (onFire) { - ChatUtils.chat("§fYour §aPersonal Bests§f perk is now granting you §a+${userLuck.round(2)}§c✴ §aSkyHanni User Luck§f! ") + ChatUtils.chat("§fYour §aPersonal Bests§f perk is now granting you §a+${userLuck.roundTo(2)}§c✴ §aSkyHanni User Luck§f! ") } else { - ChatUtils.chat("§fYour §aPersonal Bests§f perk is now granting you §a+${userLuck.round(2)}✴ SkyHanni User Luck§f!") + ChatUtils.chat("§fYour §aPersonal Bests§f perk is now granting you §a+${userLuck.roundTo(2)}✴ SkyHanni User Luck§f!") } storage?.userLuck = userLuck } @@ -152,7 +152,7 @@ object LimboTimeTracker { val currentPB = storage?.personalBest ?: 0 val userLuck = storage?.userLuck ?: 0f val limboPB: Int = if (currentPB < timeInLimbo) timeInLimbo else currentPB - var luckString = tryTruncateFloat(userLuck.round(2)) + var luckString = tryTruncateFloat(userLuck.roundTo(2)) if (userLuck > 0) luckString = "+$luckString" var firstMessage = "§fYour current PB is §e${limboPB.seconds}§f, granting you §a$luckString✴ SkyHanni User Luck§f!" diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt index a68978caec21..bbe40db5cd4a 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/massconfiguration/DefaultConfigOptionGui.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.features.misc.massconfiguration -import io.github.moulberry.notenoughupdates.util.Utils +import at.hannibal2.skyhanni.utils.renderables.Renderable +import at.hannibal2.skyhanni.utils.renderables.RenderableTooltips import io.github.notenoughupdates.moulconfig.internal.GlScissorStack import io.github.notenoughupdates.moulconfig.internal.RenderUtils import io.github.notenoughupdates.moulconfig.internal.TextRenderUtils @@ -66,7 +67,7 @@ class DefaultConfigOptionGui( mc.fontRendererObj.FONT_HEIGHT.toFloat(), false, xSize / 2 - padding, - -1 + -1, ) GlStateManager.popMatrix() @@ -74,7 +75,7 @@ class DefaultConfigOptionGui( GlStateManager.translate( (width - xSize) / 2F + padding, (height + ySize) / 2F - mc.fontRendererObj.FONT_HEIGHT * 2, - 0F + 0F, ) var i = 0 fun button(title: String, tooltip: List, func: () -> Unit) { @@ -95,7 +96,7 @@ class DefaultConfigOptionGui( 2 + i.toFloat(), 0F, if (overMouse) 0xFF00FF00.toInt() else -1, - overMouse + overMouse, ) i += width + 12 } @@ -132,12 +133,12 @@ class DefaultConfigOptionGui( (height - ySize) / 2 + barSize, (width + xSize) / 2, (height + ySize) / 2 - barSize, - scaledResolution + scaledResolution, ) GlStateManager.translate( (width - xSize) / 2F + padding, (height - ySize) / 2F + barSize - currentScrollOffset, - 0F + 0F, ) for ((cat) in orderedOptions.entries) { @@ -157,13 +158,13 @@ class DefaultConfigOptionGui( "§7${cat.description}", "§7Current plan: ${suggestionState.label}", "§aClick to toggle!", - "§7Hold shift to show all options" + "§7Hold shift to show all options", ) if (isShiftKeyDown()) { hoveringTextToDraw = listOf( "§e${cat.name}", - "§7${cat.description}" + "§7${cat.description}", ) + orderedOptions[cat]!!.map { "§7 - §a" + it.name } } @@ -179,8 +180,8 @@ class DefaultConfigOptionGui( GlStateManager.popMatrix() GlScissorStack.pop(scaledResolution) - if (hoveringTextToDraw != null) { - Utils.drawHoveringText(hoveringTextToDraw, mouseX, mouseY, width, height, 100, mc.fontRendererObj) + hoveringTextToDraw?.let { tooltip -> + RenderableTooltips.setTooltipForRender(tooltip.map { Renderable.string(it) }) } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt new file mode 100644 index 000000000000..e753948bca5e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pathfind/NavigationHelper.kt @@ -0,0 +1,114 @@ +package at.hannibal2.skyhanni.features.misc.pathfind + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.IslandGraphs +import at.hannibal2.skyhanni.data.model.GraphNode +import at.hannibal2.skyhanni.data.model.GraphNodeTag +import at.hannibal2.skyhanni.data.model.findShortestDistance +import at.hannibal2.skyhanni.features.misc.IslandAreas +import at.hannibal2.skyhanni.utils.CollectionUtils.sorted +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo +import at.hannibal2.skyhanni.utils.chat.Text +import at.hannibal2.skyhanni.utils.chat.Text.asComponent +import at.hannibal2.skyhanni.utils.chat.Text.hover +import at.hannibal2.skyhanni.utils.chat.Text.onClick +import at.hannibal2.skyhanni.utils.chat.Text.send +import kotlinx.coroutines.launch + +object NavigationHelper { + private const val NAVIGATION_CHAT_ID = -6457562 + + val allowedTags = listOf( + GraphNodeTag.NPC, + GraphNodeTag.AREA, + GraphNodeTag.SMALL_AREA, + GraphNodeTag.POI, + GraphNodeTag.SLAYER, + GraphNodeTag.GRIND_MOBS, + GraphNodeTag.GRIND_ORES, + GraphNodeTag.GRIND_CROPS, + GraphNodeTag.MINES_EMISSARY, + GraphNodeTag.CRIMSON_MINIBOSS, + ) + + fun onCommand(args: Array) { + SkyHanniMod.coroutineScope.launch { + doCommandAsync(args) + } + } + + private fun doCommandAsync(args: Array) { + val searchTerm = args.joinToString(" ").lowercase() + val distances = calculateDistances(searchTerm) + val locations = calculateNames(distances) + + val goBack = { + onCommand(searchTerm.split(" ").toTypedArray()) + IslandGraphs.stop() + } + val title = if (searchTerm.isBlank()) "SkyHanni Navigation Locations" else "SkyHanni Navigation Locations Matching: \"$searchTerm\"" + + Text.displayPaginatedList( + title, + locations, + chatLineId = NAVIGATION_CHAT_ID, + emptyMessage = "No locations found.", + ) { (name, node) -> + val distance = distances[node]!!.roundTo(1) + val component = "$name §e$distance".asComponent() + component.onClick { + IslandGraphs.pathFind(node.position) + sendNavigateMessage(name, goBack) + } + val tag = node.tags.first { it in allowedTags } + val d = "Name: $name\n§7Type: §r${tag.displayName}\n§7Distance: §e$distance blocks\n§eClick to start navigating!" + component.hover = d.asComponent() + component + } + } + + private fun sendNavigateMessage(name: String, goBack: () -> Unit) { + val componentText = "§7Navigating to §r$name".asComponent() + componentText.onClick(onClick = goBack) + componentText.hover = "§eClick to stop navigating and return to previous search".asComponent() + componentText.send(NAVIGATION_CHAT_ID) + } + + private fun calculateNames(distances: Map): List> { + val names = mutableMapOf() + for (node in distances.sorted().keys) { + // hiding areas that are none + if (node.name == "no_area") continue + // no need to navigate to the current area + if (node.name == IslandAreas.currentAreaName) continue + val tag = node.tags.first { it in allowedTags } + val name = "${node.name} §7(${tag.displayName}§7)" + if (name in names) continue + names[name] = node + } + return names.toList() + } + + private fun calculateDistances( + searchTerm: String, + ): Map { + val graph = IslandGraphs.currentIslandGraph ?: return emptyMap() + val closedNote = IslandGraphs.closedNote ?: return emptyMap() + + val nodes = graph.nodes + val distances = mutableMapOf() + for (node in nodes) { + val name = node.name ?: continue + val remainingTags = node.tags.filter { it in allowedTags } + if (remainingTags.isEmpty()) continue + if (name.lowercase().contains(searchTerm)) { + distances[node] = graph.findShortestDistance(closedNote, node) + } + if (remainingTags.size != 1) { + println("found node with invalid amount of tags: ${node.name} (${remainingTags.map { it.cleanName }}") + } + } + return distances + } + +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/PetExpTooltip.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/PetExpTooltip.kt index 8e544a3dfefc..e5c3179cc4a9 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/pets/PetExpTooltip.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/pets/PetExpTooltip.kt @@ -11,8 +11,8 @@ import at.hannibal2.skyhanni.utils.ItemUtils.name import at.hannibal2.skyhanni.utils.KeyboardManager import at.hannibal2.skyhanni.utils.LorenzRarity import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.round import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators +import at.hannibal2.skyhanni.utils.NumberUtil.roundTo import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat import at.hannibal2.skyhanni.utils.ReflectionUtils.makeAccessible import at.hannibal2.skyhanni.utils.SkyBlockItemModifierUtils.getPetExp @@ -36,7 +36,7 @@ object PetExpTooltip { if (!KeyboardManager.isShiftKeyDown() && !config.showAlways) return val itemStack = event.itemStack - val petExperience = itemStack.getPetExp()?.round(1) ?: return + val petExperience = itemStack.getPetExp()?.roundTo(1) ?: return val name = itemStack.name try { @@ -105,7 +105,7 @@ object PetExpTooltip { val maxLevel = if (useGoldenDragonLevels) 200 else 100 val maxXp = when { - useGoldenDragonLevels -> LEVEL_200_LEGENDARY // lvl 200 legendary + useGoldenDragonLevels -> LEVEL_200_LEGENDARY petName.contains("Bingo") -> LEVEL_100_COMMON else -> LEVEL_100_LEGENDARY diff --git a/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt index 472aac2de6be..a4ee7bc6af9f 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/misc/reminders/ReminderManager.kt @@ -11,15 +11,11 @@ import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.minutes import at.hannibal2.skyhanni.utils.chat.Text import at.hannibal2.skyhanni.utils.chat.Text.asComponent -import at.hannibal2.skyhanni.utils.chat.Text.center import at.hannibal2.skyhanni.utils.chat.Text.command -import at.hannibal2.skyhanni.utils.chat.Text.fitToChat import at.hannibal2.skyhanni.utils.chat.Text.hover import at.hannibal2.skyhanni.utils.chat.Text.send -import at.hannibal2.skyhanni.utils.chat.Text.style import at.hannibal2.skyhanni.utils.chat.Text.suggest import at.hannibal2.skyhanni.utils.chat.Text.wrap -import net.minecraft.util.EnumChatFormatting import net.minecraft.util.IChatComponent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration @@ -44,11 +40,6 @@ object ReminderManager { private fun sendMessage(message: String) = Text.join("§e[Reminder]", " ", message).send(REMINDERS_ACTION_ID) - private fun createDivider() = Text.HYPHEN.fitToChat().style { - strikethrough = true - color = EnumChatFormatting.BLUE - } - private fun parseDuration(text: String): Duration? = try { val duration = TimeUtils.getDuration(text) if (duration <= 1.seconds) null else duration @@ -57,65 +48,34 @@ object ReminderManager { } private fun listReminders(page: Int) { - val reminders = getSortedReminders() - val maxPage = (reminders.size + REMINDERS_PER_PAGE - 1) / REMINDERS_PER_PAGE - - listPage = page.coerceIn(0, maxPage) - - val text: MutableList = mutableListOf() - - text.add(createDivider()) - - text.add( + Text.displayPaginatedList( + "SkyHanni Reminders", + getSortedReminders(), + chatLineId = REMINDERS_LIST_ID, + emptyMessage = "No reminders found.", + currentPage = page, + maxPerPage = REMINDERS_PER_PAGE, + ) { reminderEntry -> + val id = reminderEntry.key + val reminder = reminderEntry.value Text.join( - if (listPage > 1) "§6§l<<".asComponent { - hover = "§eClick to view page ${listPage - 1}".asComponent() - command = "/shremind list ${listPage - 1}" - } else null, + "§c✕".asComponent { + hover = "§7Click to remove".asComponent() + command = "/shremind remove -l $id" + }.wrap("§8[", "§8]"), " ", - "§6Reminders (Page $listPage of $maxPage)", + "§e✎".asComponent { + hover = "§7Click to start editing".asComponent() + suggest = "/shremind edit -l $id ${reminder.reason} " + }.wrap("§8[", "§8]"), " ", - if (listPage < maxPage) "§6§l>>".asComponent { - hover = "§eClick to view page ${listPage + 1}".asComponent() - command = "/shremind list ${listPage + 1}" - } else null, - ).center(), - ) - - if (reminders.isNotEmpty()) { - for (i in (listPage - 1) * REMINDERS_PER_PAGE until listPage * REMINDERS_PER_PAGE) { - if (i >= reminders.size) break - val (id, reminder) = reminders[i] - - text.add( - Text.join( - "§c✕".asComponent { - hover = "§7Click to remove".asComponent() - command = "/shremind remove -l $id" - }.wrap("§8[", "§8]"), - " ", - "§e✎".asComponent { - hover = "§7Click to start editing".asComponent() - suggest = "/shremind edit -l $id ${reminder.reason} " - }.wrap("§8[", "§8]"), - " ", - "§6${reminder.formatShort()}".asComponent { - hover = "§7${reminder.formatFull()}".asComponent() - }.wrap("§8[", "§8]"), - " ", - "§7${reminder.reason}", - ), - ) - } - } else { - text.add(Text.EMPTY) - text.add("§cNo reminders found.".asComponent().center()) - text.add(Text.EMPTY) + "§6${reminder.formatShort()}".asComponent { + hover = "§7${reminder.formatFull()}".asComponent() + }.wrap("§8[", "§8]"), + " ", + "§7${reminder.reason}", + ) } - - text.add(createDivider()) - - Text.join(*text.toTypedArray(), separator = Text.NEWLINE).send(REMINDERS_LIST_ID) } private fun createReminder(args: Array) { @@ -183,7 +143,7 @@ object ReminderManager { } private fun help() { - createDivider().send() + Text.createDivider().send() "§6SkyHanni Reminder Commands:".asComponent().send() "§e/shremind