diff options
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 @@ -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); + } +} |