aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md30
-rw-r--r--FEATURES.md6
-rw-r--r--README.md34
-rw-r--r--build.gradle20
-rw-r--r--gradle.properties2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/SkyblockerInitializer.java3
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java68
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/discord/DiscordRPCManager.java113
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/mixin/ChatScreenMixin.java29
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java34
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java9
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/mixin/FarmlandBlockMixin.java33
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java19
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java17
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/BackpackPreview.java133
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/FancyStatusBars.java277
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTracker.java110
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/OldLever.java2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java43
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java17
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java32
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemFixerUpper.java70
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemStackBuilder.java13
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/Events.java35
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/SkyblockEvents.java33
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/UpdateChecker.java59
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java10
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json9
-rw-r--r--src/main/resources/skyblocker.mixins.json2
-rw-r--r--src/test/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTrackerTest.java74
31 files changed, 848 insertions, 492 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a9518344..df0fdc53 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,33 @@
+# Release 1.8.0
+
+New Feature
+* Added support for moving fancy bars by @ADON15c in https://github.com/SkyblockerMod/Skyblocker/pull/72
+* Add option to use 1.8 farmland hitbox by @KonaeAkira in https://github.com/SkyblockerMod/Skyblocker/commit/678025b21af4d45518a382b546c14fb12f131114
+* multi-profile support for backpack preview by @KonaeAkira in https://github.com/SkyblockerMod/Skyblocker/commit/75918834349f1068557716142e342a7d01356040
+
+Fixes
+* Fix some items having the wrong texture by @KonaeAkira in https://github.com/SkyblockerMod/Skyblocker/pull/71
+* reparty one at a time by @KonaeAkira in https://github.com/SkyblockerMod/Skyblocker/commit/aa5cf6bb18e84d604880ef37f2bda7250feaad2e
+
+New Contributors
+* @ADON15c made their first contribution in https://github.com/SkyblockerMod/Skyblocker/pull/72
+
+**Full Changelog**: https://github.com/SkyblockerMod/Skyblocker/compare/v1.7.0...v1.8.0
+___
+# Release 1.7.0
+
+New Feature
+* Commission HUD by @TacoMonkey11 in https://github.com/SkyblockerMod/Skyblocker/pull/55
+* Rewrote status bars again by @ExternalTime in https://github.com/SkyblockerMod/Skyblocker/pull/68
+
+Fixes
+* Replace bootleg events with fabric api events by @TacoMonkey11 in https://github.com/SkyblockerMod/Skyblocker/pull/66
+* Replace DiscordIPC library with a more modern one by @TacoMonkey11 in https://github.com/SkyblockerMod/Skyblocker/pull/69
+* fixed crash on itemtooltip on legacy timestamps by @LifeIsAParadox
+* Updated Trivia @LifeIsAParadox
+
+**Full Changelog**: https://github.com/SkyblockerMod/Skyblocker/compare/v1.6.3...v1.7.0
+___
# Release 1.6.3
Fixes
diff --git a/FEATURES.md b/FEATURES.md
index 4a057057..c2f2a287 100644
--- a/FEATURES.md
+++ b/FEATURES.md
@@ -1,4 +1,4 @@
-* Bars: Health and absorption, Mana, Defense, XP
+* Bars: Health and absorption, Mana, Defense, XP (moving fancy bars)
* Hide Messages: Ability Cooldown, Heal, AOTE, Implosion, Molten Wave, Teleport Pad Messages
* Dungeon Minimap
* Dungeon Puzzle Solver:
@@ -15,4 +15,6 @@
* Quicknav: fast navigate between pets, armor, enderchest, skill, collection, crafting, enchant, envil, warp dungeon, warp hub
* Recipe book: in the vanilla recipe book all skyblock items are listed and you can see the recipe of the item
* Backpack preview: after you clicked your backpack or enderchest once you can hover over the backpack or enderchest and hold shift to preview
-* Update notification \ No newline at end of file
+* Update notification
+* Commission HUD: Dwarven Mines quests
+* 1.8 hitbox for lever and farmland \ No newline at end of file
diff --git a/README.md b/README.md
index c020854e..eeb0be2d 100644
--- a/README.md
+++ b/README.md
@@ -2,27 +2,27 @@
## Skyblocker
[![modrinth statistic](https://img.shields.io/badge/dynamic/json?color=5da545&label=Download&labelColor=cecece&query=downloads&url=https://api.modrinth.com/api/v1/mod/y6DuFGwJ&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMSAxMSIgd2lkdGg9IjE0LjY2NyIgaGVpZ2h0PSIxNC42NjciICB4bWxuczp2PSJodHRwczovL3ZlY3RhLmlvL25hbm8iPjxkZWZzPjxjbGlwUGF0aCBpZD0iQSI+PHBhdGggZD0iTTAgMGgxMXYxMUgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNBKSI+PHBhdGggZD0iTTEuMzA5IDcuODU3YTQuNjQgNC42NCAwIDAgMS0uNDYxLTEuMDYzSDBDLjU5MSA5LjIwNiAyLjc5NiAxMSA1LjQyMiAxMWMxLjk4MSAwIDMuNzIyLTEuMDIgNC43MTEtMi41NTZoMGwtLjc1LS4zNDVjLS44NTQgMS4yNjEtMi4zMSAyLjA5Mi0zLjk2MSAyLjA5MmE0Ljc4IDQuNzggMCAwIDEtMy4wMDUtMS4wNTVsMS44MDktMS40NzQuOTg0Ljg0NyAxLjkwNS0xLjAwM0w4LjE3NCA1LjgybC0uMzg0LS43ODYtMS4xMTYuNjM1LS41MTYuNjk0LS42MjYuMjM2LS44NzMtLjM4N2gwbC0uMjEzLS45MS4zNTUtLjU2Ljc4Ny0uMzcuODQ1LS45NTktLjcwMi0uNTEtMS44NzQuNzEzLTEuMzYyIDEuNjUxLjY0NSAxLjA5OC0xLjgzMSAxLjQ5MnptOS42MTQtMS40NEE1LjQ0IDUuNDQgMCAwIDAgMTEgNS41QzExIDIuNDY0IDguNTAxIDAgNS40MjIgMCAyLjc5NiAwIC41OTEgMS43OTQgMCA0LjIwNmguODQ4QzEuNDE5IDIuMjQ1IDMuMjUyLjgwOSA1LjQyMi44MDljMi42MjYgMCA0Ljc1OCAyLjEwMiA0Ljc1OCA0LjY5MSAwIC4xOS0uMDEyLjM3Ni0uMDM0LjU2bC43NzcuMzU3aDB6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM1ZGE0MjYiLz48L2c+PC9zdmc+)](https://modrinth.com/mod/skyblocker-liap)
-[![github statistic](https://img.shields.io/github/downloads/lifeisaparadox/skyblocker/total?labelColor=cecece&color=000000&label=Download&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMTIgMTIgNDAgNDAiPjxwYXRoIGZpbGw9IiMzMzMzMzMiIGQ9Ik0zMiwxMy40Yy0xMC41LDAtMTksOC41LTE5LDE5YzAsOC40LDUuNSwxNS41LDEzLDE4YzEsMC4yLDEuMy0wLjQsMS4zLTAuOWMwLTAuNSwwLTEuNywwLTMuMiBjLTUuMywxLjEtNi40LTIuNi02LjQtMi42QzIwLDQxLjYsMTguOCw0MSwxOC44LDQxYy0xLjctMS4yLDAuMS0xLjEsMC4xLTEuMWMxLjksMC4xLDIuOSwyLDIuOSwyYzEuNywyLjksNC41LDIuMSw1LjUsMS42IGMwLjItMS4yLDAuNy0yLjEsMS4yLTIuNmMtNC4yLTAuNS04LjctMi4xLTguNy05LjRjMC0yLjEsMC43LTMuNywyLTUuMWMtMC4yLTAuNS0wLjgtMi40LDAuMi01YzAsMCwxLjYtMC41LDUuMiwyIGMxLjUtMC40LDMuMS0wLjcsNC44LTAuN2MxLjYsMCwzLjMsMC4yLDQuNywwLjdjMy42LTIuNCw1LjItMiw1LjItMmMxLDIuNiwwLjQsNC42LDAuMiw1YzEuMiwxLjMsMiwzLDIsNS4xYzAsNy4zLTQuNSw4LjktOC43LDkuNCBjMC43LDAuNiwxLjMsMS43LDEuMywzLjVjMCwyLjYsMCw0LjYsMCw1LjJjMCwwLjUsMC40LDEuMSwxLjMsMC45YzcuNS0yLjYsMTMtOS43LDEzLTE4LjFDNTEsMjEuOSw0Mi41LDEzLjQsMzIsMTMuNHoiLz48L3N2Zz4%3D)](https://github.com/LifeIsAParadox/Skyblocker/releases/latest)
-[![Build Beta](https://img.shields.io/github/workflow/status/LifeIsAParadox/Skyblocker/Build%20Beta?labelColor=cecece&label=beta&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMTIgMTIgNDAgNDAiPjxwYXRoIGZpbGw9IiMzMzMzMzMiIGQ9Ik0zMiwxMy40Yy0xMC41LDAtMTksOC41LTE5LDE5YzAsOC40LDUuNSwxNS41LDEzLDE4YzEsMC4yLDEuMy0wLjQsMS4zLTAuOWMwLTAuNSwwLTEuNywwLTMuMiBjLTUuMywxLjEtNi40LTIuNi02LjQtMi42QzIwLDQxLjYsMTguOCw0MSwxOC44LDQxYy0xLjctMS4yLDAuMS0xLjEsMC4xLTEuMWMxLjksMC4xLDIuOSwyLDIuOSwyYzEuNywyLjksNC41LDIuMSw1LjUsMS42IGMwLjItMS4yLDAuNy0yLjEsMS4yLTIuNmMtNC4yLTAuNS04LjctMi4xLTguNy05LjRjMC0yLjEsMC43LTMuNywyLTUuMWMtMC4yLTAuNS0wLjgtMi40LDAuMi01YzAsMCwxLjYtMC41LDUuMiwyIGMxLjUtMC40LDMuMS0wLjcsNC44LTAuN2MxLjYsMCwzLjMsMC4yLDQuNywwLjdjMy42LTIuNCw1LjItMiw1LjItMmMxLDIuNiwwLjQsNC42LDAuMiw1YzEuMiwxLjMsMiwzLDIsNS4xYzAsNy4zLTQuNSw4LjktOC43LDkuNCBjMC43LDAuNiwxLjMsMS43LDEuMywzLjVjMCwyLjYsMCw0LjYsMCw1LjJjMCwwLjUsMC40LDEuMSwxLjMsMC45YzcuNS0yLjYsMTMtOS43LDEzLTE4LjFDNTEsMjEuOSw0Mi41LDEzLjQsMzIsMTMuNHoiLz48L3N2Zz4%3D)](https://github.com/LifeIsAParadox/Skyblocker/actions/workflows/beta.yml)
+[![github statistic](https://img.shields.io/github/downloads/SkyblockerMod/skyblocker/total?labelColor=cecece&color=000000&label=Download&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMTIgMTIgNDAgNDAiPjxwYXRoIGZpbGw9IiMzMzMzMzMiIGQ9Ik0zMiwxMy40Yy0xMC41LDAtMTksOC41LTE5LDE5YzAsOC40LDUuNSwxNS41LDEzLDE4YzEsMC4yLDEuMy0wLjQsMS4zLTAuOWMwLTAuNSwwLTEuNywwLTMuMiBjLTUuMywxLjEtNi40LTIuNi02LjQtMi42QzIwLDQxLjYsMTguOCw0MSwxOC44LDQxYy0xLjctMS4yLDAuMS0xLjEsMC4xLTEuMWMxLjksMC4xLDIuOSwyLDIuOSwyYzEuNywyLjksNC41LDIuMSw1LjUsMS42IGMwLjItMS4yLDAuNy0yLjEsMS4yLTIuNmMtNC4yLTAuNS04LjctMi4xLTguNy05LjRjMC0yLjEsMC43LTMuNywyLTUuMWMtMC4yLTAuNS0wLjgtMi40LDAuMi01YzAsMCwxLjYtMC41LDUuMiwyIGMxLjUtMC40LDMuMS0wLjcsNC44LTAuN2MxLjYsMCwzLjMsMC4yLDQuNywwLjdjMy42LTIuNCw1LjItMiw1LjItMmMxLDIuNiwwLjQsNC42LDAuMiw1YzEuMiwxLjMsMiwzLDIsNS4xYzAsNy4zLTQuNSw4LjktOC43LDkuNCBjMC43LDAuNiwxLjMsMS43LDEuMywzLjVjMCwyLjYsMCw0LjYsMCw1LjJjMCwwLjUsMC40LDEuMSwxLjMsMC45YzcuNS0yLjYsMTMtOS43LDEzLTE4LjFDNTEsMjEuOSw0Mi41LDEzLjQsMzIsMTMuNHoiLz48L3N2Zz4%3D)](https://github.com/SkyblockerMod/Skyblocker/releases/latest)
+[![Build Beta](https://img.shields.io/github/workflow/status/SkyblockerMod/Skyblocker/Build%20Beta?labelColor=cecece&label=beta&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMTIgMTIgNDAgNDAiPjxwYXRoIGZpbGw9IiMzMzMzMzMiIGQ9Ik0zMiwxMy40Yy0xMC41LDAtMTksOC41LTE5LDE5YzAsOC40LDUuNSwxNS41LDEzLDE4YzEsMC4yLDEuMy0wLjQsMS4zLTAuOWMwLTAuNSwwLTEuNywwLTMuMiBjLTUuMywxLjEtNi40LTIuNi02LjQtMi42QzIwLDQxLjYsMTguOCw0MSwxOC44LDQxYy0xLjctMS4yLDAuMS0xLjEsMC4xLTEuMWMxLjksMC4xLDIuOSwyLDIuOSwyYzEuNywyLjksNC41LDIuMSw1LjUsMS42IGMwLjItMS4yLDAuNy0yLjEsMS4yLTIuNmMtNC4yLTAuNS04LjctMi4xLTguNy05LjRjMC0yLjEsMC43LTMuNywyLTUuMWMtMC4yLTAuNS0wLjgtMi40LDAuMi01YzAsMCwxLjYtMC41LDUuMiwyIGMxLjUtMC40LDMuMS0wLjcsNC44LTAuN2MxLjYsMCwzLjMsMC4yLDQuNywwLjdjMy42LTIuNCw1LjItMiw1LjItMmMxLDIuNiwwLjQsNC42LDAuMiw1YzEuMiwxLjMsMiwzLDIsNS4xYzAsNy4zLTQuNSw4LjktOC43LDkuNCBjMC43LDAuNiwxLjMsMS43LDEuMywzLjVjMCwyLjYsMCw0LjYsMCw1LjJjMCwwLjUsMC40LDEuMSwxLjMsMC45YzcuNS0yLjYsMTMtOS43LDEzLTE4LjFDNTEsMjEuOSw0Mi41LDEzLjQsMzIsMTMuNHoiLz48L3N2Zz4%3D)](https://github.com/SkyblockerMod/Skyblocker/actions/workflows/beta.yml)
[![Discord](https://img.shields.io/discord/879732108745125969?logo=discord&labelColor=cecece&color=7289DA&label=%E2%80%8B)](https://discord.com/invite/aNNJHQykck)
[![modrinth statistic](https://img.shields.io/badge/buy%20me%20coffee-skyblocker?color=434B57&query=e&logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHdpZHRoPSIxODEuOTg4Mm1tIiBoZWlnaHQ9IjExNS45NTYyOW1tIiB2aWV3Qm94PSIwIDAgNjQ0Ljg0MDEgNDEwLjg2ODc1IiBpZD0ic3ZnNDIzOCIgdmVyc2lvbj0iMS4xIiBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkxIHIxMzcyNSIgc29kaXBvZGk6ZG9jbmFtZT0iY3VwbG9nby5zdmciPgogIDxkZWZzIGlkPSJkZWZzNDI0MCIvPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcgaWQ9ImJhc2UiIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgYm9yZGVyY29sb3I9IiM2NjY2NjYiIGJvcmRlcm9wYWNpdHk9IjEuMCIgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnpvb209IjAuMzUiIGlua3NjYXBlOmN4PSI3ODAuMjc3MTgiIGlua3NjYXBlOmN5PSItMjE0LjU2NTYxIiBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIgc2hvd2dyaWQ9ImZhbHNlIiBmaXQtbWFyZ2luLXRvcD0iMCIgZml0LW1hcmdpbi1sZWZ0PSIwIiBmaXQtbWFyZ2luLXJpZ2h0PSIwIiBmaXQtbWFyZ2luLWJvdHRvbT0iMCIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxMjgwIiBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI2OTkiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMSIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIvPgogIDxtZXRhZGF0YSBpZD0ibWV0YWRhdGE0MjQzIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yayByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIvPgogICAgICAgIDxkYzp0aXRsZS8+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIiBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIiBpZD0ibGF5ZXIxIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzcuNTc5OTY0LC0xMzUuNDk5MjcpIj4KICAgIDxnIGlkPSJnNDAiIHRyYW5zZm9ybT0ibWF0cml4KDEuMTQyMTUyOCwwLDAsLTEuMTQyMTUyOCwyNjUuOTMzOTgsNDYwLjczMDk1KSI+CiAgICAgIDxnIGlkPSJnNDE4NCI+CiAgICAgICAgPHBhdGggaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgaWQ9InBhdGgzOCIgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgZD0ibSAwLDAgYyAtMTkuOTQ2LC0yLjQ5MiAtMzYuMTUxLC0wLjYyMiAtMzYuMTUxLC0wLjYyMiBsIDAsMTIyLjEzMiAzOC4wMiwwIGMgMCwwIDQyLjM4NSwtMTEuODM5IDQyLjM4NSwtNTYuNzA0IEMgNDQuMjU0LDIzLjY4IDIzLjA2Myw3LjQ3OCAwLDAgTSAxMDUuMDYzLDg1LjczOSBDIDg4LjQzNSwxNzMuNTYgMC42MjQsMTg0LjQ3MyAwLjYyNCwxODQuNDczIGwgLTM5My4zMzMsMCBjIC0xMi45OSwwIC0xNC41ODgsLTE3LjE0OCAtMTQuNTg4LC0xNy4xNDggMCwwIC0xLjc1MiwtMTU3LjQzIC0wLjQ4MSwtMjU0LjExMiAzLjUyNCwtNTIuMDkzIDU1LjU5NywtNTcuNDM1IDU1LjU5NywtNTcuNDM1IDAsMCAxNzcuNzAxLDAuNTIgMjU3LjIsMS4wMzkgNTIuNDEsOS4xODEgNTcuNjc0LDU1LjE1NSA1Ny4xNTUsODAuMyA5My41MjcsLTUuMTk2IDE1OS41MTUsNjAuOCAxNDIuODg5LDE0OC42MjIiIHRyYW5zZm9ybT0ibWF0cml4KDEuMDk0NDI0NSwwLDAsMS4wOTQ0MjQ1LDI0Ni44NTUzNiw4Mi44NjE0NDYpIi8+CiAgICAgICAgPHBhdGggaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgaWQ9InBhdGg0MiIgc3R5bGU9ImZpbGw6I2ZmNWY1ZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgZD0ibSAwLDAgYyA0LjQ0NSwtMi4yMzggNy4yODUsMC41NDMgNy4yODUsMC41NDMgMCwwIDY1LjA0NSw1OS4zNjcgOTQuMzQ4LDkzLjU1NyAyNi4wNjMsMzAuNTg2IDI3Ljc2Miw4Mi4xMjkgLTE2Ljk5NywxMDEuMzg4IC00NC43NTgsMTkuMjU4IC04MS41ODQsLTIyLjY1NyAtODEuNTg0LC0yMi42NTcgLTMxLjkzNSwzNS4xMjMgLTgwLjI2OCwzMy4zNDUgLTEwMi42MjMsOS41NzUgLTIyLjM1NCwtMjMuNzcgLTE0LjU0OCwtNjQuNTY4IDIuMTI5LC04Ny4yNzQgMTUuNjU1LC0yMS4zMTQgODQuNDY1LC04Mi42NDQgOTQuODk0LC05My4wMTYgMCwwIDAuNzYsLTAuNzk1IDIuNTQ4LC0yLjExNiIvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4=)](https://ko-fi.com/wohlhabend)
-Hypixel Skyblock Mod for Minecraft 1.17.x + 1.18.x
+Hypixel Skyblock Mod for Minecraft 1.17.x + 1.18.x + 1.19.x
-Installation guide is [here](https://github.com/LifeIsAParadox/Skyblocker/wiki/installation)
+Installation guide is [here](https://github.com/SkyblockerMod/Skyblocker/wiki/installation)
## Features
<details open>
<summary>open</summary>
-* Bars: Health and absorption, Mana, Defense, XP
+* Bars: Health and absorption, Mana, Defense, XP (moving fancy bars)
* Hide Messages: Ability Cooldown, Heal, AOTE, Implosion, Molten Wave, Teleport Pad Messages
* Dungeon Minimap
* Dungeon Puzzle Solver:
- * Three Weirdos
- * Blaze
- * F7 Terminal: Order, Color, Name
+ * Three Weirdos
+ * Blaze
+ * F7 Terminal: Order, Color, Name
* Dwarven Mines Solver: Fetchur, Puzzler
* Drill Fuel in Item Durability Bar
* Hotbar Slot Lock Keybind (Select the hotbar slot you want to lock/unlock and press the lockbutton)
@@ -34,6 +34,8 @@ Installation guide is [here](https://github.com/LifeIsAParadox/Skyblocker/wiki/i
* Recipe book: in the vanilla recipe book all skyblock items are listed and you can see the recipe of the item
* Backpack preview: after you clicked your backpack or enderchest once you can hover over the backpack or enderchest and hold shift to preview
* Update notification
+* Commission HUD: Dwarven Mines quests
+* 1.8 hitbox for lever and farmland
</details>
@@ -42,7 +44,7 @@ ___
<details open>
<summary>open</summary>
-<img padding="10px,0px" height="150" src="https://hysky.de/hotbar.png" />
+<img padding="10px,0px" src="https://user-images.githubusercontent.com/27798256/170806938-f858f0ae-4d8b-4767-9b53-8fe5a65edf56.png" />
<img padding="10px,0px" height="150" src="https://hysky.de/minimap.png" />
<img padding="10px,0px" height="150" src="https://hysky.de/tooltip1.png" />
<img padding="10px,0px" height="150" src="https://hysky.de/tooltip2.png" />
@@ -63,10 +65,18 @@ Everyone can contribute to Skyblocker, read [this](https://github.com/Skyblocker
## Credits
-| [<img alt="Kraineff" src="https://github.com/Kraineff.png" width="100">](https://github.com/Kraineff) | [<img alt="d3dx9" src="https://github.com/d3dx9.png" width="100">](https://github.com/d3dx9) | [<img alt="LifeIsAParadox" src="https://github.com/LifeIsAParadox.png" width="100">](https://github.com/LifeIsAParadox) | [<img alt="ExternalTime" src="https://github.com/ExternalTime.png" width="100">](https://github.com/ExternalTime) | [<img alt="Zailer43" src="https://github.com/Zailer43.png" width="100">](https://github.com/Zailer43) | [<img alt="TacoMonkey11" src="https://github.com/TacoMonkey11.png" width="100">](https://github.com/TacoMonkey11) | [<img alt="KonaeAkira" src="https://github.com/KonaeAkira.png" width="100">](https://github.com/KonaeAkira) | [<img alt="Fix3dll" src="https://github.com/Fix3dll.png" width="100">](https://github.com/Fix3dll) |
-|:-------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------:|
-| [Kraineff](https://github.com/Kraineff) | [d3dx9](https://github.com/d3dx9) | [LifeIsAParadox](https://github.com/LifeIsAParadox) | [ExternalTime](https://github.com/ExternalTime) | [Zailer43](https://github.com/Zailer43) | [TacoMonkey11](https://github.com/TacoMonkey11) | [KonaeAkira](https://github.com/KonaeAkira) | [Fix3dll](https://github.com/Fix3dll) |
+| [<img alt="Kraineff" src="https://github.com/Kraineff.png" width="100">](https://github.com/Kraineff) | [<img alt="d3dx9" src="https://github.com/d3dx9.png" width="100">](https://github.com/d3dx9) | [<img alt="LifeIsAParadox" src="https://github.com/LifeIsAParadox.png" width="100">](https://github.com/LifeIsAParadox) | [<img alt="ExternalTime" src="https://github.com/ExternalTime.png" width="100">](https://github.com/ExternalTime) |
+|:-------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------:|
+| [Kraineff](https://github.com/Kraineff) | [d3dx9](https://github.com/d3dx9) | [LifeIsAParadox](https://github.com/LifeIsAParadox) | [ExternalTime](https://github.com/ExternalTime) |
+| [<img alt="Zailer43" src="https://github.com/Zailer43.png" width="100">](https://github.com/Zailer43) | [<img alt="TacoMonkey11" src="https://github.com/TacoMonkey11.png" width="100">](https://github.com/TacoMonkey11) | [<img alt="KonaeAkira" src="https://github.com/KonaeAkira.png" width="100">](https://github.com/KonaeAkira) | [<img alt="Fix3dll" src="https://github.com/Fix3dll.png" width="100">](https://github.com/Fix3dll) |
+|:-----------------------------------------------------------------------------------------------------:|:-----------------------------------------------------------------------------------------------------------------:|:---------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------:|
+| [Zailer43](https://github.com/Zailer43) | [TacoMonkey11](https://github.com/TacoMonkey11) | [KonaeAkira](https://github.com/KonaeAkira) | [Fix3dll](https://github.com/Fix3dll) |
+
+
+| [<img alt="Zailer43" src="https://github.com/ADON15c.png" width="100">](https://github.com/ADON15c) |
+|:---------------------------------------------------------------------------------------------------:|
+| [ADON15c](https://github.com/ADON15c) |
### Translators
German ([LifeIsAParadox](https://github.com/LifeIsAParadox)) \
Indonesian ([null2264](https://github.com/null2264)) \
diff --git a/build.gradle b/build.gradle
index 9e918bd7..4059ebbc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
plugins {
- id 'fabric-loom' version '0.11-SNAPSHOT'
+ id 'fabric-loom' version '0.12-SNAPSHOT'
id 'maven-publish'
id 'com.modrinth.minotaur' version '2.+'
}
@@ -28,7 +28,10 @@ repositories {
url 'https://repo.maven.apache.org/maven2'
name 'Maven Central'
}
- maven {url "https://maven.jaackson.me/repo"}
+ maven {
+ name = "meteor-maven"
+ url = "https://maven.meteordev.org"
+ }
maven {url "https://jitpack.io"}
}
@@ -57,18 +60,9 @@ dependencies {
// https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit used pull data from the NEU item repo
include(implementation("org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r"))
- //DiscordIPC + Libraries so it works on unix systems
- modImplementation ("com.jagrosh:DiscordIPC:0.5")
-
- // https://github.com/jaacksondev/DiscordIPC
- include "com.jagrosh:DiscordIPC:0.5"
-
- //https://github.com/kohlschutter/junixsocket discordrpc unix
- include(modImplementation("com.kohlschutter.junixsocket:junixsocket-common:2.0.4"))
- include(modImplementation("com.kohlschutter.junixsocket:junixsocket-native-common:2.0.4"))
-
+ include(modImplementation ("meteordevelopment:discord-ipc:1.1"))
// allow gson to deserialize the api data into a record
- include(modImplementation("com.github.Marcono1234:gson-record-type-adapter-factory:0.2.0"))
+ include(implementation("com.github.Marcono1234:gson-record-type-adapter-factory:0.2.0"))
}
processResources {
diff --git a/gradle.properties b/gradle.properties
index d6eb2d06..d9473bd9 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,7 +15,7 @@ clothconfig_version=6.2.57
mod_menu_version=3.1.0
# Mod Properties
-mod_version = 1.6.3
+mod_version = 1.8.0
maven_group = me.xmrvizzy
archives_base_name = skyblocker
modrinth_id=y6DuFGwJ
diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerInitializer.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerInitializer.java
index a15b3a96..e9af52f6 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerInitializer.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerInitializer.java
@@ -8,6 +8,7 @@ import me.xmrvizzy.skyblocker.skyblock.dwarven.DwarvenHud;
import me.xmrvizzy.skyblocker.skyblock.item.PriceInfoTooltip;
import me.xmrvizzy.skyblocker.skyblock.item.WikiLookup;
import me.xmrvizzy.skyblocker.skyblock.itemlist.ItemRegistry;
+import me.xmrvizzy.skyblocker.utils.UpdateChecker;
import net.fabricmc.api.ClientModInitializer;
public class SkyblockerInitializer implements ClientModInitializer {
@@ -21,5 +22,7 @@ public class SkyblockerInitializer implements ClientModInitializer {
StatsCommand.init();
DwarvenHud.init();
ChatMessageListener.init();
+ UpdateChecker.init();
+ SkyblockerMod.getInstance().discordRPCManager.init();
}
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
index f3c851f1..6b5558cf 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
@@ -3,6 +3,7 @@ package me.xmrvizzy.skyblocker;
import me.xmrvizzy.skyblocker.container.ContainerSolverManager;
import me.xmrvizzy.skyblocker.discord.DiscordRPCManager;
import me.xmrvizzy.skyblocker.skyblock.BackpackPreview;
+import me.xmrvizzy.skyblocker.skyblock.StatusBarTracker;
import me.xmrvizzy.skyblocker.skyblock.dungeon.DungeonBlaze;
import me.xmrvizzy.skyblocker.utils.Scheduler;
import me.xmrvizzy.skyblocker.utils.Utils;
@@ -14,12 +15,13 @@ public class SkyblockerMod {
public final Scheduler scheduler = new Scheduler();
public final ContainerSolverManager containerSolverManager = new ContainerSolverManager();
public final DiscordRPCManager discordRPCManager = new DiscordRPCManager();
+ public final StatusBarTracker statusBarTracker = new StatusBarTracker();
private SkyblockerMod() {
scheduler.scheduleCyclic(Utils::sbChecker, 20);
scheduler.scheduleCyclic(discordRPCManager::update, 100);
scheduler.scheduleCyclic(DungeonBlaze::update, 4);
- scheduler.scheduleCyclic(BackpackPreview::tick, 100);
+ scheduler.scheduleCyclic(BackpackPreview::tick, 50);
}
public static SkyblockerMod getInstance() {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
index 93e1d8e9..0a7260f8 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
@@ -37,28 +37,79 @@ public class SkyblockerConfig implements ConfigData {
public String apiKey;
@ConfigEntry.Category("bars")
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public Bars bars = new Bars();
@ConfigEntry.Category("itemList")
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public ItemList itemList = new ItemList();
@ConfigEntry.Category("quicknav")
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public Quicknav quicknav = new Quicknav();
@ConfigEntry.Category("itemTooltip")
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public ItemTooltip itemTooltip = new ItemTooltip();
+ @ConfigEntry.Category("hitbox")
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
+ public Hitbox hitbox = new Hitbox();
+
@ConfigEntry.Gui.Excluded
public List<Integer> lockedSlots = new ArrayList<>();
}
public static class Bars {
public boolean enableBars = true;
+
+ @ConfigEntry.Category("barpositions")
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
+ public BarPositions barpositions = new BarPositions();
+ }
+
+ public static class BarPositions {
+ @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+ public BarPosition healthBarPosition = BarPosition.LAYER1;
+ @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+ public BarPosition manaBarPosition = BarPosition.LAYER1;
+ @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+ public BarPosition defenceBarPosition = BarPosition.LAYER1;
+ @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+ public BarPosition experienceBarPosition = BarPosition.LAYER1;
+
}
+
+ public enum BarPosition {
+ LAYER1,
+ LAYER2,
+ RIGHT,
+ NONE;
+
+ public String toString() {
+ return switch (this) {
+ case LAYER1 -> "Layer 1";
+ case LAYER2 -> "Layer 2";
+ case RIGHT -> "Right";
+ case NONE -> "Disabled";
+ };
+ }
+
+ public int toInt() {
+ return switch (this) {
+ case LAYER1 -> 0;
+ case LAYER2 -> 1;
+ case RIGHT -> 2;
+ case NONE -> -1;
+ };
+ }
+ }
+
+ public static class Hitbox {
+ public boolean oldFarmlandHitbox = true;
+ public boolean oldLeverHitbox = false;
+ }
+
public static class RichPresence {
public boolean enableRichPresence = false;
@ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
@@ -103,11 +154,11 @@ public class SkyblockerConfig implements ConfigData {
public static class Locations {
@ConfigEntry.Category("dungeons")
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public Dungeons dungeons = new Dungeons();
@ConfigEntry.Category("dwarvenmines")
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public DwarvenMines dwarvenMines = new DwarvenMines();
}
@@ -116,8 +167,7 @@ public class SkyblockerConfig implements ConfigData {
public boolean solveThreeWeirdos = true;
public boolean blazesolver = true;
public boolean solveTrivia = true;
- public boolean oldLevers = false;
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public Terminals terminals = new Terminals();
}
@@ -131,7 +181,7 @@ public class SkyblockerConfig implements ConfigData {
public boolean enableDrillFuel = true;
public boolean solveFetchur = true;
public boolean solvePuzzler = true;
- @ConfigEntry.Gui.CollapsibleObject(startExpanded = true)
+ @ConfigEntry.Gui.CollapsibleObject(startExpanded = false)
public DwarvenHud dwarvenHud = new DwarvenHud();
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/discord/DiscordRPCManager.java b/src/main/java/me/xmrvizzy/skyblocker/discord/DiscordRPCManager.java
index e13dfd09..87405989 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/discord/DiscordRPCManager.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/discord/DiscordRPCManager.java
@@ -1,101 +1,76 @@
package me.xmrvizzy.skyblocker.discord;
-import com.google.gson.JsonObject;
-import com.jagrosh.discordipc.IPCClient;
-import com.jagrosh.discordipc.IPCListener;
-import com.jagrosh.discordipc.entities.RichPresence;
-import com.jagrosh.discordipc.entities.pipe.PipeStatus;
+
+import me.shedaniel.autoconfig.AutoConfig;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
+import me.xmrvizzy.skyblocker.utils.SkyblockEvents;
import me.xmrvizzy.skyblocker.utils.Utils;
+import meteordevelopment.discordipc.DiscordIPC;
+import meteordevelopment.discordipc.RichPresence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
-import java.time.OffsetDateTime;
+import java.time.Instant;
-public class DiscordRPCManager implements IPCListener{
- public static long startTimestamp;
- public static IPCClient client;
- public boolean isConnected;
- private static final Logger LOGGER = LoggerFactory.getLogger(DiscordRPCManager.class.getName());
- public static DecimalFormat dFormat = new DecimalFormat("###,###.##");
- public int cycleCount = 0;
+public class DiscordRPCManager {
+ public static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###,###.##");
+ public static final Logger LOGGER = LoggerFactory.getLogger(DiscordRPCManager.class.getName());
+ public static long startTimeStamp;
+ public static int cycleCount;
- public void update() {
- if (!SkyblockerConfig.get().richPresence.enableRichPresence || !Utils.isOnSkyblock) {
- if (isConnected) stop();
- return;
- }
- if (!isConnected) start();
- if (SkyblockerConfig.get().richPresence.cycleMode)
- cycleCount = (cycleCount + 1) % 3;
- updatePresence();
+ public static void init(){
+ SkyblockEvents.LEAVE.register(DiscordIPC::stop);
}
- public void start(){
- try {
- LOGGER.info("[Skyblocker DiscordRPC] Starting...");
- startTimestamp = OffsetDateTime.now().toEpochSecond();
- client = new IPCClient(934607927837356052L);
- client.setListener(this);
- try {
- client.connect();
- } catch (Exception e) {
- LOGGER.warn("Failed to connect: " + e.getMessage());
+ public void update(){
+ if (SkyblockerConfig.get().richPresence.customMessage != null ) {
+ if (SkyblockerConfig.get().richPresence.customMessage.isBlank()) {
+ SkyblockerConfig.get().richPresence.customMessage = "All on Fabric!";
+ AutoConfig.getConfigHolder(SkyblockerConfig.class).save();
}
- } catch (Throwable ex) {
- LOGGER.error("[Skyblocker DiscordRPC] unexpected error occurred while trying to start...");
- ex.printStackTrace();
}
+ if (!SkyblockerConfig.get().richPresence.enableRichPresence || !Utils.isOnSkyblock){
+ if (DiscordIPC.isConnected()) DiscordIPC.stop();
+ }
+ if (SkyblockerConfig.get().richPresence.enableRichPresence && Utils.isOnSkyblock && !DiscordIPC.isConnected()){
+ if (!DiscordIPC.start(934607927837356052L, () -> {
+ LOGGER.info("Started up rich presence");
+ startTimeStamp = Instant.now().getEpochSecond();
+ })){
+ LOGGER.info("An error occurred while attempting to connect to discord");
+ return;
+ }
+ }
+ if (SkyblockerConfig.get().richPresence.cycleMode)
+ cycleCount = (cycleCount + 1) % 3;
+ buildPresence();
}
- public void updatePresence(){
- RichPresence presence = new RichPresence.Builder()
- .setState(SkyblockerConfig.get().richPresence.customMessage)
- .setDetails(getInfo())
- .setStartTimestamp(startTimestamp)
- .setLargeImage("skyblocker-default")
- .build();
- if (client != null && isConnected) client.sendRichPresence(presence);
+ public void buildPresence(){
+ RichPresence presence = new RichPresence();
+ presence.setLargeImage("skyblocker-default", null);
+ presence.setStart(startTimeStamp);
+ presence.setDetails(SkyblockerConfig.get().richPresence.customMessage);
+ presence.setState(getInfo());
+ DiscordIPC.setActivity(presence);
}
public String getInfo(){
String info = null;
if (!SkyblockerConfig.get().richPresence.cycleMode){
switch (SkyblockerConfig.get().richPresence.info){
- case BITS -> info = "Bits: " + dFormat.format(Utils.getBits());
- case PURSE -> info = "Purse: " + dFormat.format(Utils.getPurse());
+ case BITS -> info = "Bits: " + DECIMAL_FORMAT.format(Utils.getBits());
+ case PURSE -> info = "Purse: " + DECIMAL_FORMAT.format(Utils.getPurse());
case LOCATION -> info = "⏣ " + Utils.getLocation();
}
} else if (SkyblockerConfig.get().richPresence.cycleMode){
switch (cycleCount){
- case 0 -> info = "Bits: " + dFormat.format(Utils.getBits());
- case 1 -> info = "Purse: " + dFormat.format(Utils.getPurse());
+ case 0 -> info = "Bits: " + DECIMAL_FORMAT.format(Utils.getBits());
+ case 1 -> info = "Purse: " + DECIMAL_FORMAT.format(Utils.getPurse());
case 2 -> info = "⏣ " + Utils.getLocation();
}
}
return info;
}
-
- public void stop(){
- if (client != null && client.getStatus() == PipeStatus.CONNECTED) {
- LOGGER.info("[Skyblocker DiscordRPC] Closing...");
- isConnected = false;
- client.close();
- client = null;
- }
- }
-
- @Override
- public void onReady(IPCClient client) {
- LOGGER.info("[Skyblocker DiscordRPC] Started!");
- isConnected = true;
- }
-
- @Override
- public void onClose(IPCClient client, JsonObject json) {
- LOGGER.info("[Skyblocker DiscordRPC] Closed");
- isConnected = false;
- }
-
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ChatScreenMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ChatScreenMixin.java
deleted file mode 100644
index e85a64fc..00000000
--- a/src/main/java/me/xmrvizzy/skyblocker/mixin/ChatScreenMixin.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package me.xmrvizzy.skyblocker.mixin;
-
-import net.minecraft.client.gui.screen.ChatScreen;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.gui.widget.TextFieldWidget;
-import net.minecraft.text.Text;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-
-@Mixin(ChatScreen.class)
-public class ChatScreenMixin extends Screen {
-
- @Shadow protected TextFieldWidget chatField;
-
- protected ChatScreenMixin(Text title) {
- super(title);
- }
-
- @Inject(method = "keyPressed", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;openScreen(Lnet/minecraft/client/gui/screen/Screen;)V", ordinal = 1), cancellable = true)
- public void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
- String[] split = this.chatField.getText().trim().toLowerCase().split(" ");
- if (split.length > 0 && split[0].contentEquals("/skb")) {
- cir.setReturnValue(true);
- }
- }
-} \ No newline at end of file
diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
deleted file mode 100644
index ef900eef..00000000
--- a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayNetworkHandlerMixin.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package me.xmrvizzy.skyblocker.mixin;
-
-import com.mojang.authlib.GameProfile;
-import com.mojang.brigadier.CommandDispatcher;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.network.ClientPlayNetworkHandler;
-import net.minecraft.client.util.telemetry.TelemetrySender;
-import net.minecraft.command.CommandSource;
-import net.minecraft.network.ClientConnection;
-import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
-
-@Mixin(ClientPlayNetworkHandler.class)
-public class ClientPlayNetworkHandlerMixin {
-
- @Shadow private CommandDispatcher<CommandSource> commandDispatcher;
-
- @Inject(method = "<init>", at = @At("RETURN"))
- private void init(MinecraftClient client, Screen screen, ClientConnection connection, GameProfile profile, TelemetrySender telemetrySender, CallbackInfo ci) {
- commandDispatcher.register(literal("skb"));
- }
-
- @Inject(method = "onCommandTree", at = @At("RETURN"))
- private void onCommandTree(CommandTreeS2CPacket packet, CallbackInfo ci) {
- commandDispatcher.register(literal("skb"));
- }
-} \ No newline at end of file
diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java
index 160c8078..2d016459 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/ClientPlayerEntityMixin.java
@@ -9,7 +9,6 @@ import net.minecraft.client.world.ClientWorld;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(ClientPlayerEntity.class)
@@ -19,14 +18,6 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity
super(world, profile);
}
- @Inject(method = "sendChatMessage", at = @At("HEAD"), cancellable = true)
- public void sendChatMessage(String message, CallbackInfo ci) {
- String[] split = message.toLowerCase().split(" ");
- if (split.length > 0 && split[0].contentEquals("/skb")) {
- ci.cancel();
- }
- }
-
@Inject(method = "dropSelectedItem", at = @At("HEAD"), cancellable = true)
public void dropSelectedItem(boolean dropEntireStack, CallbackInfoReturnable<Boolean> cir) {
if (Utils.isOnSkyblock) HotbarSlotLock.handleDropSelectedItem(this.getInventory().selectedSlot, cir);
diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/FarmlandBlockMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/FarmlandBlockMixin.java
new file mode 100644
index 00000000..d7ca3686
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/FarmlandBlockMixin.java
@@ -0,0 +1,33 @@
+package me.xmrvizzy.skyblocker.mixin;
+
+import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
+import me.xmrvizzy.skyblocker.utils.Utils;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockState;
+import net.minecraft.block.FarmlandBlock;
+import net.minecraft.block.ShapeContext;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.shape.VoxelShape;
+import net.minecraft.world.BlockView;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(FarmlandBlock.class)
+public abstract class FarmlandBlockMixin extends Block {
+ protected FarmlandBlockMixin(Settings settings) {
+ super(settings);
+ }
+
+ @Inject(method = "getOutlineShape", at = @At("HEAD"), cancellable = true)
+ public void onGetOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, CallbackInfoReturnable<VoxelShape> cir) {
+ if (Utils.isOnSkyblock && SkyblockerConfig.get().general.hitbox.oldFarmlandHitbox)
+ cir.setReturnValue(Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, 16.0, 16.0));
+ }
+
+ @Override
+ public VoxelShape getCullingShape(BlockState state, BlockView world, BlockPos pos) {
+ return Block.createCuboidShape(0.0, 0.0, 0.0, 16.0, 15.0, 16.0);
+ }
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java
index bd99f2d4..0303bca2 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/HandledScreenMixin.java
@@ -41,25 +41,26 @@ public abstract class HandledScreenMixin extends Screen {
List<QuickNavButton> buttons = QuickNav.init(screenTitle);
for (QuickNavButton button : buttons) super.addDrawableChild(button);
}
- BackpackPreview.loadStorage((HandledScreen)(Object)this);
- BackpackPreview.updateStorage((HandledScreen)(Object)this);
+ // backpack preview
+ BackpackPreview.updateStorage((HandledScreen<?>)(Object)this);
}
@Inject(at = @At("HEAD"), method = "keyPressed", cancellable = true)
public void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
- if (focusedSlot != null){
- if (keyCode != 256 && !MinecraftClient.getInstance().options.inventoryKey.matchesKey(keyCode, scanCode)){
- if (WikiLookup.wikiLookup.matchesKey(keyCode, scanCode)) WikiLookup.openWiki(focusedSlot);
+ if (this.focusedSlot != null){
+ if (keyCode != 256 && !this.client.options.inventoryKey.matchesKey(keyCode, scanCode)){
+ if (WikiLookup.wikiLookup.matchesKey(keyCode, scanCode)) WikiLookup.openWiki(this.focusedSlot);
}
}
}
@Inject(at = @At("HEAD"), method = "drawMouseoverTooltip", cancellable = true)
public void drawMouseOverTooltip(MatrixStack matrices, int x, int y, CallbackInfo ci) {
- String title = ((HandledScreen)(Object)this).getTitle().getString();
- boolean shiftDown = SkyblockerConfig.get().general.backpackPreviewWithoutShift || Screen.hasShiftDown();
- if (shiftDown && title.equals("Storage") && focusedSlot != null) {
- if (BackpackPreview.renderPreview(matrices, focusedSlot.getIndex(), x, y)) ci.cancel();
+ String title = ((HandledScreen<?>)(Object)this).getTitle().getString();
+ boolean shiftDown = SkyblockerConfig.get().general.backpackPreviewWithoutShift ^ Screen.hasShiftDown();
+ if (shiftDown && title.equals("Storage") && this.focusedSlot != null) {
+ if (this.focusedSlot.inventory == this.client.player.getInventory()) return;
+ if (BackpackPreview.renderPreview(matrices, this.focusedSlot.getIndex(), x, y)) ci.cancel();
}
}
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java b/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java
index b9e80bd6..9ceebf9f 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/mixin/InGameHudMixin.java
@@ -5,6 +5,7 @@ import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.skyblock.FancyStatusBars;
import me.xmrvizzy.skyblocker.skyblock.HotbarSlotLock;
+import me.xmrvizzy.skyblocker.skyblock.StatusBarTracker;
import me.xmrvizzy.skyblocker.skyblock.dungeon.DungeonMap;
import me.xmrvizzy.skyblocker.utils.Utils;
import net.fabricmc.api.EnvType;
@@ -24,14 +25,12 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
@Environment(EnvType.CLIENT)
@Mixin(InGameHud.class)
public abstract class InGameHudMixin extends DrawableHelper {
private static final Identifier SLOT_LOCK = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/slot_lock.png");
+ private final StatusBarTracker statusBarTracker = SkyblockerMod.getInstance().statusBarTracker;
private final FancyStatusBars statusBars = new FancyStatusBars();
private MatrixStack hotbarMatrices;
private int hotbarSlotIndex;
@@ -44,13 +43,21 @@ public abstract class InGameHudMixin extends DrawableHelper {
@Shadow
private int scaledWidth;
+ @Shadow
+ private void setOverlayMessage(Text message, boolean tinted) {
+ }
+
@Inject(method = "setOverlayMessage(Lnet/minecraft/text/Text;Z)V", at = @At("HEAD"), cancellable = true)
private void onSetOverlayMessage(Text message, boolean tinted, CallbackInfo ci) {
- if(!Utils.isOnSkyblock)
+ if (!Utils.isOnSkyblock || !SkyblockerConfig.get().general.bars.enableBars)
return;
String msg = message.getString();
- if(statusBars.update(msg))
+ String res = statusBarTracker.update(msg, SkyblockerConfig.get().messages.hideMana);
+ if (msg != res) {
+ if (res != null)
+ setOverlayMessage(Text.of(res), tinted);
ci.cancel();
+ }
}
@Inject(method = "renderHotbar", at = @At("HEAD"))
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/BackpackPreview.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/BackpackPreview.java
index 2638b0a6..00f32459 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/BackpackPreview.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/BackpackPreview.java
@@ -9,6 +9,7 @@ import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
+import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.client.render.item.ItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
@@ -18,7 +19,9 @@ import net.minecraft.nbt.*;
import net.minecraft.util.Identifier;
import java.io.File;
+import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -26,82 +29,95 @@ import java.util.regex.Pattern;
public class BackpackPreview extends DrawableHelper {
private static final Identifier TEXTURE = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/inventory_background.png");
private static final BackpackPreview instance = new BackpackPreview();
+ private static final Pattern PROFILE_PATTERN = Pattern.compile("Profile: ([a-zA-Z]+)");
private static final Pattern ECHEST_PATTERN = Pattern.compile("Ender Chest.*\\((\\d+)/\\d+\\)");
private static final Pattern BACKPACK_PATTERN = Pattern.compile("Backpack.*\\((\\d+)/\\d+\\)");
private static final int STORAGE_SIZE = 27;
private static final Inventory[] storage = new Inventory[STORAGE_SIZE];
private static final boolean[] dirty = new boolean[STORAGE_SIZE];
- private static boolean loaded = false;
+
+ private static String loaded = ""; // uuid + sb profile currently loaded
+ private static Path save_dir = null;
public static void tick() {
+ Utils.sbChecker(); // force update isOnSkyblock to prevent crash on disconnect
if (Utils.isOnSkyblock) {
- for (int index = 0; index < STORAGE_SIZE; ++index)
- if (dirty[index]) saveStorage(index);
- if (MinecraftClient.getInstance().currentScreen != null) {
- String title = MinecraftClient.getInstance().currentScreen.getTitle().getString();
- int index = getStorageIndexFromTitle(title);
- if (index != -1) dirty[index] = true;
+ // save all dirty storages
+ saveStorage();
+ // update save dir based on uuid and sb profile
+ String uuid = MinecraftClient.getInstance().getSession().getUuid().replaceAll("-", "");
+ String profile = getSkyblockProfile();
+ if (uuid != null && profile != null) {
+ save_dir = FabricLoader.getInstance().getConfigDir().resolve("skyblocker/backpack-preview/" + uuid + "/" + profile);
+ save_dir.toFile().mkdirs();
+ if (loaded.equals(uuid + "/" + profile)) {
+ // mark currently opened storage as dirty
+ if (MinecraftClient.getInstance().currentScreen != null) {
+ String title = MinecraftClient.getInstance().currentScreen.getTitle().getString();
+ int index = getStorageIndexFromTitle(title);
+ if (index != -1) dirty[index] = true;
+ }
+ } else {
+ // load storage again because uuid/profile changed
+ loaded = uuid + "/" + profile;
+ loadStorage();
+ }
}
}
}
- private static File getSaveDir() {
- String uuid = MinecraftClient.getInstance().getSession().getUuid();
- File dir = FabricLoader.getInstance().getConfigDir().resolve("skyblocker/backpack-preview/" + uuid).toFile();
- dir.mkdirs();
- return dir;
- }
-
- public static void loadStorage(HandledScreen screen) {
- if (!loaded) {
- String title = screen.getTitle().getString();
- if (title.equals("Storage")) {
- for (int index = 0; index < STORAGE_SIZE; ++index) {
- File file = new File(getSaveDir().getPath(), index + ".nbt");
- if (file.isFile()) {
- try {
- NbtCompound root = NbtIo.read(file);
- storage[index] = new DummyInventory(root);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
+ public static void loadStorage() {
+ assert(save_dir != null);
+ for (int index = 0; index < STORAGE_SIZE; ++index) {
+ storage[index] = null;
+ dirty[index] = false;
+ File file = save_dir.resolve(index + ".nbt").toFile();
+ if (file.isFile()) {
+ try {
+ NbtCompound root = NbtIo.read(file);
+ storage[index] = new DummyInventory(root);
+ } catch (Exception e) {
+ e.printStackTrace();
}
- loaded = true;
}
}
}
- private static void saveStorage(int index) {
- File file = new File(getSaveDir().getPath(), index + ".nbt");
- if (storage[index] != null) {
- try {
- NbtCompound root = new NbtCompound();
- NbtList list = new NbtList();
- for (int i = 9; i < storage[index].size(); ++i) {
- ItemStack stack = storage[index].getStack(i);
- NbtCompound item = new NbtCompound();
- if (stack.isEmpty()) {
- item.put("id", NbtString.of("minecraft:air"));
- item.put("Count", NbtInt.of(1));
- } else {
- item.put("id", NbtString.of(stack.getItem().toString()));
- item.put("Count", NbtInt.of(stack.getCount()));
- item.put("tag", stack.getNbt());
+ private static void saveStorage() {
+ assert(save_dir != null);
+ for (int index = 0; index < STORAGE_SIZE; ++index) {
+ if (dirty[index]) {
+ if (storage[index] != null) {
+ try {
+ NbtCompound root = new NbtCompound();
+ NbtList list = new NbtList();
+ for (int i = 9; i < storage[index].size(); ++i) {
+ ItemStack stack = storage[index].getStack(i);
+ NbtCompound item = new NbtCompound();
+ if (stack.isEmpty()) {
+ item.put("id", NbtString.of("minecraft:air"));
+ item.put("Count", NbtInt.of(1));
+ } else {
+ item.put("id", NbtString.of(stack.getItem().toString()));
+ item.put("Count", NbtInt.of(stack.getCount()));
+ item.put("tag", stack.getNbt());
+ }
+ list.add(item);
+ }
+ root.put("list", list);
+ root.put("size", NbtInt.of(storage[index].size() - 9));
+ NbtIo.write(root, save_dir.resolve(index + ".nbt").toFile());
+ dirty[index] = false;
+ } catch (Exception e) {
+ e.printStackTrace();
}
- list.add(item);
}
- root.put("list", list);
- root.put("size", NbtInt.of(storage[index].size() - 9));
- NbtIo.write(root, file);
- } catch (Exception e) {
- e.printStackTrace();
}
}
}
- public static void updateStorage(HandledScreen screen) {
+ public static void updateStorage(HandledScreen<?> screen) {
String title = screen.getTitle().getString();
int index = getStorageIndexFromTitle(title);
if (index != -1) {
@@ -151,6 +167,19 @@ public class BackpackPreview extends DrawableHelper {
if (backpack.find()) return Integer.parseInt(backpack.group(1)) + 8;
return -1;
}
+
+ private static String getSkyblockProfile() {
+ Collection<PlayerListEntry> list = MinecraftClient.getInstance().getNetworkHandler().getPlayerList();
+ for (PlayerListEntry entry : list) {
+ if (entry.getDisplayName() != null) {
+ Matcher matcher = PROFILE_PATTERN.matcher(entry.getDisplayName().getString());
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ }
+ }
+ return null;
+ }
}
class DummyInventory implements Inventory {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/FancyStatusBars.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/FancyStatusBars.java
index 5d3cf9c4..dd7ef478 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/FancyStatusBars.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/FancyStatusBars.java
@@ -7,164 +7,179 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
-import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
public class FancyStatusBars extends DrawableHelper {
- private static final MinecraftClient client = MinecraftClient.getInstance();
private static final Identifier BARS = new Identifier(SkyblockerMod.NAMESPACE, "textures/gui/bars.png");
- private static final Pattern ACTION_BAR_MANA = Pattern.compile("§b-\\d+ Mana \\(.*\\) +");
- private static final Pattern ACTION_BAR_STATUS = Pattern.compile("^§[6c](\\d+)/(\\d+)❤(\\+§c\\d+.)? +(?:§a(\\d+)§a❈ Defense|([^✎]*?))?(?: +§b(\\d+)/(\\d+)✎ +(?:Mana|§3(\\d+)ʬ))?(?: +(§[27].*))?$");
-
- private final Resource[] resources = new Resource[]{
- // Health
- new Resource(16733525),
- // Mana
- new Resource(5636095),
- // Defense
- new Resource(12106180),
- // Experience
- new Resource(8453920),
- };
-
- public boolean update(String actionBar) {
- if (!SkyblockerConfig.get().general.bars.enableBars) {
- if (SkyblockerConfig.get().messages.hideMana) {
- Matcher mana = ACTION_BAR_MANA.matcher(actionBar);
- if (mana.find()) {
- assert client.player != null;
- client.player.sendMessage(Text.of(actionBar.replace(mana.group(), "")), true);
- return true;
- }
- }
- return false;
- }
-
- Matcher matcher = ACTION_BAR_STATUS.matcher(actionBar);
- if (!matcher.matches())
- return false;
-
- resources[0].setMax(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)));
- if (matcher.group(4) != null) {
- int def = Integer.parseInt(matcher.group(4));
- resources[2].setFillLevel(def, (double) def / ((double) def + 100D));
- }
- if (matcher.group(6) != null) {
- int m = Integer.parseInt(matcher.group(6));
- if (matcher.group(8) != null)
- m += Integer.parseInt(matcher.group(8));
- resources[1].setMax(m, Integer.parseInt(matcher.group(7)));
- }
- assert client.player != null;
- resources[3].setFillLevel(client.player.experienceLevel, client.player.experienceProgress);
- StringBuilder sb = new StringBuilder();
- if (matcher.group(3) != null) {
- sb.append("§c").append(matcher.group(3));
- }
- if (SkyblockerConfig.get().messages.hideMana) {
- Matcher mana = ACTION_BAR_MANA.matcher(actionBar);
- if (!mana.find())
- appendIfNotNull(sb, matcher.group(5));
- } else {
- appendIfNotNull(sb, matcher.group(5));
- }
- appendIfNotNull(sb, matcher.group(9));
+ private final MinecraftClient client = MinecraftClient.getInstance();
+ private final StatusBarTracker statusBarTracker = SkyblockerMod.getInstance().statusBarTracker;
- if (!sb.isEmpty()) {
- assert client.player != null;
- client.player.sendMessage(Text.of(sb.toString()), true);
- }
+ private final StatusBar[] bars = new StatusBar[]{
+ new StatusBar(0, 16733525, 2), // Health Bar
+ new StatusBar(1, 5636095, 2), // Intelligence Bar
+ new StatusBar(2, 12106180, 1), // Defence Bar
+ new StatusBar(3, 8453920, 1), // Experience Bar
+ };
- return true;
+ // Positions to show the bars
+ // 0: Hotbar Layer 1, 1: Hotbar Layer 2, 2: Right of hotbar
+ // Anything outside the set values hides the bar
+ private final int[] anchorsX = new int[3];
+ private final int[] anchorsY = new int[3];
+
+ public FancyStatusBars() {
+ moveBar(0, 0);
+ moveBar(1, 0);
+ moveBar(2, 0);
+ moveBar(3, 0);
}
- private void appendIfNotNull(StringBuilder sb, String str) {
- if (str == null)
- return;
- if (!sb.isEmpty())
- sb.append(" ");
- sb.append(str);
+ private int fill(int value, int max) {
+ return (100 * value) / max;
}
- private static final int BAR_SPACING = 46;
-
public boolean render(MatrixStack matrices, int scaledWidth, int scaledHeight) {
- if (!SkyblockerConfig.get().general.bars.enableBars)
+ var player = client.player;
+ if (!SkyblockerConfig.get().general.bars.enableBars || player == null)
return false;
- int left = scaledWidth / 2 - 91;
- int top = scaledHeight - 35;
- RenderSystem.setShaderTexture(0, BARS);
- for (int i = 0; i < 4; i++) {
- this.drawTexture(matrices, left + i * BAR_SPACING, top, 0, 9 * i, 43, 9);
- int fillCount = resources[i].getFillCount();
- for (int j = 0; j < fillCount; j++) {
- this.drawTexture(matrices, left + 11 + i * BAR_SPACING, top, 43 + 31 * j, 9 * i, Resource.INNER_WIDTH, 9);
- }
- int fillLevel = resources[i].getFillLevel();
- if (0 < fillLevel)
- this.drawTexture(matrices, left + 11 + i * BAR_SPACING, top, 43 + 31 * fillCount, 9 * i, fillLevel, 9);
- }
+ anchorsX[0] = scaledWidth / 2 - 91;
+ anchorsY[0] = scaledHeight - 33;
+ anchorsX[1] = anchorsX[0];
+ anchorsY[1] = anchorsY[0] - 10;
+ anchorsX[2] = (scaledWidth / 2 + 91) + 2;
+ anchorsY[2] = scaledHeight - 16;
+
+ bars[0].update(statusBarTracker.getHealth());
+ bars[1].update(statusBarTracker.getMana());
+ int def = statusBarTracker.getDefense();
+ bars[2].fill[0] = fill(def, def + 100);
+ bars[2].text = def;
+ bars[3].fill[0] = (int) (32 * player.experienceProgress);
+ bars[3].text = player.experienceLevel;
+
+ // Update positions of bars from config
for (int i = 0; i < 4; i++) {
- renderText(matrices, resources[i].getValue(), left + 11 + i * BAR_SPACING, top, resources[i].getTextColor());
- }
- return true;
- }
+ int configAnchorNum = switch (i) {
+ case 0 -> SkyblockerConfig.get().general.bars.barpositions.healthBarPosition.toInt();
+ case 1 -> SkyblockerConfig.get().general.bars.barpositions.manaBarPosition.toInt();
+ case 2 -> SkyblockerConfig.get().general.bars.barpositions.defenceBarPosition.toInt();
+ case 3 -> SkyblockerConfig.get().general.bars.barpositions.experienceBarPosition.toInt();
+ default -> 0;
+ };
- private void renderText(MatrixStack matrices, int value, int left, int top, int color) {
- TextRenderer textRenderer = client.textRenderer;
- String text = Integer.toString(value);
- int x = left + (33 - textRenderer.getWidth(text)) / 2;
- int y = top - 3;
-
- // for i in [-1, 1]
- for (int i = -1; i < 2; i += 2) {
- textRenderer.draw(matrices, text, (float) (x + i), (float) y, 0);
- textRenderer.draw(matrices, text, (float) x, (float) (y + i), 0);
+ if (bars[i].anchorNum != configAnchorNum)
+ moveBar(i, configAnchorNum);
}
- textRenderer.draw(matrices, text, (float) x, (float) y, color);
+ RenderSystem.setShaderTexture(0, BARS);
+ for (var bar : bars)
+ bar.draw(matrices);
+ for (var bar : bars)
+ bar.drawText(matrices);
+ return true;
}
- private static class Resource {
- static final int INNER_WIDTH = 31;
- private int value;
- private int fillLevel;
- private final int textColor;
+ public void moveBar(int bar, int location) {
+ // Set the bar to the new anchor
+ bars[bar].anchorNum = location;
- public Resource(int textColor) {
- this.value = 0;
- this.fillLevel = INNER_WIDTH;
- this.textColor = textColor;
- }
-
- public void setMax(int value, int max) {
- this.value = value;
- this.fillLevel = value * INNER_WIDTH / max;
+ // Count how many bars are in each location
+ int layer1Count = 0, layer2Count = 0, rightCount = 0;
+ for (int i = 0; i < 4; i++) {
+ switch (bars[i].anchorNum) {
+ case 0 -> layer1Count++;
+ case 1 -> layer2Count++;
+ case 2 -> rightCount++;
+ }
}
- public void setFillLevel(int value, double fillLevel) {
- this.value = value;
- this.fillLevel = (int) (INNER_WIDTH * fillLevel);
+ // Set the bars width and offsetX according to their anchor and how many bars are on that layer
+ int adjustedLayer1Count = 0, adjustedLayer2Count = 0, adjustedRightCount = 0;
+ for (int i = 0; i < 4; i++) {
+ switch (bars[i].anchorNum) {
+ case 0 -> {
+ bars[i].bar_width = (172 - ((layer1Count - 1) * 11)) / layer1Count;
+ bars[i].offsetX = adjustedLayer1Count * (bars[i].bar_width + 11 + (layer1Count == 3 ? 0 : 1));
+ adjustedLayer1Count++;
+ }
+ case 1 -> {
+ bars[i].bar_width = (172 - ((layer2Count - 1) * 11)) / layer2Count;
+ bars[i].offsetX = adjustedLayer2Count * (bars[i].bar_width + 11 + (layer2Count == 3 ? 0 : 1));
+ adjustedLayer2Count++;
+ }
+ case 2 -> {
+ bars[i].bar_width = 50;
+ bars[i].offsetX = adjustedRightCount * (50 + 11);
+ adjustedRightCount++;
+ }
+ }
}
+ }
- public int getValue() {
- return value;
+ private class StatusBar {
+ public final int[] fill;
+ public int offsetX;
+ private final int v;
+ private final int text_color;
+ public int anchorNum;
+ public int bar_width;
+ public Object text;
+
+ private StatusBar(int i, int textColor, int fillNum) {
+ this.v = i * 9;
+ this.text_color = textColor;
+ this.fill = new int[fillNum];
+ this.fill[0] = 100;
+ this.anchorNum = 0;
+ this.text = "";
+ }
+
+ public void update(StatusBarTracker.Resource resource) {
+ int max = resource.max();
+ int val = resource.value();
+ this.fill[0] = fill(val, max);
+ this.fill[1] = fill(resource.overflow(), max);
+ this.text = val;
+ }
+
+ public void draw(MatrixStack matrices) {
+ // Dont draw if anchorNum is outside of range
+ if (anchorNum < 0 || anchorNum > 2) return;
+
+ // Draw the icon for the bar
+ drawTexture(matrices, anchorsX[anchorNum] + offsetX, anchorsY[anchorNum], 0, v, 9, 9);
+
+ // Draw the background for the bar
+ drawTexture(matrices, anchorsX[anchorNum] + offsetX + 10, anchorsY[anchorNum], 10, v, 2, 9);
+ for (int i = 2; i < bar_width - 2; i++)
+ drawTexture(matrices, anchorsX[anchorNum] + offsetX + 10 + i, anchorsY[anchorNum], 12, v, 1, 9);
+ drawTexture(matrices, anchorsX[anchorNum] + offsetX + 10 + bar_width - 2, anchorsY[anchorNum], 41, v, 2, 9);
+
+ // Draw the filled part of the bar
+ for (int i = 0; i < fill.length; i++) {
+ for (int j = (bar_width - 3); j >= 0; j--) {
+ if ( Math.max((j * 100)/(bar_width - 3), 1) > fill[i]) continue;
+ drawTexture(matrices, anchorsX[anchorNum] + offsetX + 11 + j, anchorsY[anchorNum], ((j == 0 || j == bar_width - 3) ? 43 : 44) + i * 31, v, 1, 9);
+ }
+ }
}
- public int getFillCount() {
- return fillLevel / INNER_WIDTH;
- }
+ public void drawText(MatrixStack matrices) {
+ // Dont draw if anchorNum is outside of range
+ if (anchorNum < 0 || anchorNum > 2) return;
- public int getFillLevel() {
- return fillLevel % INNER_WIDTH;
- }
+ TextRenderer textRenderer = client.textRenderer;
+ String text = this.text.toString();
+ int x = anchorsX[anchorNum] + this.offsetX + 11 + (bar_width - textRenderer.getWidth(text)) / 2;
+ int y = anchorsY[anchorNum] - 3;
- public int getTextColor() {
- return textColor;
+ final int[] offsets = new int[]{-1, 1};
+ for (int i : offsets) {
+ textRenderer.draw(matrices, text, (float) (x + i), (float) y, 0);
+ textRenderer.draw(matrices, text, (float) x, (float) (y + i), 0);
+ }
+ textRenderer.draw(matrices, text, (float) x, (float) y, text_color);
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTracker.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTracker.java
new file mode 100644
index 00000000..0111f75a
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTracker.java
@@ -0,0 +1,110 @@
+package me.xmrvizzy.skyblocker.skyblock;
+
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.network.ClientPlayerEntity;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class StatusBarTracker {
+ private static final Pattern STATUS_HEALTH = Pattern.compile("§[6c](\\d+)/(\\d+)❤(?:(\\+§c\\d+. *)| *)");
+ private static final Pattern DEFENSE_STATUS = Pattern.compile("§a(\\d+)§a❈ Defense *");
+ private static final Pattern MANA_USE = Pattern.compile("§b-\\d+ Mana \\(§\\S+(?:\\s\\S+)* *");
+ private static final Pattern MANA_STATUS = Pattern.compile("§b(\\d+)/(\\d+)✎ (?:Mana|§3(\\d+)ʬ) *");
+
+ private Resource health = new Resource(100, 100, 0);
+ private Resource mana = new Resource(100, 100, 0);
+ private int defense = 0;
+
+ public Resource getHealth() {
+ return this.health;
+ }
+
+ public Resource getMana() {
+ return this.mana;
+ }
+
+ public int getDefense() {
+ return this.defense;
+ }
+
+ private int parseInt(Matcher m, int group) {
+ return Integer.parseInt(m.group(group));
+ }
+
+ private void updateMana(Matcher m) {
+ int value = parseInt(m, 1);
+ int max = parseInt(m, 2);
+ int overflow = m.group(3) == null ? 0 : parseInt(m, 3);
+ this.mana = new Resource(value, max, overflow);
+ }
+
+ private void updateHealth(Matcher m) {
+ int value = parseInt(m, 1);
+ int max = parseInt(m, 2);
+ int overflow = 0;
+ ClientPlayerEntity player = null;
+ try {
+ player = MinecraftClient.getInstance().player;
+ }
+ // Is triggered by tests. Couldn't come up with a better solution.
+ catch (NullPointerException ignored) {
+ }
+ if (player != null) {
+ int hp = (int) (player.getHealth() * max / player.getMaxHealth());
+ overflow = value - hp;
+ value = hp;
+ } else if (value > max) {
+ overflow = value - max;
+ value = max;
+ }
+ if (overflow > max)
+ overflow = max;
+ this.health = new Resource(value, max, overflow);
+ }
+
+ private String reset(String str, Matcher m) {
+ str = str.substring(m.end());
+ m.reset(str);
+ return str;
+ }
+
+ public String update(String actionBar, boolean filterManaUse) {
+ var sb = new StringBuilder();
+ Matcher matcher = STATUS_HEALTH.matcher(actionBar);
+ if (!matcher.lookingAt())
+ return actionBar;
+ updateHealth(matcher);
+ if (matcher.group(3) != null) {
+ sb.append("§c❤");
+ sb.append(matcher.group(3));
+ }
+ actionBar = reset(actionBar, matcher);
+ if (matcher.usePattern(MANA_STATUS).lookingAt()) {
+ defense = 0;
+ updateMana(matcher);
+ actionBar = reset(actionBar, matcher);
+ } else {
+ if (matcher.usePattern(DEFENSE_STATUS).lookingAt()) {
+ defense = parseInt(matcher, 1);
+ actionBar = reset(actionBar, matcher);
+ } else if (filterManaUse && matcher.usePattern(MANA_USE).lookingAt()) {
+ actionBar = reset(actionBar, matcher);
+ }
+ if (matcher.usePattern(MANA_STATUS).find()) {
+ updateMana(matcher);
+ matcher.appendReplacement(sb, "");
+ }
+ }
+ matcher.appendTail(sb);
+ String res = sb.toString().trim();
+ return res.isEmpty() ? null : res;
+ }
+
+ public record Resource(
+ int value,
+ int max,
+ int overflow
+ ) {
+ }
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/OldLever.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/OldLever.java
index fc26f913..c836e4f3 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/OldLever.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/OldLever.java
@@ -14,7 +14,7 @@ public class OldLever {
protected static final VoxelShape WEST_SHAPE;
public static VoxelShape getShape(WallMountLocation wallMountLocation, Direction direction) {
- if (!SkyblockerConfig.get().locations.dungeons.oldLevers)
+ if (!SkyblockerConfig.get().general.hitbox.oldLeverHitbox)
return null;
if (wallMountLocation == WallMountLocation.FLOOR) {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java
index c3da7c18..3af82b6e 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Reparty.java
@@ -16,7 +16,7 @@ public class Reparty extends ChatPatternListener {
private static final MinecraftClient client = MinecraftClient.getInstance();
private static final SkyblockerMod skyblocker = SkyblockerMod.getInstance();
public static final Pattern PLAYER = Pattern.compile(" ([a-zA-Z0-9_]{2,16}) ●");
- private static final int BASE_DELAY = 20;
+ private static final int BASE_DELAY = 10;
private String[] players;
private int playersSoFar;
@@ -24,12 +24,11 @@ public class Reparty extends ChatPatternListener {
public Reparty() {
super("^(?:You are not currently in a party\\.|Party (?:Membe|Moderato)rs(?: \\(([0-9]+)\\)|:( .*)))$");
- repartying = false;
+ this.repartying = false;
ClientCommandManager.DISPATCHER.register(
ClientCommandManager.literal("rp").executes(context -> {
- if (!Utils.isOnSkyblock || repartying || client.player == null)
- return 0;
- repartying = true;
+ if (!Utils.isOnSkyblock || this.repartying || client.player == null) return 0;
+ this.repartying = true;
client.player.sendChatMessage("/p list");
return 0;
})
@@ -38,52 +37,42 @@ public class Reparty extends ChatPatternListener {
@Override
public ChatFilterResult state() {
- return repartying ? ChatFilterResult.FILTER : ChatFilterResult.PASS;
+ return this.repartying ? ChatFilterResult.FILTER : ChatFilterResult.PASS;
}
@Override
public boolean onMatch(Text message, Matcher matcher) {
if (matcher.group(1) != null) {
- playersSoFar = 0;
- players = new String[Integer.parseInt(matcher.group(1)) - 1];
+ this.playersSoFar = 0;
+ this.players = new String[Integer.parseInt(matcher.group(1)) - 1];
} else if (matcher.group(2) != null) {
Matcher m = PLAYER.matcher(matcher.group(2));
while (m.find()) {
- players[playersSoFar++] = m.group(1);
+ this.players[playersSoFar++] = m.group(1);
}
} else {
- repartying = false;
+ this.repartying = false;
return false;
}
- if (playersSoFar == players.length)
- reparty();
+ if (this.playersSoFar == this.players.length) reparty();
return false;
}
private void reparty() {
ClientPlayerEntity playerEntity = client.player;
if (playerEntity == null) {
- repartying = false;
+ this.repartying = false;
return;
}
sendCommand(playerEntity, "/p disband", 1);
- StringBuilder sb = new StringBuilder();
- int invites = (players.length - 1) / 5 + 1;
- for (int i = 0; i < invites; i++) {
- sb.setLength(0);
- sb.append("/p invite");
- for (int j = 0; j < 5 && i * 5 + j < players.length; j++) {
- sb.append(' ');
- sb.append(players[i * 5 + j]);
- }
- sendCommand(playerEntity, sb.toString(), i + 2);
+ for (int i = 0; i < this.players.length; ++i) {
+ String command = "/p invite " + this.players[i];
+ sendCommand(playerEntity, command, i + 2);
}
- skyblocker.scheduler.schedule(() -> repartying = false, invites + 2);
+ skyblocker.scheduler.schedule(() -> this.repartying = false, this.players.length + 2);
}
private void sendCommand(ClientPlayerEntity player, String command, int delay) {
- skyblocker.scheduler.schedule(() ->
- player.sendChatMessage(command), delay * BASE_DELAY
- );
+ skyblocker.scheduler.schedule(() -> player.sendChatMessage(command), delay * BASE_DELAY);
}
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java
index 673797d4..7f22f59b 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/dungeon/Trivia.java
@@ -60,16 +60,15 @@ public class Trivia extends ChatPatternListener {
answers.put("What is the status of Thorn?", new String[]{"Shaman Necromancer"});
answers.put("What is the status of Livid?", new String[]{"Master Necromancer"});
answers.put("What is the status of Sadan?", new String[]{"Necromancer Lord"});
- answers.put("What is the status of Maxor?", new String[]{"Young Wither"});
- answers.put("What is the status of Goldor?", new String[]{"Wither Soldier"});
- answers.put("What is the status of Storm?", new String[]{"Elementalist"});
- answers.put("What is the status of Necron?", new String[]{"Wither Lord"});
- answers.put("How many total Fairy Souls are there?", new String[]{"227 Fairy Souls"});
+ answers.put("What is the status of Maxor?", new String[]{"The Wither Lords"});
+ answers.put("What is the status of Goldor?", new String[]{"The Wither Lords"});
+ answers.put("What is the status of Storm?", new String[]{"The Wither Lords"});
+ answers.put("What is the status of Necron?", new String[]{"The Wither Lords"});
+ answers.put("How many total Fairy Souls are there?", new String[]{"238 Fairy Souls"});
answers.put("How many Fairy Souls are there in Spider's Den?", new String[]{"19 Fairy Souls"});
answers.put("How many Fairy Souls are there in The End?", new String[]{"12 Fairy Souls"});
- answers.put("How many Fairy Souls are there in The Barn?", new String[]{"7 Fairy Souls"});
- answers.put("How many Fairy Souls are there in Mushroom Desert?", new String[]{"13 Fairy Souls"});
- answers.put("How many Fairy Souls are there in Blazing Fortress?", new String[]{"19 Fairy Souls"});
+ answers.put("How many Fairy Souls are there in The Farming Islands?", new String[]{"20 Fairy Souls"});
+ answers.put("How many Fairy Souls are there in Crimson Isle?", new String[]{"29 Fairy Souls"});
answers.put("How many Fairy Souls are there in The Park?", new String[]{"11 Fairy Souls"});
answers.put("How many Fairy Souls are there in Jerry's Workshop?", new String[]{"5 Fairy Souls"});
answers.put("How many Fairy Souls are there in Hub?", new String[]{"79 Fairy Souls"});
@@ -83,7 +82,7 @@ public class Trivia extends ChatPatternListener {
answers.put("What is the name of the person that upgrades pets?", new String[]{"Kat"});
answers.put("What is the name of the lady of the Nether?", new String[]{"Elle"});
answers.put("Which villager in the Village gives you a Rogue Sword?", new String[]{"Jamie"});
- answers.put("How many unique minions are there?", new String[]{"55 Minions"});
+ answers.put("How many unique minions are there?", new String[]{"58 Minions"});
answers.put("Which of these enemies does not spawn in the Spider's Den?", new String[]{"Zombie Spider", "Cave Spider", "Wither Skeleton",
"Dashing Spooder", "Broodfather", "Night Spider"});
answers.put("Which of these monsters only spawns at night?", new String[]{"Zombie Villager", "Ghast"});
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java
index 3a5980f0..fdff7831 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/item/PriceInfoTooltip.java
@@ -13,7 +13,6 @@ import net.minecraft.text.LiteralText;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Formatting;
-import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,8 +20,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
-import java.time.Month;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
@@ -180,6 +181,20 @@ public class PriceInfoTooltip {
return stack.getNbt();
}
+ /**
+ * this method converts the "timestamp" variable into the same date format as Hypixel represents it in the museum.
+ * Currently there are two types of timestamps the legacy which is built like this
+ * "dd/MM/yy hh:mm" ("25/04/20 16:38") and the current which is built like this
+ * "MM/dd/yy hh:mm aa" ("12/24/20 11:08 PM"). Since Hypixel transforms the two formats into one format without
+ * taking into account of their formats, we do the same. The final result looks like this
+ * "MMMM dd, yyyy" (December 24, 2020).
+ * Since the legacy format has a 25 as "month" SimpleDateFormat converts the 25 into 2 years and 1 month and makes
+ * "25/04/20 16:38" -> "January 04, 2022" instead of "April 25, 2020".
+ * This causes the museum rank to be much worse than it should be.
+ *
+ * @param stack the item under the pointer
+ * @return if the item have an "Timestamp" it will be shown formated on the tooltip
+ */
public static String getTimestamp(ItemStack stack) {
NbtCompound tag = getInternalNameForItem(stack);
String internalName = null;
@@ -187,9 +202,16 @@ public class PriceInfoTooltip {
NbtCompound ea = tag.getCompound("ExtraAttributes");
if (ea.contains("timestamp", 8)) {
- internalName = ea.getString("timestamp").replaceAll("\\s(.*)", "");
- int month = Integer.parseInt(internalName.replaceAll("(\\d+)/(\\d+)/(\\d+)", "$1"));
- internalName = StringUtils.capitalize(internalName.replaceAll("(\\d+)/(\\d+)/(\\d+)", Month.of(month) + " $2, 20$3").toLowerCase());
+ internalName = ea.getString("timestamp");
+ SimpleDateFormat dt = new SimpleDateFormat("MM/dd/yy");
+
+ try {
+ Date date = dt.parse(internalName);
+ SimpleDateFormat dt1 = new SimpleDateFormat("MMMM dd, yyyy", Locale.ENGLISH);
+ internalName = dt1.format(date);
+ } catch (ParseException e) {
+ LOGGER.warn("[Skyblocker-tooltip] getTimestamp", e);
+ }
}
}
return internalName;
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemFixerUpper.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemFixerUpper.java
index b694f451..4c56546d 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemFixerUpper.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemFixerUpper.java
@@ -27,12 +27,11 @@ public class ItemFixerUpper {
Map.entry("minecraft:netherbrick", "minecraft:nether_brick"),
Map.entry("minecraft:stained_hardened_clay", "minecraft:terracotta"),
Map.entry("minecraft:quartz_ore", "minecraft:nether_quartz_ore"),
- Map.entry("minecraft:fish", "minecraft:cod"),
- Map.entry("minecraft:cooked_fish", "minecraft:cooked_cod"),
Map.entry("minecraft:red_flower", "minecraft:poppy"),
Map.entry("minecraft:tallgrass", "minecraft:grass"),
Map.entry("minecraft:stone_slab2", "minecraft:red_sandstone_slab"),
- Map.entry("minecraft:waterlily", "minecraft:lily_pad")
+ Map.entry("minecraft:waterlily", "minecraft:lily_pad"),
+ Map.entry("minecraft:stone_stairs", "minecraft:cobblestone_stairs")
);
private final static String[] DYE_COLORS = {
@@ -136,6 +135,63 @@ public class ItemFixerUpper {
"minecraft:creeper_head"
};
+ private final static String[] FISH_VARIANTS = {
+ "minecraft:cod",
+ "minecraft:salmon",
+ "minecraft:tropical_fish",
+ "minecraft:pufferfish"
+ };
+
+ private final static String[] COOKED_FISH_VARIANTS = {
+ "minecraft:cooked_cod",
+ "minecraft:cooked_salmon"
+ };
+
+ private final static String[] STONE_VARIANTS = {
+ "minecraft:stone",
+ "minecraft:granite",
+ "minecraft:polished_granite",
+ "minecraft:diorite",
+ "minecraft:polished_diorite",
+ "minecraft:andesite",
+ "minecraft:polished_andesite"
+ };
+
+ private final static String[] STONE_SLAB_VARIANTS = {
+ "minecraft:smooth_stone_slab",
+ "minecraft:sandstone_slab",
+ "minecraft:barrier", // doesn't exist
+ "minecraft:cobblestone_slab",
+ "minecraft:brick_slab",
+ "minecraft:stone_brick_slab",
+ "minecraft:nether_brick_slab",
+ "minecraft:quartz_slab"
+ };
+
+ private final static String[] COBBLESTONE_WALL_VARIANTS = {
+ "minecraft:cobblestone_wall",
+ "minecraft:mossy_cobblestone_wall"
+ };
+
+ private final static String[] DIRT_VARIANTS = {
+ "minecraft:dirt",
+ "minecraft:coarse_dirt",
+ "minecraft:podzol"
+ };
+
+ private final static String[] SPONGE_VARIANTS = {
+ "minecraft:sponge",
+ "minecraft:wet_sponge"
+ };
+
+ private final static String[] PRISMARINE_VARIANTS = {
+ "minecraft:prismarine",
+ "minecraft:prismarine_bricks",
+ "minecraft:dark_prismarine"
+ };
+
+ // TODO: map potions to their correct colors
+
public static String convertItemId(String id, int damage) {
if (id.equals("minecraft:dye")) return DYE_COLORS[damage];
if (id.equals("minecraft:log2")) return "minecraft:" + TREE_VARIANTS[damage + 4] + "log";
@@ -145,6 +201,14 @@ public class ItemFixerUpper {
if (id.equals("minecraft:spawn_egg")) return SPAWN_EGG_VARIANTS.getOrDefault(damage, "minecraft:ghast_spawn_egg");
if (id.equals("minecraft:banner")) return "minecraft:" + BLOCK_COLORS[15 - damage] + "banner";
if (id.equals("minecraft:skull")) return SKULL_VARIANTS[damage];
+ if (id.equals("minecraft:fish")) return FISH_VARIANTS[damage];
+ if (id.equals("minecraft:cooked_fish")) return COOKED_FISH_VARIANTS[damage];
+ if (id.equals("minecraft:stone")) return STONE_VARIANTS[damage];
+ if (id.equals("minecraft:stone_slab")) return STONE_SLAB_VARIANTS[damage];
+ if (id.equals("minecraft:cobblestone_wall")) return COBBLESTONE_WALL_VARIANTS[damage];
+ if (id.equals("minecraft:dirt")) return DIRT_VARIANTS[damage];
+ if (id.equals("minecraft:sponge")) return SPONGE_VARIANTS[damage];
+ if (id.equals("minecraft:prismarine")) return PRISMARINE_VARIANTS[damage];
id = MAPPING.getOrDefault(id, id);
if (Registry.ITEM.get(new Identifier(id)).equals(Items.AIR)) {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemStackBuilder.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemStackBuilder.java
index f21c7ccb..fbbd49d7 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemStackBuilder.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/itemlist/ItemStackBuilder.java
@@ -47,13 +47,6 @@ public class ItemStackBuilder {
tag.put("ExtraAttributes", extra);
extra.put("id", NbtString.of(internalName));
- // add enchantment glint
- if (internalName.contains("ENCHANTED")) {
- NbtList enchantments = new NbtList();
- enchantments.add(new NbtCompound());
- tag.put("Enchantments", enchantments);
- }
-
NbtCompound display = new NbtCompound();
tag.put("display", display);
@@ -90,6 +83,12 @@ public class ItemStackBuilder {
NbtInt color = NbtInt.of(Integer.parseInt(colorMatcher.group(1)));
display.put("color", color);
}
+ // add enchantment glint
+ if (nbttag.contains("ench:")) {
+ NbtList enchantments = new NbtList();
+ enchantments.add(new NbtCompound());
+ tag.put("Enchantments", enchantments);
+ }
return ItemStack.fromNbt(root);
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/Events.java b/src/main/java/me/xmrvizzy/skyblocker/utils/Events.java
deleted file mode 100644
index 9c488f34..00000000
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/Events.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package me.xmrvizzy.skyblocker.utils;
-
-import me.xmrvizzy.skyblocker.SkyblockerMod;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.text.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Events {
- public static MinecraftClient client = MinecraftClient.getInstance();
- public static Logger LOGGER = LoggerFactory.getLogger(SkyblockerMod.NAMESPACE);
-
- public static void onSkyblockJoin(){
- Utils.isOnSkyblock = true;
- LOGGER.info("[Skyblocker] Joined Skyblock");
- if (UpdateChecker.shouldUpdate()){
- TranslatableText linkMessage = new TranslatableText("skyblocker.update.update_message");
- TranslatableText linkMessageEnding = new TranslatableText("skyblocker.update.update_message_end");
- TranslatableText link = new TranslatableText("skyblocker.update.update_link");
- TranslatableText hoverText = new TranslatableText("skyblocker.update.hover_text");
- linkMessage.append(link.styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://modrinth.com/mod/skyblocker-liap/versions")).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText)))).append(linkMessageEnding);
-
- if (client.player != null) {
- client.player.sendMessage(linkMessage, false);
- }
- }
- }
-
- public static void onSkyblockDisconnect(){
- LOGGER.info("[Skyblocker] Disconnected from Skyblock");
- SkyblockerMod.getInstance().discordRPCManager.stop();
- Utils.isOnSkyblock = false;
- Utils.isInDungeons = false;
- }
-}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/SkyblockEvents.java b/src/main/java/me/xmrvizzy/skyblocker/utils/SkyblockEvents.java
new file mode 100644
index 00000000..2dd83ffa
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/SkyblockEvents.java
@@ -0,0 +1,33 @@
+package me.xmrvizzy.skyblocker.utils;
+
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.fabricmc.fabric.api.event.Event;
+import net.fabricmc.fabric.api.event.EventFactory;
+
+@Environment(EnvType.CLIENT)
+public final class SkyblockEvents {
+ public static final Event<SkyblockEvents.SkyblockJoin> JOIN = EventFactory.createArrayBacked(SkyblockEvents.SkyblockJoin.class, callbacks -> () -> {
+ for (SkyblockEvents.SkyblockJoin callback : callbacks) {
+ callback.onSkyblockJoin();
+ }
+ });
+
+ public static final Event<SkyblockEvents.SkyblockLeave> LEAVE = EventFactory.createArrayBacked(SkyblockEvents.SkyblockLeave.class, callbacks -> () -> {
+ for (SkyblockEvents.SkyblockLeave callback : callbacks) {
+ callback.onSkyblockLeave();
+ }
+ });
+
+ @Environment(EnvType.CLIENT)
+ @FunctionalInterface
+ public interface SkyblockJoin {
+ void onSkyblockJoin();
+ }
+
+ @Environment(EnvType.CLIENT)
+ @FunctionalInterface
+ public interface SkyblockLeave {
+ void onSkyblockLeave();
+ }
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/UpdateChecker.java b/src/main/java/me/xmrvizzy/skyblocker/utils/UpdateChecker.java
index fd43d8e3..8909b5a9 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/UpdateChecker.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/UpdateChecker.java
@@ -4,15 +4,15 @@ import com.google.gson.*;
import me.xmrvizzy.skyblocker.SkyblockerMod;
import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.text.ClickEvent;
+import net.minecraft.text.HoverEvent;
+import net.minecraft.text.TranslatableText;
import org.spongepowered.asm.util.VersionNumber;
-import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
import java.net.URL;
-import java.net.URLConnection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -25,31 +25,42 @@ public class UpdateChecker {
public static VersionNumber latestVersion = null;
public static boolean shouldUpdate(){
if (SkyblockerConfig.get().general.enableUpdateNotification){
- new Thread(new Runnable() {
- @Override
- public void run() {
- try{
- URL url = new URL("https://api.modrinth.com/v2/project/skyblocker-liap/version");
+ new Thread(() -> {
+ try{
+ URL url = new URL("https://api.modrinth.com/v2/project/skyblocker-liap/version");
- InputStreamReader reader = new InputStreamReader(url.openStream());
- JsonObject versionJson = new Gson().fromJson(reader, JsonElement.class).getAsJsonArray().get(0).getAsJsonObject();
- matcher = pattern.matcher(versionJson.get("version_number").getAsString());
- if (matcher.find()){
- latestVersion = VersionNumber.parse(matcher.group(1) + "." + matcher.group(2) + "." + matcher.group(3));
- }
- matcher = localPattern.matcher(FabricLoader.getInstance().getModContainer(SkyblockerMod.NAMESPACE).get().getMetadata().getVersion().getFriendlyString());
- if (matcher.find()){
- localVersion = VersionNumber.parse(matcher.group(1) + "." + matcher.group(2) + "." + matcher.group(3));
- }
- if (localVersion != null && latestVersion != null)
- if (localVersion.compareTo(latestVersion) < 0) shouldUpdate = true;
-
- } catch (IOException e) {
- e.printStackTrace();
+ InputStreamReader reader = new InputStreamReader(url.openStream());
+ JsonObject versionJson = new Gson().fromJson(reader, JsonElement.class).getAsJsonArray().get(0).getAsJsonObject();
+ matcher = pattern.matcher(versionJson.get("version_number").getAsString());
+ if (matcher.find()){
+ latestVersion = VersionNumber.parse(matcher.group(1) + "." + matcher.group(2) + "." + matcher.group(3));
+ }
+ matcher = localPattern.matcher(FabricLoader.getInstance().getModContainer(SkyblockerMod.NAMESPACE).get().getMetadata().getVersion().getFriendlyString());
+ if (matcher.find()){
+ localVersion = VersionNumber.parse(matcher.group(1) + "." + matcher.group(2) + "." + matcher.group(3));
}
+ if (localVersion != null && latestVersion != null)
+ if (localVersion.compareTo(latestVersion) < 0) shouldUpdate = true;
+
+ } catch (IOException e) {
+ e.printStackTrace();
}
}).start();
}
return shouldUpdate;
}
+
+ public static void init(){
+ SkyblockEvents.JOIN.register(() -> {
+ if (shouldUpdate()) {
+ TranslatableText linkMessage = new TranslatableText("skyblocker.update.update_message");
+ TranslatableText linkMessageEnding = new TranslatableText("skyblocker.update.update_message_end");
+ TranslatableText link = new TranslatableText("skyblocker.update.update_link");
+ TranslatableText hoverText = new TranslatableText("skyblocker.update.hover_text");
+ linkMessage.append(link.styled(style -> style.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://modrinth.com/mod/skyblocker-liap/versions")).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, hoverText)))).append(linkMessageEnding);
+
+ MinecraftClient.getInstance().player.sendMessage(linkMessage, false);
+ }
+ });
+ }
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java b/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java
index 5894c9df..46f3a7e1 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/Utils.java
@@ -35,10 +35,14 @@ public class Utils {
isInjected = true;
ItemTooltipCallback.EVENT.register(PriceInfoTooltip::onInjectTooltip);
}
- Events.onSkyblockJoin();
-
+ SkyblockEvents.JOIN.invoker().onSkyblockJoin();
+ isOnSkyblock = true;
+ }
+ if (!sidebar.get(0).contains("SKYBLOCK") && isOnSkyblock) {
+ SkyblockEvents.LEAVE.invoker().onSkyblockLeave();
+ Utils.isOnSkyblock = false;
+ Utils.isInDungeons = false;
}
- if (!sidebar.get(0).contains("SKYBLOCK") && isOnSkyblock) Events.onSkyblockDisconnect();
isInDungeons = isOnSkyblock && string.contains("The Catacombs");
}
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index 0b148a91..0c3899d4 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -8,6 +8,11 @@
"text.autoconfig.skyblocker.category.general": "General",
"text.autoconfig.skyblocker.option.general.bars": "Health, Mana, Defence & XP Bars",
"text.autoconfig.skyblocker.option.general.bars.enableBars": "Enable Bars",
+ "text.autoconfig.skyblocker.option.general.bars.barpositions": "Configure Bar Positions",
+ "text.autoconfig.skyblocker.option.general.bars.barpositions.healthBarPosition": "Health Bar Position",
+ "text.autoconfig.skyblocker.option.general.bars.barpositions.manaBarPosition": "Mana Bar Position",
+ "text.autoconfig.skyblocker.option.general.bars.barpositions.defenceBarPosition": "Defence Bar Position",
+ "text.autoconfig.skyblocker.option.general.bars.barpositions.experienceBarPosition": "Experience Bar Position",
"text.autoconfig.skyblocker.option.general.quicknav": "Quicknav",
"text.autoconfig.skyblocker.option.general.quicknav.enableQuicknav": "Enable Quicknav",
"text.autoconfig.skyblocker.option.general.backpackPreviewWithoutShift": "View backpack preview without holding Shift",
@@ -19,6 +24,9 @@
"text.autoconfig.skyblocker.option.general.itemTooltip.enableLowestBIN": "Enable Lowest BIN Price",
"text.autoconfig.skyblocker.option.general.itemTooltip.enableBazaarPrice": "Enable Bazaar buy/sell Price",
"text.autoconfig.skyblocker.option.general.itemTooltip.enableMuseumDate": "Enable Museum & Date",
+ "text.autoconfig.skyblocker.option.general.hitbox": "Hitboxes",
+ "text.autoconfig.skyblocker.option.general.hitbox.oldFarmlandHitbox": "Enable 1.8 farmland hitbox",
+ "text.autoconfig.skyblocker.option.general.hitbox.oldLeverHitbox": "Enable 1.8 lever hitbox",
"skyblocker.itemTooltip.nullMessage": "§b[§6Skyblocker§b] §cItem price information on tooltip will renew in max 60 seconds. If not, check latest.log",
"text.autoconfig.skyblocker.category.richPresence": "Discord Rich Presence",
@@ -37,7 +45,6 @@
"text.autoconfig.skyblocker.option.locations.dungeons.solveThreeWeirdos": "Solve Three Weirdos Puzzle",
"text.autoconfig.skyblocker.option.locations.dungeons.blazesolver": "Solve Blaze Puzzle",
"text.autoconfig.skyblocker.option.locations.dungeons.solveTrivia": "Solve Trivia Puzzle",
- "text.autoconfig.skyblocker.option.locations.dungeons.oldLevers": "1.8 lever hitbox",
"text.autoconfig.skyblocker.option.locations.dungeons.terminals": "Terminal Solvers",
"text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveColor": "Solve Select Colored",
"text.autoconfig.skyblocker.option.locations.dungeons.terminals.solveOrder": "Solve Click In Order",
diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json
index f07fbfc8..fc37cfb0 100644
--- a/src/main/resources/skyblocker.mixins.json
+++ b/src/main/resources/skyblocker.mixins.json
@@ -5,10 +5,10 @@
"client": [
"ChatHudListenerMixin",
"ClientPlayerEntityMixin",
- "ClientPlayNetworkHandlerMixin",
"InGameHudMixin",
"ItemRendererMixin",
"LeverBlockMixin",
+ "FarmlandBlockMixin",
"MinecraftClientMixin",
"AccessorWorldRenderer",
"GenericContainerScreenMixin",
diff --git a/src/test/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTrackerTest.java b/src/test/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTrackerTest.java
new file mode 100644
index 00000000..da919699
--- /dev/null
+++ b/src/test/java/me/xmrvizzy/skyblocker/skyblock/StatusBarTrackerTest.java
@@ -0,0 +1,74 @@
+package me.xmrvizzy.skyblocker.skyblock;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class StatusBarTrackerTest {
+ private StatusBarTracker tracker;
+
+ @BeforeEach
+ void setUp() {
+ tracker = new StatusBarTracker();
+ }
+
+ void assertStats(int hp, int maxHp, int def, int mana, int maxMana, int overflowMana) {
+ int absorption = 0;
+ if(hp > maxHp) {
+ absorption = hp - maxHp;
+ hp -= absorption;
+ if(absorption > maxHp)
+ absorption = maxHp;
+ }
+ assertEquals(new StatusBarTracker.Resource(hp, maxHp, absorption), tracker.getHealth());
+ assertEquals(new StatusBarTracker.Resource(mana, maxMana, overflowMana), tracker.getMana());
+ }
+
+ @Test
+ void normalStatusBar() {
+ String res = tracker.update("§c934/1086❤ §a159§a❈ Defense §b562/516✎ Mana", false);
+ assertNull(res);
+ assertStats(934, 1086, 159, 562, 516, 0);
+ }
+
+ @Test
+ void overflowMana() {
+ String res = tracker.update("§61605/1305❤ §a270§a❈ Defense §b548/548✎ §3200ʬ", false);
+ assertNull(res);
+ assertStats(1605, 1305, 270, 548, 548, 200);
+ }
+
+ @Test
+ void regeneration() {
+ String res = tracker.update("§c2484/2484❤+§c120▄ §a642§a❈ Defense §b2557/2611✎ Mana", false);
+ assertEquals("§c❤+§c120▄", res);
+ }
+
+ @Test
+ void instantTransmission() {
+ String actionBar = "§c2259/2259❤ §b-20 Mana (§6Instant Transmission§b) §b549/2676✎ Mana";
+ assertEquals("§b-20 Mana (§6Instant Transmission§b)", tracker.update(actionBar, false));
+ assertNull(tracker.update(actionBar, true));
+ }
+
+ @Test
+ void rapidFire() {
+ String actionBar = "§c2509/2509❤ §b-48 Mana (§6Rapid-fire§b) §b2739/2811✎ Mana";
+ assertEquals("§b-48 Mana (§6Rapid-fire§b)", tracker.update(actionBar, false));
+ assertNull(tracker.update(actionBar, true));
+ }
+
+ @Test
+ void zombieSword() {
+ String actionBar = "§c2509/2509❤ §b-56 Mana (§6Instant Heal§b) §b2674/2821✎ Mana §e§lⓩⓩⓩⓩ§6§lⓄ";
+ assertEquals("§b-56 Mana (§6Instant Heal§b) §e§lⓩⓩⓩⓩ§6§lⓄ", tracker.update(actionBar, false));
+ assertEquals("§e§lⓩⓩⓩⓩ§6§lⓄ", tracker.update(actionBar, true));
+ }
+
+ @Test
+ void campfire() {
+ String res = tracker.update("§c17070/25565❤+§c170▃ §65,625 DPS §c1 second §b590/626✎ §3106ʬ", false);
+ assertEquals("§c❤+§c170▃ §65,625 DPS §c1 second", res);
+ }
+}