aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes14
-rw-r--r--.github/CODEOWNERS11
-rw-r--r--.github/CODE_OF_CONDUCT.md3
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md34
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml8
-rw-r--r--.github/SECURITY.md16
-rw-r--r--.github/SUPPORT.md7
-rw-r--r--.github/workflows/build.yml86
-rw-r--r--.github/workflows/infer.yml49
-rwxr-xr-x.github/workflows/send_webhook_update.sh21
-rw-r--r--.gitignore4
-rw-r--r--.idea/codeStyles/Project.xml4
-rw-r--r--.idea/copyright/NotEnoughUpdates.xml7
-rw-r--r--.idea/copyright/profiles_settings.xml7
-rw-r--r--CONTRIBUTING.md147
-rw-r--r--COPYING674
-rw-r--r--COPYING.LESSER165
-rw-r--r--FAQ.md34
-rw-r--r--LICENSE60
-rw-r--r--README.md52
-rw-r--r--Update Notes/2.0-Pre30.md9
-rw-r--r--Update Notes/2.0-Pre31-Release.md21
-rw-r--r--Update Notes/2.0-Pre31.md11
-rw-r--r--Update Notes/2.1.md222
-rw-r--r--build.gradle.kts255
-rw-r--r--buildSrc/build.gradle.kts26
-rwxr-xr-xbuildSrc/generate-public-key.sh31
-rwxr-xr-xbuildSrc/moulsign.sh26
-rw-r--r--buildSrc/src/main/kotlin/neubs/buildflags.kt56
-rw-r--r--buildSrc/src/main/kotlin/neubs/publishing.kt62
-rw-r--r--buildSrc/src/main/kotlin/neubs/versioning.kt54
-rw-r--r--cape.pngbin14652 -> 0 bytes
-rw-r--r--deps/Morus-1.0.jarbin74917 -> 0 bytes
-rw-r--r--gradle.properties7
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin52271 -> 60756 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties3
-rwxr-xr-xgradlew298
-rw-r--r--gradlew.bat65
-rw-r--r--jitpack.yml4
-rw-r--r--settings.gradle.kts53
-rw-r--r--src/main/java/NotSkyblockAddonsInstallerFrame.java27
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java72
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java187
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUApi.java22
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java2842
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java655
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java724
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java99
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java279
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java218
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java80
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAHGui.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/collectionlog/CollectionConstant.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/collectionlog/GuiCollectionLog.java111
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/ClientCommandBase.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java52
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java100
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/ScreenCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java134
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java134
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DungeonWinTestCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/EnableStorageCommand.java39
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/NullzeeSphereCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/PackDevCommand.java303
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ReloadRepoCommand.java39
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ResetRepoCommand.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dev/StatsCommand.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DhCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DnCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/JoinDungeonCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/MapCommand.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/help/FeaturesCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.java25
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/help/LinksCommand.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/help/SettingsCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/help/StorageViewerWhyCommand.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java30
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/ButtonsCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalculatorCommand.java75
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalendarCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CollectionLogCommand.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CosmeticsCommand.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CustomizeCommand.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/GamemodesCommand.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java94
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java78
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/profile/CataCommand.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PeekCommand.java81
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PvCommand.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/profile/ViewProfileCommand.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ReloadRepoCommand.java39
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/repo/RepoModeCommand.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ResetRepoCommand.java18
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/BackgroundBlur.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/ChromaColour.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/GlScissorStack.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/GuiElement.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementBoolean.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementColour.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementTextField.java69
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/GuiScreenElementWrapper.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/Config.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/GuiPositionEditor.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/KeybindHelper.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/MoulConfigGuiForgeInterop.java69
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/Position.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/PositionNew.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/Category.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigAccordionId.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorAccordion.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorBoolean.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorButton.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorColour.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDropdown.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorFSR.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorKeybind.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorSlider.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorText.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditor.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorAccordion.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorBoolean.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorButton.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorColour.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java44
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDropdown.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorFSR.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorKeybind.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorSlider.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorText.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiPositionEditor.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java54
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/GuiElementSlider.java27
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/Line.java115
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/MiscUtils.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/Splitters.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java68
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java148
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpUtils.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingFloat.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingInteger.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java91
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/core/util/render/TextRenderUtils.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java91
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java78
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/cosmetics/ShaderManager.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java43
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java1719
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/envcheck/EnvironmentScan.java85
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/envcheck/FabricEntrypoint.java26
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/envcheck/NEUMixinConfigPlugin.java46
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/GuiInventoryBackgroundDrawnEvent.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/NEUEvent.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/OnBlockBreakSoundEffect.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/RepositoryReloadEvent.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/SignSubmitEvent.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/events/SlotClickEvent.java51
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java323
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java374
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java534
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/FlipperInfoPane.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java163
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/ScrollableInfoPane.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/infopanes/TextInfoPane.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElement.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementButton.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementText.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java53
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/itemeditor/NEUItemEditor.java217
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java258
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipEssenceShopListener.java84
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java887
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java387
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java277
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/OldAnimationChecker.java68
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java1718
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/listener/ScoreboardLocationChangeListener.java49
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java25
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneWarning.java215
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java62
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java158
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java178
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionSortModeWarning.java107
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/BetterContainers.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CollectionLogManager.java44
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java115
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java573
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalOverlay.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java1108
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomItemEffects.java147
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomSkulls.java38
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DamageCommas.java48
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnchantingSolvers.java210
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java492
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FancyPortals.java293
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java157
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCustomizeManager.java27
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemRarityHalo.java25
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/MiningStuff.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NPCRetexturing.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java418
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java43
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NullzeeSphere.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java489
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java173
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SlotLocking.java118
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java126
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StreamerMode.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SunTzu.java22
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CrystalHollowsTextures.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBiomes.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBlockSounds.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/DwarvenMinesTextures.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/IslandZoneSubdivider.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/LocationChangeEvent.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/SpecialBlockZone.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java49
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java245
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java27
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java91
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java70
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java85
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/NameModifier.java34
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java65
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java48
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java256
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java47
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/SCUCompatUpdater.java100
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java141
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java76
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java74
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiCustomEnchant.java349
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiEnchantColour.java74
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiInvButtonEditor.java120
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemCustomize.java29
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java252
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiNavigation.java173
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java243
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/InventoryStorageSelector.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/KatSitterOverlay.java43
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/NEUOverlayPlacements.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java55
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/SignCalculator.java117
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java448
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/TradeWindow.java107
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java274
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/EnchantState.java37
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/GuiCustomHex.java4885
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/HexItem.java264
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/ItemType.java84
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuConfigTutorial.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuTutorial.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/TutorialBase.java20
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/ExperienceOrb.java32
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/OrbDisplay.java142
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiContainer.java52
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiEditSign.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiPlayerTabOverlay.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinAbstractClientPlayer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinContainer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEffectRenderer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntity.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayerSP.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java64
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java99
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiEditSign.java50
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiInventory.java30
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiScreen.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryPlayer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemCameraTransforms.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemRenderer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerArmorBase.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerCustomHead.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLoadingScreenRenderer.java18
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMinecraft.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMouseHelper.java23
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java60
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinPlayerControllerMP.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java28
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRendererLivingEntity.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTextureManager.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySkullRenderer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorld.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorldClient.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java145
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfigEditor.java127
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java73
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHGraph.java28
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHTweaks.java64
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AccessoryBag.java49
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java106
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiKey.java15
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/BazaarTweaks.java73
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Calendar.java125
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/CustomArmour.java32
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/DungeonMapConfig.java303
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java504
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Enchanting.java56
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Fishing.java508
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ImprovedSBMenu.java119
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/InventoryButtons.java89
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ItemOverlays.java748
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java262
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/LocationEdit.java35
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java1492
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java384
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java64
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java118
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java121
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java259
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java97
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java663
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlayerOverlay.java26
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlotLocking.java205
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/StorageGUI.java547
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Toolbar.java227
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TooltipTweaks.java367
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TradeMenu.java71
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/AuctionSearchOverlay.java128
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/BazaarSearchOverlay.java572
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/BonemerangOverlay.java25
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/CombatSkillOverlay.java107
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/CrystalHollowOverlay.java81
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java461
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingOverlay.java34
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/FishingSkillOverlay.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/FuelBar.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java214
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningSkillOverlay.java21
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java31
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/RancherBootOverlay.java22
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/SlayerOverlay.java35
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlay.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlayStyle.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/TextTabOverlay.java79
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java148
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java841
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BingoPage.java346
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java495
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java841
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java542
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java5114
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewerPage.java53
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java816
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MiningPage.java1534
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java85
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PetsPage.java389
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java485
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java1572
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java1093
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java302
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/info/QuiverInfo.java62
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFish.java71
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFishPage.java480
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java148
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java89
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java92
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java50
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java66
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java66
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java67
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java51
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java42
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java40
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java70
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java54
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java32
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java33
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java53
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java26
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/ItemShopRecipe.java208
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java352
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java60
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java188
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeSlot.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java79
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java56
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/AllowEmptyHTMLTag.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java203
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java55
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java59
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java302
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java46
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Debouncer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/DiscordMarkdownBuilder.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/GuiTextures.java48
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/HastebinUploader.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/HotmInformation.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java188
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java282
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java402
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/IteratorUtils.java36
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java84
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/LerpingFloat.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java37
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/MoulSigner.java80
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java55
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/NEUResourceManager.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java51
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/NotificationHandler.java138
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java178
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/RequestFocusListener.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ReverseWorldRenderer.java28
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java99
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java115
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java19
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java395
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java59
-rw-r--r--src/main/resources/META-INF/mods.toml14
-rw-r--r--src/main/resources/assets/notenoughupdates/auc_search/master_star.pngbin0 -> 761 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/auc_search/star_board.pngbin4352 -> 639 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/auction_profit.pngbin0 -> 595 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/button20x.pngbin170 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/dg.pngbin81534 -> 46776 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/dg_preview.pngbin42377 -> 18852 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/screensaver.pngbin0 -> 31381 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/capes/screensaver_preview.pngbin0 -> 19453 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/dream.json49
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-1.json9
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-2.json17
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-3.json15
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-4.json37
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-5.json13
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-6.json32
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_-7.json8
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_0.json28
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_3.json102
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_4.json96
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_6.json220
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_7.json245
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-10_8.json90
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_-3.json189
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_-4.json21
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_-5.json26
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_-6.json12
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_2.json24
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_5.json30
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_6.json86
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-11_7.json16
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_0.json59
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_1.json67
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_10.json52
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_11.json68
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_3.json17
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_7.json25
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_8.json41
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-1_9.json42
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_-2.json27
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_-3.json109
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_-4.json206
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_-5.json173
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_-7.json87
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_0.json62
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_10.json60
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_11.json18
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_3.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_4.json194
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_6.json221
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_7.json11
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_8.json49
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-2_9.json48
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_-3.json13
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_-4.json34
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_-5.json36
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_0.json84
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_1.json87
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_11.json5
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_2.json7
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_4.json168
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_5.json72
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_6.json134
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_7.json5
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_8.json37
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-3_9.json25
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_-1.json51
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_-5.json21
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_-6.json22
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_0.json103
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_1.json29
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_10.json200
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_11.json14
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_2.json22
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_3.json38
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_4.json12
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_5.json15
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_6.json26
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_7.json16
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_8.json77
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-4_9.json43
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_-1.json57
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_-2.json54
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_-3.json51
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_-4.json144
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_-5.json7
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_-6.json65
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_0.json103
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_1.json59
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_10.json177
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_2.json41
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_4.json11
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_6.json5
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_7.json33
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_8.json184
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-5_9.json230
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_-3.json23
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_-4.json107
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_-5.json103
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_-6.json22
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_0.json36
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_1.json99
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_2.json20
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_4.json142
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_5.json179
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_6.json115
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_7.json137
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_8.json263
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-6_9.json257
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_-1.json140
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_-2.json150
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_-3.json72
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_-4.json62
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_-5.json73
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_-6.json37
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_0.json153
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_1.json168
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_2.json101
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_3.json123
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_4.json34
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_8.json218
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-7_9.json317
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_-1.json32
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_-2.json26
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_-3.json35
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_-4.json31
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_-5.json22
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_-6.json6
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_0.json62
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_1.json107
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_2.json111
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_3.json43
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_4.json83
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_5.json42
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_6.json32
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_7.json86
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_8.json266
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-8_9.json214
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_-1.json21
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_-2.json37
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_-3.json32
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_-4.json24
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_-5.json50
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_-6.json23
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_0.json30
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_2.json24
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_3.json7
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_4.json85
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_7.json293
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_8.json280
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/-9_9.json75
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/0_0.json73
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/0_10.json60
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/0_3.json22
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/0_7.json32
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/0_8.json46
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/0_9.json53
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/10_1.json203
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/10_3.json216
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/10_4.json48
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/10_5.json97
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/11_1.json73
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/11_3.json61
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/11_4.json18
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_-1.json120
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_-2.json37
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_-3.json152
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_0.json90
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_10.json91
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_7.json8
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_8.json45
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/1_9.json97
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_-1.json19
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_-2.json49
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_-4.json72
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_-5.json61
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_-7.json41
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_0.json88
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_10.json279
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_3.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_4.json146
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_6.json133
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_7.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_8.json104
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/2_9.json266
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_-1.json28
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_-10.json6
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_-3.json31
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_-4.json20
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_-5.json35
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_-6.json59
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_0.json56
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_11.json48
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_3.json23
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_4.json53
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_5.json20
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_6.json80
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/3_7.json17
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/4_-1.json50
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/4_-2.json9
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/4_-8.json70
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/4_-9.json5
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/4_0.json130
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/4_6.json62
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_-5.json8
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_-6.json9
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_-8.json103
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_0.json11
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_10.json162
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_7.json228
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_8.json158
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/5_9.json198
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_-3.json13
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_0.json66
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_1.json234
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_2.json185
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_3.json237
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_5.json304
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/6_6.json299
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_-1.json5
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_-2.json23
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_-3.json29
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_0.json25
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_1.json116
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_2.json67
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_3.json136
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_4.json123
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_5.json121
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/7_6.json180
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/8_-1.json30
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/8_-2.json51
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/8_0.json22
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/8_1.json145
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/9_-1.json36
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/9_1.json281
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/9_2.json218
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/9_5.json254
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/9_6.json130
-rw-r--r--src/main/resources/assets/notenoughupdates/dwarven_data/all.json207
-rw-r--r--src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/gamemodes.pngbin663 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/invbuttons/extraicons.json34
-rw-r--r--src/main/resources/assets/notenoughupdates/invbuttons/presets.json5470
-rw-r--r--src/main/resources/assets/notenoughupdates/logo_bg.pngbin21390 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/logo_fg.pngbin5823 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/next.pngbin3912 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/next.xcfbin8805 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/nohup.out2
-rw-r--r--src/main/resources/assets/notenoughupdates/official-wiki.css1
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpgbin30425 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpgbin18248 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpgbin14289 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpgbin19871 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpgbin18328 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpgbin8718 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpgbin14773 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpgbin11063 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpgbin5580 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpgbin17256 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpgbin12133 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpgbin4516 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_0.jpgbin0 -> 652486 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_1.jpgbin0 -> 467208 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_2.jpgbin0 -> 277432 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_3.jpgbin0 -> 503887 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_4.jpgbin0 -> 169662 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_5.jpgbin0 -> 131721 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/prev.pngbin4508 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/prev.xcfbin8371 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/prev_unhovered.pngbin4553 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_basic.pngbin5173 -> 2836 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_bestiary_tab.pngbin0 -> 628 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_bingo_tab.pngbin0 -> 2635 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_cata.pngbin5019 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_invs.pngbin4446 -> 2426 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/pv_trophy_fish_tab.pngbin0 -> 2839 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/radial_circle_off.pngbin322 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/radial_circle_on.pngbin377 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/radial_square_off.pngbin257 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/radial_square_on.pngbin304 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/setting_border.pngbin411 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.frag54
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.vert6
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/blur.json100
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json61
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json42
-rw-r--r--src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json42
-rw-r--r--src/main/resources/assets/notenoughupdates/slider_off.pngbin765 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/slider_on.pngbin767 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds.json1
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstoneamberbreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstoneamethystbreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstonejadebreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstonejasperbreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstonerubybreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstonesapphirebreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/gemstonetopazbreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/mithrilbreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/sounds/titaniumbreak.json4
-rw-r--r--src/main/resources/assets/notenoughupdates/supersecretassets/lunar.pngbin0 -> 54979 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.pngbin0 -> 12019 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.pngbin0 -> 8085 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.pngbin889 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.pngbin0 -> 2743 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/item_shop_recipe.pngbin0 -> 3177 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.pngbin0 -> 9503 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/navigation.pngbin0 -> 984 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/tab.pngbin0 -> 1247 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.pngbin8633 -> 0 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.pngbin0 -> 2709 bytes
-rw-r--r--src/main/resources/assets/notenoughupdates/trophy_profit.pngbin0 -> 375 bytes
-rw-r--r--src/main/resources/fabric.mod.json10
-rw-r--r--src/main/resources/mcmod.info30
-rw-r--r--src/main/resources/mixins.notenoughupdates.json85
-rw-r--r--src/main/resources/moulberry.keybin0 -> 422 bytes
-rw-r--r--src/main/resources/neukeystore.jksbin0 -> 101958 bytes
-rw-r--r--src/main/resources/neukeystore.txt17
-rw-r--r--src/main/resources/notenoughupdates_at.cfg11
-rw-r--r--src/test/java/io/github/moulberry/notenoughupdates/core/util/Vec3ComparableTest.java212
-rw-r--r--src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolverTest.java255
-rw-r--r--src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java1393
-rw-r--r--src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java41
-rw-r--r--src/test/resources/log4j2-test.xml16
804 files changed, 71600 insertions, 21573 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..c51f397d
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,14 @@
+* text=auto
+
+# Always Unix-style line endings
+*.sh text eol=lf
+
+# Always Windows-style line endings
+*.bat text eol=crlf
+*.cmd text eol=crlf
+
+# Always binary
+*.jpg -text
+*.ogg -text
+*.png -text
+*.xcf -text
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..94fc9f8f
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,11 @@
+/src/main/java/io/github/moulberry/notenoughupdates/recipes/* @romangraef
+/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java @romangraef
+/*gradle* @romangraef
+/README.md @IRONM00N
+/CONTRIBUTING.md @romangraef @IRONM00N
+/.editorconfig @IRONM00N
+/.github/CODE_OF_CONDUCT.md @IRONM00N
+/.github/SECURITY.md @IRONM00N
+/.github/SUPPORT.md @IRONM00N
+/.idea/codeStyles/* @IRONM00N
+/.idea/copyright/* @IRONM00N
diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..e91612f1
--- /dev/null
+++ b/.github/CODE_OF_CONDUCT.md
@@ -0,0 +1,3 @@
+# Contributor Code of Conduct
+
+Don't be a jerk.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 5e58389d..00000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: Bug report
-about: Help Moulberry pinpoint problems.
-title: '[Bug] Title'
-labels: ''
-assignees: ''
-
----
-
-<!--
-Before you begin check if the bug already been reported.
-And also ensure you are using the latest version.
-
-
-If you are unsure about these requirements or need general support,
-please join the discord server at discord.gg/moulberry
--->
-
-<!-- This is asking for the mod version for example 1.7.3-REL -->
-**Mod Version:**
-
-<!-- Provide a clear and concise description of what the bug is. -->
-**Describe the bug**
-
-<!-- Steps to reproduce the behavior -->
-**To Reproduce**
-1.
-2.
-
-<!-- A clear and concise description of what you expected to happen. -->
-**Expected behavior**
-
-<!-- Add screenshots, crash logs etc. -->
-**Attachments** \ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..0063ceed
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,8 @@
+blank_issues_enabled: false
+contact_links:
+ - name: NEU Support
+ url: https://discord.gg/moulberry
+ about: "Please ask for support in #neu-support on Moulberry's discord."
+ - name: Report security vulnerabilities
+ url: https://discord.gg/moulberry
+ about: "If you wish to discuss a bug *with security implications* privately, please open a ticket in Moulberry's discord using /new in #bot-commands"
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
new file mode 100644
index 00000000..7ddab381
--- /dev/null
+++ b/.github/SECURITY.md
@@ -0,0 +1,16 @@
+# Security Policy
+
+## Supported Versions
+
+The following versions of the mod support security updates.
+
+| Version | Supported |
+| ------- | ------------------ |
+| < 2.0 | :x: |
+| 2.0.x | :white_check_mark: |
+| 2.1.x | :white_check_mark: |
+
+## Reporting a Vulnerability
+
+Please report vulnerabilities in our [discord server](https://discord.gg/moulberry) by creating a new
+ticket in #bot-commands with the command `/new <reason>`.
diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md
new file mode 100644
index 00000000..24328844
--- /dev/null
+++ b/.github/SUPPORT.md
@@ -0,0 +1,7 @@
+<!-- markdownlint-disable MD034 -->
+
+# Obtain Support for NotEnoughUpdates
+
+If you are struggling to install the mod, having issues with it, experiencing
+unexpected crashes, or have another issue: join our community [discord server](https://discord.gg/moulberry)
+and ask for help in the #neu-support channel.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3b6d0cbd..639d3965 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,18 +3,22 @@ name: Build
on:
push:
branches:
- - '*'
+ - "*"
paths-ignore:
- - 'README.md'
- - 'LICENSE'
- - '.gitignore'
+ - "README.md"
+ - "COPYING"
+ - "COPYING.LESSER"
+ - ".gitignore"
+ - "Update Notes"
pull_request:
branches:
- - '*'
+ - "*"
paths-ignore:
- - 'README.md'
- - 'LICENSE'
- - '.gitignore'
+ - "README.md"
+ - "COPYING"
+ - "COPYING.LESSER"
+ - ".gitignore"
+ - "Update Notes"
workflow_dispatch:
jobs:
build:
@@ -26,36 +30,36 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
- - name: Send discord notification
- id: sendmsg
- if: ${{ env.WEBHOOK_URL }}
- run: |
- ./.github/workflows/send_webhook_update.sh
- env:
- STATUS: WORKING
- - name: Set up JDK 8
- uses: actions/setup-java@v2
- with:
- java-version: 8
- distribution: zulu
- cache: gradle
- - name: Build with Gradle
- run: chmod +x ./gradlew && ./gradlew setupCIWorkspace build --no-daemon
- - uses: actions/upload-artifact@v2
- with:
- path: build/libs/*-dep.jar
- - name: Update discord notification
- if: ${{ env.WEBHOOK_URL && success() }}
- run: |
- ./.github/workflows/send_webhook_update.sh
- env:
- STATUS: SUCCESS
- MESSAGE_ID: ${{ steps.sendmsg.outputs.MESSAGE_ID }}
- - name: Update discord notification
- if: ${{ env.WEBHOOK_URL && failure() }}
- run: |
- ./.github/workflows/send_webhook_update.sh
- env:
- STATUS: FAILURE
- MESSAGE_ID: ${{ steps.sendmsg.outputs.MESSAGE_ID }}
+ - uses: actions/checkout@v2
+ - name: Send discord notification
+ id: sendmsg
+ if: ${{ env.WEBHOOK_URL }}
+ run: |
+ ./.github/workflows/send_webhook_update.sh
+ env:
+ STATUS: WORKING
+ - name: Set up JDK 17
+ uses: actions/setup-java@v2
+ with:
+ java-version: 17
+ distribution: temurin
+ cache: gradle
+ - name: Build with Gradle
+ run: chmod +x ./gradlew && ./gradlew clean test remapJar --no-daemon
+ - uses: actions/upload-artifact@v2
+ with:
+ path: build/libs/*-dep.jar
+ - name: Update discord notification
+ if: ${{ env.WEBHOOK_URL && success() }}
+ run: |
+ ./.github/workflows/send_webhook_update.sh
+ env:
+ STATUS: SUCCESS
+ MESSAGE_ID: ${{ steps.sendmsg.outputs.MESSAGE_ID }}
+ - name: Update discord notification
+ if: ${{ env.WEBHOOK_URL && failure() }}
+ run: |
+ ./.github/workflows/send_webhook_update.sh
+ env:
+ STATUS: FAILURE
+ MESSAGE_ID: ${{ steps.sendmsg.outputs.MESSAGE_ID }}
diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml
new file mode 100644
index 00000000..365e748b
--- /dev/null
+++ b/.github/workflows/infer.yml
@@ -0,0 +1,49 @@
+name: Infer
+
+on:
+ - pull_request
+ - workflow_dispatch
+jobs:
+ inferering:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ name: Checkout feature
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ - name: Set up JDK 17
+ uses: actions/setup-java@v2
+ with:
+ java-version: 17
+ distribution: temurin
+ cache: gradle
+ - name: Setup Infer
+ uses: srz-zumix/setup-infer@v1
+ - name: Run Infer on feature
+ run: |
+ echo On commit $(git log --pretty=%s -1)
+ mkdir -p ciwork
+ infer capture -- ./gradlew clean test --no-daemon
+ infer analyze
+ cp infer-out/report.json ciwork/report-feature.json
+ - uses: actions/checkout@v2
+ name: Checkout base
+ with:
+ ref: ${{ github.event.pull_request.base.sha }}
+ clean: false
+ - name: Run Infer on base
+ run: |
+ echo On commit $(git log --pretty=%s -1)
+ infer capture --reactive -- ./gradlew clean test --no-daemon
+ infer analyze --reactive
+ - name: Generate report
+ run: |
+ infer reportdiff --report-current ciwork/report-feature.json --report-previous infer-out/report.json
+ jq -r '.[] | select(.severity == "ERROR") | ("::error file="+.file +",line=" +(.line|tostring)+"::" + .qualifier)' <infer-out/differential/introduced.json
+ jq -r '.[] | select(.severity == "WARNING") | ("::warning file="+.file +",line=" +(.line|tostring)+"::" + .qualifier)' <infer-out/differential/introduced.json
+ fixcount=$(jq -r "length" <infer-out/differential/fixed.json)
+ unfixcount=$(jq -r "length" <infer-out/differential/introduced.json)
+ othercount=$(jq -r "length" <infer-out/differential/preexisting.json)
+ echo "This PR fixes $fixcount potential bug(s), introduces $unfixcount potential bug(s). (Total present in feature branch: $((unfixcount + othercount)))" >>$GITHUB_STEP_SUMMARY
+ [[ $unfixcount != 0 ]] && exit 1 || echo ok.
diff --git a/.github/workflows/send_webhook_update.sh b/.github/workflows/send_webhook_update.sh
index 56852159..f0eb0051 100755
--- a/.github/workflows/send_webhook_update.sh
+++ b/.github/workflows/send_webhook_update.sh
@@ -1,4 +1,23 @@
#!/bin/bash
+#
+# Copyright (C) 2022 NotEnoughUpdates contributors
+#
+# This file is part of NotEnoughUpdates.
+#
+# NotEnoughUpdates is free software: you can redistribute it
+# and/or modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation, either
+# version 3 of the License, or (at your option) any later version.
+#
+# NotEnoughUpdates is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+#
+
set -x
COLOR_SUCCESS=8040199
@@ -69,7 +88,7 @@ function make_request() {
curl -X $1 -H "Content-Type: multipart/form-data" -F "payload_json=$json" "$upload_arg" "$upload_name=@$to_upload" "$WEBHOOK_URL$2?wait=true"
}
-echo "Should replace message with id: $MESSAGE_ID"
+echo "Should replace message with id: <$MESSAGE_ID>"
if [ "$MESSAGE_ID" != "" ]; then
discord_output=$(make_request PATCH "/messages/$MESSAGE_ID")
RESULT=$?
diff --git a/.gitignore b/.gitignore
index a7b89d94..e02d8fc4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ out
*.iml
.idea/*
!.idea/codeStyles
+!.idea/copyright
# gradle
build
@@ -23,3 +24,6 @@ gradle.properties
eclipse
run
.vscode
+infer-out/
+ciwork/
+.DS_STORE
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 6cedf3ff..c2c50913 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,5 +1,9 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
+ <JavaCodeStyleSettings>
+ <option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="500" />
+ <option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="500" />
+ </JavaCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
diff --git a/.idea/copyright/NotEnoughUpdates.xml b/.idea/copyright/NotEnoughUpdates.xml
new file mode 100644
index 00000000..8dd67ac4
--- /dev/null
+++ b/.idea/copyright/NotEnoughUpdates.xml
@@ -0,0 +1,7 @@
+<component name="CopyrightManager">
+ <copyright>
+ <option name="allowReplaceRegexp" value="Copyright" />
+ <option name="notice" value="Copyright (C) 2022 NotEnoughUpdates contributors&#10;&#10;This file is part of NotEnoughUpdates.&#10;&#10;NotEnoughUpdates is free software: you can redistribute it&#10;and/or modify it under the terms of the GNU Lesser General Public&#10;License as published by the Free Software Foundation, either&#10;version 3 of the License, or (at your option) any later version.&#10;&#10;NotEnoughUpdates is distributed in the hope that it will be useful,&#10;but WITHOUT ANY WARRANTY; without even the implied warranty of&#10;MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&#10;Lesser General Public License for more details.&#10;&#10;You should have received a copy of the GNU Lesser General Public License&#10;along with NotEnoughUpdates. If not, see &lt;https://www.gnu.org/licenses/&gt;." />
+ <option name="myName" value="NotEnoughUpdates" />
+ </copyright>
+</component> \ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 00000000..8f73a5c0
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,7 @@
+<component name="CopyrightManager">
+ <settings>
+ <module2copyright>
+ <element module="Project Files" copyright="NotEnoughUpdates" />
+ </module2copyright>
+ </settings>
+</component> \ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..e7c4b379
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,147 @@
+# Contributing
+
+## Before you contribute
+
+- Please check your feature / bug isn't already fixed in one of our pre-releases or on [the development branch](https://github.com/NotEnoughUpdates/NotEnoughUpdates/tree/master/).
+- Consider joining our [Discord](https://discord.gg/moulberry) to check in on newest developments by other people, or to get help with problems you encounter.
+- Please check that your feature idea complies with the [Hypixel Rules](https://hypixel.net/rules)
+- Check that your feature idea isn't already done in other mods. (E.g. Dungeon Solver)
+
+## Setting up a development environment
+
+### Software prerequisites
+
+- Install a Java Development Kit (You will need both version 8 and version 17) [Eclipse Temurin Download](https://adoptium.net/temurin/releases) for convenience, however any JDK will do.
+- Install Git. [Windows download](https://git-scm.com/download/win)
+- Install an IDE, such as [Jetbrains IntelliJ IDEA](https://www.jetbrains.com/idea/download).
+
+### Software configuration
+
+- Clone the NEU repository using `git clone https://github.com/NotEnoughUpdates/NotEnoughUpdates`.
+- Import that folder as a Gradle Project in your IDE (IntelliJ should autodetect it as gradle if you select the `NotEnoughUpdates` folder in the Open dialog)
+- Set your project SDK to your 1.8 JDK. This can be done in the modules settings (CTRL+ALT+SHIFT+S) in IntelliJ.
+- Set your gradle JVM to your 1.17 JDK. This can be done by searching for `gradle jvm` in the CTRL+SHIFT+A dialog in IntelliJ.
+- Run the `gen<IntelliJ/Eclipse>Runs` gradle task. In IntelliJ that can be done in the gradle tab on the right side of your IDE.
+- Optionally, run the `genSources` gradle task.
+- Run the `Minecraft Client` to make sure that everything works.
+ - Note: if you are using OSX, remove the `XstartOnFirstThread` JVM option
+
+## Logging into Hypixel in a development environment
+
+Use [DevAuth](https://github.com/DJtheRedstoner/DevAuth). You do **not** need to download the jar, just follow the configuration instructions in the [DevAuth README](https://github.com/DJtheRedstoner/DevAuth#configuration-file)
+
+## Hot Reloading
+
+Hot Reloading is possible by first launching using the IntelliJ debugger with [DCEVM 1.8](https://dcevm.github.io/). Then running a regular build and confirming the reload prompt. This can cause issues (especially with commands), so restarting is sometimes still necessary.
+
+## Creating a new Release
+<details>
+<summary>Minimized, for your convenience</summary>
+
+> **Release Types**
+>
+> Right now we can create Full Releases, Pre Releases and Hotfixes.
+>
+> - A Full Release is sent to all users, regardless of update stream.
+> - A Pre Release is only sent to users who have opted into receiving beta updates.
+> - A Hotfix is only sent to users who have *not* opted into receiving beta updates.
+> - Therefore when a bug is fixed in a hotfix update, it should *also* be fixed in a separate prerelease update.
+> On the other hand, not all bugs fixed in a prerelease update need to be also dispatched in a hotfix.
+
+### Creating a new Full Release
+
+> Full Releases should be bug free, feature complete, and ideally checked by not only the community, but also by Moulberry himself, if he so desires.
+
+- Edit `NotEnoughUpdates.java` and change
+
+```java
+public static final String VERSION = "2.2.0-REL"; /* Update the VERSION name */
+public static final int VERSION_ID = 20200; /* Set the VERSION_ID to match the version name like so: MAJOR * 10000 + MINOR * 100 + PATCH */
+public static final int PRE_VERSION_ID = 0; /* Reset the PRE_VERSION_ID back to 0 */
+public static final int HOTFIX_VERSION_ID = 0; /* Reset the HOTFIX_VERSION_ID back to 0 */
+```
+
+- Build a jar from this, either using the CI in github actions, or using `gradle remapJar` directly.
+ - If building locally, make sure that all your changes are in version control so that the commit hash is set correctly (A non `dirty` jar)
+- Create a github release (marked as full release). This should also simultaneously create a tag on which to base future hotfixes.
+- Edit the `update.json` in the repository and change
+
+```json5
+{
+ "version": "2.1.0-REL", /* Update to match the VERSION name in java */
+ "version_id": 20100, /* Update to match the VERSION_ID in java */
+ "update_msg": "§7§m§l--------------------§6§l[§c§lNEU§6§l]§7§m§l--------------------\n\n§7A new version, v§6{version}§7, is now available!\n ", /* Update the version name. Remove old patch notes; Optionally add in a short new patch note. */
+ "pre_version": "0.0", /* Reset to 0.0 */
+ "pre_version_id": 0, /* Reset to 0 */
+ "update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */
+ "update_direct": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/download/<VERSIONNAME>/NotEnoughUpdates-<VERSIONNAME>.jar", /* Change direct link to a direct download link */
+}
+```
+
+- Launch the game in an older version with this new repo locally to test the messages look first, then push to the central NEU repo (both `master` and `dangerous`)
+- Create an announcement in discord [#neu-download](https://discord.com/channels/516977525906341928/693586404256645231).
+
+### Creating a pre release
+
+> Pre Releases are intended to be mostly feature complete, mostly bug free releases that either don't have enough changes to justify a new Full Release, or have outstanding PRs that are probably merged soon.
+
+- Edit `NotEnoughUpdates.java` and change
+
+```java
+public static final String VERSION = "2.2.0-REL"; /* The VERSION name should still be the same as the latest previously released FULL release */
+public static final int VERSION_ID = 20200; /* Same as VERSION name */
+public static final int PRE_VERSION_ID = 1; /* Increment the PRE_VERSION_ID */
+```
+
+- Build a jar from this, either using the CI in github actions, or using `gradle remapJar` directly.
+ - If building locally, make sure that all your changes are in version control so that the commit hash is set correctly (A non `dirty` jar)
+- Create a github release (marked as pre release)
+- Edit the `update.json` in the repository and change
+
+```json5
+{
+ "version": "2.1.0-REL", /* The VERSION name should still be the same as the latest previously released FULL release */
+ "version_id": 20100, /* Same as VERSION name */
+ "pre_update_msg": "§7§m§l--------------------§5§l[§c§lNEU§5§l]§7§m§l--------------------\n\n§7A new pre-release, v§52.0-PRE{pre_version}§7, is now available!\n ", /* Update the version name. Remove old patch notes; Optionally add in a short new patch note. */
+ "pre_version": "0.0", /* Set to a new string (preferably increase the major version every time, except for hotfixes on the prerelease stream) */
+ "pre_version_id": 0, /* Set to PRE_VERSION_ID from java */
+ "pre_update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */
+ "pre_update_direct": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/download/<VERSIONNAME>/NotEnoughUpdates-<VERSIONNAME>.jar", /* Change direct link to a direct download link */
+}
+```
+
+- Launch the game in an older version with this new repo locally to test the messages look first, then push to the central NEU repo (both `master` and `dangerous`, as some prerelease people sadly don't know how to change repo branches)
+- Create an announcement in discord [#unofficial-prereleases](https://discord.com/channels/516977525906341928/837679819487313971).
+
+### Creating a Hotfix
+
+> Hotfixes spring off of a Full Release and intend to fix bugs and security flaws. They can, but ideally shouldn't, contain features from pre releases and are intended as a drop in replacement of the current full release of NEU. These bug fixes should ideally also be released as a prerelease in tandem with the hotfix.
+
+- Edit `NotEnoughUpdates.java` and change
+
+```java
+public static final String VERSION = "2.2.0-REL"; /* The VERSION name should still be the same as the latest previously released FULL release */
+public static final int VERSION_ID = 20200; /* Same as VERSION name */
+public static final int PRE_VERSION_ID = 0; /* The PRE_VERSION_ID should still be 0 (as this is based off a full release) */
+public static final int HOTFIX_VERSION_ID = 1; /* Increment the HOTFIX_VERSION_ID */
+```
+
+- Build a jar from this, either using the CI in github actions, or using `gradle remapJar` directly.
+ - If building locally, make sure that all your changes are in version control so that the commit hash is set correctly (A non `dirty` jar)
+- Create a github release (marked as full release)
+- Edit the previous FULL release on github with a link to the new release.
+- Edit the `update.json` in the repository and change
+
+```json5
+{
+ "version": "2.1.0-REL", /* This version should still remain the same as the last full release */
+ "version_id": 20100, /* Same as version */
+ "update_msg": "§7§m§l--------------------§6§l[§c§lNEU§6§l]§7§m§l--------------------\n\n§7A new version, v§6{version}§7, is now available!\n ", /* Update the version name. Don't remove old patch notes; Optionally add in a short new patch note. Indicate that there is a hotfix present */
+ "update_link": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/tag/<VERSIONNAME>", /* Change download link to the github release */
+ "update_direct": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases/download/<VERSIONNAME>/NotEnoughUpdates-<VERSIONNAME>.jar", /* Change direct link to a direct download link */
+}
+```
+
+- Launch the game in an older version with this new repo locally to test the messages look first, then push to the central NEU repo (both `master` and `dangerous`)
+- Create an announcement in discord [#neu-download](https://discord.com/channels/516977525906341928/693586404256645231).
+</details>
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..e72bfdda
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>. \ No newline at end of file
diff --git a/COPYING.LESSER b/COPYING.LESSER
new file mode 100644
index 00000000..153d416d
--- /dev/null
+++ b/COPYING.LESSER
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library. \ No newline at end of file
diff --git a/FAQ.md b/FAQ.md
new file mode 100644
index 00000000..346beb63
--- /dev/null
+++ b/FAQ.md
@@ -0,0 +1,34 @@
+# FAQ For NEU
+
+## What is this feature?
+
+### Equipment Overlay
+![Equipment Overlay](https://cdn.discordapp.com/attachments/756532125443817594/1006792213432389752/unknown.png)
+
+This overlay shows the current equipment of the player
+#### It doesn't fit in with my texture pack !!!!!
+[If you go to /neu equipment you can change the style of the overlay](https://cdn.discordapp.com/attachments/756532125443817594/1006796222415245413/unknown.png)
+This also applies to the pet inventory overlay
+
+
+## What does this mean?
+
+### Missing Repo Data
+![Missing Repo Data](https://cdn.discordapp.com/attachments/756532125443817594/1006805696639143987/unknown.png)
+
+If you get this popup you need to update your repo data.
+As the popup says, you can try `/neuresetrepo` but if that doesn't resolve the issue go to [#neu-support](https://discord.gg/moulberry) and ask for help
+
+## How do I?
+
+### Turn on fairy soul waypoints
+You can either [run `/neusouls`](https://cdn.discordapp.com/attachments/756532125443817594/1006808649471103046/unknown.png) for the help menu or [turn on the option in the first page of `/neu`](https://cdn.discordapp.com/attachments/756532125443817594/1006808594743840778/unknown.png)
+
+### Help I accidentally turned off the custom storage gui
+![enable storage gui](https://cdn.discordapp.com/attachments/756532125443817594/1006810880794710046/unknown.png)
+
+Simply go to `/neu storage` and turn on the first option
+
+### Move a GUI element
+![Edit gui](https://cdn.discordapp.com/attachments/756532125443817594/1006811543356317797/unknown.png)
+Go to the second tab of `/neu` and here you will have all the gui elements you can move
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 7ff2f90d..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,60 +0,0 @@
-License
-
-THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
-
-BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
-
-1. Definitions
-
- "Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License.
- "Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.
- "Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership.
- "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.
- "Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.
- "Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.
- "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
- "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.
- "Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.
-
-2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.
-
-3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
-
- to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections;
- to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified.";
- to Distribute and Publicly Perform the Work including as incorporated in Collections; and,
- to Distribute and Publicly Perform Adaptations.
-
-The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d).
-
-4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
-
- You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested.
- You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works.
- If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.
-
- For the avoidance of doubt:
- Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;
- Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and,
- Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c).
- Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise.
-
-5. Representations, Warranties and Disclaimer
-
-UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
-
-6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. Termination
-
- This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
- Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
-
-8. Miscellaneous
-
- Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
- Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
- If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
- No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
- This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
- The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.
diff --git a/README.md b/README.md
index 2b771bb9..4249abc8 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,22 @@
-<!-- markdownlint-disable-file MD033 -->
-<h1 align="center"> NotEnoughUpdates </h1>
+<!-- markdownlint-disable-file MD001 MD033 -->
+<h1 align="center">NotEnoughUpdates</h1>
-<p align="center">
+<div align="center">
<!-- release -->
- <a href="https://github.com/Moulberry/NotEnoughUpdates-REPO/releases/latest" target="_blank">
+ <a href="https://github.com/Moulberry/NotEnoughUpdates/releases/latest" target="_blank">
<img src="https://img.shields.io/github/v/release/Moulberry/NotEnoughUpdates-REPO?color=informational&include_prereleases&label=release&logo=github&logoColor=white" alt="release">
</a>
- <!-- downloads -->
- <!-- <a href="https://github.com/Moulberry/NotEnoughUpdates/releases" target="_blank">
- <img src="https://img.shields.io/github/downloads/Moulberry/NotEnoughUpdates/total?logo=GitHub&color=informational" alt="downloads">
- </a> -->
<!-- lines -->
- <a href="https://github.com/Moulberry/NotEnoughUpdates/graphs/code-frequency" target="_blank">
- <img src="https://img.shields.io/tokei/lines/github/Moulberry/NotEnoughUpdates?label=lines&color=informational&logo=GitHub" alt="lines">
+ <a href="https://github.com/NotEnoughUpdates/NotEnoughUpdates/graphs/code-frequency" target="_blank">
+ <img src="https://img.shields.io/tokei/lines/github/NotEnoughUpdates/NotEnoughUpdates?label=lines&color=informational&logo=GitHub" alt="lines">
</a>
<!-- license -->
- <a href="https://github.com/Moulberry/NotEnoughUpdates/blob/master/LICENSE" target="_blank">
- <img src="https://img.shields.io/badge/license-CC%20BY--NC%203.0-informational" alt="license">
+ <a href="./COPYING.LESSER" target="_blank">
+ <img src="https://img.shields.io/github/license/NotEnoughUpdates/NotEnoughUpdates?color=informational" alt="license">
</a>
<!-- contributors -->
- <a href="https://github.com/Moulberry/NotEnoughUpdates/graphs/contributors" target="_blank">
- <img src="https://img.shields.io/github/contributors/Moulberry/NotEnoughUpdates?color=informational&logo=GitHub" alt="contributors">
+ <a href="https://github.com/NotEnoughUpdates/NotEnoughUpdates/graphs/contributors" target="_blank">
+ <img src="https://img.shields.io/github/contributors/NotEnoughUpdates/NotEnoughUpdates?color=informational&logo=GitHub" alt="contributors">
</a>
<!-- discord -->
<a href="https://discord.gg/moulberry" target="_blank">
@@ -30,13 +26,13 @@
<a href="https://github.com/Moulberry/NotEnoughUpdates/releases" target="_blank">
<img src="https://img.shields.io/github/downloads/Moulberry/NotEnoughUpdates/total?label=downloads&color=informational&logo=GitHub" alt="downloads">
</a>
-</p>
+</div>
NotEnoughUpdates (NEU) is a feature rich 1.8.9 Minecraft forge mod for Hypixel Skyblock.
## Getting Started
-<u>**Installing Forge:**</u>
+#### Installing Forge
1. Run normal Minecraft 1.8.9 and once it reaches the title screen wait about 5 seconds and close it.
2. Install Minecraft **1.8.9** forge from the [forge website](http://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.8.9.html)
@@ -45,9 +41,9 @@ NotEnoughUpdates (NEU) is a feature rich 1.8.9 Minecraft forge mod for Hypixel S
4. When forge is installed, open the Minecraft launcher, go under the `installations tab`, click `new installation`, select the version release `1.8.9-forge1.8.9-11.15.1.xxxx` (it will usually be all the way towards the bottom).
5. Once you are done, run this new installation that you just created. Once it reaches the title screen, wait about 5 seconds and close it.
-<u>**Installing the NotEnoughUpdates mod:**</u>
+#### Installing the NotEnoughUpdates mod
-1. Download the latest mod [release](https://github.com/Moulberry/NotEnoughUpdates/releases). If it says `this file may harm your computer`, click `allow anyways` as all java files will be flagged by Chrome.
+1. Download the latest mod [release](https://github.com/NotEnoughUpdates/NotEnoughUpdates-REPO/releases). If it says `this file may harm your computer`, click `allow anyways` as all java files will be flagged by Chrome.
2. Add the NEU mod:
- If you have java installed, double click the file, click `install`
- If not, press the windows key + R; type `%appdata%`; click on the folder called `.minecraft`; click on the folder called `mods` and drag the mods file in here.
@@ -55,11 +51,9 @@ NotEnoughUpdates (NEU) is a feature rich 1.8.9 Minecraft forge mod for Hypixel S
4. Then, hop onto Skyblock and run the command `/api new`. Your api key is automatically filled out and all features should work.
5. Type `/neu`. If you see the NotEnoughUpdates menu, you have done this correctly!
-*If you need further assistance feel free to join the [discord](https://discord.gg/moulberry) and ask for help in [#neu-support](discord://discord.com/channels/516977525906341928/714332750156660756)*
-
## Features
-- An [item list](https://github.com/Moulberry/NotEnoughUpdates-REPO) containing information and recipes about every item in skyblock.
+- An [item list](https://github.com/NotEnoughUpdates/NotEnoughUpdates-REPO) containing information and recipes about every item in skyblock.
- A dungeons minimap.
- Dungeon loot profit checker.
- Item overlays for Treecapitator, Builder's Wand, Block Zapper, and Bonemerang.
@@ -77,3 +71,19 @@ NotEnoughUpdates (NEU) is a feature rich 1.8.9 Minecraft forge mod for Hypixel S
- Slot Locking
- Fishing Particle customization & alerts.
- And [much, much, more.](https://gist.github.com/jani270/d33e249d40b0333b87ba5c5e70fca398)
+
+## Support
+
+If you need assistance installing or using the mod, feel free to join the [discord](https://discord.gg/moulberry) and ask for help in [#neu-support](discord://discord.com/channels/516977525906341928/714332750156660756)
+
+## Contributing
+
+If you would like to contribute to the project, look at our [contribution guide](CONTRIBUTING.md) for more information how to install NEU for development purposes.
+
+## Security
+
+If you have found a vulnerability, please follow our [security policy](.github/SECURITY.md).
+
+## License
+
+This project is licensed under LGPL-3.0-or-later, see [COPYING](COPYING) and [COPYING.LESSER](COPYING.LESSER) for more details.
diff --git a/Update Notes/2.0-Pre30.md b/Update Notes/2.0-Pre30.md
index e036627b..99591f47 100644
--- a/Update Notes/2.0-Pre30.md
+++ b/Update Notes/2.0-Pre30.md
@@ -11,18 +11,19 @@
- Added Storage to PV (with correct sizes)
- Added Personal Vault to PV
- Added scroll lock to storage overlay
+
### **Fixed Features:**
- Todo list
- - Fixed fetchur display
- - Fixed godpot timer
+ - Fixed fetchur display
+ - Fixed godpot timer
- PV's wardrobe view not showing second page bottom row (not fully fixed could be better by dividing on every 4 and drawing per column instead of row but right now its always a full page)
- Made dwarven overlay work in crystal hollows (nopo)
- Added Gemstone powder to dwarven overlay (nopo)
- Made smooth aote work with aotv (thanks to 8k for letting me test his aotv) (nopo)
### **Bug Fixes**
-
+
- Arrow Key backpack option under storage gui not doing anything
- Fixed pets gui going away if you open /pets (nopo)
-- Fixed PV cit models dieing (nopo) \ No newline at end of file
+- Fixed PV cit models dieing (nopo)
diff --git a/Update Notes/2.0-Pre31-Release.md b/Update Notes/2.0-Pre31-Release.md
index da4fa3f4..35306023 100644
--- a/Update Notes/2.0-Pre31-Release.md
+++ b/Update Notes/2.0-Pre31-Release.md
@@ -1,21 +1,23 @@
# These are the change notes for PRE31-Release
### **Major Changes**
-- None yet. Prob not gonna happen this is mainly for small things.
+- None yet. Prob not gonna happen this is mainly for small things.
### **Minor Changes:**
+
- Added a check to see if the storagegui is on before yelling at you for having fastrender on.
- Added toggle to disable showing the treecap cooldown in item durability. (Lulonaut)#
- Added text to inform the user to "/api new" when the /pv doesn't load.
- Added support for the new arrows to the PV.
-- Improved metal detector location detection logic. (Keebler408)
-- Improved metal detector wrong location handling. (Keebler408)
-- Added Beacons waypoints for metal detector waypoint locations. (Keebler408)
+- Improved metal detector location detection logic. (CraftyOldMiner)
+- Improved metal detector wrong location handling. (CraftyOldMiner)
+- Added Beacons waypoints for metal detector waypoint locations. (CraftyOldMiner)
- Made the PV command block in the right click player menu dynamically choose its position based on a empty slot. (DeDiamondPro)
- Added Tab auto completion to the AH search gui. (Lulonaut)
### **Bug Fixes**
+
- Fixed a nullpointer exception in dwarven textures (got some confirmation that it fixed it).
- Fixed neuec not parsing correctly.
- Fixed crashing when you copy text while in the neuec/neu buttons editor menu.
@@ -24,24 +26,21 @@
- Fixed golden goblin not having a icon.
- Fixed accessory bag overlay's reforge stat detection as hypixel broke it with their tooltip changes.
- Fixed NeuEC as hypixel broke it with their tooltip changes.
-- Fixed not being able to press repeat keys in chat.
+- Fixed not being able to press repeat keys in chat.
- Fixed gemstone gauntlet/Divan Drill not being recognised as mining tools.
- Fixed morph pets not being recognized by the extended pet info tooltip tweak.
-- Fixed wrong commission maxes values for goblin in dwarven mines and the crystal hollows. (Keebler408)
+- Fixed wrong commission max values for goblin in dwarven mines and the crystal hollows. (CraftyOldMiner)
- Fixed player right click menu command block text appearing on an inventory item. (DeDiamondPro)
-
-
### **Other**
+
- Enabled help button by default.
- Added SecondPfirsisch cape.
- Added Stormy_LH cape.
- Change cape order in /neucosmetics because ironmoon asked for it.
-
### **Notes for texturepack creators**
-
### **Previous change log**
-https://github.com/DoKM/NotEnoughUpdates/blob/master/Update%20Notes/2.0-Pre31.md
+https://github.com/DoKM/NotEnoughUpdates/blob/master/Update%20Notes/2.0-Pre31.md
diff --git a/Update Notes/2.0-Pre31.md b/Update Notes/2.0-Pre31.md
index 802ad7c4..ac85f45c 100644
--- a/Update Notes/2.0-Pre31.md
+++ b/Update Notes/2.0-Pre31.md
@@ -13,8 +13,8 @@
- Added mastermode support to /pv (basically done, just needs mastermode xp)
- Added support for the Golden Dragon Pet and added support for other weird pets that might get added.
-
### **New Features:**
+
- Added Ferocity, Magic find, Mining speed and mining fortune to Accessory bag (and ferocity and magic find to /pv).
- Update notifier for "Pre" version releases. (Ironm00n)
- Added toggle for etherwarp helper overlay text.
@@ -42,8 +42,8 @@
- Replaced the chat command when clicking on a player name with /pv (Toggleable)
- Added a link to a webpage containing neu's feature /neufeatures and it shows on the first time launch.
-
### **Bug Fixes**
+
- Fishing helper not showing "!" when the rod colours are disabled.
- Decimal point values not being counted in Accessory bag overlay.
- /pv not having the correct max minion tier. (Ironm00n)
@@ -67,15 +67,15 @@
- Fixed dwarven mines waypoints not working if dwarven mines overlay was disabled.
- Fixed being able to slot lock the 9th slot.
- Fixed NEUButtons overlapping with the Accessory Bag overlay by moving the overlapping icons to the right of the overlay. (should work pretty well, too lazy to test with custom button positions but should work fine.)
-- Stopped tooltip tweak rawcraftcost displaying if the cost was 0 (either due to the price being really low or api issue).
+- Stopped tooltip tweak rawcraftcost displaying if the cost was 0 (either due to the price being really low or api issue).
- Added a catch to the capemanger slow to catch duplicate players (https://hst.sh/enuvamecef) (idk how but hey its there now).
- Fix being able to hotkey slotlocked items in a chest gui.
- (Hopefully) Fix storage overlay nullpointer crash.
- Fix not being able to dye undyed leather armour.
- Some Storage Overlay fixes (DeDiamondPro)
-
### **Other**
+
- Code clean up by Ironm00n.
- Rename variables to be more consistent. (Ironm00n)
- Devpane changes. (? - DoKM) (Ironm00n)
@@ -106,6 +106,3 @@
- Added the edit button to the Storage gui texture (it was already on transparent but not on the others) please update your textures
- Added neu logo to the bottom right of the Storage gui textures (so people stop asking which mod adds the gui (Atleast try to make the amount less))
- Added ironman icon to pv (notenoughupdates/pv_ironman.png) (thanks ery for the icon)
-
-
-
diff --git a/Update Notes/2.1.md b/Update Notes/2.1.md
index 1a120dfb..359a56fe 100644
--- a/Update Notes/2.1.md
+++ b/Update Notes/2.1.md
@@ -1,89 +1,189 @@
# These are the change notes for NEU 2.1 REL
-### **Major Changes**
-- Added mining skill overlay
-- Added fishing skill overlay
-- Added combat skill overlay
-- Added slayer overlay
-- [Added mining tab in /pv](https://cdn.discordapp.com/attachments/832652653292027904/903619242384056370/unknown.png)
-- Big thanks to kwev1n for some math and jani for the texture
+### **Major Changes:**
+
+- Added mining skill overlay - nopo
+- Added fishing skill overlay - nopo
+- Added combat skill overlay - nopo
+- Added slayer overlay - nopo
- Added blocking clicks back to the enchanting minigames (because apparently, it's not bannable?)
-- [Donpireso replied to a sba dev's email about some of sba features, and it seems to imply that blocking clicks in guis aren't bannable](https://cdn.discordapp.com/attachments/823769568933576764/906101631861526559/unknown.png)
-- Fixed pet overlay not updating when going into /pets
-- [Added an armor overlay for the new armor slots](https://cdn.discordapp.com/attachments/832652653292027904/922399046528794634/unknown.png)
-- Added a pet overlay that shows your active pet in your inventory
+ - [Donpireso replied to a sba dev's email about some of sba features, and it seems to imply that blocking clicks in guis aren't bannable](https://cdn.discordapp.com/attachments/823769568933576764/906101631861526559/unknown.png)
+ - Made it if you hold shift in the enchant solvers it overrides prevent missclicks - nopo
+- Fixed pet overlay not updating when going into /pets - nopo
+- Fixed pet overlay randomly going to level 100 - nopo
+- [Added an armor overlay for the new armor slots](https://cdn.discordapp.com/attachments/832652653292027904/922399046528794634/unknown.png)
+- Added a pet overlay that shows your active pet in your inventory - nopo
- [Price graph for items on /ah and /bz](https://cdn.discordapp.com/attachments/896407218151366687/926968296929107999/unknown.png) - DeDiamondPro
+- Added wishing compass solver that shows target coordinates, structure, and integrates with Skytils waypoints - CraftyOldMiner
+- Improved metal detector logic to solve using a single position in most cases using known locations based on Keeper coordinates - CraftyOldMiner
+- Added support for official Hypixel wiki, can be toggled in /neu misc - DeDiamondPro
+- Added a calculator (/neucalc help), that also works in the auction house / bazaar - nea89
+- Added an enchant table style gui for /hex - nopo
+- Added and fixed various things in the profile viewer:
+ - [Added hotm tab](https://media.discordapp.net/attachments/659613194066722833/991115131507441724/unknown.png) - nopo
+ - Big thanks to kwev1n for some math and jani for the texture
+ - [Added bingo tab](https://media.discordapp.net/attachments/659613194066722833/991115625772625980/unknown.png) - Lulonaut
+ - [Added bingo and stranded profile icons](https://cdn.discordapp.com/attachments/832652653292027904/915844465372065842/unknown.png) - nopo
+ - [Added trophy fishing tab](https://media.discordapp.net/attachments/659613194066722833/991114639150698567/unknown.png) - efefury
+ - [Added bestiary tab](https://cdn.discordapp.com/attachments/832652653292027904/991927854776459324/unknown.png) - nopo
+ - Added equipment - nopo
+ - Added blaze slayer level and kills - nopo
+ - Added social level - nopo
+ - Added various new collections and minions - nopo & CrypticPlasma & hannibal2
+ - Added mastermode catacombs xp to level calculator - nopo
+ - Added profile viewer settings to /neu - nopo
+ - Added an unknown icon if neu doesn't recognize your profile type - nopo
+ - Added total xp to catacombs level - efefury
+ - Fixed minion tiers crafted by coop members not showing up in /pv - Lulonaut
+ - Fixed crash in /pv when the player had a pet that is not saved in the repo - Lulonaut
+ - Added senither and lily weight - CrypticPlasma
+ - Added the Quiver Info when hovering in inventory tab over Arrows display - Lulonaut
+ - Added the Magical Power Info when hovering in inventory tab over Accessory Bag display - Lulonaut
+ - Added carpentry skill to skill average - hannibal2
+ - Fixed sort order of fishing rods in profile viewer page - hannibal2
+ - Changing sort logic from strength plus damage to bin price for best weapons in pv inventory page - hannibal2
+ - Added pronouns to /pv - nea89
+
### **Minor Changes:**
-- Add built-in recipes for forge crafts - nea89
-- Add Stranded Villager Trades to the item list - nea89
-- Make cata xp in /pv be calculated on how many runs you have and shows master mode xp rates
+
+- Added built-in recipes for forge crafts - nea89
+- Added mob drop viewer in the recipe viewer - nea89
+- Added stranded villager trades to the item list - nea89
+- Added npc shop trades in the recipe viewer - nea89
- Added a config option to hide Dwarven Mines waypoints when already at the location - Lulonaut
-- Added some info panels to some settings in /neu
+- Added some info panels to some settings in /neu - nopo
- Added Kat Level After Upgrade Estimator - nea89
-- Added /pv button in /neu
-- Added pitch and coins/m as options in farming skill overlay
+- Added pitch and coins/m as options in farming skill overlay - nopo
- Make it so tab completion in ah search GUI goes down the items - Lulonaut
-- Added a toggle for enchant glint in storage gui (ty ery for texture)
-- Added fairy souls option to /neu misc
+- Added a toggle for enchant glint in storage gui (ty ery for texture) - nopo
+- Added fairy souls option to /neu misc - nopo
+ - Added separated settings for fairy soul tracking from showing beacons. Tracking is turned on by default. - CraftyOldMiner
+- Added fairy souls beacons changing color based on their distance - CraftyOldMiner
- Make it so fairy souls are tracked independently for each profile - Lulonaut
-- Added a button in the storage gui to open the settings
-- Added an option to change the click names for /pv to /ah
-- Added a help menu to /neuec
-- Made it so treecap shows foraging xp instead of farming xp on the farming overlay
-- Made it so a jungle axe with cult will show the "farming" overlay
-- Added /neurepomode to toggle item editing and dev mode
-- Changed "NEUAH is DISABLED! Enable in /neusettings." to /neu
-- Changed misc overlays tab to todo overlays
-- Added a config option for npc retexturing
-- Added a config option for dirt wand overlay
-- Added a config option for hoe of tilling
-- Added an option to use short numbers (1.5mil) for price tooltips
-- Added Drills and Gauntlet to the itemlist tools category - jani
-- Added an option to turn off showing next click in chronomatron
-- Turns off inv search mode after 2 minutes
-- Made /neustats modlist show normal /neustats if under 15 mods
-- Added max enchant book to /neuec - Dokm
-- [Added bingo and Stranded profile icons to /pv](https://cdn.discordapp.com/attachments/832652653292027904/915844465372065842/unknown.png)
-- Added an icon if neu doesn't know about a gamemode in /pv
-- Fixed pet overlay not resetting pet when making new profile
+- Added a button in the storage gui to open the settings - nopo
+- Added an option to change the click names for /pv to /ah - nopo
+- Added a help menu to /neuec - nopo
+- Made it so treecap shows foraging xp instead of farming xp on the farming overlay - nopo
+- Made it so a jungle axe with cult will show the "farming" overlay - nopo
+- Changed "NEUAH is DISABLED! Enable in /neusettings." to /neu - nopo
+- Changed misc overlays tab to todo overlays - nopo
+- Added a config option for npc retexturing - nopo
+- Added a config option for dirt wand overlay - nopo
+- Added a config option for hoe of tilling - nopo
+- Added a config option for etherwarp block overlay - nopo
+- Added an option to use short numbers (1.5mil) for price tooltips - nopo
+- Added Drills, Gauntlets and Flares to the itemlist tools category - jani
+- Added an option to turn off showing next click in chronomatron - nopo
+- Made inv search mode automatically turn off after 2 minutes - nopo
+- Made /neustats modlist show normal /neustats if under 15 mods - nopo
+- Added max enchant book and max attribute shard to /neuec - Dokm
+- Fixed pet overlay not resetting pet when making new profile - nopo
- Added a warning in the tooltip when price info couldn't be found/is outdated - Lulonaut
-- Added "Has Advanced Tab" to /neustats
+- Added "Has Advanced Tab" to /neustats - nopo
- Added custom runes and crab hat system - jani
-- Removed unused textures
-- Added total xp if player is above cata 50 in /pv - efefury
+- Removed unused textures - nopo
- Added daily powder to todo overlay - efefury
- Added a way to include kismet feather to profit calculator - efefury
- Added custom sounds for crystal hollow gemstones - nea89
- Added custom biomes for crystal hollow areas - nopo
- Added a config option to hide the reforge stats for Legendary items from Hypixel on reforge stones - Lulonaut
-### **Bug Fixes**
-- Fix wiki pages freezing the entire game - nea89
-- Made titanium overlay and waypoints work with dwarven overlay off
-- "fixed" divan rarity in NEUAH (scuffed)
-- Made etherwarp block overlay config option
-- Fixed ram usage in crystal hollows - Dokm
-- Made skills not show int limit when at max level in skill overlays
+- Added an option to alert you if you put something for too much onto ah (default 50%) - nopo
+- Lowest bin alert triggers if lowest bin isnt found - nopo
+- Crystal Hollows crystal states are now updated when the Heart of the Mountain menu is opened - CraftyOldMiner
+- Added /neudiag command to enable/disable debug logging and dump diagnostic data - CraftyOldMiner
+- Added Blaze Slayer information - whalker
+- Added subcommand to /neupackdev allowing you to get NBT data from nearby mob(s) - whalker
+- Added subcommand to /neupackdev allowing you to get NBT data from nearby armor stand(s) - whalker
+- Added additional data to the /neupackdev NPC subcommand - whalker
+- Added a subcommand to /neupackdev to get the NBT of all mobs, armor stands, and npc in the loaded world - whalker
+- Added a subcommand to /neupackdev to get the NBT of the closest mob, armor stand, and npc in a radius in the loaded world - whalker
+- Added optional radius argument for neupackdev subcommands. - whalker
+- Added tab completion to /neupackdev subcommands. - whalker
+- Added 6-10 stars to the auction search overlay - nopo
+- Added 6-10 stars to /neucustomize - nopo
+- Added support for attributes in neuec - nopo
+- Added Heavy Pearls to todo overlay - Cobble8
+- Added Booster Cookie Warning - 2stinkysocks
+- Added an option to only search for Level 100 pets in the auction house search overlay - Lulonaut
+- [Added an error if you have new tab list off](https://cdn.discordapp.com/attachments/896407218151366687/913681097605398528/unknown.png) - nopo
+- Added Fishing Timer over bobber - nea89
+- Added [Auction Profit Viewer Overlay](https://cdn.discordapp.com/attachments/848901833119629332/993191851400101918/176946124-28ddf336-1ec7-460b-b22a-5fe2733b46a3.png) - efefury
+- Added Trophy Reward Overlay - hannibal2
+- Add Auto-Updater (linux only) - nea89
+- Added power stone feature - hannibal2
+- Added abiphone warning - hannibal2
+- Added blur limit at 100 - nopo
+- Added an option to disable etherwarp overlay when TP is denied - hannibal2
+- Added bazaar search overlay - hannibal2
+- Added fraction display instead of percentage in slayer and dungeon RNG meter inventory - hannibal2
+- Added profit per score/XP to RNG meter - hannibal2
+- Added showing the amount of dungeon runs or slayer bosses needed for the rng meter to fill up - hannibal2
+- Added bazaar prices to enchants in the enchantment table - hannibal2 / nea89
+- Added an option to not open the item list when searching containers - Lulonaut
+- Made config option in mod settings work - nea89
+
+
+### **Bug Fixes:**
+
+- Fixed wiki pages freezing the entire game - nea89
+- Fixed titanium overlay and waypoints working while having dwarven overlay disabled - nopo
+- "fixed" divan rarity in NEUAH (scuffed) - nopo
+- Fixed ram usage in crystal hollows - DokM
+- Made skills not show int limit when at max level in skill overlays - nopo
- Fixed space cape texture - Microcontrollers
-- Make it so you can hold down keys in sign GUIs
-- Added entrance to "floor one" + made blur limit at 100
-- Fixed screenshot key in /et overlay
-- Fixed api key autofill with dg copy chat feature
-- Made missing enchants not show on an item if its not missing any enchants
-- Fixed Mining overlay crash - Dokm
-- Fixed pet crash - Dokm
-- Fixed fetchur for the 75th time
-- [Made an error if you have new tab list off](https://cdn.discordapp.com/attachments/896407218151366687/913681097605398528/unknown.png)
-- Fixed lava fishing with the fishing alert
+- Make it so you can hold down keys in sign GUIs - nopo
+- Fixed api key autofill with dg copy chat feature - nopo
+- Made missing enchants not show on an item if its not missing any enchants - nopo
+- Fixed Mining overlay crash - DokM
+- Fixed pet crash - DokM
+- Fixed fetchur for the 75th time - nopo
+- Fixed fishing alert triggering a bit to early / not working with lava fishing - nopo & nea89
- Fixed /locraw detection, [previously allowed chat messages to trigger it](https://github.com/NotEnoughUpdates/NotEnoughUpdates/issues/35) - IRONM00N
- Fixed experiment timer in todo overlay - efefury
-- Fixed replace click events with /pv working in other modes
+- Fixed replace click events with /pv working in other modes - nopo
- Fixed /neuec presets not applying the strikethrough attribute - Lulonaut
-### **Other**
+- Fixed dungeon detection - nopo
+- Added checks for chat messages for dungeon win overlay - nopo
+- Fixed some vanilla Minecraft keybinds not working in NEU GUIs - nopo
+- Fixed crash with spamming remove enchant in /neuec - nopo
+- Fixed missing enchants not working with shiny items - nopo
+- Fixed golden dragon not working in pet overlay - CrypticPlasma
+- Fixed enchant overlay - nopo
+- Fixed shortened damage - nopo
+- Fixed bazaar prices sorting order in neu item list - hannibal2
+- Fixed priceless items showing first in the missing tab of the accessory bag overlay - nopo
+- Fixed clicking outside of experimentation game causing it to go count that as a valid click - nopo
+- Fixed storage gui when having locked backpack slots - nopo
+- Fixed hyphens in /peek being the wrong color - whalker
+- Fixed skill average calculation to include carpentry in /peek - whalker
+- Fixed middle clicking on pets not registering pet swap - nopo
+- Fixed middle clicking on an item with no id searching for it - nopo
+- Fixed pets with decimal stats not showing in pv - nopo
+- Changed click packets to act like vanilla - nea89/nopo
+- Fixed custom trade menu - nopo
+- Removed "Last Seen" from /pv as hypixel removed it from the api - jani
+- Fixed profile selector in /pv if you have gui scale 5 - nopo
+- Fixed Minecraft not going to be able to access the Hypixel api after 18/10/22 - nea89
+
+### **Other:**
+
- New icons was added in storage_icons.png
- Moved the help icon in /neucustomize over a little
- Added dg partner cape
- Changed custom_enchant_gui.png to remove top right button
- Added 4 new textures for the on/off switches in /neu
- Code Cleanup - IRONM00N
+- Renamed Keebler408 to CraftyOldMiner
+- Added JUnit unit tests for metal detector and wishing compass solver
+- Custom biome names for crystal hollows:
+ - NeucrystalHollowsPrecursorRemnants
+ - NeucrystalHollowsMithrilDeposit
+ - NeucrystalHollowsGoblinHoldout
+ - NeucrystalHollowsJungle
+ - NeucrystalHollowsMagmaFields
+ - NeucrystalHollowsCrystalNucleus
+- Disabled Skyclient cosmetics disabling neu map - nopo
+
### **Previous change log**
+
https://github.com/NotEnoughUpdates/NotEnoughUpdates/blob/master/Update%20Notes/2.0-Pre31-Release.md
diff --git a/build.gradle.kts b/build.gradle.kts
index e824a9a0..deb740f5 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,149 +1,180 @@
-import java.io.ByteArrayOutputStream
-import net.minecraftforge.gradle.user.ReobfMappingType
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+import neubs.NEUBuildFlags
+import neubs.applyPublishingInformation
+import neubs.setVersionFromEnvironment
+
plugins {
- java
- id("net.minecraftforge.gradle.forge") version "6f5327738df"
- id("com.github.johnrengelman.shadow") version "6.1.0"
- id("org.spongepowered.mixin") version "d75e32e"
+ idea
+ java
+ id("gg.essential.loom") version "0.10.0.+"
+ id("dev.architectury.architectury-pack200") version "0.1.3"
+ id("com.github.johnrengelman.shadow") version "7.1.2"
+ id("io.github.juuxel.loom-quiltflower") version "1.7.3"
+ `maven-publish`
}
-group = "io.github.moulberry"
-val baseVersion = "2.1"
-
-
-var buildVersion = properties["BUILD_VERSION"]
-if (buildVersion == null) {
- val stdout = ByteArrayOutputStream()
- val execResult = exec {
- commandLine("git", "describe", "--always", "--first-parent", "--abbrev=7")
- standardOutput = stdout
- }
- if (execResult.exitValue == 0)
- buildVersion = String(stdout.toByteArray()).trim()
-}
-version = baseVersion + (buildVersion?.let { "+$it" } ?: "")
+apply<NEUBuildFlags>()
+// Build metadata
-// Toolchains:
+group = "io.github.moulberry"
-java {
- // Forge Gradle currently prevents using the toolchain: toolchain.languageVersion.set(JavaLanguageVersion.of(8))
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+setVersionFromEnvironment("2.1")
+
+// Minecraft configuration:
+loom {
+ launchConfigs {
+ "client" {
+ property("mixin.debug", "true")
+ property("asmhelper.verbose", "true")
+ arg("--tweakClass", "org.spongepowered.asm.launch.MixinTweaker")
+ arg("--mixin", "mixins.notenoughupdates.json")
+ }
+ }
+ runConfigs {
+ "server" {
+ isIdeConfigGenerated = false
+ }
+ }
+ forge {
+ pack200Provider.set(dev.architectury.pack200.java.Pack200Adapter())
+ mixinConfig("mixins.notenoughupdates.json")
+ }
+ mixin {
+ defaultRefmapName.set("mixins.notenoughupdates.refmap.json")
+ }
}
-minecraft {
- version = "1.8.9-11.15.1.2318-1.8.9"
- runDir = "run"
- mappings = "stable_22"
- clientJvmArgs.addAll(
- listOf(
- "-Dmixin.debug=true",
- "-Dasmhelper.verbose=true"
- )
- )
- clientRunArgs.addAll(
- listOf(
- "--tweakClass org.spongepowered.asm.launch.MixinTweaker",
- "--mixin mixins.notenoughupdates.json"
- )
- )
+
+// Dependencies:
+repositories {
+ mavenCentral()
+ mavenLocal()
+ maven("https://repo.spongepowered.org/maven/")
+ maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1")
+ maven("https://jitpack.io")
}
-mixin {
- add(sourceSets.main.get(), "mixins.notenoughupdates.refmap.json")
+val shadowImplementation by configurations.creating {
+ configurations.implementation.get().extendsFrom(this)
}
-// Dependencies:
+val shadowApi by configurations.creating {
+ configurations.implementation.get().extendsFrom(this)
+}
-repositories {
- mavenCentral()
- flatDir { dirs("deps/") }
- maven("https://repo.spongepowered.org/maven/")
+val devEnv by configurations.creating {
+ configurations.runtimeClasspath.get().extendsFrom(this)
+ isCanBeResolved = false
+ isCanBeConsumed = false
+ isVisible = false
}
dependencies {
- implementation("org.spongepowered:mixin:0.7.11-SNAPSHOT")
- annotationProcessor("org.spongepowered:mixin:0.7.11-SNAPSHOT")
- implementation("com.fasterxml.jackson.core:jackson-core:2.13.1")
- implementation("info.bliki.wiki:bliki-core:3.1.0")
+ minecraft("com.mojang:minecraft:1.8.9")
+ mappings("de.oceanlabs.mcp:mcp_stable:22-1.8.9")
+ forge("net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9")
+
+ shadowImplementation("org.spongepowered:mixin:0.7.11-SNAPSHOT") {
+ isTransitive = false // Dependencies of mixin are already bundled by minecraft
+ }
+ annotationProcessor("org.spongepowered:mixin:0.8.4-SNAPSHOT")
+ shadowApi("info.bliki.wiki:bliki-core:3.1.0")
+ testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
+ testAnnotationProcessor("org.spongepowered:mixin:0.8.4-SNAPSHOT")
+ // modImplementation("io.github.notenoughupdates:MoulConfig:0.0.1")
+
+ devEnv("me.djtheredstoner:DevAuth-forge-legacy:1.1.0")
}
+
+java {
+ withSourcesJar()
+ toolchain.languageVersion.set(JavaLanguageVersion.of(8))
+}
+
// Tasks:
tasks.withType(JavaCompile::class) {
- options.encoding = "UTF-8"
+ options.encoding = "UTF-8"
}
-tasks.withType(Jar::class) {
- archiveBaseName.set("NotEnoughUpdates")
- manifest.attributes.run {
- this["Main-Class"] = "NotSkyblockAddonsInstallerFrame"
- this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker"
- this["MixinConfigs"] = "mixins.notenoughupdates.json"
- this["FMLCorePluginContainsFMLMod"] = "true"
- this["ForceLoadAsMod"] = "true"
- this["FMLAT"] = "notenoughupdates_at.cfg"
- }
+tasks.named<Test>("test") {
+ useJUnitPlatform()
}
-tasks.shadowJar {
- archiveClassifier.set("dep")
- exclude(
- "module-info.class",
- "LICENSE.txt"
- )
- dependencies {
- include(dependency("org.spongepowered:mixin:0.7.11-SNAPSHOT"))
-
- include(dependency("commons-io:commons-io"))
- include(dependency("org.apache.commons:commons-lang3"))
- include(dependency("com.fasterxml.jackson.core:jackson-databind:2.10.2"))
- include(dependency("com.fasterxml.jackson.core:jackson-annotations:2.10.2"))
- include(dependency("com.fasterxml.jackson.core:jackson-core:2.10.2"))
-
- include(dependency("info.bliki.wiki:bliki-core:3.1.0"))
- include(dependency("org.slf4j:slf4j-api:1.7.18"))
- include(dependency("org.luaj:luaj-jse:3.0.1"))
- }
- fun relocate(name: String) = relocate(name, "io.github.moulberry.notenoughupdates.deps.$name")
- relocate("com.fasterxml.jackson")
- relocate("org.eclipse")
- relocate("org.slf4j")
+tasks.withType(Jar::class) {
+ archiveBaseName.set("NotEnoughUpdates")
+ manifest.attributes.run {
+ this["Main-Class"] = "NotSkyblockAddonsInstallerFrame"
+ this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker"
+ this["MixinConfigs"] = "mixins.notenoughupdates.json"
+ this["FMLCorePluginContainsFMLMod"] = "true"
+ this["ForceLoadAsMod"] = "true"
+ this["Manifest-Version"] = "1.0"
+ }
}
-tasks.build.get().dependsOn(tasks.shadowJar)
+val remapJar by tasks.named<net.fabricmc.loom.task.RemapJarTask>("remapJar") {
+ archiveClassifier.set("dep")
+ from(tasks.shadowJar)
+ input.set(tasks.shadowJar.get().archiveFile)
+ doLast {
+ println("Jar name: ${archiveFile.get().asFile}")
+ }
+}
-reobf {
- create("shadowJar") {
- mappingType = ReobfMappingType.SEARGE
- }
+tasks.shadowJar {
+ archiveClassifier.set("dep-dev")
+ configurations = listOf(shadowImplementation, shadowApi)
+ exclude("**/module-info.class", "LICENSE.txt")
+ dependencies {
+ exclude {
+ it.moduleGroup.startsWith("org.apache.") || it.moduleName in
+ listOf("logback-classic", "commons-logging", "commons-codec", "logback-core")
+ }
+ }
+ fun relocate(name: String) = relocate(name, "io.github.moulberry.notenoughupdates.deps.$name")
}
+tasks.assemble.get().dependsOn(remapJar)
+
tasks.processResources {
- from(sourceSets.main.get().resources.srcDirs)
- filesMatching("mcmod.info") {
- expand(
- "version" to project.version,
- "mcversion" to minecraft.version
- )
- }
- rename("(.+_at.cfg)".toPattern(), "META-INF/$1")
+ from(tasks["generateBuildFlags"])
+ filesMatching(listOf("mcmod.info", "fabric.mod.json", "META-INF/mods.toml")) {
+ expand(
+ "version" to project.version, "mcversion" to "1.8.9"
+ )
+ }
}
-val moveResources by tasks.creating {
- doLast {
- ant.withGroovyBuilder {
- "move"(
- "file" to "$buildDir/resources/main",
- "todir" to "$buildDir/classes/java"
- )
- }
- }
- dependsOn(tasks.processResources)
+sourceSets.main {
+ output.setResourcesDir(file("$buildDir/classes/java/main"))
}
-tasks.classes { dependsOn(moveResources) }
-
+applyPublishingInformation(
+ "deobf" to tasks.jar,
+ "all" to tasks.remapJar,
+ "sources" to tasks["sourcesJar"],
+)
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 00000000..5afecadc
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+plugins {
+ `kotlin-dsl`
+}
+
+repositories {
+ mavenCentral()
+}
diff --git a/buildSrc/generate-public-key.sh b/buildSrc/generate-public-key.sh
new file mode 100755
index 00000000..3f778c53
--- /dev/null
+++ b/buildSrc/generate-public-key.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 NotEnoughUpdates contributors
+#
+# This file is part of NotEnoughUpdates.
+#
+# NotEnoughUpdates is free software: you can redistribute it
+# and/or modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation, either
+# version 3 of the License, or (at your option) any later version.
+#
+# NotEnoughUpdates is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+#
+
+
+output="$(dirname $(dirname $(readlink -f "$0")))/src/main/resources/moulberry.key"
+
+echo processing rsa input key from $1, and outputting to $output
+
+tempfile="$(mktemp)"
+ssh-keygen -f "$1" -e -m pkcs8 > "$tempfile"
+openssl rsa -pubin -in "$tempfile" -outform der > $output
+
+echo saved x509 public key at $output
+
diff --git a/buildSrc/moulsign.sh b/buildSrc/moulsign.sh
new file mode 100755
index 00000000..dacb8ec3
--- /dev/null
+++ b/buildSrc/moulsign.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2022 NotEnoughUpdates contributors
+#
+# This file is part of NotEnoughUpdates.
+#
+# NotEnoughUpdates is free software: you can redistribute it
+# and/or modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation, either
+# version 3 of the License, or (at your option) any later version.
+#
+# NotEnoughUpdates is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+#
+
+echo use key $1, signing file $2
+openssl dgst -sign "$1" "$2" > "$2.asc"
+echo signature saved to "$2.asc"
+
+
+
diff --git a/buildSrc/src/main/kotlin/neubs/buildflags.kt b/buildSrc/src/main/kotlin/neubs/buildflags.kt
new file mode 100644
index 00000000..6b7ab489
--- /dev/null
+++ b/buildSrc/src/main/kotlin/neubs/buildflags.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package neubs
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.the
+import java.nio.charset.StandardCharsets
+import java.util.*
+
+const val NEU_BUILDFLAGS_PREFIX = "neu.buildflags."
+
+class NEUBuildFlags : Plugin<Project> {
+ override fun apply(target: Project) {
+ val props =
+ target.properties.filterKeys { it.startsWith(NEU_BUILDFLAGS_PREFIX) }.mapValues { it.value as String }
+ target.extensions.add("buildflags", Extension(props))
+ target.tasks.create("generateBuildFlags") {
+ outputs.upToDateWhen { false }
+ val t = target.layout.buildDirectory.file("buildflags.properties")
+ outputs.file(t)
+ doLast {
+ val p = Properties()
+ p.putAll(props)
+ t.get().asFile.writer(StandardCharsets.UTF_8).use {
+ p.store(it, "Store build time configuration for NEU")
+ }
+ }
+
+ }
+ }
+
+ class Extension(val props: Map<String, String>) {
+ fun bool(name: String) = props["$NEU_BUILDFLAGS_PREFIX$name"] == "true"
+ }
+}
+
+val Project.buildFlags: NEUBuildFlags.Extension
+ get() = the<NEUBuildFlags.Extension>()
diff --git a/buildSrc/src/main/kotlin/neubs/publishing.kt b/buildSrc/src/main/kotlin/neubs/publishing.kt
new file mode 100644
index 00000000..4f9979a1
--- /dev/null
+++ b/buildSrc/src/main/kotlin/neubs/publishing.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package neubs
+
+import org.gradle.api.Project
+import org.gradle.api.publish.PublishingExtension
+import org.gradle.api.publish.maven.MavenPublication
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.create
+import org.gradle.kotlin.dsl.get
+
+fun Project.applyPublishingInformation(
+ vararg artifacts: Pair<String, Any>
+) {
+ this.configure<PublishingExtension> {
+ publications {
+ create<MavenPublication>("maven") {
+ for((name, source) in artifacts) {
+ artifact(source) {
+ classifier = name
+ }
+ }
+ pom {
+ name.set("NotEnoughUpdates")
+ description.set("A feature rich 1.8.9 Minecraft forge mod for Hypixel Skyblock")
+ licenses {
+ license {
+ name.set("GNU Lesser General Public License")
+ url.set("https://github.com/NotEnoughUpdates/NotEnoughUpdates/blob/master/COPYING.LESSER")
+ }
+ }
+ developers {
+ developer {
+ name.set("Moulberry")
+ }
+ developer {
+ name.set("The NotEnoughUpdates Contributors and Maintainers")
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/buildSrc/src/main/kotlin/neubs/versioning.kt b/buildSrc/src/main/kotlin/neubs/versioning.kt
new file mode 100644
index 00000000..254e0012
--- /dev/null
+++ b/buildSrc/src/main/kotlin/neubs/versioning.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package neubs
+
+import org.gradle.api.Project
+import java.io.ByteArrayOutputStream
+
+fun Project.setVersionFromEnvironment(baseVersion: String) {
+ val buildExtra = mutableListOf<String>()
+ val buildVersion = properties["BUILD_VERSION"] as? String
+ if (buildVersion != null) buildExtra.add(buildVersion)
+ if (System.getenv("CI") == "true") buildExtra.add("ci")
+
+ val stdout = ByteArrayOutputStream()
+ val execResult = exec {
+ commandLine("git", "describe", "--always", "--first-parent", "--abbrev=7")
+ standardOutput = stdout
+ isIgnoreExitValue = true
+ }
+ if (execResult.exitValue == 0) {
+ buildExtra.add(String(stdout.toByteArray()).trim())
+ }
+
+ val gitDiffStdout = ByteArrayOutputStream()
+ val gitDiffResult = exec {
+ commandLine("git", "status", "--porcelain")
+ standardOutput = gitDiffStdout
+ isIgnoreExitValue = true
+ }
+ if (gitDiffStdout.toByteArray().isNotEmpty()) {
+ buildExtra.add("dirty")
+ }
+
+ version = baseVersion + (if (buildExtra.isEmpty()) "" else buildExtra.joinToString(prefix = "+", separator = "."))
+
+}
+
diff --git a/cape.png b/cape.png
deleted file mode 100644
index a2a2d5f7..00000000
--- a/cape.png
+++ /dev/null
Binary files differ
diff --git a/deps/Morus-1.0.jar b/deps/Morus-1.0.jar
deleted file mode 100644
index 92276d72..00000000
--- a/deps/Morus-1.0.jar
+++ /dev/null
Binary files differ
diff --git a/gradle.properties b/gradle.properties
index bf86fb71..f596b2d7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1 +1,6 @@
-org.gradle.jvmargs=-Xmx2G \ No newline at end of file
+org.gradle.jvmargs=-Xmx2G
+loom.platform=forge
+# NEU Buildflags. Please keep these flags in a commented out form while checked into version control.
+# See BuildFlags.java for usages of these values.
+# Build with Pronouns in PV by default
+# neu.buildflags.pronouns=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 30d399d8..249e5832 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c1ff7937..ae04661e 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-all.zip
diff --git a/gradlew b/gradlew
index 91a7e269..a69d9cb6 100755
--- a/gradlew
+++ b/gradlew
@@ -1,79 +1,129 @@
-#!/usr/bin/env bash
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
-warn ( ) {
+warn () {
echo "$*"
-}
+} >&2
-die ( ) {
+die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -82,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -90,75 +140,101 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
-# For Cygwin, switch paths to Windows format before running java
-if $cygwin ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=$((i+1))
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- (0) set -- ;;
- (1) set -- "$args0" ;;
- (2) set -- "$args0" "$args1" ;;
- (3) set -- "$args0" "$args1" "$args2" ;;
- (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
-}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index 8a0b282a..f127cfd4 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -1,4 +1,20 @@
-@if "%DEBUG%" == "" @echo off
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -8,20 +24,23 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -35,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -45,44 +64,26 @@ echo location of your Java installation.
goto fail
-:init
-@rem Get command-line arguments, handling Windowz variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
-
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/jitpack.yml b/jitpack.yml
new file mode 100644
index 00000000..6166e3d7
--- /dev/null
+++ b/jitpack.yml
@@ -0,0 +1,4 @@
+jdk:
+ - openjdk17
+env:
+ CI: true
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 44138312..eb291fb5 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,17 +1,40 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
pluginManagement {
- repositories {
- mavenCentral()
- gradlePluginPortal()
- maven(url = "https://jitpack.io/")
- maven(url = "https://maven.minecraftforge.net/")
- maven(url = "https://repo.spongepowered.org/maven/")
- }
- resolutionStrategy {
- eachPlugin {
- when (requested.id.id) {
- "net.minecraftforge.gradle.forge" -> useModule("com.github.asbyth:ForgeGradle:${requested.version}")
- "org.spongepowered.mixin" -> useModule("com.github.LxGaming:MixinGradle:${requested.version}")
- }
- }
- }
+ repositories {
+ mavenCentral()
+ gradlePluginPortal()
+ maven("https://oss.sonatype.org/content/repositories/snapshots")
+ maven("https://maven.architectury.dev/")
+ maven("https://maven.fabricmc.net")
+ maven(url = "https://jitpack.io/")
+ maven(url = "https://maven.minecraftforge.net/")
+ maven(url = "https://repo.spongepowered.org/maven/")
+ maven(url = "https://repo.sk1er.club/repository/maven-releases/")
+ maven(url = "https://maven.architectury.dev/")
+ }
+ resolutionStrategy {
+ eachPlugin {
+ when (requested.id.id) {
+ "gg.essential.loom" -> useModule("gg.essential:architectury-loom:${requested.version}")
+ }
+ }
+ }
}
diff --git a/src/main/java/NotSkyblockAddonsInstallerFrame.java b/src/main/java/NotSkyblockAddonsInstallerFrame.java
index e6543617..969e6c28 100644
--- a/src/main/java/NotSkyblockAddonsInstallerFrame.java
+++ b/src/main/java/NotSkyblockAddonsInstallerFrame.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
@@ -6,7 +25,13 @@ import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java b/src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java
new file mode 100644
index 00000000..d997d980
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/BuildFlags.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * For storage of compile-time configuration flags
+ */
+public class BuildFlags {
+
+ private static final Properties properties = new Properties();
+
+ static {
+ try {
+ properties.load(BuildFlags.class.getResourceAsStream("/buildflags.properties"));
+ } catch (IOException | NullPointerException e) {
+ System.out.println("Failed to load build properties: " + e);
+ }
+ }
+
+ private static boolean getBuildFlag(String flag) {
+ return Boolean.parseBoolean(properties.getProperty("neu.buildflags." + flag));
+ }
+
+ public static Map<String, Boolean> getAllFlags() {
+ return Holder.ALL_FLAGS;
+ }
+
+ public static final boolean ENABLE_PRONOUNS_IN_PV_BY_DEFAULT = getBuildFlag("pronouns");
+
+ private static class Holder {
+ static Map<String, Boolean> ALL_FLAGS = new HashMap<>();
+
+ static {
+ for (Field declaredField : BuildFlags.class.getDeclaredFields()) {
+ if (Boolean.TYPE.equals(declaredField.getType())
+ && (declaredField.getModifiers() & Modifier.STATIC) != 0) {
+ try {
+ declaredField.setAccessible(true);
+ ALL_FLAGS.put(declaredField.getName(), (Boolean) declaredField.get(null));
+ } catch (IllegalAccessException | ClassCastException | SecurityException e) {
+ System.err.println("Failed to access BuildFlag: " + e);
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java b/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java
index 28686073..3911396f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/CustomItems.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates;
import com.google.gson.JsonArray;
@@ -91,11 +110,11 @@ public class CustomItems {
* SHAAAAAAAAAAAAAAAAAAME
*/
- private static JsonObject create(String internalname, String itemid, String displayname, String... lore) {
+ private static JsonObject create(String internalname, String itemid, String displayName, String... lore) {
JsonObject json = new JsonObject();
json.addProperty("itemid", itemid);
json.addProperty("internalname", internalname);
- json.addProperty("displayname", EnumChatFormatting.RED + displayname);
+ json.addProperty("displayname", EnumChatFormatting.RED + displayName);
JsonArray jsonlore = new JsonArray();
for (String line : lore) {
jsonlore.add(new JsonPrimitive(EnumChatFormatting.GRAY + line));
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java b/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java
index 1804831b..a773abdc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/ItemPriceInformation.java
@@ -1,18 +1,46 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates;
import com.google.gson.Gson;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.auction.APIManager;
import io.github.moulberry.notenoughupdates.core.config.KeybindHelper;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.input.Keyboard;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.HashSet;
import java.util.List;
@@ -23,6 +51,7 @@ public class ItemPriceInformation {
private static File file;
private static HashSet<String> auctionableItems = null;
private static Gson gson;
+ private static final NumberFormat format = new DecimalFormat("#,##0.#", new DecimalFormatSymbols(Locale.US));
public static boolean addToTooltip(List<String> tooltip, String internalname, ItemStack stack) {
return addToTooltip(tooltip, internalname, stack, true);
@@ -75,27 +104,24 @@ public class ItemPriceInformation {
}
JsonObject auctionInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname);
JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalname);
- float lowestBinAvg = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAvgBin(internalname);
+ double lowestBinAvg = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAvgBin(internalname);
- int lowestBin = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname);
+ double lowestBin = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname);
APIManager.CraftInfo craftCost = NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(internalname);
+ boolean bazaarItem = bazaarInfo != null;
- boolean auctionItem = lowestBin > 0 || lowestBinAvg > 0;
+ boolean auctionItem = !bazaarItem;
boolean auctionInfoErrored = auctionInfo == null;
if (auctionItem) {
long currentTime = System.currentTimeMillis();
long lastUpdate = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLastLowestBinUpdateTime();
//check if info is older than 10 minutes
- if (currentTime - lastUpdate > 600 * 1000) {
+ if (currentTime - lastUpdate > 600 * 1000 && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
tooltip.add(EnumChatFormatting.RED + "[NEU] Price info is outdated.");
tooltip.add(EnumChatFormatting.RED + "It will be updated again as soon as possible.");
}
}
- boolean bazaarItem = bazaarInfo != null;
-
- NumberFormat format = NumberFormat.getInstance(Locale.US);
- boolean shortNumber = NotEnoughUpdates.INSTANCE.config.tooltipTweaks.shortNumberFormatPrices;
if (bazaarItem) {
List<Integer> lines = NotEnoughUpdates.INSTANCE.config.tooltipTweaks.priceInfoBaz;
@@ -120,11 +146,8 @@ public class ItemPriceInformation {
tooltip.add(EnumChatFormatting.DARK_GRAY + "[SHIFT show x" + shiftStackMultiplier + "]");
added = true;
}
- int bazaarBuyPrice = (int) bazaarInfo.get("avg_buy").getAsFloat() * stackMultiplier;
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Bazaar Buy: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + (shortNumber && bazaarBuyPrice > 1000
- ? Utils.shortNumberFormat(bazaarBuyPrice, 0)
- : format.format(bazaarBuyPrice)) + " coins");
+ double bazaarBuyPrice = bazaarInfo.get("avg_buy").getAsFloat() * stackMultiplier;
+ tooltip.add(formatPrice("Bazaar Buy: ", bazaarBuyPrice));
}
break;
case 1:
@@ -135,11 +158,8 @@ public class ItemPriceInformation {
tooltip.add(EnumChatFormatting.DARK_GRAY + "[SHIFT show x" + shiftStackMultiplier + "]");
added = true;
}
- int bazaarSellPrice = (int) bazaarInfo.get("avg_sell").getAsFloat() * stackMultiplier;
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Bazaar Sell: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + (shortNumber && bazaarSellPrice > 1000
- ? Utils.shortNumberFormat(bazaarSellPrice, 0)
- : format.format(bazaarSellPrice)) + " coins");
+ double bazaarSellPrice = bazaarInfo.get("avg_sell").getAsDouble() * stackMultiplier;
+ tooltip.add(formatPrice("Bazaar Sell: ", bazaarSellPrice));
}
break;
case 2:
@@ -150,12 +170,8 @@ public class ItemPriceInformation {
tooltip.add(EnumChatFormatting.DARK_GRAY + "[SHIFT show x" + shiftStackMultiplier + "]");
added = true;
}
- int bazaarInstantBuyPrice = (int) bazaarInfo.get("curr_buy").getAsFloat() * stackMultiplier;
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Bazaar Insta-Buy: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + (shortNumber && bazaarInstantBuyPrice > 1000
- ? Utils.shortNumberFormat(bazaarInstantBuyPrice, 0)
- : format.format(bazaarInstantBuyPrice)) +
- " coins");
+ double bazaarInstantBuyPrice = bazaarInfo.get("curr_buy").getAsFloat() * stackMultiplier;
+ tooltip.add(formatPrice("Bazaar Insta-Buy: ", bazaarInstantBuyPrice));
}
break;
case 3:
@@ -166,32 +182,22 @@ public class ItemPriceInformation {
tooltip.add(EnumChatFormatting.DARK_GRAY + "[SHIFT show x" + shiftStackMultiplier + "]");
added = true;
}
- int bazaarInstantSellPrice = (int) bazaarInfo.get("curr_sell").getAsFloat() * stackMultiplier;
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Bazaar Insta-Sell: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + (shortNumber && bazaarInstantSellPrice > 1000
- ? Utils.shortNumberFormat(
- bazaarInstantSellPrice,
- 0
- )
- : format.format(bazaarInstantSellPrice)) +
- " coins");
+ double bazaarInstantSellPrice = bazaarInfo.get("curr_sell").getAsFloat() * stackMultiplier;
+ tooltip.add(formatPrice("Bazaar Insta-Sell: ", bazaarInstantSellPrice));
}
break;
case 4:
if (craftCost != null && craftCost.fromRecipe) {
- if ((int) craftCost.craftCost == 0) {
+ if (craftCost.craftCost == 0) {
continue;
}
if (!added) {
tooltip.add("");
added = true;
}
- float cost = craftCost.craftCost;
+ double cost = craftCost.craftCost;
if (shiftPressed) cost = cost * shiftStackMultiplier;
-
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Raw Craft Cost: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD +
- (shortNumber && cost > 1000 ? Utils.shortNumberFormat(cost, 0) : format.format((int) cost)) + " coins");
+ tooltip.add(formatPrice("Raw Craft Cost: ", cost));
}
break;
}
@@ -211,8 +217,7 @@ public class ItemPriceInformation {
tooltip.add("");
added = true;
}
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Lowest BIN: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + format.format(lowestBin) + " coins");
+ tooltip.add(formatPrice("Lowest BIN: ", lowestBin));
}
break;
case 1:
@@ -223,21 +228,11 @@ public class ItemPriceInformation {
}
if (auctionInfo.has("clean_price")) {
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "AH Price (Clean): " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD +
- (shortNumber && auctionInfo.get("clean_price").getAsFloat() > 1000 ? Utils.shortNumberFormat(
- auctionInfo.get("clean_price").getAsFloat(),
- 0
- ) : format.format((int) auctionInfo.get("clean_price").getAsFloat())
- + " coins"));
+ double cleanPrice = auctionInfo.get("clean_price").getAsDouble();
+ tooltip.add(formatPrice("AH Price (Clean): ", cleanPrice));
} else {
- int auctionPrice =
- (int) (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "AH Price: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD +
- (shortNumber && auctionPrice > 1000
- ? Utils.shortNumberFormat(auctionPrice, 0)
- : format.format(auctionPrice)) + " coins");
+ double auctionPrice = auctionInfo.get("price").getAsDouble() / auctionInfo.get("count").getAsFloat();
+ tooltip.add(formatPrice("AH Price: ", auctionPrice));
}
}
@@ -267,18 +262,14 @@ public class ItemPriceInformation {
break;
case 3:
if (craftCost != null && craftCost.fromRecipe) {
- if ((int) craftCost.craftCost == 0) {
+ if (craftCost.craftCost == 0) {
continue;
}
if (!added) {
tooltip.add("");
added = true;
}
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Raw Craft Cost: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD +
- (shortNumber && craftCost.craftCost > 1000
- ? Utils.shortNumberFormat(craftCost.craftCost, 0)
- : format.format((int) craftCost.craftCost)) + " coins");
+ tooltip.add(formatPrice("Raw Craft Cost: ", craftCost.craftCost));
}
break;
case 4:
@@ -287,11 +278,7 @@ public class ItemPriceInformation {
tooltip.add("");
added = true;
}
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "AVG Lowest BIN: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD +
- (shortNumber && lowestBinAvg > 1000
- ? Utils.shortNumberFormat(lowestBinAvg, 0)
- : format.format(lowestBinAvg)) + " coins");
+ tooltip.add(formatPrice("AVG Lowest BIN: ", lowestBinAvg));
}
break;
case 5:
@@ -302,41 +289,56 @@ public class ItemPriceInformation {
}
JsonObject itemCosts = essenceCosts.get(internalname).getAsJsonObject();
String essenceType = itemCosts.get("type").getAsString();
+ boolean requiresItems = false;
+ JsonObject itemsObject = null;
+ if (itemCosts.has("items")) {
+ requiresItems = true;
+ itemsObject = itemCosts.get("items").getAsJsonObject();
+ }
- int dungeonItemLevel = -1;
- if (stack != null && stack.hasTagCompound() &&
- stack.getTagCompound().hasKey("ExtraAttributes", 10)) {
- NBTTagCompound ea = stack.getTagCompound().getCompoundTag("ExtraAttributes");
+ int dungeonItemLevel = Utils.getNumberOfStars(stack);
- if (ea.hasKey("dungeon_item_level", 99)) {
- dungeonItemLevel = ea.getInteger("dungeon_item_level");
- }
- }
if (dungeonItemLevel == -1) {
int dungeonizeCost = 0;
if (itemCosts.has("dungeonize")) {
dungeonizeCost = itemCosts.get("dungeonize").getAsInt();
}
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Dungeonize Cost: " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + dungeonizeCost + " " + essenceType);
- } else if (dungeonItemLevel >= 0 && dungeonItemLevel <= 4) {
- String costType = (dungeonItemLevel + 1) + "";
- int upgradeCost = itemCosts.get(costType).getAsInt();
- StringBuilder star = new StringBuilder();
- for (int i = 0; i <= dungeonItemLevel; i++) {
- star.append('\u272A');
+ if (dungeonizeCost > 0) {
+ tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Dungeonize Cost: " +
+ EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + dungeonizeCost + " " + essenceType);
+ }
+ } else if (dungeonItemLevel >= 0) {
+ String nextStarLevelString = (dungeonItemLevel + 1) + "";
+ int nextStarLevelInt = Integer.parseInt(nextStarLevelString);
+
+ if (itemCosts.has(nextStarLevelString)) {
+ int upgradeCost = itemCosts.get(nextStarLevelString).getAsInt();
+ String starString = Utils.getStarsString(nextStarLevelInt);
+ tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Upgrade to " +
+ starString + EnumChatFormatting.YELLOW + EnumChatFormatting.BOLD + ": " +
+ EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + upgradeCost + " " + essenceType);
+ if (requiresItems && itemsObject.has(nextStarLevelString)) {
+ boolean shouldShow = Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) ||
+ NotEnoughUpdates.INSTANCE.config.tooltipTweaks.alwaysShowRequiredItems;
+
+ if (shouldShow) {
+ tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Required Items:");
+ for (JsonElement item : itemsObject.get(nextStarLevelString).getAsJsonArray()) {
+ tooltip.add(" - " + item.getAsString());
+ }
+ } else {
+ tooltip.add(EnumChatFormatting.DARK_GRAY + "[CTRL to show required items]");
+ }
+ }
}
- tooltip.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Upgrade to " +
- EnumChatFormatting.GOLD + star + EnumChatFormatting.YELLOW + EnumChatFormatting.BOLD + ": " +
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + upgradeCost + " " + essenceType);
}
break;
}
}
return added;
- } else if (auctionInfoErrored) {
+ } else if (auctionInfoErrored && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
String message = EnumChatFormatting.RED.toString() + EnumChatFormatting.BOLD + "[NEU] API is down";
if (auctionableItems != null && !auctionableItems.isEmpty()) {
if (auctionableItems.contains(internalname)) {
@@ -351,4 +353,13 @@ public class ItemPriceInformation {
return false;
}
+
+ private static String formatPrice(String label, double price) {
+ boolean shortNumber = NotEnoughUpdates.INSTANCE.config.tooltipTweaks.shortNumberFormatPrices;
+ String number = (shortNumber && price > 1000
+ ? Utils.shortNumberFormat(price, 0)
+ : price > 5 ? format.format((int) price) : format.format(price));
+ return "§e§l" + label + "§6§l" + number + " coins";
+ }
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUApi.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUApi.java
index d83035d0..6cdeb474 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUApi.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUApi.java
@@ -1,9 +1,27 @@
-package io.github.moulberry.notenoughupdates;
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+package io.github.moulberry.notenoughupdates;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
public class NEUApi {
- static boolean disableInventoryButtons = false;
+ public static boolean disableInventoryButtons = false;
public static void setInventoryButtonsToDisabled() {
disableInventoryButtons = true;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java
deleted file mode 100644
index 84289e34..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUEventListener.java
+++ /dev/null
@@ -1,2842 +0,0 @@
-package io.github.moulberry.notenoughupdates;
-
-import com.google.common.collect.Lists;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import com.mojang.authlib.GameProfile;
-import com.mojang.authlib.minecraft.MinecraftProfileTexture;
-import io.github.moulberry.notenoughupdates.auction.CustomAHGui;
-import io.github.moulberry.notenoughupdates.commands.profile.ViewProfileCommand;
-import io.github.moulberry.notenoughupdates.core.BackgroundBlur;
-import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
-import io.github.moulberry.notenoughupdates.core.util.MiscUtils;
-import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
-import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
-import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks;
-import io.github.moulberry.notenoughupdates.dungeons.DungeonWin;
-import io.github.moulberry.notenoughupdates.miscfeatures.*;
-import io.github.moulberry.notenoughupdates.miscgui.*;
-import io.github.moulberry.notenoughupdates.options.NEUConfig;
-import io.github.moulberry.notenoughupdates.overlays.*;
-import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
-import io.github.moulberry.notenoughupdates.util.*;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.*;
-import net.minecraft.client.gui.inventory.GuiChest;
-import net.minecraft.client.gui.inventory.GuiContainer;
-import net.minecraft.client.gui.inventory.GuiEditSign;
-import net.minecraft.client.gui.inventory.GuiInventory;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.event.ClickEvent;
-import net.minecraft.init.Items;
-import net.minecraft.inventory.ContainerChest;
-import net.minecraft.inventory.IInventory;
-import net.minecraft.inventory.Slot;
-import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.NBTTagCompound;
-import net.minecraft.nbt.NBTTagList;
-import net.minecraft.nbt.NBTUtil;
-import net.minecraft.util.*;
-import net.minecraftforge.client.ClientCommandHandler;
-import net.minecraftforge.client.event.*;
-import net.minecraftforge.event.entity.player.ItemTooltipEvent;
-import net.minecraftforge.event.world.WorldEvent;
-import net.minecraftforge.fml.common.Loader;
-import net.minecraftforge.fml.common.eventhandler.EventPriority;
-import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import net.minecraftforge.fml.common.gameevent.TickEvent;
-import org.apache.commons.lang3.text.WordUtils;
-import org.lwjgl.input.Keyboard;
-import org.lwjgl.input.Mouse;
-import org.lwjgl.opengl.GL11;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.datatransfer.StringSelection;
-import java.io.File;
-import java.io.IOException;
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.util.List;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import static io.github.moulberry.notenoughupdates.overlays.SlayerOverlay.*;
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.dungeon_chest_worth;
-
-public class NEUEventListener {
-
- private final NotEnoughUpdates neu;
-
- private boolean hoverInv = false;
- private boolean focusInv = false;
-
- private boolean joinedSB = false;
-
- public NEUEventListener(NotEnoughUpdates neu) {
- this.neu = neu;
- }
-
- private void displayUpdateMessageIfOutOfDate() {
- File repo = neu.manager.repoLocation;
- if (repo.exists()) {
- File updateJson = new File(repo, "update.json");
- try {
- JsonObject o = neu.manager.getJsonFromFile(updateJson);
-
- String version = o.get("version").getAsString();
- String preVersion = o.get("pre_version").getAsString();
-
- boolean shouldUpdate = !NotEnoughUpdates.VERSION.equalsIgnoreCase(version);
- boolean shouldPreUpdate = !NotEnoughUpdates.PRE_VERSION.equalsIgnoreCase(preVersion);
-
- if (o.has("version_id") && o.get("version_id").isJsonPrimitive()) {
- int version_id = o.get("version_id").getAsInt();
- shouldUpdate = version_id > NotEnoughUpdates.VERSION_ID;
- }
- if (o.has("pre_version_id") && o.get("pre_version_id").isJsonPrimitive()) {
- int pre_version_id = o.get("pre_version_id").getAsInt();
- shouldPreUpdate = pre_version_id > NotEnoughUpdates.PRE_VERSION_ID;
- }
-
- if (shouldUpdate) {
- String update_msg = o.get("update_msg").getAsString();
-
- int first_len = -1;
- for (String line : update_msg.split("\n")) {
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
- int len = fr.getStringWidth(line);
- if (first_len == -1) {
- first_len = len;
- }
- int missing_len = first_len - len;
- if (missing_len > 0) {
- StringBuilder sb = new StringBuilder(line);
- for (int i = 0; i < missing_len / 8; i++) {
- sb.insert(0, " ");
- }
- line = sb.toString();
- }
- line = line.replaceAll("\\{version}", version);
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(line));
- }
-
- neu.displayLinks(o);
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- } else if (shouldPreUpdate && NotEnoughUpdates.VERSION_ID == o.get("version").getAsInt()) {
- String pre_update_msg = o.get("pre_update_msg").getAsString();
-
- int first_len = -1;
- for (String line : pre_update_msg.split("\n")) {
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
- int len = fr.getStringWidth(line);
- if (first_len == -1) {
- first_len = len;
- }
- int missing_len = first_len - len;
- if (missing_len > 0) {
- StringBuilder sb = new StringBuilder(line);
- for (int i = 0; i < missing_len / 8; i++) {
- sb.insert(0, " ");
- }
- line = sb.toString();
- }
- line = line.replaceAll("\\{pre_version}", preVersion);
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(line));
- }
-
- neu.displayLinks(o);
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- }
- } catch (Exception ignored) {
- }
- }
- }
-
- @SubscribeEvent
- public void onWorldLoad(WorldEvent.Unload event) {
- NotEnoughUpdates.INSTANCE.saveConfig();
- CrystalMetalDetectorSolver.reset(false);
- }
-
- private static long notificationDisplayMillis = 0;
- private static List<String> notificationLines = null;
- private static boolean showNotificationOverInv = false;
-
- private static final Pattern BAD_ITEM_REGEX = Pattern.compile("x[0-9]{1,2}$");
- private static final Pattern SLAYER_XP =
- Pattern.compile(" (Spider|Zombie|Wolf|Enderman) Slayer LVL (\\d) - (?:Next LVL in ([\\d,]+) XP!|LVL MAXED OUT!)");
-
- /**
- * 1)Will send the cached message from #sendChatMessage when at least 200ms has passed since the last message.
- * This is used in order to prevent the mod spamming messages.
- * 2)Adds unique items to the collection log
- */
- private boolean preloadedItems = false;
- private long lastLongUpdate = 0;
- private long lastSkyblockScoreboard = 0;
-
- private final ExecutorService itemPreloader = Executors.newFixedThreadPool(10);
- private final List<ItemStack> toPreload = new ArrayList<>();
-
- private int inventoryLoadedTicks = 0;
- private String loadedInvName = "";
- public static boolean inventoryLoaded = false;
-
- public static void displayNotification(List<String> lines, boolean showForever) {
- displayNotification(lines, showForever, false);
- }
-
- public static void displayNotification(List<String> lines, boolean showForever, boolean overInventory) {
- if (showForever) {
- notificationDisplayMillis = -420;
- } else {
- notificationDisplayMillis = System.currentTimeMillis();
- }
- notificationLines = lines;
- showNotificationOverInv = overInventory;
- }
-
- @SubscribeEvent
- public void onTick(TickEvent.ClientTickEvent event) {
- Keyboard.enableRepeatEvents(
- Minecraft.getMinecraft().currentScreen != null && (Minecraft.getMinecraft().currentScreen instanceof GuiChat
- || Minecraft.getMinecraft().currentScreen instanceof GuiEditSign ||
- Minecraft.getMinecraft().currentScreen instanceof GuiScreenBook));
- if (event.phase != TickEvent.Phase.START) return;
- if (Minecraft.getMinecraft().theWorld == null) return;
- if (Minecraft.getMinecraft().thePlayer == null) return;
-
- if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest cc = (ContainerChest) chest.inventorySlots;
-
- if (!loadedInvName.equals(cc.getLowerChestInventory().getDisplayName().getUnformattedText())) {
- loadedInvName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
- inventoryLoaded = false;
- inventoryLoadedTicks = 3;
- }
-
- if (!inventoryLoaded) {
- if (cc.getLowerChestInventory().getStackInSlot(cc.getLowerChestInventory().getSizeInventory() - 1) != null) {
- inventoryLoaded = true;
- } else {
- for (ItemStack stack : chest.inventorySlots.getInventory()) {
- if (stack != null) {
- if (--inventoryLoadedTicks <= 0) {
- inventoryLoaded = true;
- }
- break;
- }
- }
- }
- }
- } else {
- inventoryLoaded = false;
- inventoryLoadedTicks = 3;
- }
-
- if ((Keyboard.isKeyDown(Keyboard.KEY_NUMPAD1) && Keyboard.isKeyDown(Keyboard.KEY_NUMPAD4) &&
- Keyboard.isKeyDown(Keyboard.KEY_NUMPAD9))) {
- ChatComponentText component = new ChatComponentText("\u00a7cYou are permanently banned from this server!");
- component.appendText("\n");
- component.appendText("\n\u00a77Reason: \u00a7rSuspicious account activity/Other");
- component.appendText("\n\u00a77Find out more: \u00a7b\u00a7nhttps://www.hypixel.net/appeal");
- component.appendText("\n");
- component.appendText("\n\u00a77Ban ID: \u00a7r#49871982");
- component.appendText("\n\u00a77Sharing your Ban ID may affect the processing of your appeal!");
- Minecraft.getMinecraft().getNetHandler().getNetworkManager().closeChannel(component);
- return;
- }
-
- if (neu.hasSkyblockScoreboard()) {
- if (!preloadedItems) {
- preloadedItems = true;
- List<JsonObject> list = new ArrayList<>(neu.manager.getItemInformation().values());
- for (JsonObject json : list) {
- itemPreloader.submit(() -> {
- ItemStack stack = neu.manager.jsonToStack(json, true, true);
- if (stack.getItem() == Items.skull) toPreload.add(stack);
- });
- }
- } else if (!toPreload.isEmpty()) {
- Utils.drawItemStack(toPreload.get(0), -100, -100);
- toPreload.remove(0);
- } else {
- itemPreloader.shutdown();
- }
-
- for (TextOverlay overlay : OverlayManager.textOverlays) {
- overlay.shouldUpdateFrequent = true;
- }
- }
-
- boolean longUpdate = false;
- long currentTime = System.currentTimeMillis();
- if (currentTime - lastLongUpdate > 1000) {
- longUpdate = true;
- lastLongUpdate = currentTime;
- }
- if (!NotEnoughUpdates.INSTANCE.config.dungeons.slowDungeonBlocks) {
- DungeonBlocks.tick();
- }
- DungeonWin.tick();
-
- String containerName = null;
- if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
-
- if (GuiCustomEnchant.getInstance().shouldOverride(containerName)) {
- GuiCustomEnchant.getInstance().tick();
- }
- }
-
- if (longUpdate) {
- CrystalOverlay.tick();
- FairySouls.tick();
- XPInformation.getInstance().tick();
- ProfileApiSyncer.getInstance().tick();
- ItemCustomizeManager.tick();
- BackgroundBlur.markDirty();
- NPCRetexturing.getInstance().tick();
- StorageOverlay.getInstance().markDirty();
-
- if (neu.hasSkyblockScoreboard()) {
- for (TextOverlay overlay : OverlayManager.textOverlays) {
- overlay.tick();
- }
- }
-
- NotEnoughUpdates.INSTANCE.overlay.redrawItems();
- CapeManager.onTickSlow();
-
- NotEnoughUpdates.profileViewer.putNameUuid(
- Minecraft.getMinecraft().thePlayer.getName(),
- Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "")
- );
-
- if (NotEnoughUpdates.INSTANCE.config.dungeons.slowDungeonBlocks) {
- DungeonBlocks.tick();
- }
-
- if (System.currentTimeMillis() - SBInfo.getInstance().joinedWorld > 500 &&
- System.currentTimeMillis() - SBInfo.getInstance().unloadedWorld > 500) {
- neu.updateSkyblockScoreboard();
- }
- CapeManager.getInstance().tick();
-
- if (containerName != null) {
- if (!containerName.trim().startsWith("Accessory Bag")) {
- AccessoryBagOverlay.resetCache();
- }
- } else {
- AccessoryBagOverlay.resetCache();
- }
-
- if (neu.hasSkyblockScoreboard()) {
- SBInfo.getInstance().tick();
- lastSkyblockScoreboard = currentTime;
- if (!joinedSB) {
- joinedSB = true;
-
- //SBGamemodes.loadFromFile();
-
- if (NotEnoughUpdates.INSTANCE.config.notifications.showUpdateMsg) {
- displayUpdateMessageIfOutOfDate();
- }
-
- if (NotEnoughUpdates.INSTANCE.config.notifications.doRamNotif) {
- long maxMemoryMB = Runtime.getRuntime().maxMemory() / 1024L / 1024L;
- if (maxMemoryMB > 4100) {
- notificationDisplayMillis = System.currentTimeMillis();
- notificationLines = new ArrayList<>();
- notificationLines.add(EnumChatFormatting.GRAY + "Too much memory allocated!");
- notificationLines.add(String.format(
- EnumChatFormatting.DARK_GRAY + "NEU has detected %03dMB of memory allocated to Minecraft!",
- maxMemoryMB
- ));
- notificationLines.add(EnumChatFormatting.GRAY + "It is recommended to allocated between 2-4GB of memory");
- notificationLines.add(
- EnumChatFormatting.GRAY + "More than 4GB MAY cause FPS issues, EVEN if you have 16GB+ available");
- notificationLines.add("");
- notificationLines.add(
- EnumChatFormatting.GRAY + "For more information, visit #ram-info in discord.gg/moulberry");
- }
- }
-
- if (!NotEnoughUpdates.INSTANCE.config.hidden.loadedModBefore) {
- NotEnoughUpdates.INSTANCE.config.hidden.loadedModBefore = true;
- if (Constants.MISC == null || !Constants.MISC.has("featureslist")) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- "" + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + "WARNING: " + EnumChatFormatting.RESET +
- EnumChatFormatting.RED + "Could not load Feature List URL from repo."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- "" + EnumChatFormatting.RED + "Please run " + EnumChatFormatting.BOLD + "/neuresetrepo" +
- EnumChatFormatting.RESET + EnumChatFormatting.RED + " and " + EnumChatFormatting.BOLD +
- "restart your game" + EnumChatFormatting.RESET + EnumChatFormatting.RED + " in order to fix. " +
- EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + "If that doesn't fix it" +
- EnumChatFormatting.RESET + EnumChatFormatting.RED +
- ", please join discord.gg/moulberry and post in #neu-support"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- "" + EnumChatFormatting.GOLD + "To view the feature list after restarting type /neufeatures"));
- } else {
- String url = Constants.MISC.get("featureslist").getAsString();
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.BLUE + "It seems this is your first time using NotEnoughUpdates."));
- ChatComponentText clickTextFeatures = new ChatComponentText(
- EnumChatFormatting.YELLOW +
- "Click this message if you would like to view a list of NotEnoughUpdate's Features.");
- clickTextFeatures.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, url));
- Minecraft.getMinecraft().thePlayer.addChatMessage(clickTextFeatures);
- }
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- ChatComponentText clickTextHelp = new ChatComponentText(
- EnumChatFormatting.YELLOW +
- "Click this message if you would like to view a list of NotEnoughUpdate's commands.");
- clickTextHelp.setChatStyle(Utils.createClickStyle(ClickEvent.Action.RUN_COMMAND, "/neuhelp"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(clickTextHelp);
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- }
- }
- }
- if (currentTime - lastSkyblockScoreboard < 5 * 60 * 1000) { //5 minutes
- neu.manager.auctionManager.tick();
- } else {
- neu.manager.auctionManager.markNeedsUpdate();
- }
- }
-
- /*if(longUpdate && neu.hasSkyblockScoreboard()) {
- if(neu.manager.getCurrentProfile() == null || neu.manager.getCurrentProfile().length() == 0) {
- ProfileViewer.Profile profile = NotEnoughUpdates.profileViewer.getProfile(Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""),
- callback->{});
- if(profile != null) {
- String latest = profile.getLatestProfile();
- if(latest != null) {
- neu.manager.setCurrentProfileBackup(profile.getLatestProfile());
- }
- }
- }*/
- /*if(neu.manager.getCurrentProfile() != null && neu.manager.getCurrentProfile().length() > 0) {
- HashSet<String> newItem = new HashSet<>();
- if(Minecraft.getMinecraft().currentScreen instanceof GuiContainer &&
- !(Minecraft.getMinecraft().currentScreen instanceof GuiCrafting)) {
- boolean usableContainer = true;
- for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) {
- if(stack == null) {
- continue;
- }
- if(stack.hasTagCompound()) {
- NBTTagCompound tag = stack.getTagCompound();
- if(tag.hasKey("ExtraAttributes", 10)) {
- continue;
- }
- }
- usableContainer = false;
- break;
- }
- if(!usableContainer) {
- if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
-
- if(containerName.equals("Accessory Bag") || containerName.startsWith("Wardrobe")) {
- usableContainer = true;
- }
- }
- }
- if(usableContainer) {
- for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) {
- processUniqueStack(stack, newItem);
- }
- for(ItemStack stack : Minecraft.getMinecraft().thePlayer.openContainer.getInventory()) {
- processUniqueStack(stack, newItem);
- }
- }
- } else {
- for(ItemStack stack : Minecraft.getMinecraft().thePlayer.inventory.mainInventory) {
- processUniqueStack(stack, newItem);
- }
- }
- newItemAddMap.keySet().retainAll(newItem);
- }
- }*/
- }
-
- /*private void processUniqueStack(ItemStack stack, HashSet<String> newItem) {
- if(stack != null && stack.hasTagCompound()) {
- String internalname = neu.manager.getInternalNameForItem(stack);
- if(internalname != null) {
- /*ArrayList<String> log = neu.manager.config.collectionLog.value.computeIfAbsent(
- neu.manager.getCurrentProfile(), k -> new ArrayList<>());
- if(!log.contains(internalname)) {
- newItem.add(internalname);
- if(newItemAddMap.containsKey(internalname)) {
- if(System.currentTimeMillis() - newItemAddMap.get(internalname) > 1000) {
- log.add(internalname);
- try { neu.manager.saveConfig(); } catch(IOException ignored) {}
- }
- } else {
- newItemAddMap.put(internalname, System.currentTimeMillis());
- }
- }
- }
- }
- }*/
-
- @SubscribeEvent(priority = EventPriority.HIGHEST)
- public void onRenderEntitySpecials(RenderLivingEvent.Specials.Pre<EntityPlayer> event) {
- if (Minecraft.getMinecraft().currentScreen instanceof GuiProfileViewer) {
- if (((GuiProfileViewer) Minecraft.getMinecraft().currentScreen).getEntityPlayer() == event.entity) {
- event.setCanceled(true);
- }
- }
- }
-
- @SubscribeEvent
- public void onRenderGameOverlayPre(RenderGameOverlayEvent.Pre event) {
- if (event.type != null && event.type.equals(RenderGameOverlayEvent.ElementType.BOSSHEALTH) &&
- Minecraft.getMinecraft().currentScreen instanceof GuiContainer && neu.overlay.isUsingMobsFilter()) {
- event.setCanceled(true);
- }
- if (event.type != null && event.type.equals(RenderGameOverlayEvent.ElementType.PLAYER_LIST)) {
- GlStateManager.enableDepth();
- }
- }
-
- @SubscribeEvent
- public void onRenderGameOverlayPost(RenderGameOverlayEvent.Post event) {
- if (neu.hasSkyblockScoreboard() && event.type.equals(RenderGameOverlayEvent.ElementType.ALL)) {
- DungeonWin.render(event.partialTicks);
- GlStateManager.pushMatrix();
- GlStateManager.translate(0, 0, -200);
- for (TextOverlay overlay : OverlayManager.textOverlays) {
- if (OverlayManager.dontRenderOverlay != null &&
- OverlayManager.dontRenderOverlay.isAssignableFrom(overlay.getClass())) {
- continue;
- }
- GlStateManager.translate(0, 0, -1);
- GlStateManager.enableDepth();
- overlay.render();
- }
- GlStateManager.popMatrix();
- OverlayManager.dontRenderOverlay = null;
- }
- if (Keyboard.isKeyDown(Keyboard.KEY_X)) {
- notificationDisplayMillis = 0;
- }
-
- if (event.type == RenderGameOverlayEvent.ElementType.ALL) {
- renderNotification();
- }
-
- }
-
- private static void renderNotification() {
-
- long timeRemaining = 15000 - (System.currentTimeMillis() - notificationDisplayMillis);
- boolean display = timeRemaining > 0 || notificationDisplayMillis == -420;
- if (display && notificationLines != null && notificationLines.size() > 0) {
- int width = 0;
- int height = notificationLines.size() * 10 + 10;
-
- for (String line : notificationLines) {
- int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line) + 8;
- if (len > width) {
- width = len;
- }
- }
-
- ScaledResolution sr = Utils.pushGuiScale(2);
-
- int midX = sr.getScaledWidth() / 2;
- int topY = sr.getScaledHeight() * 3 / 4 - height / 2;
- RenderUtils.drawFloatingRectDark(midX - width / 2, sr.getScaledHeight() * 3 / 4 - height / 2, width, height);
- /*Gui.drawRect(midX-width/2, sr.getScaledHeight()*3/4-height/2,
- midX+width/2, sr.getScaledHeight()*3/4+height/2, 0xFF3C3C3C);
- Gui.drawRect(midX-width/2+2, sr.getScaledHeight()*3/4-height/2+2,
- midX+width/2-2, sr.getScaledHeight()*3/4+height/2-2, 0xFFC8C8C8);*/
-
- int xLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth("[X] Close");
- Minecraft.getMinecraft().fontRendererObj.drawString("[X] Close", midX + width / 2f - 3 - xLen,
- topY + 3, 0xFFFF5555, false
- );
-
- if (notificationDisplayMillis > 0) {
- Minecraft.getMinecraft().fontRendererObj.drawString((timeRemaining / 1000) + "s", midX - width / 2f + 3,
- topY + 3, 0xFFaaaaaa, false
- );
- }
-
- Utils.drawStringCentered(notificationLines.get(0), Minecraft.getMinecraft().fontRendererObj,
- midX, topY + 4 + 5, false, -1
- );
- for (int i = 1; i < notificationLines.size(); i++) {
- String line = notificationLines.get(i);
- Utils.drawStringCentered(line, Minecraft.getMinecraft().fontRendererObj,
- midX, topY + 4 + 5 + 2 + i * 10, false, -1
- );
- }
-
- Utils.pushGuiScale(-1);
- }
- }
-
- public static long lastGuiClosed = 0;
-
- /**
- * When opening a GuiContainer, will reset the overlay and load the config.
- * When closing a GuiContainer, will save the config.
- * Also includes a dev feature used for automatically acquiring crafting information from the "Crafting Table" GUI.
- */
- AtomicBoolean missingRecipe = new AtomicBoolean(false);
-
- @SubscribeEvent
- public void onGuiOpen(GuiOpenEvent event) {
- NEUApi.disableInventoryButtons = false;
-
- if ((Minecraft.getMinecraft().currentScreen instanceof GuiScreenElementWrapper ||
- Minecraft.getMinecraft().currentScreen instanceof GuiItemRecipe) &&
- event.gui == null && !(Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) &&
- System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.lastOpenedGui < 500) {
- NotEnoughUpdates.INSTANCE.lastOpenedGui = 0;
- event.setCanceled(true);
- return;
- }
-
- if (!(event.gui instanceof GuiContainer) && Minecraft.getMinecraft().currentScreen != null) {
- CalendarOverlay.setEnabled(false);
- }
-
- if (Minecraft.getMinecraft().currentScreen != null) {
- lastGuiClosed = System.currentTimeMillis();
- }
-
- neu.manager.auctionManager.customAH.lastGuiScreenSwitch = System.currentTimeMillis();
- BetterContainers.reset();
- inventoryLoaded = false;
- inventoryLoadedTicks = 3;
-
- if (event.gui == null && neu.manager.auctionManager.customAH.isRenderOverAuctionView() &&
- !(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)) {
- event.gui = new CustomAHGui();
- }
-
- if (!(event.gui instanceof GuiChest || event.gui instanceof GuiEditSign)) {
- neu.manager.auctionManager.customAH.setRenderOverAuctionView(false);
- } else if (event.gui instanceof GuiChest && (neu.manager.auctionManager.customAH.isRenderOverAuctionView() ||
- Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)) {
- GuiChest chest = (GuiChest) event.gui;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
-
- neu.manager.auctionManager.customAH.setRenderOverAuctionView(containerName.trim().equals("Auction View") ||
- containerName.trim().equals("BIN Auction View") || containerName.trim().equals("Confirm Bid") ||
- containerName.trim().equals("Confirm Purchase"));
- }
-
- //OPEN
- if (Minecraft.getMinecraft().currentScreen == null
- && event.gui instanceof GuiContainer) {
- neu.overlay.reset();
- }
- if (event.gui != null && NotEnoughUpdates.INSTANCE.config.hidden.dev) {
- if (event.gui instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) event.gui;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- IInventory lower = cc.getLowerChestInventory();
- ses.schedule(() -> {
- if (Minecraft.getMinecraft().currentScreen != event.gui) {
- return;
- }
- if (lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) {
- try {
- ItemStack res = lower.getStackInSlot(25);
- String resInternalname = neu.manager.getInternalNameForItem(res);
-
- if (lower.getStackInSlot(48) != null) {
- String backName = null;
- NBTTagCompound tag = lower.getStackInSlot(48).getTagCompound();
- if (tag.hasKey("display", 10)) {
- NBTTagCompound nbttagcompound = tag.getCompoundTag("display");
- if (nbttagcompound.getTagId("Lore") == 9) {
- NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore", 8);
- backName = nbttaglist1.getStringTagAt(0);
- }
- }
-
- if (backName != null) {
- String[] split = backName.split(" ");
- if (split[split.length - 1].contains("Rewards")) {
- String col = backName.substring(
- split[0].length() + 1,
- backName.length() - split[split.length - 1].length() - 1
- );
-
- JsonObject json = neu.manager.getItemInformation().get(resInternalname);
- json.addProperty("crafttext", "Requires: " + col);
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- "Added: " + resInternalname));
- neu.manager.writeJsonDefaultDir(json, resInternalname + ".json");
- neu.manager.loadItem(resInternalname);
- }
- }
- }
-
- /*JsonArray arr = null;
- File f = new File(neu.manager.configLocation, "missing.json");
- try(InputStream instream = new FileInputStream(f)) {
- BufferedReader reader = new BufferedReader(new InputStreamReader(instream, StandardCharsets.UTF_8));
- JsonObject json = neu.manager.gson.fromJson(reader, JsonObject.class);
- arr = json.getAsJsonArray("missing");
- } catch(IOException e) {}
- try {
- JsonObject json = new JsonObject();
- JsonArray newArr = new JsonArray();
- for(JsonElement e : arr) {
- if(!e.getAsString().equals(resInternalname)) {
- newArr.add(e);
- }
- }
- json.add("missing", newArr);
- neu.manager.writeJson(json, f);
- } catch(IOException e) {}*/
-
-
-
- /*JsonObject recipe = new JsonObject();
-
- String[] x = {"1","2","3"};
- String[] y = {"A","B","C"};
-
- for(int i=0; i<=18; i+=9) {
- for(int j=0; j<3; j++) {
- ItemStack stack = lower.getStackInSlot(10+i+j);
- String internalname = "";
- if(stack != null) {
- internalname = neu.manager.getInternalNameForItem(stack);
- if(!neu.manager.getItemInformation().containsKey(internalname)) {
- neu.manager.writeItemToFile(stack);
- }
- internalname += ":"+stack.stackSize;
- }
- recipe.addProperty(y[i/9]+x[j], internalname);
- }
- }
-
- JsonObject json = neu.manager.getJsonForItem(res);
- json.add("recipe", recipe);
- json.addProperty("internalname", resInternalname);
- json.addProperty("clickcommand", "viewrecipe");
- json.addProperty("modver", NotEnoughUpdates.VERSION);
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname));
- neu.manager.writeJsonDefaultDir(json, resInternalname+".json");
- neu.manager.loadItem(resInternalname);*/
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }, 200, TimeUnit.MILLISECONDS);
- }
- }
- }
-
- /*@SubscribeEvent
- public void onPlayerInteract(EntityInteractEvent event) {
- if(!event.isCanceled() && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() &&
- Minecraft.getMinecraft().thePlayer.isSneaking() &&
- Minecraft.getMinecraft().ingameGUI != null) {
- if(event.target instanceof EntityPlayer) {
- for(NetworkPlayerInfo info : Minecraft.getMinecraft().thePlayer.sendQueue.getPlayerInfoMap()) {
- String name = Minecraft.getMinecraft().ingameGUI.getTabList().getPlayerName(info);
- if(name.contains("Status: "+EnumChatFormatting.RESET+EnumChatFormatting.BLUE+"Guest")) {
- NotEnoughUpdates.INSTANCE.sendChatMessage("/trade " + event.target.getName());
- event.setCanceled(true);
- break;
- }
- }
- }
- }
- }*/
-
- private IChatComponent processChatComponent(IChatComponent chatComponent) {
- IChatComponent newComponent;
- if (chatComponent instanceof ChatComponentText) {
- ChatComponentText text = (ChatComponentText) chatComponent;
-
- newComponent = new ChatComponentText(processText(text.getUnformattedTextForChat()));
- newComponent.setChatStyle(text.getChatStyle().createShallowCopy());
-
- for (IChatComponent sibling : text.getSiblings()) {
- newComponent.appendSibling(processChatComponent(sibling));
- }
- } else if (chatComponent instanceof ChatComponentTranslation) {
- ChatComponentTranslation trans = (ChatComponentTranslation) chatComponent;
-
- Object[] args = trans.getFormatArgs();
- Object[] newArgs = new Object[args.length];
- for (int i = 0; i < trans.getFormatArgs().length; i++) {
- if (args[i] instanceof IChatComponent) {
- newArgs[i] = processChatComponent((IChatComponent) args[i]);
- } else {
- newArgs[i] = args[i];
- }
- }
- newComponent = new ChatComponentTranslation(trans.getKey(), newArgs);
-
- for (IChatComponent sibling : trans.getSiblings()) {
- newComponent.appendSibling(processChatComponent(sibling));
- }
- } else {
- newComponent = chatComponent.createCopy();
- }
-
- return newComponent;
- }
-
- private String processText(String text) {
- if (SBInfo.getInstance().getLocation() == null) return text;
- if (!SBInfo.getInstance().getLocation().startsWith("mining_") &&
- !SBInfo.getInstance().getLocation().equals("crystal_hollows"))
- return text;
-
- if (Minecraft.getMinecraft().thePlayer == null) return text;
- if (!NotEnoughUpdates.INSTANCE.config.mining.drillFuelBar) return text;
-
- return Utils.trimIgnoreColour(text.replaceAll(EnumChatFormatting.DARK_GREEN + "\\S+ Drill Fuel", ""));
- }
-
- private IChatComponent replaceSocialControlsWithPV(IChatComponent chatComponent) {
-
- if (NotEnoughUpdates.INSTANCE.config.misc.replaceSocialOptions1 > 0 && chatComponent.getChatStyle() != null &&
- chatComponent.getChatStyle().getChatClickEvent() != null &&
- chatComponent.getChatStyle().getChatClickEvent().getAction() == ClickEvent.Action.RUN_COMMAND &&
- NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
- if (chatComponent.getChatStyle().getChatClickEvent().getValue().startsWith("/socialoptions")) {
- String username = chatComponent.getChatStyle().getChatClickEvent().getValue().substring(15);
- if (NotEnoughUpdates.INSTANCE.config.misc.replaceSocialOptions1 == 1) {
- chatComponent.setChatStyle(Utils.createClickStyle(
- ClickEvent.Action.RUN_COMMAND,
- "/pv " + username,
- "" + EnumChatFormatting.YELLOW + "Click to open " + EnumChatFormatting.AQUA + EnumChatFormatting.BOLD +
- username + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + "'s profile in " +
- EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.BOLD + "NEU's" + EnumChatFormatting.RESET +
- EnumChatFormatting.YELLOW + " profile viewer."
- ));
- return chatComponent;
- } else if (NotEnoughUpdates.INSTANCE.config.misc.replaceSocialOptions1 == 2) {
- chatComponent.setChatStyle(Utils.createClickStyle(
- ClickEvent.Action.RUN_COMMAND,
- "/ah " + username,
- "" + EnumChatFormatting.YELLOW + "Click to open " + EnumChatFormatting.AQUA + EnumChatFormatting.BOLD +
- username + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + "'s /ah page"
- ));
- return chatComponent;
- }
- } // wanted to add this for guild but guild uses uuid :sad:
- }
- return chatComponent;
- }
-
- /**
- * 1) When receiving "You are playing on profile" messages, will set the current profile.
- * 2) When a /viewrecipe command fails (i.e. player does not have recipe unlocked, will open the custom recipe GUI)
- * 3) Replaces lobby join notifications when streamer mode is active
- */
- @SubscribeEvent(priority = EventPriority.LOW, receiveCanceled = true)
- public void onGuiChat(ClientChatReceivedEvent e) {
- if (e.type == 2) {
- CrystalMetalDetectorSolver.process(e.message);
- e.message = processChatComponent(e.message);
- return;
- } else if (e.type == 0) {
- e.message = replaceSocialControlsWithPV(e.message);
- }
-
- DungeonWin.onChatMessage(e);
-
- String r = null;
- String unformatted = Utils.cleanColour(e.message.getUnformattedText());
- Matcher matcher = SLAYER_XP.matcher(unformatted);
- if (unformatted.startsWith("You are playing on profile: ")) {
- neu.manager.setCurrentProfile(unformatted
- .substring("You are playing on profile: ".length())
- .split(" ")[0].trim());
- } else if (unformatted.startsWith("Your profile was changed to: ")) {//Your profile was changed to:
- neu.manager.setCurrentProfile(unformatted
- .substring("Your profile was changed to: ".length())
- .split(" ")[0].trim());
- } else if (unformatted.startsWith("Your new API key is ")) {
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey = unformatted.substring("Your new API key is ".length());
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
- "[NEU] API Key automatically configured"));
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey = NotEnoughUpdates.INSTANCE.config.apiKey.apiKey.substring(0, 36);
- } else if (unformatted.startsWith("Player List Info is now disabled!")) {
- SBInfo.getInstance().hasNewTab = false;
- } else if (unformatted.startsWith("Player List Info is now enabled!")) {
- SBInfo.getInstance().hasNewTab = true;
- }
- if (e.message.getFormattedText().equals(EnumChatFormatting.RESET.toString() +
- EnumChatFormatting.RED + "You haven't unlocked this recipe!" + EnumChatFormatting.RESET)) {
- r = EnumChatFormatting.RED + "You haven't unlocked this recipe!";
- } else if (e.message.getFormattedText().startsWith(EnumChatFormatting.RESET.toString() +
- EnumChatFormatting.RED + "Invalid recipe ")) {
- r = "";
- } else if (unformatted.equals(" NICE! SLAYER BOSS SLAIN!")) {
- SlayerOverlay.isSlain = true;
- } else if (unformatted.equals(" SLAYER QUEST STARTED!")) {
- SlayerOverlay.isSlain = false;
- if (timeSinceLastBoss == 0) {
- SlayerOverlay.timeSinceLastBoss = System.currentTimeMillis();
- } else {
- timeSinceLastBoss2 = timeSinceLastBoss;
- timeSinceLastBoss = System.currentTimeMillis();
- }
- } else if (unformatted.startsWith(" RNGesus Meter:")) {
- RNGMeter = unformatted.substring(" RNGesus Meter: -------------------- ".length());
- } else if (matcher.matches()) {
- //matcher.group(1);
- SlayerOverlay.slayerLVL = matcher.group(2);
- if (!SlayerOverlay.slayerLVL.equals("9")) {
- SlayerOverlay.slayerXp = matcher.group(3);
- } else {
- slayerXp = "maxed";
- }
- } else if (unformatted.startsWith("Sending to server") ||
- (unformatted.startsWith("Your Slayer Quest has been cancelled!"))) {
- SlayerOverlay.slayerQuest = false;
- SlayerOverlay.unloadOverlayTimer = System.currentTimeMillis();
- }
- if (e.message
- .getFormattedText()
- .contains(EnumChatFormatting.YELLOW + "Visit the Auction House to collect your item!")) {
- if (NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBid != null &&
- System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBidMillis < 5000) {
- NotEnoughUpdates.INSTANCE.sendChatMessage("/viewauction " +
- NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.niceAucId(
- NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBid));
- }
- }
- if (r != null) {
- if (neu.manager.failViewItem(r)) {
- e.setCanceled(true);
- }
- missingRecipe.set(true);
- }
- //System.out.println(e.message);
- if (unformatted.startsWith("Sending to server") &&
- neu.isOnSkyblock() && NotEnoughUpdates.INSTANCE.config.misc.streamerMode &&
- e.message instanceof ChatComponentText) {
- String m = e.message.getFormattedText();
- String m2 = StreamerMode.filterChat(e.message.getFormattedText());
- if (!m.equals(m2)) {
- e.message = new ChatComponentText(m2);
- }
- }
- if (unformatted.startsWith("You found ") && SBInfo.getInstance().getLocation() != null &&
- SBInfo.getInstance().getLocation().equals("crystal_hollows")) {
- CrystalMetalDetectorSolver.reset(true);
- }
- if (unformatted.startsWith("[NPC] Keeper of ") | unformatted.startsWith("[NPC] Professor Robot: ") ||
- unformatted.startsWith(" ") || unformatted.startsWith("✦") ||
- unformatted.equals(" You've earned a Crystal Loot Bundle!"))
- OverlayManager.crystalHollowOverlay.message(unformatted);
- }
-
- public static boolean drawingGuiScreen = false;
-
- /**
- * Sets hoverInv and focusInv variables, representing whether the NEUOverlay should render behind the inventory when
- * (hoverInv == true) and whether mouse/kbd inputs shouldn't be sent to NEUOverlay (focusInv == true).
- * <p>
- * If hoverInv is true, will render the overlay immediately (resulting in the inventory being drawn over the GUI)
- * If hoverInv is false, the overlay will render in #onGuiScreenDraw (resulting in the GUI being drawn over the inv)
- * <p>
- * All of this only matters if players are using gui scale auto which may result in the inventory being drawn
- * over the various panes.
- */
- @SubscribeEvent
- public void onGuiBackgroundDraw(GuiScreenEvent.BackgroundDrawnEvent event) {
- if (showNotificationOverInv) {
-
- renderNotification();
-
- }
- if ((shouldRenderOverlay(event.gui) || event.gui instanceof CustomAHGui) && neu.isOnSkyblock()) {
- ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
- int width = scaledresolution.getScaledWidth();
-
- boolean hoverPane = event.getMouseX() < width * neu.overlay.getInfoPaneOffsetFactor() ||
- event.getMouseX() > width * neu.overlay.getItemPaneOffsetFactor();
-
- if (event.gui instanceof GuiContainer) {
- try {
- int xSize = ((GuiContainer) event.gui).xSize;
- int ySize = ((GuiContainer) event.gui).ySize;
- int guiLeft = ((GuiContainer) event.gui).guiLeft;
- int guiTop = ((GuiContainer) event.gui).guiTop;
-
- hoverInv = event.getMouseX() > guiLeft && event.getMouseX() < guiLeft + xSize &&
- event.getMouseY() > guiTop && event.getMouseY() < guiTop + ySize;
-
- if (hoverPane) {
- if (!hoverInv) focusInv = false;
- } else {
- focusInv = true;
- }
- } catch (NullPointerException npe) {
- focusInv = !hoverPane;
- }
- }
- if (event.gui instanceof GuiItemRecipe) {
- GuiItemRecipe guiItemRecipe = ((GuiItemRecipe) event.gui);
- hoverInv = event.getMouseX() > guiItemRecipe.guiLeft &&
- event.getMouseX() < guiItemRecipe.guiLeft + guiItemRecipe.xSize &&
- event.getMouseY() > guiItemRecipe.guiTop && event.getMouseY() < guiItemRecipe.guiTop + guiItemRecipe.ySize;
-
- if (hoverPane) {
- if (!hoverInv) focusInv = false;
- } else {
- focusInv = true;
- }
- }
- if (focusInv) {
- try {
- neu.overlay.render(hoverInv);
- } catch (ConcurrentModificationException e) {
- e.printStackTrace();
- }
- GL11.glTranslatef(0, 0, 10);
- }
- if (hoverInv) {
- renderDungeonChestOverlay(event.gui);
- if (NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay) {
- AccessoryBagOverlay.renderOverlay();
- }
- }
- }
-
- drawingGuiScreen = true;
- }
-
- private boolean doInventoryButtons = false;
-
- @SubscribeEvent
- public void onGuiScreenDrawPre(GuiScreenEvent.DrawScreenEvent.Pre event) {
- doInventoryButtons = false;
-
- if (AuctionSearchOverlay.shouldReplace()) {
- AuctionSearchOverlay.render();
- event.setCanceled(true);
- return;
- }
- if (RancherBootOverlay.shouldReplace()) {
- RancherBootOverlay.render();
- event.setCanceled(true);
- return;
- }
-
- String containerName = null;
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
- if (guiScreen instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) guiScreen;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
- }
-
- if (GuiCustomEnchant.getInstance().shouldOverride(containerName)) {
- GuiCustomEnchant.getInstance().render(event.renderPartialTicks);
- event.setCanceled(true);
- return;
- }
-
- boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
- boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
- boolean customAhActive =
- event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
-
- if (storageOverlayActive) {
- StorageOverlay.getInstance().render();
- event.setCanceled(true);
- return;
- }
-
- if (tradeWindowActive || customAhActive) {
- event.setCanceled(true);
-
- ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
- int width = scaledResolution.getScaledWidth();
- int height = scaledResolution.getScaledHeight();
-
- //Dark background
- Utils.drawGradientRect(0, 0, width, height, -1072689136, -804253680);
-
- if (event.mouseX < width * neu.overlay.getWidthMult() / 3 ||
- event.mouseX > width - width * neu.overlay.getWidthMult() / 3) {
- if (customAhActive) {
- neu.manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY);
- } else if (tradeWindowActive) {
- TradeWindow.render(event.mouseX, event.mouseY);
- }
- neu.overlay.render(false);
- } else {
- neu.overlay.render(false);
- if (customAhActive) {
- neu.manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY);
- } else if (tradeWindowActive) {
- TradeWindow.render(event.mouseX, event.mouseY);
- }
- }
- }
-
- if (CalendarOverlay.isEnabled() || event.isCanceled()) return;
- if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && shouldRenderOverlay(event.gui)
- && event.gui instanceof GuiContainer) {
- doInventoryButtons = true;
-
- int zOffset = 50;
-
- GlStateManager.translate(0, 0, zOffset);
-
- int xSize = ((GuiContainer) event.gui).xSize;
- int ySize = ((GuiContainer) event.gui).ySize;
- int guiLeft = ((GuiContainer) event.gui).guiLeft;
- int guiTop = ((GuiContainer) event.gui).guiTop;
-
- if (!NEUApi.disableInventoryButtons) {
- for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
- if (!button.isActive()) continue;
- if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
-
- int x = guiLeft + button.x;
- int y = guiTop + button.y;
- if (button.anchorRight) {
- x += xSize;
- }
- if (button.anchorBottom) {
- y += ySize;
- }
- if (AccessoryBagOverlay.isInAccessoryBag()) {
- if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
- x += 80 + 28;
- }
- }
- if (NEUOverlay.isRenderingArmorHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
- x -= 25;
- }
- }
- if (NEUOverlay.isRenderingPetHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
- x -= 25;
- }
- }
-
- GlStateManager.color(1, 1, 1, 1f);
-
- GlStateManager.enableDepth();
- GlStateManager.enableAlpha();
- Minecraft.getMinecraft().getTextureManager().bindTexture(EDITOR);
- Utils.drawTexturedRect(x, y, 18, 18,
- button.backgroundIndex * 18 / 256f, (button.backgroundIndex * 18 + 18) / 256f,
- 18 / 256f, 36 / 256f, GL11.GL_NEAREST
- );
-
- if (button.icon != null && !button.icon.trim().isEmpty()) {
- GuiInvButtonEditor.renderIcon(button.icon, x + 1, y + 1);
- }
- }
- }
- GlStateManager.translate(0, 0, -zOffset);
- }
- }
-
- private static boolean shouldRenderOverlay(Gui gui) {
- boolean validGui = gui instanceof GuiContainer || gui instanceof GuiItemRecipe;
- if (gui instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) gui;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
- if (containerName.trim().equals("Fast Travel")) {
- validGui = false;
- }
- }
- return validGui;
- }
-
- private static final ResourceLocation EDITOR = new ResourceLocation("notenoughupdates:invbuttons/editor.png");
- private NEUConfig.InventoryButton buttonHovered = null;
- private long buttonHoveredMillis = 0;
- public static boolean disableCraftingText = false;
-
- /**
- * Will draw the NEUOverlay over the inventory if focusInv == false. (z-translation of 300 is so that NEUOverlay
- * will draw over Items in the inventory (which render at a z value of about 250))
- */
- @SubscribeEvent
- public void onGuiScreenDrawPost(GuiScreenEvent.DrawScreenEvent.Post event) {
- drawingGuiScreen = false;
- disableCraftingText = false;
-
- String containerName = null;
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
- if (guiScreen instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) guiScreen;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
-
- if (GuiCustomEnchant.getInstance().shouldOverride(containerName))
- return;
- }
-
- boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
- boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
- boolean customAhActive =
- event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
-
- if (!(tradeWindowActive || storageOverlayActive || customAhActive)) {
- if (shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) {
- GlStateManager.pushMatrix();
- if (!focusInv) {
- GL11.glTranslatef(0, 0, 300);
- neu.overlay.render(hoverInv && focusInv);
- GL11.glTranslatef(0, 0, -300);
- }
- GlStateManager.popMatrix();
- }
- }
-
- if (shouldRenderOverlay(event.gui) && neu.isOnSkyblock() && !hoverInv) {
- renderDungeonChestOverlay(event.gui);
- if (NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay) {
- AccessoryBagOverlay.renderOverlay();
- }
- }
-
- boolean hoveringButton = false;
- if (!doInventoryButtons) return;
- if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && shouldRenderOverlay(event.gui) &&
- event.gui instanceof GuiContainer) {
- int xSize = ((GuiContainer) event.gui).xSize;
- int ySize = ((GuiContainer) event.gui).ySize;
- int guiLeft = ((GuiContainer) event.gui).guiLeft;
- int guiTop = ((GuiContainer) event.gui).guiTop;
-
- if (!NEUApi.disableInventoryButtons) {
- for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
- if (!button.isActive()) continue;
- if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
-
- int x = guiLeft + button.x;
- int y = guiTop + button.y;
- if (button.anchorRight) {
- x += xSize;
- }
- if (button.anchorBottom) {
- y += ySize;
- }
- if (AccessoryBagOverlay.isInAccessoryBag()) {
- if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
- x += 80 + 28;
- }
- }
- if (NEUOverlay.isRenderingArmorHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
- x -= 25;
- }
- }
- if (NEUOverlay.isRenderingPetHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
- x -= 25;
- }
- }
-
- if (x - guiLeft >= 85 && x - guiLeft <= 115 && y - guiTop >= 4 && y - guiTop <= 25) {
- disableCraftingText = true;
- }
-
- if (event.mouseX >= x && event.mouseX <= x + 18 &&
- event.mouseY >= y && event.mouseY <= y + 18) {
- hoveringButton = true;
- long currentTime = System.currentTimeMillis();
-
- if (buttonHovered != button) {
- buttonHoveredMillis = currentTime;
- buttonHovered = button;
- }
-
- if (currentTime - buttonHoveredMillis > 600) {
- String command = button.command.trim();
- if (!command.startsWith("/")) {
- command = "/" + command;
- }
-
- Utils.drawHoveringText(Lists.newArrayList("\u00a77" + command), event.mouseX, event.mouseY,
- event.gui.width, event.gui.height, -1, Minecraft.getMinecraft().fontRendererObj
- );
- }
- }
- }
- }
- }
- if (!hoveringButton) buttonHovered = null;
-
- if (AuctionBINWarning.getInstance().shouldShow()) {
- AuctionBINWarning.getInstance().render();
- }
- }
-
- private void renderDungeonChestOverlay(GuiScreen gui) {
- if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 3) return;
-
- if (gui instanceof GuiChest && NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc != 2) {
- try {
- int xSize = ((GuiContainer) gui).xSize;
- int ySize = ((GuiContainer) gui).ySize;
- int guiLeft = ((GuiContainer) gui).guiLeft;
- int guiTop = ((GuiContainer) gui).guiTop;
-
- GuiChest eventGui = (GuiChest) gui;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- IInventory lower = cc.getLowerChestInventory();
-
- ItemStack rewardChest = lower.getStackInSlot(31);
- if (rewardChest != null &&
- rewardChest.getDisplayName().endsWith(EnumChatFormatting.GREEN + "Open Reward Chest")) {
- int chestCost = 0;
- try {
- String line6 = Utils.cleanColour(neu.manager.getLoreFromNBT(rewardChest.getTagCompound())[6]);
- StringBuilder cost = new StringBuilder();
- for (int i = 0; i < line6.length(); i++) {
- char c = line6.charAt(i);
- if ("0123456789".indexOf(c) >= 0) {
- cost.append(c);
- }
- }
- if (cost.length() > 0) {
- chestCost = Integer.parseInt(cost.toString());
- }
- } catch (Exception ignored) {
- }
-
- String missingItem = null;
- int totalValue = 0;
- HashMap<String, Float> itemValues = new HashMap<>();
- for (int i = 0; i < 5; i++) {
- ItemStack item = lower.getStackInSlot(11 + i);
- String internal = neu.manager.getInternalNameForItem(item);
- if (internal != null) {
- internal = internal.replace("\u00CD", "I").replace("\u0130", "I");
- float bazaarPrice = -1;
- JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(internal);
- if (bazaarInfo != null && bazaarInfo.has("curr_sell")) {
- bazaarPrice = bazaarInfo.get("curr_sell").getAsFloat();
- }
- if (bazaarPrice < 5000000 && internal.equals("RECOMBOBULATOR_3000")) bazaarPrice = 5000000;
-
- float worth = -1;
- if (bazaarPrice > 0) {
- worth = bazaarPrice;
- } else {
- switch (NotEnoughUpdates.INSTANCE.config.dungeons.profitType) {
- case 1:
- worth = neu.manager.auctionManager.getItemAvgBin(internal);
- break;
- case 2:
- JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
- if (auctionInfo != null) {
- if (auctionInfo.has("clean_price")) {
- worth = (int) auctionInfo.get("clean_price").getAsFloat();
- } else {
- worth = (int) (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
- }
- }
- break;
- default:
- worth = neu.manager.auctionManager.getLowestBin(internal);
- }
- if (worth <= 0) {
- worth = neu.manager.auctionManager.getLowestBin(internal);
- if (worth <= 0) {
- worth = neu.manager.auctionManager.getItemAvgBin(internal);
- if (worth <= 0) {
- JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
- if (auctionInfo != null) {
- if (auctionInfo.has("clean_price")) {
- worth = (int) auctionInfo.get("clean_price").getAsFloat();
- } else {
- worth = (int) (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
- }
- }
- }
- }
- }
- }
-
- if (worth > 0 && totalValue >= 0) {
- totalValue += worth;
- String display = item.getDisplayName();
-
- if (display.contains("Enchanted Book")) {
- NBTTagCompound tag = item.getTagCompound();
- if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
- NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
- NBTTagCompound enchants = ea.getCompoundTag("enchantments");
-
- int highestLevel = -1;
- for (String enchname : enchants.getKeySet()) {
- int level = enchants.getInteger(enchname);
- if (level > highestLevel) {
- display = EnumChatFormatting.BLUE + WordUtils.capitalizeFully(
- enchname.replace("_", " ")
- .replace("Ultimate", "")
- .trim()) + " " + level;
- }
- }
- }
- }
-
- itemValues.put(display, worth);
- } else {
- if (totalValue != -1) {
- missingItem = internal;
- }
- totalValue = -1;
- }
- }
- }
-
- NumberFormat format = NumberFormat.getInstance(Locale.US);
- String valueStringBIN1;
- String valueStringBIN2;
- if (totalValue >= 0) {
- valueStringBIN1 = EnumChatFormatting.YELLOW + "Value (BIN): ";
- valueStringBIN2 = EnumChatFormatting.GOLD + format.format(totalValue) + " coins";
- } else {
- valueStringBIN1 = EnumChatFormatting.YELLOW + "Can't find BIN: ";
- valueStringBIN2 = missingItem;
- }
-
- int profitLossBIN = totalValue - chestCost;
-
- boolean kismetUsed = false;
- // checking for kismet
- Slot slot = (eventGui.inventorySlots.getSlot(50));
- if (slot.getHasStack()) {
- String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(slot.getStack().getTagCompound());
- for (String line : lore) {
- if (line.contains("You already rerolled a chest!")) {
- kismetUsed = true;
- break;
- }
- }
- }
- int kismetPrice = neu.manager.auctionManager.getLowestBin("KISMET_FEATHER");
- String kismetStr = EnumChatFormatting.RED + format.format(kismetPrice) + " coins";
- if (neu.config.dungeons.useKismetOnDungeonProfit)
- profitLossBIN = kismetUsed ? profitLossBIN - kismetPrice : profitLossBIN;
-
- String profitPrefix = EnumChatFormatting.DARK_GREEN.toString();
- String lossPrefix = EnumChatFormatting.RED.toString();
- String prefix = profitLossBIN >= 0 ? profitPrefix : lossPrefix;
-
- String plStringBIN;
- if (profitLossBIN >= 0) {
- plStringBIN = prefix + "+" + format.format(profitLossBIN) + " coins";
- } else {
- plStringBIN = prefix + "-" + format.format(-profitLossBIN) + " coins";
- }
-
- if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 1 && !valueStringBIN2.equals(missingItem)) {
- int w = Minecraft.getMinecraft().fontRendererObj.getStringWidth(plStringBIN);
- GlStateManager.disableLighting();
- GlStateManager.translate(0, 0, 200);
- Minecraft.getMinecraft().fontRendererObj.drawString(plStringBIN, guiLeft + xSize - 5 - w, guiTop + 5,
- 0xffffffff, true
- );
- GlStateManager.translate(0, 0, -200);
- return;
- }
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(dungeon_chest_worth);
- GL11.glColor4f(1, 1, 1, 1);
- GlStateManager.disableLighting();
- Utils.drawTexturedRect(guiLeft + xSize + 4, guiTop, 180, 101, 0, 180 / 256f, 0, 101 / 256f, GL11.GL_NEAREST);
-
- Utils.renderAlignedString(valueStringBIN1, valueStringBIN2,
- guiLeft + xSize + 4 + 10, guiTop + 14, 160
- );
- if (neu.config.dungeons.useKismetOnDungeonProfit && kismetUsed) {
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Kismet Feather: ", kismetStr,
- guiLeft + xSize + 4 + 10, guiTop + 24, 160
- );
- }
- if (totalValue >= 0) {
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Profit/Loss: ",
- plStringBIN,
- guiLeft + xSize + 4 + 10,
- guiTop + (neu.config.dungeons.useKismetOnDungeonProfit ? (kismetUsed ? 34 : 24) : 24),
- 160
- );
- }
-
- int index = 0;
- for (Map.Entry<String, Float> entry : itemValues.entrySet()) {
- Utils.renderAlignedString(
- entry.getKey(),
- prefix +
- format.format(entry.getValue().intValue()),
- guiLeft + xSize + 4 + 10,
- guiTop + (neu.config.dungeons.useKismetOnDungeonProfit ? (kismetUsed ? 39 : 29) : 29) + (++index) * 10,
- 160
- );
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- public void drawStringShadow(String str, float x, float y, int len) {
- for (int xOff = -2; xOff <= 2; xOff++) {
- for (int yOff = -2; yOff <= 2; yOff++) {
- if (Math.abs(xOff) != Math.abs(yOff)) {
- Utils.drawStringCenteredScaledMaxWidth(Utils.cleanColourNotModifiers(str),
- Minecraft.getMinecraft().fontRendererObj,
- x + xOff / 2f, y + yOff / 2f, false, len,
- new Color(20, 20, 20, 100 / Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()
- );
- }
- }
- }
-
- Utils.drawStringCenteredScaledMaxWidth(str,
- Minecraft.getMinecraft().fontRendererObj,
- x, y, false, len,
- new Color(64, 64, 64, 255).getRGB()
- );
- }
-
- /**
- * Sends a mouse event to NEUOverlay if the inventory isn't hovered AND focused.
- * Will also cancel the event if if NEUOverlay#mouseInput returns true.
- */
- @SubscribeEvent(priority = EventPriority.LOW)
- public void onGuiScreenMouse(GuiScreenEvent.MouseInputEvent.Pre event) {
- if (Mouse.getEventButtonState() && StorageManager.getInstance().onAnyClick()) {
- event.setCanceled(true);
- return;
- }
-
- final ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
- final int scaledWidth = scaledresolution.getScaledWidth();
- final int scaledHeight = scaledresolution.getScaledHeight();
- int mouseX = Mouse.getX() * scaledWidth / Minecraft.getMinecraft().displayWidth;
- int mouseY = scaledHeight - Mouse.getY() * scaledHeight / Minecraft.getMinecraft().displayHeight - 1;
-
- if (AuctionBINWarning.getInstance().shouldShow()) {
- AuctionBINWarning.getInstance().mouseInput(mouseX, mouseY);
- event.setCanceled(true);
- return;
- }
-
- if (!event.isCanceled()) {
- Utils.scrollTooltip(Mouse.getEventDWheel());
- }
- if (AuctionSearchOverlay.shouldReplace()) {
- AuctionSearchOverlay.mouseEvent();
- event.setCanceled(true);
- return;
- }
- if (RancherBootOverlay.shouldReplace()) {
- RancherBootOverlay.mouseEvent();
- event.setCanceled(true);
- return;
- }
-
- String containerName = null;
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
- if (guiScreen instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) guiScreen;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
- if (containerName.contains(" Profile") && BetterContainers.profileViewerStackIndex != -1 &&
- eventGui.isMouseOverSlot(cc.inventorySlots.get(BetterContainers.profileViewerStackIndex), mouseX, mouseY) &&
- Mouse.getEventButton() >= 0) {
- event.setCanceled(true);
- if (Mouse.getEventButtonState() && eventGui.inventorySlots.inventorySlots.get(22).getStack() != null &&
- eventGui.inventorySlots.inventorySlots.get(22).getStack().getTagCompound() != null) {
- NBTTagCompound tag = eventGui.inventorySlots.inventorySlots.get(22).getStack().getTagCompound();
- if (tag.hasKey("SkullOwner") && tag.getCompoundTag("SkullOwner").hasKey("Name")) {
- String username = tag.getCompoundTag("SkullOwner").getString("Name");
- Utils.playPressSound();
- ViewProfileCommand.RUNNABLE.accept(new String[]{username});
- }
- }
- }
- }
-
- if (GuiCustomEnchant.getInstance().shouldOverride(containerName) &&
- GuiCustomEnchant.getInstance().mouseInput(mouseX, mouseY)) {
- event.setCanceled(true);
- return;
- }
-
- boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
- boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
- boolean customAhActive =
- event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
-
- if (storageOverlayActive) {
- if (StorageOverlay.getInstance().mouseInput(mouseX, mouseY)) {
- event.setCanceled(true);
- }
- return;
- }
-
- if (tradeWindowActive || customAhActive) {
- event.setCanceled(true);
- if (customAhActive) {
- neu.manager.auctionManager.customAH.handleMouseInput();
- } else if (tradeWindowActive) {
- TradeWindow.handleMouseInput();
- }
- neu.overlay.mouseInput();
- return;
- }
-
- if (shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) {
- if (!NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay || !AccessoryBagOverlay.mouseClick()) {
- if (!(hoverInv && focusInv)) {
- if (neu.overlay.mouseInput()) {
- event.setCanceled(true);
- }
- } else {
- neu.overlay.mouseInputInv();
- }
- }
- }
- if (event.isCanceled()) return;
- if (!doInventoryButtons) return;
- if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && shouldRenderOverlay(event.gui) &&
- Mouse.getEventButton() >= 0
- && event.gui instanceof GuiContainer) {
- int xSize = ((GuiContainer) event.gui).xSize;
- int ySize = ((GuiContainer) event.gui).ySize;
- int guiLeft = ((GuiContainer) event.gui).guiLeft;
- int guiTop = ((GuiContainer) event.gui).guiTop;
- if (!NEUApi.disableInventoryButtons) {
- for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
- if (!button.isActive()) continue;
- if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
-
- int x = guiLeft + button.x;
- int y = guiTop + button.y;
- if (button.anchorRight) {
- x += xSize;
- }
- if (button.anchorBottom) {
- y += ySize;
- }
- if (AccessoryBagOverlay.isInAccessoryBag()) {
- if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
- x += 80 + 28;
- }
- }
- if (NEUOverlay.isRenderingArmorHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
- x -= 25;
- }
- }
- if (NEUOverlay.isRenderingPetHud()) {
- if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
- x -= 25;
- }
- }
-
- if (mouseX >= x && mouseX <= x + 18 && mouseY >= y && mouseY <= y + 18) {
- if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
- int clickType = NotEnoughUpdates.INSTANCE.config.inventoryButtons.clickType;
- if ((clickType == 0 && Mouse.getEventButtonState()) || (clickType == 1 && !Mouse.getEventButtonState())) {
- String command = button.command.trim();
- if (!command.startsWith("/")) {
- command = "/" + command;
- }
- if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command) == 0) {
- NotEnoughUpdates.INSTANCE.sendChatMessage(command);
- }
- }
- } else {
- event.setCanceled(true);
- }
- return;
- }
- }
- }
- }
- }
-
- ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
-
- JsonObject essenceJson = new JsonObject();
-
- /**
- * Sends a kbd event to NEUOverlay, cancelling if NEUOverlay#keyboardInput returns true.
- * Also includes a dev function used for creating custom named json files with recipes.
- */
- @SubscribeEvent
- public void onGuiScreenKeyboard(GuiScreenEvent.KeyboardInputEvent.Pre event) {
- if (AuctionBINWarning.getInstance().shouldShow()) {
- AuctionBINWarning.getInstance().keyboardInput();
- event.setCanceled(true);
- return;
- }
-
- if (AuctionSearchOverlay.shouldReplace()) {
- AuctionSearchOverlay.keyEvent();
- event.setCanceled(true);
- return;
- }
- if (RancherBootOverlay.shouldReplace()) {
- RancherBootOverlay.keyEvent();
- event.setCanceled(true);
- return;
- }
-
- String containerName = null;
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
-
- if (guiScreen instanceof GuiChest) {
- containerName = ((ContainerChest) ((GuiChest) guiScreen).inventorySlots)
- .getLowerChestInventory()
- .getDisplayName()
- .getUnformattedText();
- }
-
- if (GuiCustomEnchant.getInstance().shouldOverride(containerName) &&
- GuiCustomEnchant.getInstance().keyboardInput()) {
- event.setCanceled(true);
- return;
- }
-
- boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
- boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
- boolean customAhActive =
- event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
-
- if (storageOverlayActive) {
- if (StorageOverlay.getInstance().keyboardInput()) {
- event.setCanceled(true);
- return;
- }
- }
-
- if (tradeWindowActive || customAhActive) {
- if (customAhActive) {
- if (neu.manager.auctionManager.customAH.keyboardInput()) {
- event.setCanceled(true);
- Minecraft.getMinecraft().dispatchKeypresses();
- } else if (neu.overlay.keyboardInput(focusInv)) {
- event.setCanceled(true);
- }
- } else if (tradeWindowActive) {
- TradeWindow.keyboardInput();
- if (Keyboard.getEventKey() != Keyboard.KEY_ESCAPE) {
- event.setCanceled(true);
- Minecraft.getMinecraft().dispatchKeypresses();
- neu.overlay.keyboardInput(focusInv);
- }
- }
- return;
- }
-
- if (shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) {
- if (neu.overlay.keyboardInput(focusInv)) {
- event.setCanceled(true);
- }
- }
- if (NotEnoughUpdates.INSTANCE.config.hidden.dev && NotEnoughUpdates.INSTANCE.config.hidden.enableItemEditing &&
- Minecraft.getMinecraft().theWorld != null &&
- Keyboard.getEventKey() == Keyboard.KEY_N && Keyboard.getEventKeyState()) {
- GuiScreen gui = Minecraft.getMinecraft().currentScreen;
- if (gui instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) event.gui;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- IInventory lower = cc.getLowerChestInventory();
-
- if (!lower.getDisplayName().getUnformattedText().endsWith("Essence")) return;
-
- for (int i = 0; i < lower.getSizeInventory(); i++) {
- ItemStack stack = lower.getStackInSlot(i);
-
- String internalname = neu.manager.getInternalNameForItem(stack);
- if (internalname != null) {
- String[] lore = neu.manager.getLoreFromNBT(stack.getTagCompound());
-
- for (String line : lore) {
- if (line.contains(":") && (line.startsWith("\u00A77Upgrade to") ||
- line.startsWith("\u00A77Convert to Dungeon Item"))) {
- String[] split = line.split(":");
- String after = Utils.cleanColour(split[1]);
- StringBuilder costS = new StringBuilder();
- for (char c : after.toCharArray()) {
- if (c >= '0' && c <= '9') {
- costS.append(c);
- }
- }
- int cost = Integer.parseInt(costS.toString());
- String[] afterSplit = after.split(" ");
- String type = afterSplit[afterSplit.length - 2];
-
- if (!essenceJson.has(internalname)) {
- essenceJson.add(internalname, new JsonObject());
- }
- JsonObject obj = essenceJson.get(internalname).getAsJsonObject();
- obj.addProperty("type", type);
-
- if (line.startsWith("\u00A77Convert to Dungeon Item")) {
- obj.addProperty("dungeonize", cost);
- } else if (line.startsWith("\u00A77Upgrade to")) {
- int stars = 0;
- for (char c : line.toCharArray()) {
- if (c == '\u272A') stars++;
- }
- if (stars > 0) {
- obj.addProperty(stars + "", cost);
- }
- }
- }
- }
- }
- }
- System.out.println(essenceJson);
- }
- }
- if (NotEnoughUpdates.INSTANCE.config.hidden.dev && NotEnoughUpdates.INSTANCE.config.hidden.enableItemEditing &&
- Minecraft.getMinecraft().theWorld != null &&
- Keyboard.getEventKey() == Keyboard.KEY_O && Keyboard.getEventKeyState()) {
- GuiScreen gui = Minecraft.getMinecraft().currentScreen;
- if (gui instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) event.gui;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- IInventory lower = cc.getLowerChestInventory();
-
- if (lower.getStackInSlot(23) != null &&
- lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) {
- ItemStack res = lower.getStackInSlot(25);
- String resInternalname = neu.manager.getInternalNameForItem(res);
- JTextField tf = new JTextField();
- tf.setText(resInternalname);
- tf.addAncestorListener(new RequestFocusListener());
- JOptionPane.showOptionDialog(null,
- tf,
- "Enter Name:",
- JOptionPane.NO_OPTION,
- JOptionPane.PLAIN_MESSAGE,
- null, new String[]{"Enter"}, "Enter"
- );
- resInternalname = tf.getText();
- if (resInternalname.trim().length() == 0) {
- return;
- }
-
- JsonObject recipe = new JsonObject();
-
- String[] x = {"1", "2", "3"};
- String[] y = {"A", "B", "C"};
-
- for (int i = 0; i <= 18; i += 9) {
- for (int j = 0; j < 3; j++) {
- ItemStack stack = lower.getStackInSlot(10 + i + j);
- String internalname = "";
- if (stack != null) {
- internalname = neu.manager.getInternalNameForItem(stack);
- if (!neu.manager.getItemInformation().containsKey(internalname)) {
- neu.manager.writeItemToFile(stack);
- }
- internalname += ":" + stack.stackSize;
- }
- recipe.addProperty(y[i / 9] + x[j], internalname);
- }
- }
-
- JsonObject json = neu.manager.getJsonForItem(res);
- json.add("recipe", recipe);
- json.addProperty("internalname", resInternalname);
- json.addProperty("clickcommand", "viewrecipe");
- json.addProperty("modver", NotEnoughUpdates.VERSION);
- try {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname));
- neu.manager.writeJsonDefaultDir(json, resInternalname + ".json");
- neu.manager.loadItem(resInternalname);
- } catch (IOException ignored) {
- }
- }
- }
- }
- }
-
- private final HashSet<String> percentStats = new HashSet<>();
-
- {
- percentStats.add("bonus_attack_speed");
- percentStats.add("crit_damage");
- percentStats.add("crit_chance");
- percentStats.add("sea_creature_chance");
- percentStats.add("ability_damage");
- }
-
- private String currentRarity = "COMMON";
- private boolean showReforgeStoneStats = true;
- private boolean pressedArrowLast = false;
- private boolean pressedShiftLast = false;
-
- private boolean copied = false;
-
- //just to try and optimize it a bit
- private int sbaloaded = -1;
-
- private boolean isSbaloaded() {
- if (sbaloaded == -1) {
- if (Loader.isModLoaded("skyblockaddons")) {
- sbaloaded = 1;
- } else {
- sbaloaded = 0;
- }
- }
- return sbaloaded == 1;
- }
-
- @SubscribeEvent(priority = EventPriority.LOW)
- public void onItemTooltipLow(ItemTooltipEvent event) {
- if (!NotEnoughUpdates.INSTANCE.isOnSkyblock()) return;
-
- String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack);
- if (internalname == null) {
- onItemToolTipInternalNameNull(event);
- return;
- }
-
- boolean hasEnchantments =
- event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("enchantments", 10);
- Set<String> enchantIds = new HashSet<>();
- if (hasEnchantments)
- enchantIds =
- event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").getCompoundTag("enchantments").getKeySet();
-
- JsonObject enchantsConst = Constants.ENCHANTS;
- JsonArray allItemEnchs = null;
- Set<String> ignoreFromPool = new HashSet<>();
- if (enchantsConst != null && hasEnchantments && NotEnoughUpdates.INSTANCE.config.tooltipTweaks.missingEnchantList) {
- try {
- JsonArray enchantPools = enchantsConst.get("enchant_pools").getAsJsonArray();
- for (JsonElement element : enchantPools) {
- Set<String> currentPool = new HashSet<>();
- for (JsonElement poolElement : element.getAsJsonArray()) {
- String poolS = poolElement.getAsString();
- currentPool.add(poolS);
- }
- for (JsonElement poolElement : element.getAsJsonArray()) {
- String poolS = poolElement.getAsString();
- if (enchantIds.contains(poolS)) {
- ignoreFromPool.addAll(currentPool);
- break;
- }
- }
- }
-
- JsonObject enchantsObj = enchantsConst.get("enchants").getAsJsonObject();
- NBTTagCompound tag = event.itemStack.getTagCompound();
- if (tag != null) {
- NBTTagCompound display = tag.getCompoundTag("display");
- if (display.hasKey("Lore", 9)) {
- NBTTagList list = display.getTagList("Lore", 8);
- out:
- for (int i = list.tagCount(); i >= 0; i--) {
- String line = list.getStringTagAt(i);
- for (int j = 0; j < Utils.rarityArrC.length; j++) {
- for (Map.Entry<String, JsonElement> entry : enchantsObj.entrySet()) {
- if (line.contains(Utils.rarityArrC[j] + " " + entry.getKey()) ||
- line.contains(Utils.rarityArrC[j] + " DUNGEON " + entry.getKey())) {
- allItemEnchs = entry.getValue().getAsJsonArray();
- break out;
- }
- }
- }
- }
- }
- }
- } catch (Exception ignored) {
- }
- }
-
- boolean gotToEnchants = false;
- boolean passedEnchants = false;
-
- boolean dungeonProfit = false;
- int index = 0;
- List<String> newTooltip = new ArrayList<>();
-
- for (String line : event.toolTip) {
- if (line.endsWith(EnumChatFormatting.DARK_GRAY + "Reforge Stone") &&
- NotEnoughUpdates.INSTANCE.config.tooltipTweaks.showReforgeStats) {
- JsonObject reforgeStones = Constants.REFORGESTONES;
-
- if (reforgeStones != null && reforgeStones.has(internalname)) {
- boolean shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
- if (!pressedShiftLast && shift) {
- showReforgeStoneStats = !showReforgeStoneStats;
- }
- pressedShiftLast = shift;
-
- newTooltip.add(line);
- newTooltip.add("");
- if (!showReforgeStoneStats) {
- newTooltip.add(EnumChatFormatting.DARK_GRAY + "[Press SHIFT to show extra info]");
- } else {
- newTooltip.add(EnumChatFormatting.DARK_GRAY + "[Press SHIFT to hide extra info]");
- }
-
- JsonObject reforgeInfo = reforgeStones.get(internalname).getAsJsonObject();
- JsonArray requiredRaritiesArray = reforgeInfo.get("requiredRarities").getAsJsonArray();
-
- if (showReforgeStoneStats && requiredRaritiesArray.size() > 0) {
- String reforgeName = Utils.getElementAsString(reforgeInfo.get("reforgeName"), "");
-
- String[] requiredRarities = new String[requiredRaritiesArray.size()];
- for (int i = 0; i < requiredRaritiesArray.size(); i++) {
- requiredRarities[i] = requiredRaritiesArray.get(i).getAsString();
- }
-
- int rarityIndex = requiredRarities.length - 1;
- String rarity = requiredRarities[rarityIndex];
- for (int i = 0; i < requiredRarities.length; i++) {
- String rar = requiredRarities[i];
- if (rar.equalsIgnoreCase(currentRarity)) {
- rarity = rar;
- rarityIndex = i;
- break;
- }
- }
-
- boolean left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
- boolean right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
- if (!pressedArrowLast && (left || right)) {
- if (left) {
- rarityIndex--;
- } else if (right) {
- rarityIndex++;
- }
- if (rarityIndex < 0) rarityIndex = 0;
- if (rarityIndex >= requiredRarities.length) rarityIndex = requiredRarities.length - 1;
- currentRarity = requiredRarities[rarityIndex];
- rarity = currentRarity;
- }
- pressedArrowLast = left || right;
-
- JsonElement statsE = reforgeInfo.get("reforgeStats");
-
- String rarityFormatted = Utils.rarityArrMap.getOrDefault(rarity, rarity);
-
- JsonElement reforgeAbilityE = reforgeInfo.get("reforgeAbility");
- String reforgeAbility = null;
- if (reforgeAbilityE != null) {
- if (reforgeAbilityE.isJsonPrimitive() && reforgeAbilityE.getAsJsonPrimitive().isString()) {
- reforgeAbility = Utils.getElementAsString(reforgeInfo.get("reforgeAbility"), "");
-
- } else if (reforgeAbilityE.isJsonObject()) {
- if (reforgeAbilityE.getAsJsonObject().has(rarity)) {
- reforgeAbility = reforgeAbilityE.getAsJsonObject().get(rarity).getAsString();
- }
- }
- }
-
- if (reforgeAbility != null && !reforgeAbility.isEmpty()) {
- String text = EnumChatFormatting.BLUE + (reforgeName.isEmpty() ? "Bonus: " : reforgeName + " Bonus: ") +
- EnumChatFormatting.GRAY + reforgeAbility;
- boolean first = true;
- for (String s : Minecraft.getMinecraft().fontRendererObj.listFormattedStringToWidth(text, 150)) {
- newTooltip.add((first ? "" : " ") + s);
- first = false;
- }
- newTooltip.add("");
- }
-
- newTooltip.add(EnumChatFormatting.BLUE + "Stats for " + rarityFormatted +
- "\u00a79: [\u00a7l\u00a7m< \u00a79Switch\u00a7l\u27a1\u00a79]");
-
- if (statsE != null && statsE.isJsonObject()) {
- JsonObject stats = statsE.getAsJsonObject();
-
- JsonElement statsRarE = stats.get(rarity);
- if (statsRarE != null && statsRarE.isJsonObject()) {
-
- JsonObject statsRar = statsRarE.getAsJsonObject();
-
- TreeSet<Map.Entry<String, JsonElement>> sorted = new TreeSet<>(Map.Entry.comparingByKey());
- sorted.addAll(statsRar.entrySet());
-
- for (Map.Entry<String, JsonElement> entry : sorted) {
- if (entry.getValue().isJsonPrimitive() && ((JsonPrimitive) entry.getValue()).isNumber()) {
- float statNumF = entry.getValue().getAsFloat();
- String statNumS;
- if (statNumF % 1 == 0) {
- statNumS = String.valueOf(Math.round(statNumF));
- } else {
- statNumS = Utils.floatToString(statNumF, 1);
- }
- String reforgeNamePretty = WordUtils.capitalizeFully(entry.getKey().replace("_", " "));
- String text =
- EnumChatFormatting.GRAY + reforgeNamePretty + ": " + EnumChatFormatting.GREEN + "+" + statNumS;
- if (percentStats.contains(entry.getKey())) {
- text += "%";
- }
- newTooltip.add(" " + text);
- }
- }
- }
- }
-
- JsonElement reforgeCostsE = reforgeInfo.get("reforgeCosts");
- int reforgeCost = -1;
- if (reforgeCostsE != null) {
- if (reforgeCostsE.isJsonPrimitive() && reforgeCostsE.getAsJsonPrimitive().isNumber()) {
- reforgeCost = (int) Utils.getElementAsFloat(reforgeInfo.get("reforgeAbility"), -1);
-
- } else if (reforgeCostsE.isJsonObject()) {
- if (reforgeCostsE.getAsJsonObject().has(rarity)) {
- reforgeCost = (int) Utils.getElementAsFloat(reforgeCostsE.getAsJsonObject().get(rarity), -1);
- }
- }
- }
-
- if (reforgeCost >= 0) {
- String text = EnumChatFormatting.BLUE + "Apply Cost: " + EnumChatFormatting.GOLD +
- NumberFormat.getNumberInstance().format(reforgeCost) + " coins";
- newTooltip.add("");
- newTooltip.add(text);
- }
-
- }
-
- continue;
- }
-
- } else if (line.contains("\u00A7cR\u00A76a\u00A7ei\u00A7an\u00A7bb\u00A79o\u00A7dw\u00A79 Rune")) {
- line = line.replace(
- "\u00A7cR\u00A76a\u00A7ei\u00A7an\u00A7bb\u00A79o\u00A7dw\u00A79 Rune",
- Utils.chromaString("Rainbow Rune", index, false) + EnumChatFormatting.BLUE
- );
- } else if (hasEnchantments) {
- if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) &&
- NotEnoughUpdates.INSTANCE.config.tooltipTweaks.missingEnchantList) {
- boolean lineHasEnch = false;
- for (String s : enchantIds) {
- String enchantName = WordUtils.capitalizeFully(s.replace("_", " "));
- if (line.contains(enchantName)) {
- lineHasEnch = true;
- break;
- }
- }
- if (lineHasEnch) {
- gotToEnchants = true;
- } else {
- if (gotToEnchants && !passedEnchants && Utils.cleanColour(line).trim().length() == 0) {
- if (enchantsConst != null && allItemEnchs != null) {
- List<String> missing = new ArrayList<>();
- for (JsonElement enchIdElement : allItemEnchs) {
- String enchId = enchIdElement.getAsString();
- if (!enchId.startsWith("ultimate_") && !ignoreFromPool.contains(enchId) &&
- !enchantIds.contains(enchId)) {
- missing.add(enchId);
- }
- }
- if (!missing.isEmpty()) {
- newTooltip.add("");
- StringBuilder currentLine =
- new StringBuilder(EnumChatFormatting.RED + "Missing: " + EnumChatFormatting.GRAY);
- for (int i = 0; i < missing.size(); i++) {
- String enchName = WordUtils.capitalizeFully(missing.get(i).replace("_", " "));
- if (currentLine.length() != 0 &&
- (Utils.cleanColour(currentLine.toString()).length() + enchName.length()) > 40) {
- newTooltip.add(currentLine.toString());
- currentLine = new StringBuilder();
- }
- if (currentLine.length() != 0 && i != 0) {
- currentLine.append(", ").append(enchName);
- } else {
- currentLine.append(EnumChatFormatting.GRAY).append(enchName);
- }
- }
- if (currentLine.length() != 0) {
- newTooltip.add(currentLine.toString());
- }
- }
- }
- passedEnchants = true;
- }
- }
- }
- for (String op : NotEnoughUpdates.INSTANCE.config.hidden.enchantColours) {
- List<String> colourOps = GuiEnchantColour.splitter.splitToList(op);
- String enchantName = GuiEnchantColour.getColourOpIndex(colourOps, 0);
- String comparator = GuiEnchantColour.getColourOpIndex(colourOps, 1);
- String comparison = GuiEnchantColour.getColourOpIndex(colourOps, 2);
- String colourCode = GuiEnchantColour.getColourOpIndex(colourOps, 3);
- String modifier = GuiEnchantColour.getColourOpIndex(colourOps, 4);
-
- int modifierI = GuiEnchantColour.getIntModifier(modifier);
-
- if (enchantName.length() == 0) continue;
- if (comparator.length() == 0) continue;
- if (comparison.length() == 0) continue;
- if (colourCode.length() == 0) continue;
-
- int comparatorI = ">=<".indexOf(comparator.charAt(0));
-
- int levelToFind = -1;
- try {
- levelToFind = Integer.parseInt(comparison);
- } catch (Exception e) {
- continue;
- }
-
- if (comparatorI < 0) continue;
- String regexText = "0123456789abcdefz";
- if (isSbaloaded()) {
- regexText = regexText + "Z";
- }
-
- if (regexText.indexOf(colourCode.charAt(0)) < 0) continue;
-
- //item_lore = item_lore.replaceAll("\\u00A79("+lvl4Max+" IV)", EnumChatFormatting.DARK_PURPLE+"$1");
- //9([a-zA-Z ]+?) ([0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X))(,|$)
- Pattern pattern;
- try {
- pattern = Pattern.compile("(\\u00A79|\\u00A7(9|l)\\u00A7d\\u00A7l)(?<enchantName>" + enchantName + ") " +
- "(?<level>[0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX))((\\u00A79)?,|( \\u00A78(?:,?[0-9]+)*)?$)");
- } catch (Exception e) {
- continue;
- } //malformed regex
- Matcher matcher = pattern.matcher(line);
- int matchCount = 0;
- while (matcher.find() && matchCount < 5) {
- if (Utils.cleanColour(matcher.group("enchantName")).startsWith(" ")) continue;
-
- matchCount++;
- int level = -1;
- String levelStr = matcher.group("level");
- if (levelStr == null) continue;
- try {
- level = Integer.parseInt(levelStr);
- } catch (Exception e) {
- switch (levelStr) {
- case "I":
- level = 1;
- break;
- case "II":
- level = 2;
- break;
- case "III":
- level = 3;
- break;
- case "IV":
- level = 4;
- break;
- case "V":
- level = 5;
- break;
- case "VI":
- level = 6;
- break;
- case "VII":
- level = 7;
- break;
- case "VIII":
- level = 8;
- break;
- case "IX":
- level = 9;
- break;
- case "X":
- level = 10;
- break;
- case "XI":
- level = 11;
- break;
- case "XII":
- level = 12;
- break;
- case "XIII":
- level = 13;
- break;
- case "XIV":
- level = 14;
- break;
- case "XV":
- level = 15;
- break;
- case "XVI":
- level = 16;
- break;
- case "XVII":
- level = 17;
- break;
- case "XVIII":
- level = 18;
- break;
- case "XIX":
- level = 19;
- break;
- case "XX":
- level = 20;
- break;
- }
- }
- boolean matches = false;
- if (level > 0) {
- switch (comparator) {
- case ">":
- matches = level > levelToFind;
- break;
- case "=":
- matches = level == levelToFind;
- break;
- case "<":
- matches = level < levelToFind;
- break;
- }
- }
- if (matches) {
- String enchantText = matcher.group("enchantName");
- StringBuilder extraModifiersBuilder = new StringBuilder();
-
- if ((modifierI & GuiEnchantColour.BOLD_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.BOLD);
- }
- if ((modifierI & GuiEnchantColour.ITALIC_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.ITALIC);
- }
- if ((modifierI & GuiEnchantColour.UNDERLINE_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.UNDERLINE);
- }
- if ((modifierI & GuiEnchantColour.OBFUSCATED_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.OBFUSCATED);
- }
- if ((modifierI & GuiEnchantColour.STRIKETHROUGH_MODIFIER) != 0) {
- extraModifiersBuilder.append(EnumChatFormatting.STRIKETHROUGH);
- }
-
- String extraMods = extraModifiersBuilder.toString();
-
- if (!colourCode.equals("z")) {
- line = line.replace(
- "\u00A79" + enchantText,
- "\u00A7" + colourCode + extraMods + enchantText
- );
- line = line.replace(
- "\u00A79\u00A7d\u00A7l" + enchantText,
- "\u00A7" + colourCode + extraMods + enchantText
- );
- line = line.replace(
- "\u00A7l\u00A7d\u00A7l" + enchantText,
- "\u00A7" + colourCode + extraMods + enchantText
- );
- } else {
- int offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll(
- "\\u00A79" + enchantText + ".*", ""));
- line =
- line.replace("\u00A79" + enchantText, Utils.chromaString(enchantText, offset / 12f + index, false));
-
- offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll(
- "\\u00A79\\u00A7d\\u00A7l" + enchantText + ".*", ""));
- line = line.replace("\u00A79\u00A7d\u00A7l" + enchantText, Utils.chromaString(enchantText,
- offset / 12f + index, true
- ));
- offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll(
- "\\u00A7l\\u00A7d\\u00A7l" + enchantText + ".*", ""));
- line = line.replace("\u00A7l\u00A7d\u00A7l" + enchantText, Utils.chromaString(enchantText,
- offset / 12f + index, true
- ));
- }
- }
- }
- }
- }
-
- newTooltip.add(line);
-
- if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.showPriceInfoAucItem) {
- if (line.contains(EnumChatFormatting.GRAY + "Buy it now: ") ||
- line.contains(EnumChatFormatting.GRAY + "Bidder: ") ||
- line.contains(EnumChatFormatting.GRAY + "Starting bid: ")) {
-
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && !Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
- newTooltip.add("");
- newTooltip.add(EnumChatFormatting.GRAY + "[SHIFT for Price Info]");
- } else {
- ItemPriceInformation.addToTooltip(newTooltip, internalname, event.itemStack);
- }
- }
- }
-
- if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 2 &&
- Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
- if (line.contains(EnumChatFormatting.GREEN + "Open Reward Chest")) {
- dungeonProfit = true;
- } else if (index == 7 && dungeonProfit) {
- GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- IInventory lower = cc.getLowerChestInventory();
-
- int chestCost = 0;
- try {
- String line6 = Utils.cleanColour(line);
- StringBuilder cost = new StringBuilder();
- for (int i = 0; i < line6.length(); i++) {
- char c = line6.charAt(i);
- if ("0123456789".indexOf(c) >= 0) {
- cost.append(c);
- }
- }
- if (cost.length() > 0) {
- chestCost = Integer.parseInt(cost.toString());
- }
- } catch (Exception ignored) {
- }
-
- String missingItem = null;
- int totalValue = 0;
- HashMap<String, Float> itemValues = new HashMap<>();
- for (int i = 0; i < 5; i++) {
- ItemStack item = lower.getStackInSlot(11 + i);
- String internal = neu.manager.getInternalNameForItem(item);
- if (internal != null) {
- internal = internal.replace("\u00CD", "I").replace("\u0130", "I");
- float bazaarPrice = -1;
- JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(internal);
- if (bazaarInfo != null && bazaarInfo.has("curr_sell")) {
- bazaarPrice = bazaarInfo.get("curr_sell").getAsFloat();
- }
- if (bazaarPrice < 5000000 && internal.equals("RECOMBOBULATOR_3000")) bazaarPrice = 5000000;
-
- float worth = -1;
- if (bazaarPrice > 0) {
- worth = bazaarPrice;
- } else {
- switch (NotEnoughUpdates.INSTANCE.config.dungeons.profitType) {
- case 1:
- worth = neu.manager.auctionManager.getItemAvgBin(internal);
- break;
- case 2:
- JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
- if (auctionInfo != null) {
- if (auctionInfo.has("clean_price")) {
- worth = (int) auctionInfo.get("clean_price").getAsFloat();
- } else {
- worth = (int) (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
- }
- }
- break;
- default:
- worth = neu.manager.auctionManager.getLowestBin(internal);
- }
- if (worth <= 0) {
- worth = neu.manager.auctionManager.getLowestBin(internal);
- if (worth <= 0) {
- worth = neu.manager.auctionManager.getItemAvgBin(internal);
- if (worth <= 0) {
- JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
- if (auctionInfo != null) {
- if (auctionInfo.has("clean_price")) {
- worth = (int) auctionInfo.get("clean_price").getAsFloat();
- } else {
- worth = (int) (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
- }
- }
- }
- }
- }
- }
-
- if (worth > 0 && totalValue >= 0) {
- totalValue += worth;
-
- String display = item.getDisplayName();
-
- if (display.contains("Enchanted Book")) {
- NBTTagCompound tag = item.getTagCompound();
- if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
- NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
- NBTTagCompound enchants = ea.getCompoundTag("enchantments");
-
- int highestLevel = -1;
- for (String enchname : enchants.getKeySet()) {
- int level = enchants.getInteger(enchname);
- if (level > highestLevel) {
- display = EnumChatFormatting.BLUE + WordUtils.capitalizeFully(
- enchname.replace("_", " ")
- .replace("Ultimate", "")
- .trim()) + " " + level;
- }
- }
- }
- }
-
- itemValues.put(display, worth);
- } else {
- if (totalValue != -1) {
- missingItem = internal;
- }
- totalValue = -1;
- }
- }
- }
-
- NumberFormat format = NumberFormat.getInstance(Locale.US);
- String valueStringBIN1;
- String valueStringBIN2;
- if (totalValue >= 0) {
- valueStringBIN1 = EnumChatFormatting.YELLOW + "Value (BIN): ";
- valueStringBIN2 = EnumChatFormatting.GOLD + format.format(totalValue) + " coins";
- } else {
- valueStringBIN1 = EnumChatFormatting.YELLOW + "Can't find BIN: ";
- valueStringBIN2 = missingItem;
- }
-
- int profitLossBIN = totalValue - chestCost;
- String profitPrefix = EnumChatFormatting.DARK_GREEN.toString();
- String lossPrefix = EnumChatFormatting.RED.toString();
- String prefix = profitLossBIN >= 0 ? profitPrefix : lossPrefix;
-
- String plStringBIN;
- if (profitLossBIN >= 0) {
- plStringBIN = prefix + "+" + format.format(profitLossBIN) + " coins";
- } else {
- plStringBIN = prefix + "-" + format.format(-profitLossBIN) + " coins";
- }
-
- String neu = EnumChatFormatting.YELLOW + "[NEU] ";
-
- newTooltip.add(neu + valueStringBIN1 + " " + valueStringBIN2);
- if (totalValue >= 0) {
- newTooltip.add(neu + EnumChatFormatting.YELLOW + "Profit/Loss: " + plStringBIN);
- }
-
- for (Map.Entry<String, Float> entry : itemValues.entrySet()) {
- newTooltip.add(neu + entry.getKey() + prefix + "+" +
- format.format(entry.getValue().intValue()));
- }
- }
- }
-
- index++;
- }
-
- for (int i = newTooltip.size() - 1; i >= 0; i--) {
- String line = Utils.cleanColour(newTooltip.get(i));
- for (int i1 = 0; i1 < Utils.rarityArr.length; i1++) {
- if (line.equals(Utils.rarityArr[i1])) {
- if (i - 2 < 0) {
- break;
- }
- newTooltip.addAll(i - 1, petToolTipXPExtend(event));
- break;
- }
- }
- }
-
- pressedShiftLast = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
- pressedArrowLast = Keyboard.isKeyDown(Keyboard.KEY_LEFT) || Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
-
- event.toolTip.clear();
- event.toolTip.addAll(newTooltip);
-
- HashMap<String, List<String>> loreBuckets = new HashMap<>();
-
- List<String> hypixelOrder = new ArrayList<>();
-
- hypixelOrder.add("attributes");
- hypixelOrder.add("enchants");
- hypixelOrder.add("ability");
- hypixelOrder.add("reforge_bonus");
- hypixelOrder.add("rarity");
-
- if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.showPriceInfoInvItem) {
- ItemPriceInformation.addToTooltip(event.toolTip, internalname, event.itemStack);
- }
-
- if (event.itemStack.getTagCompound() != null && event.itemStack.getTagCompound().getBoolean("NEUHIDEPETTOOLTIP") &&
- NotEnoughUpdates.INSTANCE.config.petOverlay.hidePetTooltip) {
- event.toolTip.clear();
- }
- }
-
- private final Pattern xpLevelPattern = Pattern.compile("(.*) (\\xA7e(.*)\\xA76/\\xA7e(.*))");
-
- private void onItemToolTipInternalNameNull(ItemTooltipEvent event) {
- petToolTipXPExtendPetMenu(event);
- }
-
- private List<String> petToolTipXPExtend(ItemTooltipEvent event) {
- List<String> tooltipText = new ArrayList<>();
- if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.petExtendExp) {
- if (event.itemStack.getTagCompound().hasKey("DisablePetExp")) {
- if (event.itemStack.getTagCompound().getBoolean("DisablePetExp")) {
- return tooltipText;
- }
- }
- //7 is just a random number i chose, prob no pets with less lines than 7
- if (event.toolTip.size() > 7) {
- if (Utils.cleanColour(event.toolTip.get(1)).matches(petToolTipRegex)) {
-
- GuiProfileViewer.PetLevel petlevel = null;
-
- //this is the item itself
- NBTTagCompound tag = event.itemStack.getTagCompound();
- if (tag.hasKey("ExtraAttributes")) {
- if (tag.getCompoundTag("ExtraAttributes").hasKey("petInfo")) {
- JsonObject petInfo = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(
- tag.getCompoundTag("ExtraAttributes").getString("petInfo"), JsonObject.class);
- if (petInfo.has("exp") && petInfo.get("exp").isJsonPrimitive()) {
- JsonPrimitive exp = petInfo.getAsJsonPrimitive("exp");
- String petName = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack);
- //Utils.getRarityFromInt(Utils.checkItemTypePet(event.toolTip))).getAsInt();
- petlevel = GuiProfileViewer.getPetLevel(
- petName,
- Utils.getRarityFromInt(Utils.checkItemTypePet(event.toolTip)),
- exp.getAsLong()
- );
- }
- }
- }
-
- if (petlevel != null) {
- tooltipText.add("");
- if (petlevel.totalXp > petlevel.maxXP) {
- tooltipText.add(EnumChatFormatting.AQUA + "" + EnumChatFormatting.BOLD + "MAX LEVEL");
- } else {
- tooltipText.add(
- EnumChatFormatting.GRAY + "Progress to Level " + (int) Math.floor(petlevel.level + 1) + ": " +
- EnumChatFormatting.YELLOW + Utils.round(petlevel.levelPercentage * 100, 1) + "%");
- int levelpercentage = Math.round(petlevel.levelPercentage * 20);
- tooltipText.add(
- EnumChatFormatting.DARK_GREEN + String.join("", Collections.nCopies(levelpercentage, "-")) +
- EnumChatFormatting.WHITE + String.join("", Collections.nCopies(20 - levelpercentage, "-")));
- tooltipText.add(
- EnumChatFormatting.GRAY + "EXP: " + EnumChatFormatting.YELLOW + myFormatter.format(petlevel.levelXp) +
- EnumChatFormatting.GOLD + "/" + EnumChatFormatting.YELLOW +
- myFormatter.format(petlevel.currentLevelRequirement) + " EXP");
- }
- }
- }
- }
- }
- return tooltipText;
- }
-
- private static final String petToolTipRegex =
- "((Farming)|(Combat)|(Fishing)|(Mining)|(Foraging)|(Enchanting)|(Alchemy)) ((Mount)|(Pet)|(Morph)).*";
-
- private void petToolTipXPExtendPetMenu(ItemTooltipEvent event) {
- if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.petExtendExp) {
- //7 is just a random number i chose, prob no pets with less lines than 7
- if (event.toolTip.size() > 7) {
- if (Utils.cleanColour(event.toolTip.get(1)).matches(petToolTipRegex)) {
- GuiProfileViewer.PetLevel petlevel = null;
-
- int xpLine = -1;
- for (int i = event.toolTip.size() - 1; i >= 0; i--) {
- Matcher matcher = xpLevelPattern.matcher(event.toolTip.get(i));
- if (matcher.matches()) {
- xpLine = i;
- event.toolTip.set(xpLine, matcher.group(1));
- break;
- } else if (event.toolTip.get(i).matches("MAX LEVEL")) {
- return;
- }
- }
-
- PetInfoOverlay.Pet pet = PetInfoOverlay.getPetFromStack(
- event.itemStack.getDisplayName(),
- NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(event.itemStack.getTagCompound())
- );
- if (pet == null) {
- return;
- }
- petlevel = pet.petLevel;
-
- if (petlevel == null || xpLine == -1) {
- return;
- }
-
- event.toolTip.add(
- xpLine + 1,
- EnumChatFormatting.GRAY + "EXP: " + EnumChatFormatting.YELLOW + myFormatter.format(petlevel.levelXp) +
- EnumChatFormatting.GOLD + "/" + EnumChatFormatting.YELLOW +
- myFormatter.format(petlevel.currentLevelRequirement)
- );
-
- }
- }
- }
- }
-
- DecimalFormat myFormatter = new DecimalFormat("###,###.###");
-
- /**
- * This method does the following:
- * Move the pet inventory display tooltip to the left to avoid conflicts
- * Remove reforge stats for Legendary items from Hypixel if enabled
- * Show NBT data when holding LCONTROL
- */
- @SubscribeEvent
- public void onItemTooltip(ItemTooltipEvent event) {
- if (!neu.isOnSkyblock()) return;
- if (event.toolTip == null) return;
- //Render the pet inventory display tooltip to the left to avoid things from other mods rendering over the tooltip
- if (event.itemStack.getTagCompound() != null && event.itemStack.getTagCompound().getBoolean("NEUPETINVDISPLAY")) {
- GlStateManager.translate(-200, 0, 0);
- }
-
- if (event.toolTip.size() > 2 && NotEnoughUpdates.INSTANCE.config.tooltipTweaks.hideDefaultReforgeStats) {
- String secondLine = StringUtils.stripControlCodes(event.toolTip.get(1));
- if (secondLine.equals("Reforge Stone")) {
- Integer startIndex = null;
- Integer cutoffIndex = null;
- //loop from the back of the List to find the wanted index sooner
- for (int i = event.toolTip.size() - 1; i >= 0; i--) {
- //rarity or mining level requirement
- String line = StringUtils.stripControlCodes(event.toolTip.get(i));
- if (line.contains("REFORGE STONE") || line.contains("Requires Mining Skill Level")) {
- cutoffIndex = i;
- }
-
- //The line where the Hypixel stats start
- if (line.contains("(Legendary):")) {
- startIndex = i;
- break;
- }
- }
- if (startIndex != null && cutoffIndex != null && startIndex < cutoffIndex) {
- event.toolTip.subList(startIndex, cutoffIndex).clear();
- }
- }
- }
-
- if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && NotEnoughUpdates.INSTANCE.config.hidden.dev &&
- event.toolTip.size() > 0 &&
- event.toolTip.get(event.toolTip.size() - 1).startsWith(EnumChatFormatting.DARK_GRAY + "NBT: ")) {
- event.toolTip.remove(event.toolTip.size() - 1);
-
- StringBuilder sb = new StringBuilder();
- String nbt = event.itemStack.getTagCompound().toString();
- int indent = 0;
- for (char c : nbt.toCharArray()) {
- boolean newline = false;
- if (c == '{' || c == '[') {
- indent++;
- newline = true;
- } else if (c == '}' || c == ']') {
- indent--;
- sb.append("\n");
- for (int i = 0; i < indent; i++) sb.append(" ");
- } else if (c == ',') {
- newline = true;
- } else if (c == '\"') {
- sb.append(EnumChatFormatting.RESET.toString() + EnumChatFormatting.GRAY);
- }
-
- sb.append(c);
- if (newline) {
- sb.append("\n");
- for (int i = 0; i < indent; i++) sb.append(" ");
- }
- }
- event.toolTip.add(sb.toString());
- if (Keyboard.isKeyDown(Keyboard.KEY_H)) {
- if (!copied) {
- copied = true;
- StringSelection selection = new StringSelection(sb.toString());
- Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
- }
- } else {
- copied = false;
- }
- } else if (NotEnoughUpdates.INSTANCE.packDevEnabled) {
- event.toolTip.add("");
- event.toolTip.add(EnumChatFormatting.AQUA + "NEU Pack Dev Info:");
- event.toolTip.add("Press " + EnumChatFormatting.GOLD + "[KEY]" + EnumChatFormatting.GRAY + " to copy line");
-
- String internal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack);
-
- boolean k = Keyboard.isKeyDown(Keyboard.KEY_K);
- boolean m = Keyboard.isKeyDown(Keyboard.KEY_M);
- boolean n = Keyboard.isKeyDown(Keyboard.KEY_N);
-
- event.toolTip.add(
- EnumChatFormatting.AQUA + "Internal Name: " + EnumChatFormatting.GRAY + internal + EnumChatFormatting.GOLD +
- " [K]");
- if (!copied && k) {
- MiscUtils.copyToClipboard(internal);
- }
-
- if (event.itemStack.getTagCompound() != null) {
- NBTTagCompound tag = event.itemStack.getTagCompound();
-
- if (tag.hasKey("SkullOwner", 10)) {
- GameProfile gameprofile = NBTUtil.readGameProfileFromNBT(tag.getCompoundTag("SkullOwner"));
-
- if (gameprofile != null) {
- event.toolTip.add(EnumChatFormatting.AQUA + "Skull UUID: " + EnumChatFormatting.GRAY + gameprofile.getId() +
- EnumChatFormatting.GOLD + " [M]");
- if (!copied && m) {
- MiscUtils.copyToClipboard(gameprofile.getId().toString());
- }
-
- Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map =
- Minecraft.getMinecraft().getSkinManager().loadSkinFromCache(gameprofile);
-
- if (map.containsKey(MinecraftProfileTexture.Type.SKIN)) {
- MinecraftProfileTexture profTex = map.get(MinecraftProfileTexture.Type.SKIN);
- event.toolTip.add(
- EnumChatFormatting.AQUA + "Skull Texture Link: " + EnumChatFormatting.GRAY + profTex.getUrl() +
- EnumChatFormatting.GOLD + " [N]");
-
- if (!copied && n) {
- MiscUtils.copyToClipboard(profTex.getUrl());
- }
- }
- }
- }
- }
-
- copied = k || m || n;
- }
- }
-
- @SubscribeEvent
- public void onRenderLast(RenderWorldLastEvent event) {
- CrystalMetalDetectorSolver.render(event.partialTicks);
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
index df31834f..598ecc2e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java
@@ -1,14 +1,46 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates;
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.auction.APIManager;
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent;
import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
import io.github.moulberry.notenoughupdates.miscgui.KatSitterOverlay;
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag;
import io.github.moulberry.notenoughupdates.recipes.CraftingOverlay;
import io.github.moulberry.notenoughupdates.recipes.CraftingRecipe;
import io.github.moulberry.notenoughupdates.recipes.Ingredient;
import io.github.moulberry.notenoughupdates.recipes.NeuRecipe;
-import io.github.moulberry.notenoughupdates.util.*;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.HotmInformation;
+import io.github.moulberry.notenoughupdates.util.ApiUtil;
+import io.github.moulberry.notenoughupdates.util.ItemResolutionQuery;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.init.Blocks;
@@ -16,23 +48,48 @@ import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.*;
+import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTException;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTTagString;
import net.minecraft.util.ResourceLocation;
-import net.minecraftforge.fml.common.ProgressManager;
import org.apache.commons.io.FileUtils;
import org.lwjgl.input.Keyboard;
-import org.lwjgl.opengl.Display;
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-import java.io.*;
+import javax.net.ssl.HttpsURLConnection;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Optional;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -43,6 +100,7 @@ public class NEUManager {
public final APIManager auctionManager;
private final TreeMap<String, JsonObject> itemMap = new TreeMap<>();
+ private boolean hasBeenLoadedBefore = false;
private final TreeMap<String, HashMap<String, List<Integer>>> titleWordMap = new TreeMap<>();
private final TreeMap<String, HashMap<String, List<Integer>>> loreWordMap = new TreeMap<>();
@@ -66,18 +124,10 @@ public class NEUManager {
public String viewItemAttemptID = null;
public long viewItemAttemptTime = 0;
- private final String currentProfile = "";
- private final String currentProfileBackup = "";
- public final HypixelApi hypixelApi = new HypixelApi();
+ public final ApiUtil apiUtils = new ApiUtil();
private final Map<String, ItemStack> itemstackCache = new HashMap<>();
- private final ExecutorService repoLoaderES = Executors.newSingleThreadExecutor();
-
- private static String GIT_COMMITS_URL;
-
- // TODO: private final Map<String, NeuItem>
-
private final Set<NeuRecipe> recipes = new HashSet<>();
private final HashMap<String, Set<NeuRecipe>> recipesMap = new HashMap<>();
private final HashMap<String, Set<NeuRecipe>> usagesMap = new HashMap<>();
@@ -101,8 +151,6 @@ public class NEUManager {
this.craftingOverlay = new CraftingOverlay(this);
this.katSitterOverlay = new KatSitterOverlay();
- GIT_COMMITS_URL = neu.config.hidden.repoCommitsURL;
-
gson = new GsonBuilder().setPrettyPrinting().create();
this.repoLocation = new File(configLocation, "repo");
@@ -159,186 +207,74 @@ public class NEUManager {
}
}
- /**
- * Called when the game is first loaded. Compares the local repository to the github repository and handles the
- * downloading of new/updated files. This then calls the "loadItem" method for every item in the local repository.
- */
- public void loadItemInformation() {
- /*File repoFile = new File(configLocation, "repo2");
- repoFile.mkdirs();
-
- try(Git git = Git.init().setDirectory(repoFile).call()) {
- StoredConfig config = git.getRepository().getConfig();
- config.setString("branch", "master", "merge", "refs/heads/master");
- config.setString("branch", "master", "remote", "origin");
- config.setString("remote", "origin", "fetch", "+refs/heads/*:refs/remotes/origin/*");
- config.setString("remote", "origin", "url", "https://github.com/Moulberry/NotEnoughUpdates-REPO.git");
- config.save();
-
- git.remoteAdd().setName("origin").setUri(new URIish("https://github.com/Moulberry/NotEnoughUpdates-REPO.git")).call();
- PullResult result = git.pull().setRemote("origin").setTimeout(30000).call();
- System.out.println("successful pull: " + result.isSuccessful());
- } catch(Exception e) {
- e.printStackTrace();
- }*/
-
- /*if(repoFile.mkdirs()) {
- try {
- Git.cloneRepository()
- .setURI("https://github.com/Moulberry/NotEnoughUpdates-REPO.git")
- .setDirectory(repoFile)
- .call();
- } catch(Exception e) {
- e.printStackTrace();
- }
- } else {
-
- }*/
-
- repoLoaderES.submit(() -> {
- JDialog dialog = null;
+ public CompletableFuture<Boolean> fetchRepository() {
+ return CompletableFuture.supplyAsync(() -> {
try {
- if (NotEnoughUpdates.INSTANCE.config.hidden.autoupdate) {
- JOptionPane pane = new JOptionPane("Getting items to download from remote repository.");
- dialog = pane.createDialog("NotEnoughUpdates Remote Sync");
- dialog.setModal(false);
- if (NotEnoughUpdates.INSTANCE.config.hidden.dev) dialog.setVisible(true);
-
- if (Display.isActive()) dialog.toFront();
-
- JsonObject currentCommitJSON = getJsonFromFile(new File(configLocation, "currentCommit.json"));
-
- latestRepoCommit = null;
- try (Reader inReader = new InputStreamReader(new URL(GIT_COMMITS_URL).openStream())) {
- JsonObject commits = gson.fromJson(inReader, JsonObject.class);
- latestRepoCommit = commits.get("sha").getAsString();
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (latestRepoCommit == null || latestRepoCommit.isEmpty()) return;
+ JsonObject currentCommitJSON = getJsonFromFile(new File(configLocation, "currentCommit.json"));
+
+ latestRepoCommit = null;
+ try (Reader inReader = new InputStreamReader(new URL(neu.config.apiData.getCommitApiUrl()).openStream())) {
+ JsonObject commits = gson.fromJson(inReader, JsonObject.class);
+ latestRepoCommit = commits.get("sha").getAsString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ if (latestRepoCommit == null || latestRepoCommit.isEmpty()) return false;
- if (new File(configLocation, "repo").exists() && new File(configLocation, "repo/items").exists()) {
- if (currentCommitJSON != null && currentCommitJSON.get("sha").getAsString().equals(latestRepoCommit)) {
- dialog.setVisible(false);
- return;
- }
+ if (new File(configLocation, "repo").exists() && new File(configLocation, "repo/items").exists()) {
+ if (currentCommitJSON != null && currentCommitJSON.get("sha").getAsString().equals(latestRepoCommit)) {
+ return false;
}
+ }
+ Utils.recursiveDelete(repoLocation);
+ repoLocation.mkdirs();
- if (Display.isActive()) dialog.toFront();
-
- Utils.recursiveDelete(repoLocation);
- repoLocation.mkdirs();
+ File itemsZip = new File(repoLocation, "neu-items-master.zip");
+ try {
+ itemsZip.createNewFile();
+ } catch (IOException e) {
+ return false;
+ }
- String dlUrl = neu.config.hidden.repoURL;
+ URL url = new URL(neu.config.apiData.getDownloadUrl(latestRepoCommit));
+ URLConnection urlConnection = url.openConnection();
+ urlConnection.setConnectTimeout(15000);
+ urlConnection.setReadTimeout(30000);
+
+ try (InputStream is = urlConnection.getInputStream()) {
+ FileUtils.copyInputStreamToFile(is, itemsZip);
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.err.println("Failed to download NEU Repo! Please report this issue to the mod creator");
+ return false;
+ }
- pane.setMessage("Downloading NEU Master Archive. (DL# >20)");
- dialog.pack();
- if (NotEnoughUpdates.INSTANCE.config.hidden.dev) dialog.setVisible(true);
- if (Display.isActive()) dialog.toFront();
+ unzipIgnoreFirstFolder(itemsZip.getAbsolutePath(), repoLocation.getAbsolutePath());
- File itemsZip = new File(repoLocation, "neu-items-master.zip");
+ if (currentCommitJSON == null || !currentCommitJSON.get("sha").getAsString().equals(latestRepoCommit)) {
+ JsonObject newCurrentCommitJSON = new JsonObject();
+ newCurrentCommitJSON.addProperty("sha", latestRepoCommit);
try {
- itemsZip.createNewFile();
- } catch (IOException e) {
- return;
- }
-
- URL url = new URL(dlUrl);
- URLConnection urlConnection = url.openConnection();
- urlConnection.setConnectTimeout(15000);
- urlConnection.setReadTimeout(30000);
-
- try (InputStream is = urlConnection.getInputStream()) {
- FileUtils.copyInputStreamToFile(is, itemsZip);
- } catch (IOException e) {
- dialog.dispose();
- e.printStackTrace();
- System.err.println("Failed to download NEU Repo! Please report this issue to the mod creator");
- return;
- }
- /*try (
- BufferedInputStream inStream = new BufferedInputStream(urlConnection.getInputStream());
- FileOutputStream fileOutputStream = new FileOutputStream(itemsZip)
- ) {
- byte dataBuffer[] = new byte[1024];
- int bytesRead;
- while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) {
- fileOutputStream.write(dataBuffer, 0, bytesRead);
- }
- } catch (IOException e) {
- dialog.dispose();
- return;
- }*/
-
- pane.setMessage("Unzipping NEU Master Archive.");
- dialog.pack();
- //dialog.setVisible(true);
- if (Display.isActive()) dialog.toFront();
-
- unzipIgnoreFirstFolder(itemsZip.getAbsolutePath(), repoLocation.getAbsolutePath());
-
- if (currentCommitJSON == null || !currentCommitJSON.get("sha").getAsString().equals(latestRepoCommit)) {
- JsonObject newCurrentCommitJSON = new JsonObject();
- newCurrentCommitJSON.addProperty("sha", latestRepoCommit);
- try {
- writeJson(newCurrentCommitJSON, new File(configLocation, "currentCommit.json"));
- } catch (IOException ignored) {
- }
+ writeJson(newCurrentCommitJSON, new File(configLocation, "currentCommit.json"));
+ } catch (IOException ignored) {
}
}
} catch (Exception e) {
e.printStackTrace();
- } finally {
- if (dialog != null) dialog.dispose();
- }
-
- File items = new File(repoLocation, "items");
- if (items.exists()) {
- File[] itemFiles = new File(repoLocation, "items").listFiles();
- if (itemFiles != null) {
- ProgressManager.ProgressBar bar = ProgressManager.push("Loading recipes", itemFiles.length);
- for (File f : itemFiles) {
- String internalname = f.getName().substring(0, f.getName().length() - 5);
- bar.step(internalname);
- synchronized (itemMap) {
- if (!itemMap.containsKey(internalname)) {
- loadItem(internalname);
- }
- }
- }
- ProgressManager.pop(bar);
- }
- }
-
- try {
- Constants.reload();
- } catch (Exception e) {
- e.printStackTrace();
}
+ return true;
});
+ }
- File items = new File(repoLocation, "items");
- if (items.exists()) {
- File[] itemFiles = new File(repoLocation, "items").listFiles();
- if (itemFiles != null) {
- ProgressManager.ProgressBar bar = ProgressManager.push("Loading items", itemFiles.length);
- for (File f : itemFiles) {
- String internalname = f.getName().substring(0, f.getName().length() - 5);
- bar.step(internalname);
- synchronized (itemMap) {
- if (!itemMap.containsKey(internalname)) {
- loadItem(internalname);
- }
- }
- }
- ProgressManager.pop(bar);
- }
- }
-
- try {
- Constants.reload();
- } catch (Exception e) {
- e.printStackTrace();
+ /**
+ * Called when the game is first loaded. Compares the local repository to the github repository and handles the
+ * downloading of new/updated files. This then calls the "loadItem" method for every item in the local repository.
+ */
+ public void loadItemInformation() {
+ if (NotEnoughUpdates.INSTANCE.config.apiData.autoupdate) {
+ fetchRepository().thenRun(this::reloadRepository);
+ } else {
+ reloadRepository();
}
}
@@ -435,6 +371,10 @@ public class NEUManager {
for (Ingredient input : recipe.getIngredients()) {
usagesMap.computeIfAbsent(input.getInternalItemId(), ignored -> new HashSet<>()).add(recipe);
}
+ for (Ingredient catalystItem : recipe.getCatalystItems()) {
+ recipesMap.computeIfAbsent(catalystItem.getInternalItemId(), ignored -> new HashSet<>()).add(recipe);
+ usagesMap.computeIfAbsent(catalystItem.getInternalItemId(), ignored -> new HashSet<>()).add(recipe);
+ }
}
public Set<NeuRecipe> getRecipesFor(String internalName) {
@@ -453,29 +393,94 @@ public class NEUManager {
return getUsagesFor(internalname).stream().filter(NeuRecipe::isAvailable).collect(Collectors.toList());
}
+ private static class DebugMatch {
+ int index;
+ String match;
+
+ DebugMatch(int index, String match) {
+ this.index = index;
+ this.match = match;
+ }
+ }
+
+
+ private String searchDebug(String[] searchArray, ArrayList<DebugMatch> debugMatches) {
+ //splitToSearch, debugMatches and query
+ final String ANSI_RED = "\u001B[31m";
+ final String ANSI_RESET = "\u001B[0m";
+ final String ANSI_YELLOW = "\u001B[33m";
+
+ //create debug message
+ StringBuilder debugBuilder = new StringBuilder();
+ for (int i = 0; i < searchArray.length; i++) {
+ final int fi = i;
+ Object[] matches = debugMatches.stream().filter((d) -> d.index == fi).toArray();
+
+ if (matches.length > 0) {
+ debugBuilder.append(ANSI_YELLOW + "[").append(((DebugMatch) matches[0]).match).append("]");
+ debugBuilder.append(ANSI_RED + "[").append(searchArray[i]).append("]").append(ANSI_RESET).append(" ");
+ } else {
+ debugBuilder.append(searchArray[i]).append(" ");
+ }
+ }
+
+ //yellow = query match and red = string match
+ return debugBuilder.toString();
+ }
+
/**
* Searches a string for a query. This method is used to mimic the behaviour of the more complex map-based search
* function. This method is used for the chest-item-search feature.
*/
public boolean searchString(String toSearch, String query) {
- int lastMatch = -1;
+ final String ANSI_RESET = "\u001B[0m";
+ final String ANSI_YELLOW = "\u001B[33m";
+
+ int lastStringMatch = -1;
+ ArrayList<DebugMatch> debugMatches = new ArrayList<>();
toSearch = clean(toSearch).toLowerCase();
query = clean(query).toLowerCase();
- String[] splitToSeach = toSearch.split(" ");
- out:
- for (String s : query.split(" ")) {
- for (int i = 0; i < splitToSeach.length; i++) {
- if (!(lastMatch == -1 || lastMatch == i - 1)) continue;
- if (splitToSeach[i].startsWith(s)) {
- lastMatch = i;
- continue out;
+ String[] splitToSearch = toSearch.split(" ");
+ String[] queryArray = query.split(" ");
+
+ {
+ String currentSearch = queryArray[0];
+ int queryIndex = 0;
+ boolean matchedLastQueryItem = false;
+
+ for (int k = 0; k < splitToSearch.length; k++) {
+ if (queryIndex - 1 != -1 && (queryArray.length - queryIndex) > (splitToSearch.length - k)) continue;
+ if (splitToSearch[k].startsWith(currentSearch)) {
+ if (((lastStringMatch != -1 ? lastStringMatch : k-1) == k-1)) {
+ debugMatches.add(new DebugMatch(k, currentSearch));
+ lastStringMatch = k;
+ if (queryIndex+1 != queryArray.length) {
+ queryIndex++;
+ currentSearch = queryArray[queryIndex];
+ } else {
+ matchedLastQueryItem = true;
+ }
+ }
+ } else if (queryIndex != 0) {
+ queryIndex = 0;
+ currentSearch = queryArray[queryIndex];
+ lastStringMatch = -1;
}
}
- return false;
- }
- return true;
+ if (matchedLastQueryItem) {
+ if (NEUDebugFlag.SEARCH.isSet()) {
+ NotEnoughUpdates.LOGGER.info("Found match for \"" + ANSI_YELLOW + query + ANSI_RESET + "\":\n\t" + searchDebug(splitToSearch, debugMatches));
+ }
+ } else {
+ if (NEUDebugFlag.SEARCH.isSet() && lastStringMatch != -1) {
+ NotEnoughUpdates.LOGGER.info("Found partial match for \"" + ANSI_YELLOW + query + ANSI_RESET + "\":\n\t" + searchDebug(splitToSearch, debugMatches));
+ }
+ }
+
+ return matchedLastQueryItem;
+ }
}
/**
@@ -723,82 +728,35 @@ public class NEUManager {
return uuid;
}
- public String getInternalnameFromNBT(NBTTagCompound tag) {
- String internalname = null;
- if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
- NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
-
- if (ea.hasKey("id", 8)) {
- internalname = ea.getString("id").replaceAll(":", "-");
- } else {
- return null;
- }
-
- if ("PET".equals(internalname)) {
- String petInfo = ea.getString("petInfo");
- if (petInfo.length() > 0) {
- JsonObject petInfoObject = gson.fromJson(petInfo, JsonObject.class);
- internalname = petInfoObject.get("type").getAsString();
- String tier = petInfoObject.get("tier").getAsString();
- switch (tier) {
- case "COMMON":
- internalname += ";0";
- break;
- case "UNCOMMON":
- internalname += ";1";
- break;
- case "RARE":
- internalname += ";2";
- break;
- case "EPIC":
- internalname += ";3";
- break;
- case "LEGENDARY":
- internalname += ";4";
- break;
- case "MYTHIC":
- internalname += ";5";
- break;
- }
- }
- }
- if ("ENCHANTED_BOOK".equals(internalname) && ea.hasKey("enchantments", 10)) {
- NBTTagCompound enchants = ea.getCompoundTag("enchantments");
-
- for (String enchname : enchants.getKeySet()) {
- internalname = enchname.toUpperCase() + ";" + enchants.getInteger(enchname);
- break;
- }
- }
- if ("RUNE".equals(internalname) && ea.hasKey("runes", 10)) {
- NBTTagCompound rune = ea.getCompoundTag("runes");
-
- for (String runename : rune.getKeySet()) {
- internalname = runename.toUpperCase() + "_RUNE" + ";" + rune.getInteger(runename);
- break;
- }
- }
- if ("PARTY_HAT_CRAB".equals(internalname) && (ea.getString("party_hat_color") != null)) {
- String crabhat = ea.getString("party_hat_color");
- internalname = "PARTY_HAT_CRAB" + "_" + crabhat.toUpperCase();
+ public String getSkullValueFromNBT(NBTTagCompound tag) {
+ if (tag != null && tag.hasKey("SkullOwner", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("SkullOwner");
+ NBTTagCompound ea3 = tag.getCompoundTag("display");
+
+ if (ea.hasKey("Properties", 10)) {
+ NBTTagCompound ea2 = ea;
+ ea = ea.getCompoundTag("Properties");
+ ea = ea.getTagList("textures", 10).getCompoundTagAt(0);
+ String name = ea3.getString("Name").replaceAll(" M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$", "");
+ return "put(\"ID\", Utils.createSkull(EnumChatFormatting.AQUA + \"" + name + "\" ,\"" + ea2.getString("Id") +
+ "\", \"" + ea.getString("Value") + "\"));";
}
}
+ return null;
+ }
- return internalname;
+ /**
+ * Replaced with {@link #createItemResolutionQuery()}
+ */
+ @Deprecated
+ public String getInternalnameFromNBT(NBTTagCompound tag) {
+ return createItemResolutionQuery()
+ .withItemNBT(tag)
+ .resolveInternalName();
}
public String[] getLoreFromNBT(NBTTagCompound tag) {
- String[] lore = new String[0];
- NBTTagCompound display = tag.getCompoundTag("display");
-
- if (display.hasKey("Lore", 9)) {
- NBTTagList list = display.getTagList("Lore", 8);
- lore = new String[list.tagCount()];
- for (int k = 0; k < list.tagCount(); k++) {
- lore[k] = list.getStringTagAt(k);
- }
- }
- return lore;
+ return ItemUtils.getLore(tag).toArray(new String[0]);
}
public JsonObject getJsonFromNBT(NBTTagCompound tag) {
@@ -826,14 +784,14 @@ public class NEUManager {
if (itemMc != null) {
itemid = itemMc.getRegistryName();
}
- String displayname = display.getString("Name");
+ String displayName = display.getString("Name");
String[] info = new String[0];
String clickcommand = "";
JsonObject item = new JsonObject();
item.addProperty("internalname", internalname);
item.addProperty("itemid", itemid);
- item.addProperty("displayname", displayname);
+ item.addProperty("displayname", displayName);
if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
@@ -894,12 +852,12 @@ public class NEUManager {
String clickcommand = item.get("clickcommand").getAsString();
switch (clickcommand.intern()) {
case "viewrecipe":
- displayGuiItemRecipe(internalName, null);
+ displayGuiItemRecipe(internalName);
break;
- case "viewoption":
+ case "viewpotion":
neu.sendChatMessage("/viewpotion " + internalName.split(";")[0].toLowerCase(Locale.ROOT));
}
- displayGuiItemRecipe(internalName, "");
+ displayGuiItemRecipe(internalName);
}
public void showRecipe(String internalName) {
@@ -952,10 +910,24 @@ public class NEUManager {
return json;
}
- public String getInternalNameForItem(ItemStack stack) {
+ public String getSkullValueForItem(ItemStack stack) {
if (stack == null) return null;
NBTTagCompound tag = stack.getTagCompound();
- return getInternalnameFromNBT(tag);
+ return getSkullValueFromNBT(tag);
+ }
+
+ public ItemResolutionQuery createItemResolutionQuery() {
+ return new ItemResolutionQuery(this);
+ }
+
+ /**
+ * Replaced with {@link #createItemResolutionQuery()}
+ */
+ @Deprecated
+ public String getInternalNameForItem(ItemStack stack) {
+ return createItemResolutionQuery()
+ .withItemStack(stack)
+ .resolveInternalName();
}
public String getUUIDForItem(ItemStack stack) {
@@ -988,17 +960,15 @@ public class NEUManager {
if (!usagesMap.containsKey(internalName)) return false;
List<NeuRecipe> usages = getAvailableUsagesFor(internalName);
if (usages.isEmpty()) return false;
- Minecraft.getMinecraft().displayGuiScreen(
- new GuiItemRecipe("Item Usages", usages, this));
+ NotEnoughUpdates.INSTANCE.openGui = (new GuiItemRecipe(usages, this));
return true;
}
- public boolean displayGuiItemRecipe(String internalName, String text) {
+ public boolean displayGuiItemRecipe(String internalName) {
if (!recipesMap.containsKey(internalName)) return false;
List<NeuRecipe> recipes = getAvailableRecipesFor(internalName);
if (recipes.isEmpty()) return false;
- Minecraft.getMinecraft().displayGuiScreen(
- new GuiItemRecipe(text != null ? text : "Item Recipe", recipes, this));
+ NotEnoughUpdates.INSTANCE.openGui = (new GuiItemRecipe(recipes, this));
return true;
}
@@ -1009,7 +979,7 @@ public class NEUManager {
public boolean failViewItem(String text) {
if (viewItemAttemptID != null && !viewItemAttemptID.isEmpty()) {
if (System.currentTimeMillis() - viewItemAttemptTime < 500) {
- return displayGuiItemRecipe(viewItemAttemptID, text);
+ return displayGuiItemRecipe(viewItemAttemptID);
}
}
return false;
@@ -1032,11 +1002,12 @@ public class NEUManager {
} catch (IOException e) {
return null;
}
- try (
- BufferedInputStream inStream = new BufferedInputStream(new URL(
- url + "?action=raw&templates=expand").openStream());
- FileOutputStream fileOutputStream = new FileOutputStream(f)
- ) {
+ try {
+ HttpsURLConnection con = (HttpsURLConnection) new URL(url + "?action=raw&templates=expand").openConnection();
+ con.setRequestMethod("GET");
+ con.setRequestProperty("User-Agent", "NotEnoughUpdates");
+ BufferedInputStream inStream = new BufferedInputStream(con.getInputStream());
+ FileOutputStream fileOutputStream = new FileOutputStream(f);
byte[] dataBuffer = new byte[1024];
int bytesRead;
while ((bytesRead = inStream.read(dataBuffer, 0, 1024)) != -1) {
@@ -1149,7 +1120,7 @@ public class NEUManager {
* json files representing skyblock item data.
*/
public JsonObject createItemJson(
- String internalname, String itemid, String displayname, String[] lore,
+ String internalname, String itemid, String displayName, String[] lore,
String crafttext, String infoType, String[] info,
String clickcommand, int damage, NBTTagCompound nbttag
) {
@@ -1157,7 +1128,7 @@ public class NEUManager {
new JsonObject(),
internalname,
itemid,
- displayname,
+ displayName,
lore,
crafttext,
infoType,
@@ -1169,7 +1140,7 @@ public class NEUManager {
}
public JsonObject createItemJson(
- JsonObject base, String internalname, String itemid, String displayname, String[] lore,
+ JsonObject base, String internalname, String itemid, String displayName, String[] lore,
String crafttext, String infoType, String[] info,
String clickcommand, int damage, NBTTagCompound nbttag
) {
@@ -1180,7 +1151,7 @@ public class NEUManager {
JsonObject json = gson.fromJson(gson.toJson(base, JsonObject.class), JsonObject.class);
json.addProperty("internalname", internalname);
json.addProperty("itemid", itemid);
- json.addProperty("displayname", displayname);
+ json.addProperty("displayname", displayName);
json.addProperty("crafttext", crafttext);
json.addProperty("clickcommand", clickcommand);
json.addProperty("damage", damage);
@@ -1206,14 +1177,14 @@ public class NEUManager {
}
public boolean writeItemJson(
- String internalname, String itemid, String displayname, String[] lore, String crafttext,
+ String internalname, String itemid, String displayName, String[] lore, String crafttext,
String infoType, String[] info, String clickcommand, int damage, NBTTagCompound nbttag
) {
return writeItemJson(
new JsonObject(),
internalname,
itemid,
- displayname,
+ displayName,
lore,
crafttext,
infoType,
@@ -1225,14 +1196,14 @@ public class NEUManager {
}
public boolean writeItemJson(
- JsonObject base, String internalname, String itemid, String displayname, String[] lore,
+ JsonObject base, String internalname, String itemid, String displayName, String[] lore,
String crafttext, String infoType, String[] info, String clickcommand, int damage, NBTTagCompound nbttag
) {
JsonObject json = createItemJson(
base,
internalname,
itemid,
- displayname,
+ displayName,
lore,
crafttext,
infoType,
@@ -1294,7 +1265,7 @@ public class NEUManager {
}
}
- public HashMap<String, String> getLoreReplacements(String petname, String tier, int level) {
+ public HashMap<String, String> getPetLoreReplacements(String petname, String tier, int level) {
JsonObject petnums = null;
if (petname != null && tier != null) {
petnums = Constants.PETNUMS;
@@ -1407,7 +1378,7 @@ public class NEUManager {
float statMax = entry.getValue().getAsFloat();
float statMin = min.get("statNums").getAsJsonObject().get(entry.getKey()).getAsFloat();
float val = statMin * minMix + statMax * maxMix;
- String statStr = (statMin > 0 ? "+" : "") + (int) Math.floor(val);
+ String statStr = (statMin > 0 ? "+" : "") + removeUnusedDecimal(Math.floor(val * 10) / 10);
replacements.put(entry.getKey(), statStr);
}
}
@@ -1419,7 +1390,7 @@ public class NEUManager {
return replacements;
}
- public HashMap<String, String> getLoreReplacements(NBTTagCompound tag, int level) {
+ public HashMap<String, String> getPetLoreReplacements(NBTTagCompound tag, int level) {
String petname = null;
String tier = null;
if (tag != null && tag.hasKey("ExtraAttributes")) {
@@ -1453,7 +1424,7 @@ public class NEUManager {
}
}
}
- return getLoreReplacements(petname, tier, level);
+ return getPetLoreReplacements(petname, tier, level);
}
public NBTTagList processLore(JsonArray lore, HashMap<String, String> replacements) {
@@ -1484,6 +1455,7 @@ public class NEUManager {
}
public ItemStack jsonToStack(JsonObject json, boolean useCache, boolean useReplacements, boolean copyStack) {
+ if (useReplacements) useCache = false;
if (json == null) return new ItemStack(Items.painting, 1, 10);
String internalname = json.get("internalname").getAsString();
@@ -1523,13 +1495,13 @@ public class NEUManager {
HashMap<String, String> replacements = new HashMap<>();
if (useReplacements) {
- replacements = getLoreReplacements(stack.getTagCompound(), -1);
+ replacements = getPetLoreReplacements(stack.getTagCompound(), -1);
- String displayname = json.get("displayname").getAsString();
+ String displayName = json.get("displayname").getAsString();
for (Map.Entry<String, String> entry : replacements.entrySet()) {
- displayname = displayname.replace("{" + entry.getKey() + "}", entry.getValue());
+ displayName = displayName.replace("{" + entry.getKey() + "}", entry.getValue());
}
- stack.setStackDisplayName(displayname);
+ stack.setStackDisplayName(displayName);
}
if (json.has("lore")) {
@@ -1552,20 +1524,73 @@ public class NEUManager {
}
}
- public void reloadRepository() {
- File items = new File(repoLocation, "items");
- if (items.exists()) {
- recipes.clear();
- recipesMap.clear();
- usagesMap.clear();
+ public CompletableFuture<List<String>> userFacingRepositoryReload() {
+ String lastCommit = NotEnoughUpdates.INSTANCE.manager.latestRepoCommit;
+ NotEnoughUpdates.INSTANCE.manager.resetRepo();
+ return NotEnoughUpdates.INSTANCE.manager
+ .fetchRepository()
+ .thenCompose(ignored -> NotEnoughUpdates.INSTANCE.manager.reloadRepository())
+ .thenApply(ignored -> {
+ String newCommitHash = NotEnoughUpdates.INSTANCE.manager.latestRepoCommit;
+ String newCommitShortHash = (newCommitHash == null ? "MISSING" : newCommitHash.substring(0, 7));
+ return Arrays.asList(
+ "§aRepository reloaded.",
+ (lastCommit == null
+ ? "§eYou downloaded the repository version §b" + newCommitShortHash + "§e."
+ : "§eYou updated your repository from §b" + lastCommit.substring(0, 7) + "§e to §b" +
+ newCommitShortHash + "§e."
+ )
+ );
+ })
+ .exceptionally(ex -> {
+ ex.printStackTrace();
+ return Arrays.asList(
+ "§cRepository not fully reloaded.",
+ "§cThere was an error reloading your repository.",
+ "§cThis might be caused by an outdated version of neu",
+ "§c(or by not using the dangerous repository if you are using a prerelease of neu).",
+ "§aYour repository will still work, but is in a suboptimal state.",
+ "§eJoin §bdiscord.gg/moulberry §efor help."
+ );
+ });
+ }
- File[] itemFiles = new File(repoLocation, "items").listFiles();
- if (itemFiles != null) {
- for (File f : itemFiles) {
- String internalname = f.getName().substring(0, f.getName().length() - 5);
- loadItem(internalname);
+ public CompletableFuture<Void> reloadRepository() {
+ CompletableFuture<Void> comp = new CompletableFuture<>();
+ Minecraft.getMinecraft().addScheduledTask(() -> {
+ try {
+ File items = new File(repoLocation, "items");
+ if (items.exists()) {
+ recipes.clear();
+ recipesMap.clear();
+ usagesMap.clear();
+
+ File[] itemFiles = new File(repoLocation, "items").listFiles();
+ if (itemFiles != null) {
+ for (File f : itemFiles) {
+ String internalname = f.getName().substring(0, f.getName().length() - 5);
+ loadItem(internalname);
+ }
+ }
}
+
+ new RepositoryReloadEvent(repoLocation, !hasBeenLoadedBefore).post();
+ hasBeenLoadedBefore = true;
+ comp.complete(null);
+ } catch (Exception e) {
+ comp.completeExceptionally(e);
}
- }
+ });
+ return comp;
+ }
+
+ public ItemStack createItem(String internalName) {
+ return createItemResolutionQuery()
+ .withKnownInternalName(internalName)
+ .resolveToItemStack();
+ }
+
+ public boolean isValidInternalName(String internalName) {
+ return itemMap.containsKey(internalName);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
index d1bfed14..14078069 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates;
import com.google.common.collect.Lists;
@@ -16,23 +35,27 @@ import io.github.moulberry.notenoughupdates.mbgui.MBAnchorPoint;
import io.github.moulberry.notenoughupdates.mbgui.MBGuiElement;
import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroupAligned;
import io.github.moulberry.notenoughupdates.mbgui.MBGuiGroupFloating;
-import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
import io.github.moulberry.notenoughupdates.miscfeatures.SunTzu;
import io.github.moulberry.notenoughupdates.miscgui.GuiPriceGraph;
+import io.github.moulberry.notenoughupdates.miscgui.NeuSearchCalculator;
import io.github.moulberry.notenoughupdates.options.NEUConfigEditor;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.GuiTextures;
import io.github.moulberry.notenoughupdates.util.LerpingFloat;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
import io.github.moulberry.notenoughupdates.util.SpecialColour;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
-import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
-import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.gui.inventory.GuiContainer;
-import net.minecraft.client.gui.inventory.GuiInventory;
-import net.minecraft.client.renderer.*;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.OpenGlHelper;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
@@ -43,8 +66,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.init.Items;
-import net.minecraft.inventory.ContainerChest;
-import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@@ -62,82 +83,61 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.vector.Vector2f;
-import java.awt.Color;
+import java.awt.*;
import java.lang.reflect.InvocationTargetException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.*;
-
public class NEUOverlay extends Gui {
- private static final ResourceLocation SUPERGEHEIMNISVERMOGEN =
- new ResourceLocation("notenoughupdates:supersecretassets/bald.png");
+ private static final ResourceLocation SUPERGEHEIMNISVERMOGEN = new ResourceLocation(
+ "notenoughupdates:supersecretassets/bald.png");
+
+ private static final ResourceLocation ATMOULBERRYWHYISMYLUNARCLIENTBUGGING = new ResourceLocation(
+ "notenoughupdates:supersecretassets/lunar.png");
private static final ResourceLocation SEARCH_BAR = new ResourceLocation("notenoughupdates:search_bar.png");
private static final ResourceLocation SEARCH_BAR_GOLD = new ResourceLocation("notenoughupdates:search_bar_gold.png");
- private static final ResourceLocation ARMOR_DISPLAY =
- new ResourceLocation("notenoughupdates:armordisplay/armordisplay.png");
- private static final ResourceLocation ARMOR_DISPLAY_GREY =
- new ResourceLocation("notenoughupdates:armordisplay/armordisplay_grey.png");
- private static final ResourceLocation ARMOR_DISPLAY_DARK =
- new ResourceLocation("notenoughupdates:armordisplay/armordisplay_phq_dark.png");
- private static final ResourceLocation ARMOR_DISPLAY_FSR =
- new ResourceLocation("notenoughupdates:armordisplay/armordisplay_fsr.png");
- private static final ResourceLocation ARMOR_DISPLAY_TRANSPARENT =
- new ResourceLocation("notenoughupdates:armordisplay/armordisplay_transparent.png");
- private static final ResourceLocation ARMOR_DISPLAY_TRANSPARENT_PET =
- new ResourceLocation("notenoughupdates:armordisplay/armordisplay_transparent_pet.png");
-
- private static final ResourceLocation QUESTION_MARK = new ResourceLocation("notenoughupdates:pv_unknown.png");
-
- private static final ResourceLocation PET_DISPLAY =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplaysolo.png");
- private static final ResourceLocation PET_DISPLAY_GREY =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplaysolo_dark.png");
- private static final ResourceLocation PET_DISPLAY_DARK =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplaysolo_phqdark.png");
- private static final ResourceLocation PET_DISPLAY_FSR =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplaysolo_fsr.png");
- private static final ResourceLocation PET_DISPLAY_TRANSPARENT =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplaysolo_transparent.png");
-
- private static final ResourceLocation PET_ARMOR_DISPLAY =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplayarmor.png");
- private static final ResourceLocation PET_ARMOR_DISPLAY_GREY =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplayarmor_dark.png");
- private static final ResourceLocation PET_ARMOR_DISPLAY_DARK =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplayarmor_phqdark.png");
- private static final ResourceLocation PET_ARMOR_DISPLAY_FSR =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplayarmor_fsr.png");
- private static final ResourceLocation PET_ARMOR_DISPLAY_TRANSPARENT =
- new ResourceLocation("notenoughupdates:petdisplay/petdisplayarmor_transparent.png");
-
- private static boolean renderingArmorHud;
- private static boolean renderingPetHud;
- public static boolean shouldUseCachedPet;
- public static long cachedPetTimer;
-
private final NEUManager manager;
- private final String mobRegex = ".*?((_MONSTER)|(_ANIMAL)|(_MINIBOSS)|(_BOSS)|(_SC))$";
+ private final String mobRegex = ".*?((_MONSTER)|(_NPC)|(_ANIMAL)|(_MINIBOSS)|(_BOSS)|(_SC))$";
private final String petRegex = ".*?;[0-5]$";
private final ResourceLocation[] sortIcons = new ResourceLocation[]{
- sort_all, sort_mob, sort_pet, sort_tool, sort_armor, sort_accessory
+ GuiTextures.sort_all,
+ GuiTextures.sort_mob,
+ GuiTextures.sort_pet,
+ GuiTextures.sort_tool,
+ GuiTextures.sort_armor,
+ GuiTextures.sort_accessory
};
private final ResourceLocation[] sortIconsActive = new ResourceLocation[]{
- sort_all_active, sort_mob_active, sort_pet_active, sort_tool_active, sort_armor_active, sort_accessory_active
+ GuiTextures.sort_all_active,
+ GuiTextures.sort_mob_active,
+ GuiTextures.sort_pet_active,
+ GuiTextures.sort_tool_active,
+ GuiTextures.sort_armor_active,
+ GuiTextures.sort_accessory_active
};
private final ResourceLocation[] orderIcons = new ResourceLocation[]{
- order_alphabetical, order_rarity, order_value
+ GuiTextures.order_alphabetical, GuiTextures.order_rarity, GuiTextures.order_value
};
private final ResourceLocation[] orderIconsActive = new ResourceLocation[]{
- order_alphabetical_active, order_rarity_active, order_value_active
+ GuiTextures.order_alphabetical_active, GuiTextures.order_rarity_active, GuiTextures.order_value_active
};
//Various constants used for GUI structure
@@ -166,6 +166,7 @@ public class NEUOverlay extends Gui {
private List<JsonObject> selectedItemGroup = null;
private boolean itemPaneOpen = false;
+ private long itemPaneShouldOpen = -1;
private int page = 0;
@@ -186,8 +187,8 @@ public class NEUOverlay extends Gui {
private boolean redrawItems = false;
- private boolean searchBarHasFocus = false;
- private final GuiTextField textField = new GuiTextField(0, null, 0, 0, 0, 0);
+ public static boolean searchBarHasFocus = false;
+ private static final GuiTextField textField = new GuiTextField(0, null, 0, 0, 0, 0);
private static final int COMPARE_MODE_ALPHABETICAL = 0;
private static final int COMPARE_MODE_RARITY = 1;
@@ -241,15 +242,17 @@ public class NEUOverlay extends Gui {
}
if (Mouse.getEventButtonState()) {
setSearchBarFocus(true);
+
if (Mouse.getEventButton() == 1) { //Right mouse button down
textField.setText("");
updateSearch();
} else {
if (System.currentTimeMillis() - millisLastLeftClick < 300) {
searchMode = !searchMode;
+ itemPaneShouldOpen = -1;
lastSearchMode = System.currentTimeMillis();
if (searchMode && NotEnoughUpdates.INSTANCE.config.hidden.firstTimeSearchFocus) {
- NEUEventListener.displayNotification(Lists.newArrayList(
+ NotificationHandler.displayNotification(Lists.newArrayList(
"\u00a7eSearch Highlight",
"\u00a77In this mode NEU will gray out non matching items in",
"\u00a77your inventory or chests.",
@@ -328,7 +331,7 @@ public class NEUOverlay extends Gui {
}
//Search bar text
- fr.drawString(textField.getText(), (int) x + 5,
+ fr.drawString(NeuSearchCalculator.format(textField.getText()), (int) x + 5,
(int) y - 4 + getHeight() / 2, Color.WHITE.getRGB()
);
@@ -366,8 +369,7 @@ public class NEUOverlay extends Gui {
}
@Override
- public void recalculate() {
- }
+ public void recalculate() {}
};
}
@@ -384,8 +386,7 @@ public class NEUOverlay extends Gui {
}
@Override
- public void recalculate() {
- }
+ public void recalculate() {}
@Override
public void mouseClick(float x, float y, int mouseX, int mouseY) {
@@ -398,8 +399,7 @@ public class NEUOverlay extends Gui {
}
@Override
- public void mouseClickOutside() {
- }
+ public void mouseClickOutside() {}
@Override
public void render(float x, float y) {
@@ -409,13 +409,13 @@ public class NEUOverlay extends Gui {
if (!NotEnoughUpdates.INSTANCE.config.toolbar.enableSettingsButton) {
return;
}
- Minecraft.getMinecraft().getTextureManager().bindTexture(quickcommand_background);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.quickcommand_background);
GlStateManager.color(1, 1, 1, 1);
Utils.drawTexturedRect(x, y,
searchYSize + paddingUnscaled * 2, searchYSize + paddingUnscaled * 2, GL11.GL_NEAREST
);
- Minecraft.getMinecraft().getTextureManager().bindTexture(settings);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.settings);
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect((int) x + paddingUnscaled, (int) y + paddingUnscaled,
searchYSize, searchYSize
@@ -439,8 +439,7 @@ public class NEUOverlay extends Gui {
}
@Override
- public void recalculate() {
- }
+ public void recalculate() {}
@Override
public void mouseClick(float x, float y, int mouseX, int mouseY) {
@@ -457,8 +456,7 @@ public class NEUOverlay extends Gui {
}
@Override
- public void mouseClickOutside() {
- }
+ public void mouseClickOutside() {}
@Override
public void render(float x, float y) {
@@ -469,13 +467,13 @@ public class NEUOverlay extends Gui {
return;
}
- Minecraft.getMinecraft().getTextureManager().bindTexture(quickcommand_background);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.quickcommand_background);
GlStateManager.color(1, 1, 1, 1);
Utils.drawTexturedRect(x, y,
searchYSize + paddingUnscaled * 2, searchYSize + paddingUnscaled * 2, GL11.GL_NEAREST
);
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.help);
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect((int) x + paddingUnscaled, (int) y + paddingUnscaled,
getSearchBarYSize(), getSearchBarYSize()
@@ -499,16 +497,15 @@ public class NEUOverlay extends Gui {
}
@Override
- public void recalculate() {
- }
+ public void recalculate() {}
@Override
public void mouseClick(float x, float y, int mouseX, int mouseY) {
if (!NotEnoughUpdates.INSTANCE.config.toolbar.quickCommands) return;
+ if (EnchantingSolvers.disableButtons()) return;
if ((NotEnoughUpdates.INSTANCE.config.toolbar.quickCommandsClickType != 0 && Mouse.getEventButtonState()) ||
- (NotEnoughUpdates.INSTANCE.config.toolbar.quickCommandsClickType == 0 &&
- !Mouse.getEventButtonState() &&
+ (NotEnoughUpdates.INSTANCE.config.toolbar.quickCommandsClickType == 0 && !Mouse.getEventButtonState() &&
Mouse.getEventButton() != -1)) {
if (quickCommandStr.contains(":")) {
String command = quickCommandStr.split(":")[0].trim();
@@ -523,12 +520,12 @@ public class NEUOverlay extends Gui {
}
@Override
- public void mouseClickOutside() {
- }
+ public void mouseClickOutside() {}
@Override
public void render(float x, float y) {
if (!NotEnoughUpdates.INSTANCE.config.toolbar.quickCommands) return;
+ if (EnchantingSolvers.disableButtons()) return;
int paddingUnscaled = getPaddingUnscaled();
int bigItemSize = getSearchBarYSize();
@@ -574,7 +571,7 @@ public class NEUOverlay extends Gui {
tag.setString("qc_id", quickCommandStrSplit[0].toLowerCase().trim());
render.setTagCompound(tag);
- Minecraft.getMinecraft().getTextureManager().bindTexture(quickcommand_background);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.quickcommand_background);
GlStateManager.color(1, 1, 1, 1);
Utils.drawTexturedRect(x, y,
bigItemSize + paddingUnscaled * 2, bigItemSize + paddingUnscaled * 2, GL11.GL_NEAREST
@@ -582,8 +579,7 @@ public class NEUOverlay extends Gui {
int mouseX = Mouse.getX() * Utils.peekGuiScale().getScaledWidth() / Minecraft.getMinecraft().displayWidth;
int mouseY = Utils.peekGuiScale().getScaledHeight() -
- Mouse.getY() * Utils.peekGuiScale().getScaledHeight() / Minecraft.getMinecraft().displayHeight -
- 1;
+ Mouse.getY() * Utils.peekGuiScale().getScaledHeight() / Minecraft.getMinecraft().displayHeight - 1;
if (mouseX > x && mouseX < x + bigItemSize) {
if (mouseY > y && mouseY < y + bigItemSize) {
@@ -619,8 +615,11 @@ public class NEUOverlay extends Gui {
}
private MBGuiGroupAligned createSearchBarGroup() {
- List<MBGuiElement> children =
- Lists.newArrayList(createSettingsButton(this), createSearchBar(), createHelpButton(this));
+ List<MBGuiElement> children = Lists.newArrayList(
+ createSettingsButton(this),
+ createSearchBar(),
+ createHelpButton(this)
+ );
return new MBGuiGroupAligned(children, false) {
public int getPadding() {
return getPaddingUnscaled() * 4;
@@ -714,19 +713,33 @@ public class NEUOverlay extends Gui {
public void showInfo(JsonObject item) {
if (item.has("info") && item.has("infoType")) {
JsonArray lore = item.get("info").getAsJsonArray();
- StringBuilder loreBuilder = new StringBuilder();
- for (int i = 0; i < lore.size(); i++) {
- loreBuilder.append(lore.get(i).getAsString());
- if (i != lore.size() - 1)
- loreBuilder.append("\n");
+ String infoType = item.get("infoType").getAsString();
+ String infoText = "";
+ if (infoType.equals("WIKI_URL")) {
+ for (JsonElement url : lore) {
+ infoText = url.getAsString();
+ if (
+ url.getAsString().startsWith("https://wiki.hypixel.net/") && NotEnoughUpdates.INSTANCE.config.misc.wiki == 0
+ || url.getAsString().startsWith("https://hypixel-skyblock.fandom.com/") &&
+ NotEnoughUpdates.INSTANCE.config.misc.wiki == 1) break;
+ }
+ } else {
+ StringBuilder loreBuilder = new StringBuilder();
+ for (int i = 0; i < lore.size(); i++) {
+ loreBuilder.append(lore.get(i).getAsString());
+ if (i != lore.size() - 1)
+ loreBuilder.append("\n");
+ }
+ infoText = loreBuilder.toString();
}
- String infoText = loreBuilder.toString();
String internalname = item.get("internalname").getAsString();
String name = item.get("displayname").getAsString();
- String infoType = item.get("infoType").getAsString();
- displayInformationPane(new TextInfoPane(this, manager, "Loading", "Loading your requested information about " +
- name +
- "."));
+ displayInformationPane(new TextInfoPane(
+ this,
+ manager,
+ EnumChatFormatting.GRAY + "Loading",
+ EnumChatFormatting.GRAY + "Loading your requested information about " + name + EnumChatFormatting.GRAY + "."
+ ));
infoPaneLoadingJob = InfoPane.create(this, manager, infoType, name, internalname, infoText)
.thenAccept(this::displayInformationPane);
}
@@ -740,7 +753,9 @@ public class NEUOverlay extends Gui {
if (slot != null) {
ItemStack hover = slot.getStack();
if (hover != null) {
- textField.setText("id:" + manager.getInternalNameForItem(hover));
+ if (manager.getInternalNameForItem(hover) != null) {
+ textField.setText("id:" + manager.getInternalNameForItem(hover));
+ }
itemPaneOpen = true;
updateSearch();
}
@@ -752,7 +767,7 @@ public class NEUOverlay extends Gui {
/**
* Handles the mouse input, cancelling the forge event if a NEU gui element is clicked.
*/
- public boolean mouseInput() {
+ public synchronized boolean mouseInput() {
if (disabled) {
return false;
}
@@ -785,6 +800,10 @@ public class NEUOverlay extends Gui {
if (selectedItemGroup != null) {
int selectedX = Math.min(selectedItemGroupX, width - getBoxPadding() - 18 * selectedItemGroup.size());
if (mouseY > selectedItemGroupY + 17 && mouseY < selectedItemGroupY + 35) {
+ if (!Mouse.getEventButtonState()) {
+ Utils.pushGuiScale(-1);
+ return true; //End early if the mouse isn't pressed, but still cancel event.
+ }
for (int i = 0; i < selectedItemGroup.size(); i++) {
if (mouseX >= selectedX - 1 + 18 * i && mouseX <= selectedX + 17 + 18 * i) {
JsonObject item = selectedItemGroup.get(i);
@@ -941,7 +960,7 @@ public class NEUOverlay extends Gui {
return paddingUnscaled;
}
- public GuiTextField getTextField() {
+ public static GuiTextField getTextField() {
return textField;
}
@@ -1006,7 +1025,6 @@ public class NEUOverlay extends Gui {
*/
public boolean keyboardInput(boolean hoverInv) {
if (Minecraft.getMinecraft().currentScreen == null) return false;
- Keyboard.enableRepeatEvents(true);
int keyPressed = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
@@ -1062,7 +1080,7 @@ public class NEUOverlay extends Gui {
internalname.set(manager.getInternalNameForItem(hover));
itemstack.set(hover);
}
- } else if (!hoverInv) {
+ } else {
Utils.pushGuiScale(NotEnoughUpdates.INSTANCE.config.itemlist.paneGuiScale);
int width = Utils.peekGuiScale().getScaledWidth();
@@ -1097,9 +1115,10 @@ public class NEUOverlay extends Gui {
}
if (internalname.get() != null) {
if (itemstack.get() != null) {
- if (NotEnoughUpdates.INSTANCE.config.hidden.enableItemEditing && Keyboard.getEventCharacter() == 'k') {
- Minecraft.getMinecraft().displayGuiScreen(new NEUItemEditor(manager,
- internalname.get(), manager.getJsonForItem(itemstack.get())
+ if (NotEnoughUpdates.INSTANCE.config.apiData.repositoryEditing && Keyboard.getEventCharacter() == 'k') {
+ Minecraft.getMinecraft().displayGuiScreen(new NEUItemEditor(
+ internalname.get(),
+ manager.getJsonForItem(itemstack.get())
));
return true;
}
@@ -1120,11 +1139,9 @@ public class NEUOverlay extends Gui {
Minecraft.getMinecraft().thePlayer.inventory.addItemStackToInventory(
manager.jsonToStack(item));
}
- } else if (NotEnoughUpdates.INSTANCE.config.hidden.enableItemEditing &&
+ } else if (NotEnoughUpdates.INSTANCE.config.apiData.repositoryEditing &&
Keyboard.getEventCharacter() == 'k') {
- Minecraft.getMinecraft().displayGuiScreen(new NEUItemEditor(manager,
- internalname.get(), item
- ));
+ Minecraft.getMinecraft().displayGuiScreen(new NEUItemEditor(internalname.get(), item));
return true;
} else if (keyPressed == manager.keybindItemSelect.getKeyCode() &&
NotEnoughUpdates.INSTANCE.config.toolbar.searchBar) {
@@ -1153,40 +1170,6 @@ public class NEUOverlay extends Gui {
updateSearch();
}
- String[] rarityArr = new String[]{
- EnumChatFormatting.WHITE + EnumChatFormatting.BOLD.toString() + "COMMON",
- EnumChatFormatting.GREEN + EnumChatFormatting.BOLD.toString() + "UNCOMMON",
- EnumChatFormatting.BLUE + EnumChatFormatting.BOLD.toString() + "RARE",
- EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.BOLD.toString() + "EPIC",
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD.toString() + "LEGENDARY",
- EnumChatFormatting.LIGHT_PURPLE + EnumChatFormatting.BOLD.toString() + "MYTHIC",
- EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "SPECIAL",
- };
-
- /**
- * Finds the rarity from the lore of an item.
- * -1 = UNKNOWN
- * 0 = COMMON
- * 1 = UNCOMMON
- * 2 = RARE
- * 3 = EPIC
- * 4 = LEGENDARY
- * 5 = MYTHIC
- * 6 = SPECIAL
- */
- public int getRarity(JsonArray lore) {
- for (int i = lore.size() - 1; i >= 0; i--) {
- String line = lore.get(i).getAsString();
-
- for (int j = 0; j < rarityArr.length; j++) {
- if (line.startsWith(rarityArr[j])) {
- return j;
- }
- }
- }
- return -1;
- }
-
/**
* Convenience functions that get various compare/sort modes from the config.
*/
@@ -1214,19 +1197,21 @@ public class NEUOverlay extends Gui {
return (o1, o2) -> {
//1 (mult) if o1 should appear after o2
//-1 (-mult) if o2 should appear after o1
- if (getFavourites().contains(o1.get("internalname").getAsString()) &&
- !getFavourites().contains(o2.get("internalname").getAsString())) {
+ if (getFavourites().contains(o1.get("internalname").getAsString()) && !getFavourites().contains(o2
+ .get("internalname")
+ .getAsString())) {
return -1;
}
- if (!getFavourites().contains(o1.get("internalname").getAsString()) &&
- getFavourites().contains(o2.get("internalname").getAsString())) {
+ if (!getFavourites().contains(o1.get("internalname").getAsString()) && getFavourites().contains(o2
+ .get("internalname")
+ .getAsString())) {
return 1;
}
int mult = getCompareAscending().get(getCompareMode()) ? 1 : -1;
if (getCompareMode() == COMPARE_MODE_RARITY) {
- int rarity1 = getRarity(o1.get("lore").getAsJsonArray());
- int rarity2 = getRarity(o2.get("lore").getAsJsonArray());
+ int rarity1 = Utils.getRarityFromLore(o1.get("lore").getAsJsonArray());
+ int rarity2 = Utils.getRarityFromLore(o2.get("lore").getAsJsonArray());
if (rarity1 < rarity2) return mult;
if (rarity1 > rarity2) return -mult;
@@ -1234,8 +1219,8 @@ public class NEUOverlay extends Gui {
String internal1 = o1.get("internalname").getAsString();
String internal2 = o2.get("internalname").getAsString();
- float cost1 = manager.auctionManager.getLowestBin(internal1);
- float cost2 = manager.auctionManager.getLowestBin(internal2);
+ double cost1 = manager.auctionManager.getBazaarOrBin(internal1);
+ double cost2 = manager.auctionManager.getBazaarOrBin(internal2);
if (cost1 < cost2) return mult;
if (cost1 > cost2) return -mult;
@@ -1280,7 +1265,7 @@ public class NEUOverlay extends Gui {
for (int i = lore.size() - 1; i >= 0; i--) {
String line = lore.get(i).getAsString();
- for (String rarity : rarityArr) {
+ for (String rarity : Utils.rarityArrC) {
for (int j = 0; j < typeMatches.length; j++) {
if (line.trim().equals(rarity + " " + typeMatches[j])) {
return j;
@@ -1295,14 +1280,13 @@ public class NEUOverlay extends Gui {
* Checks whether an item matches the current sort mode.
*/
public boolean checkMatchesSort(String internalname, JsonObject item) {
- if (!NotEnoughUpdates.INSTANCE.config.itemlist.showVanillaItems &&
- item.has("vanilla") &&
+ if (!NotEnoughUpdates.INSTANCE.config.itemlist.showVanillaItems && item.has("vanilla") &&
item.get("vanilla").getAsBoolean()) {
return false;
}
if (getSortMode() == SORT_MODE_ALL) {
- return !internalname.matches(mobRegex);
+ return NotEnoughUpdates.INSTANCE.config.itemlist.alwaysShowMonsters || !internalname.matches(mobRegex);
} else if (getSortMode() == SORT_MODE_MOB) {
return internalname.matches(mobRegex);
} else if (getSortMode() == SORT_MODE_PET) {
@@ -1321,13 +1305,13 @@ public class NEUOverlay extends Gui {
"DUNGEON SWORD",
"DUNGEON BOW",
"DRILL",
- "GAUNTLET"
+ "GAUNTLET",
+ "LONGSWORD",
+ "DEPLOYABLE"
) >= 0;
} else if (getSortMode() == SORT_MODE_ARMOR) {
return checkItemType(
- item
- .get("lore")
- .getAsJsonArray(),
+ item.get("lore").getAsJsonArray(),
"HELMET",
"CHESTPLATE",
"LEGGINGS",
@@ -1335,9 +1319,13 @@ public class NEUOverlay extends Gui {
"DUNGEON HELMET",
"DUNGEON CHESTPLATE",
"DUNGEON LEGGINGS",
- "DUNGEON BOOTS"
- ) >=
- 0;
+ "DUNGEON BOOTS",
+ "BELT",
+ "GLOVES",
+ "CLOAK",
+ "NECKLACE",
+ "BRACELET"
+ ) >= 0;
} else if (getSortMode() == SORT_MODE_ACCESSORY) {
return checkItemType(item.get("lore").getAsJsonArray(), "ACCESSORY", "HATCCESSORY", "DUNGEON ACCESSORY") >= 0;
}
@@ -1449,7 +1437,7 @@ public class NEUOverlay extends Gui {
* Returns an index-able array containing the elements in searchedItems.
* Whenever searchedItems is updated in updateSearch(), the array is recreated here.
*/
- public List<JsonObject> getSearchedItems() {
+ public synchronized List<JsonObject> getSearchedItems() {
if (searchedItems == null) {
updateSearch();
return new ArrayList<>();
@@ -1472,7 +1460,7 @@ public class NEUOverlay extends Gui {
if (index < getSlotsXSize() * getSlotsYSize()) {
int actualIndex = index + getSlotsXSize() * getSlotsYSize() * page;
List<JsonObject> searchedItems = getSearchedItems();
- if (actualIndex < searchedItems.size()) {
+ if (0 <= actualIndex && actualIndex < searchedItems.size()) {
return searchedItems.get(actualIndex);
} else {
return null;
@@ -1620,12 +1608,12 @@ public class NEUOverlay extends Gui {
drawRect(leftSide - 1, top, leftSide - 1 + buttonXSize, top + ySize, fg.getRGB());
GlStateManager.color(1f, 1f, 1f, 1f);
- Minecraft.getMinecraft().getTextureManager().bindTexture(rightarrow);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.rightarrow);
Utils.drawTexturedRect(leftSide - 1 + leftPressed,
top + leftPressed,
buttonXSize, ySize, 1, 0, 0, 1
);
- Minecraft.getMinecraft().getTextureManager().bindTexture(rightarrow_overlay);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.rightarrow_overlay);
Utils.drawTexturedRect(leftSide - 1,
top,
buttonXSize, ySize, 1 - leftPressed, leftPressed, 1 - leftPressed, leftPressed
@@ -1639,12 +1627,12 @@ public class NEUOverlay extends Gui {
drawRect(rightSide + 1 - buttonXSize, top, rightSide + 1, top + ySize, fg.getRGB());
GlStateManager.color(1f, 1f, 1f, 1f);
- Minecraft.getMinecraft().getTextureManager().bindTexture(rightarrow);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.rightarrow);
Utils.drawTexturedRect(rightSide + 1 - buttonXSize + rightPressed,
top + rightPressed,
buttonXSize, ySize
);
- Minecraft.getMinecraft().getTextureManager().bindTexture(rightarrow_overlay);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.rightarrow_overlay);
Utils.drawTexturedRect(rightSide + 1 - buttonXSize,
top,
buttonXSize, ySize, 1 - rightPressed, rightPressed, 1 - rightPressed, rightPressed
@@ -1802,129 +1790,13 @@ public class NEUOverlay extends Gui {
int guiScaleLast = 0;
private boolean showVanillaLast = false;
-
- private boolean wardrobeOpen = false;
-
- private boolean isInNamedGui(String guiName) {
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
- if (guiScreen instanceof GuiChest) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- IInventory lower = container.getLowerChestInventory();
- String containerName = lower.getDisplayName().getUnformattedText();
- wardrobeOpen = containerName.contains(guiName);
- }
- if (guiScreen instanceof GuiInventory) {
- wardrobeOpen = false;
- }
- return wardrobeOpen;
- }
-
- private int wardrobePage = -1;
-
- private int getWardrobePage() {
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
- if (guiScreen instanceof GuiChest) {
- if (isInNamedGui("Wardrobe")) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- IInventory lower = container.getLowerChestInventory();
- String containerName = lower.getDisplayName().getUnformattedText();
- try {
- wardrobePage = Integer.parseInt(containerName.substring(10, 11));
- } catch (NumberFormatException e) {
- System.out.println(containerName.charAt(10));
- System.out.println("Did hypixel change the wardrobe string?");
- wardrobePage = -1;
- }
- } else wardrobePage = -1;
- }
- return wardrobePage;
- }
-
- private ItemStack getChestSlotsAsItemStack(int slot) {
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
- if (guiScreen instanceof GuiChest) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- return chest.inventorySlots.getSlot(slot).getStack();
- } else {
- return null;
- }
- }
-
- private int selectedArmor = 9;
-
- private int getEquippedArmor() {
- if (!isInNamedGui("Wardrobe")) return selectedArmor;
-
- ItemStack nullTest1 = getChestSlotsAsItemStack(8);
- ItemStack nullTest2 = getChestSlotsAsItemStack(17);
- ItemStack nullTest3 = getChestSlotsAsItemStack(26);
- ItemStack nullTest4 = getChestSlotsAsItemStack(35);
- ItemStack nullTest5 = getChestSlotsAsItemStack(44);
- if (nullTest1 != null || nullTest2 != null || nullTest3 != null || nullTest4 != null || nullTest5 != null) {
- selectedArmor = 9;
- }
- for (int ii = 1; ii < 5; ii++) {
- if (ii != 1 && selectedArmor != 9) continue;
- if (getWardrobePage() != ii) continue;
- for (int i = 8; i < 54; i += 9) {
- ItemStack stack1 = getChestSlotsAsItemStack(i);
- if (stack1 == null) continue;
- String[] lore1 = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack1.getTagCompound());
- for (String line : lore1) {
- if (line.contains("to unequip this armor")) {
- selectedArmor = i;
- break;
- }
- }
- }
- }
- return selectedArmor;
- }
-
- private ItemStack getWardrobeSlot(int armourSlot) {
- if (isInNamedGui("Wardrobe")) {
- if (getChestSlotsAsItemStack(getEquippedArmor() - armourSlot) != null && getEquippedArmor() != 9) {
- return getChestSlotsAsItemStack(getEquippedArmor() - armourSlot);
- } else return null;
- } else return null;
- }
-
- public boolean isWardrobeSystemOnMainServer() {
- JsonElement alphaWardrobeElement = Utils.getElement(Constants.DISABLE, "wardrobeFeature");
- if (alphaWardrobeElement == null || !alphaWardrobeElement.isJsonObject()) {
- return true;
- }
- JsonObject isWardrobe = alphaWardrobeElement.getAsJsonObject();
- if (isWardrobe.has("enableNewWardrob")) {
- return isWardrobe.get("enableNewWardrob").getAsBoolean();
- } else {
- return true;
- }
- }
-
- public ItemStack slot1 = null;
- public ItemStack slot2 = null;
- public ItemStack slot3 = null;
- public ItemStack slot4 = null;
- public ItemStack petSlot = null;
-
- public static boolean isRenderingArmorHud() {
- return renderingArmorHud;
- }
-
- public static boolean isRenderingPetHud() {
- return renderingPetHud;
- }
-
/**
* Renders the search bar, quick commands, item selection (right), item info (left) and armor hud gui elements.
*/
public void render(boolean hoverInv) {
- if (disabled) return;
- renderingArmorHud = false;
- renderingPetHud = false;
+ if (disabled) {
+ return;
+ }
GlStateManager.enableDepth();
FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
@@ -1948,236 +1820,13 @@ public class NEUOverlay extends Gui {
Utils.drawTexturedRect((width - 64) / 2f, (height - 64) / 2f - 114, 64, 64, GL11.GL_LINEAR);
GlStateManager.bindTexture(0);
}
- GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
-
- if (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud &&
- NotEnoughUpdates.INSTANCE.config.misc.hidePotionEffect
- &&
- NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() &&
- isWardrobeSystemOnMainServer()) {
- if (getWardrobeSlot(1) != null) {
- slot1 = getWardrobeSlot(4);
- slot2 = getWardrobeSlot(3);
- slot3 = getWardrobeSlot(2);
- slot4 = getWardrobeSlot(1);
- }
- if (guiScreen instanceof GuiInventory) {
- renderingArmorHud = true;
- selectedArmor = 9;
-
- List<String> tooltipToDisplay = null;
- if (NotEnoughUpdates.INSTANCE.config.customArmour.colourStyle == 0) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(ARMOR_DISPLAY);
- }
- if (NotEnoughUpdates.INSTANCE.config.customArmour.colourStyle == 1) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(ARMOR_DISPLAY_GREY);
- }
- if (NotEnoughUpdates.INSTANCE.config.customArmour.colourStyle == 2) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(ARMOR_DISPLAY_DARK);
- }
- if (NotEnoughUpdates.INSTANCE.config.customArmour.colourStyle == 3) {
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 3 &&
- NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay &&
- petSlot != null) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(ARMOR_DISPLAY_TRANSPARENT_PET);
- } else {
- Minecraft.getMinecraft().getTextureManager().bindTexture(ARMOR_DISPLAY_TRANSPARENT);
- }
- }
- if (NotEnoughUpdates.INSTANCE.config.customArmour.colourStyle == 4) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(ARMOR_DISPLAY_FSR);
- }
-
- GlStateManager.color(1, 1, 1, 1);
- GL11.glTranslatef(0, 0, 401);
- float yNumber = (float) (height - 167) / 2f;
- Utils.drawTexturedRect((float) ((width - 224.1) / 2f), yNumber, 31, 86, GL11.GL_NEAREST);
- GlStateManager.bindTexture(0);
- Utils.drawItemStack(slot1, (int) ((width - 208) / 2f), (int) ((height + 60) / 2f - 105));
- Utils.drawItemStack(slot2, (int) ((width - 208) / 2f), (int) ((height + 60) / 2f - 105) + 18);
- Utils.drawItemStack(slot3, (int) ((width - 208) / 2f), (int) ((height + 60) / 2f - 105) + 36);
- Utils.drawItemStack(slot4, (int) ((width - 208) / 2f), (int) ((height + 60) / 2f - 105) + 54);
- if (slot1 == null) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(QUESTION_MARK);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(((width - 208) / 2f), ((height + 60) / 2f - 105), 16, 16, GL11.GL_NEAREST);
- GlStateManager.bindTexture(0);
-
- tooltipToDisplay = Lists.newArrayList(
- EnumChatFormatting.RED + "Warning",
- EnumChatFormatting.GREEN + "You need to open /wardrobe",
- EnumChatFormatting.GREEN + "To cache your armour"
- );
- if (mouseX >= ((width - 208) / 2f) && mouseX < ((width - 208) / 2f) + 16) {
- if (mouseY >= ((height + 60) / 2f - 105) &&
- mouseY <= ((height + 60) / 2f - 105) + 70 &&
- NotEnoughUpdates.INSTANCE.config.customArmour.sendWardrobeCommand) {
- if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
- if (Mouse.getEventButtonState()) {
- if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/wardrobe") ==
- 0) {
- NotEnoughUpdates.INSTANCE.sendChatMessage("/wardrobe");
- }
- }
- }
- }
- if (mouseY >= ((height + 60) / 2f - 105) && mouseY <= ((height + 60) / 2f - 105) + 16) {
- Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
- GL11.glTranslatef(0, 0, -401);
- }
- }
-
- }
- if (slot1 != null && slot2 != null && slot3 != null && slot4 != null) {
- if (mouseX >= ((width - 208) / 2f) && mouseX < ((width - 208) / 2f) + 16) {
- if (mouseY >= ((height + 60) / 2f - 105) &&
- mouseY <= ((height + 60) / 2f - 105) + 70 &&
- NotEnoughUpdates.INSTANCE.config.customArmour.sendWardrobeCommand) {
- if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
- if (Mouse.getEventButtonState()) {
- if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/wardrobe") ==
- 0) {
- NotEnoughUpdates.INSTANCE.sendChatMessage("/wardrobe");
- }
- }
- }
- }
- //top slot
- if (mouseY >= ((height + 60) / 2f - 105) && mouseY <= ((height + 60) / 2f - 105) + 16) {
- tooltipToDisplay = slot1.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
- tooltipToDisplay = null;
- GL11.glTranslatef(0, 0, -401);
- }
- if (mouseY >= ((height + 60) / 2f - 105) + 18 && mouseY <= ((height + 60) / 2f - 105) + 34) {
- tooltipToDisplay = slot2.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
- tooltipToDisplay = null;
- GL11.glTranslatef(0, 0, -401);
- }
- if (mouseY >= ((height + 60) / 2f - 105) + 36 && mouseY <= ((height + 60) / 2f - 105) + 52) {
- tooltipToDisplay = slot3.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
- tooltipToDisplay = null;
- GL11.glTranslatef(0, 0, -401);
- }
- if (mouseY >= ((height + 60) / 2f - 105) + 54 && mouseY <= ((height + 60) / 2f - 105) + 70) {
- tooltipToDisplay = slot4.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
- tooltipToDisplay = null;
- GL11.glTranslatef(0, 0, -401);
- }
- }
- GL11.glTranslatef(0, 0, -401);
- }
- }
- }
- if (PetInfoOverlay.getCurrentPet() != null) {
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay
- &&
- (NotEnoughUpdates.INSTANCE.manager
- .jsonToStack(NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get(PetInfoOverlay.getCurrentPet().petType + ";" + PetInfoOverlay.getCurrentPet().rarity.petId))
- .hasDisplayName()
- ||
- NotEnoughUpdates.INSTANCE.manager
- .jsonToStack(NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get(PetInfoOverlay.getCurrentPet().petType + ";" + (PetInfoOverlay.getCurrentPet().rarity.petId - 1)))
- .hasDisplayName())
- &&
- NotEnoughUpdates.INSTANCE.config.misc.hidePotionEffect &&
- NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
- if (!NotEnoughUpdates.INSTANCE.manager
- .jsonToStack(
- NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get(PetInfoOverlay.getCurrentPet().petType + ";" + PetInfoOverlay.getCurrentPet().rarity.petId))
- .hasDisplayName()) {
- petSlot = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
- NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(
- PetInfoOverlay.getCurrentPet().petType + ";" + (PetInfoOverlay.getCurrentPet().rarity.petId - 1)));
- } else {
- petSlot = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
- NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(
- PetInfoOverlay.getCurrentPet().petType + ";" + PetInfoOverlay.getCurrentPet().rarity.petId));
- }
- petSlot.getTagCompound().setBoolean("NEUPETINVDISPLAY", true);
- petSlot
- .getTagCompound()
- .setBoolean("NEUHIDEPETTOOLTIP", NotEnoughUpdates.INSTANCE.config.petOverlay.hidePetTooltip);
- ItemStack petInfo = petSlot;
-
- if (guiScreen instanceof GuiInventory) {
- GL11.glTranslatef(0, 0, 401);
- if (!NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud || !isWardrobeSystemOnMainServer()) {
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 0) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_DISPLAY);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 1) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_DISPLAY_GREY);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 2) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_DISPLAY_DARK);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 3) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_DISPLAY_TRANSPARENT);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 4) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_DISPLAY_FSR);
- }
- } else {
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 0) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_ARMOR_DISPLAY);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 1) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_ARMOR_DISPLAY_GREY);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 2) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_ARMOR_DISPLAY_DARK);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 3) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_ARMOR_DISPLAY_TRANSPARENT);
- }
- if (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 4) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(PET_ARMOR_DISPLAY_FSR);
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- float yNumber = (float) (height - 23) / 2f;
- Utils.drawTexturedRect((float) ((width - 224.1) / 2f), yNumber, 31, 32, GL11.GL_NEAREST);
- GlStateManager.bindTexture(0);
-
- Utils.drawItemStack(petInfo, (int) ((width - 208) / 2f), (int) ((height + 60) / 2f - 105) + 72);
- renderingPetHud = true;
-
- List<String> tooltipToDisplay = null;
- if (petInfo != null) {
- if (mouseX >= ((width - 208) / 2f) && mouseX < ((width - 208) / 2f) + 16) {
- if (mouseY >= ((height + 60) / 2f - 105) + 72 &&
- mouseY <= ((height + 60) / 2f - 105) + 88 &&
- NotEnoughUpdates.INSTANCE.config.petOverlay.sendPetsCommand) {
- if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
- if (Mouse.getEventButtonState()) {
- if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/pets") ==
- 0) {
- NotEnoughUpdates.INSTANCE.sendChatMessage("/pets");
- }
- }
- }
- tooltipToDisplay = petInfo.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
- tooltipToDisplay = null;
- GL11.glTranslatef(0, 0, -80);
- }
- }
-
- }
- }
- }
+ if (textField.getText().toLowerCase().contains("lunar")) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(ATMOULBERRYWHYISMYLUNARCLIENTBUGGING);
+ GlStateManager.color(1, 1, 1, 1);
+ GlStateManager.translate(0, 0, 100);
+ Utils.drawTexturedRect((width + 410) / 2f, (height + 450) / 2f - 114, 113, 64, GL11.GL_LINEAR);
+ GlStateManager.bindTexture(0);
}
SunTzu.setEnabled(textField.getText().toLowerCase().startsWith("potato"));
@@ -2208,6 +1857,13 @@ public class NEUOverlay extends Gui {
(int) (fgFavourite2.getBlue() * 0.8f), fgFavourite2.getAlpha()
);
+ if (!NotEnoughUpdates.INSTANCE.config.itemlist.openWhenSearching && searchMode) {
+ itemPaneOpen = false;
+ }
+ if (itemPaneShouldOpen != -1 && System.currentTimeMillis() > itemPaneShouldOpen) {
+ itemPaneOpen = true;
+ itemPaneShouldOpen = -1;
+ }
if (itemPaneOpen) {
if (itemPaneTabOffset.getValue() == 0) {
if (itemPaneOffsetFactor.getTarget() != 2 / 3f) {
@@ -2252,7 +1908,7 @@ public class NEUOverlay extends Gui {
//Tab
if (NotEnoughUpdates.INSTANCE.config.itemlist.tabOpen) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(itemPaneTabArrow);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.itemPaneTabArrow);
GlStateManager.color(1f, 1f, 1f, 0.3f);
Utils.drawTexturedRect(width - itemPaneTabOffset.getValue() * 64 / 20f, height / 2f - 32, 64, 64);
GlStateManager.bindTexture(0);
@@ -2308,17 +1964,14 @@ public class NEUOverlay extends Gui {
int orderIconX = leftSide + getBoxPadding() + getItemBoxXPadding() + i * scaledItemPaddedSize;
drawRect(orderIconX, iconTop, scaledITEM_SIZE + orderIconX, iconTop + scaledITEM_SIZE, fg.getRGB());
- Minecraft
- .getMinecraft()
- .getTextureManager()
- .bindTexture(getCompareMode() == i ? orderIconsActive[i] : orderIcons[i]);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(
+ getCompareMode() == i ? orderIconsActive[i] : orderIcons[i]);
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect(orderIconX, iconTop, scaledITEM_SIZE, scaledITEM_SIZE, 0, 1, 0, 1, GL11.GL_NEAREST);
- Minecraft
- .getMinecraft()
- .getTextureManager()
- .bindTexture(getCompareAscending().get(i) ? ascending_overlay : descending_overlay);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(getCompareAscending().get(i)
+ ? GuiTextures.ascending_overlay
+ : GuiTextures.descending_overlay);
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect(orderIconX, iconTop, scaledITEM_SIZE, scaledITEM_SIZE, 0, 1, 0, 1, GL11.GL_NEAREST);
GlStateManager.bindTexture(0);
@@ -2341,10 +1994,8 @@ public class NEUOverlay extends Gui {
for (int i = 0; i < sortIcons.length; i++) {
int sortIconX = rightSide - scaledITEM_SIZE - i * scaledItemPaddedSize;
drawRect(sortIconX, iconTop, scaledITEM_SIZE + sortIconX, iconTop + scaledITEM_SIZE, fg.getRGB());
- Minecraft
- .getMinecraft()
- .getTextureManager()
- .bindTexture(getSortMode() == i ? sortIconsActive[i] : sortIcons[i]);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(
+ getSortMode() == i ? sortIconsActive[i] : sortIcons[i]);
GlStateManager.color(1f, 1f, 1f, 1f);
Utils.drawTexturedRect(sortIconX, iconTop, scaledITEM_SIZE, scaledITEM_SIZE, 0, 1, 0, 1, GL11.GL_NEAREST);
GlStateManager.bindTexture(0);
@@ -2504,7 +2155,7 @@ public class NEUOverlay extends Gui {
activeInfoPane.render(width, height, bg, fg, Utils.peekGuiScale(), mouseX, mouseY);
GlStateManager.color(1f, 1f, 1f, 1f);
- Minecraft.getMinecraft().getTextureManager().bindTexture(close);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.close);
Utils.drawTexturedRect(rightSide - getBoxPadding() - 8, getBoxPadding() - 8, 16, 16);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
}
@@ -2550,7 +2201,6 @@ public class NEUOverlay extends Gui {
GlStateManager.enableAlpha();
GlStateManager.alphaFunc(516, 0.1F);
GlStateManager.disableLighting();
-
Utils.pushGuiScale(-1);
if (System.currentTimeMillis() - lastSearchMode > 120000 &&
@@ -2560,6 +2210,7 @@ public class NEUOverlay extends Gui {
}
}
+
/**
* Used in SettingsInfoPane to redraw the items when a setting changes.
*/
@@ -2585,8 +2236,7 @@ public class NEUOverlay extends Gui {
int sw = width * Utils.peekGuiScale().getScaleFactor();
int sh = height * Utils.peekGuiScale().getScaleFactor();
for (int i = 0; i < itemFramebuffers.length; i++) {
- if (itemFramebuffers[i] == null ||
- itemFramebuffers[i].framebufferWidth != sw ||
+ if (itemFramebuffers[i] == null || itemFramebuffers[i].framebufferWidth != sw ||
itemFramebuffers[i].framebufferHeight != sh) {
if (itemFramebuffers[i] == null) {
itemFramebuffers[i] = new Framebuffer(sw, sh, true);
@@ -2772,7 +2422,7 @@ public class NEUOverlay extends Gui {
return;
}
- Minecraft.getMinecraft().getTextureManager().bindTexture(item_mask);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.item_mask);
if (getFavourites().contains(json.get("internalname").getAsString())) {
if (NotEnoughUpdates.INSTANCE.config.itemlist.itemStyle == 0) {
GlStateManager.color(fgFavourite2.getRed() / 255f, fgFavourite2.getGreen() / 255f,
@@ -2854,7 +2504,7 @@ public class NEUOverlay extends Gui {
GlStateManager.translate(0, 0, 50);
if (searchedItemsSubgroup.containsKey(json.get("internalname").getAsString())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(item_haschild);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.item_haschild);
GlStateManager.color(1, 1, 1, 1);
Utils.drawTexturedRect(x - 1, y - 1, ITEM_SIZE + 2, ITEM_SIZE + 2, GL11.GL_NEAREST);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java b/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java
new file mode 100644
index 00000000..bc279188
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NEURepoResourcePack.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates;
+
+import com.google.gson.JsonObject;
+import net.minecraft.client.resources.IResourcePack;
+import net.minecraft.client.resources.data.IMetadataSection;
+import net.minecraft.client.resources.data.IMetadataSerializer;
+import net.minecraft.util.ResourceLocation;
+
+import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+public class NEURepoResourcePack implements IResourcePack {
+
+ File repoLocation;
+ Set<String> resourceDomains = new HashSet<>();
+
+ public NEURepoResourcePack(File repoLocation, String domain) {
+ this.repoLocation = repoLocation;
+ resourceDomains.add(domain);
+ }
+
+ public boolean loadRepoLocation() {
+ if (repoLocation != null) return true;
+ NotEnoughUpdates instance = NotEnoughUpdates.INSTANCE;
+ if (instance == null) return false;
+ NEUManager manager = instance.manager;
+ if (manager == null) return false;
+ repoLocation = manager.repoLocation;
+ return repoLocation != null;
+ }
+
+ public File getFileForResource(ResourceLocation loc) {
+ if (repoLocation == null) {
+ if (!loadRepoLocation())
+ return null;
+ }
+ if (!"neurepo".equals(loc.getResourceDomain())) {
+ return null;
+ }
+ return new File(repoLocation, loc.getResourcePath());
+ }
+
+ @Override
+ public InputStream getInputStream(ResourceLocation resourceLocation) throws IOException {
+ return new BufferedInputStream(new FileInputStream(getFileForResource(resourceLocation)));
+ }
+
+ @Override
+ public boolean resourceExists(ResourceLocation resourceLocation) {
+ File file = getFileForResource(resourceLocation);
+ return file != null && file.exists();
+ }
+
+ @Override
+ public Set<String> getResourceDomains() {
+ return resourceDomains;
+ }
+
+ @Override
+ public <T extends IMetadataSection> T getPackMetadata(IMetadataSerializer iMetadataSerializer, String s)
+ throws IOException {
+ return iMetadataSerializer.parseMetadataSection(s, new JsonObject());
+ }
+
+ @Override
+ public BufferedImage getPackImage() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getPackName() {
+ return "NEU Repo Resources";
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
index b6ac71a4..39826ded 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/NotEnoughUpdates.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates;
import com.google.common.collect.Sets;
@@ -7,22 +26,60 @@ import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.commands.Commands;
import io.github.moulberry.notenoughupdates.core.BackgroundBlur;
import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
+import io.github.moulberry.notenoughupdates.cosmetics.ShaderManager;
import io.github.moulberry.notenoughupdates.dungeons.DungeonMap;
-import io.github.moulberry.notenoughupdates.miscfeatures.*;
+import io.github.moulberry.notenoughupdates.listener.ChatListener;
+import io.github.moulberry.notenoughupdates.listener.ItemTooltipEssenceShopListener;
+import io.github.moulberry.notenoughupdates.listener.ItemTooltipListener;
+import io.github.moulberry.notenoughupdates.listener.ItemTooltipRngListener;
+import io.github.moulberry.notenoughupdates.listener.NEUEventListener;
+import io.github.moulberry.notenoughupdates.listener.OldAnimationChecker;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
+import io.github.moulberry.notenoughupdates.miscfeatures.AbiphoneWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.AntiCoopAdd;
+import io.github.moulberry.notenoughupdates.miscfeatures.AuctionBINWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.AuctionProfit;
+import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalOverlay;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects;
+import io.github.moulberry.notenoughupdates.miscfeatures.CustomSkulls;
+import io.github.moulberry.notenoughupdates.miscfeatures.DwarvenMinesWaypoints;
+import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
+import io.github.moulberry.notenoughupdates.miscfeatures.FairySouls;
+import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper;
+import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns;
+import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
+import io.github.moulberry.notenoughupdates.miscfeatures.MiningStuff;
+import io.github.moulberry.notenoughupdates.miscfeatures.NPCRetexturing;
+import io.github.moulberry.notenoughupdates.miscfeatures.Navigation;
+import io.github.moulberry.notenoughupdates.miscfeatures.NullzeeSphere;
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.miscfeatures.PowerStoneStatsDisplay;
+import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
+import io.github.moulberry.notenoughupdates.miscfeatures.SunTzu;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBlockSounds;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.DwarvenMinesTextures;
+import io.github.moulberry.notenoughupdates.miscfeatures.updater.AutoUpdater;
import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay;
import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector;
+import io.github.moulberry.notenoughupdates.miscgui.SignCalculator;
+import io.github.moulberry.notenoughupdates.miscgui.TrophyRewardOverlay;
+import io.github.moulberry.notenoughupdates.mixins.AccessorMinecraft;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.overlays.EquipmentOverlay;
import io.github.moulberry.notenoughupdates.overlays.FuelBar;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.recipes.RecipeGenerator;
+import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import io.github.moulberry.notenoughupdates.util.XPInformation;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraft.client.settings.KeyBinding;
@@ -31,82 +88,46 @@ import net.minecraft.scoreboard.ScoreObjective;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
-import net.minecraft.world.biome.*;
+import net.minecraft.world.biome.BiomeGenBase;
+import net.minecraft.world.biome.BiomeGenHell;
+import net.minecraft.world.biome.BiomeGenJungle;
+import net.minecraft.world.biome.BiomeGenMesa;
+import net.minecraft.world.biome.BiomeGenSnow;
+import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import java.awt.*;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Set;
-@Mod(modid = NotEnoughUpdates.MODID, version = NotEnoughUpdates.VERSION, clientSideOnly = true)
+@Mod(
+ modid = NotEnoughUpdates.MODID, version = NotEnoughUpdates.VERSION, clientSideOnly = true, useMetadata = true,
+ guiFactory = "io.github.moulberry.notenoughupdates.core.config.MoulConfigGuiForgeInterop")
public class NotEnoughUpdates {
public static final String MODID = "notenoughupdates";
public static final String VERSION = "2.1.0-REL";
- public static final String PRE_VERSION = "0.0";
- public static final int VERSION_ID = 20100;
+ public static final int VERSION_ID = 20101; //2.1.1 only so update notif works
public static final int PRE_VERSION_ID = 0;
+ public static final int HOTFIX_VERSION_ID = 0;
- public static NotEnoughUpdates INSTANCE = null;
-
- public NEUManager manager;
- public NEUOverlay overlay;
- public NEUConfig config;
-
- private File configFile;
-
- public File getConfigFile() {
- return this.configFile;
- }
-
- public void newConfigFile() {
- this.configFile = new File(NotEnoughUpdates.INSTANCE.getNeuDir(), "configNew.json");
- }
-
- private static final long CHAT_MSG_COOLDOWN = 200;
- private long lastChatMessage = 0;
- private long secondLastChatMessage = 0;
- private String currChatMessage = null;
-
- //Stolen from Biscut and used for detecting whether in skyblock
- private static final Set<String> SKYBLOCK_IN_ALL_LANGUAGES =
- Sets.newHashSet("SKYBLOCK", "\u7A7A\u5C9B\u751F\u5B58", "\u7A7A\u5CF6\u751F\u5B58");
-
- public GuiScreen openGui = null;
- public long lastOpenedGui = 0;
-
- public Commands commands;
-
- public static HashMap<String, String> petRarityToColourMap = new HashMap<String, String>() {{
- put("UNKNOWN", EnumChatFormatting.RED.toString());
- put("COMMON", EnumChatFormatting.WHITE.toString());
- put("UNCOMMON", EnumChatFormatting.GREEN.toString());
- put("RARE", EnumChatFormatting.BLUE.toString());
- put("EPIC", EnumChatFormatting.DARK_PURPLE.toString());
- put("LEGENDARY", EnumChatFormatting.GOLD.toString());
- put("MYTHIC", EnumChatFormatting.LIGHT_PURPLE.toString());
- }};
-
- public static ProfileViewer profileViewer;
-
- public boolean packDevEnabled = false;
-
- private final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
- private File neuDir;
-
- public File getNeuDir() {
- return this.neuDir;
- }
-
- public Color[][] colourMap = null;
-
+ public static final Logger LOGGER = LogManager.getLogger("NotEnoughUpdates");
/**
* Registers the biomes for the crystal hollows here so optifine knows they exists
*/
@@ -140,6 +161,57 @@ public class NotEnoughUpdates {
.setBiomeName("NeuCrystalHollowsCrystalNucleus")
.setFillerBlockMetadata(5470985)
.setTemperatureRainfall(0.95F, 0.9F);
+ private static final long CHAT_MSG_COOLDOWN = 200;
+ //Stolen from Biscut and used for detecting whether in skyblock
+ private static final Set<String> SKYBLOCK_IN_ALL_LANGUAGES =
+ Sets.newHashSet("SKYBLOCK", "\u7A7A\u5C9B\u751F\u5B58", "\u7A7A\u5CF6\u751F\u5B58");
+ public static NotEnoughUpdates INSTANCE = null;
+ public static HashMap<String, String> petRarityToColourMap = new HashMap<String, String>() {{
+ put("UNKNOWN", EnumChatFormatting.RED.toString());
+ put("COMMON", EnumChatFormatting.WHITE.toString());
+ put("UNCOMMON", EnumChatFormatting.GREEN.toString());
+ put("RARE", EnumChatFormatting.BLUE.toString());
+ put("EPIC", EnumChatFormatting.DARK_PURPLE.toString());
+ put("LEGENDARY", EnumChatFormatting.GOLD.toString());
+ put("MYTHIC", EnumChatFormatting.LIGHT_PURPLE.toString());
+ }};
+ public static ProfileViewer profileViewer;
+ private final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
+ public NEUManager manager;
+ public NEUOverlay overlay;
+ public NEUConfig config;
+ public Navigation navigation = new Navigation(this);
+ public GuiScreen openGui = null;
+ public long lastOpenedGui = 0;
+ public Commands commands;
+ public boolean packDevEnabled = false;
+ public Color[][] colourMap = null;
+ public AutoUpdater autoUpdater = new AutoUpdater(this);
+ private File configFile;
+ private long lastChatMessage = 0;
+ private long secondLastChatMessage = 0;
+ private String currChatMessage = null;
+ private File neuDir;
+ private boolean hasSkyblockScoreboard;
+
+ public File getConfigFile() {
+ return this.configFile;
+ }
+
+ public void newConfigFile() {
+ this.configFile = new File(NotEnoughUpdates.INSTANCE.getNeuDir(), "configNew.json");
+ }
+
+ public File getNeuDir() {
+ return this.neuDir;
+ }
+
+ public NotEnoughUpdates() {
+ // Budget Construction Event
+ ((AccessorMinecraft) FMLClientHandler.instance().getClient())
+ .onGetDefaultResourcePacks()
+ .add(new NEURepoResourcePack(null, "neurepo"));
+ }
/**
* Instantiates NEUIo, NEUManager and NEUOverlay instances. Registers keybinds and adds a shutdown hook to clear tmp folder.
@@ -161,13 +233,14 @@ public class NotEnoughUpdates {
))
) {
config = gson.fromJson(reader, NEUConfig.class);
- } catch (Exception ignored) {
+ } catch (Exception exc) {
+ new RuntimeException("Invalid config file. This will reset the config to default", exc).printStackTrace();
}
}
ItemCustomizeManager.loadCustomization(new File(neuDir, "itemCustomization.json"));
StorageManager.getInstance().loadConfig(new File(neuDir, "storageItems.json"));
- FairySouls.load(new File(neuDir, "collected_fairy_souls.json"), gson);
+ FairySouls.getInstance().loadFoundSoulsForAllProfiles(new File(neuDir, "collected_fairy_souls.json"), gson);
PetInfoOverlay.loadConfig(new File(neuDir, "petCache.json"));
SlotLocking.getInstance().loadConfig(new File(neuDir, "slotLocking.json"));
ItemPriceInformation.init(new File(neuDir, "auctionable_items.json"), gson);
@@ -175,6 +248,28 @@ public class NotEnoughUpdates {
if (config == null) {
config = new NEUConfig();
saveConfig();
+ } else {
+ if (config.apiKey != null && config.apiKey.apiKey != null) {
+ config.apiData.apiKey = config.apiKey.apiKey;
+ config.apiKey = null;
+ }
+
+ //add the trophy fishing tab to the config
+ if (config.profileViewer.pageLayout.size() == 8) {
+ config.profileViewer.pageLayout.add(8);
+ }
+ if (config.profileViewer.pageLayout.size() == 9) {
+ config.profileViewer.pageLayout.add(9);
+ }
+
+ // Remove after 2.1 ig
+ if ("dangerous".equals(config.apiData.repoBranch) || "rune".equals(config.apiData.repoBranch)) {
+ config.apiData.repoBranch = "master";
+ } else if ("jani270".equals(config.apiData.repoUser)) {
+ config.apiData.repoUser = "NotEnoughUpdates";
+ }
+
+ saveConfig();
}
MinecraftForge.EVENT_BUS.register(this);
@@ -186,15 +281,16 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(new CalendarOverlay());
MinecraftForge.EVENT_BUS.register(SBInfo.getInstance());
MinecraftForge.EVENT_BUS.register(CustomItemEffects.INSTANCE);
+ MinecraftForge.EVENT_BUS.register(new Constants());
MinecraftForge.EVENT_BUS.register(new DungeonMap());
MinecraftForge.EVENT_BUS.register(new SunTzu());
MinecraftForge.EVENT_BUS.register(new MiningStuff());
- MinecraftForge.EVENT_BUS.register(new FairySouls());
+ MinecraftForge.EVENT_BUS.register(FairySouls.getInstance());
MinecraftForge.EVENT_BUS.register(new CrystalOverlay());
MinecraftForge.EVENT_BUS.register(new ItemCooldowns());
MinecraftForge.EVENT_BUS.register(new DwarvenMinesWaypoints());
MinecraftForge.EVENT_BUS.register(new FuelBar());
- //MinecraftForge.EVENT_BUS.register(new FancyPortals());
+ MinecraftForge.EVENT_BUS.register(new AuctionProfit());
MinecraftForge.EVENT_BUS.register(XPInformation.getInstance());
MinecraftForge.EVENT_BUS.register(OverlayManager.petInfoOverlay);
MinecraftForge.EVENT_BUS.register(OverlayManager.timersOverlay);
@@ -202,13 +298,30 @@ public class NotEnoughUpdates {
MinecraftForge.EVENT_BUS.register(InventoryStorageSelector.getInstance());
MinecraftForge.EVENT_BUS.register(SlotLocking.getInstance());
MinecraftForge.EVENT_BUS.register(FishingHelper.getInstance());
+ MinecraftForge.EVENT_BUS.register(CrystalWishingCompassSolver.getInstance());
MinecraftForge.EVENT_BUS.register(new DwarvenMinesTextures());
+ MinecraftForge.EVENT_BUS.register(EquipmentOverlay.INSTANCE);
MinecraftForge.EVENT_BUS.register(CustomBiomes.INSTANCE);
+ MinecraftForge.EVENT_BUS.register(new ChatListener(this));
+ MinecraftForge.EVENT_BUS.register(new ItemTooltipListener(this));
+ MinecraftForge.EVENT_BUS.register(new ItemTooltipRngListener(this));
+ MinecraftForge.EVENT_BUS.register(new ItemTooltipEssenceShopListener(this));
+ MinecraftForge.EVENT_BUS.register(new RenderListener(this));
+ MinecraftForge.EVENT_BUS.register(new OldAnimationChecker());
+ MinecraftForge.EVENT_BUS.register(new SignCalculator());
+ MinecraftForge.EVENT_BUS.register(TrophyRewardOverlay.getInstance());
+ MinecraftForge.EVENT_BUS.register(PowerStoneStatsDisplay.getInstance());
+ MinecraftForge.EVENT_BUS.register(new AntiCoopAdd());
+ MinecraftForge.EVENT_BUS.register(AbiphoneWarning.getInstance());
+ MinecraftForge.EVENT_BUS.register(new BetterContainers());
+ MinecraftForge.EVENT_BUS.register(AuctionBINWarning.getInstance());
+ MinecraftForge.EVENT_BUS.register(navigation);
if (Minecraft.getMinecraft().getResourceManager() instanceof IReloadableResourceManager) {
IReloadableResourceManager manager = (IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager();
manager.registerReloadListener(CustomSkulls.getInstance());
manager.registerReloadListener(NPCRetexturing.getInstance());
+ manager.registerReloadListener(ShaderManager.getInstance());
manager.registerReloadListener(new ItemCustomizeManager.ReloadListener());
manager.registerReloadListener(new CustomBlockSounds.ReloaderListener());
}
@@ -234,7 +347,6 @@ public class NotEnoughUpdates {
}
tmp.delete();
}
- //saveConfig();
}));
}
@@ -262,7 +374,7 @@ public class NotEnoughUpdates {
} catch (Exception ignored) {
}
try {
- FairySouls.save(new File(neuDir, "collected_fairy_souls.json"), gson);
+ FairySouls.getInstance().saveFoundSoulsForAllProfiles(new File(neuDir, "collected_fairy_souls.json"), gson);
} catch (Exception ignored) {
}
try {
@@ -290,11 +402,16 @@ public class NotEnoughUpdates {
}
}
- public void displayLinks(JsonObject update) {
+ public void trySendCommand(String message) {
+ if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, message) == 0) {
+ sendChatMessage(message);
+ }
+ }
+
+ public void displayLinks(JsonObject update, int totalWidth) {
String discord_link = update.get("discord_link").getAsString();
String youtube_link = update.get("youtube_link").getAsString();
String twitch_link = update.get("twitch_link").getAsString();
- String update_link = update.get("update_link").getAsString();
String github_link = update.get("github_link").getAsString();
String other_text = update.get("other_text").getAsString();
String other_link = update.get("other_link").getAsString();
@@ -307,8 +424,7 @@ public class NotEnoughUpdates {
}
ChatComponentText links = new ChatComponentText("");
ChatComponentText separator = new ChatComponentText(
- EnumChatFormatting.GRAY + EnumChatFormatting.BOLD.toString() + EnumChatFormatting.STRIKETHROUGH +
- (other == null ? "--" : "-"));
+ EnumChatFormatting.GRAY + EnumChatFormatting.BOLD.toString() + EnumChatFormatting.STRIKETHROUGH + "-");
ChatComponentText discord = new ChatComponentText(
EnumChatFormatting.GRAY + "[" + EnumChatFormatting.BLUE + "Discord" + EnumChatFormatting.GRAY + "]");
discord.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, discord_link));
@@ -318,9 +434,6 @@ public class NotEnoughUpdates {
ChatComponentText twitch = new ChatComponentText(
EnumChatFormatting.GRAY + "[" + EnumChatFormatting.DARK_PURPLE + "Twitch" + EnumChatFormatting.GRAY + "]");
twitch.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, twitch_link));
- ChatComponentText release = new ChatComponentText(
- EnumChatFormatting.GRAY + "[" + EnumChatFormatting.GREEN + "Release" + EnumChatFormatting.GRAY + "]");
- release.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, update_link));
ChatComponentText github = new ChatComponentText(
EnumChatFormatting.GRAY + "[" + EnumChatFormatting.DARK_PURPLE + "GitHub" + EnumChatFormatting.GRAY + "]");
github.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, github_link));
@@ -332,16 +445,28 @@ public class NotEnoughUpdates {
links.appendSibling(separator);
links.appendSibling(twitch);
links.appendSibling(separator);
- links.appendSibling(release);
- links.appendSibling(separator);
links.appendSibling(github);
links.appendSibling(separator);
if (other != null) {
links.appendSibling(other);
links.appendSibling(separator);
}
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(links);
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ int missingWidth = Math.max(0, totalWidth - fr.getStringWidth(links.getFormattedText()));
+ int missingCharsOnEitherSide = missingWidth / fr.getStringWidth(EnumChatFormatting.BOLD + "-") / 2;
+ StringBuilder sb = new StringBuilder(missingCharsOnEitherSide + 6);
+ sb.append(EnumChatFormatting.GRAY);
+ sb.append(EnumChatFormatting.BOLD);
+ sb.append(EnumChatFormatting.STRIKETHROUGH);
+ for (int i = 0; i < missingCharsOnEitherSide; i++) {
+ sb.append("-");
+ }
+ String padding = sb.toString();
+ ChatComponentText cp = new ChatComponentText("");
+ cp.appendText(padding);
+ cp.appendSibling(links);
+ cp.appendText(padding);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(cp);
}
@SubscribeEvent
@@ -374,8 +499,6 @@ public class NotEnoughUpdates {
return hasSkyblockScoreboard();
}
- private boolean hasSkyblockScoreboard;
-
public boolean hasSkyblockScoreboard() {
return hasSkyblockScoreboard;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
index c47e0844..1b6896db 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/APIManager.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.auction;
import com.google.gson.JsonArray;
@@ -27,10 +46,21 @@ import net.minecraft.util.ResourceLocation;
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.util.*;
+import java.util.Base64;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class APIManager {
private final NEUManager manager;
@@ -41,6 +71,9 @@ public class APIManager {
private final HashSet<String> playerBids = new HashSet<>();
private final HashSet<String> playerBidsNotified = new HashSet<>();
private final HashSet<String> playerBidsFinishedNotified = new HashSet<>();
+ private final int LOWEST_BIN_UPDATE_INTERVAL = 2 * 60 * 1000; // 2 minutes
+ private final int AUCTION_AVG_UPDATE_INTERVAL = 5 * 60 * 1000; // 5 minutes
+ private final int BAZAAR_UPDATE_INTERVAL = 5 * 60 * 1000; // 5 minutes
private JsonObject lowestBins = null;
private JsonObject auctionPricesAvgLowestBinJson = null;
@@ -92,7 +125,7 @@ public class APIManager {
public class Auction {
public String auctioneerUuid;
public long end;
- public int starting_bid;
+ public long starting_bid;
public int highest_bid_amount;
public int bid_count;
public boolean bin;
@@ -106,7 +139,7 @@ public class APIManager {
public int enchLevel = 0; //0 = clean, 1 = ench, 2 = ench/hpb
public Auction(
- String auctioneerUuid, long end, int starting_bid, int highest_bid_amount, int bid_count,
+ String auctioneerUuid, long end, long starting_bid, int highest_bid_amount, int bid_count,
boolean bin, String category, String rarity, int dungeonTier, String item_tag_str
) {
this.auctioneerUuid = auctioneerUuid;
@@ -135,6 +168,7 @@ public class APIManager {
return stack;
} else {
JsonObject item = manager.getJsonFromNBT(item_tag);
+ if (item == null) return null;
ItemStack stack = manager.jsonToStack(item, false);
JsonObject itemDefault = manager.getItemInformation().get(item.get("internalname").getAsString());
@@ -180,8 +214,8 @@ public class APIManager {
customAH.tick();
long currentTime = System.currentTimeMillis();
if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.enableNeuAuctionHouse &&
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey != null &&
- !NotEnoughUpdates.INSTANCE.config.apiKey.apiKey.isEmpty()) {
+ NotEnoughUpdates.INSTANCE.config.apiData.apiKey != null &&
+ !NotEnoughUpdates.INSTANCE.config.apiData.apiKey.isEmpty()) {
if (currentTime - lastAuctionUpdate > 60 * 1000) {
lastAuctionUpdate = currentTime;
updatePageTick();
@@ -203,15 +237,16 @@ public class APIManager {
}
}
}
- if (currentTime - lastAuctionAvgUpdate > 5 * 60 * 1000) { //5 minutes
- lastAuctionAvgUpdate = currentTime - 4 * 60 * 1000; //Try again in 1 minute if updateAvgPrices doesn't succeed
+ if (currentTime - lastAuctionAvgUpdate > AUCTION_AVG_UPDATE_INTERVAL) {
+ lastAuctionAvgUpdate = currentTime - AUCTION_AVG_UPDATE_INTERVAL + 60 * 1000; // Try again in 1 minute on failure
updateAvgPrices();
}
- if (currentTime - lastBazaarUpdate > 5 * 60 * 1000) { //5 minutes
- lastBazaarUpdate = currentTime;
+ if (currentTime - lastBazaarUpdate > BAZAAR_UPDATE_INTERVAL) {
+ lastBazaarUpdate = currentTime - BAZAAR_UPDATE_INTERVAL + 60 * 1000; // Try again in 1 minute on failure
updateBazaar();
}
- if (currentTime - lastLowestBinUpdate > 2 * 60 * 1000) {
+ if (currentTime - lastLowestBinUpdate > LOWEST_BIN_UPDATE_INTERVAL) {
+ lastLowestBinUpdate = currentTime - LOWEST_BIN_UPDATE_INTERVAL + 30 * 1000; // Try again in 30 seconds on failure
updateLowestBin();
}
}
@@ -241,34 +276,37 @@ public class APIManager {
return keys;
}
- public int getLowestBin(String internalname) {
- if (lowestBins != null && lowestBins.has(internalname)) {
- JsonElement e = lowestBins.get(internalname);
+ public long getLowestBin(String internalName) {
+ if (lowestBins != null && lowestBins.has(internalName)) {
+ JsonElement e = lowestBins.get(internalName);
if (e.isJsonPrimitive() && e.getAsJsonPrimitive().isNumber()) {
- return e.getAsInt();
+ return e.getAsBigDecimal().longValue();
}
}
return -1;
}
public void updateLowestBin() {
- manager.hypixelApi.getMyApiGZIPAsync("lowestbin.json.gz", (jsonObject) -> {
- if (lowestBins == null) {
- lowestBins = new JsonObject();
- }
- if (!jsonObject.entrySet().isEmpty()) {
- lastLowestBinUpdate = System.currentTimeMillis();
- }
- for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
- lowestBins.add(entry.getKey(), entry.getValue());
- }
- if (!didFirstUpdate) {
- ItemPriceInformation.updateAuctionableItemsList();
- didFirstUpdate = true;
- }
- GuiPriceGraph.addToCache(lowestBins, false);
- }, () -> {
- });
+ manager.apiUtils
+ .newMoulberryRequest("lowestbin.json.gz")
+ .gunzip()
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ if (lowestBins == null) {
+ lowestBins = new JsonObject();
+ }
+ if (!jsonObject.entrySet().isEmpty()) {
+ lastLowestBinUpdate = System.currentTimeMillis();
+ }
+ for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
+ lowestBins.add(entry.getKey(), entry.getValue());
+ }
+ if (!didFirstUpdate) {
+ ItemPriceInformation.updateAuctionableItemsList();
+ didFirstUpdate = true;
+ }
+ GuiPriceGraph.addToCache(lowestBins, false);
+ });
}
private void ahNotification() {
@@ -377,6 +415,7 @@ public class APIManager {
int page = pagesToDownload.pop();
getPageFromAPI(page);
} catch (NoSuchElementException ignored) {
+ return;
} //Weird race condition?
}
}
@@ -424,20 +463,23 @@ public class APIManager {
}
};
- manager.hypixelApi.getMyApiGZIPAsync("auctionLast.json.gz", process, () ->
- System.out.println("Error downloading auction from Moulberry's jank API. :("));
+ manager.apiUtils.newMoulberryRequest("auctionLast.json.gz")
+ .gunzip().requestJson().thenAccept(process);
- manager.hypixelApi.getMyApiGZIPAsync("auction.json.gz", jsonObject -> {
- if (jsonObject.get("success").getAsBoolean()) {
- long apiUpdate = (long) jsonObject.get("time").getAsFloat();
- if (lastApiUpdate == apiUpdate) {
- lastAuctionUpdate -= 30 * 1000;
- }
- lastApiUpdate = apiUpdate;
+ manager.apiUtils
+ .newMoulberryRequest("auction.json.gz")
+ .gunzip().requestJson()
+ .thenAccept(jsonObject -> {
+ if (jsonObject.get("success").getAsBoolean()) {
+ long apiUpdate = (long) jsonObject.get("time").getAsFloat();
+ if (lastApiUpdate == apiUpdate) {
+ lastAuctionUpdate -= 30 * 1000;
+ }
+ lastApiUpdate = apiUpdate;
- process.accept(jsonObject);
- }
- }, () -> System.out.println("Error downloading auction from Moulberry's jank API. :("));
+ process.accept(jsonObject);
+ }
+ });
}
@@ -508,7 +550,7 @@ public class APIManager {
String auctionUuid = auction.get("uuid").getAsString();
String auctioneerUuid = auction.get("auctioneer").getAsString();
long end = auction.get("end").getAsLong();
- int starting_bid = auction.get("starting_bid").getAsInt();
+ long starting_bid = auction.get("starting_bid").getAsLong();
int highest_bid_amount = auction.get("highest_bid_amount").getAsInt();
int bid_count = auction.get("bids").getAsJsonArray().size();
boolean bin = false;
@@ -637,8 +679,10 @@ public class APIManager {
//System.out.println("Trying to update page: " + page);
HashMap<String, String> args = new HashMap<>();
args.put("page", "" + page);
- manager.hypixelApi.getHypixelApiAsync(null, "skyblock/auctions",
- args, jsonObject -> {
+ manager.apiUtils
+ .newAnonymousHypixelApiRequest("skyblock/auctions")
+ .requestJson()
+ .thenAccept(jsonObject -> {
if (jsonObject == null) return;
if (jsonObject.get("success").getAsBoolean()) {
@@ -665,16 +709,30 @@ public class APIManager {
} else {
pagesToDownload.addLast(page);
}
- }, () -> pagesToDownload.addLast(page)
- );
+ })
+ .handle((ignored, ex) -> {
+ if (ex != null) {
+ pagesToDownload.addLast(page);
+ }
+ return null;
+ });
+ }
+
+ private static final Pattern BAZAAR_ENCHANTMENT_PATTERN = Pattern.compile("ENCHANTMENT_(\\D*)_(\\d+)");
+
+ public String transformHypixelBazaarToNEUItemId(String hypixelId) {
+ Matcher matcher = BAZAAR_ENCHANTMENT_PATTERN.matcher(hypixelId);
+ if (matcher.matches()) {
+ return matcher.group(1) + ";" + matcher.group(2);
+ }
+ return hypixelId.replace(":", "-");
}
public void updateBazaar() {
- manager.hypixelApi.getHypixelApiAsync(
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey,
- "skyblock/bazaar",
- new HashMap<>(),
- (jsonObject) -> {
+ manager.apiUtils
+ .newHypixelApiRequest("skyblock/bazaar")
+ .requestJson()
+ .thenAccept(jsonObject -> {
if (!jsonObject.get("success").getAsBoolean()) return;
craftCost.clear();
@@ -705,24 +763,27 @@ public class APIManager {
}
}
- bazaarJson.add(entry.getKey().replace(":", "-"), productInfo);
+ bazaarJson.add(transformHypixelBazaarToNEUItemId(entry.getKey()), productInfo);
}
}
GuiPriceGraph.addToCache(bazaarJson, true);
- }
- );
+ });
}
public void updateAvgPrices() {
- manager.hypixelApi.getMyApiGZIPAsync("auction_averages/3day.json.gz", (jsonObject) -> {
- craftCost.clear();
- auctionPricesJson = jsonObject;
- lastAuctionAvgUpdate = System.currentTimeMillis();
- }, () -> {
- });
- manager.hypixelApi.getMyApiGZIPAsync("auction_averages_lbin/1day.json.gz", (jsonObject) ->
- auctionPricesAvgLowestBinJson = jsonObject, () -> {
- });
+ manager.apiUtils
+ .newMoulberryRequest("auction_averages/3day.json.gz")
+ .gunzip().requestJson().thenAccept((jsonObject) -> {
+ craftCost.clear();
+ auctionPricesJson = jsonObject;
+ lastAuctionAvgUpdate = System.currentTimeMillis();
+ });
+ manager.apiUtils
+ .newMoulberryRequest("auction_averages_lbin/1day.json.gz")
+ .gunzip().requestJson()
+ .thenAccept((jsonObject) -> {
+ auctionPricesAvgLowestBinJson = jsonObject;
+ });
}
public Set<String> getItemAuctionInfoKeySet() {
@@ -743,13 +804,13 @@ public class APIManager {
return e.getAsJsonObject();
}
- public float getItemAvgBin(String internalname) {
+ public double getItemAvgBin(String internalName) {
if (auctionPricesAvgLowestBinJson == null) return -1;
- JsonElement e = auctionPricesAvgLowestBinJson.get(internalname);
+ JsonElement e = auctionPricesAvgLowestBinJson.get(internalName);
if (e == null) {
return -1;
}
- return Math.round(e.getAsFloat());
+ return Math.round(e.getAsDouble());
}
public Set<String> getBazaarKeySet() {
@@ -761,9 +822,18 @@ public class APIManager {
return keys;
}
- public JsonObject getBazaarInfo(String internalname) {
+ public double getBazaarOrBin(String internalName) {
+ JsonObject bazaarInfo = manager.auctionManager.getBazaarInfo(internalName);
+ if (bazaarInfo != null && bazaarInfo.get("curr_buy") != null) {
+ return bazaarInfo.get("curr_buy").getAsFloat();
+ } else {
+ return manager.auctionManager.getLowestBin(internalName);
+ }
+ }
+
+ public JsonObject getBazaarInfo(String internalName) {
if (bazaarJson == null) return null;
- JsonElement e = bazaarJson.get(internalname);
+ JsonElement e = bazaarJson.get(internalName);
if (e == null) {
return null;
}
@@ -791,7 +861,7 @@ public class APIManager {
public static class CraftInfo {
public boolean fromRecipe = false;
public boolean vanillaItem = false;
- public float craftCost = -1;
+ public double craftCost = -1;
}
public CraftInfo getCraftCost(String internalname) {
@@ -807,10 +877,10 @@ public class APIManager {
visited.add(internalname);
boolean vanillaItem = isVanillaItem(internalname);
- float craftCost = Float.POSITIVE_INFINITY;
+ double craftCost = Double.POSITIVE_INFINITY;
JsonObject auctionInfo = getItemAuctionInfo(internalname);
- float lowestBin = getLowestBin(internalname);
+ double lowestBin = getLowestBin(internalname);
JsonObject bazaarInfo = getBazaarInfo(internalname);
if (bazaarInfo != null && bazaarInfo.get("curr_buy") != null) {
@@ -857,7 +927,7 @@ public class APIManager {
}
}
visited.remove(internalname);
- if (Float.isInfinite(craftCost)) {
+ if (Double.isInfinite(craftCost)) {
return null;
}
CraftInfo craftInfo = new CraftInfo();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java
index 123da60a..7b4542d0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAH.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.auction;
import com.google.gson.JsonObject;
@@ -35,14 +54,23 @@ import org.lwjgl.opengl.GL14;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.*;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.*;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.auction_accept;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.auction_price;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.auction_view;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.auction_view_buttons;
public class CustomAH extends Gui {
private enum PriceFilter {
@@ -66,7 +94,7 @@ public class CustomAH extends Gui {
private boolean shouldUpdateSearch = false;
private boolean shouldSortItems = false;
- private int startingBid = 0;
+ private long startingBid = 0;
private String currentAucId = null;
private int clickedMainCategory = -1;
@@ -105,6 +133,8 @@ public class CustomAH extends Gui {
public int guiLeft = -1;
public int guiTop = -1;
+ private String lastSearch = "";
+
private final Category CATEGORY_SWORD = new Category("sword", "Swords", "diamond_sword");
private final Category CATEGORY_ARMOR = new Category("armor", "Armor", "diamond_chestplate");
private final Category CATEGORY_BOWS = new Category("bow", "Bows", "bow");
@@ -247,7 +277,11 @@ public class CustomAH extends Gui {
}
public void setSearch(String search) {
- searchField.setText(search);
+ if (search == null) {
+ searchField.setText(lastSearch);
+ } else {
+ searchField.setText(search);
+ }
updateSearch();
}
@@ -612,7 +646,7 @@ public class CustomAH extends Gui {
}
}
if (priceNumbers.length() > 0) {
- startingBid = Integer.parseInt(priceNumbers.toString());
+ startingBid = Long.parseLong(priceNumbers.toString());
}
}
}
@@ -651,7 +685,7 @@ public class CustomAH extends Gui {
boolean hasAuctionPrice = auctionInfo != null;
boolean hasBazaarPrice = bazaarInfo != null;
- int lowestBin = manager.auctionManager.getLowestBin(internalname);
+ long lowestBin = manager.auctionManager.getLowestBin(internalname);
NumberFormat format = NumberFormat.getInstance(Locale.US);
@@ -1347,7 +1381,7 @@ public class CustomAH extends Gui {
}
}
if (getBinPriceFilterAmount() > -1) {
- int lowestBin =
+ long lowestBin =
NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(
auc.getStack()));
if (lowestBin > 0) {
@@ -1459,8 +1493,15 @@ public class CustomAH extends Gui {
auctionIdsNew.add(entry.getKey());
}
}
+ if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.saveLastSearch) {
+ lastSearch = "";
+ }
} else {
String query = searchField.getText();
+
+ if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.saveLastSearch) {
+ lastSearch = query;
+ }
Set<String> dontMatch = new HashSet<>();
HashSet<String> allMatch = new HashSet<>();
@@ -1550,18 +1591,18 @@ public class CustomAH extends Gui {
if (auc2 == null) return -1;
if (sortMode == SORT_MODE_HIGH) {
- int price1 = Math.max(auc1.highest_bid_amount, auc1.starting_bid);
- int price2 = Math.max(auc2.highest_bid_amount, auc2.starting_bid);
- int diff = price2 - price1;
+ long price1 = Math.max(auc1.highest_bid_amount, auc1.starting_bid);
+ long price2 = Math.max(auc2.highest_bid_amount, auc2.starting_bid);
+ long diff = price2 - price1;
if (diff != 0) {
- return diff;
+ return Long.compare(price2, price1);
}
} else if (sortMode == SORT_MODE_LOW) {
- int price1 = Math.max(auc1.highest_bid_amount, auc1.starting_bid);
- int price2 = Math.max(auc2.highest_bid_amount, auc2.starting_bid);
- int diff = price1 - price2;
+ long price1 = Math.max(auc1.highest_bid_amount, auc1.starting_bid);
+ long price2 = Math.max(auc2.highest_bid_amount, auc2.starting_bid);
+ long diff = price1 - price2;
if (diff != 0) {
- return diff;
+ return Long.compare(price1, price2);
}
} else {
long end1 = auc1.end;
@@ -1589,7 +1630,6 @@ public class CustomAH extends Gui {
return false;
}
- Keyboard.enableRepeatEvents(true);
if (isEditingPrice() && Keyboard.getEventKey() == Keyboard.KEY_RETURN) {
Minecraft.getMinecraft().displayGuiScreen(null);
} else if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
@@ -1652,16 +1692,16 @@ public class CustomAH extends Gui {
priceField.setText((int) (priceI * factor) + end);
}
- private int getPriceFilterAmount() {
+ private long getPriceFilterAmount() {
return getNumberFromTextBox(priceFilterField);
}
- private int getNumberFromTextBox(GuiTextField textField) {
+ private long getNumberFromTextBox(GuiTextField textField) {
if (textField.getText().equals("")) {
return -2;
}
try {
- int parsed = Integer.parseInt(textField.getText());
+ long parsed = Long.parseLong(textField.getText());
if (parsed < 0) {
return -1;
}
@@ -1671,7 +1711,7 @@ public class CustomAH extends Gui {
}
}
- private int getBinPriceFilterAmount() {
+ private long getBinPriceFilterAmount() {
return getNumberFromTextBox(binPriceFilterField);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAHGui.java b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAHGui.java
index 9311040d..ca85ca1c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAHGui.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/auction/CustomAHGui.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.auction;
import net.minecraft.client.gui.GuiScreen;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/collectionlog/CollectionConstant.java b/src/main/java/io/github/moulberry/notenoughupdates/collectionlog/CollectionConstant.java
deleted file mode 100644
index e789e882..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/collectionlog/CollectionConstant.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.github.moulberry.notenoughupdates.collectionlog;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.regex.Pattern;
-
-public class CollectionConstant {
- public static class DropEntry {
- public String type;
- public Pattern regex;
- public HashMap<String, String> items;
- }
-
- public List<DropEntry> dropdata;
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/collectionlog/GuiCollectionLog.java b/src/main/java/io/github/moulberry/notenoughupdates/collectionlog/GuiCollectionLog.java
deleted file mode 100644
index dac104c6..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/collectionlog/GuiCollectionLog.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package io.github.moulberry.notenoughupdates.collectionlog;
-
-import io.github.moulberry.notenoughupdates.core.BackgroundBlur;
-import io.github.moulberry.notenoughupdates.core.GlScissorStack;
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.util.EnumChatFormatting;
-import net.minecraft.util.ResourceLocation;
-import org.lwjgl.opengl.GL11;
-
-public class GuiCollectionLog extends GuiScreen {
- private static final ResourceLocation COLLECTION_LOG_TEX = new ResourceLocation("notenoughupdates:collectionlog.png");
-
- @Override
- public void drawScreen(int mouseX, int mouseY, float partialTicks) {
- ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
- int width = scaledResolution.getScaledWidth();
- int height = scaledResolution.getScaledHeight();
-
- int colwidth = 307;
- int colheight = 187;
-
- int left = width / 2 - colwidth / 2;
- int top = height / 2 - colheight / 2;
-
- BackgroundBlur.renderBlurredBackground(10, width, height, left, top, colwidth, colheight);
- super.drawDefaultBackground();
-
- Utils.drawStringCentered("\u00a7lCollection Log", fontRendererObj, width / 2, top - 27, true, 0xfff5aa00);
-
- String[] cats = {"Bosses", "Dragons", "Slayer", "Dungeons"};
-
- GlStateManager.enableDepth();
-
- GlStateManager.translate(0, 0, 2);
- for (int i = 0; i < 4; i++) {
- if (i == 0) {
- int offset = i == 0 ? 1 : 2;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(COLLECTION_LOG_TEX);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(left + i * 71, top - 21, 71, 25,
- (71 * offset) / 512f, (71 + 71 * offset) / 512f, 211 / 512f, (211 + 25) / 512f, GL11.GL_NEAREST
- );
-
- Utils.drawStringCentered(cats[i], fontRendererObj, left + i * 71 + 71 / 2, top - 8, true, 0xfff5aa00);
- }
- }
-
- GlStateManager.translate(0, 0, -1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(COLLECTION_LOG_TEX);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(left, top, colwidth, colheight,
- 0, colwidth / 512f, 0, colheight / 512f, GL11.GL_NEAREST
- );
-
- GlScissorStack.push(0, top + 3, width, top + colheight - 6, scaledResolution);
- int catIndex = 0;
- for (int h = top + 3; h < top + colheight - 6; h += 24) {
- catIndex += 2;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(COLLECTION_LOG_TEX);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(left, h, 100, 24,
- 0, 100 / 512f, 187 / 512f, 211 / 512f, GL11.GL_NEAREST
- );
-
- fontRendererObj.drawString("Thing " + catIndex, left + 5, h + 2, 0xfff5aa00, true);
- fontRendererObj.drawString("Thing " + (catIndex + 1), left + 5, h + 14, 0xfff5aa00, true);
- }
- GlScissorStack.pop(scaledResolution);
-
- fontRendererObj.drawString("\u00a7lSuperior Dragon", left + 119, top + 8, 0xfff5aa00, true);
- fontRendererObj.drawString(
- "Obtained: " + EnumChatFormatting.YELLOW + "3/5",
- left + 122,
- top + 23,
- 0xfff5aa00,
- true
- );
-
- String killCountText = "Kills: " + EnumChatFormatting.WHITE + "3";
- //int killCountLen = fontRendererObj.getStringWidth(killCountText);
- fontRendererObj.drawString(killCountText, left + 122, top + 68, 0xfff5aa00, true);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(COLLECTION_LOG_TEX);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(left + colwidth - 196, top, 196, colheight,
- (512 - 196) / 512f, 1, 0 / 512f, colheight / 512f, GL11.GL_NEAREST
- );
-
- GlStateManager.translate(0, 0, -1);
-
- for (int i = 0; i < 4; i++) {
- if (i != 0) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(COLLECTION_LOG_TEX);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(left + i * 71, top - 21, 71, 25,
- 0, 71 / 512f, 211 / 512f, (211 + 25) / 512f, GL11.GL_NEAREST
- );
-
- Utils.drawStringCentered(cats[i], fontRendererObj, left + i * 71 + 71 / 2, top - 8, true, 0xfff5aa00);
- }
- }
-
- super.drawScreen(mouseX, mouseY, partialTicks);
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/ClientCommandBase.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/ClientCommandBase.java
index 8ba87ecd..e0ae7a1a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/ClientCommandBase.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/ClientCommandBase.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands;
import net.minecraft.command.CommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java
index de017cb5..62981a30 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/Commands.java
@@ -1,22 +1,54 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands;
-import io.github.moulberry.notenoughupdates.commands.dev.*;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.dev.DevTestCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.DiagCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.DungeonWinTestCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.EnableStorageCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.NullzeeSphereCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.PackDevCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.ReloadRepoCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.ResetRepoCommand;
+import io.github.moulberry.notenoughupdates.commands.dev.StatsCommand;
import io.github.moulberry.notenoughupdates.commands.dungeon.DhCommand;
import io.github.moulberry.notenoughupdates.commands.dungeon.DnCommand;
import io.github.moulberry.notenoughupdates.commands.dungeon.JoinDungeonCommand;
import io.github.moulberry.notenoughupdates.commands.dungeon.MapCommand;
-import io.github.moulberry.notenoughupdates.commands.help.*;
+import io.github.moulberry.notenoughupdates.commands.help.FeaturesCommand;
+import io.github.moulberry.notenoughupdates.commands.help.HelpCommand;
+import io.github.moulberry.notenoughupdates.commands.help.LinksCommand;
+import io.github.moulberry.notenoughupdates.commands.help.SettingsCommand;
+import io.github.moulberry.notenoughupdates.commands.help.StorageViewerWhyCommand;
import io.github.moulberry.notenoughupdates.commands.misc.AhCommand;
+import io.github.moulberry.notenoughupdates.commands.misc.CalculatorCommand;
import io.github.moulberry.notenoughupdates.commands.misc.CalendarCommand;
import io.github.moulberry.notenoughupdates.commands.misc.CosmeticsCommand;
import io.github.moulberry.notenoughupdates.commands.misc.CustomizeCommand;
+import io.github.moulberry.notenoughupdates.commands.misc.PronounsCommand;
+import io.github.moulberry.notenoughupdates.commands.misc.UpdateCommand;
import io.github.moulberry.notenoughupdates.commands.profile.CataCommand;
import io.github.moulberry.notenoughupdates.commands.profile.PeekCommand;
import io.github.moulberry.notenoughupdates.commands.profile.PvCommand;
import io.github.moulberry.notenoughupdates.commands.profile.ViewProfileCommand;
-import io.github.moulberry.notenoughupdates.commands.repo.ReloadRepoCommand;
-import io.github.moulberry.notenoughupdates.commands.repo.RepoModeCommand;
-import io.github.moulberry.notenoughupdates.commands.repo.ResetRepoCommand;
import io.github.moulberry.notenoughupdates.miscfeatures.FairySouls;
import io.github.moulberry.notenoughupdates.miscgui.GuiEnchantColour;
import io.github.moulberry.notenoughupdates.miscgui.GuiInvButtonEditor;
@@ -40,11 +72,10 @@ public class Commands {
ClientCommandHandler.instance.registerCommand(new StatsCommand());
ClientCommandHandler.instance.registerCommand(new DevTestCommand());
ClientCommandHandler.instance.registerCommand(new NullzeeSphereCommand());
-
- // Repo Commands
- ClientCommandHandler.instance.registerCommand(new ResetRepoCommand());
- ClientCommandHandler.instance.registerCommand(new RepoModeCommand());
+ ClientCommandHandler.instance.registerCommand(new DiagCommand());
ClientCommandHandler.instance.registerCommand(new ReloadRepoCommand());
+ ClientCommandHandler.instance.registerCommand(new ResetRepoCommand());
+ ClientCommandHandler.instance.registerCommand(new EnableStorageCommand());
// Profile Commands
ClientCommandHandler.instance.registerCommand(new PeekCommand());
@@ -66,7 +97,10 @@ public class Commands {
ClientCommandHandler.instance.registerCommand(new ScreenCommand("neuoverlay", NEUOverlayPlacements::new));
//ClientCommandHandler.instance.registerCommand(new ScreenCommand("neututorial", NeuTutorial::new));
ClientCommandHandler.instance.registerCommand(new AhCommand());
+ ClientCommandHandler.instance.registerCommand(new CalculatorCommand());
ClientCommandHandler.instance.registerCommand(new CalendarCommand());
+ ClientCommandHandler.instance.registerCommand(new UpdateCommand(NotEnoughUpdates.INSTANCE));
+ ClientCommandHandler.instance.registerCommand(new PronounsCommand());
// Fairy Soul Commands
ClientCommandHandler.instance.registerCommand(new FairySouls.FairySoulsCommand());
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java
new file mode 100644
index 00000000..e3738661
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/EntityViewerCommand.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands;
+
+import com.google.common.collect.Lists;
+import io.github.moulberry.notenoughupdates.miscfeatures.entityviewer.EntityViewer;
+import net.minecraft.client.Minecraft;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedDeque;
+
+public class EntityViewerCommand extends ClientCommandBase {
+ public EntityViewerCommand() {
+ super("neushowentity");
+ MinecraftForge.EVENT_BUS.register(this);
+ }
+
+ @Override
+ public List<String> getCommandAliases() {
+ return Lists.newArrayList("neuentityviewer");
+ }
+
+ @Override
+ public String getCommandUsage(ICommandSender sender) {
+ return EnumChatFormatting.RED + "Use /neushowentity list";
+ }
+
+ public void showUsage(ICommandSender sender) {
+ sender.addChatMessage(new ChatComponentText(getCommandUsage(sender)));
+ }
+
+ private final Queue<EntityViewer> queuedGUIS = new ConcurrentLinkedDeque<>();
+
+ @SubscribeEvent
+ public void onTick(TickEvent event) {
+ if (Minecraft.getMinecraft().currentScreen == null) {
+ EntityViewer poll = queuedGUIS.poll();
+ if (poll == null) return;
+ Minecraft.getMinecraft().displayGuiScreen(poll);
+ }
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] strings) throws CommandException {
+ if (strings.length == 0) {
+ showUsage(sender);
+ return;
+ }
+ if (strings[0].equals("list")) {
+ for (String label : EntityViewer.validEntities.keySet()) {
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.BLUE + " " + label)
+ .setChatStyle(new ChatStyle().setChatClickEvent(
+ new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/neuentityviewer " + label))));
+ }
+ return;
+ }
+ EntityLivingBase entityLivingBase;
+ if (strings[0].startsWith("@")) {
+ ResourceLocation resourceLocation = new ResourceLocation(strings[0].substring(1));
+ entityLivingBase = EntityViewer.constructEntity(resourceLocation);
+ } else {
+ entityLivingBase = EntityViewer.constructEntity(strings[0], Arrays.copyOfRange(strings, 1, strings.length));
+ }
+ if (entityLivingBase == null) {
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "Could not create that entity"));
+ return;
+ }
+ queuedGUIS.add(new EntityViewer(strings[0], entityLivingBase));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/ScreenCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/ScreenCommand.java
index 29dd9d55..1b90e5df 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/ScreenCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/ScreenCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
index 66da4f9f..972557c8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DevTestCommand.java
@@ -1,34 +1,66 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dev;
+import io.github.moulberry.notenoughupdates.BuildFlags;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
import io.github.moulberry.notenoughupdates.core.config.GuiPositionEditor;
-import io.github.moulberry.notenoughupdates.miscfeatures.FancyPortals;
import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.SpecialBlockZone;
import io.github.moulberry.notenoughupdates.miscgui.GuiPriceGraph;
+import io.github.moulberry.notenoughupdates.util.PronounDB;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import net.minecraft.client.Minecraft;
-import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.GuiScreen;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
-import net.minecraft.util.*;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.EnumParticleTypes;
import net.minecraftforge.common.MinecraftForge;
-import java.io.File;
import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
public class DevTestCommand extends ClientCommandBase {
private static final List<String> DEV_TESTERS =
- Arrays.asList("moulberry", "lucycoconut", "ironm00n", "ariyio", "throwpo", "lrg89", "dediamondpro");
+ Arrays.asList(
+ "moulberry",
+ "lucycoconut",
+ "ironm00n",
+ "ariyio",
+ "throwpo",
+ "lrg89",
+ "dediamondpro",
+ "lulonaut",
+ "craftyoldminer",
+ "eisengolem",
+ "whalker",
+ "ascynx"
+ );
private static final String[] DEV_FAIL_STRINGS = {
"No.",
@@ -48,9 +80,7 @@ public class DevTestCommand extends ClientCommandBase {
"",
"Ok, this is actually the last message, use the command again and you'll crash I promise"
};
-
private int devFailIndex = 0;
- private final ScheduledExecutorService devES = Executors.newSingleThreadScheduledExecutor();
public DevTestCommand() {
super("neudevtest");
@@ -84,10 +114,6 @@ public class DevTestCommand extends ClientCommandBase {
DEV_FAIL_STRINGS[devFailIndex++]));
return;
}
- /*if(args.length == 1) {
- DupePOC.doDupe(args[0]);
- return;
- }*/
if (args.length >= 1 && args[0].equalsIgnoreCase("profileinfo")) {
String currentProfile = SBInfo.getInstance().currentProfile;
SBInfo.Gamemode gamemode = SBInfo.getInstance().getGamemodeForProfile(currentProfile);
@@ -97,6 +123,14 @@ public class DevTestCommand extends ClientCommandBase {
" with the mode " +
gamemode));
}
+ if (args.length >= 1 && args[0].equalsIgnoreCase("buildflags")) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "BuildFlags: \n" +
+ BuildFlags.getAllFlags().entrySet().stream()
+ .map(it -> " + " + it.getKey() + " - " + it.getValue())
+ .collect(Collectors.joining("\n"))));
+ return;
+ }
if (args.length >= 1 && args[0].equalsIgnoreCase("pricetest")) {
if (args.length == 1) {
NotEnoughUpdates.INSTANCE.manager.auctionManager.updateBazaar();
@@ -142,66 +176,24 @@ public class DevTestCommand extends ClientCommandBase {
"I would never search"));
return;
}
+ if (args.length == 1 && args[0].equalsIgnoreCase("bluehair")) {
+ PronounDB.test();
+ return;
+ }
+ if (args.length == 2 && args[0].equalsIgnoreCase("openGui")) {
+ try {
+ NotEnoughUpdates.INSTANCE.openGui = (GuiScreen) Class.forName(args[1]).newInstance();
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "Opening gui: " + NotEnoughUpdates.INSTANCE.openGui));
+ } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | ClassCastException e) {
+ e.printStackTrace();
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Failed to open this gui."));
+ }
+ }
if (args.length == 1 && args[0].equalsIgnoreCase("center")) {
double x = Math.floor(Minecraft.getMinecraft().thePlayer.posX) + 0.5f;
double z = Math.floor(Minecraft.getMinecraft().thePlayer.posZ) + 0.5f;
Minecraft.getMinecraft().thePlayer.setPosition(x, Minecraft.getMinecraft().thePlayer.posY, z);
- return;
}
- if (args.length == 1 && args[0].equalsIgnoreCase("pansc")) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN +
- "Taking panorama screenshot"));
-
- AtomicInteger perspective = new AtomicInteger(0);
- FancyPortals.perspectiveId = 0;
-
- EntityPlayerSP p = Minecraft.getMinecraft().thePlayer;
- p.prevRotationYaw = p.rotationYaw = 0;
- p.prevRotationPitch = p.rotationPitch = 90;
- devES.schedule(new Runnable() {
- @Override
- public void run() {
- Minecraft.getMinecraft().addScheduledTask(() -> {
- ScreenShotHelper.saveScreenshot(new File("C:/Users/James/Desktop/"), "pansc-" + perspective.get() + ".png",
- Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight,
- Minecraft.getMinecraft().getFramebuffer()
- );
- });
- if (perspective.incrementAndGet() >= 6) {
- FancyPortals.perspectiveId = -1;
- return;
- }
- devES.schedule(() -> {
- FancyPortals.perspectiveId = perspective.get();
- if (FancyPortals.perspectiveId == 5) {
- p.prevRotationYaw = p.rotationYaw = 0;
- p.prevRotationPitch = p.rotationPitch = -90;
- } else if (FancyPortals.perspectiveId >= 1 && FancyPortals.perspectiveId <= 4) {
- float yaw = 90 * FancyPortals.perspectiveId - 180;
- if (yaw > 180) yaw -= 360;
- p.prevRotationYaw = p.rotationYaw = yaw;
- p.prevRotationPitch = p.rotationPitch = 0;
- }
- devES.schedule(this, 3000L, TimeUnit.MILLISECONDS);
- }, 100L, TimeUnit.MILLISECONDS);
- }
- }, 3000L, TimeUnit.MILLISECONDS);
-
- return;
- }
-
- /* if(args.length == 1 && args[0].equalsIgnoreCase("update")) {
- NEUEventListener.displayUpdateMessageIfOutOfDate();
- } */
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN +
- "Executing dubious code"));
- /*Minecraft.getMinecraft().thePlayer.rotationYaw = 0;
- Minecraft.getMinecraft().thePlayer.rotationPitch = 0;
- Minecraft.getMinecraft().thePlayer.setPosition(
- Math.floor(Minecraft.getMinecraft().thePlayer.posX) + Float.parseFloat(args[0]),
- Minecraft.getMinecraft().thePlayer.posY,
- Minecraft.getMinecraft().thePlayer.posZ);*/
- //Hot reload me yay!
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java
new file mode 100644
index 00000000..fb546efb
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DiagCommand.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.dev;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver;
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+
+public class DiagCommand extends ClientCommandBase {
+ public DiagCommand() {
+ super("neudiag");
+ }
+
+ private static final String USAGE_TEXT = EnumChatFormatting.WHITE +
+ "Usage: /neudiag <metal | wishing | debug>\n\n" +
+ "/neudiag metal Metal Detector Solver diagnostics\n" +
+ " <no sub-command> Show current solution diags\n" +
+ " center=<off | on> Disable / enable using center\n" +
+ "/neudiag wishing Wishing Compass Solver diagnostics\n" +
+ "/neudiag debug\n" +
+ " <no sub-command> Show all enabled flags\n" +
+ " <list> Show all flags\n"+
+ " <enable | disable> <flag> Enable/disable flag\n";
+
+ private void showUsage(ICommandSender sender) {
+ sender.addChatMessage(new ChatComponentText(USAGE_TEXT));
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ if (args.length == 0) {
+ showUsage(sender);
+ return;
+ }
+
+ String command = args[0].toLowerCase();
+ switch (command) {
+ case "metal":
+ if (args.length == 1) {
+ CrystalMetalDetectorSolver.logDiagnosticData(true);
+ return;
+ }
+
+ String subCommand = args[1].toLowerCase();
+ if (subCommand.equals("center=off")) {
+ CrystalMetalDetectorSolver.setDebugDoNotUseCenter(true);
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "Center coordinates-based solutions disabled"));
+ } else if (subCommand.equals("center=on")) {
+ CrystalMetalDetectorSolver.setDebugDoNotUseCenter(false);
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "Center coordinates-based solutions enabled"));
+ } else {
+ showUsage(sender);
+ return;
+ }
+
+ break;
+ case "wishing":
+ CrystalWishingCompassSolver.getInstance().logDiagnosticData(true);
+ break;
+ case "debug":
+ if (args.length > 1) {
+ boolean enablingFlag = true;
+ String action = args[1];
+ switch (action) {
+ case "list":
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.YELLOW + "Here are all flags:\n" + NEUDebugFlag.getFlagList()));
+ return;
+ case "disable":
+ enablingFlag = false;
+ // falls through
+ case "enable":
+ if (args.length != 3) {
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "You must specify a flag:\n" +
+ NEUDebugFlag.getFlagList()));
+ return;
+ }
+
+ String flagName = args[2].toUpperCase();
+ try {
+ NEUDebugFlag debugFlag = NEUDebugFlag.valueOf(flagName);
+ if (enablingFlag) {
+ NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.add(debugFlag);
+ } else {
+ NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.remove(debugFlag);
+ }
+ } catch (IllegalArgumentException e) {
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ flagName + " is invalid. Valid flags are:\n" +
+ NEUDebugFlag.getFlagList()));
+ return;
+ }
+ break;
+ default:
+ showUsage(sender);
+ return;
+ }
+ }
+
+ sender.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "Effective debug flags: \n" +
+ NEUDebugFlag.getEnabledFlags()));
+ break;
+ default:
+ showUsage(sender);
+ return;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DungeonWinTestCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DungeonWinTestCommand.java
index 223e154a..be25e697 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DungeonWinTestCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/DungeonWinTestCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dev;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/EnableStorageCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/EnableStorageCommand.java
new file mode 100644
index 00000000..3415b030
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/EnableStorageCommand.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.dev;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+
+public class EnableStorageCommand extends ClientCommandBase {
+
+ public EnableStorageCommand() {
+ super("neuenablestorage");
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ NotEnoughUpdates.INSTANCE.config.storageGUI.enableStorageGUI3 = true;
+ NotEnoughUpdates.INSTANCE.saveConfig();
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/NullzeeSphereCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/NullzeeSphereCommand.java
index 64d64545..3a9ce90f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/NullzeeSphereCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/NullzeeSphereCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dev;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/PackDevCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/PackDevCommand.java
index e809ed72..e1504472 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/PackDevCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/PackDevCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dev;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -5,55 +24,281 @@ import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
import io.github.moulberry.notenoughupdates.core.util.MiscUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.AbstractClientPlayer;
-import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLiving;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.item.EntityArmorStand;
import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
+import java.util.HashMap;
+import java.util.List;
+import java.util.function.Supplier;
+
public class PackDevCommand extends ClientCommandBase {
+ static Minecraft mc = Minecraft.getMinecraft();
public PackDevCommand() {
super("neupackdev");
}
+ private static final HashMap<String, Command<?, ?>> commands = new HashMap<String, Command<?, ?>>() {{
+ put(
+ "getnpc",
+ new Command<>(
+ "NPC",
+ () -> mc.theWorld.playerEntities,
+ true,
+ AbstractClientPlayer.class
+ )
+ );
+ put(
+ "getnpcs",
+ new Command<>(
+ "NPC",
+ () -> mc.theWorld.playerEntities,
+ false,
+ AbstractClientPlayer.class
+ )
+ );
+ put(
+ "getmob",
+ new Command<>(
+ "mob",
+ () -> mc.theWorld.loadedEntityList,
+ true,
+ EntityLiving.class
+ )
+ );
+ put(
+ "getmobs",
+ new Command<>(
+ "mob",
+ () -> mc.theWorld.loadedEntityList,
+ false,
+ EntityLiving.class
+ )
+ );
+ put(
+ "getarmorstand",
+ new Command<>(
+ "armor stand",
+ () -> mc.theWorld.loadedEntityList,
+ true,
+ EntityArmorStand.class
+ )
+ );
+ put(
+ "getarmorstands",
+ new Command<>(
+ "armor stand",
+ () -> mc.theWorld.loadedEntityList,
+ false,
+ EntityArmorStand.class
+ )
+ );
+ }};
+
+ @Override
+ public List<String> addTabCompletionOptions(ICommandSender sender, String[] args, BlockPos pos) {
+ return args.length == 1 ? getListOfStringsMatchingLastWord(args, commands.keySet()) : null;
+ }
+
+ public static void togglePackDeveloperMode(ICommandSender sender) {
+ NotEnoughUpdates.INSTANCE.packDevEnabled = !NotEnoughUpdates.INSTANCE.packDevEnabled;
+ if (NotEnoughUpdates.INSTANCE.packDevEnabled) {
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.GREEN + "Enabled pack developer mode."));
+ } else {
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Disabled pack developer mode."));
+ }
+ }
+
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
- if (args.length == 1 && args[0].equalsIgnoreCase("getnpc")) {
- double distSq = 25;
- EntityPlayer closestNPC = null;
- EntityPlayerSP p = Minecraft.getMinecraft().thePlayer;
- for (EntityPlayer player : Minecraft.getMinecraft().theWorld.playerEntities) {
- if (player instanceof AbstractClientPlayer && p != player && player.getUniqueID().version() != 4) {
- double dSq = player.getDistanceSq(p.posX, p.posY, p.posZ);
- if (dSq < distSq) {
- distSq = dSq;
- closestNPC = player;
+ if (args.length == 0) {
+ togglePackDeveloperMode(sender);
+ return;
+ }
+
+ double dist = 5.0;
+ if (args.length >= 2) {
+ try {
+ dist = Double.parseDouble(args[1]);
+ } catch (NumberFormatException e) {
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Invalid distance! Must be a number, defaulting to a radius of 5."));
+ }
+ }
+
+ StringBuilder output;
+ String subCommand = args[0].toLowerCase();
+ if (commands.containsKey(subCommand)) {
+ Command<?, ?> command = commands.get(subCommand);
+ output = command.getData(dist);
+ } else if (subCommand.equals("getall")) {
+ output = getAll(dist);
+ } else if (subCommand.equals("getallclose")) {
+ output = getAllClose(dist);
+ } else {
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Invalid sub-command."));
+ return;
+ }
+
+ if (output.length() != 0) {
+ MiscUtils.copyToClipboard(output.toString());
+ }
+ }
+
+ private static StringBuilder getAllClose(Double dist) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(commands.get("getmob").getData(dist));
+ sb.append(commands.get("getarmorstand").getData(dist));
+ sb.append(commands.get("getnpc").getData(dist));
+ return sb;
+ }
+
+ private static StringBuilder getAll(Double dist) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(commands.get("getmobs").getData(dist));
+ sb.append(commands.get("getarmorstands").getData(dist));
+ sb.append(commands.get("getnpcs").getData(dist));
+ return sb;
+ }
+
+ public static <T extends EntityLivingBase> StringBuilder livingBaseDataBuilder(T entity, Class<T> clazz) {
+ StringBuilder entityData = new StringBuilder();
+ if (EntityPlayer.class.isAssignableFrom(entity.getClass())) {
+ EntityPlayer entityPlayer = (EntityPlayer) entity;
+
+ // NPC Information
+ String skinResourcePath = ((AbstractClientPlayer) entityPlayer).getLocationSkin().getResourcePath();
+ entityData
+ .append("Player Id: ")
+ .append(entityPlayer.getUniqueID() != null ? entityPlayer.getUniqueID().toString() : "null")
+ .append(entityPlayer.getCustomNameTag() != null ? entityPlayer.getCustomNameTag() : "null")
+ .append("\nEntity Texture Id: ")
+ .append(skinResourcePath != null ? skinResourcePath.replace("skins/", "") : "null");
+ }
+
+ if (!clazz.isAssignableFrom(entity.getClass())) {
+ return entityData;
+ }
+
+ //Entity Information
+ entityData
+ .append("Entity Id: ")
+ .append(entity.getEntityId())
+ .append("\nMob: ")
+ .append(entity.getName() != null ? entity.getName() : "null")
+ .append("\nCustom Name: ")
+ .append(entity.getCustomNameTag() != null ? entity.getCustomNameTag() : "null");
+
+ //Held Item
+ if (entity.getHeldItem() != null) {
+ entityData
+ .append("\nItem: ")
+ .append(entity.getHeldItem())
+ .append("\nItem Display Name: ")
+ .append(entity.getHeldItem().getDisplayName() != null
+ ? entity.getHeldItem().getDisplayName()
+ : "null")
+ .append("\nItem Tag Compound: ");
+ NBTTagCompound heldItemTagCompound = entity.getHeldItem().getTagCompound();
+ if (heldItemTagCompound != null) {
+ String heldItemString = heldItemTagCompound.toString();
+ NBTBase extraAttrTag = heldItemTagCompound.getTag("ExtraAttributes");
+ entityData
+ .append(heldItemString != null ? heldItemString : "null")
+ .append("\nItem Tag Compound Extra Attributes: ")
+ .append(extraAttrTag != null ? extraAttrTag : "null");
+ } else {
+ entityData.append("null");
+ }
+
+ } else {
+ entityData.append("\nItem: null");
+ }
+
+ entityData.append(armorDataBuilder(entity)).append("\n\n");
+
+ return entityData;
+ }
+
+ private static final String[] armorPieceTypes = {"Boots", "Leggings", "Chestplate", "Helmet"};
+
+ public static <T extends EntityLivingBase> StringBuilder armorDataBuilder(T entity) {
+ StringBuilder armorData = new StringBuilder();
+ for (int i = 0; i < 4; i++) {
+ ItemStack currentArmor = entity.getCurrentArmor(0);
+ armorData.append(String.format("\n%s: ", armorPieceTypes[i]));
+ if (currentArmor == null) {
+ armorData.append("null");
+ } else {
+ armorData.append(currentArmor.getTagCompound() != null ? currentArmor.getTagCompound().toString() : "null");
+ }
+ }
+ return armorData;
+ }
+
+ static class Command<T extends EntityLivingBase, U extends Entity> {
+ String typeFriendlyName;
+ Supplier<List<U>> entitySupplier;
+ Class<T> clazz;
+ boolean single;
+
+ Command(
+ String typeFriendlyName,
+ Supplier<List<U>> entitySupplier,
+ boolean single,
+ Class<T> clazz
+ ) {
+ this.typeFriendlyName = typeFriendlyName;
+ this.entitySupplier = entitySupplier;
+ this.single = single;
+ this.clazz = clazz;
+ }
+
+ @SuppressWarnings("unchecked")
+ public StringBuilder getData(double dist) {
+ StringBuilder result = new StringBuilder();
+ double distSq = dist * dist;
+ T closest = null;
+ for (Entity entity : entitySupplier.get()) {
+ if (!clazz.isAssignableFrom(entity.getClass()) || entity == mc.thePlayer) {
+ continue;
+ }
+ T entityT = (T) entity;
+ double entityDistanceSq = entity.getDistanceSq(mc.thePlayer.posX, mc.thePlayer.posY, mc.thePlayer.posZ);
+ if (entityDistanceSq < distSq) {
+ if (single) {
+ distSq = entityDistanceSq;
+ closest = entityT;
+ } else {
+ result.append(livingBaseDataBuilder(entityT, clazz));
}
}
}
- if (closestNPC == null) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.RED + "No NPCs found within 5 blocks :("));
+ if ((single && closest == null) || (!single && result.length() == 0)) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "No " + typeFriendlyName + "s found within " + dist + " blocks."));
} else {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.GREEN + "Copied entity texture id to clipboard"));
- MiscUtils.copyToClipboard(((AbstractClientPlayer) closestNPC)
- .getLocationSkin()
- .getResourcePath()
- .replace("skins/", ""));
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.GREEN + "Copied " + typeFriendlyName + " data to clipboard"));
+ return single ? livingBaseDataBuilder(closest, clazz) : result;
}
- return;
- }
- NotEnoughUpdates.INSTANCE.packDevEnabled = !NotEnoughUpdates.INSTANCE.packDevEnabled;
- if (NotEnoughUpdates.INSTANCE.packDevEnabled) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.GREEN + "Enabled pack developer mode."));
- } else {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.RED + "Disabled pack developer mode."));
+
+ return result;
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ReloadRepoCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ReloadRepoCommand.java
new file mode 100644
index 00000000..0bf57594
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ReloadRepoCommand.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.dev;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.ChatComponentText;
+
+public class ReloadRepoCommand extends ClientCommandBase {
+
+ public ReloadRepoCommand() {
+ super("neureloadrepo");
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ NotEnoughUpdates.INSTANCE.manager.reloadRepository();
+ sender.addChatMessage(new ChatComponentText("§e[NEU] Reloaded repository."));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ResetRepoCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ResetRepoCommand.java
new file mode 100644
index 00000000..3f693898
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/ResetRepoCommand.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.dev;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.ChatComponentText;
+
+public class ResetRepoCommand extends ClientCommandBase {
+
+ public ResetRepoCommand() {
+ super("neuresetrepo");
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ NotEnoughUpdates.INSTANCE.manager
+ .userFacingRepositoryReload()
+ .thenAccept(strings ->
+ strings.forEach(line ->
+ sender.addChatMessage(new ChatComponentText("§e[NEU] " + line))));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/StatsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/StatsCommand.java
index 38eafe39..756afc88 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/StatsCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dev/StatsCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dev;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -146,7 +165,7 @@ public class StatsCommand extends ClientCommandBase {
builder.append("Loaded Mods", String.valueOf(activeModCount));
builder.append("Forge", ForgeVersion.getVersion());
builder.category("Neu Settings");
- builder.append("API Key", NotEnoughUpdates.INSTANCE.config.apiKey.apiKey.isEmpty() ? "FALSE" : "TRUE");
+ builder.append("API Key", NotEnoughUpdates.INSTANCE.config.apiData.apiKey.isEmpty() ? "FALSE" : "TRUE");
builder.append("On Skyblock", NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() ? "TRUE" : "FALSE");
builder.append(
"Mod Version",
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DhCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DhCommand.java
index 89299a36..222862f9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DhCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DhCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dungeon;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DnCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DnCommand.java
index 8fbbceba..a5a7bcca 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DnCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/DnCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dungeon;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/JoinDungeonCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/JoinDungeonCommand.java
index 874e81db..d69f86f3 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/JoinDungeonCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/JoinDungeonCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dungeon;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/MapCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/MapCommand.java
index ae06a346..f5381adb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/MapCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/dungeon/MapCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.dungeon;
import com.google.gson.JsonElement;
@@ -31,6 +50,7 @@ public class MapCommand extends ClientCommandBase {
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+
if (NotEnoughUpdates.INSTANCE.colourMap == null) {
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(Minecraft
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/FeaturesCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/FeaturesCommand.java
index 593f2575..5f709c4f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/FeaturesCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/FeaturesCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.help;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.java
index 9669be60..7655f561 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/HelpCommand.java
@@ -1,15 +1,32 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.help;
import com.google.common.collect.Lists;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
import net.minecraft.client.Minecraft;
-import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.ChatComponentText;
import java.util.ArrayList;
-import java.util.List;
public class HelpCommand extends ClientCommandBase {
@@ -33,8 +50,8 @@ public class HelpCommand extends ClientCommandBase {
"\u00a76/neulinks \u00a7r\u00a77- Shows links to neu/moulberry.",
"\u00a76/neuoverlay \u00a7r\u00a77- Opens GUI Editor for quickcommands and searchbar.",
"\u00a76/neuah \u00a7r\u00a77- Opens neu's custom ah GUI.",
- "\u00a76/neumap \u00a7r\u00a77- Opens the dungeon map GUI.",
"\u00a76/neucalendar \u00a7r\u00a77- Opens neu's custom calendar GUI.",
+ "\u00a76/neucalc \u00a7r\u00a77- Run calculations.",
"",
"\u00a76\u00a7lOld commands:",
"\u00a76/peek \u00a7b?{user} \u00a72\u2D35 \u00a7r\u00a77- Shows quickly stats for a user.",
@@ -46,7 +63,7 @@ public class HelpCommand extends ClientCommandBase {
"\u00a76/neureloadrepo \u00a7r\u00a77- Debug command with repo.",
"",
"\u00a76\u00a7lDev commands:",
- "\u00a76/neupackdev \u00a7r\u00a77- pack creator command - getnpc"
+ "\u00a76/neupackdev \u00a7r\u00a77- pack creator command - getnpc, getmob(s), getarmorstand(s), getall. Optional radius argument for all."
);
for (String neuHelpMessage : neuHelpMessages) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(neuHelpMessage));
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/LinksCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/LinksCommand.java
index c81f44a8..9938403c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/LinksCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/LinksCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.help;
import com.google.gson.JsonObject;
@@ -25,7 +44,7 @@ public class LinksCommand extends ClientCommandBase {
JsonObject update = NotEnoughUpdates.INSTANCE.manager.getJsonFromFile(updateJson);
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- NotEnoughUpdates.INSTANCE.displayLinks(update);
+ NotEnoughUpdates.INSTANCE.displayLinks(update,0 );
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
} catch (Exception ignored) {
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/SettingsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/SettingsCommand.java
index 08350be9..9964b739 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/SettingsCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/SettingsCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.help;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/StorageViewerWhyCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/StorageViewerWhyCommand.java
index 4f85c26e..820c6f2a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/help/StorageViewerWhyCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/help/StorageViewerWhyCommand.java
@@ -1,8 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.help;
import com.google.common.collect.Lists;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
import net.minecraft.command.ICommandSender;
public class StorageViewerWhyCommand extends ClientCommandBase {
@@ -13,7 +32,7 @@ public class StorageViewerWhyCommand extends ClientCommandBase {
@Override
public void processCommand(ICommandSender sender, String[] args) {
- NEUEventListener.displayNotification(Lists.newArrayList(
+ NotificationHandler.displayNotification(Lists.newArrayList(
"\u00a7eStorage Viewer",
"\u00a77Currently, the storage viewer requires you to click twice",
"\u00a77in order to switch between pages. This is because Hypixel",
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java
index 0b2c155e..bd8abf1d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/AhCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.misc;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -21,8 +40,8 @@ public class AhCommand extends ClientCommandBase {
if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
"You must be on Skyblock to use this feature."));
- } else if (NotEnoughUpdates.INSTANCE.config.apiKey.apiKey == null ||
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey.trim().isEmpty()) {
+ } else if (NotEnoughUpdates.INSTANCE.config.apiData.apiKey == null ||
+ NotEnoughUpdates.INSTANCE.config.apiData.apiKey.trim().isEmpty()) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
"Can't open NeuAH, apikey is not set. Run /api new and put the result in settings."));
} else {
@@ -31,8 +50,13 @@ public class AhCommand extends ClientCommandBase {
NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.clearSearch();
NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.updateSearch();
- if (args.length > 0)
+ if (args.length > 0) {
NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.setSearch(StringUtils.join(args, " "));
+ } else {
+ if (NotEnoughUpdates.INSTANCE.config.neuAuctionHouse.saveLastSearch) {
+ NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.setSearch(null);
+ }
+ }
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/ButtonsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/ButtonsCommand.java
index 63d5c327..55113462 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/ButtonsCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/ButtonsCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.misc;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalculatorCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalculatorCommand.java
new file mode 100644
index 00000000..2ba93585
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalculatorCommand.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.misc;
+
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import io.github.moulberry.notenoughupdates.util.Calculator;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+
+import java.text.DecimalFormat;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public class CalculatorCommand extends ClientCommandBase {
+ public CalculatorCommand() {
+ super("neucalc");
+ }
+
+ @Override
+ public List<String> getCommandAliases() {
+ return Arrays.asList("neucalculator");
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ if ((args.length == 1 && Objects.equals(args[0], "help")) || args.length == 0) {
+ sender.addChatMessage(new ChatComponentText(
+ "\n§e[NEU] §5It's a calculator.\n" +
+ "§eFor Example §b/neucalc 3m*7k§e.\n" +
+ "§eYou can also use suffixes (k, m, b, t, s)§e.\n" +
+ "§eThe \"s\" suffix acts as 64.\n" +
+ "§eTurn on Sign Calculator in /neu misc to also support this in sign popups and the neu search bar.\n"));
+ return;
+ }
+ String source = String.join(" ", args);
+ try {
+ BigDecimal calculate = Calculator.calculate(source);
+ DecimalFormat formatter = new DecimalFormat("#,##0.##");
+ String format = formatter.format(calculate);
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.YELLOW + "[NEU] " + EnumChatFormatting.WHITE + source + " " + EnumChatFormatting.YELLOW +
+ "= " + EnumChatFormatting.GREEN + format
+ ));
+ } catch (Calculator.CalculatorException e) {
+ sender.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.YELLOW + "[NEU] " + EnumChatFormatting.RED + "Error during calculation: " +
+ e.getMessage() + "\n" +
+ EnumChatFormatting.WHITE + source.substring(0, e.getOffset()) + EnumChatFormatting.DARK_RED +
+ source.substring(e.getOffset(), e.getLength() + e.getOffset()) + EnumChatFormatting.GRAY +
+ source.substring(e.getLength() + e.getOffset())
+ ));
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalendarCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalendarCommand.java
index d3c472bd..58c13474 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalendarCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CalendarCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.misc;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CollectionLogCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CollectionLogCommand.java
deleted file mode 100644
index 1bde7631..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CollectionLogCommand.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package io.github.moulberry.notenoughupdates.commands.misc;
-
-import io.github.moulberry.notenoughupdates.collectionlog.GuiCollectionLog;
-import io.github.moulberry.notenoughupdates.commands.ScreenCommand;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-public class CollectionLogCommand extends ScreenCommand {
-
- public CollectionLogCommand() {
- super("neucl", GuiCollectionLog::new);
- }
-
- @Override
- public List<String> getCommandAliases() {
- return Collections.singletonList("collectionlog");
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CosmeticsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CosmeticsCommand.java
index 9ccb7cf0..f74b5813 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CosmeticsCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CosmeticsCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.misc;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -18,7 +37,7 @@ public class CosmeticsCommand extends ClientCommandBase {
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
- if (!OpenGlHelper.isFramebufferEnabled()) {
+ if (!OpenGlHelper.isFramebufferEnabled() && NotEnoughUpdates.INSTANCE.config.notifications.doFastRenderNotif) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
"NEU cosmetics do not work with OF Fast Render. Go to ESC > Options > Video Settings > Performance > Fast Render to disable it."));
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CustomizeCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CustomizeCommand.java
index 6bce4f5a..cca6535e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CustomizeCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/CustomizeCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.misc;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -9,7 +28,6 @@ import net.minecraft.command.ICommandSender;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ChatComponentText;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/GamemodesCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/GamemodesCommand.java
deleted file mode 100644
index d33e560a..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/GamemodesCommand.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package io.github.moulberry.notenoughupdates.commands.misc;
-
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
-import io.github.moulberry.notenoughupdates.gamemodes.GuiGamemodes;
-import net.minecraft.command.CommandException;
-import net.minecraft.command.ICommandSender;
-
-public class GamemodesCommand extends ClientCommandBase {
-
- public GamemodesCommand() {
- super("neugamemodes");
- }
-
- @Override
- public void processCommand(ICommandSender sender, String[] args) throws CommandException {
- boolean upgradeOverride = args.length == 1 && args[0].equals("upgradeOverride");
- NotEnoughUpdates.INSTANCE.openGui = new GuiGamemodes(upgradeOverride);
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java
new file mode 100644
index 00000000..5a4f1400
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/PronounsCommand.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.misc;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import io.github.moulberry.notenoughupdates.util.MinecraftExecutor;
+import io.github.moulberry.notenoughupdates.util.PronounDB;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiNewChat;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.ChatComponentText;
+
+import java.util.Optional;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+
+public class PronounsCommand extends ClientCommandBase {
+ public PronounsCommand() {
+ super("neupronouns");
+ }
+
+ @Override
+ public String getCommandUsage(ICommandSender sender) {
+ return "/neupronouns <username> [platform]";
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ switch (args.length) {
+ case 1:
+ fetchPronouns("minecraft", args[0]);
+ break;
+ case 2:
+ fetchPronouns(args[1], args[0]);
+ break;
+ default:
+ sender.addChatMessage(new ChatComponentText("§4" + getCommandUsage(sender)));
+ }
+ }
+
+ private void fetchPronouns(String platform, String user) {
+ GuiNewChat nc = Minecraft.getMinecraft().ingameGUI.getChatGUI();
+ int id = new Random().nextInt();
+ nc.printChatMessageWithOptionalDeletion(new ChatComponentText("§e[NEU] Fetching Pronouns..."), id);
+
+ CompletableFuture<Optional<PronounDB.PronounChoice>> pronouns;
+ if ("minecraft".equals(platform)) {
+ CompletableFuture<UUID> c = new CompletableFuture<>();
+ NotEnoughUpdates.profileViewer.getPlayerUUID(user, uuidString -> {
+ if (uuidString == null) {
+ c.completeExceptionally(new NullPointerException());
+ } else {
+ c.complete(Utils.parseDashlessUUID(uuidString));
+ }
+ });
+ pronouns = c.thenCompose(PronounDB::getPronounsFor);
+ } else {
+ pronouns = PronounDB.getPronounsFor(platform, user);
+ }
+ pronouns.handleAsync((pronounChoice, throwable) -> {
+ if (throwable != null || !pronounChoice.isPresent()) {
+ nc.printChatMessageWithOptionalDeletion(new ChatComponentText("§e[NEU] §4Failed to fetch pronouns."), id);
+ return null;
+ }
+ PronounDB.PronounChoice betterPronounChoice = pronounChoice.get();
+ nc.printChatMessageWithOptionalDeletion(new ChatComponentText(
+ "§e[NEU] Pronouns for §b" + user + " §eon §b" + platform + "§e:"), id);
+ betterPronounChoice.render().forEach(it -> nc.printChatMessage(new ChatComponentText("§e[NEU] §a" + it)));
+ return null;
+ }, MinecraftExecutor.INSTANCE);
+
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java
new file mode 100644
index 00000000..cac93369
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/misc/UpdateCommand.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.commands.misc;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
+import net.minecraft.command.CommandException;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.util.ChatComponentText;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public class UpdateCommand extends ClientCommandBase {
+ NotEnoughUpdates neu;
+
+ public UpdateCommand(NotEnoughUpdates neu) {
+ super("neuupdate");
+ this.neu = neu;
+ }
+
+ @Override
+ public List<String> getCommandAliases() {
+ return Arrays.asList("neuupdates", "enoughupdates");
+ }
+
+ public void displayHelp(ICommandSender sender) {
+ sender.addChatMessage(new ChatComponentText(
+ "" +
+ "§e[NEU] §b/neuupdate help - View help.\n" +
+ "§e[NEU] §b/neuupdate check - Check for updates.\n" +
+ ""
+ ));
+
+ }
+
+ @Override
+ public void processCommand(ICommandSender sender, String[] args) throws CommandException {
+ if ((args.length == 1 && Objects.equals(args[0], "help")) || args.length == 0) {
+ displayHelp(sender);
+ return;
+ }
+ switch (args[0].toLowerCase().intern()) {
+ case "check":
+ neu.autoUpdater.displayUpdateMessageIfOutOfDate();
+ break;
+ case "scheduledownload":
+ neu.autoUpdater.scheduleDownload();
+ break;
+ case "updatemodes":
+ sender.addChatMessage(new ChatComponentText("§e[NEU] §bTo ensure we do not accidentally corrupt your mod folder, we can only offer support for autoupdates on system with certain capabilities for file deletions (specifically unix systems). You can still manually update your files"));
+ break;
+ default:
+ displayHelp(sender);
+
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/CataCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/CataCommand.java
index 09253e50..afc47418 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/CataCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/CataCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.profile;
import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
@@ -11,7 +30,7 @@ public class CataCommand extends ViewProfileCommand {
@Override
public void processCommand(ICommandSender sender, String[] args) {
- GuiProfileViewer.currentPage = GuiProfileViewer.ProfileViewerPage.DUNG;
+ GuiProfileViewer.currentPage = GuiProfileViewer.ProfileViewerPage.DUNGEON;
super.processCommand(sender, args);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PeekCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PeekCommand.java
index d69139aa..75e779fc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PeekCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PeekCommand.java
@@ -1,10 +1,29 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.profile;
-import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.command.CommandException;
@@ -16,16 +35,19 @@ import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.lang3.text.WordUtils;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class PeekCommand extends ClientCommandBase {
private ScheduledExecutorService peekCommandExecutorService = null;
+ private ScheduledFuture<?> peekScheduledFuture = null;
public PeekCommand() {
super("peek");
@@ -50,23 +72,23 @@ public class PeekCommand extends ClientCommandBase {
} else {
profile.resetCache();
- if (peekCommandExecutorService == null || peekCommandExecutorService.isShutdown()) {
+ if (peekCommandExecutorService == null) {
peekCommandExecutorService = Executors.newSingleThreadScheduledExecutor();
- } else {
+ }
+
+ if (peekScheduledFuture != null && !peekScheduledFuture.isDone()) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
EnumChatFormatting.RED + "[PEEK] New peek command run, cancelling old one."));
- peekCommandExecutorService.shutdownNow();
- peekCommandExecutorService = Executors.newSingleThreadScheduledExecutor();
+ peekScheduledFuture.cancel(true);
}
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessageWithOptionalDeletion(new ChatComponentText(
EnumChatFormatting.YELLOW + "[PEEK] Getting the player's Skyblock profile(s)..."), id);
long startTime = System.currentTimeMillis();
- peekCommandExecutorService.schedule(new Runnable() {
+ peekScheduledFuture = peekCommandExecutorService.schedule(new Runnable() {
public void run() {
if (System.currentTimeMillis() - startTime > 10 * 1000) {
-
Minecraft.getMinecraft().ingameGUI
.getChatGUI()
.printChatMessageWithOptionalDeletion(new ChatComponentText(
@@ -83,7 +105,8 @@ public class PeekCommand extends ClientCommandBase {
boolean isMe = name.equalsIgnoreCase("moulberry");
PlayerStats.Stats stats = profile.getStats(null);
- JsonObject skill = profile.getSkillInfo(null);
+ if (stats == null) return;
+ Map<String, ProfileViewer.Level> skyblockInfo = profile.getSkyblockInfo(null);
Minecraft.getMinecraft().ingameGUI
.getChatGUI()
@@ -92,27 +115,25 @@ public class PeekCommand extends ClientCommandBase {
Utils.getElementAsString(profile.getHypixelProfile().get("displayname"), name) + "'s Info " +
EnumChatFormatting.STRIKETHROUGH + "-=-"), id);
- if (skill == null) {
+ if (skyblockInfo == null) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "Skills api disabled!"));
+ EnumChatFormatting.YELLOW + "Skills API disabled!"));
} else {
float totalSkillLVL = 0;
float totalSkillCount = 0;
- for (Map.Entry<String, JsonElement> entry : skill.entrySet()) {
- if (entry.getKey().startsWith("level_skill")) {
- if (entry.getKey().contains("runecrafting")) continue;
- if (entry.getKey().contains("carpentry")) continue;
- totalSkillLVL += entry.getValue().getAsFloat();
- totalSkillCount++;
- }
+ List<String> skills = Arrays.asList("taming", "mining", "foraging", "enchanting", "farming", "combat", "fishing", "alchemy", "carpentry");
+ for (String skillName : skills) {
+ totalSkillLVL += skyblockInfo.get(skillName).level;
+ totalSkillCount++;
}
- float combat = Utils.getElementAsFloat(skill.get("level_skill_combat"), 0);
- float zombie = Utils.getElementAsFloat(skill.get("level_slayer_zombie"), 0);
- float spider = Utils.getElementAsFloat(skill.get("level_slayer_spider"), 0);
- float wolf = Utils.getElementAsFloat(skill.get("level_slayer_wolf"), 0);
- float enderman = Utils.getElementAsFloat(skill.get("level_slayer_enderman"), 0);
+ float combat = skyblockInfo.get("combat").level;
+ float zombie = skyblockInfo.get("zombie").level;
+ float spider = skyblockInfo.get("spider").level;
+ float wolf = skyblockInfo.get("wolf").level;
+ float enderman = skyblockInfo.get("enderman").level;
+ float blaze = skyblockInfo.get("blaze").level;
float avgSkillLVL = totalSkillLVL / totalSkillCount;
@@ -123,6 +144,7 @@ public class PeekCommand extends ClientCommandBase {
spider = 1;
wolf = 2;
enderman = 0;
+ blaze = 0;
}
EnumChatFormatting combatPrefix = combat > 20
@@ -141,6 +163,11 @@ public class PeekCommand extends ClientCommandBase {
? EnumChatFormatting.GREEN
: EnumChatFormatting.YELLOW)
: EnumChatFormatting.RED;
+ EnumChatFormatting blazePrefix = blaze > 3
+ ? (blaze > 6
+ ? EnumChatFormatting.GREEN
+ : EnumChatFormatting.YELLOW)
+ : EnumChatFormatting.RED;
EnumChatFormatting avgPrefix = avgSkillLVL > 20
? (avgSkillLVL > 35
? EnumChatFormatting.GREEN
@@ -151,9 +178,10 @@ public class PeekCommand extends ClientCommandBase {
overallScore += spider * spider / 81f;
overallScore += wolf * wolf / 81f;
overallScore += enderman * enderman / 81f;
+ overallScore += blaze * blaze / 81f;
overallScore += avgSkillLVL / 20f;
- int cata = (int) Utils.getElementAsFloat(skill.get("level_skill_catacombs"), 0);
+ int cata = (int) skyblockInfo.get("catacombs").level;
EnumChatFormatting cataPrefix = cata > 15
? (cata > 25 ? EnumChatFormatting.GREEN : EnumChatFormatting.YELLOW)
: EnumChatFormatting.RED;
@@ -167,8 +195,9 @@ public class PeekCommand extends ClientCommandBase {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
g + "Slayer: " + zombiePrefix + (int) Math.floor(zombie) + g + "-" +
spiderPrefix + (int) Math.floor(spider) + g + "-" +
- wolfPrefix + (int) Math.floor(wolf) + "-" +
- endermanPrefix + (int) Math.floor(enderman)));
+ wolfPrefix + (int) Math.floor(wolf) + g+ "-" +
+ endermanPrefix + (int) Math.floor(enderman) + g + "-" +
+ blazePrefix + (int) Math.floor(blaze)));
}
if (stats == null) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
@@ -266,7 +295,7 @@ public class PeekCommand extends ClientCommandBase {
peekCommandExecutorService.shutdownNow();
} else {
- peekCommandExecutorService.schedule(this, 200, TimeUnit.MILLISECONDS);
+ peekScheduledFuture = peekCommandExecutorService.schedule(this, 200, TimeUnit.MILLISECONDS);
}
}
}, 200, TimeUnit.MILLISECONDS);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PvCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PvCommand.java
index 07394ffd..2d5c05f4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PvCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/PvCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.profile;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/ViewProfileCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/ViewProfileCommand.java
index 371db394..e4ca497c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/ViewProfileCommand.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/commands/profile/ViewProfileCommand.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.commands.profile;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -23,8 +42,8 @@ public class ViewProfileCommand extends ClientCommandBase {
"Some parts of the profile viewer do not work with OF Fast Render. Go to ESC > Options > Video Settings > Performance > Fast Render to disable it."));
}
- if (NotEnoughUpdates.INSTANCE.config.apiKey.apiKey == null ||
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey.trim().isEmpty()) {
+ if (NotEnoughUpdates.INSTANCE.config.apiData.apiKey == null ||
+ NotEnoughUpdates.INSTANCE.config.apiData.apiKey.trim().isEmpty()) {
Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
"Can't view profile, apikey is not set. Run /api new and put the result in settings."));
} else if (args.length == 0) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ReloadRepoCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ReloadRepoCommand.java
deleted file mode 100644
index e363b59f..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ReloadRepoCommand.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package io.github.moulberry.notenoughupdates.commands.repo;
-
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
-import io.github.moulberry.notenoughupdates.options.NEUConfig;
-import io.github.moulberry.notenoughupdates.util.Constants;
-import net.minecraft.command.CommandException;
-import net.minecraft.command.ICommandSender;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-
-public class ReloadRepoCommand extends ClientCommandBase {
-
- public ReloadRepoCommand() {
- super("neureloadrepo");
- }
-
- @Override
- public void processCommand(ICommandSender sender, String[] args) throws CommandException {
- NotEnoughUpdates.INSTANCE.manager.reloadRepository();
- Constants.reload();
-
- NotEnoughUpdates.INSTANCE.newConfigFile();
- if (NotEnoughUpdates.INSTANCE.getConfigFile().exists()) {
- try (
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- new FileInputStream(NotEnoughUpdates.INSTANCE.getConfigFile()),
- StandardCharsets.UTF_8
- ))
- ) {
- NotEnoughUpdates.INSTANCE.config = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(reader, NEUConfig.class);
- } catch (Exception ignored) {
- }
- }
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/RepoModeCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/RepoModeCommand.java
deleted file mode 100644
index bb6e1675..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/RepoModeCommand.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package io.github.moulberry.notenoughupdates.commands.repo;
-
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
-import net.minecraft.client.Minecraft;
-import net.minecraft.command.CommandException;
-import net.minecraft.command.ICommandSender;
-import net.minecraft.util.ChatComponentText;
-
-public class RepoModeCommand extends ClientCommandBase {
-
- public RepoModeCommand() {
- super("neurepomode");
- }
-
- @Override
- public void processCommand(ICommandSender sender, String[] args) throws CommandException {
- NotEnoughUpdates.INSTANCE.config.hidden.dev = !NotEnoughUpdates.INSTANCE.config.hidden.dev;
- NotEnoughUpdates.INSTANCE.config.hidden.enableItemEditing =
- !NotEnoughUpdates.INSTANCE.config.hidden.enableItemEditing;
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("\u00a75Toggled NEU repo dev mode."));
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ResetRepoCommand.java b/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ResetRepoCommand.java
deleted file mode 100644
index b9a0d7cd..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/commands/repo/ResetRepoCommand.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.github.moulberry.notenoughupdates.commands.repo;
-
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.commands.ClientCommandBase;
-import net.minecraft.command.CommandException;
-import net.minecraft.command.ICommandSender;
-
-public class ResetRepoCommand extends ClientCommandBase {
-
- public ResetRepoCommand() {
- super("neuresetrepo");
- }
-
- @Override
- public void processCommand(ICommandSender sender, String[] args) throws CommandException {
- NotEnoughUpdates.INSTANCE.manager.resetRepo();
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/BackgroundBlur.java b/src/main/java/io/github/moulberry/notenoughupdates/core/BackgroundBlur.java
index c85841b3..fc2be97b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/BackgroundBlur.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/BackgroundBlur.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/ChromaColour.java b/src/main/java/io/github/moulberry/notenoughupdates/core/ChromaColour.java
index 8f4dd87d..05a9a65e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/ChromaColour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/ChromaColour.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import java.awt.*;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/GlScissorStack.java b/src/main/java/io/github/moulberry/notenoughupdates/core/GlScissorStack.java
index 7cc8893f..40b9fe7a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/GlScissorStack.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/GlScissorStack.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import net.minecraft.client.Minecraft;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElement.java b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElement.java
index c1c76675..2a684164 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElement.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElement.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import net.minecraft.client.gui.Gui;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementBoolean.java b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementBoolean.java
index d5cbb3ad..b0586210 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementBoolean.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementBoolean.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpUtils;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementColour.java b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementColour.java
index 48996c8d..1f655aaf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementColour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementColour.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementTextField.java b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementTextField.java
index 51a4654c..45dc58cc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementTextField.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiElementTextField.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
@@ -36,6 +55,7 @@ public class GuiElementTextField {
private int y;
private String prependText = "";
+ private String masterStarUnicode = "";
private int customTextColour = 0xffffffff;
private final GuiTextField textField = new GuiTextField(0, Minecraft.getMinecraft().fontRendererObj,
@@ -395,6 +415,55 @@ public class GuiElementTextField {
textField.setCursorPosition(pos + 1);
}
}
+ } else {
+ for (int i = 0; i < 10; i++) {
+ if (typedChar == Integer.toString(i + 1).charAt(0)) {
+ int pos = textField.getCursorPosition() - 2;
+ if (pos >= 0 && pos < textField.getText().length()) {
+ if (textField.getText().charAt(pos) == '*') {
+ switch (i) {
+ case 0:
+ masterStarUnicode = "\u278A";
+ break;
+ case 1:
+ masterStarUnicode = "\u278B";
+ break;
+ case 2:
+ masterStarUnicode = "\u278C";
+ break;
+ case 3:
+ masterStarUnicode = "\u278D";
+ break;
+ case 4:
+ masterStarUnicode = "\u278E";
+ break;
+ case 5:
+ masterStarUnicode = "\u278F";
+ break;
+ case 6:
+ masterStarUnicode = "\u2790";
+ break;
+ case 7:
+ masterStarUnicode = "\u2791";
+ break;
+ case 8:
+ masterStarUnicode = "\u2792";
+ break;
+ case 9:
+ masterStarUnicode = "\u2793";
+ break;
+ }
+ String before = textField.getText().substring(0, pos);
+ String after = "";
+ if (pos + 2 < textField.getText().length()) {
+ after = textField.getText().substring(pos + 2);
+ }
+ textField.setText(before + masterStarUnicode + after);
+ textField.setCursorPosition(pos + 1);
+ }
+ }
+ }
+ }
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiScreenElementWrapper.java b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiScreenElementWrapper.java
index c7c4517b..95ed8a5f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/GuiScreenElementWrapper.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/GuiScreenElementWrapper.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core;
import net.minecraft.client.gui.GuiScreen;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/Config.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/Config.java
index 2a696a44..6bafb1fd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/Config.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/Config.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config;
public class Config {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/GuiPositionEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/GuiPositionEditor.java
index 9d0133cb..eac1e5cd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/GuiPositionEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/GuiPositionEditor.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config;
import net.minecraft.client.Minecraft;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/KeybindHelper.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/KeybindHelper.java
index 30226a22..d63f871c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/KeybindHelper.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/KeybindHelper.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config;
import org.lwjgl.input.Keyboard;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/MoulConfigGuiForgeInterop.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/MoulConfigGuiForgeInterop.java
new file mode 100644
index 00000000..40887e54
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/MoulConfigGuiForgeInterop.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.core.config;
+
+import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
+import io.github.moulberry.notenoughupdates.options.NEUConfigEditor;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraftforge.fml.client.IModGuiFactory;
+import org.lwjgl.input.Keyboard;
+
+import java.io.IOException;
+import java.util.Set;
+
+public class MoulConfigGuiForgeInterop implements IModGuiFactory {
+ @Override
+ public void initialize(Minecraft minecraft) {}
+
+ @Override
+ public Class<? extends GuiScreen> mainConfigGuiClass() {
+ return WrappedMoulConfig.class;
+ }
+
+ @Override
+ public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
+ return null;
+ }
+
+ @Override
+ public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement runtimeOptionCategoryElement) {
+ return null;
+ }
+
+ public static class WrappedMoulConfig extends GuiScreenElementWrapper {
+
+ private final GuiScreen parent;
+
+ public WrappedMoulConfig(GuiScreen parent) {
+ super(NEUConfigEditor.editor);
+ this.parent = parent;
+ }
+
+ @Override
+ public void handleKeyboardInput() throws IOException {
+ if (Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
+ Minecraft.getMinecraft().displayGuiScreen(parent);
+ return;
+ }
+ super.handleKeyboardInput();
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/Position.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/Position.java
index cf946649..535c92bf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/Position.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/Position.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config;
import com.google.gson.annotations.Expose;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/PositionNew.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/PositionNew.java
index 8f2b02d8..cf756c91 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/PositionNew.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/PositionNew.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config;
import com.google.gson.annotations.Expose;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/Category.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/Category.java
index b67d0383..e0a9585a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/Category.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/Category.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigAccordionId.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigAccordionId.java
index 1c847851..b11f7651 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigAccordionId.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigAccordionId.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorAccordion.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorAccordion.java
index 11b798f9..7491a94f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorAccordion.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorAccordion.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorBoolean.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorBoolean.java
index a0ca1f38..8e6f652c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorBoolean.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorBoolean.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
@@ -7,4 +26,6 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
-public @interface ConfigEditorBoolean {}
+public @interface ConfigEditorBoolean {
+ int runnableId() default -1;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorButton.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorButton.java
index 455df65f..a2c56dc0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorButton.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorButton.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorColour.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorColour.java
index 6640ade9..824b2eec 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorColour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorColour.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java
index e171e0ae..d9707c9b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDraggableList.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
@@ -9,4 +28,6 @@ import java.lang.annotation.Target;
@Target(ElementType.FIELD)
public @interface ConfigEditorDraggableList {
String[] exampleText();
+
+ boolean allowDeleting() default true;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDropdown.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDropdown.java
index ac766e93..8d870643 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDropdown.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorDropdown.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorFSR.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorFSR.java
index 217df0c5..ba45ae68 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorFSR.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorFSR.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorKeybind.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorKeybind.java
index 8d8de2eb..f1a3e329 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorKeybind.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorKeybind.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorSlider.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorSlider.java
index abab37f9..b8db25bc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorSlider.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorSlider.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorText.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorText.java
index 1ff7e39e..b6b32fb2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorText.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigEditorText.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java
index 2ee23dcf..d51294e7 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/annotations/ConfigOption.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.annotations;
import java.lang.annotation.ElementType;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditor.java
index d62c7ec7..c3969e35 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditor.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.struct.ConfigProcessor;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorAccordion.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorAccordion.java
index 8877cd03..dc1173ef 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorAccordion.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorAccordion.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.struct.ConfigProcessor;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorBoolean.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorBoolean.java
index 9e2c912a..d12ec8e7 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorBoolean.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorBoolean.java
@@ -1,15 +1,43 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.GuiElementBoolean;
+import io.github.moulberry.notenoughupdates.core.config.Config;
import io.github.moulberry.notenoughupdates.core.config.struct.ConfigProcessor;
public class GuiOptionEditorBoolean extends GuiOptionEditor {
+
private final GuiElementBoolean bool;
+ private final Config config;
+ private final int runnableId;
- public GuiOptionEditorBoolean(ConfigProcessor.ProcessedOption option) {
+ public GuiOptionEditorBoolean(
+ ConfigProcessor.ProcessedOption option,
+ int runnableId,
+ Config config
+ ) {
super(option);
-
- bool = new GuiElementBoolean(0, 0, (boolean) option.get(), 10, option::set);
+ this.config = config;
+ this.runnableId = runnableId;
+ bool = new GuiElementBoolean(0, 0, (boolean) option.get(), 10, (value) -> onUpdate(option, value));
}
@Override
@@ -34,4 +62,10 @@ public class GuiOptionEditorBoolean extends GuiOptionEditor {
public boolean keyboardInput() {
return false;
}
+
+ private void onUpdate(ConfigProcessor.ProcessedOption option, boolean value) {
+ if (option.set(value)) {
+ config.executeRunnable(runnableId);
+ }
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorButton.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorButton.java
index 76944efa..aef6318c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorButton.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorButton.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.Config;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorColour.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorColour.java
index 80d2af42..ca4087b5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorColour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorColour.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.ChromaColour;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java
index 08a1024f..63a932b5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDraggableList.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.struct.ConfigProcessor;
@@ -24,6 +43,7 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor {
private static final ResourceLocation DELETE = new ResourceLocation("notenoughupdates:core/delete.png");
private final String[] exampleText;
+ private final boolean enableDeleting;
private final List<Integer> activeText;
private int currentDragging = -1;
private int dragStartIndex = -1;
@@ -35,9 +55,14 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor {
private boolean dropdownOpen = false;
- public GuiOptionEditorDraggableList(ConfigProcessor.ProcessedOption option, String[] exampleText) {
+ public GuiOptionEditorDraggableList(
+ ConfigProcessor.ProcessedOption option,
+ String[] exampleText,
+ boolean disableDeleting
+ ) {
super(option);
+ this.enableDeleting = disableDeleting;
this.exampleText = exampleText;
this.activeText = (List<Integer>) option.get();
}
@@ -77,8 +102,11 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor {
float greenBlue = LerpUtils.clampZeroOne((250 + trashHoverTime - currentTime) / 250f);
GlStateManager.color(1, greenBlue, greenBlue, 1);
}
- Minecraft.getMinecraft().getTextureManager().bindTexture(DELETE);
- Utils.drawTexturedRect(x + width / 6 + 27, y + 45 - 7 - 13, 11, 14, GL11.GL_NEAREST);
+
+ if (enableDeleting) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(DELETE);
+ Utils.drawTexturedRect(x + width / 6 + 27, y + 45 - 7 - 13, 11, 14, GL11.GL_NEAREST);
+ }
Gui.drawRect(x + 5, y + 45, x + width - 5, y + height - 5, 0xffdddddd);
Gui.drawRect(x + 6, y + 46, x + width - 6, y + height - 6, 0xff000000);
@@ -206,7 +234,9 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor {
dragStartIndex >= 0 && Mouse.getEventButton() == 0 &&
mouseX >= x + width / 6 + 27 - 3 && mouseX <= x + width / 6 + 27 + 11 + 3 &&
mouseY >= y + 45 - 7 - 13 - 3 && mouseY <= y + 45 - 7 - 13 + 14 + 3) {
- activeText.remove(dragStartIndex);
+ if (enableDeleting) {
+ activeText.remove(dragStartIndex);
+ }
currentDragging = -1;
dragStartIndex = -1;
return false;
@@ -215,13 +245,13 @@ public class GuiOptionEditorDraggableList extends GuiOptionEditor {
if (!Mouse.isButtonDown(0) || dropdownOpen) {
currentDragging = -1;
dragStartIndex = -1;
- if (trashHoverTime > 0) trashHoverTime = -System.currentTimeMillis();
+ if (trashHoverTime > 0 && enableDeleting) trashHoverTime = -System.currentTimeMillis();
} else if (currentDragging >= 0 &&
mouseX >= x + width / 6 + 27 - 3 && mouseX <= x + width / 6 + 27 + 11 + 3 &&
mouseY >= y + 45 - 7 - 13 - 3 && mouseY <= y + 45 - 7 - 13 + 14 + 3) {
- if (trashHoverTime < 0) trashHoverTime = System.currentTimeMillis();
+ if (trashHoverTime < 0 && enableDeleting) trashHoverTime = System.currentTimeMillis();
} else {
- if (trashHoverTime > 0) trashHoverTime = -System.currentTimeMillis();
+ if (trashHoverTime > 0 && enableDeleting) trashHoverTime = -System.currentTimeMillis();
}
if (Mouse.getEventButtonState()) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDropdown.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDropdown.java
index a17737e3..af6af277 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDropdown.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorDropdown.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.struct.ConfigProcessor;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorFSR.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorFSR.java
index b443b5f6..048e261e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorFSR.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorFSR.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.Config;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorKeybind.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorKeybind.java
index 5ff961a7..6eb71d1e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorKeybind.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorKeybind.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.KeybindHelper;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorSlider.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorSlider.java
index 45ae70d9..7fceb92d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorSlider.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorSlider.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorText.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorText.java
index f98c87ee..ad2fa4db 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorText.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiOptionEditorText.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
@@ -68,7 +87,6 @@ public class GuiOptionEditorText extends GuiOptionEditor {
@Override
public boolean keyboardInput() {
if (Keyboard.getEventKeyState() && textField.getFocus()) {
- Keyboard.enableRepeatEvents(true);
textField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey());
try {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiPositionEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiPositionEditor.java
index 651335ed..ed45bab6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiPositionEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/gui/GuiPositionEditor.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.gui;
import io.github.moulberry.notenoughupdates.core.config.Position;
@@ -129,8 +148,6 @@ public class GuiPositionEditor extends GuiScreen {
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
- Keyboard.enableRepeatEvents(true);
-
if (keyCode == Keyboard.KEY_R) {
position.set(originalPosition);
} else if (!clicked) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java b/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java
index b5aa6ba8..75862069 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/config/struct/ConfigProcessor.java
@@ -1,9 +1,50 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.config.struct;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.core.config.Config;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-import io.github.moulberry.notenoughupdates.core.config.gui.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.Category;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorText;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditor;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiOptionEditorText;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
@@ -130,7 +171,8 @@ public class ConfigProcessor {
}
if (optionType.isAssignableFrom(boolean.class) &&
optionField.isAnnotationPresent(ConfigEditorBoolean.class)) {
- editor = new GuiOptionEditorBoolean(option);
+ ConfigEditorBoolean configEditorAnnotation = optionField.getAnnotation(ConfigEditorBoolean.class);
+ editor = new GuiOptionEditorBoolean(option, configEditorAnnotation.runnableId(), config);
}
if (optionType.isAssignableFrom(boolean.class) &&
optionField.isAnnotationPresent(ConfigEditorAccordion.class)) {
@@ -147,7 +189,11 @@ public class ConfigProcessor {
if (optionField.isAnnotationPresent(ConfigEditorDraggableList.class)) {
ConfigEditorDraggableList configEditorAnnotation =
optionField.getAnnotation(ConfigEditorDraggableList.class);
- editor = new GuiOptionEditorDraggableList(option, configEditorAnnotation.exampleText());
+ editor = new GuiOptionEditorDraggableList(
+ option,
+ configEditorAnnotation.exampleText(),
+ configEditorAnnotation.allowDeleting()
+ );
}
}
if (optionType.isAssignableFrom(String.class)) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/GuiElementSlider.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/GuiElementSlider.java
index c2252a97..3e982f9d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/GuiElementSlider.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/GuiElementSlider.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util;
import io.github.moulberry.notenoughupdates.core.GuiElement;
@@ -10,7 +29,13 @@ import org.lwjgl.opengl.GL11;
import java.util.function.Consumer;
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.*;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_button_new;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_off_cap;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_off_notch;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_off_segment;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_on_cap;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_on_notch;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_on_segment;
public class GuiElementSlider extends GuiElement {
public int x;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/Line.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Line.java
new file mode 100644
index 00000000..a5744a26
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Line.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.core.util;
+
+import net.minecraft.util.Vec3;
+
+/**
+ * Represents a line using two points along the line or a segment with endpoints.
+ */
+public class Line {
+ private static final double DOUBLE_EPSILON = 4.94065645841247E-324;
+ public Vec3 point1;
+ public Vec3 point2;
+
+ public Line(Vec3 first, Vec3 second) {
+ point1 = first;
+ point2 = second;
+ }
+
+ public Vec3 getMidpoint() {
+ return new Vec3(
+ (point1.xCoord + point2.xCoord) / 2.0,
+ (point1.yCoord + point2.yCoord) / 2.0,
+ (point1.zCoord + point2.zCoord) / 2.0
+ );
+ }
+
+ /**
+ * Calculates the intersection line segment between 2 lines
+ * Based on http://paulbourke.net/geometry/pointlineplane/calclineline.cs
+ *
+ * @return The intersection {@link Line} or {@code null} if no solution found
+ */
+ public Line getIntersectionLineSegment(Line other) {
+ Vec3 p1 = this.point1;
+ Vec3 p2 = this.point2;
+ Vec3 p3 = other.point1;
+ Vec3 p4 = other.point2;
+ Vec3 p13 = p1.subtract(p3);
+ Vec3 p43 = p4.subtract(p3);
+
+ if (lengthSquared(p43) < DOUBLE_EPSILON) {
+ return null;
+ }
+
+ Vec3 p21 = p2.subtract(p1);
+ if (lengthSquared(p21) < DOUBLE_EPSILON) {
+ return null;
+ }
+
+ double d1343 = p13.xCoord * p43.xCoord + p13.yCoord * p43.yCoord + p13.zCoord * p43.zCoord;
+ double d4321 = p43.xCoord * p21.xCoord + p43.yCoord * p21.yCoord + p43.zCoord * p21.zCoord;
+ double d1321 = p13.xCoord * p21.xCoord + p13.yCoord * p21.yCoord + p13.zCoord * p21.zCoord;
+ double d4343 = p43.xCoord * p43.xCoord + p43.yCoord * p43.yCoord + p43.zCoord * p43.zCoord;
+ double d2121 = p21.xCoord * p21.xCoord + p21.yCoord * p21.yCoord + p21.zCoord * p21.zCoord;
+
+ double denom = d2121 * d4343 - d4321 * d4321;
+ if (Math.abs(denom) < DOUBLE_EPSILON) {
+ return null;
+ }
+ double numer = d1343 * d4321 - d1321 * d4343;
+
+ double mua = numer / denom;
+ double mub = (d1343 + d4321 * (mua)) / d4343;
+
+ Line resultSegment = new Line(
+ new Vec3(
+ (float) (p1.xCoord + mua * p21.xCoord),
+ (float) (p1.yCoord + mua * p21.yCoord),
+ (float) (p1.zCoord + mua * p21.zCoord)
+ ),
+ new Vec3(
+ (float) (p3.xCoord + mub * p43.xCoord),
+ (float) (p3.yCoord + mub * p43.yCoord),
+ (float) (p3.zCoord + mub * p43.zCoord)
+ )
+ );
+
+ return resultSegment;
+ }
+
+ public Line getImmutable() {
+ return new Line(point1, point2);
+ }
+
+ private static double lengthSquared(Vec3 vec) {
+ return vec.dotProduct(vec);
+ }
+
+ public String toString() {
+ return String.format(
+ "point1 = %s, point2 = %s, midpoint = %s",
+ point1 == null ? "NULL" : point1.toString(),
+ point2 == null ? "NULL" : point2.toString(),
+ (point1 == null || point2 == null) ? "NULL" : getMidpoint()
+ );
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/MiscUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/MiscUtils.java
index 03a9483b..41780140 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/MiscUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/MiscUtils.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util;
import net.minecraft.client.Minecraft;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/Splitters.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Splitters.java
index 0bb858db..389991b4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/Splitters.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Splitters.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util;
import com.google.common.base.Splitter;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java
index b0deadd2..a4f814d1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/StringUtils.java
@@ -1,9 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util;
import com.google.common.collect.Sets;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
import java.util.Set;
public class StringUtils {
@@ -34,4 +56,50 @@ public class StringUtils {
return trim;
}
+
+ public static String substringBetween(String str, String open, String close) {
+ return org.apache.commons.lang3.StringUtils.substringBetween(str, open, close);
+ }
+
+ public static int cleanAndParseInt(String str) {
+ str = cleanColour(str);
+ str = str.replace(",", "");
+ return Integer.parseInt(str);
+ }
+
+ public static String shortNumberFormat(double n) {
+ return shortNumberFormat(n, 0);
+ }
+
+ private static final char[] c = new char[] { 'k', 'm', 'b', 't' };
+
+ public static String shortNumberFormat(double n, int iteration) {
+ if (n < 1000) {
+ if (n % 1 == 0) {
+ return Integer.toString((int) n);
+ } else {
+ return String.format("%.2f", n);
+ }
+ }
+
+ double d = ((long) n / 100) / 10.0;
+ boolean isRound = (d * 10) % 10 == 0;
+ return d < 1000 ? (isRound || d > 9.99 ? (int) d * 10 / 10 : d + "") + "" + c[iteration] : shortNumberFormat(d, iteration + 1);
+ }
+
+ public static String urlEncode(String something) {
+ try {
+ return URLEncoder.encode(something, StandardCharsets.UTF_8.name());
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // UTF 8 should always be present
+ }
+ }
+
+ /**
+ * taken and modified from https://stackoverflow.com/a/23326014/5507634
+ */
+ public static String replaceLast(String string, String toReplace, String replacement) {
+ int start = string.lastIndexOf(toReplace);
+ return string.substring(0, start) + replacement + string.substring(start + toReplace.length());
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java
new file mode 100644
index 00000000..c9736b77
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/Vec3Comparable.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.core.util;
+
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+import net.minecraft.util.Vec3i;
+
+public class Vec3Comparable extends Vec3 implements Comparable<Vec3Comparable> {
+ public static final Vec3Comparable NULL_VECTOR = new Vec3Comparable(0.0, 0.0, 0.0);
+
+ public Vec3Comparable(double x, double y, double z) {
+ super(x, y, z);
+ }
+
+ public Vec3Comparable(Vec3i sourceVec) {
+ super(sourceVec);
+ }
+
+ public Vec3Comparable(Vec3 source) {
+ super(source.xCoord, source.yCoord, source.zCoord);
+ }
+
+ public Vec3Comparable(BlockPos source) {
+
+ super(source.getX(), source.getY(), source.getZ());
+ }
+
+ public Vec3Comparable(Vec3Comparable source) {
+ super(source.xCoord, source.yCoord, source.zCoord);
+ }
+
+ @Override
+ public Vec3Comparable subtractReverse(Vec3 vec) {
+ return new Vec3Comparable(super.subtractReverse(vec));
+ }
+
+ @Override
+ public Vec3Comparable normalize() {
+ return new Vec3Comparable(super.normalize());
+ }
+
+ @Override
+ public Vec3Comparable crossProduct(Vec3 vec) {
+ return new Vec3Comparable(super.crossProduct(vec));
+ }
+
+ @Override
+ public Vec3Comparable subtract(Vec3 vec) {
+ return new Vec3Comparable(super.subtract(vec));
+ }
+
+ @Override
+ public Vec3Comparable subtract(double x, double y, double z) {
+ return new Vec3Comparable(super.subtract(x, y, z));
+ }
+
+ @Override
+ public Vec3Comparable add(Vec3 other) {
+ return new Vec3Comparable(super.add(other));
+ }
+
+ @Override
+ public Vec3Comparable addVector(double x, double y, double z) {
+ return new Vec3Comparable(super.addVector(x, y, z));
+ }
+
+ @Override
+ public Vec3Comparable getIntermediateWithXValue(Vec3 vec, double x) {
+ return new Vec3Comparable(super.getIntermediateWithXValue(vec, x));
+ }
+
+ @Override
+ public Vec3Comparable getIntermediateWithYValue(Vec3 vec, double y) {
+ return new Vec3Comparable(super.getIntermediateWithYValue(vec, y));
+ }
+
+ @Override
+ public Vec3Comparable getIntermediateWithZValue(Vec3 vec, double z) {
+ return new Vec3Comparable(super.getIntermediateWithZValue(vec, z));
+ }
+
+ @Override
+ public Vec3Comparable rotatePitch(float pitch) {
+ return new Vec3Comparable(super.rotatePitch(pitch));
+ }
+
+ @Override
+ public Vec3Comparable rotateYaw(float yaw) {
+ return new Vec3Comparable(super.rotateYaw(yaw));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ } else if (!(other instanceof Vec3Comparable)) {
+ return false;
+ } else {
+ Vec3Comparable vec3c = (Vec3Comparable) other;
+ return this.xCoord == vec3c.xCoord && this.yCoord == vec3c.yCoord && this.zCoord == vec3c.zCoord;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ long bits = 1L;
+ bits = 31L * bits + doubleToLongBits(xCoord);
+ bits = 31L * bits + doubleToLongBits(yCoord);
+ bits = 31L * bits + doubleToLongBits(zCoord);
+ return (int) (bits ^ (bits >> 32));
+ }
+
+ public int compareTo(Vec3Comparable other) {
+ return this.yCoord == other.yCoord ?
+ (this.zCoord == other.zCoord ?
+ (int) (this.xCoord - other.xCoord)
+ : (int) (this.zCoord - other.zCoord))
+ : (int) (this.yCoord - other.yCoord);
+ }
+
+ public boolean signumEquals(Vec3 other) {
+ return Math.signum(xCoord) == Math.signum(other.xCoord) &&
+ Math.signum(yCoord) == Math.signum(other.yCoord) &&
+ Math.signum(zCoord) == Math.signum(other.zCoord);
+ }
+
+ private static long doubleToLongBits(double d) {
+ return d == 0.0 ? 0L : Double.doubleToLongBits(d);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpUtils.java
index 7e401959..0e60ad92 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpUtils.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util.lerp;
public class LerpUtils {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingFloat.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingFloat.java
index 3d9e7787..fb03140c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingFloat.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingFloat.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util.lerp;
public class LerpingFloat {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingInteger.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingInteger.java
index 024455fd..8462200f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingInteger.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/lerp/LerpingInteger.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util.lerp;
public class LerpingInteger {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java
index 9a4607ed..e7ce29c3 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/RenderUtils.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util.render;
import io.github.moulberry.notenoughupdates.core.BackgroundBlur;
@@ -13,11 +32,20 @@ import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.entity.Entity;
-import net.minecraft.util.*;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.Vec3i;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.util.vector.Vector3f;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
public class RenderUtils {
public static void drawFloatingRectDark(int x, int y, int width, int height) {
drawFloatingRectDark(x, y, width, height, true);
@@ -228,7 +256,7 @@ public class RenderUtils {
double d11 = 0.5D + Math.sin(d2 + 5.497787143782138D) * 0.2D;
double d14 = -1.0D + d1;
double d15 = (double) (height) * 2.5D + d14;
- worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldrenderer.pos(x + d4, y + topOffset, z + d5).tex(1.0D, d15).color(r, g, b, 1.0F * alphaMult).endVertex();
worldrenderer.pos(x + d4, y + bottomOffset, z + d5).tex(1.0D, d14).color(r, g, b, 1.0F).endVertex();
worldrenderer.pos(x + d6, y + bottomOffset, z + d7).tex(0.0D, d14).color(r, g, b, 1.0F).endVertex();
@@ -251,7 +279,7 @@ public class RenderUtils {
double d12 = -1.0D + d1;
double d13 = height + d12;
- worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
+ worldrenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR);
worldrenderer.pos(x + 0.2D, y + topOffset, z + 0.2D).tex(1.0D, d13).color(r, g, b, 0.25F * alphaMult).endVertex();
worldrenderer.pos(x + 0.2D, y + bottomOffset, z + 0.2D).tex(1.0D, d12).color(r, g, b, 0.25F).endVertex();
worldrenderer.pos(x + 0.8D, y + bottomOffset, z + 0.2D).tex(0.0D, d12).color(r, g, b, 0.25F).endVertex();
@@ -345,11 +373,19 @@ public class RenderUtils {
}
}
- public static void renderWayPoint(String str, BlockPos loc, float partialTicks) {
+ public static void renderWayPoint(String str, Vec3i loc, float partialTicks) {
+ renderWayPoint(str, new Vector3f(loc.getX(), loc.getY(), loc.getZ()), partialTicks);
+ }
+
+ public static void renderWayPoint(List<String> str, Vec3i loc, float partialTicks) {
renderWayPoint(str, new Vector3f(loc.getX(), loc.getY(), loc.getZ()), partialTicks);
}
public static void renderWayPoint(String str, Vector3f loc, float partialTicks) {
+ renderWayPoint(Arrays.asList(str), loc, partialTicks);
+ }
+
+ public static void renderWayPoint(List<String> lines, Vector3f loc, float partialTicks) {
GlStateManager.alphaFunc(516, 0.1F);
GlStateManager.pushMatrix();
@@ -373,15 +409,9 @@ public class RenderUtils {
GlStateManager.translate(x, y, z);
GlStateManager.translate(0, viewer.getEyeHeight(), 0);
- renderNametag(str);
-
- GlStateManager.rotate(-Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);
- GlStateManager.rotate(Minecraft.getMinecraft().getRenderManager().playerViewX, 1.0F, 0.0F, 0.0F);
- GlStateManager.translate(0, -0.25f, 0);
- GlStateManager.rotate(-Minecraft.getMinecraft().getRenderManager().playerViewX, 1.0F, 0.0F, 0.0F);
- GlStateManager.rotate(Minecraft.getMinecraft().getRenderManager().playerViewY, 0.0F, 1.0F, 0.0F);
-
- renderNametag(EnumChatFormatting.YELLOW.toString() + Math.round(dist) + "m");
+ lines = new ArrayList<>(lines);
+ lines.add(EnumChatFormatting.YELLOW.toString() + Math.round(dist) + "m");
+ renderNametag(lines);
GlStateManager.popMatrix();
@@ -389,6 +419,10 @@ public class RenderUtils {
}
public static void renderNametag(String str) {
+ renderNametag(Arrays.asList(str));
+ }
+
+ public static void renderNametag(List<String> lines) {
FontRenderer fontrenderer = Minecraft.getMinecraft().fontRendererObj;
float f = 1.6F;
float f1 = 0.016666668F * f;
@@ -406,20 +440,23 @@ public class RenderUtils {
WorldRenderer worldrenderer = tessellator.getWorldRenderer();
int i = 0;
- int j = fontrenderer.getStringWidth(str) / 2;
- GlStateManager.disableTexture2D();
- worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR);
- worldrenderer.pos(-j - 1, -1 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
- worldrenderer.pos(-j - 1, 8 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
- worldrenderer.pos(j + 1, 8 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
- worldrenderer.pos(j + 1, -1 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
- tessellator.draw();
- GlStateManager.enableTexture2D();
- fontrenderer.drawString(str, -fontrenderer.getStringWidth(str) / 2, i, 553648127);
- GlStateManager.depthMask(true);
-
- fontrenderer.drawString(str, -fontrenderer.getStringWidth(str) / 2, i, -1);
-
+ for (String str : lines) {
+ int j = fontrenderer.getStringWidth(str) / 2;
+
+ GlStateManager.disableTexture2D();
+ worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR);
+ worldrenderer.pos(-j - 1, -1 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
+ worldrenderer.pos(-j - 1, 8 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
+ worldrenderer.pos(j + 1, 8 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
+ worldrenderer.pos(j + 1, -1 + i, 0.0D).color(0.0F, 0.0F, 0.0F, 0.25F).endVertex();
+ tessellator.draw();
+ GlStateManager.enableTexture2D();
+ fontrenderer.drawString(str, -fontrenderer.getStringWidth(str) / 2, i, 553648127);
+ GlStateManager.depthMask(true);
+
+ fontrenderer.drawString(str, -fontrenderer.getStringWidth(str) / 2, i, -1);
+ GlStateManager.translate(0, 10f, 0);
+ }
GlStateManager.enableDepth();
GlStateManager.enableBlend();
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/TextRenderUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/TextRenderUtils.java
index ff7ac53a..cee38cea 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/TextRenderUtils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/core/util/render/TextRenderUtils.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.core.util.render;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
index 3f7476bd..7a609a2a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeManager.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.cosmetics;
import com.google.common.collect.BiMap;
@@ -67,6 +86,7 @@ public class CapeManager {
new CapeData("lava", false, false),
new CapeData("tunnel", false, false),
new CapeData("planets", false, false),
+ new CapeData("screensaver", false, false),
//Admins
new CapeData("nullzee", true, false),
@@ -125,46 +145,53 @@ public class CapeManager {
}
private void updateCapes() {
- NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("activecapes.json", (jsonObject) -> {
- if (jsonObject.get("success").getAsBoolean()) {
- lastJsonSync = jsonObject;
-
- lastCapeSynced = System.currentTimeMillis();
- capeMap.clear();
- for (JsonElement active : jsonObject.get("active").getAsJsonArray()) {
- if (active.isJsonObject()) {
- JsonObject activeObj = (JsonObject) active;
- setCape(activeObj.get("_id").getAsString(), activeObj.get("capeType").getAsString(), false);
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newMoulberryRequest("activecapes.json")
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ if (jsonObject.get("success").getAsBoolean()) {
+ lastJsonSync = jsonObject;
+
+ lastCapeSynced = System.currentTimeMillis();
+ capeMap.clear();
+ for (JsonElement active : jsonObject.get("active").getAsJsonArray()) {
+ if (active.isJsonObject()) {
+ JsonObject activeObj = (JsonObject) active;
+ setCape(activeObj.get("_id").getAsString(), activeObj.get("capeType").getAsString(), false);
+ }
}
}
- }
- }, () -> System.out.println("[MBAPI] Update capes errored"));
+ });
if (Minecraft.getMinecraft().thePlayer != null && permSyncTries > 0) {
String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "");
permSyncTries--;
- NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("permscapes.json", (jsonObject) -> {
- if (!jsonObject.get("success").getAsBoolean()) return;
-
- permSyncTries = 0;
- availableCapes.clear();
- for (JsonElement permPlayer : jsonObject.get("perms").getAsJsonArray()) {
- if (!permPlayer.isJsonObject()) continue;
- String playerUuid = permPlayer.getAsJsonObject().get("_id").getAsString();
- if (!(playerUuid != null && playerUuid.equals(uuid))) continue;
- for (JsonElement perm : permPlayer.getAsJsonObject().get("perms").getAsJsonArray()) {
- if (!perm.isJsonPrimitive()) continue;
- String cape = perm.getAsString();
- if (cape.equals("*")) {
- allAvailable = true;
- } else {
- availableCapes.add(cape);
- }
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newMoulberryRequest("permscapes.json")
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ if (!jsonObject.get("success").getAsBoolean()) return;
+
+ permSyncTries = 0;
+ availableCapes.clear();
+ for (JsonElement permPlayer : jsonObject.get("perms").getAsJsonArray()) {
+ if (!permPlayer.isJsonObject()) continue;
+ String playerUuid = permPlayer.getAsJsonObject().get("_id").getAsString();
+ if (!(playerUuid != null && playerUuid.equals(uuid))) continue;
+ for (JsonElement perm : permPlayer.getAsJsonObject().get("perms").getAsJsonArray()) {
+ if (!perm.isJsonPrimitive()) continue;
+ String cape = perm.getAsString();
+ if (cape.equals("*")) {
+ allAvailable = true;
+ } else {
+ availableCapes.add(cape);
+ }
+ }
+ return;
}
- return;
- }
- }, () -> System.out.println("[MBAPI] Update capes errored - perms"));
+
+ });
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java
index c32cc98f..9bf0313b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/CapeNode.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.cosmetics;
import net.minecraft.client.renderer.Tessellator;
@@ -391,4 +410,4 @@ public class CapeNode {
.normal(otherSideNorm.x, otherSideNorm.y, otherSideNorm.z).endVertex();
tessellator.draw();
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java
index 1b33decf..12d8c92d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/GuiCosmetics.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.cosmetics;
import com.google.gson.Gson;
@@ -385,21 +404,14 @@ public class GuiCosmetics extends GuiScreen {
.getSession()
.getProfile(), accessToken, serverId);
- if (wantToEquipCape == null) {
- NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync(
- "cgi-bin/changecape.py?capeType=null&serverId=" +
- serverId + "&username=" + userName,
- System.out::println,
- () -> System.out.println("Change cape error")
- );
- } else {
- NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync(
- "cgi-bin/changecape.py?capeType=" + wantToEquipCape + "&serverId=" +
- serverId + "&username=" + userName,
- System.out::println,
- () -> System.out.println("Change cape error")
- );
- }
+ String toEquipName = wantToEquipCape == null ? "null" : wantToEquipCape;
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newMoulberryRequest("cgi-bin/changecape.py")
+ .queryArgument("capeType", toEquipName)
+ .queryArgument("serverId", serverId)
+ .queryArgument("username", userName)
+ .requestString()
+ .thenAccept(System.out::println);
} catch (Exception e) {
System.out.println("Exception while generating mojang shared secret");
e.printStackTrace();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java
index da9d1f68..d32abf64 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/NEUCape.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.cosmetics;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -18,13 +37,22 @@ import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Keyboard;
-import org.lwjgl.opengl.*;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL15;
+import org.lwjgl.opengl.GL20;
+import org.lwjgl.opengl.GL30;
+import org.lwjgl.opengl.GL42;
+import org.lwjgl.opengl.GL43;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.TreeMap;
public class NEUCape {
private int currentFrame = 0;
@@ -43,6 +71,10 @@ public class NEUCape {
private final Random random = new Random();
private long eventMillis;
+ private float dvdPositionX = 100;
+ private float dvdPositionY = 100;
+ private float dvdVelocityX = -10;
+ private float dvdVelocityY = 10;
private float eventLength;
private float eventRandom;
@@ -101,6 +133,8 @@ public class NEUCape {
shaderName = "tunnel";
} else if (capeName.equalsIgnoreCase("planets")) {
shaderName = "planets";
+ } else if (capeName.equalsIgnoreCase("screensaver")) {
+ shaderName = "screensaver";
} else {
shaderName = "shiny_cape";
}
@@ -322,6 +356,9 @@ public class NEUCape {
Minecraft.getMinecraft().displayWidth,
Minecraft.getMinecraft().displayHeight
));
+ } else if (shaderName.equalsIgnoreCase("screensaver")) {
+ shaderManager.loadData(shaderId, "something", (int) ((System.currentTimeMillis() / 4) % 256));
+ shaderManager.loadData(shaderId, "dvdPosition", new Vector2f(dvdPositionX, dvdPositionY));
}
}
@@ -530,6 +567,19 @@ public class NEUCape {
private int crouchTicks = 0;
long startTime = 0;
+ public float deltaYComparedToLine(float x0, float y0, float x1, float y1) {
+ float m = (y1 - y0) / (x1 - x0);
+ float b = y0 - m * x0;
+ float lineAtX = dvdPositionX * m + b;
+ return dvdPositionY - lineAtX;
+ }
+
+ public float projectOntoLine(float x0, float y0, float x1, float y1, float x) {
+ float m = (y1 - y0) / (x1 - x0);
+ float b = y0 - m * x0;
+ return x * m + b;
+ }
+
private void updateCape(EntityPlayer player) {
Vector3f capeTranslation = updateFixedCapeNodes(player);
@@ -546,6 +596,30 @@ public class NEUCape {
eventMillis = currentTime;
eventLength = random.nextFloat() * 3000 + 3000;
}
+ } else if (shaderName.equals("screensaver")) {
+ dvdPositionX += dvdVelocityX;
+ dvdPositionY += dvdVelocityY;
+ float diskSizeX = 162 / 2F, diskSizeY = 78 / 2F;
+ // Left line
+ if (deltaYComparedToLine(0, 404, 47, 0) < 0) {
+ dvdVelocityX = 10;
+ dvdPositionX = projectOntoLine(404, 0, 0, 47, dvdPositionY);
+ }
+ // Bottom line
+ if (deltaYComparedToLine(0, 404 - diskSizeY, 292, 404 - diskSizeY) > 0) {
+ dvdVelocityY = -10;
+ dvdPositionY = 404 - diskSizeY;
+ }
+ // Top line
+ if (deltaYComparedToLine(47, 0, 246, 0) < 0) {
+ dvdVelocityY = 10;
+ dvdPositionY = 0;
+ }
+ // Right line
+ if (deltaYComparedToLine(246 - diskSizeX, 0, 293 - diskSizeX, 404) < 0) {
+ dvdVelocityX = -10;
+ dvdPositionX = projectOntoLine(0, 246 - diskSizeX, 404, 293 - diskSizeX, dvdPositionY);
+ }
}
double playerAngle = getPlayerRenderAngle(player, 0);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/ShaderManager.java b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/ShaderManager.java
index 4e934e10..45db303b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/ShaderManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/cosmetics/ShaderManager.java
@@ -1,6 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.cosmetics;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.resources.IResourceManager;
+import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL43;
@@ -14,7 +35,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
-public class ShaderManager {
+public class ShaderManager implements IResourceManagerReloadListener {
private final ResourceLocation shaderLocation = new ResourceLocation("notenoughupdates:shaders");
private final HashMap<String, Shader> shaderMap = new HashMap<>();
@@ -24,6 +45,14 @@ public class ShaderManager {
return INSTANCE;
}
+ @Override
+ public void onResourceManagerReload(IResourceManager iResourceManager) {
+ shaderMap.values().forEach(it -> {
+ GL20.glDeleteProgram(it.program);
+ });
+ shaderMap.clear();
+ }
+
public static class Shader {
public final int program;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java
index 0e7c59c7..7a2eb2b0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonBlocks.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.dungeons;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java
index 592f5b19..a4c5a60a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonMap.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.dungeons;
import com.google.common.collect.Iterables;
@@ -660,17 +679,6 @@ public class DungeonMap {
float deltaX = entityPos.getRenderX() - pos.getRenderX();
float deltaY = entityPos.getRenderY() - pos.getRenderY();
- /*if(deltaX > (renderRoomSize + renderConnSize)/2) {
- deltaX -= (renderRoomSize + renderConnSize);
- } else if(deltaX < -(renderRoomSize + renderConnSize)/2) {
- deltaX += (renderRoomSize + renderConnSize);
- }
- if(deltaY > (renderRoomSize + renderConnSize)/2) {
- deltaY -= (renderRoomSize + renderConnSize);
- } else if(deltaY < -(renderRoomSize + renderConnSize)/2) {
- deltaY += (renderRoomSize + renderConnSize);
- }*/
-
x += deltaX;
y += deltaY;
@@ -718,7 +726,7 @@ public class DungeonMap {
}
GlStateManager.color(1, 1, 1, 1);
if ((!NotEnoughUpdates.INSTANCE.config.dungeons.showOwnHeadAsMarker ||
- playerMarkerMapPositions.size() <= 1 || minU != 1 / 4f) &&
+ playerMarkerMapPositions.size() < 1 || minU != 1 / 4f) &&
NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPlayerHeads >= 1 &&
playerSkinMap.containsKey(entry.getKey())) {
Minecraft.getMinecraft().getTextureManager().bindTexture(playerSkinMap.get(entry.getKey()));
@@ -1153,7 +1161,7 @@ public class DungeonMap {
String line = ScorePlayerTeam.formatPlayerName(scoreplayerteam1, score.getPlayerName());
line = Utils.cleanColour(line);
- if (line.contains("(F1)") || line.contains("(E0)") || line.contains("(M1)")) {
+ if (line.contains("(F1)") || line.contains("(E)") || line.contains("(M1)")) {
isFloorOne = true;
break;
}
@@ -1278,15 +1286,15 @@ public class DungeonMap {
if (entity instanceof EntityPlayer) {
EntityPlayer player = (EntityPlayer) entity;
- float roomX = (float) player.posX / (roomSizeBlocks + 1);
- float roomY = (float) player.posZ / (roomSizeBlocks + 1);
+ float roomX = (float) (player.posX + 200) / (roomSizeBlocks + 1);
+ float roomY = (float) (player.posZ + 200) / (roomSizeBlocks + 1);
float playerRoomOffsetX = (float) Math.floor(roomX);
float playerConnOffsetX = (float) Math.floor(roomX);
float playerRoomOffsetY = (float) Math.floor(roomY);
float playerConnOffsetY = (float) Math.floor(roomY);
- float roomXInBlocks = (float) player.posX % (roomSizeBlocks + 1);
+ float roomXInBlocks = (float) (player.posX + 200) % (roomSizeBlocks + 1);
if (roomXInBlocks < 2) { //0,1
playerConnOffsetX -= 2 / 5f - roomXInBlocks / 5f;
} else if (roomXInBlocks > roomSizeBlocks - 2) { //31,30,29
@@ -1296,7 +1304,7 @@ public class DungeonMap {
playerRoomOffsetX += (roomXInBlocks - 2) / (roomSizeBlocks - 4);
}
- float roomYInBlocks = (float) player.posZ % (roomSizeBlocks + 1);
+ float roomYInBlocks = (float) (player.posZ + 200) % (roomSizeBlocks + 1);
if (roomYInBlocks < 2) { //0,1
playerConnOffsetY -= 2 / 5f - roomYInBlocks / 5f;
} else if (roomYInBlocks > roomSizeBlocks - 2) { //31,30,29
@@ -1606,7 +1614,6 @@ public class DungeonMap {
if(player.getUniqueID().toString().charAt(14) == '4') {
actualPlayers.add(player.getName());
System.out.println(player.getName());
-
}
}*/
int players = 0;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java
index 976dfcf8..a56a5679 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/DungeonWin.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.dungeons;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -14,7 +33,12 @@ import net.minecraftforge.client.event.ClientChatReceivedEvent;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -200,7 +224,17 @@ public class DungeonWin {
displayWin();
} else {
if (unformatted.trim().length() > 0) {
- text.add(e.message.getFormattedText().substring(6).trim());
+ if (unformatted.contains("The Catacombs") || unformatted.contains("Master Mode Catacombs") ||
+ unformatted.contains("Team Score") || unformatted.contains("Defeated") || unformatted.contains(
+ "Total Damage")
+ || unformatted.contains("Ally Healing") || unformatted.contains("Enemies Killed") || unformatted.contains(
+ "Deaths") || unformatted.contains("Secrets Found")) {
+ text.add(e.message.getFormattedText().substring(6).trim());
+ } else {
+ System.out.println(
+ "These messages would of showed on neu dungeon overlay but didnt, They are either bugged or i missed them: \"" +
+ e.message.getFormattedText().substring(6).trim() + "\"");
+ }
}
}
} else {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java
index 41fa3663..8ce9d505 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/dungeons/GuiDungeonMapEditor.java
@@ -1,847 +1,872 @@
-package io.github.moulberry.notenoughupdates.dungeons;
-
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.core.GuiElementColour;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-import io.github.moulberry.notenoughupdates.core.config.gui.GuiPositionEditor;
-import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
-import io.github.moulberry.notenoughupdates.core.util.render.TextRenderUtils;
-import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField;
-import io.github.moulberry.notenoughupdates.options.seperateSections.DungeonMapConfig;
-import io.github.moulberry.notenoughupdates.util.SpecialColour;
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.client.renderer.OpenGlHelper;
-import net.minecraft.client.shader.Framebuffer;
-import net.minecraft.client.shader.Shader;
-import net.minecraft.util.EnumChatFormatting;
-import net.minecraft.util.Matrix4f;
-import net.minecraft.util.ResourceLocation;
-import net.minecraft.util.Vec4b;
-import org.lwjgl.input.Keyboard;
-import org.lwjgl.input.Mouse;
-import org.lwjgl.opengl.GL11;
-
-import java.awt.*;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.util.List;
-import java.util.*;
-
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.*;
-
-public class GuiDungeonMapEditor extends GuiScreen {
- public static final ResourceLocation BACKGROUND = new ResourceLocation(
- "notenoughupdates:dungeon_map/editor/background.png");
- public static final ResourceLocation BUTTON = new ResourceLocation("notenoughupdates:dungeon_map/editor/button.png");
- private static final DungeonMap demoMap = new DungeonMap();
-
- private int sizeX;
- private int sizeY;
- private int guiLeft;
- private int guiTop;
-
- private final List<Button> buttons = new ArrayList<>();
-
- private final GuiElementTextField blurField = new GuiElementTextField(
- "",
- GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE
- );
- private GuiElementColour activeColourEditor = null;
-
- private Field clickedSlider;
-
- class Button {
- private final int id;
- private final int x;
- private final int y;
- private String text;
- private Color colour = new Color(-1, true);
- private final Field option;
- private String displayName;
- private String desc;
-
- public Button(int id, int x, int y, String text) {
- this(id, x, y, text, null);
- }
-
- public Button(int id, int x, int y, String text, Field option) {
- this.id = id;
- this.x = x;
- this.y = y;
- this.text = text;
- this.option = option;
-
- if (option != null) {
- ConfigOption optionAnnotation = option.getAnnotation(ConfigOption.class);
- displayName = optionAnnotation.name();
- desc = optionAnnotation.desc();
- }
- }
-
- public List<String> getTooltip() {
- if (option == null) {
- return null;
- }
-
- List<String> tooltip = new ArrayList<>();
- tooltip.add(EnumChatFormatting.YELLOW + displayName);
- for (String line : desc.split("\n")) {
- tooltip.add(EnumChatFormatting.AQUA + line);
- }
- return tooltip;
- }
-
- public void render() {
- if (text == null) return;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(BUTTON);
- if (isButtonPressed(id)) {
- GlStateManager.color(colour.getRed() * 0.85f / 255f, colour.getGreen() * 0.85f / 255f,
- colour.getBlue() * 0.85f / 255f, 1
- );
- Utils.drawTexturedRect(guiLeft + x, guiTop + y, 48, 16, 1, 0, 1, 0, GL11.GL_NEAREST);
- } else {
- GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, 1);
- Utils.drawTexturedRect(guiLeft + x, guiTop + y, 48, 16, GL11.GL_NEAREST);
- }
-
- if (text.length() > 0) {
- Utils.drawStringCenteredScaledMaxWidth(
- text,
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + x + 24,
- guiTop + y + 8,
- false,
- 39,
- 0xFF000000
- );
- }
- }
-
- }
-
- public GuiDungeonMapEditor() {
- DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
- //Map Border Size
- //buttons.add(new Button(0, 6, 37, "Small", options.dmBorderSize));
- //buttons.add(new Button(1, 52, 37, "Medium", options.dmBorderSize));
- //buttons.add(new Button(2, 98, 37, "Large", options.dmBorderSize));
-
- //Map Rooms Size
- //buttons.add(new Button(3, 6, 67+19, "Small", options.dmRoomSize));
- //buttons.add(new Button(4, 52, 67+19, "Medium", options.dmRoomSize));
- //buttons.add(new Button(5, 98, 67+19, "Large", options.dmRoomSize));
-
- //Map Border Styles
- buttons.add(new Button(6, 6, 97 + 30, "None"));
- buttons.add(new Button(7, 52, 97 + 30, "Custom"));
- buttons.add(new Button(8, 98, 97 + 30, "Stone"));
- buttons.add(new Button(9, 6, 116 + 30, "Wood"));
- buttons.add(new Button(10, 52, 116 + 30, "Rustic(S)"));
- buttons.add(new Button(11, 98, 116 + 30, "Rustic(C)"));
- buttons.add(new Button(12, 6, 135 + 30, "Fade"));
- buttons.add(new Button(13, 52, 135 + 30, "Ribbons"));
- buttons.add(new Button(14, 98, 135 + 30, "Paper"));
- buttons.add(new Button(15, 6, 154 + 30, "Crimson"));
- buttons.add(new Button(16, 52, 154 + 30, "Ornate"));
- buttons.add(new Button(17, 98, 154 + 30, "Dragon"));
-
- try {
- //Dungeon Map
- buttons.add(new Button(18, 20 + 139, 36, "Yes/No", DungeonMapConfig.class.getDeclaredField("dmEnable")));
- //Center
- buttons.add(new Button(
- 19,
- 84 + 139,
- 36,
- "Player/Map",
- DungeonMapConfig.class.getDeclaredField("dmCenterPlayer")
- ));
- //Rotate
- buttons.add(new Button(
- 20,
- 20 + 139,
- 65,
- "Player/No Rotate",
- DungeonMapConfig.class.getDeclaredField("dmRotatePlayer")
- ));
- //Icon Style
- buttons.add(new Button(
- 21,
- 84 + 139,
- 65,
- "Default/Heads",
- DungeonMapConfig.class.getDeclaredField("dmPlayerHeads")
- ));
- //Check Orient
- buttons.add(new Button(
- 22,
- 20 + 139,
- 94,
- "Normal/Reorient",
- DungeonMapConfig.class.getDeclaredField("dmOrientCheck")
- ));
- //Check Center
- buttons.add(new Button(23, 84 + 139, 94, "Yes/No", DungeonMapConfig.class.getDeclaredField("dmCenterCheck")));
- //Interpolation
- buttons.add(new Button(24, 20 + 139, 123, "Yes/No", DungeonMapConfig.class.getDeclaredField("dmPlayerInterp")));
- //Compatibility
- buttons.add(new Button(
- 25,
- 84 + 139,
- 123,
- "Normal/No SHD/No FB/SHD",
- DungeonMapConfig.class.getDeclaredField("dmCompat")
- ));
-
- //Background
- buttons.add(new Button(26, 20 + 139, 152, "", DungeonMapConfig.class.getDeclaredField("dmBackgroundColour")));
- //Border
- buttons.add(new Button(27, 84 + 139, 152, "", DungeonMapConfig.class.getDeclaredField("dmBorderColour")));
-
- //Chroma Mode
- buttons.add(new Button(
- 28,
- 84 + 139,
- 181,
- "Normal/Scroll",
- DungeonMapConfig.class.getDeclaredField("dmChromaBorder")
- ));
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- //buttons.add(new Button(29, 52, 86+19, "XLarge", options.dmRoomSize));
- //buttons.add(new Button(30, 52, 56, "XLarge", options.dmBorderSize));
-
- {
- double val = NotEnoughUpdates.INSTANCE.config.dungeonMap.dmBackgroundBlur;
- String strVal;
- if (val % 1 == 0) {
- strVal = Integer.toString((int) val);
- } else {
- strVal = Double.toString(val);
- strVal = strVal.replaceAll("(\\.\\d\\d\\d)(?:\\d)+", "$1");
- strVal = strVal.replaceAll("0+$", "");
- }
- blurField.setText(strVal);
- }
- }
-
- @Override
- public void drawScreen(int mouseX, int mouseY, float partialTicks) {
- ScaledResolution scaledResolution = Utils.pushGuiScale(2);
- this.width = scaledResolution.getScaledWidth();
- this.height = scaledResolution.getScaledHeight();
-
- mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth;
- mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1;
-
- List<String> tooltipToDisplay = null;
- for (Button button : buttons) {
- if (mouseX >= guiLeft + button.x && mouseX <= guiLeft + button.x + 48 &&
- mouseY >= guiTop + button.y - 13 && mouseY <= guiTop + button.y + 16) {
- if (button.id >= 6 && button.id <= 17) {
- String mapDesc = null;
- String mapCredit = null;
- int id = button.id;
- switch (id) {
- case 6:
- mapDesc = "No Border";
- break;
- case 7:
- mapDesc = "Used by custom Resource Packs";
- break;
- case 8:
- mapDesc = "Simple gray border";
- mapCredit = "TomEngMaster";
- break;
- case 9:
- mapDesc = "Viney wood border";
- mapCredit = "iDevil4Hell";
- break;
- case 10:
- mapDesc = "Steampunk-inspired square border";
- mapCredit = "ThatGravyBoat";
- break;
- case 11:
- mapDesc = "Steampunk-inspired circular border";
- mapCredit = "ThatGravyBoat";
- break;
- case 12:
- mapDesc = "Light fade border";
- mapCredit = "Qwiken";
- break;
- case 13:
- mapDesc = "Simple gray border with red ribbons";
- mapCredit = "Sai";
- break;
- case 14:
- mapDesc = "Paper border";
- mapCredit = "KingJames02st";
- break;
- case 15:
- mapDesc = "Nether-inspired border";
- mapCredit = "DTRW191";
- break;
- case 16:
- mapDesc = "Golden ornate border";
- mapCredit = "iDevil4Hell";
- break;
- case 17:
- mapDesc = "Stone dragon border";
- mapCredit = "ImperiaL";
- break;
- }
-
- ArrayList<String> tooltip = new ArrayList<>();
- tooltip.add(EnumChatFormatting.YELLOW + "Border Style");
- tooltip.add(EnumChatFormatting.AQUA + "Customize the look of the dungeon border");
- tooltip.add("");
- if (mapDesc != null)
- tooltip.add(EnumChatFormatting.YELLOW + "Set to: " + EnumChatFormatting.AQUA + mapDesc);
- if (mapCredit != null)
- tooltip.add(EnumChatFormatting.YELLOW + "Artist: " + EnumChatFormatting.GOLD + mapCredit);
- tooltipToDisplay = tooltip;
- } else {
- tooltipToDisplay = button.getTooltip();
- }
- break;
- }
- }
-
- this.sizeX = 431;
- this.sizeY = 237;
- this.guiLeft = (this.width - this.sizeX) / 2;
- this.guiTop = (this.height - this.sizeY) / 2;
-
- super.drawScreen(mouseX, mouseY, partialTicks);
- drawDefaultBackground();
-
- blurBackground();
- renderBlurredBackground(width, height, guiLeft + 2, guiTop + 2, sizeX - 4, sizeY - 4);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
- GlStateManager.color(1, 1, 1, 1);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().fontRendererObj.drawString("NEU Dungeon Map Editor", guiLeft + 8, guiTop + 6, 0xFFB4B4B4);
-
- Utils.drawStringCenteredScaledMaxWidth("Border Size", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 76, guiTop + 30, false, 137, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Rooms Size", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 76, guiTop + 60, false, 137, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Icon Scale", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 76, guiTop + 90, false, 137, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Border Style", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 76, guiTop + 120, false, 137, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("Dungeon Map", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 44 + 139, guiTop + 30, false, 60, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Center", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 108 + 139, guiTop + 30, false, 60, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("Rotate", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 44 + 139, guiTop + 59, false, 60, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Icon Style", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 108 + 139, guiTop + 59, false, 60, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("Check Orient", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 44 + 139, guiTop + 88, false, 60, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Check Center", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 108 + 139, guiTop + 88, false, 60, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("Interpolation", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 44 + 139, guiTop + 117, false, 60, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Compatibility", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 108 + 139, guiTop + 117, false, 60, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("Background", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 44 + 139, guiTop + 146, false, 60, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Border", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 108 + 139, guiTop + 146, false, 60, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("BG Blur", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 44 + 139, guiTop + 175, false, 60, 0xFFB4B4B4
- );
- Utils.drawStringCenteredScaledMaxWidth("Chroma Type", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 108 + 139, guiTop + 175, false, 60, 0xFFB4B4B4
- );
-
- Utils.drawStringCenteredScaledMaxWidth("Edit Map Position", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 76, guiTop + 209, false, 200, 0xFFB4B4B4
- );
-
- try {
- drawSlider(DungeonMapConfig.class.getDeclaredField("dmBorderSize"), guiLeft + 76, guiTop + 45);
- drawSlider(DungeonMapConfig.class.getDeclaredField("dmRoomSize"), guiLeft + 76, guiTop + 75);
- drawSlider(DungeonMapConfig.class.getDeclaredField("dmIconScale"), guiLeft + 76, guiTop + 105);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
- buttons.get(18 - 6).text = options.dmEnable ? "Enabled" : "Disabled";
- buttons.get(19 - 6).text = options.dmCenterPlayer ? "Player" : "Map";
- buttons.get(20 - 6).text = options.dmRotatePlayer ? "Player" : "Vertical";
- buttons.get(21 - 6).text =
- options.dmPlayerHeads <= 0 ? "Default" : options.dmPlayerHeads == 1 ? "Heads" : "Heads w/ Border";
- buttons.get(22 - 6).text = options.dmOrientCheck ? "Orient" : "Off";
- buttons.get(23 - 6).text = options.dmCenterCheck ? "Center" : "Off";
- buttons.get(24 - 6).text = options.dmPlayerInterp ? "Interp" : "No Interp";
- buttons.get(25 - 6).text = options.dmCompat <= 0 ? "Normal" : options.dmCompat >= 2 ? "No FB/SHD" : "No SHD";
-
- buttons.get(26 - 6).colour = new Color(SpecialColour.specialToChromaRGB(options.dmBackgroundColour));
- buttons.get(27 - 6).colour = new Color(SpecialColour.specialToChromaRGB(options.dmBorderColour));
-
- buttons.get(28 - 6).text = options.dmChromaBorder ? "Scroll" : "Normal";
-
- blurField.setSize(48, 16);
- blurField.render(guiLeft + 20 + 139, guiTop + 181);
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex);
- RenderUtils.drawTexturedRect(guiLeft + 52, guiTop + 215, 48, 16);
- TextRenderUtils.drawStringCenteredScaledMaxWidth("Edit", fontRendererObj, guiLeft + 76, guiTop + 223,
- false, 48, 0xFF303030
- );
-
- Map<String, Vec4b> decorations = new HashMap<>();
- Vec4b vec4b = new Vec4b((byte) 3, (byte) (((50) - 64) * 2), (byte) (((40) - 64) * 2), (byte) ((60) * 16 / 360));
- decorations.put(Minecraft.getMinecraft().thePlayer.getName(), vec4b);
-
- HashSet<String> players = new HashSet<>();
- players.add(Minecraft.getMinecraft().thePlayer.getName());
- GlStateManager.color(1, 1, 1, 1);
-
- demoMap.renderMap(guiLeft + 357, guiTop + 125, NotEnoughUpdates.INSTANCE.colourMap, decorations, 0,
- players, false, partialTicks
- );
-
- for (Button button : buttons) {
- button.render();
- }
-
- //List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font
- if (tooltipToDisplay != null) {
- Utils.drawHoveringText(
- tooltipToDisplay,
- mouseX,
- mouseY,
- width,
- height,
- 200,
- Minecraft.getMinecraft().fontRendererObj
- );
- }
-
- Utils.pushGuiScale(-1);
-
- if (activeColourEditor != null) {
- activeColourEditor.render();
- }
- }
-
- public void drawSlider(Field option, int centerX, int centerY) {
- float value;
- float minValue;
- float maxValue;
- try {
- value = ((Number) option.get(NotEnoughUpdates.INSTANCE.config.dungeonMap)).floatValue();
-
- ConfigEditorSlider sliderAnnotation = option.getAnnotation(ConfigEditorSlider.class);
- minValue = sliderAnnotation.minValue();
- maxValue = sliderAnnotation.maxValue();
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
-
- float sliderAmount = Math.max(0, Math.min(1, (value - minValue) / (maxValue - minValue)));
- int sliderAmountI = (int) (96 * sliderAmount);
-
- GlStateManager.color(1f, 1f, 1f, 1f);
- Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on_large);
- Utils.drawTexturedRect(centerX - 48, centerY - 8, sliderAmountI, 16,
- 0, sliderAmount, 0, 1, GL11.GL_NEAREST
- );
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off_large);
- Utils.drawTexturedRect(centerX - 48 + sliderAmountI, centerY - 8, 96 - sliderAmountI, 16,
- sliderAmount, 1, 0, 1, GL11.GL_NEAREST
- );
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(slider_button);
- Utils.drawTexturedRect(centerX - 48 + sliderAmountI - 4, centerY - 8, 8, 16,
- 0, 1, 0, 1, GL11.GL_NEAREST
- );
- }
-
- @Override
- protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
- super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
-
- if (clickedSlider != null) {
- float minValue;
- float maxValue;
- try {
- ConfigEditorSlider sliderAnnotation = clickedSlider.getAnnotation(ConfigEditorSlider.class);
- minValue = sliderAnnotation.minValue();
- maxValue = sliderAnnotation.maxValue();
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
-
- float sliderAmount = (mouseX - (guiLeft + 76 - 48)) / 96f;
- double val = minValue + (maxValue - minValue) * sliderAmount;
- if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
- val = Math.round(val);
- }
- float value = (float) Math.max(minValue, Math.min(maxValue, val));
- try {
- if (clickedSlider.getType() == int.class) {
- clickedSlider.set(NotEnoughUpdates.INSTANCE.config.dungeonMap, Math.round(value));
- } else {
- clickedSlider.set(NotEnoughUpdates.INSTANCE.config.dungeonMap, value);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- }
-
- @Override
- protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
- for (Button button : buttons) {
- if (mouseX >= guiLeft + button.x && mouseX <= guiLeft + button.x + 48 &&
- mouseY >= guiTop + button.y && mouseY <= guiTop + button.y + 16) {
- buttonClicked(mouseX, mouseY, button.id);
-
- blurField.otherComponentClick();
- return;
- }
- }
-
- clickedSlider = null;
- if (mouseX >= guiLeft + 76 - 48 && mouseX <= guiLeft + 76 + 48) {
- try {
- if (mouseY > guiTop + 45 - 8 && mouseY < guiTop + 45 + 8) {
- clickedSlider = DungeonMapConfig.class.getDeclaredField("dmBorderSize");
- return;
- } else if (mouseY > guiTop + 75 - 8 && mouseY < guiTop + 75 + 8) {
- clickedSlider = DungeonMapConfig.class.getDeclaredField("dmRoomSize");
- return;
- } else if (mouseY > guiTop + 105 - 8 && mouseY < guiTop + 105 + 8) {
- clickedSlider = DungeonMapConfig.class.getDeclaredField("dmIconScale");
- return;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- if (mouseY > guiTop + 181 && mouseY < guiTop + 181 + 16) {
- if (mouseX > guiLeft + 20 + 139 && mouseX < guiLeft + 20 + 139 + 48) {
- blurField.mouseClicked(mouseX, mouseY, mouseButton);
- return;
- }
- } else if (mouseY > guiTop + 215 && mouseY < guiTop + 215 + 16) {
- if (mouseX > guiLeft + 52 && mouseX < guiLeft + 100) {
- int size = 80 + Math.round(40 * NotEnoughUpdates.INSTANCE.config.dungeonMap.dmBorderSize);
-
- Map<String, Vec4b> decorations = new HashMap<>();
- Vec4b vec4b = new Vec4b((byte) 3, (byte) (((50) - 64) * 2), (byte) (((40) - 64) * 2), (byte) ((60) * 16 / 360));
- decorations.put(Minecraft.getMinecraft().thePlayer.getName(), vec4b);
-
- HashSet<String> players = new HashSet<>();
- players.add(Minecraft.getMinecraft().thePlayer.getName());
- GlStateManager.color(1, 1, 1, 1);
-
- Minecraft.getMinecraft().displayGuiScreen(new GuiPositionEditor(
- NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPosition,
- size, size, () -> {
- ScaledResolution scaledResolution = Utils.pushGuiScale(2);
- demoMap.renderMap(
- NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPosition.getAbsX(scaledResolution, size) + size / 2,
- NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPosition.getAbsY(scaledResolution, size) + size / 2,
- NotEnoughUpdates.INSTANCE.colourMap,
- decorations,
- 0,
- players,
- false,
- 0
- );
- Utils.pushGuiScale(-1);
- }, () -> {}, () -> NotEnoughUpdates.INSTANCE.openGui = new GuiDungeonMapEditor()
- ).withScale(2));
- return;
- }
- }
-
- blurField.otherComponentClick();
- }
-
- @Override
- public void handleMouseInput() throws IOException {
- super.handleMouseInput();
-
- if (activeColourEditor != null) {
- ScaledResolution realRes = new ScaledResolution(Minecraft.getMinecraft());
- int mouseX = Mouse.getEventX() * realRes.getScaledWidth() / this.mc.displayWidth;
- int mouseY =
- realRes.getScaledHeight() - Mouse.getEventY() * realRes.getScaledHeight() / this.mc.displayHeight - 1;
- activeColourEditor.mouseInput(mouseX, mouseY);
- }
- }
-
- @Override
- public void handleKeyboardInput() throws IOException {
- super.handleKeyboardInput();
-
- if (activeColourEditor != null) {
- activeColourEditor.keyboardInput();
- }
- }
-
- @Override
- protected void keyTyped(char typedChar, int keyCode) throws IOException {
- super.keyTyped(typedChar, keyCode);
-
- if (blurField.getFocus()) {
- blurField.keyTyped(typedChar, keyCode);
-
- try {
- blurField.setCustomBorderColour(-1);
- NotEnoughUpdates.INSTANCE.config.dungeonMap.dmBackgroundBlur = Float.parseFloat(blurField.getText());
- } catch (Exception e) {
- blurField.setCustomBorderColour(Color.RED.getRGB());
- }
- }
- }
-
- private void buttonClicked(int mouseX, int mouseY, int id) {
- DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
- switch (id) {
- case 0:
- options.dmBorderSize = 0;
- break;
- case 1:
- options.dmBorderSize = 1;
- break;
- case 2:
- options.dmBorderSize = 2;
- break;
- case 30:
- options.dmBorderSize = 3;
- break;
- case 3:
- options.dmRoomSize = 0;
- break;
- case 4:
- options.dmRoomSize = 1;
- break;
- case 5:
- options.dmRoomSize = 2;
- break;
- case 29:
- options.dmRoomSize = 3;
- break;
- case 18:
- options.dmEnable = !options.dmEnable;
- break;
- case 19:
- options.dmCenterPlayer = !options.dmCenterPlayer;
- break;
- case 20:
- options.dmRotatePlayer = !options.dmRotatePlayer;
- break;
- case 21:
- options.dmPlayerHeads++;
- if (options.dmPlayerHeads > 2) options.dmPlayerHeads = 0;
- break;
- case 22:
- options.dmOrientCheck = !options.dmOrientCheck;
- break;
- case 23:
- options.dmCenterCheck = !options.dmCenterCheck;
- break;
- case 24:
- options.dmPlayerInterp = !options.dmPlayerInterp;
- break;
- case 25:
- options.dmCompat++;
- if (options.dmCompat > 2) options.dmCompat = 0;
- break;
- case 26: {
- ScaledResolution realRes = new ScaledResolution(Minecraft.getMinecraft());
- mouseX = Mouse.getEventX() * realRes.getScaledWidth() / this.mc.displayWidth;
- mouseY = realRes.getScaledHeight() - Mouse.getEventY() * realRes.getScaledHeight() / this.mc.displayHeight - 1;
- activeColourEditor = new GuiElementColour(mouseX, mouseY, options.dmBackgroundColour,
- (col) -> options.dmBackgroundColour = col, () -> activeColourEditor = null
- );
- }
- break;
- case 27: {
- ScaledResolution realRes = new ScaledResolution(Minecraft.getMinecraft());
- mouseX = Mouse.getEventX() * realRes.getScaledWidth() / this.mc.displayWidth;
- mouseY = realRes.getScaledHeight() - Mouse.getEventY() * realRes.getScaledHeight() / this.mc.displayHeight - 1;
- activeColourEditor = new GuiElementColour(mouseX, mouseY, options.dmBorderColour,
- (col) -> options.dmBorderColour = col, () -> activeColourEditor = null
- );
- }
- break;
- case 28:
- options.dmChromaBorder = !options.dmChromaBorder;
- break;
- default:
- if (id >= 6 && id <= 17) {
- options.dmBorderStyle = id - 6;
- break;
- }
- }
- }
-
- private boolean isButtonPressed(int id) {
- DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
-
- if (id >= 0 && id <= 2) {
- return options.dmBorderSize == id;
- } else if (id >= 3 && id <= 5) {
- return options.dmRoomSize == id - 3;
- } else if (id >= 6 && id <= 17) {
- return options.dmBorderStyle == id - 6;
- } else if (id == 29) {
- return options.dmRoomSize == 3;
- } else if (id == 30) {
- return options.dmBorderSize == 3;
- }
- return false;
- }
-
- Shader blurShaderHorz = null;
- Framebuffer blurOutputHorz = null;
- Shader blurShaderVert = null;
- Framebuffer blurOutputVert = null;
-
- /**
- * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate
- * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis).
- * <p>
- * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to
- * apply scales and translations manually.
- */
- private Matrix4f createProjectionMatrix(int width, int height) {
- Matrix4f projMatrix = new Matrix4f();
- projMatrix.setIdentity();
- projMatrix.m00 = 2.0F / (float) width;
- projMatrix.m11 = 2.0F / (float) (-height);
- projMatrix.m22 = -0.0020001999F;
- projMatrix.m33 = 1.0F;
- projMatrix.m03 = -1.0F;
- projMatrix.m13 = 1.0F;
- projMatrix.m23 = -1.0001999F;
- return projMatrix;
- }
-
- private double lastBgBlurFactor = -1;
-
- private void blurBackground() {
- if (!OpenGlHelper.isFramebufferEnabled()) return;
-
- int width = Minecraft.getMinecraft().displayWidth;
- int height = Minecraft.getMinecraft().displayHeight;
-
- if (blurOutputHorz == null) {
- blurOutputHorz = new Framebuffer(width, height, false);
- blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST);
- }
- if (blurOutputVert == null) {
- blurOutputVert = new Framebuffer(width, height, false);
- blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST);
- }
- if (blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) {
- blurOutputHorz.createBindFramebuffer(width, height);
- blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
- }
- if (blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) {
- blurOutputVert.createBindFramebuffer(width, height);
- blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
- }
-
- if (blurShaderHorz == null) {
- try {
- blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
- Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz
- );
- blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0);
- blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
- } catch (Exception ignored) {
- }
- }
- if (blurShaderVert == null) {
- try {
- blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
- blurOutputHorz, blurOutputVert
- );
- blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1);
- blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
- } catch (Exception ignored) {
- }
- }
- if (blurShaderHorz != null && blurShaderVert != null) {
- if (15 != lastBgBlurFactor) {
- blurShaderHorz.getShaderManager().getShaderUniform("Radius").set((float) 15);
- blurShaderVert.getShaderManager().getShaderUniform("Radius").set((float) 15);
- lastBgBlurFactor = 15;
- }
- GL11.glPushMatrix();
- blurShaderHorz.loadShader(0);
- blurShaderVert.loadShader(0);
- GlStateManager.enableDepth();
- GL11.glPopMatrix();
-
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
- }
- }
-
- /**
- * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen.
- * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight]
- */
- public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) {
- if (!OpenGlHelper.isFramebufferEnabled()) return;
-
- float uMin = x / (float) width;
- float uMax = (x + blurWidth) / (float) width;
- float vMin = (height - y) / (float) height;
- float vMax = (height - y - blurHeight) / (float) height;
-
- blurOutputVert.bindFramebufferTexture();
- GlStateManager.color(1f, 1f, 1f, 1f);
- Utils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax);
- blurOutputVert.unbindFramebufferTexture();
- }
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.dungeons;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.GuiElementColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import io.github.moulberry.notenoughupdates.core.config.gui.GuiPositionEditor;
+import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.core.util.render.TextRenderUtils;
+import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.options.seperateSections.DungeonMapConfig;
+import io.github.moulberry.notenoughupdates.util.SpecialColour;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.OpenGlHelper;
+import net.minecraft.client.shader.Framebuffer;
+import net.minecraft.client.shader.Shader;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.Matrix4f;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.Vec4b;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.button_tex;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_button;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_off_large;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.slider_on_large;
+
+public class GuiDungeonMapEditor extends GuiScreen {
+ public static final ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates:dungeon_map/editor/background.png");
+ public static final ResourceLocation BUTTON = new ResourceLocation("notenoughupdates:dungeon_map/editor/button.png");
+ private static final DungeonMap demoMap = new DungeonMap();
+
+ private int sizeX;
+ private int sizeY;
+ private int guiLeft;
+ private int guiTop;
+
+ private final List<Button> buttons = new ArrayList<>();
+
+ private final GuiElementTextField blurField = new GuiElementTextField(
+ "",
+ GuiElementTextField.NUM_ONLY | GuiElementTextField.NO_SPACE
+ );
+ private GuiElementColour activeColourEditor = null;
+
+ private Field clickedSlider;
+
+ class Button {
+ private final int id;
+ private final int x;
+ private final int y;
+ private String text;
+ private Color colour = new Color(-1, true);
+ private final Field option;
+ private String displayName;
+ private String desc;
+
+ public Button(int id, int x, int y, String text) {
+ this(id, x, y, text, null);
+ }
+
+ public Button(int id, int x, int y, String text, Field option) {
+ this.id = id;
+ this.x = x;
+ this.y = y;
+ this.text = text;
+ this.option = option;
+
+ if (option != null) {
+ ConfigOption optionAnnotation = option.getAnnotation(ConfigOption.class);
+ displayName = optionAnnotation.name();
+ desc = optionAnnotation.desc();
+ }
+ }
+
+ public List<String> getTooltip() {
+ if (option == null) {
+ return null;
+ }
+
+ List<String> tooltip = new ArrayList<>();
+ tooltip.add(EnumChatFormatting.YELLOW + displayName);
+ for (String line : desc.split("\n")) {
+ tooltip.add(EnumChatFormatting.AQUA + line);
+ }
+ return tooltip;
+ }
+
+ public void render() {
+ if (text == null) return;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BUTTON);
+ if (isButtonPressed(id)) {
+ GlStateManager.color(colour.getRed() * 0.85f / 255f, colour.getGreen() * 0.85f / 255f,
+ colour.getBlue() * 0.85f / 255f, 1
+ );
+ Utils.drawTexturedRect(guiLeft + x, guiTop + y, 48, 16, 1, 0, 1, 0, GL11.GL_NEAREST);
+ } else {
+ GlStateManager.color(colour.getRed() / 255f, colour.getGreen() / 255f, colour.getBlue() / 255f, 1);
+ Utils.drawTexturedRect(guiLeft + x, guiTop + y, 48, 16, GL11.GL_NEAREST);
+ }
+
+ if (text.length() > 0) {
+ Utils.drawStringCenteredScaledMaxWidth(
+ text,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 24,
+ guiTop + y + 8,
+ false,
+ 39,
+ 0xFF000000
+ );
+ }
+ }
+
+ }
+
+ public GuiDungeonMapEditor() {
+ DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
+ //Map Border Size
+ //buttons.add(new Button(0, 6, 37, "Small", options.dmBorderSize));
+ //buttons.add(new Button(1, 52, 37, "Medium", options.dmBorderSize));
+ //buttons.add(new Button(2, 98, 37, "Large", options.dmBorderSize));
+
+ //Map Rooms Size
+ //buttons.add(new Button(3, 6, 67+19, "Small", options.dmRoomSize));
+ //buttons.add(new Button(4, 52, 67+19, "Medium", options.dmRoomSize));
+ //buttons.add(new Button(5, 98, 67+19, "Large", options.dmRoomSize));
+
+ //Map Border Styles
+ buttons.add(new Button(6, 6, 97 + 30, "None"));
+ buttons.add(new Button(7, 52, 97 + 30, "Custom"));
+ buttons.add(new Button(8, 98, 97 + 30, "Stone"));
+ buttons.add(new Button(9, 6, 116 + 30, "Wood"));
+ buttons.add(new Button(10, 52, 116 + 30, "Rustic(S)"));
+ buttons.add(new Button(11, 98, 116 + 30, "Rustic(C)"));
+ buttons.add(new Button(12, 6, 135 + 30, "Fade"));
+ buttons.add(new Button(13, 52, 135 + 30, "Ribbons"));
+ buttons.add(new Button(14, 98, 135 + 30, "Paper"));
+ buttons.add(new Button(15, 6, 154 + 30, "Crimson"));
+ buttons.add(new Button(16, 52, 154 + 30, "Ornate"));
+ buttons.add(new Button(17, 98, 154 + 30, "Dragon"));
+
+ try {
+ //Dungeon Map
+ buttons.add(new Button(18, 20 + 139, 36, "Yes/No", DungeonMapConfig.class.getDeclaredField("dmEnable")));
+ //Center
+ buttons.add(new Button(
+ 19,
+ 84 + 139,
+ 36,
+ "Player/Map",
+ DungeonMapConfig.class.getDeclaredField("dmCenterPlayer")
+ ));
+ //Rotate
+ buttons.add(new Button(
+ 20,
+ 20 + 139,
+ 65,
+ "Player/No Rotate",
+ DungeonMapConfig.class.getDeclaredField("dmRotatePlayer")
+ ));
+ //Icon Style
+ buttons.add(new Button(
+ 21,
+ 84 + 139,
+ 65,
+ "Default/Heads",
+ DungeonMapConfig.class.getDeclaredField("dmPlayerHeads")
+ ));
+ //Check Orient
+ buttons.add(new Button(
+ 22,
+ 20 + 139,
+ 94,
+ "Normal/Reorient",
+ DungeonMapConfig.class.getDeclaredField("dmOrientCheck")
+ ));
+ //Check Center
+ buttons.add(new Button(23, 84 + 139, 94, "Yes/No", DungeonMapConfig.class.getDeclaredField("dmCenterCheck")));
+ //Interpolation
+ buttons.add(new Button(24, 20 + 139, 123, "Yes/No", DungeonMapConfig.class.getDeclaredField("dmPlayerInterp")));
+ //Compatibility
+ buttons.add(new Button(
+ 25,
+ 84 + 139,
+ 123,
+ "Normal/No SHD/No FB/SHD",
+ DungeonMapConfig.class.getDeclaredField("dmCompat")
+ ));
+
+ //Background
+ buttons.add(new Button(26, 20 + 139, 152, "", DungeonMapConfig.class.getDeclaredField("dmBackgroundColour")));
+ //Border
+ buttons.add(new Button(27, 84 + 139, 152, "", DungeonMapConfig.class.getDeclaredField("dmBorderColour")));
+
+ //Chroma Mode
+ buttons.add(new Button(
+ 28,
+ 84 + 139,
+ 181,
+ "Normal/Scroll",
+ DungeonMapConfig.class.getDeclaredField("dmChromaBorder")
+ ));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ //buttons.add(new Button(29, 52, 86+19, "XLarge", options.dmRoomSize));
+ //buttons.add(new Button(30, 52, 56, "XLarge", options.dmBorderSize));
+
+ {
+ double val = NotEnoughUpdates.INSTANCE.config.dungeonMap.dmBackgroundBlur;
+ String strVal;
+ if (val % 1 == 0) {
+ strVal = Integer.toString((int) val);
+ } else {
+ strVal = Double.toString(val);
+ strVal = strVal.replaceAll("(\\.\\d\\d\\d)(?:\\d)+", "$1");
+ strVal = strVal.replaceAll("0+$", "");
+ }
+ blurField.setText(strVal);
+ }
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ ScaledResolution scaledResolution = Utils.pushGuiScale(2);
+ this.width = scaledResolution.getScaledWidth();
+ this.height = scaledResolution.getScaledHeight();
+
+ mouseX = Mouse.getEventX() * this.width / this.mc.displayWidth;
+ mouseY = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1;
+
+ List<String> tooltipToDisplay = null;
+ for (Button button : buttons) {
+ if (mouseX >= guiLeft + button.x && mouseX <= guiLeft + button.x + 48 &&
+ mouseY >= guiTop + button.y - 13 && mouseY <= guiTop + button.y + 16) {
+ if (button.id >= 6 && button.id <= 17) {
+ String mapDesc = null;
+ String mapCredit = null;
+ int id = button.id;
+ switch (id) {
+ case 6:
+ mapDesc = "No Border";
+ break;
+ case 7:
+ mapDesc = "Used by custom Resource Packs";
+ break;
+ case 8:
+ mapDesc = "Simple gray border";
+ mapCredit = "Lucy";
+ break;
+ case 9:
+ mapDesc = "Viney wood border";
+ mapCredit = "iDevil4Hell";
+ break;
+ case 10:
+ mapDesc = "Steampunk-inspired square border";
+ mapCredit = "ThatGravyBoat";
+ break;
+ case 11:
+ mapDesc = "Steampunk-inspired circular border";
+ mapCredit = "ThatGravyBoat";
+ break;
+ case 12:
+ mapDesc = "Light fade border";
+ mapCredit = "Qwiken";
+ break;
+ case 13:
+ mapDesc = "Simple gray border with red ribbons";
+ mapCredit = "Sai";
+ break;
+ case 14:
+ mapDesc = "Paper border";
+ mapCredit = "KingJames02st";
+ break;
+ case 15:
+ mapDesc = "Nether-inspired border";
+ mapCredit = "DTRW191";
+ break;
+ case 16:
+ mapDesc = "Golden ornate border";
+ mapCredit = "iDevil4Hell";
+ break;
+ case 17:
+ mapDesc = "Stone dragon border";
+ mapCredit = "ImperiaL";
+ break;
+ }
+
+ ArrayList<String> tooltip = new ArrayList<>();
+ tooltip.add(EnumChatFormatting.YELLOW + "Border Style");
+ tooltip.add(EnumChatFormatting.AQUA + "Customize the look of the dungeon border");
+ tooltip.add("");
+ if (mapDesc != null)
+ tooltip.add(EnumChatFormatting.YELLOW + "Set to: " + EnumChatFormatting.AQUA + mapDesc);
+ if (mapCredit != null)
+ tooltip.add(EnumChatFormatting.YELLOW + "Artist: " + EnumChatFormatting.GOLD + mapCredit);
+ tooltipToDisplay = tooltip;
+ } else {
+ tooltipToDisplay = button.getTooltip();
+ }
+ break;
+ }
+ }
+
+ this.sizeX = 431;
+ this.sizeY = 237;
+ this.guiLeft = (this.width - this.sizeX) / 2;
+ this.guiTop = (this.height - this.sizeY) / 2;
+
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ drawDefaultBackground();
+
+ blurBackground();
+ renderBlurredBackground(width, height, guiLeft + 2, guiTop + 2, sizeX - 4, sizeY - 4);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
+
+ Minecraft.getMinecraft().fontRendererObj.drawString("NEU Dungeon Map Editor", guiLeft + 8, guiTop + 6, 0xFFB4B4B4);
+
+ Utils.drawStringCenteredScaledMaxWidth("Border Size", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 76, guiTop + 30, false, 137, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Rooms Size", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 76, guiTop + 60, false, 137, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Icon Scale", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 76, guiTop + 90, false, 137, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Border Style", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 76, guiTop + 120, false, 137, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("Dungeon Map", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 44 + 139, guiTop + 30, false, 60, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Center", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 108 + 139, guiTop + 30, false, 60, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("Rotate", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 44 + 139, guiTop + 59, false, 60, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Icon Style", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 108 + 139, guiTop + 59, false, 60, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("Check Orient", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 44 + 139, guiTop + 88, false, 60, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Check Center", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 108 + 139, guiTop + 88, false, 60, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("Interpolation", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 44 + 139, guiTop + 117, false, 60, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Compatibility", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 108 + 139, guiTop + 117, false, 60, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("Background", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 44 + 139, guiTop + 146, false, 60, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Border", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 108 + 139, guiTop + 146, false, 60, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("BG Blur", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 44 + 139, guiTop + 175, false, 60, 0xFFB4B4B4
+ );
+ Utils.drawStringCenteredScaledMaxWidth("Chroma Type", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 108 + 139, guiTop + 175, false, 60, 0xFFB4B4B4
+ );
+
+ Utils.drawStringCenteredScaledMaxWidth("Edit Map Position", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 76, guiTop + 209, false, 200, 0xFFB4B4B4
+ );
+
+ try {
+ drawSlider(DungeonMapConfig.class.getDeclaredField("dmBorderSize"), guiLeft + 76, guiTop + 45);
+ drawSlider(DungeonMapConfig.class.getDeclaredField("dmRoomSize"), guiLeft + 76, guiTop + 75);
+ drawSlider(DungeonMapConfig.class.getDeclaredField("dmIconScale"), guiLeft + 76, guiTop + 105);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
+ buttons.get(18 - 6).text = options.dmEnable ? "Enabled" : "Disabled";
+ buttons.get(19 - 6).text = options.dmCenterPlayer ? "Player" : "Map";
+ buttons.get(20 - 6).text = options.dmRotatePlayer ? "Player" : "Vertical";
+ buttons.get(21 - 6).text =
+ options.dmPlayerHeads <= 0 ? "Default" : options.dmPlayerHeads == 1 ? "Heads" : "Heads w/ Border";
+ buttons.get(22 - 6).text = options.dmOrientCheck ? "Orient" : "Off";
+ buttons.get(23 - 6).text = options.dmCenterCheck ? "Center" : "Off";
+ buttons.get(24 - 6).text = options.dmPlayerInterp ? "Interp" : "No Interp";
+ buttons.get(25 - 6).text = options.dmCompat <= 0 ? "Normal" : options.dmCompat >= 2 ? "No FB/SHD" : "No SHD";
+
+ buttons.get(26 - 6).colour = new Color(SpecialColour.specialToChromaRGB(options.dmBackgroundColour));
+ buttons.get(27 - 6).colour = new Color(SpecialColour.specialToChromaRGB(options.dmBorderColour));
+
+ buttons.get(28 - 6).text = options.dmChromaBorder ? "Scroll" : "Normal";
+
+ blurField.setSize(48, 16);
+ blurField.render(guiLeft + 20 + 139, guiTop + 181);
+
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex);
+ RenderUtils.drawTexturedRect(guiLeft + 52, guiTop + 215, 48, 16);
+ TextRenderUtils.drawStringCenteredScaledMaxWidth("Edit", fontRendererObj, guiLeft + 76, guiTop + 223,
+ false, 48, 0xFF303030
+ );
+
+ Map<String, Vec4b> decorations = new HashMap<>();
+ Vec4b vec4b = new Vec4b((byte) 3, (byte) (((50) - 64) * 2), (byte) (((40) - 64) * 2), (byte) ((60) * 16 / 360));
+ decorations.put(Minecraft.getMinecraft().thePlayer.getName(), vec4b);
+
+ HashSet<String> players = new HashSet<>();
+ players.add(Minecraft.getMinecraft().thePlayer.getName());
+ GlStateManager.color(1, 1, 1, 1);
+
+ demoMap.renderMap(guiLeft + 357, guiTop + 125, NotEnoughUpdates.INSTANCE.colourMap, decorations, 0,
+ players, false, partialTicks
+ );
+
+ for (Button button : buttons) {
+ button.render();
+ }
+
+ //List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font
+ if (tooltipToDisplay != null) {
+ Utils.drawHoveringText(
+ tooltipToDisplay,
+ mouseX,
+ mouseY,
+ width,
+ height,
+ 200,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+
+ Utils.pushGuiScale(-1);
+
+ if (activeColourEditor != null) {
+ activeColourEditor.render();
+ }
+ }
+
+ public void drawSlider(Field option, int centerX, int centerY) {
+ float value;
+ float minValue;
+ float maxValue;
+ try {
+ value = ((Number) option.get(NotEnoughUpdates.INSTANCE.config.dungeonMap)).floatValue();
+
+ ConfigEditorSlider sliderAnnotation = option.getAnnotation(ConfigEditorSlider.class);
+ minValue = sliderAnnotation.minValue();
+ maxValue = sliderAnnotation.maxValue();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
+
+ float sliderAmount = Math.max(0, Math.min(1, (value - minValue) / (maxValue - minValue)));
+ int sliderAmountI = (int) (96 * sliderAmount);
+
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on_large);
+ Utils.drawTexturedRect(centerX - 48, centerY - 8, sliderAmountI, 16,
+ 0, sliderAmount, 0, 1, GL11.GL_NEAREST
+ );
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off_large);
+ Utils.drawTexturedRect(centerX - 48 + sliderAmountI, centerY - 8, 96 - sliderAmountI, 16,
+ sliderAmount, 1, 0, 1, GL11.GL_NEAREST
+ );
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(slider_button);
+ Utils.drawTexturedRect(centerX - 48 + sliderAmountI - 4, centerY - 8, 8, 16,
+ 0, 1, 0, 1, GL11.GL_NEAREST
+ );
+ }
+
+ @Override
+ protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
+ super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
+
+ if (clickedSlider != null) {
+ float minValue;
+ float maxValue;
+ try {
+ ConfigEditorSlider sliderAnnotation = clickedSlider.getAnnotation(ConfigEditorSlider.class);
+ minValue = sliderAnnotation.minValue();
+ maxValue = sliderAnnotation.maxValue();
+ } catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
+
+ float sliderAmount = (mouseX - (guiLeft + 76 - 48)) / 96f;
+ double val = minValue + (maxValue - minValue) * sliderAmount;
+ if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+ val = Math.round(val);
+ }
+ float value = (float) Math.max(minValue, Math.min(maxValue, val));
+ try {
+ if (clickedSlider.getType() == int.class) {
+ clickedSlider.set(NotEnoughUpdates.INSTANCE.config.dungeonMap, Math.round(value));
+ } else {
+ clickedSlider.set(NotEnoughUpdates.INSTANCE.config.dungeonMap, value);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
+ for (Button button : buttons) {
+ if (mouseX >= guiLeft + button.x && mouseX <= guiLeft + button.x + 48 &&
+ mouseY >= guiTop + button.y && mouseY <= guiTop + button.y + 16) {
+ buttonClicked(mouseX, mouseY, button.id);
+
+ blurField.otherComponentClick();
+ return;
+ }
+ }
+
+ clickedSlider = null;
+ if (mouseX >= guiLeft + 76 - 48 && mouseX <= guiLeft + 76 + 48) {
+ try {
+ if (mouseY > guiTop + 45 - 8 && mouseY < guiTop + 45 + 8) {
+ clickedSlider = DungeonMapConfig.class.getDeclaredField("dmBorderSize");
+ return;
+ } else if (mouseY > guiTop + 75 - 8 && mouseY < guiTop + 75 + 8) {
+ clickedSlider = DungeonMapConfig.class.getDeclaredField("dmRoomSize");
+ return;
+ } else if (mouseY > guiTop + 105 - 8 && mouseY < guiTop + 105 + 8) {
+ clickedSlider = DungeonMapConfig.class.getDeclaredField("dmIconScale");
+ return;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (mouseY > guiTop + 181 && mouseY < guiTop + 181 + 16) {
+ if (mouseX > guiLeft + 20 + 139 && mouseX < guiLeft + 20 + 139 + 48) {
+ blurField.mouseClicked(mouseX, mouseY, mouseButton);
+ return;
+ }
+ } else if (mouseY > guiTop + 215 && mouseY < guiTop + 215 + 16) {
+ if (mouseX > guiLeft + 52 && mouseX < guiLeft + 100) {
+ int size = 80 + Math.round(40 * NotEnoughUpdates.INSTANCE.config.dungeonMap.dmBorderSize);
+
+ Map<String, Vec4b> decorations = new HashMap<>();
+ Vec4b vec4b = new Vec4b((byte) 3, (byte) (((50) - 64) * 2), (byte) (((40) - 64) * 2), (byte) ((60) * 16 / 360));
+ decorations.put(Minecraft.getMinecraft().thePlayer.getName(), vec4b);
+
+ HashSet<String> players = new HashSet<>();
+ players.add(Minecraft.getMinecraft().thePlayer.getName());
+ GlStateManager.color(1, 1, 1, 1);
+
+ Minecraft.getMinecraft().displayGuiScreen(new GuiPositionEditor(
+ NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPosition,
+ size, size, () -> {
+ ScaledResolution scaledResolution = Utils.pushGuiScale(2);
+ demoMap.renderMap(
+ NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPosition.getAbsX(scaledResolution, size) + size / 2,
+ NotEnoughUpdates.INSTANCE.config.dungeonMap.dmPosition.getAbsY(scaledResolution, size) + size / 2,
+ NotEnoughUpdates.INSTANCE.colourMap,
+ decorations,
+ 0,
+ players,
+ false,
+ 0
+ );
+ Utils.pushGuiScale(-1);
+ }, () -> {}, () -> NotEnoughUpdates.INSTANCE.openGui = new GuiDungeonMapEditor()
+ ).withScale(2));
+ return;
+ }
+ }
+
+ blurField.otherComponentClick();
+ }
+
+ @Override
+ public void handleMouseInput() throws IOException {
+ super.handleMouseInput();
+
+ if (activeColourEditor != null) {
+ ScaledResolution realRes = new ScaledResolution(Minecraft.getMinecraft());
+ int mouseX = Mouse.getEventX() * realRes.getScaledWidth() / this.mc.displayWidth;
+ int mouseY =
+ realRes.getScaledHeight() - Mouse.getEventY() * realRes.getScaledHeight() / this.mc.displayHeight - 1;
+ activeColourEditor.mouseInput(mouseX, mouseY);
+ }
+ }
+
+ @Override
+ public void handleKeyboardInput() throws IOException {
+ super.handleKeyboardInput();
+
+ if (activeColourEditor != null) {
+ activeColourEditor.keyboardInput();
+ }
+ }
+
+ @Override
+ protected void keyTyped(char typedChar, int keyCode) throws IOException {
+ super.keyTyped(typedChar, keyCode);
+
+ if (blurField.getFocus()) {
+ blurField.keyTyped(typedChar, keyCode);
+
+ try {
+ blurField.setCustomBorderColour(-1);
+ NotEnoughUpdates.INSTANCE.config.dungeonMap.dmBackgroundBlur = Float.parseFloat(blurField.getText());
+ } catch (Exception e) {
+ blurField.setCustomBorderColour(Color.RED.getRGB());
+ }
+ }
+ }
+
+ private void buttonClicked(int mouseX, int mouseY, int id) {
+ DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
+ switch (id) {
+ case 0:
+ options.dmBorderSize = 0;
+ break;
+ case 1:
+ options.dmBorderSize = 1;
+ break;
+ case 2:
+ options.dmBorderSize = 2;
+ break;
+ case 30:
+ options.dmBorderSize = 3;
+ break;
+ case 3:
+ options.dmRoomSize = 0;
+ break;
+ case 4:
+ options.dmRoomSize = 1;
+ break;
+ case 5:
+ options.dmRoomSize = 2;
+ break;
+ case 29:
+ options.dmRoomSize = 3;
+ break;
+ case 18:
+ options.dmEnable = !options.dmEnable;
+ break;
+ case 19:
+ options.dmCenterPlayer = !options.dmCenterPlayer;
+ break;
+ case 20:
+ options.dmRotatePlayer = !options.dmRotatePlayer;
+ break;
+ case 21:
+ options.dmPlayerHeads++;
+ if (options.dmPlayerHeads > 2) options.dmPlayerHeads = 0;
+ break;
+ case 22:
+ options.dmOrientCheck = !options.dmOrientCheck;
+ break;
+ case 23:
+ options.dmCenterCheck = !options.dmCenterCheck;
+ break;
+ case 24:
+ options.dmPlayerInterp = !options.dmPlayerInterp;
+ break;
+ case 25:
+ options.dmCompat++;
+ if (options.dmCompat > 2) options.dmCompat = 0;
+ break;
+ case 26: {
+ ScaledResolution realRes = new ScaledResolution(Minecraft.getMinecraft());
+ mouseX = Mouse.getEventX() * realRes.getScaledWidth() / this.mc.displayWidth;
+ mouseY = realRes.getScaledHeight() - Mouse.getEventY() * realRes.getScaledHeight() / this.mc.displayHeight - 1;
+ activeColourEditor = new GuiElementColour(mouseX, mouseY, options.dmBackgroundColour,
+ (col) -> options.dmBackgroundColour = col, () -> activeColourEditor = null
+ );
+ }
+ break;
+ case 27: {
+ ScaledResolution realRes = new ScaledResolution(Minecraft.getMinecraft());
+ mouseX = Mouse.getEventX() * realRes.getScaledWidth() / this.mc.displayWidth;
+ mouseY = realRes.getScaledHeight() - Mouse.getEventY() * realRes.getScaledHeight() / this.mc.displayHeight - 1;
+ activeColourEditor = new GuiElementColour(mouseX, mouseY, options.dmBorderColour,
+ (col) -> options.dmBorderColour = col, () -> activeColourEditor = null
+ );
+ }
+ break;
+ case 28:
+ options.dmChromaBorder = !options.dmChromaBorder;
+ break;
+ default:
+ if (id >= 6 && id <= 17) {
+ options.dmBorderStyle = id - 6;
+ break;
+ }
+ }
+ }
+
+ private boolean isButtonPressed(int id) {
+ DungeonMapConfig options = NotEnoughUpdates.INSTANCE.config.dungeonMap;
+
+ if (id >= 0 && id <= 2) {
+ return options.dmBorderSize == id;
+ } else if (id >= 3 && id <= 5) {
+ return options.dmRoomSize == id - 3;
+ } else if (id >= 6 && id <= 17) {
+ return options.dmBorderStyle == id - 6;
+ } else if (id == 29) {
+ return options.dmRoomSize == 3;
+ } else if (id == 30) {
+ return options.dmBorderSize == 3;
+ }
+ return false;
+ }
+
+ Shader blurShaderHorz = null;
+ Framebuffer blurOutputHorz = null;
+ Shader blurShaderVert = null;
+ Framebuffer blurOutputVert = null;
+
+ /**
+ * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate
+ * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis).
+ * <p>
+ * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to
+ * apply scales and translations manually.
+ */
+ private Matrix4f createProjectionMatrix(int width, int height) {
+ Matrix4f projMatrix = new Matrix4f();
+ projMatrix.setIdentity();
+ projMatrix.m00 = 2.0F / (float) width;
+ projMatrix.m11 = 2.0F / (float) (-height);
+ projMatrix.m22 = -0.0020001999F;
+ projMatrix.m33 = 1.0F;
+ projMatrix.m03 = -1.0F;
+ projMatrix.m13 = 1.0F;
+ projMatrix.m23 = -1.0001999F;
+ return projMatrix;
+ }
+
+ private double lastBgBlurFactor = -1;
+
+ private void blurBackground() {
+ if (!OpenGlHelper.isFramebufferEnabled()) return;
+
+ int width = Minecraft.getMinecraft().displayWidth;
+ int height = Minecraft.getMinecraft().displayHeight;
+
+ if (blurOutputHorz == null) {
+ blurOutputHorz = new Framebuffer(width, height, false);
+ blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST);
+ }
+ if (blurOutputVert == null) {
+ blurOutputVert = new Framebuffer(width, height, false);
+ blurOutputVert.setFramebufferFilter(GL11.GL_NEAREST);
+ }
+ if (blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) {
+ blurOutputHorz.createBindFramebuffer(width, height);
+ blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
+ }
+ if (blurOutputVert.framebufferWidth != width || blurOutputVert.framebufferHeight != height) {
+ blurOutputVert.createBindFramebuffer(width, height);
+ blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
+ }
+
+ if (blurShaderHorz == null) {
+ try {
+ blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
+ Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz
+ );
+ blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0);
+ blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
+ } catch (Exception ignored) {
+ }
+ }
+ if (blurShaderVert == null) {
+ try {
+ blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
+ blurOutputHorz, blurOutputVert
+ );
+ blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1);
+ blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
+ } catch (Exception ignored) {
+ }
+ }
+ if (blurShaderHorz != null && blurShaderVert != null) {
+ if (15 != lastBgBlurFactor) {
+ blurShaderHorz.getShaderManager().getShaderUniform("Radius").set((float) 15);
+ blurShaderVert.getShaderManager().getShaderUniform("Radius").set((float) 15);
+ lastBgBlurFactor = 15;
+ }
+ GL11.glPushMatrix();
+ blurShaderHorz.loadShader(0);
+ blurShaderVert.loadShader(0);
+ GlStateManager.enableDepth();
+ GL11.glPopMatrix();
+
+ Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false);
+ }
+ }
+
+ /**
+ * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen.
+ * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight]
+ */
+ public void renderBlurredBackground(int width, int height, int x, int y, int blurWidth, int blurHeight) {
+ if (!OpenGlHelper.isFramebufferEnabled()) return;
+
+ float uMin = x / (float) width;
+ float uMax = (x + blurWidth) / (float) width;
+ float vMin = (height - y) / (float) height;
+ float vMax = (height - y - blurHeight) / (float) height;
+
+ blurOutputVert.bindFramebufferTexture();
+ GlStateManager.color(1f, 1f, 1f, 1f);
+ Utils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax);
+ blurOutputVert.unbindFramebufferTexture();
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/envcheck/EnvironmentScan.java b/src/main/java/io/github/moulberry/notenoughupdates/envcheck/EnvironmentScan.java
new file mode 100644
index 00000000..8e0f24b9
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/envcheck/EnvironmentScan.java
@@ -0,0 +1,85 @@
+package io.github.moulberry.notenoughupdates.envcheck;
+
+import javax.swing.*;
+import java.lang.reflect.Field;
+import java.util.Objects;
+
+public class EnvironmentScan {
+
+ static Class<?> tryGetClass(String name) {
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ static Object tryGetField(Class<?> clazz, Object inst, String name) {
+ if (clazz == null) return null;
+ try {
+ Field declaredField = clazz.getDeclaredField(name);
+ return declaredField.get(inst);
+ } catch (NoSuchFieldException | IllegalAccessException ignored) {
+ }
+ return null;
+ }
+
+
+ static boolean isAtLeast(Object left, int right) {
+ if (left instanceof Integer) {
+ return (Integer) left >= right;
+ }
+ return false;
+ }
+
+ static boolean shouldCheckOnce = true;
+
+ static void checkEnvironmentOnce() {
+ if (shouldCheckOnce) checkEnvironment();
+ }
+
+
+ static void checkEnvironment() {
+ shouldCheckOnce = false;
+ checkForgeEnvironment();
+ }
+
+ static void checkForgeEnvironment() {
+ Class<?> forgeVersion = tryGetClass("net.minecraftforge.common.ForgeVersion");
+ if (forgeVersion == null
+ || !Objects.equals(tryGetField(forgeVersion, null, "majorVersion"), 11)
+ || !Objects.equals(tryGetField(forgeVersion, null, "minorVersion"), 15)
+ || !isAtLeast(tryGetField(forgeVersion, null, "revisionVersion"), 1)
+ || !Objects.equals(tryGetField(forgeVersion, null, "mcVersion"), "1.8.9")
+ ) {
+
+ System.out.printf("Forge Version : %s%nMajor : %s%nMinor : %s%nRevision : %s%nMinecraft : %s%n",
+ forgeVersion,
+ tryGetField(forgeVersion, null, "majorVersion"),
+ tryGetField(forgeVersion, null, "minorVersion"),
+ tryGetField(forgeVersion, null, "revisionVersion"),
+ tryGetField(forgeVersion, null, "mcVersion")
+ );
+ missingOrOutdatedForgeError();
+ }
+ }
+
+ static void missingOrOutdatedForgeError() {
+ showErrorMessage(
+ "You just launched NotEnoughUpdates with the wrong (or no) modloader installed.",
+ "",
+ "NotEnoughUpdates only works in Minecraft 1.8.9, with Forge 11.15.1+",
+ "Please relaunch NotEnoughUpdates in the correct environment.",
+ "If you are using Minecraft 1.8.9 with Forge 11.15.1+ installed, please contact support.",
+ "Click OK to launch anyways."
+ );
+ }
+
+
+ public static void showErrorMessage(String... messages) {
+ String message = String.join("\n", messages);
+ JOptionPane.showMessageDialog(
+ null, message, "NotEnoughUpdates - Problematic System Configuration", JOptionPane.ERROR_MESSAGE
+ );
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/envcheck/FabricEntrypoint.java b/src/main/java/io/github/moulberry/notenoughupdates/envcheck/FabricEntrypoint.java
new file mode 100644
index 00000000..4a70fca3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/envcheck/FabricEntrypoint.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.envcheck;
+
+public class FabricEntrypoint {
+ static {
+ EnvironmentScan.checkForgeEnvironment();
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/envcheck/NEUMixinConfigPlugin.java b/src/main/java/io/github/moulberry/notenoughupdates/envcheck/NEUMixinConfigPlugin.java
new file mode 100644
index 00000000..44e24ff4
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/envcheck/NEUMixinConfigPlugin.java
@@ -0,0 +1,46 @@
+package io.github.moulberry.notenoughupdates.envcheck;
+
+import org.spongepowered.asm.lib.tree.ClassNode;
+import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
+import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
+
+import java.util.List;
+import java.util.Set;
+
+public class NEUMixinConfigPlugin implements IMixinConfigPlugin {
+
+ static {
+ EnvironmentScan.checkEnvironmentOnce();
+ }
+
+ @Override
+ public void onLoad(String mixinPackage) {
+ }
+
+ @Override
+ public String getRefMapperConfig() {
+ return null;
+ }
+
+ @Override
+ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
+ return true;
+ }
+
+ @Override
+ public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
+ }
+
+ @Override
+ public List<String> getMixins() {
+ return null;
+ }
+
+ @Override
+ public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
+ }
+
+ @Override
+ public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/GuiInventoryBackgroundDrawnEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/events/GuiInventoryBackgroundDrawnEvent.java
new file mode 100644
index 00000000..0b8bf126
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/GuiInventoryBackgroundDrawnEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events;
+
+import net.minecraft.client.gui.inventory.GuiContainer;
+
+public class GuiInventoryBackgroundDrawnEvent extends NEUEvent {
+ private final GuiContainer container;
+ private final float partialTicks;
+
+ public GuiInventoryBackgroundDrawnEvent(GuiContainer container, float partialTicks) {
+ this.container = container;
+ this.partialTicks = partialTicks;
+ }
+
+ public GuiContainer getContainer() {
+ return container;
+ }
+
+ public float getPartialTicks() {
+ return partialTicks;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/NEUEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/events/NEUEvent.java
index a2c82070..178431d0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/events/NEUEvent.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/NEUEvent.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.events;
import net.minecraftforge.common.MinecraftForge;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/OnBlockBreakSoundEffect.java b/src/main/java/io/github/moulberry/notenoughupdates/events/OnBlockBreakSoundEffect.java
index aeffa7da..9a2516e1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/events/OnBlockBreakSoundEffect.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/OnBlockBreakSoundEffect.java
@@ -1,6 +1,24 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.events;
-import net.minecraft.block.state.BlockState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.audio.ISound;
import net.minecraft.util.BlockPos;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/RepositoryReloadEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/events/RepositoryReloadEvent.java
new file mode 100644
index 00000000..ab650c54
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/RepositoryReloadEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events;
+
+import java.io.File;
+
+public class RepositoryReloadEvent extends NEUEvent {
+ private final File baseFile;
+ private final boolean isFirstLoad;
+
+ public RepositoryReloadEvent(File baseFile, boolean isFirstLoad) {
+ this.baseFile = baseFile;
+ this.isFirstLoad = isFirstLoad;
+ }
+
+ public boolean isFirstLoad() {
+ return isFirstLoad;
+ }
+
+ public File getRepositoryRoot() {
+ return baseFile;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/SignSubmitEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/events/SignSubmitEvent.java
new file mode 100644
index 00000000..9bc7b8b0
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/SignSubmitEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events;
+
+import net.minecraft.client.gui.inventory.GuiEditSign;
+
+public class SignSubmitEvent extends NEUEvent {
+ public final GuiEditSign sign;
+ public final String[] lines;
+
+ public SignSubmitEvent(GuiEditSign sign, String[] hehe) {
+ this.sign = sign;
+ this.lines = hehe;
+ }
+
+ public GuiEditSign getSign() {
+ return sign;
+ }
+
+ public String[] getLines() {
+ return lines;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/events/SlotClickEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/events/SlotClickEvent.java
new file mode 100644
index 00000000..13c31b54
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/events/SlotClickEvent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.events;
+
+import net.minecraft.client.gui.inventory.GuiContainer;
+import net.minecraft.inventory.Slot;
+import net.minecraftforge.fml.common.eventhandler.Cancelable;
+
+@Cancelable
+public class SlotClickEvent extends NEUEvent {
+ public final GuiContainer guiContainer;
+ public final Slot slot;
+ public final int slotId;
+ public int clickedButton;
+ public int clickType;
+ public boolean usePickblockInstead = false;
+
+ public SlotClickEvent(GuiContainer guiContainer, Slot slot, int slotId, int clickedButton, int clickType) {
+ this.guiContainer = guiContainer;
+ this.slot = slot;
+ this.slotId = slotId;
+ this.clickedButton = clickedButton;
+ this.clickType = clickType;
+ }
+
+ public void usePickblockInstead() {
+ usePickblockInstead = true;
+ }
+
+ @Override
+ public void setCanceled(boolean cancel) {
+ super.setCanceled(cancel);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java
deleted file mode 100644
index 77305904..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/GuiGamemodes.java
+++ /dev/null
@@ -1,323 +0,0 @@
-package io.github.moulberry.notenoughupdates.gamemodes;
-
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.EnumChatFormatting;
-import org.lwjgl.input.Keyboard;
-import org.lwjgl.opengl.GL11;
-
-import java.awt.*;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.*;
-
-public class GuiGamemodes extends GuiScreen {
- private final String currentProfile;
- private SBGamemodes.Gamemode currentGamemode = null;
- private final boolean upgradeOverride;
-
- private int guiLeft = 100;
- private int guiTop = 100;
- private final int xSize = 200;
- private final int ySize = 232;
-
- public GuiGamemodes(boolean upgradeOverride) {
- this.currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile();
- this.upgradeOverride = upgradeOverride;
- }
-
- private boolean canChange(int from, int to) {
- if (from >= to) {
- return true;
- } else {
- return !currentGamemode.locked || upgradeOverride;
- }
- }
-
- @Override
- public void updateScreen() {
- if (this.currentProfile == null) {
- Minecraft.getMinecraft().displayGuiScreen(null);
- Minecraft.getMinecraft().thePlayer.addChatMessage(
- new ChatComponentText(EnumChatFormatting.RED + "Couldn't detect current profile. Maybe try later?"));
- }
-
- if (currentGamemode == null) {
- currentGamemode = SBGamemodes.getGamemode();
- if (currentGamemode == null) {
- Minecraft.getMinecraft().displayGuiScreen(null);
- Minecraft.getMinecraft().thePlayer.addChatMessage(
- new ChatComponentText(EnumChatFormatting.RED + "Couldn't automatically detect current profile." +
- "If you have only 1 profile, try using /api new so that NEU can detect your profile."));
- }
- }
-
- String currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile();
- if (!this.currentProfile.equals(currentProfile)) {
- Minecraft.getMinecraft().displayGuiScreen(null);
- Minecraft.getMinecraft().thePlayer.addChatMessage(
- new ChatComponentText(EnumChatFormatting.RED + "Profile change detected. Closing gamemodes menu."));
- }
- }
-
- @Override
- public void handleKeyboardInput() throws IOException {
- if (Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
- SBGamemodes.saveToFile();
- }
-
- super.handleKeyboardInput();
- }
-
- public void drawStringShadow(String str, float x, float y, int len) {
- for (int xOff = -2; xOff <= 2; xOff++) {
- for (int yOff = -2; yOff <= 2; yOff++) {
- if (Math.abs(xOff) != Math.abs(yOff)) {
- Utils.drawStringScaledMaxWidth(Utils.cleanColourNotModifiers(str),
- Minecraft.getMinecraft().fontRendererObj,
- x + xOff / 2f, y + yOff / 2f, false, len,
- new Color(20, 20, 20, 100 / Math.max(Math.abs(xOff), Math.abs(yOff))).getRGB()
- );
- }
- }
- }
-
- Utils.drawStringScaledMaxWidth(str,
- Minecraft.getMinecraft().fontRendererObj,
- x, y, false, len,
- new Color(64, 64, 64, 255).getRGB()
- );
- }
-
- @Override
- protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
- if (mouseButton == 0) {
- SBGamemodes.HardcoreMode setHC = SBGamemodes.HardcoreMode.NORMAL;
- SBGamemodes.IronmanMode setIM = SBGamemodes.IronmanMode.NORMAL;
- int setMod = 0;
-
- if (mouseX > guiLeft + xSize - 27 && mouseX < guiLeft + xSize - 9) {
- if (mouseY > guiTop + 30 && mouseY < guiTop + 30 + 16) {
- setHC = SBGamemodes.HardcoreMode.SOFTCORE;
- } else if (mouseY > guiTop + 50 && mouseY < guiTop + 50 + 16) {
- setHC = SBGamemodes.HardcoreMode.HARDCORE;
- } else if (mouseY > guiTop + 80 && mouseY < guiTop + 80 + 16) {
- setIM = SBGamemodes.IronmanMode.IRONMAN;
- } else if (mouseY > guiTop + 100 && mouseY < guiTop + 100 + 16) {
- setIM = SBGamemodes.IronmanMode.IRONMANPLUS;
- } else if (mouseY > guiTop + 120 && mouseY < guiTop + 120 + 16) {
- setIM = SBGamemodes.IronmanMode.ULTIMATE_IRONMAN;
- } else if (mouseY > guiTop + 140 && mouseY < guiTop + 140 + 16) {
- setIM = SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS;
- } else if (mouseY > guiTop + 170 && mouseY < guiTop + 170 + 16) {
- setMod = SBGamemodes.MODIFIER_DEVILISH;
- } else if (mouseY > guiTop + 190 && mouseY < guiTop + 190 + 16) {
- setMod = SBGamemodes.MODIFIER_NOBANK;
- } else if (mouseY > guiTop + 210 && mouseY < guiTop + 210 + 16) {
- setMod = SBGamemodes.MODIFIER_SMALLISLAND;
- }
- }
-
- if (setHC != SBGamemodes.HardcoreMode.NORMAL) {
- if (currentGamemode.hardcoreMode == setHC) {
- currentGamemode.hardcoreMode = SBGamemodes.HardcoreMode.NORMAL;
- } else {
- if (canChange(currentGamemode.hardcoreMode.ordinal(), setHC.ordinal())) {
- currentGamemode.hardcoreMode = setHC;
- }
- }
- } else if (setIM != SBGamemodes.IronmanMode.NORMAL) {
- if (currentGamemode.ironmanMode == setIM) {
- currentGamemode.ironmanMode = SBGamemodes.IronmanMode.NORMAL;
- } else {
- if (canChange(currentGamemode.ironmanMode.ordinal(), setIM.ordinal())) {
- currentGamemode.ironmanMode = setIM;
- }
- }
- } else if (setMod != 0) {
- if (canChange(currentGamemode.gamemodeModifiers, currentGamemode.gamemodeModifiers ^ setMod)) {
- currentGamemode.gamemodeModifiers ^= setMod;
- }
- }
- }
- }
-
- @Override
- public void drawScreen(int mouseX, int mouseY, float partialTicks) {
- super.drawDefaultBackground();
-
- guiLeft = (width - xSize) / 2;
- guiTop = (height - ySize) / 2;
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(gamemodes);
- Utils.drawTexturedRect(guiLeft, guiTop, xSize, ySize, GL11.GL_NEAREST);
-
- if (currentGamemode == null) return;
-
- Utils.drawStringCentered("NEU Skyblock Gamemodes", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + xSize / 2f, guiTop + 14, false, new Color(64, 64, 64).getRGB()
- );
-
- drawStringShadow(SBGamemodes.HardcoreMode.SOFTCORE.display, guiLeft + 10, guiTop + 30, xSize - 47);
- drawStringShadow(SBGamemodes.HardcoreMode.HARDCORE.display, guiLeft + 10, guiTop + 50, xSize - 47);
-
- drawStringShadow(SBGamemodes.IronmanMode.IRONMAN.display, guiLeft + 10, guiTop + 80, xSize - 47);
- drawStringShadow(SBGamemodes.IronmanMode.IRONMANPLUS.display, guiLeft + 10, guiTop + 100, xSize - 47);
- drawStringShadow(SBGamemodes.IronmanMode.ULTIMATE_IRONMAN.display, guiLeft + 10, guiTop + 120, xSize - 47);
- drawStringShadow(SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS.display, guiLeft + 10, guiTop + 140, xSize - 47);
-
- drawStringShadow(SBGamemodes.MODIFIER_DEVILISH_DISPLAY, guiLeft + 10, guiTop + 170, xSize - 47);
- drawStringShadow(SBGamemodes.MODIFIER_NOBANK_DISPLAY, guiLeft + 10, guiTop + 190, xSize - 47);
- drawStringShadow(SBGamemodes.MODIFIER_SMALLISLAND_DISPLAY, guiLeft + 10, guiTop + 210, xSize - 47);
-
- String tooltipToDisplay = null;
-
- GlStateManager.color(1, 1, 1, 1);
- if (canChange(currentGamemode.hardcoreMode.ordinal(), SBGamemodes.HardcoreMode.SOFTCORE.ordinal())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- currentGamemode.hardcoreMode == SBGamemodes.HardcoreMode.SOFTCORE ? radial_circle_on : radial_circle_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 30 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 30 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 30 - 4 && mouseY < guiTop + 30 + 12) {
- tooltipToDisplay = SBGamemodes.HardcoreMode.SOFTCORE.desc;
- }
- }
- }
- if (canChange(currentGamemode.hardcoreMode.ordinal(), SBGamemodes.HardcoreMode.HARDCORE.ordinal())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- currentGamemode.hardcoreMode == SBGamemodes.HardcoreMode.HARDCORE ? radial_circle_on : radial_circle_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 50 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 50 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 50 - 4 && mouseY < guiTop + 50 + 12) {
- tooltipToDisplay = SBGamemodes.HardcoreMode.HARDCORE.desc;
- }
- }
- }
-
- if (canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.IRONMAN.ordinal())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- currentGamemode.ironmanMode == SBGamemodes.IronmanMode.IRONMAN ? radial_circle_on : radial_circle_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 80 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 80 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 80 - 4 && mouseY < guiTop + 80 + 12) {
- tooltipToDisplay = SBGamemodes.IronmanMode.IRONMAN.desc;
- }
- }
- }
- if (canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.IRONMANPLUS.ordinal())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- currentGamemode.ironmanMode == SBGamemodes.IronmanMode.IRONMANPLUS ? radial_circle_on : radial_circle_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 100 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 100 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 100 - 4 && mouseY < guiTop + 100 + 12) {
- tooltipToDisplay = SBGamemodes.IronmanMode.IRONMANPLUS.desc;
- }
- }
- }
- if (canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.ULTIMATE_IRONMAN.ordinal())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- currentGamemode.ironmanMode == SBGamemodes.IronmanMode.ULTIMATE_IRONMAN ? radial_circle_on : radial_circle_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 120 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 120 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 120 - 4 && mouseY < guiTop + 120 + 12) {
- tooltipToDisplay = SBGamemodes.IronmanMode.ULTIMATE_IRONMAN.desc;
- }
- }
- }
- if (canChange(currentGamemode.ironmanMode.ordinal(), SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS.ordinal())) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- currentGamemode.ironmanMode == SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS
- ? radial_circle_on
- : radial_circle_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 140 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 140 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 140 - 4 && mouseY < guiTop + 140 + 12) {
- tooltipToDisplay = SBGamemodes.IronmanMode.ULTIMATE_IRONMANPLUS.desc;
- }
- }
- }
-
- if (canChange(
- currentGamemode.gamemodeModifiers,
- currentGamemode.gamemodeModifiers ^ SBGamemodes.MODIFIER_DEVILISH
- )) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- (currentGamemode.gamemodeModifiers & SBGamemodes.MODIFIER_DEVILISH) != 0
- ? radial_square_on
- : radial_square_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 170 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 170 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 170 - 4 && mouseY < guiTop + 170 + 12) {
- tooltipToDisplay = SBGamemodes.MODIFIER_DEVILISH_DESC;
- }
- }
- }
- if (canChange(currentGamemode.gamemodeModifiers, currentGamemode.gamemodeModifiers ^ SBGamemodes.MODIFIER_NOBANK)) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- (currentGamemode.gamemodeModifiers & SBGamemodes.MODIFIER_NOBANK) != 0 ? radial_square_on : radial_square_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 190 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 190 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 190 - 4 && mouseY < guiTop + 190 + 12) {
- tooltipToDisplay = SBGamemodes.MODIFIER_NOBANK_DESC;
- }
- }
- }
- if (canChange(
- currentGamemode.gamemodeModifiers,
- currentGamemode.gamemodeModifiers ^ SBGamemodes.MODIFIER_SMALLISLAND
- )) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(
- (currentGamemode.gamemodeModifiers & SBGamemodes.MODIFIER_SMALLISLAND) != 0
- ? radial_square_on
- : radial_square_off);
- Utils.drawTexturedRect(guiLeft + xSize - 26, guiTop + 210 - 4, 16, 16, GL11.GL_NEAREST);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(help);
- Utils.drawTexturedRect(guiLeft + xSize - 47, guiTop + 210 - 4, 16, 16, GL11.GL_NEAREST);
- if (mouseX > guiLeft + xSize - 47 && mouseX < guiLeft + xSize - 31) {
- if (mouseY > guiTop + 210 - 4 && mouseY < guiTop + 210 + 12) {
- tooltipToDisplay = SBGamemodes.MODIFIER_SMALLISLAND_DESC;
- }
- }
- }
-
- if (tooltipToDisplay != null) {
- List<String> lines = new ArrayList<>();
- for (String line : tooltipToDisplay.split("\n")) {
- lines.add(EnumChatFormatting.GRAY + line);
- }
- Utils.drawHoveringText(lines, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
- }
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java b/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java
deleted file mode 100644
index ddd4a4ba..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/gamemodes/SBGamemodes.java
+++ /dev/null
@@ -1,374 +0,0 @@
-package io.github.moulberry.notenoughupdates.gamemodes;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.util.SBInfo;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiScreen;
-import net.minecraft.client.gui.inventory.GuiChest;
-import net.minecraft.inventory.ContainerChest;
-import net.minecraft.util.ChatComponentText;
-import net.minecraft.util.EnumChatFormatting;
-import net.minecraftforge.client.event.ClientChatReceivedEvent;
-import net.minecraftforge.event.entity.player.PlayerInteractEvent;
-import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import net.minecraftforge.fml.common.gameevent.TickEvent;
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.*;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.security.Key;
-import java.util.Base64;
-import java.util.HashMap;
-
-public class SBGamemodes {
- private static final Gson gson = new Gson();
-
- public static final int MODIFIER_DEVILISH = 0b1;
- public static final int MODIFIER_NOBANK = 0b10;
- public static final int MODIFIER_SMALLISLAND = 0b100;
-
- public static final String MODIFIER_DEVILISH_DISPLAY = EnumChatFormatting.DARK_PURPLE + "Devilish";
- public static final String MODIFIER_NOBANK_DISPLAY = EnumChatFormatting.RED + "No" + EnumChatFormatting.GOLD + "Bank";
- public static final String MODIFIER_SMALLISLAND_DISPLAY = EnumChatFormatting.GREEN + "SmallIsland";
-
- public static final String MODIFIER_DEVILISH_DESC = EnumChatFormatting.DARK_PURPLE + "Devilish\n" +
- "You are NOT allowed to use fairy souls.";
- public static final String MODIFIER_NOBANK_DESC = EnumChatFormatting.RED + "No" + EnumChatFormatting.GOLD + "Bank\n" +
- "You are NOT allowed to use the bank.";
- public static final String MODIFIER_SMALLISLAND_DESC = EnumChatFormatting.GREEN + "SmallIsland\n" +
- "Your private island is 1/4 the normal size.";
-
- private static HashMap<String, Gamemode> currentGamemode = new HashMap<>();
- private static long lastDeathExemption = 0;
-
- public static class Gamemode {
- public HardcoreMode hardcoreMode = HardcoreMode.NORMAL;
- public IronmanMode ironmanMode = IronmanMode.NORMAL;
- public int gamemodeModifiers = 0;
-
- public boolean locked = true;
- }
-
- public enum HardcoreMode {
- NORMAL("Normal", "Normal"),
- SOFTCORE(EnumChatFormatting.RED + "Soft" + EnumChatFormatting.DARK_RED + "core\n" +
- "You only have 1 life.\nDying will remove your hardcore status.\nDeaths to the void or 'unknown' are exempted.",
- "You died.", "You fell into the void"
- ),
- HARDCORE(EnumChatFormatting.DARK_RED + "Hardcore\n" +
- "You only have 1 life.\nDying will remove your hardcore status.");
-
- public final String display;
- public final String desc;
- private final String[] exemptions;
-
- HardcoreMode(String display, String... exemptions) {
- this.display = display.split("\n")[0];
- this.desc = display;
- this.exemptions = exemptions;
- }
-
- public boolean isExemption(String line) {
- for (String exemption : exemptions) {
- if (line.contains(exemption)) return true;
- }
- return false;
- }
- }
-
- public enum IronmanMode {
- NORMAL("Normal"),
- IRONMAN(EnumChatFormatting.WHITE + "Ironman\n" +
- "You are NOT allowed to trade or use the auction house.",
- "You ", "Auction House", "Auctions Browser", "Auction View"
- ),
- IRONMANPLUS(EnumChatFormatting.WHITE + "Ironman" + EnumChatFormatting.GOLD + "+\n" +
- "You are NOT allowed to trade, use the auction house or bazaar.",
- "You ", "Auction House", "Auctions Browser", "Auction View", "Bazaar"
- ),
- ULTIMATE_IRONMAN(EnumChatFormatting.DARK_AQUA + "Ultimate " + EnumChatFormatting.WHITE + "Ironman\n" +
- "You are NOT allowed to trade or use the auction house.\n" +
- "You are restricted to 1 inventory. (No containers, no echest, no wardrobe).",
- "You ", "Auction House", "Auctions Browser", "Auction View", "Chest",
- "Wardrobe", "Weapon Rack", "Shelves"
- ),
- ULTIMATE_IRONMANPLUS(
- EnumChatFormatting.DARK_AQUA + "Ultimate " + EnumChatFormatting.WHITE + "Ironman" + EnumChatFormatting.GOLD +
- "+\n" +
- "You are NOT allowed to trade, use the auction house or bazaar.\n" +
- "You are restricted to 1 inventory. (No containers, no echest, no wardrobe).",
- "You ",
- "Auction House",
- "Auctions Browser",
- "Auction View",
- "Bazaar",
- "Chest",
- "Wardrobe",
- "Weapon Rack",
- "Shelves"
- );
-
- public final String display;
- public final String desc;
- private final String[] bannedInventories;
-
- IronmanMode(String display, String... bannedInventories) {
- this.display = display.split("\n")[0];
- this.desc = display;
- this.bannedInventories = bannedInventories;
- }
-
- public boolean isBanned(String inventoryName) {
- for (String banned : bannedInventories) {
- if (inventoryName.contains(banned + " ") || inventoryName.endsWith(banned)) return true;
- }
- return false;
- }
- }
-
- public static Gamemode getGamemode() {
- String currentProfile = SBInfo.getInstance().currentProfile;
-
- if (currentProfile == null || currentProfile.isEmpty()) return null;
-
- return currentGamemode.computeIfAbsent(currentProfile, k -> new Gamemode());
- }
-
- public static void loadFromFile() {
- File configDir = NotEnoughUpdates.INSTANCE.manager.configLocation;
- File gamemodeFile = new File(
- configDir,
- "gamemodes/gamemodes-" + Minecraft.getMinecraft().thePlayer.getUniqueID().toString() + ".json"
- );
- gamemodeFile.getParentFile().mkdirs();
-
- if (!gamemodeFile.exists()) {
- return;
- }
-
- try (
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- new FileInputStream(gamemodeFile),
- StandardCharsets.UTF_8
- ))
- ) {
- String line = reader.readLine();
- String decoded = decrypt(line);
- currentGamemode = gson.fromJson(decoded, GamemodeWrapper.class).currentGamemode;
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public static class GamemodeWrapper {
- private final HashMap<String, Gamemode> currentGamemode;
-
- public GamemodeWrapper(HashMap<String, Gamemode> currentGamemode) {
- this.currentGamemode = currentGamemode;
- }
- }
-
- public static void saveToFile() {
- File configDir = NotEnoughUpdates.INSTANCE.manager.configLocation;
- File gamemodeFile = new File(
- configDir,
- "gamemodes/gamemodes-" + Minecraft.getMinecraft().thePlayer.getUniqueID().toString() + ".json"
- );
- gamemodeFile.getParentFile().mkdirs();
-
- try {
- gamemodeFile.createNewFile();
-
- try (
- BufferedWriter writer = new BufferedWriter(
- new OutputStreamWriter(new FileOutputStream(gamemodeFile), StandardCharsets.UTF_8))
- ) {
- JsonObject obj = new JsonObject();
- writer.write(encrypt(gson.toJson(new GamemodeWrapper(currentGamemode), GamemodeWrapper.class)));
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public static Key getKeyFromPlayerUUID() {
- byte[] bytes = ByteBuffer.allocate(2 * Long.SIZE / Byte.SIZE)
- .putLong(Minecraft.getMinecraft().thePlayer.getUniqueID().getLeastSignificantBits())
- .putLong(Minecraft.getMinecraft().thePlayer.getUniqueID().getMostSignificantBits())
- .array();
- SecretKeySpec key = new SecretKeySpec(bytes, "AES");
-
- return key;
- }
-
- public static String encrypt(String value) {
- try {
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.ENCRYPT_MODE, getKeyFromPlayerUUID());
- String encrypt = Base64.getEncoder().encodeToString(cipher.doFinal(value.getBytes()));
- return encrypt;
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- public static String decrypt(String encrypted) {
- try {
- Cipher cipher = Cipher.getInstance("AES");
- cipher.init(Cipher.DECRYPT_MODE, getKeyFromPlayerUUID());
- byte[] b64Decoded = Base64.getDecoder().decode(encrypted);
- byte[] bytes = cipher.doFinal(b64Decoded);
-
- return new String(bytes);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
-
- public static void setGamemode(Gamemode gamemode) {
- String currentProfile = NotEnoughUpdates.INSTANCE.manager.getCurrentProfile();
-
- if (currentProfile == null || currentProfile.isEmpty()) return;
-
- currentGamemode.put(currentProfile, gamemode);
- }
-
- @SubscribeEvent
- public void onPlayerInteract(PlayerInteractEvent event) {
- if (getGamemode() == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return;
-
- if (!"Your Island".equals(SBInfo.getInstance().location)) return;
-
- if ((getGamemode().gamemodeModifiers & MODIFIER_SMALLISLAND) != 0) {
- if (event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK) {
- if (Math.abs(event.pos.getX()) > 40 || Math.abs(event.pos.getZ()) > 40) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[NPC] Builder" +
- EnumChatFormatting.WHITE + ": Sorry, " + Minecraft.getMinecraft().thePlayer.getName() +
- ", due to budget cuts your skyblock island is now only 80 blocks wide."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.AQUA + "(Use " + EnumChatFormatting.YELLOW + "/neugamemodes" +
- EnumChatFormatting.AQUA + " if you would like to build further out)"));
-
- event.setCanceled(true);
- }
- }
- }
- }
-
- @SubscribeEvent
- public void onTick(TickEvent.ClientTickEvent event) {
- if (event.phase != TickEvent.Phase.START) return;
-
- if (getGamemode() == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return;
-
- boolean inDungeons = SBInfo.getInstance().getLocation() != null && SBInfo.getInstance().getLocation().equals(
- "dungeon");
-
- getGamemode().locked = !(EnumChatFormatting.YELLOW + "Break a log").equals(SBInfo.getInstance().objective);
-
- IronmanMode ironmanMode = getGamemode().ironmanMode;
- GuiScreen gui = Minecraft.getMinecraft().currentScreen;
- if (gui instanceof GuiChest) {
- GuiChest eventGui = (GuiChest) gui;
- ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
- String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
-
- if (containerName.equals("Bank") && (getGamemode().gamemodeModifiers & MODIFIER_NOBANK) != 0) {
- Minecraft.getMinecraft().thePlayer.closeScreen();
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[NPC] Banker" +
- EnumChatFormatting.WHITE + ": Hi, " + Minecraft.getMinecraft().thePlayer.getName() +
- ", you would like to create an account and make a deposit?"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[NPC] Banker" +
- EnumChatFormatting.WHITE + ": Alright, I've invested your money into ..."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[" +
- EnumChatFormatting.WHITE + "YouTube" + EnumChatFormatting.RED + "] Nullzee" +
- EnumChatFormatting.WHITE + ": Hows it going everyone, welcome to my ultimate bazaar flipping guide ..."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[NPC] Banker" +
- EnumChatFormatting.WHITE +
- ": Hmm, it seems as though the economy has crashed. All your money is gone. Poof. Vanished."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[IDIOT] You" +
- EnumChatFormatting.WHITE + ": ... never again ..."));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.AQUA + "(Use " + EnumChatFormatting.YELLOW + "/neugamemodes" +
- EnumChatFormatting.AQUA + " if you would like to use the bank)"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- } else if (containerName.equals("Fairy") && (getGamemode().gamemodeModifiers & MODIFIER_DEVILISH) != 0) {
- Minecraft.getMinecraft().thePlayer.closeScreen();
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[NPC] " + EnumChatFormatting.LIGHT_PURPLE + "Tia the Fairy" +
- EnumChatFormatting.WHITE + ": Oh no, " + Minecraft.getMinecraft().thePlayer.getName() +
- ", you have sold your soul to the devil... please go away!"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.AQUA + "(Use " + EnumChatFormatting.YELLOW + "/neugamemodes" +
- EnumChatFormatting.AQUA + " if you would like to use fairy souls)"));
- } else if (!inDungeons && ironmanMode.isBanned(containerName)) {
- Minecraft.getMinecraft().thePlayer.closeScreen();
-
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.AQUA + "You cannot access this inventory/menu because of your"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- " " + ironmanMode.display + EnumChatFormatting.AQUA + " status!"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.AQUA + "(Use " + EnumChatFormatting.YELLOW + "/neugamemodes" +
- EnumChatFormatting.AQUA + " if you would like to downgrade the status)"));
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
- }
- }
- }
-
- @SubscribeEvent
- public void onChatMessage(ClientChatReceivedEvent event) {
- if (event.type != 0) return;
-
- /*if(Keyboard.isKeyDown(Keyboard.KEY_K)) {
- boolean has = false;
- for(char c : event.message.getFormattedText().toCharArray()) {
- if((int)c > 200) {
- if(!has) System.out.println("-----START");
- has = true;
- System.out.println((int)c);
- }
- }
- if(has) System.out.println("-----END");
- }*/
- if (getGamemode() == null || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return;
-
- String message = event.message.getFormattedText();
- if (message.contains("\u2620")) { //Death symbol ( ☠ )
- HardcoreMode hardcoreMode = getGamemode().hardcoreMode;
- if (hardcoreMode != HardcoreMode.NORMAL) {
- if (hardcoreMode.isExemption(message)) {
- lastDeathExemption = System.currentTimeMillis();
- }
- }
- }
-
- if (System.currentTimeMillis() - lastDeathExemption > 1000 &&
- message.contains("!") && message.startsWith(
- EnumChatFormatting.RESET.toString() + EnumChatFormatting.RED + "You died")) {
- if (getGamemode().hardcoreMode != HardcoreMode.NORMAL) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.RED.toString() + EnumChatFormatting.OBFUSCATED + "AAA" +
- EnumChatFormatting.RED + " You have lost your " +
- getGamemode().hardcoreMode.display + EnumChatFormatting.RED + " status! " +
- EnumChatFormatting.RED + EnumChatFormatting.OBFUSCATED + "AAA"));
- getGamemode().hardcoreMode = HardcoreMode.NORMAL;
- }
- }
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java
deleted file mode 100644
index bbdbabd2..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/CollectionLogInfoPane.java
+++ /dev/null
@@ -1,534 +0,0 @@
-package io.github.moulberry.notenoughupdates.infopanes;
-
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NEUManager;
-import io.github.moulberry.notenoughupdates.NEUOverlay;
-import io.github.moulberry.notenoughupdates.util.NEUResourceManager;
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.client.shader.Framebuffer;
-import net.minecraft.client.shader.Shader;
-import net.minecraft.item.ItemStack;
-import net.minecraft.util.EnumChatFormatting;
-import org.lwjgl.input.Mouse;
-import org.lwjgl.opengl.GL11;
-
-import java.awt.*;
-import java.util.List;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.item_mask;
-
-public class CollectionLogInfoPane extends ScrollableInfoPane {
- private final String mobRegex = ".*?((_MONSTER)|(_ANIMAL)|(_MINIBOSS)|(_BOSS)|(_SC))$";
- private final String petRegex = ".*?;[0-4]$";
-
- TreeSet<String> items = new TreeSet<>(getItemComparator());
-
- private int buttonHover = -1;
-
- private int previousAcquiredCount = 0;
- private int previousScroll = 0;
- private int previousX = 0;
- private int previousFilter = 0;
-
- private final long lastUpdate = 0;
-
- private static final int FILTER_ALL = 0;
- private static final int FILTER_WEAPON = 1;
- private static final int FILTER_ARMOR = 2;
- private static final int FILTER_ACCESSORY = 3;
- private static final int FILTER_PET = 4;
- private static final int FILTER_DUNGEON = 5;
- private static final int FILTER_SLAYER_ZOMBIE = 6;
- private static final int FILTER_SLAYER_WOLF = 7;
- private static final int FILTER_SLAYER_SPIDER = 8;
- private int filterMode = FILTER_ALL;
- private final String[] filterPrettyNames = new String[]{
- "ALL", "WEAPON", "ARMOR",
- "ACCESSORY", "PET", "DUNGEON", "ZOMBIE SLAYER", "WOLF SLAYER", "SPIDER SLAYER"
- };
-
- private Framebuffer itemFramebuffer = null;
- private Framebuffer itemBGFramebuffer = null;
- private Framebuffer itemFramebufferGrayscale = null;
- private Shader grayscaleShader = null;
-
- private final int updateCounter = 0;
-
- public CollectionLogInfoPane(NEUOverlay overlay, NEUManager manager) {
- super(overlay, manager);
- refreshItems();
- }
-
- private boolean loreContains(JsonArray lore, String str) {
- for (int i = 0; i < lore.size(); i++) {
- String line = lore.get(i).getAsString();
- if (line.contains(str)) return true;
- }
- return false;
- }
-
- private void refreshItems() {
- items.clear();
- for (String internalname : manager.getItemInformation().keySet()) {
- if (!manager.auctionManager.isVanillaItem(internalname) && !internalname.matches(mobRegex)) {
- JsonObject item = manager.getItemInformation().get(internalname);
- JsonArray lore = manager.getItemInformation().get(internalname).get("lore").getAsJsonArray();
- switch (filterMode) {
- case FILTER_WEAPON:
- if (overlay.checkItemType(lore, "SWORD", "BOW", "WAND") < 0) continue;
- break;
- case FILTER_ARMOR:
- if (overlay.checkItemType(lore, "HELMET", "CHESTPLATE", "LEGGINGS", "BOOTS") < 0) continue;
- break;
- case FILTER_ACCESSORY:
- if (overlay.checkItemType(lore, "ACCESSORY") < 0) continue;
- break;
- case FILTER_PET:
- if (!internalname.matches(petRegex) || !item.get("displayname").getAsString().contains("["))
- continue;
- break;
- case FILTER_DUNGEON:
- if (Utils.checkItemType(lore, true, "DUNGEON") < 0) continue;
- break;
- case FILTER_SLAYER_ZOMBIE:
- if (!item.has("slayer_req") || !item.get("slayer_req").getAsString().startsWith("ZOMBIE"))
- continue;
- break;
- case FILTER_SLAYER_WOLF:
- if (!item.has("slayer_req") || !item.get("slayer_req").getAsString().startsWith("WOLF"))
- continue;
- break;
- case FILTER_SLAYER_SPIDER:
- if (!item.has("slayer_req") || !item.get("slayer_req").getAsString().startsWith("SPIDER"))
- continue;
- break;
- }
- items.add(internalname);
- }
- }
- }
-
- private Map<String, ArrayList<String>> getAcquiredItems() {
- return null;//manager.config.collectionLog.value;
- }
-
- private Comparator<String> getItemComparator() {
- return (o1, o2) -> {
- float cost1 = manager.auctionManager.getLowestBin(o1);
- float cost2 = manager.auctionManager.getLowestBin(o2);
-
- if (cost1 == -1) cost1 = manager.auctionManager.getCraftCost(o1).craftCost;
- if (cost2 == -1) cost2 = manager.auctionManager.getCraftCost(o2).craftCost;
-
- if (cost1 < cost2) return 1;
- if (cost1 > cost2) return -1;
-
- return o1.compareTo(o2);
- };
- }
-
- public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) {
- super.mouseInput(width, height, mouseX, mouseY, mouseDown);
- if (mouseDown) {
- if (buttonHover == 0) {
- if (Mouse.getEventButton() == 0) {
- filterMode++;
- if (filterMode >= filterPrettyNames.length) {
- filterMode = 0;
- }
- } else if (Mouse.getEventButton() == 1) {
- filterMode--;
- if (filterMode < 0) {
- filterMode = filterPrettyNames.length - 1;
- }
- }
- }
- refreshItems();
- }
- }
-
- public void render(
- int width,
- int height,
- Color bg,
- Color fg,
- ScaledResolution scaledresolution,
- int mouseX,
- int mouseY
- ) {
- int paneWidth = (int) (width / 3 * overlay.getWidthMult());
- int rightSide = (int) (width * overlay.getInfoPaneOffsetFactor());
- int leftSide = rightSide - paneWidth;
- int padding = overlay.getBoxPadding();
-
- renderDefaultBackground(width, height, bg);
-
- renderControls(height, padding, leftSide + padding, rightSide - padding, 20, fg);
- renderCollectionLog(fg, width, height, leftSide + padding, rightSide - padding, padding + 25, height - padding);
- }
-
- private float getCompletedness() {
- int total = items.size();
- int own = 0;
- for (String item : items) {
- if (getAcquiredItems() != null &&
- getAcquiredItems().containsKey(manager.getCurrentProfile()) &&
- getAcquiredItems().get(manager.getCurrentProfile()).contains(item)) {
- own++;
- }
-
- }
- return own / (float) total;
- }
-
- private final EnumChatFormatting[] rainbow = new EnumChatFormatting[]{
- EnumChatFormatting.RED,
- EnumChatFormatting.GOLD,
- EnumChatFormatting.YELLOW,
- EnumChatFormatting.GREEN,
- EnumChatFormatting.AQUA,
- EnumChatFormatting.LIGHT_PURPLE,
- EnumChatFormatting.DARK_PURPLE
- };
-
- private String getCompletednessString() {
- float completedness = getCompletedness();
- String text = (int) (completedness * 100) + "% Complete";
- if (completedness >= 1) {
- StringBuilder rainbowText = new StringBuilder();
- for (int i = 0; i < text.length(); i++) {
- char c = text.charAt(i);
- int index = (int) (i - System.currentTimeMillis() / 100) % rainbow.length;
- if (index < 0) index += rainbow.length;
- rainbowText.append(rainbow[index]).append(c);
- }
- text = rainbowText.toString();
- }
- return text;
- }
-
- private void renderControls(int height, int top, int left, int right, int ySize, Color fg) {
- ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
-
- int mouseX = Mouse.getX() / scaledresolution.getScaleFactor();
- int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor();
-
- buttonHover = -1;
-
- int totalAvailable = right - left;
- int controlPadding = 3;
- String[] controls = new String[]{
- "Filter: " + filterPrettyNames[filterMode],
- getCompletednessString()
- };
- int numControls = controls.length;
- int available = totalAvailable - (numControls - 1) * controlPadding;
- int controlSize = available / numControls;
- int extraPadding = (available % controlSize) / 2;
-
- for (int i = 0; i < numControls; i++) {
- int width = controlSize + controlPadding;
- int x = left + extraPadding + i * width;
-
- if (mouseX > x && mouseX < x + controlSize) {
- if (mouseY > top && mouseY < top + ySize) {
- buttonHover = i;
- }
- }
-
- drawRect(x, top, x + controlSize, top + ySize,
- new Color(177, 177, 177).getRGB()
- );
- drawRect(x + 1, top + 1, x + controlSize, top + ySize,
- new Color(50, 50, 50).getRGB()
- );
- drawRect(x + 1, top + 1, x + controlSize - 1, top + ySize - 1, fg.getRGB());
- Utils.drawStringCenteredScaledMaxWidth(controls[i], Minecraft.getMinecraft().fontRendererObj,
- x + width / 2f, top + ySize / 2f, true, controlSize - 4, Color.WHITE.getRGB()
- );
- }
- }
-
- public int getCurrentAcquiredCount() {
- if (getAcquiredItems() == null) return 0;
- if (!getAcquiredItems().containsKey(manager.getCurrentProfile())) return 0;
- return getAcquiredItems().get(manager.getCurrentProfile()).size();
- }
-
- private void renderCollectionLog(Color fg, int width, int height, int left, int right, int top, int bottom) {
- ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
-
- int mouseX = Mouse.getX() / scaledresolution.getScaleFactor();
- int mouseY = height - Mouse.getY() / scaledresolution.getScaleFactor();
-
- if (itemFramebuffer != null && grayscaleShader != null &&
- (itemFramebuffer.framebufferWidth != width || itemFramebuffer.framebufferHeight != height)) {
- grayscaleShader.setProjectionMatrix(Utils.createProjectionMatrix(
- width * scaledresolution.getScaleFactor(), height * scaledresolution.getScaleFactor()));
- }
-
- itemFramebuffer = checkFramebufferSizes(itemFramebuffer, width, height,
- scaledresolution.getScaleFactor()
- );
- itemBGFramebuffer = checkFramebufferSizes(itemBGFramebuffer, width, height,
- scaledresolution.getScaleFactor()
- );
- itemFramebufferGrayscale = checkFramebufferSizes(itemFramebufferGrayscale, width, height,
- scaledresolution.getScaleFactor()
- );
-
- /*if(!manager.config.cacheRenderedItempane.value || previousAcquiredCount != getCurrentAcquiredCount() ||
- previousScroll != scrollHeight.getValue() || previousX != left || previousFilter != filterMode ||
- System.currentTimeMillis() - lastUpdate > 5000) {
- lastUpdate = System.currentTimeMillis();
- renderItemsToImage(itemFramebuffer, fg, left+5, right, top+1, bottom);
- renderItemBGToImage(itemBGFramebuffer, fg, left+5, right, top+1, bottom);
- }*/
- previousAcquiredCount = getCurrentAcquiredCount();
- previousScroll = scrollHeight.getValue();
- previousX = left;
- previousFilter = filterMode;
-
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
- renderFromImage(itemBGFramebuffer, width, height, left, right, top, bottom);
- renderFromImage(itemFramebuffer, width, height, left, right, top, bottom);
-
- if (grayscaleShader == null) {
- try {
- grayscaleShader = new Shader(new NEUResourceManager(Minecraft.getMinecraft().getResourceManager()),
- "grayscale",
- itemFramebuffer, itemFramebufferGrayscale
- );
- grayscaleShader.setProjectionMatrix(Utils.createProjectionMatrix(
- width * scaledresolution.getScaleFactor(), height * scaledresolution.getScaleFactor()));
- } catch (Exception e) {
- return;
- }
- }
-
- GL11.glPushMatrix();
- grayscaleShader.loadShader(0);
- GlStateManager.enableDepth();
- GL11.glPopMatrix();
-
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
-
- itemFramebufferGrayscale.bindFramebufferTexture();
-
- AtomicReference<ItemStack> tooltipToDisplay = new AtomicReference<>(null);
-
- AtomicBoolean isTop = new AtomicBoolean(false);
- AtomicInteger lowestY = new AtomicInteger(-1);
-
- String[] items = getItemList();
- GlStateManager.color(1f, 1f, 1f, 1f);
- iterateItemSlots(new ItemSlotConsumer() {
- @Override
- public void consume(int x, int y, int id) {
- if (id < items.length) {
- String internalname = items[id];
- if (id == 0) isTop.set(true);
-
- int leftI = x - 1;
- int rightI = x + 17;
- int topI = y - 1;
- int bottomI = y + 17;
-
- lowestY.set(Math.max(bottomI, lowestY.get()));
-
- if (mouseX > leftI && mouseX < rightI) {
- if (mouseY > topI && mouseY < bottomI) {
- tooltipToDisplay.set(manager.jsonToStack(manager.getItemInformation().get(internalname), true));
- }
- }
-
- if (getAcquiredItems() != null &&
- getAcquiredItems().containsKey(manager.getCurrentProfile()) &&
- getAcquiredItems().get(manager.getCurrentProfile()).contains(internalname)) {
- return;
- }
-
- topI = Math.max(topI, top);
- bottomI = Math.min(bottomI, bottom);
-
- Utils.drawTexturedRect(leftI, topI, rightI - leftI, bottomI - topI,
- leftI / (float) width, rightI / (float) width,
- (height - topI) / (float) height, (height - bottomI) / (float) height
- );
- }
- }
- }, left + 5, right, top + 1, bottom);
-
- if (!isTop.get()) {
- if (lowestY.get() == -1) {
- scrollHeight.setValue(0);
- } else {
- int dist = bottom - lowestY.get() - 10;
- if (dist > 0) {
- scrollHeight.setValue(scrollHeight.getValue() - dist);
- }
- }
- }
-
- itemFramebufferGrayscale.unbindFramebufferTexture();
-
- ItemStack displayStack = tooltipToDisplay.get();
- if (displayStack != null) {
- List<String> text = displayStack.getTooltip(Minecraft.getMinecraft().thePlayer, true);
- Utils.drawHoveringText(text, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
- }
- }
-
- private String[] getItemList() {
- String[] items_arr = new String[items.size()];
- int i = 0;
- for (String internalname : items) {
- items_arr[i++] = internalname;
- }
- return items_arr;
- }
-
- private int limCol(int col) {
- return Math.min(255, Math.max(0, col));
- }
-
- private void renderItems(int left, int right, int top, int bottom) {
- String[] items = getItemList();
- iterateItemSlots(new ItemSlotConsumer() {
- public void consume(int x, int y, int id) {
- if (id < items.length) {
- String internalname = items[id];
-
- ItemStack stack = manager.jsonToStack(manager.getItemInformation().get(internalname));
- Utils.drawItemStack(stack, x, y);
- }
- }
- }, left, right, top, bottom);
- }
-
- private void renderItemBackgrounds(Color fg, int left, int right, int top, int bottom) {
- Color fgCustomOpacity =
- null;//new Color(SpecialColour.specialToChromaRGB(manager.config.itemBackgroundColour.value), true);
- Color fgGold = null;//new Color(SpecialColour.specialToChromaRGB(manager.config.itemFavouriteColour.value), true);
-
- String[] items = getItemList();
- iterateItemSlots(new ItemSlotConsumer() {
- public void consume(int x, int y, int id) {
- if (id < items.length) {
- String internalname = items[id];
-
- Color color = fgCustomOpacity;
- if (getAcquiredItems() != null &&
- getAcquiredItems().containsKey(manager.getCurrentProfile()) &&
- getAcquiredItems().get(manager.getCurrentProfile()).contains(internalname)) {
- color = fgGold;
- }
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(item_mask);
- /*if(manager.config.itemStyle.value) {
- GlStateManager.color(color.getRed() / 255f, color.getGreen() / 255f,
- color.getBlue() / 255f, color.getAlpha() / 255f);
- Utils.drawTexturedRect(x - 1, y - 1, overlay.ITEM_SIZE + 2, overlay.ITEM_SIZE + 2, GL11.GL_NEAREST);
- } else {
- drawRect(x-1, y-1, x+overlay.ITEM_SIZE+1, y+overlay.ITEM_SIZE+1, color.getRGB());
- }*/
- GlStateManager.bindTexture(0);
- }
- }
- }, left, right, top, bottom);
- }
-
- /**
- * Checks whether the screen size has changed, if so it reconstructs the itemPane framebuffer and marks that the
- * itemPane should be redrawn.
- */
- private Framebuffer checkFramebufferSizes(Framebuffer framebuffer, int width, int height, int scaleFactor) {
- int sw = width * scaleFactor;
- int sh = height * scaleFactor;
-
- if (framebuffer == null || framebuffer.framebufferWidth != sw || framebuffer.framebufferHeight != sh) {
- if (framebuffer == null) {
- framebuffer = new Framebuffer(sw, sh, true);
- } else {
- framebuffer.createBindFramebuffer(sw, sh);
- }
- framebuffer.setFramebufferFilter(GL11.GL_NEAREST);
- }
- return framebuffer;
- }
-
- private void renderItemsToImage(Framebuffer framebuffer, Color fg, int left, int right, int top, int bottom) {
- GL11.glPushMatrix();
- framebuffer.framebufferClear();
- framebuffer.bindFramebuffer(false);
-
- renderItems(left, right, top, bottom);
-
- framebuffer.unbindFramebuffer();
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
- GL11.glPopMatrix();
- }
-
- private void renderItemBGToImage(Framebuffer framebuffer, Color fg, int left, int right, int top, int bottom) {
- GL11.glPushMatrix();
- framebuffer.framebufferClear();
- framebuffer.bindFramebuffer(false);
-
- renderItemBackgrounds(fg, left, right, top, bottom);
-
- framebuffer.unbindFramebuffer();
- Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(true);
- GL11.glPopMatrix();
- }
-
- private void renderFromImage(
- Framebuffer framebuffer,
- int width,
- int height,
- int left,
- int right,
- int top,
- int bottom
- ) {
- framebuffer.bindFramebufferTexture();
- GlStateManager.color(1f, 1f, 1f, 1f);
- Utils.drawTexturedRect(left, top, right - left, bottom - top,
- left / (float) width, right / (float) width,
- (height - top) / (float) height, (height - bottom) / (float) height
- );
- framebuffer.unbindFramebufferTexture();
- }
-
- private abstract static class ItemSlotConsumer {
- public abstract void consume(int x, int y, int id);
- }
-
- public void iterateItemSlots(ItemSlotConsumer itemSlotConsumer, int left, int right, int top, int bottom) {
- int scrolledTop = top - scrollHeight.getValue();
-
- int id = 0;
- int extraSize = NEUOverlay.ITEM_SIZE + NEUOverlay.ITEM_PADDING;
- for (int y = scrolledTop; y < bottom; y += extraSize) {
- for (int x = left; x < right - extraSize; x += extraSize) {
- if (y > top - extraSize) {
- itemSlotConsumer.consume(x, y, id);
- }
- if (++id >= items.size()) {
- return;
- }
- }
- }
- }
-
- public boolean keyboardInput() {
- return false;
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java
index 945dd71c..0b1963d6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/DevInfoPane.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.infopanes;
import com.google.gson.JsonObject;
@@ -62,6 +81,7 @@ public class DevInfoPane extends TextInfoPane {
for (String internalname : manager.auctionManager.getItemAuctionInfoKeySet()) {
if (internalname.matches("^.*-[0-9]{1,3}$")) continue;
if (!manager.getItemInformation().containsKey(internalname)) {
+ if (internalname.equals("RUNE") || internalname.contains("PARTY_HAT_CRAB")) continue;
text += internalname + "\n";
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/FlipperInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/FlipperInfoPane.java
index 441bf735..4b6c73f4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/FlipperInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/FlipperInfoPane.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.infopanes;
import io.github.moulberry.notenoughupdates.NEUManager;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java
index baf88457..de9c608f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/HTMLInfoPane.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.infopanes;
import info.bliki.htmlcleaner.TagNode;
@@ -14,6 +33,7 @@ import io.github.moulberry.notenoughupdates.util.AllowEmptyHTMLTag;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.DynamicTexture;
@@ -25,15 +45,26 @@ import org.apache.commons.lang3.SystemUtils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
public class HTMLInfoPane extends TextInfoPane {
private static final WikiModel wikiModel;
@@ -47,6 +78,10 @@ public class HTMLInfoPane extends TextInfoPane {
private int imageHeight = 0;
private int imageWidth = 0;
+ private float xMin = 0;
+ private int mouseOffset = 0;
+ private boolean selected = false;
+
private static boolean hasAttemptedDownload = false;
/*
@@ -61,6 +96,16 @@ public class HTMLInfoPane extends TextInfoPane {
conf.addTokenTag("infobox", new IgnoreTag("infobox"));
conf.addTokenTag("tabber", new IgnoreTag("tabber"));
conf.addTokenTag("kbd", new HTMLTag("kbd"));
+ conf.addTokenTag("td", new AllowEmptyHTMLTag("td"));
+ conf.addTokenTag("tbody", new AllowEmptyHTMLTag("tbody"));
+ conf.addTokenTag("style", new AllowEmptyHTMLTag("style"));
+ conf.addTokenTag("article", new AllowEmptyHTMLTag("article"));
+ conf.addTokenTag("section", new AllowEmptyHTMLTag("section"));
+ conf.addTokenTag("link", new AllowEmptyHTMLTag("link"));
+ conf.addTokenTag("wbr", new AllowEmptyHTMLTag("wbr"));
+ conf.addTokenTag("dl", new AllowEmptyHTMLTag("dl"));
+ conf.addTokenTag("dd", new AllowEmptyHTMLTag("dd"));
+ conf.addTokenTag("dt", new AllowEmptyHTMLTag("dt"));
wikiModel = new WikiModel(conf, "https://hypixel-skyblock.fandom.com/wiki/Special:Filepath/${image}",
"https://hypixel-skyblock.fandom.com/wiki/${title}"
) {
@@ -101,7 +146,7 @@ public class HTMLInfoPane extends TextInfoPane {
) {
return manager.getWebFile(wikiUrl).thenApply(f -> {
if (f == null) {
- return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl);
+ return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl, false);
}
StringBuilder sb = new StringBuilder();
@@ -114,9 +159,16 @@ public class HTMLInfoPane extends TextInfoPane {
sb.append(l).append("\n");
}
} catch (IOException e) {
- return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl);
+ return new HTMLInfoPane(overlay, manager, "error", "error", "Failed to load wiki url: " + wikiUrl, false);
}
- return createFromWikiText(overlay, manager, name, f.getName(), sb.toString());
+ return createFromWikiText(
+ overlay,
+ manager,
+ name,
+ f.getName(),
+ sb.toString(),
+ wikiUrl.startsWith("https://wiki.hypixel.net/")
+ );
});
}
@@ -126,30 +178,55 @@ public class HTMLInfoPane extends TextInfoPane {
* a more permanent solution that can be abstracted to work with arbitrary wiki codes (eg. moulberry.github.io/
* files/neu_help.html).
*/
+
+ private static final Pattern replacePattern = Pattern.compile(
+ "<nav class=\"page-actions-menu\">.*</nav>|",
+ Pattern.DOTALL
+ );
+
public static HTMLInfoPane createFromWikiText(
NEUOverlay overlay, NEUManager manager, String name, String filename,
- String wiki
+ String wiki, boolean isOfficialWiki
) {
- String[] split = wiki.split("</infobox>");
- wiki = split[split.length - 1]; //Remove everything before infobox
- wiki = wiki.split("<span class=\"navbox-vde\">")[0]; //Remove navbox
- wiki = wiki.split("<table class=\"navbox mw-collapsible\"")[0];
- wiki = "__NOTOC__\n" + wiki; //Remove TOC
+ if (isOfficialWiki) {
+ wiki = wiki.split("<main id=\"content\" class=\"mw-body\">")[1].split("</main>")[0]; // hide top bar
+ wiki = wiki.split("<div class=\"container-navbox\">")[0]; // hide giant bottom list
+ wiki = wiki.split("<div class=\"categoryboxcontainer\">")[0]; // hide small bottom category thing
+ wiki = replacePattern.matcher(wiki).replaceAll("");
+ wiki = wiki.replaceAll(
+ "<div id=\"siteNotice\"></div><div id=\"mw-dismissablenotice-anonplace\"></div><script>.*</script>",
+ ""
+ ); // hide beta box
+ wiki = wiki.replaceAll("<h1 id=\"section_0\">.*</h1>", ""); // hide title
+ wiki = wiki.replace("src=\"/", "src=\"https://wiki.hypixel.net/");
+ wiki = wiki.replace("\uD83D\uDDF8", "✓"); // replace checkmark with one that renders
+ wiki = wiki.replace("\uD83E\uDC10", "\u27F5"); // replace left arrow with one that renders
+ wiki = wiki.replace("\uD83E\uDC12", "\u27F6"); // replace right arrow with one that renders
+ } else {
+ String[] split = wiki.split("</infobox>");
+ wiki = split[split.length - 1]; //Remove everything before infobox
+ wiki = wiki.split("<span class=\"navbox-vde\">")[0]; //Remove navbox
+ wiki = wiki.split("<table class=\"navbox mw-collapsible\"")[0];
+ wiki = "__NOTOC__\n" + wiki; //Remove TOC
+ }
try (PrintWriter out = new PrintWriter(new File(manager.configLocation, "debug/parsed.txt"))) {
out.println(wiki);
} catch (IOException ignored) {
}
String html;
try {
- html = wikiModel.render(wiki);
- } catch (IOException e) {
- return new HTMLInfoPane(overlay, manager, "error", "error", "Could not render wiki.");
+ if (isOfficialWiki)
+ html = wiki;
+ else
+ html = wikiModel.render(wiki);
+ } catch (Exception e) {
+ return new HTMLInfoPane(overlay, manager, "error", "error", "Could not render wiki.", false);
}
try (PrintWriter out = new PrintWriter(new File(manager.configLocation, "debug/html.txt"))) {
out.println(html);
} catch (IOException ignored) {
}
- return new HTMLInfoPane(overlay, manager, name, filename, html);
+ return new HTMLInfoPane(overlay, manager, name, filename, html, isOfficialWiki);
}
private String spaceEscape(String str) {
@@ -164,7 +241,14 @@ public class HTMLInfoPane extends TextInfoPane {
* generation is done asynchronously as sometimes it can take up to 10 seconds for more
* complex webpages.
*/
- public HTMLInfoPane(NEUOverlay overlay, NEUManager manager, String name, String filename, String html) {
+ public HTMLInfoPane(
+ NEUOverlay overlay,
+ NEUManager manager,
+ String name,
+ String filename,
+ String html,
+ boolean isOfficial
+ ) {
super(overlay, manager, name, "");
this.title = name;
@@ -180,7 +264,7 @@ public class HTMLInfoPane extends TextInfoPane {
return;
}
- File cssFile = new File(manager.configLocation, "wikia.css");
+ File cssFile = new File(manager.configLocation, isOfficial ? "official-wiki.css" : "wikia.css");
File wkHtmlToImage = new File(manager.configLocation, "wkhtmltox-" + osId + "/bin/wkhtmltoimage");
//Use old binary folder
@@ -235,13 +319,20 @@ public class HTMLInfoPane extends TextInfoPane {
return;
}
+ if (!cssFile.exists() && isOfficial) {
+ try {
+ Files.copy(this.getClass().getResourceAsStream("/assets/notenoughupdates/official-wiki.css"), cssFile.toPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ }
+
File input = new File(manager.configLocation, "tmp/input.html");
String outputFileName = filename.replaceAll("(?i)\\u00A7.", "")
.replaceAll("[^a-zA-Z0-9_\\-]", "_");
File output = new File(manager.configLocation, "tmp/" +
outputFileName + ".png");
- File outputExt = new File(manager.configLocation, "tmp/" +
- outputFileName + "_ext.png");
input.deleteOnExit();
output.deleteOnExit();
@@ -412,12 +503,23 @@ public class HTMLInfoPane extends TextInfoPane {
}
int yScroll = scrollHeight.getValue();
+ float xSize = Math.min((paneWidth - overlay.getBoxPadding() * 2f) / imageWidth * scaleF, 1);
+ float xMax = xMin + xSize;
+
float vMin = yScroll / (imageHeight / scaleF);
float vMax = (yScroll + height - overlay.getBoxPadding() * 3) / (imageHeight / scaleF);
Utils.drawTexturedRect(leftSide + overlay.getBoxPadding(), overlay.getBoxPadding() * 2, imageW,
- height - overlay.getBoxPadding() * 3,
- 0, 1, vMin, vMax
+ (height - overlay.getBoxPadding() * 3),
+ xMin, xMax, vMin, vMax
);
+ if (xSize < 1) {
+ int barX = (int) (xMin * imageW) + leftSide + overlay.getBoxPadding();
+ int barY = height - overlay.getBoxPadding() - 10;
+ int barWidth = (int) (xMax * imageW) + leftSide + overlay.getBoxPadding();
+ int barHeight = height - overlay.getBoxPadding() - 5;
+ boolean isHovered = mouseX >= barX && mouseX <= barWidth && mouseY >= barY && mouseY <= barHeight || selected;
+ Gui.drawRect(barX, barY, barWidth, barHeight, new Color(255, 255, 255, isHovered ? 150 : 100).getRGB());
+ }
} else {
scrollHeight.setValue(0);
@@ -435,6 +537,27 @@ public class HTMLInfoPane extends TextInfoPane {
@Override
public void mouseInput(int width, int height, int mouseX, int mouseY, boolean mouseDown) {
+ int paneWidth = (int) (width / 3 * overlay.getWidthMult());
+ int rightSide = (int) (width * overlay.getInfoPaneOffsetFactor());
+ int leftSide = rightSide - paneWidth;
+ int imageW = paneWidth - overlay.getBoxPadding() * 2;
+ float scaleF = IMAGE_WIDTH * ZOOM_FACTOR / (float) imageW;
+ float xSize = Math.min((paneWidth - overlay.getBoxPadding() * 2f) / imageWidth * scaleF, 1);
+ float xMax = xMin + xSize;
+ int barX = (int) (xMin * imageW) + leftSide + overlay.getBoxPadding();
+ int barY = height - overlay.getBoxPadding() - 10;
+ int barWidth = (int) (xMax * imageW) + leftSide + overlay.getBoxPadding();
+ int barHeight = height - overlay.getBoxPadding() - 5;
+ if (!mouseDown)
+ selected = false;
+ if (mouseX >= barX && mouseX <= barWidth && mouseY >= barY && mouseY <= barHeight && mouseDown || selected) {
+ if (!selected)
+ mouseOffset = mouseX - barX;
+ xMin = (mouseX - leftSide - overlay.getBoxPadding() / 2f - mouseOffset) / imageWidth * scaleF;
+ xMin = Math.max(0, xMin);
+ xMin = Math.min(xMin, 1 - xSize);
+ selected = true;
+ }
super.mouseInput(width, height, mouseX, mouseY, mouseDown);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java
index 70d7d65b..5f73e57a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/InfoPane.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.infopanes;
import io.github.moulberry.notenoughupdates.NEUManager;
@@ -61,10 +80,10 @@ public abstract class InfoPane extends Gui {
return HTMLInfoPane.createFromWikiUrl(overlay, manager, name, infoText);
case "WIKI":
return CompletableFuture.completedFuture(
- HTMLInfoPane.createFromWikiText(overlay, manager, name, internalName, infoText));
+ HTMLInfoPane.createFromWikiText(overlay, manager, name, internalName, infoText, false));
case "HTML":
return CompletableFuture.completedFuture(
- new HTMLInfoPane(overlay, manager, name, internalName, infoText));
+ new HTMLInfoPane(overlay, manager, name, internalName, infoText, false));
default:
return CompletableFuture.completedFuture(
new TextInfoPane(overlay, manager, name, infoText));
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/ScrollableInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/ScrollableInfoPane.java
index 75b66770..9bc47fc5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/ScrollableInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/ScrollableInfoPane.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.infopanes;
import io.github.moulberry.notenoughupdates.NEUManager;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/TextInfoPane.java b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/TextInfoPane.java
index 77d47a3d..90bed1fa 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/infopanes/TextInfoPane.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/infopanes/TextInfoPane.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.infopanes;
import io.github.moulberry.notenoughupdates.NEUManager;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElement.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElement.java
index 38ad2824..ab277078 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElement.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElement.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.itemeditor;
import net.minecraft.client.gui.Gui;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementButton.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementButton.java
index 35b31490..54cba6b8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementButton.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementButton.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.itemeditor;
import java.awt.*;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementText.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementText.java
index 1e7a8c08..9f612fcf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementText.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementText.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.itemeditor;
import net.minecraft.client.Minecraft;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java
index fd78f3aa..71c4d498 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/GuiElementTextField.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.itemeditor;
import io.github.moulberry.notenoughupdates.util.Utils;
@@ -158,7 +177,12 @@ public class GuiElementTextField extends GuiElement {
String textNC = textNoColour.substring(0, cursorIndex);
int colorCodes = StringUtils.countMatches(textNC, "\u00B6");
- String line = text.substring(cursorIndex + (((options & COLOUR) != 0) ? colorCodes * 2 : 0)).split("\n")[0];
+ String[] lines = text.substring(cursorIndex + (((options & COLOUR) != 0) ? colorCodes * 2 : 0)).split("\n");
+ if (lines.length < 1) {
+ return 0;
+ }
+ String line = lines[0];
+
int padding = Math.min(5, searchBarXSize - strLenNoColor(line)) / 2;
String trimmed = Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(line, xComp - padding);
int linePos = strLenNoColor(trimmed);
@@ -210,6 +234,33 @@ public class GuiElementTextField extends GuiElement {
@Override
public void keyTyped(char typedChar, int keyCode) {
if (focus) {
+ //allows for pasting formatted text that includes "§"
+ if (GuiScreen.isKeyComboCtrlV(keyCode)) {
+ textField.setEnabled(false);
+
+ int selectionEnd = textField.getSelectionEnd();
+ int cursorPosition = textField.getCursorPosition();
+
+ if (cursorPosition < selectionEnd) {
+ //swap selectionEnd and cursorPosition
+ selectionEnd = selectionEnd ^ cursorPosition;
+ cursorPosition = selectionEnd ^ cursorPosition;
+ selectionEnd = selectionEnd ^ cursorPosition;
+ }
+
+ String clipboardContent = GuiScreen.getClipboardString();
+
+ StringBuilder stringBuilder = new StringBuilder(getText())
+ .replace(selectionEnd, cursorPosition, "")
+ .insert(selectionEnd, clipboardContent);
+
+ //writeText removes unwanted chars from the String which includes "§"
+ textField.setText(stringBuilder.toString());
+ textField.setCursorPosition(selectionEnd + clipboardContent.length());
+ } else {
+ textField.setEnabled(true);
+ }
+
if ((options & MULTILINE) != 0) { //Carriage return
Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6\n])(?!\\u00B6)");
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/NEUItemEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/NEUItemEditor.java
index 0392c32f..e08e5369 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/NEUItemEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/itemeditor/NEUItemEditor.java
@@ -1,8 +1,29 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.itemeditor;
import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NEUManager;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingInteger;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
@@ -14,7 +35,11 @@ import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.*;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTException;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTTagString;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
@@ -27,116 +52,172 @@ import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
-import static io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField.*;
+import static io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField.COLOUR;
+import static io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField.FORCE_CAPS;
+import static io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField.MULTILINE;
+import static io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField.NO_SPACE;
+import static io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField.NUM_ONLY;
public class NEUItemEditor extends GuiScreen {
- private final NEUManager manager;
-
private final List<GuiElement> options = new ArrayList<>();
private final List<GuiElement> rightOptions = new ArrayList<>();
- private final JsonObject item;
+ private JsonObject item;
+ private final JsonObject savedRepoItem;
private static final int PADDING = 10;
private static final int SCROLL_AMOUNT = 20;
private final LerpingInteger scrollHeight = new LerpingInteger(0);
- private final Supplier<String> internalname;
- private final Supplier<String> itemid;
- private final Supplier<String> displayname;
+ private final Supplier<String> internalName;
+ private final Supplier<String> itemId;
+ private final Supplier<String> displayName;
private final Supplier<String> lore;
- private final Supplier<String> crafttext;
+ private final Supplier<String> craftText;
private final Supplier<String> infoType;
private final Supplier<String> info;
- private final Supplier<String> clickcommand;
+ private final Supplier<String> clickCommand;
private final Supplier<String> damage;
- private NBTTagCompound nbttag;
+ private NBTTagCompound nbtTag;
+ private int saved = 0;
- public NEUItemEditor(NEUManager manager, String internalname, JsonObject item) {
- this.manager = manager;
+ public NEUItemEditor(String internalName, JsonObject item) {
this.item = item;
-
if (item.has("nbttag")) {
try {
- nbttag = JsonToNBT.getTagFromJson(item.get("nbttag").getAsString());
+ nbtTag = JsonToNBT.getTagFromJson(item.get("nbttag").getAsString());
} catch (NBTException ignored) {
}
}
+ NBTTagCompound extraAttributes = nbtTag.getCompoundTag("ExtraAttributes");
+ extraAttributes.removeTag("uuid");
+ extraAttributes.removeTag("timestamp");
+
+ if (extraAttributes.hasKey("petInfo")) {
+ String petInfo = extraAttributes.getString("petInfo");
+ JsonObject jsonObject = NotEnoughUpdates.INSTANCE.manager.gson.fromJson(petInfo, JsonObject.class);
+
+ jsonObject.remove("heldItem");
+ jsonObject.add("exp", new JsonPrimitive(0));
+ jsonObject.add("candyUsed", new JsonPrimitive(0));
+
+ extraAttributes.setString("petInfo", jsonObject.toString());
+ }
+
+ savedRepoItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().getOrDefault(internalName, null);
- internalname = internalname == null ? "" : internalname;
+ internalName = internalName == null ? "" : internalName;
options.add(new GuiElementText("Internal Name: ", Color.WHITE.getRGB()));
- this.internalname = addTextFieldWithSupplier(internalname, NO_SPACE | FORCE_CAPS);
+ this.internalName = addTextFieldWithSupplier(internalName, NO_SPACE | FORCE_CAPS);
options.add(new GuiElementText("Item ID: ", Color.WHITE.getRGB()));
String itemid = item.has("itemid") ? item.get("itemid").getAsString() : "";
- this.itemid = addTextFieldWithSupplier(itemid, NO_SPACE);
+ this.itemId = addTextFieldWithSupplier(itemid, NO_SPACE);
options.add(new GuiElementText("Display name: ", Color.WHITE.getRGB()));
- String displayname = item.has("displayname") ? item.get("displayname").getAsString() : "";
- this.displayname = addTextFieldWithSupplier(displayname, COLOUR);
+ String displayName = item.has("displayname") ? item.get("displayname").getAsString() : "";
+ this.displayName = addTextFieldWithSupplier(displayName, COLOUR);
options.add(new GuiElementText("Lore: ", Color.WHITE.getRGB()));
- JsonArray lore = item.has("lore") ? item.get("lore").getAsJsonArray() : new JsonArray();
+ JsonElement loreElement = getItemInfo("lore");
+ JsonArray lore = loreElement != null ? loreElement.getAsJsonArray() : new JsonArray();
String[] loreA = new String[lore.size()];
for (int i = 0; i < lore.size(); i++) loreA[i] = lore.get(i).getAsString();
this.lore = addTextFieldWithSupplier(String.join("\n", loreA), COLOUR | MULTILINE);
options.add(new GuiElementText("Craft text: ", Color.WHITE.getRGB()));
- String crafttext = item.has("crafttext") ? item.get("crafttext").getAsString() : "";
- this.crafttext = addTextFieldWithSupplier(crafttext, COLOUR);
+ JsonElement craftTextElement = getItemInfo("crafttext");
+ String craftText = craftTextElement != null ? craftTextElement.getAsString() : "";
+ this.craftText = addTextFieldWithSupplier(craftText, COLOUR);
options.add(new GuiElementText("Info type: ", Color.WHITE.getRGB()));
- String infoType = item.has("infoType") ? item.get("infoType").getAsString() : "";
+ JsonElement infoTypeElement = getItemInfo("infoType");
+ String infoType = infoTypeElement != null ? infoTypeElement.getAsString() : "";
this.infoType = addTextFieldWithSupplier(infoType, NO_SPACE | FORCE_CAPS);
options.add(new GuiElementText("Additional information: ", Color.WHITE.getRGB()));
- JsonArray info = item.has("info") ? item.get("info").getAsJsonArray() : new JsonArray();
+ JsonElement infoElement = getItemInfo("info");
+ JsonArray info = infoElement != null ? infoElement.getAsJsonArray() : new JsonArray();
String[] infoA = new String[info.size()];
for (int i = 0; i < info.size(); i++) infoA[i] = info.get(i).getAsString();
this.info = addTextFieldWithSupplier(String.join("\n", infoA), COLOUR | MULTILINE);
options.add(new GuiElementText("Click-command (viewrecipe or viewpotion): ", Color.WHITE.getRGB()));
- String clickcommand = item.has("clickcommand") ? item.get("clickcommand").getAsString() : "";
- this.clickcommand = addTextFieldWithSupplier(clickcommand, NO_SPACE);
+ JsonElement clickCommandElement = getItemInfo("clickcommand");
+ String clickCommand = clickCommandElement != null ? clickCommandElement.getAsString() : "";
+ this.clickCommand = addTextFieldWithSupplier(clickCommand, NO_SPACE);
options.add(new GuiElementText("Damage: ", Color.WHITE.getRGB()));
- String damage = item.has("damage") ? item.get("damage").getAsString() : "";
+ JsonElement damageElement = getItemInfo("damage");
+ String damage = damageElement != null ? damageElement.getAsString() : "";
this.damage = addTextFieldWithSupplier(damage, NO_SPACE | NUM_ONLY);
rightOptions.add(new GuiElementButton("Close (discards changes)", Color.LIGHT_GRAY.getRGB(), () ->
Minecraft.getMinecraft().displayGuiScreen(null)));
+
+ rightOptions.add(new GuiElementText("", Color.WHITE.getRGB()));
+
GuiElementButton button = new Object() { //Used to make the compiler shut the fuck up
final GuiElementButton b = new GuiElementButton("Save to local disk", Color.GREEN.getRGB(), new Runnable() {
public void run() {
if (save()) {
- b.setText("Save to local disk (SUCCESS)");
+ b.setText(saved == 0 ? "Saved" : "Saved (" + saved + ")");
+ saved++;
} else {
- b.setText("Save to local disk (FAILED)");
+ b.setText("Saving FAILED!");
}
}
});
}.b;
rightOptions.add(button);
- rightOptions.add(new GuiElementText("", Color.WHITE.getRGB()));
-
rightOptions.add(new GuiElementButton("Remove enchants", Color.RED.getRGB(), () -> {
- nbttag.removeTag("ench");
- nbttag.getCompoundTag("ExtraAttributes").removeTag("enchantments");
+ nbtTag.removeTag("ench");
+ extraAttributes.removeTag("enchantments");
}));
rightOptions.add(new GuiElementButton(
"Add enchant glint",
Color.ORANGE.getRGB(),
- () -> nbttag.setTag("ench", new NBTTagList())
+ () -> nbtTag.setTag("ench", new NBTTagList())
));
- rightOptions.add(new GuiElementButton("Remove timestamp/uuid", Color.RED.getRGB(), () -> {
- nbttag.getCompoundTag("ExtraAttributes").removeTag("uuid");
- nbttag.getCompoundTag("ExtraAttributes").removeTag("timestamp");
- }));
-
resetScrollToTop();
+ if (savedRepoItem != null) {
+ this.item = savedRepoItem;
+ } else {
+ this.item = item;
+ }
+ }
+
+ /**
+ * Creates a new ItemEditor object and instantly saves. This will update the lore/nbt tag and other item infos in the repo without removing things like recipes and wiki URLs and without showing the GUI
+ *
+ * @param internalName the internal name for the item
+ * @param item the Item as a JsonObject
+ * @return weather the saving was successful or not
+ * @see io.github.moulberry.notenoughupdates.NEUManager#getInternalNameForItem(ItemStack)
+ * @see io.github.moulberry.notenoughupdates.NEUManager#getJsonForItem(ItemStack)
+ */
+ public static boolean saveOnly(String internalName, JsonObject item) {
+ NEUItemEditor editor = new NEUItemEditor(internalName, item);
+ return editor.save();
+ }
+
+ /**
+ * Returns the Element from the item being edited or the already existing item, prioritizing the item currently being edited
+ *
+ * @param key The JSON key
+ * @return the element found, or null
+ */
+ private JsonElement getItemInfo(String key) {
+ if (item.has(key)) {
+ return item.get(key);
+ } else if (savedRepoItem != null && savedRepoItem.has(key)) {
+ return savedRepoItem.get(key);
+ } else {
+ return null;
+ }
}
public boolean save() {
@@ -150,15 +231,21 @@ public class NEUItemEditor extends GuiScreen {
if (infoA.length == 0 || infoA[0].isEmpty()) {
infoA = new String[0];
}
- return manager.writeItemJson(item, internalname.get(), itemid.get(), displayname.get(), lore.get().split("\n"),
- crafttext.get(), infoType.get(), infoA, clickcommand.get(), damageI, nbttag
+ return NotEnoughUpdates.INSTANCE.manager.writeItemJson(
+ item,
+ internalName.get(),
+ itemId.get(),
+ displayName.get(),
+ lore.get().split("\n"),
+ craftText.get(),
+ infoType.get(),
+ infoA,
+ clickCommand.get(),
+ damageI,
+ nbtTag
);
}
- public void onGuiClosed() {
- Keyboard.enableRepeatEvents(false);
- }
-
public Supplier<String> addTextFieldWithSupplier(String initialText, int options) {
GuiElementTextField textField = new GuiElementTextField(initialText, options);
this.options.add(textField);
@@ -166,7 +253,7 @@ public class NEUItemEditor extends GuiScreen {
}
public void resyncNbttag() {
- if (nbttag == null) nbttag = new NBTTagCompound();
+ if (nbtTag == null) nbtTag = new NBTTagCompound();
//Item lore
NBTTagList list = new NBTTagList();
@@ -174,17 +261,17 @@ public class NEUItemEditor extends GuiScreen {
list.appendTag(new NBTTagString(lore));
}
- NBTTagCompound display = nbttag.getCompoundTag("display");
+ NBTTagCompound display = nbtTag.getCompoundTag("display");
display.setTag("Lore", list);
//Name
- display.setString("Name", displayname.get());
- nbttag.setTag("display", display);
+ display.setString("Name", displayName.get());
+ nbtTag.setTag("display", display);
//Internal ID
- NBTTagCompound ea = nbttag.getCompoundTag("ExtraAttributes");
- ea.setString("id", internalname.get());
- nbttag.setTag("ExtraAttributes", ea);
+ NBTTagCompound ea = nbtTag.getCompoundTag("ExtraAttributes");
+ ea.setString("id", internalName.get());
+ nbtTag.setTag("ExtraAttributes", ea);
}
public void resetScrollToTop() {
@@ -238,9 +325,6 @@ public class NEUItemEditor extends GuiScreen {
drawRect(0, 0, width, height, backgroundColour.getRGB());
int yScroll = calculateYScroll();
- if (yScroll > 0) {
- //Render scroll bar
- }
int currentY = PADDING - yScroll;
for (GuiElement gui : options) {
@@ -263,7 +347,7 @@ public class NEUItemEditor extends GuiScreen {
drawRect(itemX - 9, itemY - 9, itemX + itemSize + 9, itemY + itemSize + 9, itemBorder.getRGB());
drawRect(itemX - 6, itemY - 6, itemX + itemSize + 6, itemY + itemSize + 6, Color.DARK_GRAY.getRGB());
drawRect(itemX - 5, itemY - 5, itemX + itemSize + 5, itemY + itemSize + 5, itemBackground.getRGB());
- ItemStack stack = new ItemStack(Item.itemRegistry.getObject(new ResourceLocation(itemid.get())));
+ ItemStack stack = new ItemStack(Item.itemRegistry.getObject(new ResourceLocation(itemId.get())));
if (stack.getItem() != null) {
try {
@@ -272,18 +356,18 @@ public class NEUItemEditor extends GuiScreen {
}
resyncNbttag();
- stack.setTagCompound(nbttag);
+ stack.setTagCompound(nbtTag);
int scaleFactor = itemSize / 16;
GL11.glPushMatrix();
GlStateManager.scale(scaleFactor, scaleFactor, 1);
- drawItemStack(stack, itemX / scaleFactor, itemY / scaleFactor, null);
+ drawItemStack(stack, itemX / scaleFactor, itemY / scaleFactor);
GL11.glPopMatrix();
}
//Tooltip
List<String> text = new ArrayList<>();
- text.add(displayname.get());
+ text.add(displayName.get());
text.addAll(Arrays.asList(lore.get().split("\n")));
Utils.drawHoveringText(text, itemX - 20, itemY + itemSize + 28, width, height, -1,
@@ -295,6 +379,12 @@ public class NEUItemEditor extends GuiScreen {
@Override
protected void keyTyped(char typedChar, int keyCode) {
+ boolean hasChanges = false;
+ if (keyCode == Keyboard.KEY_ESCAPE && !hasChanges) {
+ Minecraft.getMinecraft().displayGuiScreen(null);
+ return;
+ }
+
for (GuiElement gui : options) {
gui.keyTyped(typedChar, keyCode);
}
@@ -398,7 +488,7 @@ public class NEUItemEditor extends GuiScreen {
}
}
- private void drawItemStack(ItemStack stack, int x, int y, String altText) {
+ private void drawItemStack(ItemStack stack, int x, int y) {
RenderItem itemRender = Minecraft.getMinecraft().getRenderItem();
FontRenderer font = Minecraft.getMinecraft().fontRendererObj;
@@ -406,7 +496,6 @@ public class NEUItemEditor extends GuiScreen {
itemRender.renderItemAndEffectIntoGUI(stack, x, y);
RenderHelper.disableStandardItemLighting();
- itemRender.renderItemOverlayIntoGUI(font, stack, x, y, altText);
+ itemRender.renderItemOverlayIntoGUI(font, stack, x, y, null);
}
-
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java
new file mode 100644
index 00000000..3473124c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ChatListener.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.dungeons.DungeonWin;
+import io.github.moulberry.notenoughupdates.miscfeatures.CookieWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.StreamerMode;
+import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
+import io.github.moulberry.notenoughupdates.overlays.SlayerOverlay;
+import io.github.moulberry.notenoughupdates.overlays.TimersOverlay;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatComponentTranslation;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.client.ClientCommandHandler;
+import net.minecraftforge.client.event.ClientChatReceivedEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static io.github.moulberry.notenoughupdates.overlays.SlayerOverlay.RNGMeter;
+import static io.github.moulberry.notenoughupdates.overlays.SlayerOverlay.slayerXp;
+import static io.github.moulberry.notenoughupdates.overlays.SlayerOverlay.timeSinceLastBoss;
+import static io.github.moulberry.notenoughupdates.overlays.SlayerOverlay.timeSinceLastBoss2;
+
+public class ChatListener {
+ private final NotEnoughUpdates neu;
+ private static final Pattern SLAYER_XP = Pattern.compile(
+ " (Spider|Zombie|Wolf|Enderman|Blaze) Slayer LVL (\\d) - (?:Next LVL in ([\\d,]+) XP!|LVL MAXED OUT!)");
+ AtomicBoolean missingRecipe = new AtomicBoolean(false);
+
+ public ChatListener(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ private String processText(String text) {
+ if (SBInfo.getInstance().getLocation() == null) return text;
+ if (!SBInfo.getInstance().getLocation().startsWith("mining_") && !SBInfo.getInstance().getLocation().equals(
+ "crystal_hollows"))
+ return text;
+
+ if (Minecraft.getMinecraft().thePlayer == null) return text;
+ if (!NotEnoughUpdates.INSTANCE.config.mining.drillFuelBar) return text;
+
+ return Utils.trimIgnoreColour(text.replaceAll(EnumChatFormatting.DARK_GREEN + "\\S+ Drill Fuel", ""));
+ }
+
+ private IChatComponent processChatComponent(IChatComponent chatComponent) {
+ IChatComponent newComponent;
+ if (chatComponent instanceof ChatComponentText) {
+ ChatComponentText text = (ChatComponentText) chatComponent;
+
+ newComponent = new ChatComponentText(processText(text.getUnformattedTextForChat()));
+ newComponent.setChatStyle(text.getChatStyle().createShallowCopy());
+
+ for (IChatComponent sibling : text.getSiblings()) {
+ newComponent.appendSibling(processChatComponent(sibling));
+ }
+ } else if (chatComponent instanceof ChatComponentTranslation) {
+ ChatComponentTranslation trans = (ChatComponentTranslation) chatComponent;
+
+ Object[] args = trans.getFormatArgs();
+ Object[] newArgs = new Object[args.length];
+ for (int i = 0; i < trans.getFormatArgs().length; i++) {
+ if (args[i] instanceof IChatComponent) {
+ newArgs[i] = processChatComponent((IChatComponent) args[i]);
+ } else {
+ newArgs[i] = args[i];
+ }
+ }
+ newComponent = new ChatComponentTranslation(trans.getKey(), newArgs);
+
+ for (IChatComponent sibling : trans.getSiblings()) {
+ newComponent.appendSibling(processChatComponent(sibling));
+ }
+ } else {
+ newComponent = chatComponent.createCopy();
+ }
+
+ return newComponent;
+ }
+
+ private IChatComponent replaceSocialControlsWithPV(IChatComponent chatComponent) {
+
+ if (NotEnoughUpdates.INSTANCE.config.misc.replaceSocialOptions1 > 0 && chatComponent.getChatStyle() != null &&
+ chatComponent.getChatStyle().getChatClickEvent() != null &&
+ chatComponent.getChatStyle().getChatClickEvent().getAction() == ClickEvent.Action.RUN_COMMAND &&
+ NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ if (chatComponent.getChatStyle().getChatClickEvent().getValue().startsWith("/socialoptions")) {
+ String username = chatComponent.getChatStyle().getChatClickEvent().getValue().substring(15);
+ if (NotEnoughUpdates.INSTANCE.config.misc.replaceSocialOptions1 == 1) {
+ chatComponent.setChatStyle(Utils.createClickStyle(
+ ClickEvent.Action.RUN_COMMAND,
+ "/pv " + username,
+ "" + EnumChatFormatting.YELLOW + "Click to open " + EnumChatFormatting.AQUA + EnumChatFormatting.BOLD +
+ username + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + "'s profile in " +
+ EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.BOLD + "NEU's" + EnumChatFormatting.RESET +
+ EnumChatFormatting.YELLOW + " profile viewer."
+ ));
+ return chatComponent;
+ } else if (NotEnoughUpdates.INSTANCE.config.misc.replaceSocialOptions1 == 2) {
+ chatComponent.setChatStyle(Utils.createClickStyle(
+ ClickEvent.Action.RUN_COMMAND,
+ "/ah " + username,
+ "" + EnumChatFormatting.YELLOW + "Click to open " + EnumChatFormatting.AQUA + EnumChatFormatting.BOLD +
+ username + EnumChatFormatting.RESET + EnumChatFormatting.YELLOW + "'s /ah page"
+ ));
+ return chatComponent;
+ }
+ } // wanted to add this for guild but guild uses uuid :sad:
+ }
+ return chatComponent;
+ }
+
+ /**
+ * 1) When receiving "You are playing on profile" messages, will set the current profile.
+ * 2) When a /viewrecipe command fails (i.e. player does not have recipe unlocked, will open the custom recipe GUI)
+ * 3) Replaces lobby join notifications when streamer mode is active
+ */
+ @SubscribeEvent(priority = EventPriority.LOW, receiveCanceled = true)
+ public void onGuiChat(ClientChatReceivedEvent e) {
+ if (e.type == 2) {
+ CrystalMetalDetectorSolver.process(e.message);
+ TimersOverlay.processActionBar(e.message.getUnformattedText());
+ e.message = processChatComponent(e.message);
+ return;
+ } else if (e.type == 0) {
+ e.message = replaceSocialControlsWithPV(e.message);
+ }
+
+ DungeonWin.onChatMessage(e);
+
+ String r = null;
+ String unformatted = Utils.cleanColour(e.message.getUnformattedText());
+ Matcher matcher = SLAYER_XP.matcher(unformatted);
+ if (unformatted.startsWith("You are playing on profile: ")) {
+ neu.manager.setCurrentProfile(unformatted
+ .substring("You are playing on profile: ".length())
+ .split(" ")[0].trim());
+ } else if (unformatted.startsWith("Your profile was changed to: ")) {//Your profile was changed to:
+ neu.manager.setCurrentProfile(unformatted
+ .substring("Your profile was changed to: ".length())
+ .split(" ")[0].trim());
+ } else if (unformatted.startsWith("Your new API key is ")) {
+ NotEnoughUpdates.INSTANCE.config.apiData.apiKey =
+ unformatted.substring("Your new API key is ".length()).substring(
+ 0,
+ 36
+ );
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.YELLOW + "[NEU] API Key automatically configured"));
+ NotEnoughUpdates.INSTANCE.saveConfig();
+ } else if (unformatted.startsWith("Player List Info is now disabled!")) {
+ SBInfo.getInstance().hasNewTab = false;
+ } else if (unformatted.startsWith("Player List Info is now enabled!")) {
+ SBInfo.getInstance().hasNewTab = true;
+ }
+ if (e.message.getFormattedText().equals(
+ EnumChatFormatting.RESET.toString() + EnumChatFormatting.RED + "You haven't unlocked this recipe!" +
+ EnumChatFormatting.RESET)) {
+ r = EnumChatFormatting.RED + "You haven't unlocked this recipe!";
+ } else if (e.message.getFormattedText().startsWith(
+ EnumChatFormatting.RESET.toString() + EnumChatFormatting.RED + "Invalid recipe ")) {
+ r = "";
+ } else if (unformatted.equals(" NICE! SLAYER BOSS SLAIN!")) {
+ SlayerOverlay.isSlain = true;
+ } else if (unformatted.equals(" SLAYER QUEST STARTED!")) {
+ SlayerOverlay.isSlain = false;
+ if (timeSinceLastBoss == 0) {
+ SlayerOverlay.timeSinceLastBoss = System.currentTimeMillis();
+ } else {
+ timeSinceLastBoss2 = timeSinceLastBoss;
+ timeSinceLastBoss = System.currentTimeMillis();
+ }
+ } else if (unformatted.startsWith(" RNG Meter")) {
+ RNGMeter = unformatted.substring(" RNG Meter - ".length());
+ } else if (matcher.matches()) {
+ //matcher.group(1);
+ SlayerOverlay.slayerLVL = matcher.group(2);
+ if (!SlayerOverlay.slayerLVL.equals("9")) {
+ SlayerOverlay.slayerXp = matcher.group(3);
+ } else {
+ slayerXp = "maxed";
+ }
+ } else if (unformatted.startsWith("Sending to server") || (unformatted.startsWith(
+ "Your Slayer Quest has been cancelled!"))) {
+ SlayerOverlay.slayerQuest = false;
+ SlayerOverlay.unloadOverlayTimer = System.currentTimeMillis();
+ } else if (unformatted.startsWith("You consumed a Booster Cookie!")) {
+ CookieWarning.resetNotification();
+ } else if (unformatted.startsWith("QUICK MATHS! Solve:") && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ if (Math.random() < 0.2) {
+ if (NotEnoughUpdates.INSTANCE.config.misc.calculationMode == 2) {
+ ClientCommandHandler.instance.executeCommand(
+ Minecraft.getMinecraft().thePlayer,
+ "/neucalc " + unformatted.substring("QUICK MATHS! Solve: ".length())
+ );
+ }
+ }
+ }
+ if (e.message.getFormattedText().contains(
+ EnumChatFormatting.YELLOW + "Visit the Auction House to collect your item!")) {
+ if (NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBid != null &&
+ System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBidMillis < 5000) {
+ NotEnoughUpdates.INSTANCE.sendChatMessage("/viewauction " +
+ NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.niceAucId(NotEnoughUpdates.INSTANCE.manager.auctionManager.customAH.latestBid));
+ }
+ }
+ if (r != null) {
+ if (neu.manager.failViewItem(r)) {
+ e.setCanceled(true);
+ }
+ missingRecipe.set(true);
+ }
+ if (unformatted.startsWith("Sending to server") &&
+ NotEnoughUpdates.INSTANCE.config.misc.streamerMode && e.message instanceof ChatComponentText) {
+ String m = e.message.getFormattedText();
+ String m2 = StreamerMode.filterChat(e.message.getFormattedText());
+ if (!m.equals(m2)) {
+ e.message = new ChatComponentText(m2);
+ }
+ }
+ if (unformatted.startsWith("You found ") && SBInfo.getInstance().getLocation() != null &&
+ SBInfo.getInstance().getLocation().equals("crystal_hollows")) {
+ CrystalMetalDetectorSolver.resetSolution(true);
+ }
+ if (unformatted.startsWith("[NPC] Keeper of ") | unformatted.startsWith("[NPC] Professor Robot: ") ||
+ unformatted.startsWith(" ") || unformatted.startsWith("✦") || unformatted.equals(
+ " You've earned a Crystal Loot Bundle!"))
+ OverlayManager.crystalHollowOverlay.message(unformatted);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipEssenceShopListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipEssenceShopListener.java
new file mode 100644
index 00000000..4b380c2f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipEssenceShopListener.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ItemTooltipEssenceShopListener {
+ private final NotEnoughUpdates neu;
+
+ private final Pattern ESSENCE_PATTERN = Pattern.compile("§5§o§d([\\d,]+) (.+) Essence");
+
+ public ItemTooltipEssenceShopListener(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ @SubscribeEvent
+ public void onItemTooltip(ItemTooltipEvent event) {
+ if (!neu.isOnSkyblock()) return;
+ if (event.toolTip == null) return;
+ if (!Utils.getOpenChestName().endsWith(" Essence Shop")) return;
+ if (!NotEnoughUpdates.INSTANCE.config.tooltipTweaks.essencePriceInEssenceShop) return;
+
+ List<String> newToolTip = new ArrayList<>();
+ boolean next = false;
+ for (String line : event.toolTip) {
+
+ if (next) {
+ next = false;
+ Matcher matcher = ESSENCE_PATTERN.matcher(line);
+ if (matcher.matches()) {
+ String rawNumber = matcher.group(1).replace(",", "");
+ int amount = Integer.parseInt(rawNumber);
+ String type = matcher.group(2);
+
+ String essenceName = "ESSENCE_" + type.toUpperCase();
+ JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(essenceName);
+
+ if (bazaarInfo != null && bazaarInfo.has("curr_sell")) {
+ float bazaarPrice = bazaarInfo.get("curr_sell").getAsFloat();
+ double price = bazaarPrice * amount;
+ String format = StringUtils.shortNumberFormat(price);
+ newToolTip.add(line + " §7(§6" + format + " coins§7)");
+ continue;
+ }
+ }
+ }
+
+ if (line.contains("Cost")) {
+ next = true;
+ }
+ newToolTip.add(line);
+ }
+
+ event.toolTip.clear();
+ event.toolTip.addAll(newToolTip);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java
new file mode 100644
index 00000000..d89e886f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipListener.java
@@ -0,0 +1,887 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.minecraft.MinecraftProfileTexture;
+import io.github.moulberry.notenoughupdates.ItemPriceInformation;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.MiscUtils;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.GuiEnchantColour;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTUtil;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.Loader;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.apache.commons.lang3.text.WordUtils;
+import org.lwjgl.input.Keyboard;
+
+import java.awt.*;
+import java.awt.datatransfer.StringSelection;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ItemTooltipListener {
+ public static final String petToolTipRegex =
+ "((Farming)|(Combat)|(Fishing)|(Mining)|(Foraging)|(Enchanting)|(Alchemy)) ((Mount)|(Pet)|(Morph)).*";
+ private final NotEnoughUpdates neu;
+ private final Pattern xpLevelPattern = Pattern.compile("(.*) (\\xA7e(.*)\\xA76/\\xA7e(.*))");
+ private final HashSet<String> percentStats = new HashSet<>();
+ DecimalFormat myFormatter = new DecimalFormat("#,###,###.###");
+ private String currentRarity = "COMMON";
+ private boolean copied = false;
+ private boolean showReforgeStoneStats = true;
+ private boolean pressedArrowLast = false;
+ private boolean pressedShiftLast = false;
+ private int sbaloaded = -1;
+
+ public ItemTooltipListener(NotEnoughUpdates neu) {
+ this.neu = neu;
+ percentStats.add("bonus_attack_speed");
+ percentStats.add("crit_damage");
+ percentStats.add("crit_chance");
+ percentStats.add("sea_creature_chance");
+ percentStats.add("ability_damage");
+ }
+
+ private boolean isSkyblockAddonsLoaded() {
+ if (sbaloaded == -1) {
+ if (Loader.isModLoaded("skyblockaddons")) {
+ sbaloaded = 1;
+ } else {
+ sbaloaded = 0;
+ }
+ }
+ return sbaloaded == 1;
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOW)
+ public void onItemTooltipLow(ItemTooltipEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.isOnSkyblock()) return;
+
+ String internalName = NotEnoughUpdates.INSTANCE.manager
+ .createItemResolutionQuery()
+ .withCurrentGuiContext()
+ .withItemStack(event.itemStack)
+ .resolveInternalName();
+
+ if (internalName == null) {
+ return;
+ }
+ petToolTipXPExtendPetMenu(event);
+
+ boolean hasEnchantments = event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").hasKey(
+ "enchantments",
+ 10
+ );
+ boolean hasAttributes = event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").hasKey(
+ "attributes",
+ 10
+ );
+ Set<String> enchantIds = new HashSet<>();
+ if (hasEnchantments) enchantIds = event.itemStack.getTagCompound().getCompoundTag("ExtraAttributes").getCompoundTag(
+ "enchantments").getKeySet();
+
+ JsonObject enchantsConst = Constants.ENCHANTS;
+ JsonArray allItemEnchs = null;
+ Set<String> ignoreFromPool = new HashSet<>();
+ if (enchantsConst != null && hasEnchantments && NotEnoughUpdates.INSTANCE.config.tooltipTweaks.missingEnchantList) {
+ try {
+ JsonArray enchantPools = enchantsConst.get("enchant_pools").getAsJsonArray();
+ for (JsonElement element : enchantPools) {
+ Set<String> currentPool = new HashSet<>();
+ for (JsonElement poolElement : element.getAsJsonArray()) {
+ String poolS = poolElement.getAsString();
+ currentPool.add(poolS);
+ }
+ for (JsonElement poolElement : element.getAsJsonArray()) {
+ String poolS = poolElement.getAsString();
+ if (enchantIds.contains(poolS)) {
+ ignoreFromPool.addAll(currentPool);
+ break;
+ }
+ }
+ }
+
+ JsonObject enchantsObj = enchantsConst.get("enchants").getAsJsonObject();
+ NBTTagCompound tag = event.itemStack.getTagCompound();
+ if (tag != null) {
+ NBTTagCompound display = tag.getCompoundTag("display");
+ if (display.hasKey("Lore", 9)) {
+ NBTTagList list = display.getTagList("Lore", 8);
+ out:
+ for (int i = list.tagCount(); i >= 0; i--) {
+ String line = list.getStringTagAt(i);
+ for (int j = 0; j < Utils.rarityArrC.length; j++) {
+ for (Map.Entry<String, JsonElement> entry : enchantsObj.entrySet()) {
+ if (line.contains(Utils.rarityArrC[j] + " " + entry.getKey()) || line.contains(
+ Utils.rarityArrC[j] + " DUNGEON " + entry.getKey()) || line.contains(
+ "SHINY " + Utils.rarityArrC[j].replaceAll("§.§.", "") + " DUNGEON " + entry.getKey())) {
+ allItemEnchs = entry.getValue().getAsJsonArray();
+ break out;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception ignored) {
+ }
+ }
+
+ boolean gotToEnchants = false;
+ boolean passedEnchants = false;
+
+ boolean dungeonProfit = false;
+ int index = 0;
+ List<String> newTooltip = new ArrayList<>();
+
+ for (String line : event.toolTip) {
+ if (line.endsWith(EnumChatFormatting.DARK_GRAY + "Reforge Stone") &&
+ NotEnoughUpdates.INSTANCE.config.tooltipTweaks.showReforgeStats) {
+ JsonObject reforgeStones = Constants.REFORGESTONES;
+
+ if (reforgeStones != null && reforgeStones.has(internalName)) {
+ boolean shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
+ if (!pressedShiftLast && shift) {
+ showReforgeStoneStats = !showReforgeStoneStats;
+ }
+ pressedShiftLast = shift;
+
+ newTooltip.add(line);
+ newTooltip.add("");
+ if (!showReforgeStoneStats) {
+ newTooltip.add(EnumChatFormatting.DARK_GRAY + "[Press SHIFT to show extra info]");
+ } else {
+ newTooltip.add(EnumChatFormatting.DARK_GRAY + "[Press SHIFT to hide extra info]");
+ }
+
+ JsonObject reforgeInfo = reforgeStones.get(internalName).getAsJsonObject();
+ JsonArray requiredRaritiesArray = reforgeInfo.get("requiredRarities").getAsJsonArray();
+
+ if (showReforgeStoneStats && requiredRaritiesArray.size() > 0) {
+ String reforgeName = Utils.getElementAsString(reforgeInfo.get("reforgeName"), "");
+
+ String[] requiredRarities = new String[requiredRaritiesArray.size()];
+ for (int i = 0; i < requiredRaritiesArray.size(); i++) {
+ requiredRarities[i] = requiredRaritiesArray.get(i).getAsString();
+ }
+
+ int rarityIndex = requiredRarities.length - 1;
+ String rarity = requiredRarities[rarityIndex];
+ for (int i = 0; i < requiredRarities.length; i++) {
+ String rar = requiredRarities[i];
+ if (rar.equalsIgnoreCase(currentRarity)) {
+ rarity = rar;
+ rarityIndex = i;
+ break;
+ }
+ }
+
+ boolean left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
+ boolean right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
+ if (!pressedArrowLast && (left || right)) {
+ if (left) {
+ rarityIndex--;
+ } else {
+ rarityIndex++;
+ }
+ if (rarityIndex < 0) rarityIndex = 0;
+ if (rarityIndex >= requiredRarities.length) rarityIndex = requiredRarities.length - 1;
+ currentRarity = requiredRarities[rarityIndex];
+ rarity = currentRarity;
+ }
+ pressedArrowLast = left || right;
+
+ JsonElement statsE = reforgeInfo.get("reforgeStats");
+
+ String rarityFormatted = Utils.rarityArrMap.getOrDefault(rarity, rarity);
+
+ JsonElement reforgeAbilityE = reforgeInfo.get("reforgeAbility");
+ String reforgeAbility = null;
+ if (reforgeAbilityE != null) {
+ if (reforgeAbilityE.isJsonPrimitive() && reforgeAbilityE.getAsJsonPrimitive().isString()) {
+ reforgeAbility = Utils.getElementAsString(reforgeInfo.get("reforgeAbility"), "");
+
+ } else if (reforgeAbilityE.isJsonObject()) {
+ if (reforgeAbilityE.getAsJsonObject().has(rarity)) {
+ reforgeAbility = reforgeAbilityE.getAsJsonObject().get(rarity).getAsString();
+ }
+ }
+ }
+
+ if (reforgeAbility != null && !reforgeAbility.isEmpty()) {
+ String text = EnumChatFormatting.BLUE + (reforgeName.isEmpty() ? "Bonus: " : reforgeName + " Bonus: ") +
+ EnumChatFormatting.GRAY + reforgeAbility;
+ boolean first = true;
+ for (String s : Minecraft.getMinecraft().fontRendererObj.listFormattedStringToWidth(text, 150)) {
+ newTooltip.add((first ? "" : " ") + s);
+ first = false;
+ }
+ newTooltip.add("");
+ }
+
+ newTooltip.add(EnumChatFormatting.BLUE + "Stats for " + rarityFormatted + "§9: [§l§m< §9Switch§l➡§9]");
+
+ if (statsE != null && statsE.isJsonObject()) {
+ JsonObject stats = statsE.getAsJsonObject();
+
+ JsonElement statsRarE = stats.get(rarity);
+ if (statsRarE != null && statsRarE.isJsonObject()) {
+
+ JsonObject statsRar = statsRarE.getAsJsonObject();
+
+ TreeSet<Map.Entry<String, JsonElement>> sorted = new TreeSet<>(Map.Entry.comparingByKey());
+ sorted.addAll(statsRar.entrySet());
+
+ for (Map.Entry<String, JsonElement> entry : sorted) {
+ if (entry.getValue().isJsonPrimitive() && ((JsonPrimitive) entry.getValue()).isNumber()) {
+ float statNumF = entry.getValue().getAsFloat();
+ String statNumS;
+ if (statNumF % 1 == 0) {
+ statNumS = String.valueOf(Math.round(statNumF));
+ } else {
+ statNumS = Utils.floatToString(statNumF, 1);
+ }
+ String reforgeNamePretty = WordUtils.capitalizeFully(entry.getKey().replace("_", " "));
+ String text =
+ EnumChatFormatting.GRAY + reforgeNamePretty + ": " + EnumChatFormatting.GREEN + "+" + statNumS;
+ if (percentStats.contains(entry.getKey())) {
+ text += "%";
+ }
+ newTooltip.add(" " + text);
+ }
+ }
+ }
+ }
+
+ JsonElement reforgeCostsE = reforgeInfo.get("reforgeCosts");
+ int reforgeCost = -1;
+ if (reforgeCostsE != null) {
+ if (reforgeCostsE.isJsonPrimitive() && reforgeCostsE.getAsJsonPrimitive().isNumber()) {
+ reforgeCost = (int) Utils.getElementAsFloat(reforgeInfo.get("reforgeAbility"), -1);
+
+ } else if (reforgeCostsE.isJsonObject()) {
+ if (reforgeCostsE.getAsJsonObject().has(rarity)) {
+ reforgeCost = (int) Utils.getElementAsFloat(reforgeCostsE.getAsJsonObject().get(rarity), -1);
+ }
+ }
+ }
+
+ if (reforgeCost >= 0) {
+ String text = EnumChatFormatting.BLUE + "Apply Cost: " + EnumChatFormatting.GOLD +
+ NumberFormat.getNumberInstance().format(reforgeCost) + " coins";
+ newTooltip.add("");
+ newTooltip.add(text);
+ }
+
+ }
+
+ continue;
+ }
+
+ } else if (line.contains("\u00A7cR\u00A76a\u00A7ei\u00A7an\u00A7bb\u00A79o\u00A7dw\u00A79 Rune")) {
+ line = line.replace(
+ "\u00A7cR\u00A76a\u00A7ei\u00A7an\u00A7bb\u00A79o\u00A7dw\u00A79 Rune",
+ Utils.chromaString("Rainbow Rune", index, false) + EnumChatFormatting.BLUE
+ );
+ } else if (hasEnchantments) {
+ if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) &&
+ NotEnoughUpdates.INSTANCE.config.tooltipTweaks.missingEnchantList) {
+ boolean lineHasEnch = false;
+ for (String s : enchantIds) {
+ String enchantName = WordUtils.capitalizeFully(s.replace("_", " "));
+ if (line.contains(enchantName)) {
+ lineHasEnch = true;
+ break;
+ }
+ }
+ if (lineHasEnch) {
+ gotToEnchants = true;
+ } else {
+ if (gotToEnchants && !passedEnchants && Utils.cleanColour(line).trim().length() == 0) {
+ if (enchantsConst != null && allItemEnchs != null) {
+ List<String> missing = new ArrayList<>();
+ for (JsonElement enchIdElement : allItemEnchs) {
+ String enchId = enchIdElement.getAsString();
+ if (!enchId.startsWith("ultimate_") && !ignoreFromPool.contains(enchId) &&
+ !enchantIds.contains(enchId)) {
+ missing.add(enchId);
+ }
+ }
+ if (!missing.isEmpty()) {
+ newTooltip.add("");
+ StringBuilder currentLine = new StringBuilder(
+ EnumChatFormatting.RED + "Missing: " + EnumChatFormatting.GRAY);
+ for (int i = 0; i < missing.size(); i++) {
+ String enchName = WordUtils.capitalizeFully(missing.get(i).replace("_", " "));
+ if (currentLine.length() != 0 &&
+ (Utils.cleanColour(currentLine.toString()).length() + enchName.length()) > 40) {
+ newTooltip.add(currentLine.toString());
+ currentLine = new StringBuilder();
+ }
+ if (currentLine.length() != 0 && i != 0) {
+ currentLine.append(", ").append(enchName);
+ } else {
+ currentLine.append(EnumChatFormatting.GRAY).append(enchName);
+ }
+ }
+ if (currentLine.length() != 0) {
+ newTooltip.add(currentLine.toString());
+ }
+ }
+ }
+ passedEnchants = true;
+ }
+ }
+ }
+ }
+ if (hasEnchantments || hasAttributes) {
+ ArrayList<String> addedEnchants = new ArrayList<>();
+ for (String op : NotEnoughUpdates.INSTANCE.config.hidden.enchantColours) {
+ List<String> colourOps = GuiEnchantColour.splitter.splitToList(op);
+ String enchantName = GuiEnchantColour.getColourOpIndex(colourOps, 0);
+ String comparator = GuiEnchantColour.getColourOpIndex(colourOps, 1);
+ String comparison = GuiEnchantColour.getColourOpIndex(colourOps, 2);
+ String colourCode = GuiEnchantColour.getColourOpIndex(colourOps, 3);
+ String modifier = GuiEnchantColour.getColourOpIndex(colourOps, 4);
+
+ int modifierI = GuiEnchantColour.getIntModifier(modifier);
+
+ assert enchantName != null;
+ if (enchantName.length() == 0) continue;
+ assert comparator != null;
+ if (comparator.length() == 0) continue;
+ assert comparison != null;
+ if (comparison.length() == 0) continue;
+ assert colourCode != null;
+ if (colourCode.length() == 0) continue;
+
+ int comparatorI = ">=<".indexOf(comparator.charAt(0));
+
+ int levelToFind;
+ try {
+ levelToFind = Integer.parseInt(comparison);
+ } catch (Exception e) {
+ continue;
+ }
+
+ if (comparatorI < 0) continue;
+ String regexText = "0123456789abcdefz";
+ if (isSkyblockAddonsLoaded()) {
+ regexText = regexText + "Z";
+ }
+
+ if (regexText.indexOf(colourCode.charAt(0)) < 0) continue;
+
+ //item_lore = item_lore.replaceAll("\\u00A79("+lvl4Max+" IV)", EnumChatFormatting.DARK_PURPLE+"$1");
+ //9([a-zA-Z ]+?) ([0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X))(,|$)
+ Pattern pattern;
+ try {
+ pattern = Pattern.compile(
+ "(\\u00A7b|\\u00A79|\\u00A7(b|9|l)\\u00A7d\\u00A7l)(?<enchantName>" + enchantName + ") " +
+ "(?<level>[0-9]+|(I|II|III|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX))((\\u00A79)?,|( \\u00A78(?:,?[0-9]+)*)?$)");
+ } catch (Exception e) {
+ continue;
+ }
+ Matcher matcher = pattern.matcher(line);
+ int matchCount = 0;
+ while (matcher.find() && matchCount < 5) {
+ if (Utils.cleanColour(matcher.group("enchantName")).startsWith(" ")) continue;
+
+ matchCount++;
+ int level = -1;
+ String levelStr = matcher.group("level");
+ if (levelStr == null || levelStr.isEmpty()) continue;
+ level = Utils.parseIntOrRomanNumeral(levelStr);
+ boolean matches = false;
+ if (level > 0) {
+ switch (comparator) {
+ case ">":
+ matches = level > levelToFind;
+ break;
+ case "=":
+ matches = level == levelToFind;
+ break;
+ case "<":
+ matches = level < levelToFind;
+ break;
+ }
+ }
+ if (matches) {
+ String enchantText = matcher.group("enchantName");
+ StringBuilder extraModifiersBuilder = new StringBuilder();
+
+ if ((modifierI & GuiEnchantColour.BOLD_MODIFIER) != 0) {
+ extraModifiersBuilder.append(EnumChatFormatting.BOLD);
+ }
+ if ((modifierI & GuiEnchantColour.ITALIC_MODIFIER) != 0) {
+ extraModifiersBuilder.append(EnumChatFormatting.ITALIC);
+ }
+ if ((modifierI & GuiEnchantColour.UNDERLINE_MODIFIER) != 0) {
+ extraModifiersBuilder.append(EnumChatFormatting.UNDERLINE);
+ }
+ if ((modifierI & GuiEnchantColour.OBFUSCATED_MODIFIER) != 0) {
+ extraModifiersBuilder.append(EnumChatFormatting.OBFUSCATED);
+ }
+ if ((modifierI & GuiEnchantColour.STRIKETHROUGH_MODIFIER) != 0) {
+ extraModifiersBuilder.append(EnumChatFormatting.STRIKETHROUGH);
+ }
+
+ String extraMods = extraModifiersBuilder.toString();
+
+ if (!colourCode.equals("z")) {
+ if (!addedEnchants.contains(enchantText)) {
+ line = line.replace("\u00A79" + enchantText, "\u00A7" + colourCode + extraMods + enchantText);
+ line = line.replace("\u00A7b" + enchantText, "\u00A7" + colourCode + extraMods + enchantText);
+ line = line.replace(
+ "\u00A79\u00A7d\u00A7l" + enchantText,
+ "\u00A7" + colourCode + extraMods + enchantText
+ );
+ line = line.replace(
+ "\u00A7b\u00A7d\u00A7l" + enchantText,
+ "\u00A7" + colourCode + extraMods + enchantText
+ );
+ line = line.replace(
+ "\u00A7l\u00A7d\u00A7l" + enchantText,
+ "\u00A7" + colourCode + extraMods + enchantText
+ );
+ }
+ } else {
+ int offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll(
+ "\\u00A79" + enchantText + ".*",
+ ""
+ ));
+ line = line.replace(
+ "\u00A79" + enchantText,
+ Utils.chromaString(enchantText, offset / 12f + index, false)
+ );
+
+ offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll(
+ "\\u00A79\\u00A7d\\u00A7l" + enchantText + ".*",
+ ""
+ ));
+ line = line.replace(
+ "\u00A79\u00A7d\u00A7l" + enchantText,
+ Utils.chromaString(enchantText, offset / 12f + index, true)
+ );
+ offset = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line.replaceAll(
+ "\\u00A7l\\u00A7d\\u00A7l" + enchantText + ".*",
+ ""
+ ));
+ line = line.replace(
+ "\u00A7l\u00A7d\u00A7l" + enchantText,
+ Utils.chromaString(enchantText, offset / 12f + index, true)
+ );
+ }
+ addedEnchants.add(enchantText);
+ }
+ }
+ }
+ }
+
+ newTooltip.add(line);
+
+ if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.showPriceInfoAucItem) {
+ if (line.contains(EnumChatFormatting.GRAY + "Buy it now: ") || line.contains(
+ EnumChatFormatting.GRAY + "Bidder: ") || line.contains(EnumChatFormatting.GRAY + "Starting bid: ")) {
+
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && !Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
+ newTooltip.add("");
+ newTooltip.add(EnumChatFormatting.GRAY + "[SHIFT for Price Info]");
+ } else {
+ ItemPriceInformation.addToTooltip(newTooltip, internalName, event.itemStack);
+ }
+ }
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 2 &&
+ Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
+ if (line.contains(EnumChatFormatting.GREEN + "Open Reward Chest")) {
+ dungeonProfit = true;
+ } else if (index == 7 && dungeonProfit) {
+ GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ int chestCost = 0;
+ try {
+ String line6 = Utils.cleanColour(line);
+ StringBuilder cost = new StringBuilder();
+ for (int i = 0; i < line6.length(); i++) {
+ char c = line6.charAt(i);
+ if ("0123456789".indexOf(c) >= 0) {
+ cost.append(c);
+ }
+ }
+ if (cost.length() > 0) {
+ chestCost = Integer.parseInt(cost.toString());
+ }
+ } catch (Exception ignored) {
+ }
+
+ String missingItem = null;
+ int totalValue = 0;
+ HashMap<String, Double> itemValues = new HashMap<>();
+ for (int i = 0; i < 5; i++) {
+ ItemStack item = lower.getStackInSlot(11 + i);
+ String internal = neu.manager.getInternalNameForItem(item);
+ if (internal != null) {
+ internal = internal.replace("\u00CD", "I").replace("\u0130", "I");
+ float bazaarPrice = -1;
+ JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(internal);
+ if (bazaarInfo != null && bazaarInfo.has("curr_sell")) {
+ bazaarPrice = bazaarInfo.get("curr_sell").getAsFloat();
+ }
+ if (bazaarPrice < 5000000 && internal.equals("RECOMBOBULATOR_3000")) bazaarPrice = 5000000;
+
+ double worth = -1;
+ if (bazaarPrice > 0) {
+ worth = bazaarPrice;
+ } else {
+ switch (NotEnoughUpdates.INSTANCE.config.dungeons.profitType) {
+ case 1:
+ worth = neu.manager.auctionManager.getItemAvgBin(internal);
+ break;
+ case 2:
+ JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
+ if (auctionInfo != null) {
+ if (auctionInfo.has("clean_price")) {
+ worth = (long) auctionInfo.get("clean_price").getAsDouble();
+ } else {
+ worth =
+ (long) (auctionInfo.get("price").getAsDouble() / auctionInfo.get("count").getAsDouble());
+ }
+ }
+ break;
+ default:
+ worth = neu.manager.auctionManager.getLowestBin(internal);
+ }
+ if (worth <= 0) {
+ worth = neu.manager.auctionManager.getLowestBin(internal);
+ if (worth <= 0) {
+ worth = neu.manager.auctionManager.getItemAvgBin(internal);
+ if (worth <= 0) {
+ JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
+ if (auctionInfo != null) {
+ if (auctionInfo.has("clean_price")) {
+ worth = (int) auctionInfo.get("clean_price").getAsFloat();
+ } else {
+ worth = (int) (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (worth > 0 && totalValue >= 0) {
+ totalValue += worth;
+
+ String display = item.getDisplayName();
+
+ if (display.contains("Enchanted Book")) {
+ NBTTagCompound tag = item.getTagCompound();
+ if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ NBTTagCompound enchants = ea.getCompoundTag("enchantments");
+
+ int highestLevel = -1;
+ for (String enchname : enchants.getKeySet()) {
+ int level = enchants.getInteger(enchname);
+ if (level > highestLevel) {
+ display = EnumChatFormatting.BLUE + WordUtils.capitalizeFully(enchname
+ .replace("_", " ")
+ .replace("Ultimate", "")
+ .trim()) + " " + level;
+ }
+ }
+ }
+ }
+
+ itemValues.put(display, worth);
+ } else {
+ if (totalValue != -1) {
+ missingItem = internal;
+ }
+ totalValue = -1;
+ }
+ }
+ }
+
+ NumberFormat format = NumberFormat.getInstance(Locale.US);
+ String valueStringBIN1;
+ String valueStringBIN2;
+ if (totalValue >= 0) {
+ valueStringBIN1 = EnumChatFormatting.YELLOW + "Value (BIN): ";
+ valueStringBIN2 = EnumChatFormatting.GOLD + format.format(totalValue) + " coins";
+ } else {
+ valueStringBIN1 = EnumChatFormatting.YELLOW + "Can't find BIN: ";
+ valueStringBIN2 = missingItem;
+ }
+
+ int profitLossBIN = totalValue - chestCost;
+ String profitPrefix = EnumChatFormatting.DARK_GREEN.toString();
+ String lossPrefix = EnumChatFormatting.RED.toString();
+ String prefix = profitLossBIN >= 0 ? profitPrefix : lossPrefix;
+
+ String plStringBIN;
+ if (profitLossBIN >= 0) {
+ plStringBIN = prefix + "+" + format.format(profitLossBIN) + " coins";
+ } else {
+ plStringBIN = prefix + "-" + format.format(-profitLossBIN) + " coins";
+ }
+
+ String neu = EnumChatFormatting.YELLOW + "[NEU] ";
+
+ newTooltip.add(neu + valueStringBIN1 + " " + valueStringBIN2);
+ if (totalValue >= 0) {
+ newTooltip.add(neu + EnumChatFormatting.YELLOW + "Profit/Loss: " + plStringBIN);
+ }
+
+ for (Map.Entry<String, Double> entry : itemValues.entrySet()) {
+ newTooltip.add(neu + entry.getKey() + prefix + "+" + format.format(entry.getValue().intValue()));
+ }
+ }
+ }
+
+ index++;
+ }
+
+
+ pressedShiftLast = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
+ pressedArrowLast = Keyboard.isKeyDown(Keyboard.KEY_LEFT) || Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
+
+ event.toolTip.clear();
+ event.toolTip.addAll(newTooltip);
+
+ if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.showPriceInfoInvItem) {
+ ItemPriceInformation.addToTooltip(event.toolTip, internalName, event.itemStack);
+ }
+
+ if (event.itemStack.getTagCompound() != null && event.itemStack.getTagCompound().getBoolean("NEUHIDEPETTOOLTIP") &&
+ NotEnoughUpdates.INSTANCE.config.petOverlay.hidePetTooltip) {
+ event.toolTip.clear();
+ }
+ }
+
+ private void petToolTipXPExtendPetMenu(ItemTooltipEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.tooltipTweaks.petExtendExp) return;
+ //7 is just a random number i chose, prob no pets with less lines than 7
+ if (event.toolTip.size() < 7) return;
+ if (event.itemStack.getTagCompound().hasKey("NEUHIDEPETTOOLTIP")) return;
+ if (Utils.cleanColour(event.toolTip.get(1)).matches(petToolTipRegex)) {
+ GuiProfileViewer.PetLevel petLevel;
+
+ int xpLine = -1;
+ for (int i = event.toolTip.size() - 1; i >= 0; i--) {
+ Matcher matcher = xpLevelPattern.matcher(event.toolTip.get(i));
+ if (matcher.matches()) {
+ xpLine = i;
+ event.toolTip.set(xpLine, matcher.group(1));
+ break;
+ } else if (event.toolTip.get(i).matches("MAX LEVEL")) {
+ return;
+ }
+ }
+
+ PetInfoOverlay.Pet pet = PetInfoOverlay.getPetFromStack(
+ event.itemStack.getTagCompound()
+ );
+ if (pet == null) {
+ return;
+ }
+ petLevel = pet.petLevel;
+
+ if (petLevel == null || xpLine == -1) {
+ return;
+ }
+
+ event.toolTip.add(
+ xpLine + 1,
+ EnumChatFormatting.GRAY + "EXP: " + EnumChatFormatting.YELLOW + myFormatter.format(petLevel.levelXp) +
+ EnumChatFormatting.GOLD + "/" + EnumChatFormatting.YELLOW +
+ myFormatter.format(petLevel.currentLevelRequirement)
+ );
+
+ }
+ }
+
+ /**
+ * This method does the following:
+ * Remove reforge stats for Legendary items from Hypixel if enabled
+ * Show NBT data when holding LCONTROL
+ */
+ @SubscribeEvent
+ public void onItemTooltip(ItemTooltipEvent event) {
+ if (!neu.isOnSkyblock()) return;
+ if (event.toolTip == null) return;
+
+ if (event.toolTip.size() > 2 && NotEnoughUpdates.INSTANCE.config.tooltipTweaks.hideDefaultReforgeStats) {
+ String secondLine = StringUtils.cleanColour(event.toolTip.get(1));
+ if (secondLine.equals("Reforge Stone")) {
+ Integer startIndex = null;
+ Integer cutoffIndex = null;
+ //loop from the back of the List to find the wanted index sooner
+ for (int i = event.toolTip.size() - 1; i >= 0; i--) {
+ //rarity or mining level requirement
+ String line = StringUtils.cleanColour(event.toolTip.get(i));
+ if (line.contains("REFORGE STONE") || line.contains("Requires Mining Skill Level")) {
+ cutoffIndex = i;
+ }
+
+ //The line where the Hypixel stats start
+ if (line.contains("(Legendary):")) {
+ startIndex = i;
+ break;
+ }
+ }
+ if (startIndex != null && cutoffIndex != null && startIndex < cutoffIndex) {
+ event.toolTip.subList(startIndex, cutoffIndex).clear();
+ }
+ }
+ }
+
+ if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) && NotEnoughUpdates.INSTANCE.config.hidden.dev &&
+ event.toolTip.size() > 0 && event.toolTip.get(event.toolTip.size() - 1).startsWith(
+ EnumChatFormatting.DARK_GRAY + "NBT: ")) {
+ event.toolTip.remove(event.toolTip.size() - 1);
+
+ StringBuilder sb = new StringBuilder();
+ String nbt = event.itemStack.getTagCompound().toString();
+ int indent = 0;
+ for (char c : nbt.toCharArray()) {
+ boolean newline = false;
+ if (c == '{' || c == '[') {
+ indent++;
+ newline = true;
+ } else if (c == '}' || c == ']') {
+ indent--;
+ sb.append("\n");
+ for (int i = 0; i < indent; i++) sb.append(" ");
+ } else if (c == ',') {
+ newline = true;
+ } else if (c == '\"') {
+ sb.append(EnumChatFormatting.RESET).append(EnumChatFormatting.GRAY);
+ }
+
+ sb.append(c);
+ if (newline) {
+ sb.append("\n");
+ for (int i = 0; i < indent; i++) sb.append(" ");
+ }
+ }
+ event.toolTip.add(sb.toString());
+ if (Keyboard.isKeyDown(Keyboard.KEY_H)) {
+ if (!copied) {
+ copied = true;
+ StringSelection selection = new StringSelection(sb.toString());
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
+ }
+ } else {
+ copied = false;
+ }
+ } else if (NotEnoughUpdates.INSTANCE.packDevEnabled) {
+ event.toolTip.add("");
+ event.toolTip.add(EnumChatFormatting.AQUA + "NEU Pack Dev Info:");
+ event.toolTip.add(
+ EnumChatFormatting.GRAY + "Press " + EnumChatFormatting.GOLD + "[KEY]" + EnumChatFormatting.GRAY +
+ " to copy line");
+
+ String internal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(event.itemStack);
+
+ boolean k = Keyboard.isKeyDown(Keyboard.KEY_K);
+ boolean m = Keyboard.isKeyDown(Keyboard.KEY_M);
+ boolean n = Keyboard.isKeyDown(Keyboard.KEY_N);
+ boolean f = Keyboard.isKeyDown(Keyboard.KEY_F);
+
+ if (!copied && f && NotEnoughUpdates.INSTANCE.config.hidden.dev) {
+ MiscUtils.copyToClipboard(NotEnoughUpdates.INSTANCE.manager.getSkullValueForItem(event.itemStack));
+ }
+
+
+ event.toolTip.add(
+ EnumChatFormatting.AQUA + "Internal Name: " + EnumChatFormatting.GRAY + internal + EnumChatFormatting.GOLD +
+ " [K]");
+ if (!copied && k) {
+ MiscUtils.copyToClipboard(internal);
+ }
+
+ if (event.itemStack.getTagCompound() != null) {
+ NBTTagCompound tag = event.itemStack.getTagCompound();
+
+ if (tag.hasKey("SkullOwner", 10)) {
+ GameProfile gameprofile = NBTUtil.readGameProfileFromNBT(tag.getCompoundTag("SkullOwner"));
+
+ if (gameprofile != null) {
+ event.toolTip.add(EnumChatFormatting.AQUA + "Skull UUID: " + EnumChatFormatting.GRAY + gameprofile.getId() +
+ EnumChatFormatting.GOLD + " [M]");
+ if (!copied && m) {
+ MiscUtils.copyToClipboard(gameprofile.getId().toString());
+ }
+
+ Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> map =
+ Minecraft.getMinecraft().getSkinManager().loadSkinFromCache(gameprofile);
+
+ if (map.containsKey(MinecraftProfileTexture.Type.SKIN)) {
+ MinecraftProfileTexture profTex = map.get(MinecraftProfileTexture.Type.SKIN);
+ event.toolTip.add(
+ EnumChatFormatting.AQUA + "Skull Texture Link: " + EnumChatFormatting.GRAY + profTex.getUrl() +
+ EnumChatFormatting.GOLD + " [N]");
+
+ if (!copied && n) {
+ MiscUtils.copyToClipboard(profTex.getUrl());
+ }
+ }
+ }
+ }
+ }
+
+ copied = k || m || n || f;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java
new file mode 100644
index 00000000..fdae53ea
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ItemTooltipRngListener.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.util.Calculator;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.ItemResolutionQuery;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ItemTooltipRngListener {
+ private final NotEnoughUpdates neu;
+ private boolean showSlayerRngFractions = false;
+ private boolean pressedShiftLast = false;
+ private int currentSelected = 0;
+ private boolean pressedArrowLast = false;
+ private boolean repoReloadNeeded = true;
+
+ private final Pattern ODDS_PATTERN = Pattern.compile("§5§o§7Odds: (.+) §7\\(§7(.*)%\\)");
+ private final Pattern ODDS_SELECTED_PATTERN = Pattern.compile("§5§o§7Odds: (.+) §7\\(§8§m(.*)%§r §7(.+)%\\)");
+
+ private final Pattern RUNS_PATTERN = Pattern.compile("§5§o§7(Dungeon Score|Slayer XP): §d(.*)§5/§d(.+)");
+ private final Pattern RUNS_SELECTED_PATTERN = Pattern.compile("§5§o§d-(.+)- §d(.*)§5/§d(.+)");
+
+ private final Pattern SLAYER_INVENTORY_TITLE_PATTERN = Pattern.compile("(.+) RNG Meter");
+
+ private final Map<String, Integer> dungeonData = new LinkedHashMap<>();
+ private final Map<String, LinkedHashMap<String, Integer>> slayerData = new LinkedHashMap<>();
+
+ public ItemTooltipRngListener(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ @SubscribeEvent
+ public void onItemTooltip(ItemTooltipEvent event) {
+ if (!neu.isOnSkyblock()) return;
+ if (event.toolTip == null) return;
+ if (!Utils.getOpenChestName().endsWith(" RNG Meter") && !slayerData.containsKey(Utils.getOpenChestName())) return;
+
+ List<String> newToolTip = new ArrayList<>();
+
+ boolean nextLineProgress = false;
+ for (String line : event.toolTip) {
+
+ if (line.contains("Odds:")) {
+ if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.rngMeterFractionDisplay) {
+ fractionDisplay(newToolTip, line);
+ continue;
+ }
+ }
+
+ if (nextLineProgress || line.contains("Dungeon Score:") || line.contains("Slayer XP:")) {
+ Matcher matcher = RUNS_PATTERN.matcher(line);
+ Matcher matcherSelected = RUNS_SELECTED_PATTERN.matcher(line);
+ Matcher m = null;
+ if (matcher.matches()) {
+ m = matcher;
+ } else if (matcherSelected.matches()) {
+ m = matcherSelected;
+ }
+
+ if (m != null) {
+ int having;
+ try {
+ having = Calculator.calculate(m.group(2).replace(",", "")).intValue();
+ } catch (Calculator.CalculatorException e) {
+ having = -1;
+ }
+
+ int needed;
+ try {
+ needed = Calculator.calculate(m.group(3).replace(",", "")).intValue();
+ } catch (Calculator.CalculatorException e) {
+ needed = -1;
+ }
+ if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.rngMeterRunsNeeded) {
+ runsRequired(newToolTip, having, needed, nextLineProgress, event.itemStack);
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.rngMeterProfitPerUnit) {
+ if (!NotEnoughUpdates.INSTANCE.config.tooltipTweaks.rngMeterRunsNeeded) {
+ String name = Utils.getOpenChestName().contains("Catacombs") ? "Score" : "XP";
+ String formatCoinsPer = getFormatCoinsPer(event.itemStack, needed, 1, name);
+ if (formatCoinsPer != null) {
+ newToolTip.add(line);
+ newToolTip.add(formatCoinsPer);
+ continue;
+ }
+ }
+ }
+ }
+ nextLineProgress = false;
+ }
+
+ if (line.contains("Progress:")) {
+ nextLineProgress = true;
+ }
+ newToolTip.add(line);
+ }
+
+ event.toolTip.clear();
+ event.toolTip.addAll(newToolTip);
+ }
+
+ private String getFormatCoinsPer(ItemStack stack, int needed, int multiplier, String label) {
+ String internalName = neu.manager.createItemResolutionQuery().withItemStack(stack).resolveInternalName();
+ double profit = neu.manager.auctionManager.getBazaarOrBin(internalName);
+ if (profit <= 0) return null;
+
+ //ask hypixel nicely to release a 'chest price api' with 4 dimensions for us. the 4 dimensions needed are: item name, floor, normal/mm, s/s+
+// double chestPrice = grabChestPrice(stack, internalName);
+// profit -= chestPrice;
+
+ double coinsPer = (profit / needed) * multiplier;
+ String format = StringUtils.shortNumberFormat(coinsPer);
+ return "§7Coins per " + label + ": §6" + format + " coins";
+ }
+
+ private void fractionDisplay(List<String> newToolTip, String line) {
+ boolean shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT);
+ if (!pressedShiftLast && shift) {
+ showSlayerRngFractions = !showSlayerRngFractions;
+ }
+ pressedShiftLast = shift;
+
+ String result;
+ Matcher matcher = ODDS_PATTERN.matcher(line);
+ Matcher matcherSelected = ODDS_SELECTED_PATTERN.matcher(line);
+ if (matcher.matches()) {
+ String odds = matcher.group(1);
+ int baseChance = calculateChance(matcher.group(2));
+ String baseFormat = GuiProfileViewer.numberFormat.format(baseChance);
+
+ String fractionFormat = "§7(1/" + baseFormat + ")";
+ result = odds + " " + fractionFormat;
+ } else if (matcherSelected.matches()) {
+ String odds = matcherSelected.group(1);
+ int baseChance = calculateChance(matcherSelected.group(2));
+ String baseFormat = GuiProfileViewer.numberFormat.format(baseChance);
+
+ int increasedChance = calculateChance(matcherSelected.group(3));
+ String increased = GuiProfileViewer.numberFormat.format(increasedChance);
+ String fractionFormat = "§7(§8§m1/" + baseFormat + "§r §71/" + increased + ")";
+
+ result = odds + " " + fractionFormat;
+ } else {
+ return;
+ }
+
+ if (showSlayerRngFractions) {
+ newToolTip.add("§7Odds: " + result);
+ newToolTip.add("§8[Press SHIFT to show odds as percentages]");
+ } else {
+ newToolTip.add(line);
+ newToolTip.add("§8[Press SHIFT to show odds as fractions]");
+ }
+ }
+
+ /**
+ * This adds support for the /neureloadrepo command
+ */
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ public void onRepoReload(RepositoryReloadEvent event) {
+ repoReloadNeeded = true;
+ }
+
+ public void checkUpdateData() {
+ if (repoReloadNeeded) {
+ updateRepoData();
+ }
+ }
+
+ private void updateRepoData() {
+ slayerData.clear();
+ dungeonData.clear();
+
+ JsonObject leveling = Constants.LEVELING;
+ if (!leveling.has("slayer_boss_xp") ||
+ !leveling.has("slayer_highest_tier") ||
+ !leveling.has("slayer_tier_colors") ||
+ !leveling.has("rng_meter_dungeon_score")) {
+ Utils.showOutdatedRepoNotification();
+ return;
+ }
+
+ List<Integer> slayerExp = new ArrayList<>();
+ for (JsonElement element : leveling.get("slayer_boss_xp").getAsJsonArray()) {
+ slayerExp.add(element.getAsInt());
+ }
+
+ List<String> slayerColors = new ArrayList<>();
+ for (JsonElement element : leveling.get("slayer_tier_colors").getAsJsonArray()) {
+ slayerColors.add(element.getAsString());
+ }
+
+ for (Map.Entry<String, JsonElement> entry : leveling.get("slayer_highest_tier").getAsJsonObject().entrySet()) {
+ String slayerName = entry.getKey();
+ int maxTier = entry.getValue().getAsInt();
+ LinkedHashMap<String, Integer> singleSlayerData = new LinkedHashMap<>();
+ for (int i = 0; i < maxTier; i++) {
+ String name = slayerColors.get(i) + "Tier " + (i + 1);
+ singleSlayerData.put(name, slayerExp.get(i));
+ }
+ slayerData.put(slayerName, singleSlayerData);
+ }
+
+ for (Map.Entry<String, JsonElement> entry : leveling.get("rng_meter_dungeon_score").getAsJsonObject().entrySet()) {
+ String dungeonScore = entry.getKey();
+ int score = entry.getValue().getAsInt();
+ dungeonData.put(dungeonScore, score);
+ }
+
+ repoReloadNeeded = false;
+ }
+
+ private void runsRequired(
+ List<String> toolTip,
+ int having,
+ int needed,
+ boolean nextLineProgress,
+ ItemStack stack
+ ) {
+ checkUpdateData();
+ if (repoReloadNeeded) return;
+
+ String openChestName = Utils.getOpenChestName();
+ Map<String, Integer> runsData;
+ String labelPlural;
+ String labelSingular;
+ String repoCategory;
+ if (openChestName.contains("Catacombs")) {
+ runsData = dungeonData;
+ labelPlural = "Runs";
+ labelSingular = "Run";
+ repoCategory = "catacombs";
+ } else { // Slayer
+ Matcher matcher = SLAYER_INVENTORY_TITLE_PATTERN.matcher(openChestName);
+ if (!matcher.matches()) {
+ //Happens for the first 4-5 ticks after inventory opens. Thanks hypixel
+ return;
+ }
+
+ String slayerName = matcher.group(1);
+ runsData = slayerData.get(slayerName);
+ labelPlural = "Bosses";
+ labelSingular = "Boss";
+ repoCategory = "slayer";
+ }
+
+ int repoScore = getRepoScore(stack, repoCategory);
+ if (repoScore != -1) {
+ needed = repoScore;
+ }
+
+ handleArrowKeys(runsData);
+
+ if (currentSelected >= runsData.keySet().size()) {
+ currentSelected = 0;
+ }
+
+ String name = (String) runsData.keySet().toArray()[currentSelected];
+ int gainPerRun = runsData.get(name);
+
+ int runsNeeded = (int) Math.floor((double) needed / (double) gainPerRun);
+ int runsHaving = having / gainPerRun;
+ String runsNeededFormat = GuiProfileViewer.numberFormat.format(runsNeeded);
+ String runsHavingFormat = GuiProfileViewer.numberFormat.format(runsHaving);
+
+ String progressString = null;
+ if (nextLineProgress) {
+ progressString = toolTip.remove(toolTip.size() - 1);
+ }
+
+ toolTip.add("§9Stats for " + name + "§9: [§l§m< §9Switch§l➡§9]");
+ toolTip.add(
+ " §7" + labelPlural + " completed: §e" + runsHavingFormat + " §7(of §e" + runsNeededFormat + " §7needed)");
+
+ if (NotEnoughUpdates.INSTANCE.config.tooltipTweaks.rngMeterProfitPerUnit) {
+ String formatCoinsPer = getFormatCoinsPer(stack, needed, gainPerRun, labelSingular);
+ if (formatCoinsPer != null) {
+ toolTip.add(" " + formatCoinsPer);
+ }
+ }
+
+ toolTip.add(" ");
+ if (progressString != null) {
+ toolTip.add(progressString);
+ }
+ }
+
+ private int getRepoScore(ItemStack stack, String repoCategory) {
+ ItemResolutionQuery query =
+ NotEnoughUpdates.INSTANCE.manager.createItemResolutionQuery().withItemStack(stack).withCurrentGuiContext();
+ String internalName = query.resolveInternalName();
+
+ JsonObject jsonObject = Constants.RNGSCORE;
+ if (jsonObject == null) {
+ Utils.showOutdatedRepoNotification();
+ return -1;
+ }
+
+ String repoType = grabRepoType(stack);
+ if (!jsonObject.has(repoCategory)) return -1;
+
+ JsonObject category = jsonObject.get(repoCategory).getAsJsonObject();
+ if (!category.has(repoType)) return -1;
+
+ JsonObject typeObject = category.get(repoType).getAsJsonObject();
+ if (!typeObject.has(internalName)) return -1;
+
+ return typeObject.get(internalName).getAsInt();
+ }
+
+ // Determines the floor or the slayer type from where the item can be obtained. E.g. F7, M3, Revenant Horror or Sven Packmaster
+ private String grabRepoType(ItemStack stack) {
+ String openChestName = Utils.getOpenChestName();
+ if (openChestName.contains("Catacombs")) {
+ if (openChestName.equals("Catacombs RNG Meter")) {
+ List<String> list = ItemUtils.getLore(stack);
+ String line = list.get(4);
+ return line.substring(26, 28);
+ } else {
+ // supporting more pages (f7/m7)
+ if (openChestName.contains("(")) {
+ return openChestName.substring(17, 19);
+ }
+ return openChestName.substring(11, 13);
+ }
+ } else {
+ return openChestName.substring(0, openChestName.length() - 9);
+ }
+ }
+
+ private void handleArrowKeys(Map<String, Integer> runsData) {
+ boolean left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
+ boolean right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
+ if (!pressedArrowLast && (left || right)) {
+ if (Utils.getOpenChestName().contains("Catacombs") ? right : left) {
+ currentSelected--;
+ } else {
+ currentSelected++;
+ }
+ if (currentSelected < 0) currentSelected = 0;
+ if (currentSelected >= runsData.size()) currentSelected = runsData.size() - 1;
+ }
+ pressedArrowLast = left || right;
+ }
+
+ private int calculateChance(String string) {
+ return (int) (100.0 / Double.parseDouble(string));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java
new file mode 100644
index 00000000..e202b828
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/NEUEventListener.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.BackgroundBlur;
+import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
+import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks;
+import io.github.moulberry.notenoughupdates.dungeons.DungeonWin;
+import io.github.moulberry.notenoughupdates.miscfeatures.CookieWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalOverlay;
+import io.github.moulberry.notenoughupdates.miscfeatures.FairySouls;
+import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
+import io.github.moulberry.notenoughupdates.miscfeatures.NPCRetexturing;
+import io.github.moulberry.notenoughupdates.miscgui.AccessoryBagOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.GuiCustomEnchant;
+import io.github.moulberry.notenoughupdates.miscgui.hex.GuiCustomHex;
+import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay;
+import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
+import io.github.moulberry.notenoughupdates.overlays.TextOverlay;
+import io.github.moulberry.notenoughupdates.overlays.TextTabOverlay;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import io.github.moulberry.notenoughupdates.util.ProfileApiSyncer;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import io.github.moulberry.notenoughupdates.util.XPInformation;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.init.Items;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class NEUEventListener {
+
+ private final NotEnoughUpdates neu;
+ private final ExecutorService itemPreloader = Executors.newFixedThreadPool(10);
+ private final List<ItemStack> toPreload = new ArrayList<>();
+ private boolean joinedSB = false;
+
+ private boolean preloadedItems = false;
+ private long lastLongUpdate = 0;
+ private long lastSkyblockScoreboard = 0;
+
+ public NEUEventListener(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ @SubscribeEvent
+ public void onWorldLoad(WorldEvent.Unload event) {
+ NotEnoughUpdates.INSTANCE.saveConfig();
+ CrystalMetalDetectorSolver.initWorld();
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+ if (Minecraft.getMinecraft().theWorld == null) return;
+ if (Minecraft.getMinecraft().thePlayer == null) return;
+
+ if ((Keyboard.isKeyDown(Keyboard.KEY_NUMPAD1) && Keyboard.isKeyDown(Keyboard.KEY_NUMPAD4) && Keyboard.isKeyDown(
+ Keyboard.KEY_NUMPAD9))) {
+ ChatComponentText component = new ChatComponentText("\u00a7cYou are permanently banned from this server!");
+ component.appendText("\n");
+ component.appendText("\n\u00a77Reason: \u00a7rSuspicious account activity/Other");
+ component.appendText("\n\u00a77Find out more: \u00a7b\u00a7nhttps://www.hypixel.net/appeal");
+ component.appendText("\n");
+ component.appendText("\n\u00a77Ban ID: \u00a7r#49871982");
+ component.appendText("\n\u00a77Sharing your Ban ID may affect the processing of your appeal!");
+ Minecraft.getMinecraft().getNetHandler().getNetworkManager().closeChannel(component);
+ return;
+ }
+
+ if (neu.hasSkyblockScoreboard()) {
+ if (!preloadedItems) {
+ preloadedItems = true;
+ List<JsonObject> list = new ArrayList<>(neu.manager.getItemInformation().values());
+ for (JsonObject json : list) {
+ itemPreloader.submit(() -> {
+ ItemStack stack = neu.manager.jsonToStack(json, true, true);
+ if (stack.getItem() == Items.skull) toPreload.add(stack);
+ });
+ }
+ } else if (!toPreload.isEmpty()) {
+ Utils.drawItemStack(toPreload.get(0), -100, -100);
+ toPreload.remove(0);
+ } else {
+ itemPreloader.shutdown();
+ }
+
+ for (TextOverlay overlay : OverlayManager.textOverlays) {
+ overlay.shouldUpdateFrequent = true;
+ }
+ }
+
+ boolean longUpdate = false;
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - lastLongUpdate > 1000) {
+ longUpdate = true;
+ lastLongUpdate = currentTime;
+ }
+ if (!NotEnoughUpdates.INSTANCE.config.dungeons.slowDungeonBlocks) {
+ DungeonBlocks.tick();
+ }
+ DungeonWin.tick();
+
+ String containerName = null;
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
+
+ if (GuiCustomEnchant.getInstance().shouldOverride(containerName)) {
+ GuiCustomEnchant.getInstance().tick();
+ }
+ if (GuiCustomHex.getInstance().shouldOverride(containerName)) {
+ GuiCustomHex.getInstance().tick(containerName);
+ }
+ }
+
+ //MiningOverlay and TimersOverlay need real tick speed
+ if (neu.hasSkyblockScoreboard()) {
+ for (TextOverlay overlay : OverlayManager.textOverlays) {
+ if (overlay instanceof TextTabOverlay) {
+ TextTabOverlay skillOverlay = (TextTabOverlay) overlay;
+ skillOverlay.realTick();
+ }
+ }
+ }
+
+
+ if (longUpdate) {
+ CrystalOverlay.tick();
+ FairySouls.getInstance().tick();
+ XPInformation.getInstance().tick();
+ ProfileApiSyncer.getInstance().tick();
+ ItemCustomizeManager.tick();
+ BackgroundBlur.markDirty();
+ NPCRetexturing.getInstance().tick();
+ StorageOverlay.getInstance().markDirty();
+ CookieWarning.checkCookie();
+
+ if (neu.hasSkyblockScoreboard()) {
+ for (TextOverlay overlay : OverlayManager.textOverlays) {
+ overlay.tick();
+ }
+ }
+
+ NotEnoughUpdates.INSTANCE.overlay.redrawItems();
+ CapeManager.onTickSlow();
+
+ NotEnoughUpdates.profileViewer.putNameUuid(
+ Minecraft.getMinecraft().thePlayer.getName(),
+ Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", "")
+ );
+
+ if (NotEnoughUpdates.INSTANCE.config.dungeons.slowDungeonBlocks) {
+ DungeonBlocks.tick();
+ }
+
+ if (System.currentTimeMillis() - SBInfo.getInstance().joinedWorld > 500 &&
+ System.currentTimeMillis() - SBInfo.getInstance().unloadedWorld > 500) {
+ neu.updateSkyblockScoreboard();
+ }
+ CapeManager.getInstance().tick();
+
+ if (containerName != null) {
+ if (!containerName.trim().startsWith("Accessory Bag")) {
+ AccessoryBagOverlay.resetCache();
+ }
+ } else {
+ AccessoryBagOverlay.resetCache();
+ }
+
+ if (neu.hasSkyblockScoreboard()) {
+ SBInfo.getInstance().tick();
+ lastSkyblockScoreboard = currentTime;
+ if (!joinedSB) {
+ joinedSB = true;
+
+ if (NotEnoughUpdates.INSTANCE.config.notifications.updateChannel != 0) {
+ NotEnoughUpdates.INSTANCE.autoUpdater.displayUpdateMessageIfOutOfDate();
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.notifications.doRamNotif) {
+ long maxMemoryMB = Runtime.getRuntime().maxMemory() / 1024L / 1024L;
+ if (maxMemoryMB > 4100) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ EnumChatFormatting.GRAY + "Too much memory allocated!",
+ String.format(
+ EnumChatFormatting.DARK_GRAY + "NEU has detected %03dMB of memory allocated to Minecraft!",
+ maxMemoryMB
+ ),
+ EnumChatFormatting.GRAY + "It is recommended to allocated between 2-4GB of memory",
+ EnumChatFormatting.GRAY + "More than 4GB MAY cause FPS issues, EVEN if you have 16GB+ available",
+ EnumChatFormatting.GRAY + "For more information, visit #ram-info in discord.gg/moulberry",
+ "",
+ EnumChatFormatting.GRAY + "Press X on your keyboard to close this notification"
+ ), false);
+ }
+ }
+
+ if (!NotEnoughUpdates.INSTANCE.config.hidden.loadedModBefore) {
+ NotEnoughUpdates.INSTANCE.config.hidden.loadedModBefore = true;
+ if (Constants.MISC == null || !Constants.MISC.has("featureslist")) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "" + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + "WARNING: " + EnumChatFormatting.RESET +
+ EnumChatFormatting.RED + "Could not load Feature List URL from repo."));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "" + EnumChatFormatting.RED + "Please run " + EnumChatFormatting.BOLD + "/neuresetrepo" +
+ EnumChatFormatting.RESET + EnumChatFormatting.RED + " and " + EnumChatFormatting.BOLD +
+ "restart your game" + EnumChatFormatting.RESET + EnumChatFormatting.RED + " in order to fix. " +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + "If that doesn't fix it" +
+ EnumChatFormatting.RESET + EnumChatFormatting.RED +
+ ", please join discord.gg/moulberry and post in #neu-support"));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "" + EnumChatFormatting.GOLD + "To view the feature list after restarting type /neufeatures"));
+ } else {
+ String url = Constants.MISC.get("featureslist").getAsString();
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.BLUE + "It seems this is your first time using NotEnoughUpdates."));
+ ChatComponentText clickTextFeatures = new ChatComponentText(EnumChatFormatting.YELLOW +
+ "Click this message if you would like to view a list of NotEnoughUpdate's Features.");
+ clickTextFeatures.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, url));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(clickTextFeatures);
+ }
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+ ChatComponentText clickTextHelp = new ChatComponentText(EnumChatFormatting.YELLOW +
+ "Click this message if you would like to view a list of NotEnoughUpdate's commands.");
+ clickTextHelp.setChatStyle(Utils.createClickStyle(ClickEvent.Action.RUN_COMMAND, "/neuhelp"));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(clickTextHelp);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(""));
+ }
+ }
+ }
+ if (currentTime - lastSkyblockScoreboard < 5 * 60 * 1000) { //5 minutes
+ neu.manager.auctionManager.tick();
+ } else {
+ neu.manager.auctionManager.markNeedsUpdate();
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/OldAnimationChecker.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/OldAnimationChecker.java
new file mode 100644
index 00000000..7858918b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/OldAnimationChecker.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import com.google.common.collect.Lists;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.Loader;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class OldAnimationChecker {
+
+ private void unregister() {
+ MinecraftForge.EVENT_BUS.unregister(this);
+ }
+
+ @SubscribeEvent
+ public void onWorldLoad(WorldEvent.Load event) {
+ if (!NotEnoughUpdates.INSTANCE.config.notifications.doOamNotif) {
+ unregister();
+ return;
+ }
+ boolean oldAnimations = false;
+ if (Loader.isModLoaded("animations")) {
+ oldAnimations = true;
+ } else {
+ try {
+ Class.forName("com.spiderfrog.oldanimations.OldAnimationsMod");
+ //previous statement would throw if not present
+ oldAnimations = true;
+ } catch (ClassNotFoundException ignored) {
+ }
+ }
+
+ if (oldAnimations) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ "\u00a74Old animations warning",
+ "\u00a77You use a old animations mod from Orange or spiderfrog",
+ "\u00a77These mods break features in NEU and other mods",
+ "\u00a77Please remove them and optionally replace them with the OldAnimations mod from Sk1er",
+ "\u00a77It can be found at the following website: \u00a79sk1er.club/beta",
+ "\u00a77For more information join the discord at \u00a79discord.gg/moulberry\u00a77 and message in \u00a79#neu-support",
+ "\u00a77",
+ "\u00a77Press X on your keyboard to close this notification or turn it off in the config"
+ ), true, true);
+ unregister();
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
new file mode 100644
index 00000000..6460e1ed
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/RenderListener.java
@@ -0,0 +1,1718 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import com.google.common.collect.Lists;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUApi;
+import io.github.moulberry.notenoughupdates.NEUOverlay;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.auction.CustomAHGui;
+import io.github.moulberry.notenoughupdates.commands.profile.ViewProfileCommand;
+import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
+import io.github.moulberry.notenoughupdates.dungeons.DungeonWin;
+import io.github.moulberry.notenoughupdates.itemeditor.NEUItemEditor;
+import io.github.moulberry.notenoughupdates.miscfeatures.AbiphoneWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.AuctionBINWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.AuctionProfit;
+import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
+import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
+import io.github.moulberry.notenoughupdates.miscgui.AccessoryBagOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.GuiCustomEnchant;
+import io.github.moulberry.notenoughupdates.miscgui.GuiInvButtonEditor;
+import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
+import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.TradeWindow;
+import io.github.moulberry.notenoughupdates.miscgui.TrophyRewardOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.hex.GuiCustomHex;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.overlays.AuctionSearchOverlay;
+import io.github.moulberry.notenoughupdates.overlays.BazaarSearchOverlay;
+import io.github.moulberry.notenoughupdates.overlays.EquipmentOverlay;
+import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
+import io.github.moulberry.notenoughupdates.overlays.RancherBootOverlay;
+import io.github.moulberry.notenoughupdates.overlays.TextOverlay;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import io.github.moulberry.notenoughupdates.util.RequestFocusListener;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.gui.inventory.GuiContainer;
+import net.minecraft.client.gui.inventory.GuiEditSign;
+import net.minecraft.client.gui.inventory.GuiInventory;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.StringUtils;
+import net.minecraftforge.client.ClientCommandHandler;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.client.event.RenderGameOverlayEvent;
+import net.minecraftforge.client.event.RenderLivingEvent;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.apache.commons.lang3.text.WordUtils;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import javax.swing.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.dungeon_chest_worth;
+
+public class RenderListener {
+ private static final ResourceLocation EDITOR = new ResourceLocation("notenoughupdates:invbuttons/editor.png");
+ public static boolean disableCraftingText = false;
+ public static boolean drawingGuiScreen = false;
+ public static long lastGuiClosed = 0;
+ public static boolean inventoryLoaded = false;
+ private final NotEnoughUpdates neu;
+ ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
+ JsonObject essenceJson = new JsonObject();
+ private boolean hoverInv = false;
+ private boolean focusInv = false;
+ private boolean doInventoryButtons = false;
+ private NEUConfig.InventoryButton buttonHovered = null;
+ private long buttonHoveredMillis = 0;
+ private int inventoryLoadedTicks = 0;
+ private String loadedInvName = "";
+ //NPC parsing
+ private String correctingItem;
+ private boolean typing;
+ private HashMap<String, String> cachedDefinitions;
+ private boolean inDungeonPage = false;
+ private final NumberFormat format = new DecimalFormat("#,##0.#", new DecimalFormatSymbols(Locale.US));
+
+ private final Pattern ESSENCE_PATTERN = Pattern.compile("§d(.+) Essence §8x([\\d,]+)");
+
+ public RenderListener(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ @SubscribeEvent(priority = EventPriority.HIGHEST)
+ public void onRenderEntitySpecials(RenderLivingEvent.Specials.Pre<EntityPlayer> event) {
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiProfileViewer) {
+ if (((GuiProfileViewer) Minecraft.getMinecraft().currentScreen).getEntityPlayer() == event.entity) {
+ event.setCanceled(true);
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onRenderGameOverlayPre(RenderGameOverlayEvent.Pre event) {
+ if (event.type != null && event.type.equals(RenderGameOverlayEvent.ElementType.BOSSHEALTH) &&
+ Minecraft.getMinecraft().currentScreen instanceof GuiContainer && neu.overlay.isUsingMobsFilter()) {
+ event.setCanceled(true);
+ }
+ if (event.type != null && event.type.equals(RenderGameOverlayEvent.ElementType.PLAYER_LIST)) {
+ GlStateManager.enableDepth();
+ }
+ }
+
+ @SubscribeEvent
+ public void onRenderGameOverlayPost(RenderGameOverlayEvent.Post event) {
+ if (neu.hasSkyblockScoreboard() && event.type.equals(RenderGameOverlayEvent.ElementType.ALL)) {
+ DungeonWin.render(event.partialTicks);
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, 0, -200);
+ for (TextOverlay overlay : OverlayManager.textOverlays) {
+ if (OverlayManager.dontRenderOverlay != null &&
+ OverlayManager.dontRenderOverlay.isAssignableFrom(overlay.getClass())) {
+ continue;
+ }
+ GlStateManager.translate(0, 0, -1);
+ GlStateManager.enableDepth();
+ overlay.render();
+ }
+ GlStateManager.popMatrix();
+ OverlayManager.dontRenderOverlay = null;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_X)) {
+ NotificationHandler.notificationDisplayMillis = 0;
+ }
+
+ if (event.type == RenderGameOverlayEvent.ElementType.ALL) {
+ NotificationHandler.renderNotification();
+ }
+
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+ if (Minecraft.getMinecraft().theWorld == null) return;
+ if (Minecraft.getMinecraft().thePlayer == null) return;
+
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ if (!loadedInvName.equals(cc.getLowerChestInventory().getDisplayName().getUnformattedText())) {
+ loadedInvName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
+ inventoryLoaded = false;
+ inventoryLoadedTicks = 3;
+ }
+
+ if (!inventoryLoaded) {
+ if (cc.getLowerChestInventory().getStackInSlot(cc.getLowerChestInventory().getSizeInventory() - 1) != null) {
+ inventoryLoaded = true;
+ } else {
+ for (ItemStack stack : chest.inventorySlots.getInventory()) {
+ if (stack != null) {
+ if (--inventoryLoadedTicks <= 0) {
+ inventoryLoaded = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ inventoryLoaded = false;
+ inventoryLoadedTicks = 3;
+ }
+
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ NEUApi.disableInventoryButtons = false;
+
+ if ((Minecraft.getMinecraft().currentScreen instanceof GuiScreenElementWrapper ||
+ Minecraft.getMinecraft().currentScreen instanceof GuiItemRecipe) && event.gui == null &&
+ !(Keyboard.getEventKeyState() && Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) &&
+ System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.lastOpenedGui < 500) {
+ NotEnoughUpdates.INSTANCE.lastOpenedGui = 0;
+ event.setCanceled(true);
+ return;
+ }
+
+ if (!(event.gui instanceof GuiContainer) && Minecraft.getMinecraft().currentScreen != null) {
+ CalendarOverlay.setEnabled(false);
+ }
+
+ if (Minecraft.getMinecraft().currentScreen != null) {
+ lastGuiClosed = System.currentTimeMillis();
+ }
+
+ neu.manager.auctionManager.customAH.lastGuiScreenSwitch = System.currentTimeMillis();
+ BetterContainers.reset();
+ inventoryLoaded = false;
+ inventoryLoadedTicks = 3;
+
+ if (event.gui == null && neu.manager.auctionManager.customAH.isRenderOverAuctionView() &&
+ !(Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)) {
+ event.gui = new CustomAHGui();
+ }
+
+ if (!(event.gui instanceof GuiChest || event.gui instanceof GuiEditSign)) {
+ neu.manager.auctionManager.customAH.setRenderOverAuctionView(false);
+ } else if (event.gui instanceof GuiChest && (neu.manager.auctionManager.customAH.isRenderOverAuctionView() ||
+ Minecraft.getMinecraft().currentScreen instanceof CustomAHGui)) {
+ GuiChest chest = (GuiChest) event.gui;
+ ContainerChest container = (ContainerChest) chest.inventorySlots;
+ String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
+
+ neu.manager.auctionManager.customAH.setRenderOverAuctionView(
+ containerName.trim().equals("Auction View") || containerName.trim().equals("BIN Auction View") ||
+ containerName.trim().equals("Confirm Bid") || containerName.trim().equals("Confirm Purchase"));
+ }
+
+ //OPEN
+ if (Minecraft.getMinecraft().currentScreen == null && event.gui instanceof GuiContainer) {
+ neu.overlay.reset();
+ }
+ if (event.gui != null && NotEnoughUpdates.INSTANCE.config.hidden.dev) {
+ if (event.gui instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) event.gui;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+ ses.schedule(() -> {
+ if (Minecraft.getMinecraft().currentScreen != event.gui) {
+ return;
+ }
+ if (lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) {
+ try {
+ ItemStack res = lower.getStackInSlot(25);
+ String resInternalname = neu.manager.getInternalNameForItem(res);
+
+ if (lower.getStackInSlot(48) != null) {
+ String backName = null;
+ NBTTagCompound tag = lower.getStackInSlot(48).getTagCompound();
+ if (tag.hasKey("display", 10)) {
+ NBTTagCompound nbttagcompound = tag.getCompoundTag("display");
+ if (nbttagcompound.getTagId("Lore") == 9) {
+ NBTTagList nbttaglist1 = nbttagcompound.getTagList("Lore", 8);
+ backName = nbttaglist1.getStringTagAt(0);
+ }
+ }
+
+ if (backName != null) {
+ String[] split = backName.split(" ");
+ if (split[split.length - 1].contains("Rewards")) {
+ String col = backName.substring(
+ split[0].length() + 1,
+ backName.length() - split[split.length - 1].length() - 1
+ );
+
+ JsonObject json = neu.manager.getItemInformation().get(resInternalname);
+ json.addProperty("crafttext", "Requires: " + col);
+
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "Added: " + resInternalname));
+ neu.manager.writeJsonDefaultDir(json, resInternalname + ".json");
+ neu.manager.loadItem(resInternalname);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }, 200, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+
+ /**
+ * Sets hoverInv and focusInv variables, representing whether the NEUOverlay should render behind the inventory when
+ * (hoverInv == true) and whether mouse/kbd inputs shouldn't be sent to NEUOverlay (focusInv == true).
+ * <p>
+ * If hoverInv is true, will render the overlay immediately (resulting in the inventory being drawn over the GUI)
+ * If hoverInv is false, the overlay will render in #onGuiScreenDraw (resulting in the GUI being drawn over the inv)
+ * <p>
+ * All of this only matters if players are using gui scale auto which may result in the inventory being drawn
+ * over the various panes.
+ */
+ @SubscribeEvent
+ public void onGuiBackgroundDraw(GuiScreenEvent.BackgroundDrawnEvent event) {
+ if (NotificationHandler.showNotificationOverInv) {
+
+ NotificationHandler.renderNotification();
+
+ }
+ inDungeonPage = false;
+ if ((NotificationHandler.shouldRenderOverlay(event.gui) || event.gui instanceof CustomAHGui) &&
+ neu.isOnSkyblock()) {
+ ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledresolution.getScaledWidth();
+
+ boolean hoverPane = event.getMouseX() < width * neu.overlay.getInfoPaneOffsetFactor() ||
+ event.getMouseX() > width * neu.overlay.getItemPaneOffsetFactor();
+
+ if (event.gui instanceof GuiContainer) {
+ try {
+ int xSize = ((AccessorGuiContainer) event.gui).getXSize();
+ int ySize = ((AccessorGuiContainer) event.gui).getYSize();
+ int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
+
+ hoverInv = event.getMouseX() > guiLeft && event.getMouseX() < guiLeft + xSize && event.getMouseY() > guiTop &&
+ event.getMouseY() < guiTop + ySize;
+
+ if (hoverPane) {
+ if (!hoverInv) focusInv = false;
+ } else {
+ focusInv = true;
+ }
+ } catch (NullPointerException npe) {
+ focusInv = !hoverPane;
+ }
+ }
+ if (event.gui instanceof GuiItemRecipe) {
+ GuiItemRecipe guiItemRecipe = ((GuiItemRecipe) event.gui);
+ hoverInv = event.getMouseX() > guiItemRecipe.guiLeft &&
+ event.getMouseX() < guiItemRecipe.guiLeft + guiItemRecipe.xSize && event.getMouseY() > guiItemRecipe.guiTop &&
+ event.getMouseY() < guiItemRecipe.guiTop + guiItemRecipe.ySize;
+
+ if (hoverPane) {
+ if (!hoverInv) focusInv = false;
+ } else {
+ focusInv = true;
+ }
+ }
+ if (focusInv) {
+ try {
+ neu.overlay.render(hoverInv);
+ } catch (ConcurrentModificationException e) {
+ e.printStackTrace();
+ }
+ GL11.glTranslatef(0, 0, 10);
+ }
+ if (hoverInv) {
+ renderDungKuudraChestOverlay(event.gui);
+ if (NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay) {
+ AccessoryBagOverlay.renderOverlay();
+ }
+ }
+ }
+
+ drawingGuiScreen = true;
+ }
+
+ @SubscribeEvent
+ public void onGuiScreenDrawPre(GuiScreenEvent.DrawScreenEvent.Pre event) {
+ doInventoryButtons = false;
+
+ if (AuctionSearchOverlay.shouldReplace()) {
+ AuctionSearchOverlay.render();
+ event.setCanceled(true);
+ return;
+ }
+ if (BazaarSearchOverlay.shouldReplace()) {
+ BazaarSearchOverlay.render();
+ event.setCanceled(true);
+ return;
+ }
+ if (RancherBootOverlay.shouldReplace()) {
+ RancherBootOverlay.render();
+ event.setCanceled(true);
+ return;
+ }
+
+ String containerName = null;
+ GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
+ if (guiScreen instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) guiScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
+ }
+
+ if (GuiCustomHex.getInstance().shouldOverride(containerName)) {
+ GuiCustomHex.getInstance().render(event.renderPartialTicks, containerName);
+ event.setCanceled(true);
+ return;
+ }
+
+ if (GuiCustomEnchant.getInstance().shouldOverride(containerName)) {
+ GuiCustomEnchant.getInstance().render(event.renderPartialTicks);
+ event.setCanceled(true);
+ return;
+ }
+
+
+ boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
+ boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
+ boolean customAhActive =
+ event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
+
+ if (storageOverlayActive) {
+ StorageOverlay.getInstance().render();
+ event.setCanceled(true);
+ return;
+ }
+
+ if (tradeWindowActive || customAhActive) {
+ event.setCanceled(true);
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+
+ //Dark background
+ Utils.drawGradientRect(0, 0, width, height, -1072689136, -804253680);
+
+ if (event.mouseX < width * neu.overlay.getWidthMult() / 3 ||
+ event.mouseX > width - width * neu.overlay.getWidthMult() / 3) {
+ if (customAhActive) {
+ neu.manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY);
+ } else {
+ TradeWindow.render(event.mouseX, event.mouseY);
+ }
+ neu.overlay.render(false);
+ } else {
+ neu.overlay.render(false);
+ if (customAhActive) {
+ neu.manager.auctionManager.customAH.drawScreen(event.mouseX, event.mouseY);
+ } else {
+ TradeWindow.render(event.mouseX, event.mouseY);
+ }
+ }
+ }
+
+ if (CalendarOverlay.isEnabled() || event.isCanceled()) return;
+ if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && NotificationHandler.shouldRenderOverlay(event.gui) &&
+ event.gui instanceof GuiContainer) {
+ doInventoryButtons = true;
+
+ int zOffset = 50;
+
+ GlStateManager.translate(0, 0, zOffset);
+
+ int xSize = ((AccessorGuiContainer) event.gui).getXSize();
+ int ySize = ((AccessorGuiContainer) event.gui).getYSize();
+ int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
+
+ if (!NEUApi.disableInventoryButtons) {
+ if (!EnchantingSolvers.disableButtons()) {
+ for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
+ if (!button.isActive()) continue;
+ if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
+
+ int x = guiLeft + button.x;
+ int y = guiTop + button.y;
+ if (button.anchorRight) {
+ x += xSize;
+ }
+ if (button.anchorBottom) {
+ y += ySize;
+ }
+ if (AccessoryBagOverlay.isInAccessoryBag()) {
+ if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
+ x += 80 + 28;
+ }
+ }
+ if (TrophyRewardOverlay.inTrophyFishingInventory()) {
+ int diffX = 162;
+ if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 120) {
+ x += diffX;
+ }
+ }
+ if (AuctionProfit.inAuctionPage()) {
+ if (x + 18 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
+ y < guiTop + 56) {
+ x -= 68 - 200;
+ }
+ }
+ if (EquipmentOverlay.isRenderingArmorHud()) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
+ x -= 25;
+ }
+ }
+ if (EquipmentOverlay.isRenderingPetHud()) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
+ x -= 25;
+ }
+ }
+ if (inDungeonPage) {
+ if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
+ y < guiTop + 100) {
+ x += 185;
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1f);
+
+ GlStateManager.enableDepth();
+ GlStateManager.enableAlpha();
+ Minecraft.getMinecraft().getTextureManager().bindTexture(EDITOR);
+ Utils.drawTexturedRect(
+ x,
+ y,
+ 18,
+ 18,
+ button.backgroundIndex * 18 / 256f,
+ (button.backgroundIndex * 18 + 18) / 256f,
+ 18 / 256f,
+ 36 / 256f,
+ GL11.GL_NEAREST
+ );
+
+ if (button.icon != null && !button.icon.trim().isEmpty()) {
+ GuiInvButtonEditor.renderIcon(button.icon, x + 1, y + 1);
+ }
+ }
+ }
+ }
+ GlStateManager.translate(0, 0, -zOffset);
+ }
+ }
+
+ /**
+ * Will draw the NEUOverlay over the inventory if focusInv == false. (z-translation of 300 is so that NEUOverlay
+ * will draw over Items in the inventory (which render at a z value of about 250))
+ */
+ @SubscribeEvent
+ public void onGuiScreenDrawPost(GuiScreenEvent.DrawScreenEvent.Post event) {
+ drawingGuiScreen = false;
+ disableCraftingText = false;
+
+ String containerName = null;
+ GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
+ if (guiScreen instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) guiScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
+
+ if (GuiCustomHex.getInstance().shouldOverride(containerName)) return;
+ if (GuiCustomEnchant.getInstance().shouldOverride(containerName)) return;
+ }
+
+ boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
+ boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
+ boolean customAhActive =
+ event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
+
+ if (!(tradeWindowActive || storageOverlayActive || customAhActive)) {
+ if (NotificationHandler.shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) {
+ GlStateManager.pushMatrix();
+ if (!focusInv) {
+ GL11.glTranslatef(0, 0, 300);
+ neu.overlay.render(hoverInv && focusInv);
+ GL11.glTranslatef(0, 0, -300);
+ }
+ GlStateManager.popMatrix();
+ }
+ }
+
+ if (NotificationHandler.shouldRenderOverlay(event.gui) && neu.isOnSkyblock() && !hoverInv) {
+ renderDungKuudraChestOverlay(event.gui);
+ if (NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay) {
+ AccessoryBagOverlay.renderOverlay();
+ }
+ }
+
+ boolean hoveringButton = false;
+ if (!doInventoryButtons) return;
+ if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && NotificationHandler.shouldRenderOverlay(event.gui) &&
+ event.gui instanceof GuiContainer) {
+ int xSize = ((AccessorGuiContainer) event.gui).getXSize();
+ int ySize = ((AccessorGuiContainer) event.gui).getYSize();
+ int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
+
+ if (!NEUApi.disableInventoryButtons) {
+ if (!EnchantingSolvers.disableButtons()) {
+ for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
+ if (!button.isActive()) continue;
+ if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
+
+ int x = guiLeft + button.x;
+ int y = guiTop + button.y;
+ if (button.anchorRight) {
+ x += xSize;
+ }
+ if (button.anchorBottom) {
+ y += ySize;
+ }
+ if (AccessoryBagOverlay.isInAccessoryBag()) {
+ if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
+ x += 80 + 28;
+ }
+ }
+ if (TrophyRewardOverlay.inTrophyFishingInventory()) {
+ int diffX = 162;
+ if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 120) {
+ x += diffX;
+ }
+ }
+ if (AuctionProfit.inAuctionPage()) {
+ if (x + 18 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
+ y < guiTop + 56) {
+ x -= 68 - 200;
+ }
+ }
+ if (EquipmentOverlay.isRenderingArmorHud()) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
+ x -= 25;
+ }
+ }
+ if (EquipmentOverlay.isRenderingPetHud()) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
+ x -= 25;
+ }
+ }
+
+ if (inDungeonPage) {
+ if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
+ y < guiTop + 100) {
+ x += 185;
+ }
+ }
+
+ if (x - guiLeft >= 85 && x - guiLeft <= 115 && y - guiTop >= 4 && y - guiTop <= 25) {
+ disableCraftingText = true;
+ }
+
+ if (event.mouseX >= x && event.mouseX <= x + 18 && event.mouseY >= y && event.mouseY <= y + 18) {
+ hoveringButton = true;
+ long currentTime = System.currentTimeMillis();
+
+ if (buttonHovered != button) {
+ buttonHoveredMillis = currentTime;
+ buttonHovered = button;
+ }
+
+ if (currentTime - buttonHoveredMillis > 600) {
+ String command = button.command.trim();
+ if (!command.startsWith("/")) {
+ command = "/" + command;
+ }
+
+ Utils.drawHoveringText(
+ Lists.newArrayList("\u00a77" + command),
+ event.mouseX,
+ event.mouseY,
+ event.gui.width,
+ event.gui.height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!hoveringButton) buttonHovered = null;
+
+ if (AuctionBINWarning.getInstance().shouldShow()) {
+ AuctionBINWarning.getInstance().render();
+ }
+
+ if (AbiphoneWarning.getInstance().shouldShow()) {
+ AbiphoneWarning.getInstance().render();
+ }
+ }
+
+ private void renderDungKuudraChestOverlay(GuiScreen gui) {
+ if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 3) return;
+ if (gui instanceof GuiChest && NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc != 2) {
+ try {
+ int xSize = ((AccessorGuiContainer) gui).getXSize();
+ int guiLeft = ((AccessorGuiContainer) gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) gui).getGuiTop();
+
+ GuiChest eventGui = (GuiChest) gui;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ ItemStack rewardChest = lower.getStackInSlot(31);
+ this.inDungeonPage = rewardChest != null && rewardChest.getDisplayName().endsWith(
+ EnumChatFormatting.GREEN + "Open Reward Chest");
+ if (inDungeonPage) {
+ int chestCost = 0;
+ try {
+ String line6 = Utils.cleanColour(neu.manager.getLoreFromNBT(rewardChest.getTagCompound())[6]);
+ StringBuilder cost = new StringBuilder();
+ for (int i = 0; i < line6.length(); i++) {
+ char c = line6.charAt(i);
+ if (Character.isDigit(c)) {
+ cost.append(c);
+ }
+ }
+ if (cost.length() > 0) {
+ chestCost = Integer.parseInt(cost.toString());
+ }
+ } catch (Exception ignored) {
+ }
+
+ String missingItem = null;
+ double totalValue = 0;
+ HashMap<String, Double> itemValues = new HashMap<>();
+ for (int i = 0; i < 5; i++) {
+ ItemStack item = lower.getStackInSlot(11 + i);
+ if (ItemUtils.isSoulbound(item)) continue;
+
+ String internal = neu.manager.createItemResolutionQuery().withItemStack(item).resolveInternalName();
+ String displayName = item.getDisplayName();
+ Matcher matcher = ESSENCE_PATTERN.matcher(displayName);
+ if (neu.config.dungeons.useEssenceCostFromBazaar && matcher.matches()) {
+ String type = matcher.group(1).toUpperCase();
+ JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo("ESSENCE_" + type);
+ if (bazaarInfo != null && bazaarInfo.has("curr_sell")) {
+ float bazaarPrice = bazaarInfo.get("curr_sell").getAsFloat();
+ int amount = Integer.parseInt(matcher.group(2));
+ double price = bazaarPrice * amount;
+ itemValues.put(displayName, price);
+ totalValue += price;
+ }
+ continue;
+ }
+ if (internal != null) {
+ internal = internal.replace("\u00CD", "I").replace("\u0130", "I");
+ float bazaarPrice = -1;
+ JsonObject bazaarInfo = neu.manager.auctionManager.getBazaarInfo(internal);
+ if (bazaarInfo != null && bazaarInfo.has("curr_sell")) {
+ bazaarPrice = bazaarInfo.get("curr_sell").getAsFloat();
+ } else if (bazaarInfo != null) {
+ bazaarPrice = 0;
+ }
+ if (bazaarPrice < 5000000 && internal.equals("RECOMBOBULATOR_3000")) bazaarPrice = 5000000;
+
+ double worth = -1;
+ boolean isOnBz = false;
+ if (bazaarPrice >= 0) {
+ worth = bazaarPrice;
+ isOnBz = true;
+ } else {
+ switch (NotEnoughUpdates.INSTANCE.config.dungeons.profitType) {
+ case 1:
+ worth = neu.manager.auctionManager.getItemAvgBin(internal);
+ break;
+ case 2:
+ JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
+ if (auctionInfo != null) {
+ if (auctionInfo.has("clean_price")) {
+ worth = (long) auctionInfo.get("clean_price").getAsDouble();
+ } else {
+ worth =
+ (long) (auctionInfo.get("price").getAsDouble() / auctionInfo.get("count").getAsDouble());
+ }
+ }
+ break;
+ default:
+ worth = neu.manager.auctionManager.getLowestBin(internal);
+ }
+ if (worth <= 0) {
+ worth = neu.manager.auctionManager.getLowestBin(internal);
+ if (worth <= 0) {
+ worth = neu.manager.auctionManager.getItemAvgBin(internal);
+ if (worth <= 0) {
+ JsonObject auctionInfo = neu.manager.auctionManager.getItemAuctionInfo(internal);
+ if (auctionInfo != null) {
+ if (auctionInfo.has("clean_price")) {
+ worth = auctionInfo.get("clean_price").getAsFloat();
+ } else {
+ worth = (auctionInfo.get("price").getAsFloat() / auctionInfo.get("count").getAsFloat());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((worth >= 0 || isOnBz) && totalValue >= 0) {
+ totalValue += worth;
+ String display = item.getDisplayName();
+
+ if (display.contains("Enchanted Book")) {
+ NBTTagCompound tag = item.getTagCompound();
+ if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ NBTTagCompound enchants = ea.getCompoundTag("enchantments");
+
+ int highestLevel = -1;
+ for (String enchname : enchants.getKeySet()) {
+ int level = enchants.getInteger(enchname);
+ if (level > highestLevel) {
+ display = EnumChatFormatting.BLUE + WordUtils.capitalizeFully(enchname
+ .replace("_", " ")
+ .replace("Ultimate", "")
+ .trim()) + " " + level;
+ }
+ }
+ }
+ }
+
+ itemValues.put(display, worth);
+ } else {
+ if (totalValue != -1) {
+ missingItem = internal;
+ }
+ totalValue = -1;
+ }
+ }
+ }
+
+ String valueStringBIN1;
+ String valueStringBIN2;
+ if (totalValue >= 0) {
+ valueStringBIN1 = EnumChatFormatting.YELLOW + "Value (BIN): ";
+ valueStringBIN2 = EnumChatFormatting.GOLD + formatCoins(totalValue) + " coins";
+ } else {
+ valueStringBIN1 = EnumChatFormatting.YELLOW + "Can't find BIN: ";
+ valueStringBIN2 = missingItem;
+ }
+
+ double profitLossBIN = totalValue - chestCost;
+
+ boolean kismetUsed = false;
+ // checking for kismet
+ Slot slot = (eventGui.inventorySlots.getSlot(50));
+ if (slot.getHasStack()) {
+ String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(slot.getStack().getTagCompound());
+ for (String line : lore) {
+ if (line.contains("You already rerolled a chest!")) {
+ kismetUsed = true;
+ break;
+ }
+ }
+ }
+ double kismetPrice = neu.manager.auctionManager.getLowestBin("KISMET_FEATHER");
+ String kismetStr = EnumChatFormatting.RED + formatCoins(kismetPrice) + " coins";
+ if (neu.config.dungeons.useKismetOnDungeonProfit)
+ profitLossBIN = kismetUsed ? profitLossBIN - kismetPrice : profitLossBIN;
+
+ String profitPrefix = EnumChatFormatting.DARK_GREEN.toString();
+ String lossPrefix = EnumChatFormatting.RED.toString();
+ String prefix = profitLossBIN >= 0 ? profitPrefix : lossPrefix;
+
+ String plStringBIN;
+ if (profitLossBIN >= 0) {
+ plStringBIN = prefix + "+" + formatCoins(profitLossBIN) + " coins";
+ } else {
+ plStringBIN = prefix + "-" + formatCoins(-profitLossBIN) + " coins";
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.dungeons.profitDisplayLoc == 1 && !valueStringBIN2.equals(missingItem)) {
+ int w = Minecraft.getMinecraft().fontRendererObj.getStringWidth(plStringBIN);
+ GlStateManager.disableLighting();
+ GlStateManager.translate(0, 0, 200);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ plStringBIN,
+ guiLeft + xSize - 5 - w,
+ guiTop + 5,
+ 0xffffffff,
+ true
+ );
+ GlStateManager.translate(0, 0, -200);
+ return;
+ }
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(dungeon_chest_worth);
+ GL11.glColor4f(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+ Utils.drawTexturedRect(guiLeft + xSize + 4, guiTop, 180, 101, 0, 180 / 256f, 0, 101 / 256f, GL11.GL_NEAREST);
+
+ Utils.renderAlignedString(valueStringBIN1, valueStringBIN2, guiLeft + xSize + 4 + 10, guiTop + 14, 160);
+ if (neu.config.dungeons.useKismetOnDungeonProfit && kismetUsed) {
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Kismet Feather: ",
+ kismetStr,
+ guiLeft + xSize + 4 + 10,
+ guiTop + 24,
+ 160
+ );
+ }
+ if (totalValue >= 0) {
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Profit/Loss: ",
+ plStringBIN,
+ guiLeft + xSize + 4 + 10,
+ guiTop + (neu.config.dungeons.useKismetOnDungeonProfit ? (kismetUsed ? 34 : 24) : 24),
+ 160
+ );
+ }
+
+ int index = 0;
+ for (Map.Entry<String, Double> entry : itemValues.entrySet()) {
+ Utils.renderAlignedString(
+ entry.getKey(),
+ prefix + formatCoins(entry.getValue().doubleValue()),
+ guiLeft + xSize + 4 + 10,
+ guiTop + (neu.config.dungeons.useKismetOnDungeonProfit ? (kismetUsed ? 39 : 29) : 29) + (++index) * 10,
+ 160
+ );
+ }
+ JsonObject mayorJson = SBInfo.getInstance().getMayorJson();
+ JsonElement mayor = mayorJson.get("mayor");
+ if (mayorJson.has("mayor") && mayor != null && mayor.getAsJsonObject().has("name") &&
+ mayor.getAsJsonObject().get("name").getAsString().equals("Derpy")
+ && NotEnoughUpdates.INSTANCE.config.dungeons.shouldWarningDerpy) {
+ Utils.drawStringScaled(
+ EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "shMayor Derpy active!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + xSize + 4 + 10,
+ guiTop + 85,
+ true,
+ 0,
+ 1.3f
+ );
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private String formatCoins(double price) {
+ return format.format(price < 5 ? price : (long) price);
+ }
+
+ /**
+ * Sends a mouse event to NEUOverlay if the inventory isn't hovered AND focused.
+ * Will also cancel the event if if NEUOverlay#mouseInput returns true.
+ */
+ @SubscribeEvent(priority = EventPriority.LOW)
+ public void onGuiScreenMouse(GuiScreenEvent.MouseInputEvent.Pre event) {
+ if (Mouse.getEventButtonState() && StorageManager.getInstance().onAnyClick()) {
+ event.setCanceled(true);
+ return;
+ }
+
+ final ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft());
+ final int scaledWidth = scaledresolution.getScaledWidth();
+ final int scaledHeight = scaledresolution.getScaledHeight();
+ int mouseX = Mouse.getX() * scaledWidth / Minecraft.getMinecraft().displayWidth;
+ int mouseY = scaledHeight - Mouse.getY() * scaledHeight / Minecraft.getMinecraft().displayHeight - 1;
+
+ if (AuctionBINWarning.getInstance().shouldShow()) {
+ AuctionBINWarning.getInstance().mouseInput(mouseX, mouseY);
+ event.setCanceled(true);
+ return;
+ }
+ if (AbiphoneWarning.getInstance().shouldShow()) {
+ AbiphoneWarning.getInstance().mouseInput(mouseX, mouseY);
+ event.setCanceled(true);
+ return;
+ }
+
+ if (!event.isCanceled()) {
+ Utils.scrollTooltip(Mouse.getEventDWheel());
+ }
+ if (AuctionSearchOverlay.shouldReplace()) {
+ AuctionSearchOverlay.mouseEvent();
+ event.setCanceled(true);
+ return;
+ }
+ if (BazaarSearchOverlay.shouldReplace()) {
+ BazaarSearchOverlay.mouseEvent();
+ event.setCanceled(true);
+ return;
+ }
+ if (RancherBootOverlay.shouldReplace()) {
+ RancherBootOverlay.mouseEvent();
+ event.setCanceled(true);
+ return;
+ }
+
+ String containerName = null;
+ GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
+ if (guiScreen instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) guiScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
+ if (containerName.contains(" Profile") && BetterContainers.profileViewerStackIndex != -1 &&
+ ((AccessorGuiContainer) eventGui).doIsMouseOverSlot(
+ cc.inventorySlots.get(BetterContainers.profileViewerStackIndex),
+ mouseX,
+ mouseY
+ ) &&
+ Mouse.getEventButton() >= 0) {
+ event.setCanceled(true);
+ if (Mouse.getEventButtonState() && eventGui.inventorySlots.inventorySlots.get(22).getStack() != null &&
+ eventGui.inventorySlots.inventorySlots.get(22).getStack().getTagCompound() != null) {
+ NBTTagCompound tag = eventGui.inventorySlots.inventorySlots.get(22).getStack().getTagCompound();
+ if (tag.hasKey("SkullOwner") && tag.getCompoundTag("SkullOwner").hasKey("Name")) {
+ String username = tag.getCompoundTag("SkullOwner").getString("Name");
+ Utils.playPressSound();
+ ViewProfileCommand.RUNNABLE.accept(new String[]{username});
+ }
+ }
+ }
+ }
+
+ if (GuiCustomHex.getInstance().shouldOverride(containerName) &&
+ GuiCustomHex.getInstance().mouseInput(mouseX, mouseY)) {
+ event.setCanceled(true);
+ return;
+ }
+ if (GuiCustomEnchant.getInstance().shouldOverride(containerName) &&
+ GuiCustomEnchant.getInstance().mouseInput(mouseX, mouseY)) {
+ event.setCanceled(true);
+ return;
+ }
+
+
+ boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
+ boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
+ boolean customAhActive =
+ event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
+
+ if (storageOverlayActive) {
+ if (StorageOverlay.getInstance().mouseInput(mouseX, mouseY)) {
+ event.setCanceled(true);
+ }
+ return;
+ }
+
+ if (tradeWindowActive || customAhActive) {
+ event.setCanceled(true);
+ if (customAhActive) {
+ neu.manager.auctionManager.customAH.handleMouseInput();
+ } else {
+ TradeWindow.handleMouseInput();
+ }
+ neu.overlay.mouseInput();
+ return;
+ }
+
+ if (NotificationHandler.shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) {
+ if (!NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay || !AccessoryBagOverlay.mouseClick()) {
+ if (!(hoverInv && focusInv)) {
+ if (neu.overlay.mouseInput()) {
+ event.setCanceled(true);
+ }
+ } else {
+ neu.overlay.mouseInputInv();
+ }
+ }
+ }
+ if (event.isCanceled()) return;
+ if (!doInventoryButtons) return;
+ if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() && NotificationHandler.shouldRenderOverlay(event.gui) &&
+ Mouse.getEventButton() >= 0 && event.gui instanceof GuiContainer) {
+ int xSize = ((AccessorGuiContainer) event.gui).getXSize();
+ int ySize = ((AccessorGuiContainer) event.gui).getYSize();
+ int guiLeft = ((AccessorGuiContainer) event.gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) event.gui).getGuiTop();
+ if (!NEUApi.disableInventoryButtons) {
+ if (!EnchantingSolvers.disableButtons()) {
+ for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
+ if (!button.isActive()) continue;
+ if (button.playerInvOnly && !(event.gui instanceof GuiInventory)) continue;
+
+ int x = guiLeft + button.x;
+ int y = guiTop + button.y;
+ if (button.anchorRight) {
+ x += xSize;
+ }
+ if (button.anchorBottom) {
+ y += ySize;
+ }
+ if (AccessoryBagOverlay.isInAccessoryBag()) {
+ if (x > guiLeft + xSize && x < guiLeft + xSize + 80 + 28 + 5 && y > guiTop - 18 && y < guiTop + 150) {
+ x += 80 + 28;
+ }
+ }
+ if (TrophyRewardOverlay.inTrophyFishingInventory()) {
+ int diffX = 162;
+ if (x > guiLeft + xSize && x < guiLeft + xSize + diffX + 5 && y > guiTop - 18 && y < guiTop + 120) {
+ x += diffX;
+ }
+ }
+ if (AuctionProfit.inAuctionPage()) {
+ if (x + 18 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
+ y < guiTop + 56) {
+ x -= 68 - 200;
+ }
+ }
+ if (EquipmentOverlay.isRenderingArmorHud()) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
+ x -= 25;
+ }
+ }
+ if (EquipmentOverlay.isRenderingPetHud()) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
+ x -= 25;
+ }
+ }
+ if (inDungeonPage) {
+ if (x + 10 > guiLeft + xSize && x + 18 < guiLeft + xSize + 4 + 28 + 20 && y > guiTop - 180 &&
+ y < guiTop + 100) {
+ x += 185;
+ }
+ }
+
+ if (mouseX >= x && mouseX <= x + 18 && mouseY >= y && mouseY <= y + 18) {
+ if (Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
+ int clickType = NotEnoughUpdates.INSTANCE.config.inventoryButtons.clickType;
+ if ((clickType == 0 && Mouse.getEventButtonState()) ||
+ (clickType == 1 && !Mouse.getEventButtonState())) {
+ String command = button.command.trim();
+ if (!command.startsWith("/")) {
+ command = "/" + command;
+ }
+ if (ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command) == 0) {
+ NotEnoughUpdates.INSTANCE.sendChatMessage(command);
+ }
+ }
+ } else {
+ event.setCanceled(true);
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends a kbd event to NEUOverlay, cancelling if NEUOverlay#keyboardInput returns true.
+ * Also includes a dev function used for creating custom named json files with recipes.
+ */
+ @SubscribeEvent
+ public void onGuiScreenKeyboard(GuiScreenEvent.KeyboardInputEvent.Pre event) {
+ Keyboard.enableRepeatEvents(true);
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiInventory &&
+ !NEUOverlay.searchBarHasFocus &&
+ Keyboard.isRepeatEvent()) {
+ event.setCanceled(true);
+ return;
+ }
+ if (typing) {
+ event.setCanceled(true);
+ }
+ if (NotEnoughUpdates.INSTANCE.config.hidden.dev && Keyboard.isKeyDown(Keyboard.KEY_B) &&
+ Minecraft.getMinecraft().currentScreen instanceof GuiChest
+ ) {
+ GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ ItemStack backArrow = lower.getStackInSlot(48);
+ List<String> tooltip = backArrow != null ? backArrow.getTooltip(Minecraft.getMinecraft().thePlayer, false) : null;
+ if (tooltip != null && tooltip.size() >= 2 && tooltip.get(1).endsWith("Essence")) {
+
+ try {
+ File file = new File(
+ Minecraft.getMinecraft().mcDataDir.getAbsolutePath(),
+ "config/notenoughupdates/repo/constants/essencecosts.json"
+ );
+ String fileContent;
+ fileContent = new BufferedReader(new InputStreamReader(
+ Files.newInputStream(file.toPath()),
+ StandardCharsets.UTF_8
+ ))
+ .lines()
+ .collect(Collectors.joining(System.lineSeparator()));
+ String id = null;
+ JsonObject jsonObject = new JsonParser().parse(fileContent).getAsJsonObject();
+ JsonObject newEntry = new JsonObject();
+ for (int i = 0; i < 54; i++) {
+ ItemStack stack = lower.getStackInSlot(i);
+ if (!stack.getDisplayName().isEmpty() && stack.getItem() != Item.getItemFromBlock(Blocks.barrier) &&
+ stack.getItem() != Items.arrow) {
+ if (stack.getTagCompound().getCompoundTag("display").hasKey("Lore", 9)) {
+ int stars = Utils.getNumberOfStars(stack);
+ if (stars == 0) continue;
+
+ NBTTagList lore = stack.getTagCompound().getCompoundTag("display").getTagList("Lore", 8);
+ int costIndex = 10000;
+ id = NotEnoughUpdates.INSTANCE.manager.getInternalnameFromNBT(stack.getTagCompound());
+ if (jsonObject.has(id)) {
+ jsonObject.remove(id);
+ }
+ for (int j = 0; j < lore.tagCount(); j++) {
+ String entry = lore.getStringTagAt(j);
+ if (entry.equals("§7Cost")) {
+ costIndex = j;
+ }
+ if (j > costIndex) {
+ entry = entry.trim();
+ int index = entry.lastIndexOf('x');
+ String item, amountString;
+ if (index < 0) {
+ item = entry.trim() + " x1";
+ amountString = "x1";
+ } else {
+ amountString = entry.substring(index);
+ item = entry.substring(0, index).trim();
+ }
+ item = item.substring(0, item.length() - 3);
+ int amount = Integer.parseInt(amountString.trim().replace("x", "").replace(",", ""));
+ if (item.endsWith("Essence")) {
+ int index2 = entry.indexOf("Essence");
+ String type = item.substring(0, index2).trim().substring(2);
+ newEntry.add("type", new JsonPrimitive(type));
+ newEntry.add(String.valueOf(stars), new JsonPrimitive(amount));
+ } else {
+ String itemString = item + " §8x" + amount;
+ if (!newEntry.has("items")) {
+ newEntry.add("items", new JsonObject());
+ }
+ if (!newEntry.get("items").getAsJsonObject().has(String.valueOf(stars))) {
+ newEntry.get("items").getAsJsonObject().add(String.valueOf(stars), new JsonArray());
+ }
+ newEntry
+ .get("items")
+ .getAsJsonObject()
+ .get(String.valueOf(stars))
+ .getAsJsonArray()
+ .add(new JsonPrimitive(itemString));
+ }
+ }
+ }
+ jsonObject.add(id, newEntry);
+ }
+ }
+ }
+ if (jsonObject.get(id).getAsJsonObject().has("items")) {
+ JsonObject itemsObj = jsonObject.get(id).getAsJsonObject().get("items").getAsJsonObject();
+ jsonObject.get(id).getAsJsonObject().remove("items");
+ jsonObject.get(id).getAsJsonObject().add("items", itemsObj);
+ }
+ Gson gson = new GsonBuilder().setPrettyPrinting().create();
+ try {
+ try (
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
+ Files.newOutputStream(file.toPath()),
+ StandardCharsets.UTF_8
+ ))
+ ) {
+ writer.write(gson.toJson(jsonObject));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.AQUA + "Parsed and saved: " + EnumChatFormatting.WHITE + id));
+ }
+ } catch (IOException ignored) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Error while writing file."));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Error while parsing inventory. Try again or check logs for details."));
+ }
+ }
+ } else if (Keyboard.isKeyDown(Keyboard.KEY_RETURN) && NotEnoughUpdates.INSTANCE.config.hidden.dev) {
+ Minecraft mc = Minecraft.getMinecraft();
+
+ if (typing) {
+ typing = false;
+ cachedDefinitions.put(correctingItem, NEUOverlay.getTextField().getText());
+ NEUOverlay.getTextField().setText("");
+ }
+
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ try {
+ JsonObject newNPC = new JsonObject();
+ String displayName = lower.getDisplayName().getUnformattedText();
+ File file = new File(
+ Minecraft.getMinecraft().mcDataDir.getAbsolutePath(),
+ "config" + File.separator + "notenoughupdates" +
+ File.separator + "repo" + File.separator + "npc" + File.separator +
+ displayName.toUpperCase().replace(" ", "_") + ".json"
+ );
+ newNPC.add("itemid", new JsonPrimitive("minecraft:skull"));
+ newNPC.add("displayname", new JsonPrimitive("§9" + displayName + " (NPC)"));
+ newNPC.add("nbttag", new JsonPrimitive("TODO"));
+ newNPC.add("damage", new JsonPrimitive(3));
+
+ JsonArray newArray = new JsonArray();
+ newArray.add(new JsonPrimitive(""));
+ newNPC.add("lore", newArray);
+ newNPC.add("internalname", new JsonPrimitive(displayName.toUpperCase().replace(" ", "_") + "_NPC"));
+ newNPC.add("clickcommand", new JsonPrimitive("viewrecipe"));
+ newNPC.add("modver", new JsonPrimitive(NotEnoughUpdates.VERSION));
+ newNPC.add("infoType", new JsonPrimitive("WIKI_URL"));
+ JsonArray emptyInfoArray = new JsonArray();
+ emptyInfoArray.add(new JsonPrimitive("TODO"));
+ newNPC.add("info", emptyInfoArray);
+ newNPC.add("x", new JsonPrimitive((int) mc.thePlayer.posX));
+ newNPC.add("y", new JsonPrimitive((int) mc.thePlayer.posY + 2));
+ newNPC.add("z", new JsonPrimitive((int) mc.thePlayer.posZ));
+ newNPC.add("island", new JsonPrimitive(SBInfo.getInstance().getLocation()));
+
+ JsonArray recipesArray = new JsonArray();
+
+ TreeMap<String, JsonObject> itemInformation = NotEnoughUpdates.INSTANCE.manager.getItemInformation();
+ for (int i = 0; i < 45; i++) {
+ ItemStack stack = lower.getStackInSlot(i);
+ if (stack == null) continue;
+ if (stack.getDisplayName().isEmpty() || stack.getDisplayName().equals(" ")) continue;
+
+ String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalnameFromNBT(stack.getTagCompound());
+ if (internalname == null) continue;
+ JsonObject currentRecipe = new JsonObject();
+ currentRecipe.add("type", new JsonPrimitive("npc_shop"));
+ JsonArray costArray = new JsonArray();
+ boolean inCost = false;
+ for (String s : NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound())) {
+ if (s.equals("§7Cost")) {
+ inCost = true;
+ continue;
+ } else if (s.equals("§eClick to trade!")) {
+ inCost = false;
+ }
+ if (!inCost) continue;
+ String entry = StringUtils.stripControlCodes(s);
+ if (entry.isEmpty()) continue;
+ int coinIndex = entry.indexOf(" Coins");
+ if (coinIndex != -1) {
+ String amountString = entry.substring(0, coinIndex).replace(",", "");
+ costArray.add(new JsonPrimitive("SKYBLOCK_COIN:" + amountString));
+ } else {
+ if (cachedDefinitions == null) {
+ cachedDefinitions = new HashMap<>();
+ }
+
+ String item;
+ int amountIndex = entry.lastIndexOf(" x");
+ String amountString;
+ if (amountIndex == -1) {
+ amountString = "1";
+ item = entry.replace(" ", "_").toUpperCase();
+ } else {
+ amountString = entry.substring(amountIndex);
+ item = entry.substring(0, amountIndex).replace(" ", "_").toUpperCase();
+ }
+ amountString = amountString.replace(",", "").replace("x", "").trim();
+ if (itemInformation.containsKey(item)) {
+ costArray.add(new JsonPrimitive(item + ":" + amountString));
+ } else if (cachedDefinitions.containsKey(item)) {
+ costArray.add(new JsonPrimitive(cachedDefinitions.get(item) + ":" + amountString));
+ } else {
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ "Change the item ID of " + item + " to the correct one and press Enter."));
+ NEUOverlay.getTextField().setText(item);
+ event.setCanceled(true);
+ typing = true;
+ correctingItem = item;
+ if (cachedDefinitions == null) {
+ cachedDefinitions = new HashMap<>();
+ }
+ return;
+ }
+ }
+ }
+ currentRecipe.add("cost", costArray);
+ currentRecipe.add("result", new JsonPrimitive(internalname));
+ recipesArray.add(currentRecipe);
+ newNPC.add("recipes", recipesArray);
+ }
+ Gson gson = new GsonBuilder().setPrettyPrinting().create();
+ System.out.println(gson.toJson(newNPC));
+ try {
+ //noinspection ResultOfMethodCallIgnored
+ file.createNewFile();
+ try (
+ BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
+ Files.newOutputStream(file.toPath()),
+ StandardCharsets.UTF_8
+ ))
+ ) {
+ writer.write(gson.toJson(newNPC));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.AQUA + "Parsed and saved: " + EnumChatFormatting.WHITE + displayName));
+ }
+ } catch (IOException ignored) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Error while writing file."));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "Error while parsing inventory. Try again or check logs for details"));
+ }
+ }
+ } else if (NotEnoughUpdates.INSTANCE.config.hidden.dev && Keyboard.isKeyDown(Keyboard.KEY_B) &&
+ Minecraft.getMinecraft().currentScreen instanceof GuiChest &&
+ ((((ContainerChest) ((GuiChest) Minecraft.getMinecraft().currentScreen).inventorySlots)
+ .getLowerChestInventory()
+ .getDisplayName()
+ .getUnformattedText()
+ .endsWith("Essence")))) {
+ GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ for (int i = 9; i < 45; i++) {
+ ItemStack stack = lower.getStackInSlot(i);
+ if (stack == null) continue;
+ if (stack.getDisplayName().isEmpty() || stack.getDisplayName().equals(" ")) continue;
+ String internalName = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack);
+ if (internalName == null) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "ERROR: Could not get internal name for: " + EnumChatFormatting.AQUA +
+ stack.getDisplayName()));
+ continue;
+ }
+ JsonObject itemObject = NotEnoughUpdates.INSTANCE.manager.getJsonForItem(stack);
+ JsonArray lore = itemObject.get("lore").getAsJsonArray();
+ List<String> loreList = new ArrayList<>();
+ for (int j = 0; j < lore.size(); j++) loreList.add(lore.get(j).getAsString());
+ if (loreList.get(loreList.size() - 1).equals("§7§eClick to view upgrades!")) {
+ loreList.remove(loreList.size() - 1);
+ loreList.remove(loreList.size() - 1);
+ }
+
+ JsonArray newLore = new JsonArray();
+ for (String s : loreList) {
+ newLore.add(new JsonPrimitive(s));
+ }
+ itemObject.remove("lore");
+ itemObject.add("lore", newLore);
+
+ if (!NEUItemEditor.saveOnly(internalName, itemObject)) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "ERROR: Failed to save item: " + EnumChatFormatting.AQUA +
+ stack.getDisplayName()));
+ }
+ }
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.AQUA + "Parsed page: " + lower.getDisplayName().getUnformattedText()));
+ event.setCanceled(true);
+ return;
+ }
+
+ if (AuctionBINWarning.getInstance().shouldShow()) {
+ AuctionBINWarning.getInstance().keyboardInput();
+ event.setCanceled(true);
+ return;
+ }
+ if (AbiphoneWarning.getInstance().shouldShow()) {
+ AbiphoneWarning.getInstance().keyboardInput();
+ event.setCanceled(true);
+ return;
+ }
+
+ if (AuctionSearchOverlay.shouldReplace()) {
+ AuctionSearchOverlay.keyEvent();
+ event.setCanceled(true);
+ return;
+ }
+ if (BazaarSearchOverlay.shouldReplace()) {
+ BazaarSearchOverlay.keyEvent();
+ event.setCanceled(true);
+ return;
+ }
+ if (RancherBootOverlay.shouldReplace()) {
+ RancherBootOverlay.keyEvent();
+ event.setCanceled(true);
+ return;
+ }
+
+ String containerName = null;
+ GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
+
+ if (guiScreen instanceof GuiChest) {
+ containerName = ((ContainerChest) ((GuiChest) guiScreen).inventorySlots)
+ .getLowerChestInventory()
+ .getDisplayName()
+ .getUnformattedText();
+ }
+
+ if (GuiCustomHex.getInstance().shouldOverride(containerName) &&
+ GuiCustomHex.getInstance().keyboardInput()) {
+ event.setCanceled(true);
+ return;
+ }
+
+ if (GuiCustomEnchant.getInstance().shouldOverride(containerName) &&
+ GuiCustomEnchant.getInstance().keyboardInput()) {
+ event.setCanceled(true);
+ return;
+ }
+
+
+ boolean tradeWindowActive = TradeWindow.tradeWindowActive(containerName);
+ boolean storageOverlayActive = StorageManager.getInstance().shouldRenderStorageOverlay(containerName);
+ boolean customAhActive =
+ event.gui instanceof CustomAHGui || neu.manager.auctionManager.customAH.isRenderOverAuctionView();
+
+ if (storageOverlayActive) {
+ if (StorageOverlay.getInstance().keyboardInput()) {
+ event.setCanceled(true);
+ return;
+ }
+ }
+
+ if (tradeWindowActive || customAhActive) {
+ if (customAhActive) {
+ if (neu.manager.auctionManager.customAH.keyboardInput()) {
+ event.setCanceled(true);
+ Minecraft.getMinecraft().dispatchKeypresses();
+ } else if (neu.overlay.keyboardInput(focusInv)) {
+ event.setCanceled(true);
+ }
+ } else {
+ TradeWindow.keyboardInput();
+ if (Keyboard.getEventKey() != Keyboard.KEY_ESCAPE) {
+ event.setCanceled(true);
+ Minecraft.getMinecraft().dispatchKeypresses();
+ neu.overlay.keyboardInput(focusInv);
+ }
+ }
+ return;
+ }
+
+ if (NotificationHandler.shouldRenderOverlay(event.gui) && neu.isOnSkyblock()) {
+ if (neu.overlay.keyboardInput(focusInv)) {
+ event.setCanceled(true);
+ }
+ }
+ if (NotEnoughUpdates.INSTANCE.config.apiData.repositoryEditing &&
+ Minecraft.getMinecraft().theWorld != null && Keyboard.getEventKey() == Keyboard.KEY_N &&
+ Keyboard.getEventKeyState()) {
+ GuiScreen gui = Minecraft.getMinecraft().currentScreen;
+ if (gui instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) event.gui;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ if (!lower.getDisplayName().getUnformattedText().endsWith("Essence")) return;
+
+ for (int i = 0; i < lower.getSizeInventory(); i++) {
+ ItemStack stack = lower.getStackInSlot(i);
+
+ String internalname = neu.manager.getInternalNameForItem(stack);
+ if (internalname != null) {
+ String[] lore = neu.manager.getLoreFromNBT(stack.getTagCompound());
+
+ for (String line : lore) {
+ if (line.contains(":") && (line.startsWith("\u00A77Upgrade to") || line.startsWith(
+ "\u00A77Convert to Dungeon Item"))) {
+ String[] split = line.split(":");
+ String after = Utils.cleanColour(split[1]);
+ StringBuilder costS = new StringBuilder();
+ for (char c : after.toCharArray()) {
+ if (c >= '0' && c <= '9') {
+ costS.append(c);
+ }
+ }
+ int cost = Integer.parseInt(costS.toString());
+ String[] afterSplit = after.split(" ");
+ String type = afterSplit[afterSplit.length - 2];
+
+ if (!essenceJson.has(internalname)) {
+ essenceJson.add(internalname, new JsonObject());
+ }
+ JsonObject obj = essenceJson.get(internalname).getAsJsonObject();
+ obj.addProperty("type", type);
+
+ if (line.startsWith("\u00A77Convert to Dungeon Item")) {
+ obj.addProperty("dungeonize", cost);
+ } else if (line.startsWith("\u00A77Upgrade to")) {
+ int stars = 0;
+ for (char c : line.toCharArray()) {
+ if (c == '\u272A') stars++;
+ }
+ if (stars > 0) {
+ obj.addProperty(stars + "", cost);
+ }
+ }
+ }
+ }
+ }
+ }
+ System.out.println(essenceJson);
+ }
+ }
+ if (NotEnoughUpdates.INSTANCE.config.apiData.repositoryEditing &&
+ Minecraft.getMinecraft().theWorld != null && Keyboard.getEventKey() == Keyboard.KEY_O &&
+ Keyboard.getEventKeyState()) {
+ GuiScreen gui = Minecraft.getMinecraft().currentScreen;
+ if (gui instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) event.gui;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ IInventory lower = cc.getLowerChestInventory();
+
+ if (lower.getStackInSlot(23) != null && lower.getStackInSlot(23).getDisplayName().endsWith("Crafting Table")) {
+ ItemStack res = lower.getStackInSlot(25);
+ String resInternalname = neu.manager.getInternalNameForItem(res);
+ JTextField tf = new JTextField();
+ tf.setText(resInternalname);
+ tf.addAncestorListener(new RequestFocusListener());
+ JOptionPane.showOptionDialog(
+ null,
+ tf,
+ "Enter Name:",
+ JOptionPane.NO_OPTION,
+ JOptionPane.PLAIN_MESSAGE,
+ null,
+ new String[]{"Enter"},
+ "Enter"
+ );
+ resInternalname = tf.getText();
+ if (resInternalname.trim().length() == 0) {
+ return;
+ }
+
+ JsonObject recipe = new JsonObject();
+
+ String[] x = {"1", "2", "3"};
+ String[] y = {"A", "B", "C"};
+
+ for (int i = 0; i <= 18; i += 9) {
+ for (int j = 0; j < 3; j++) {
+ ItemStack stack = lower.getStackInSlot(10 + i + j);
+ String internalname = "";
+ if (stack != null) {
+ internalname = neu.manager.getInternalNameForItem(stack);
+ if (!neu.manager.getItemInformation().containsKey(internalname)) {
+ neu.manager.writeItemToFile(stack);
+ }
+ internalname += ":" + stack.stackSize;
+ }
+ recipe.addProperty(y[i / 9] + x[j], internalname);
+ }
+ }
+
+ JsonObject json = neu.manager.getJsonForItem(res);
+ json.add("recipe", recipe);
+ json.addProperty("internalname", resInternalname);
+ json.addProperty("clickcommand", "viewrecipe");
+ json.addProperty("modver", NotEnoughUpdates.VERSION);
+ try {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("Added: " + resInternalname));
+ neu.manager.writeJsonDefaultDir(json, resInternalname + ".json");
+ neu.manager.loadItem(resInternalname);
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onRenderLast(RenderWorldLastEvent event) {
+ CrystalMetalDetectorSolver.render(event.partialTicks);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/listener/ScoreboardLocationChangeListener.java b/src/main/java/io/github/moulberry/notenoughupdates/listener/ScoreboardLocationChangeListener.java
new file mode 100644
index 00000000..622b2088
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/listener/ScoreboardLocationChangeListener.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.listener;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.overlays.TimersOverlay;
+
+public class ScoreboardLocationChangeListener {
+
+ public ScoreboardLocationChangeListener(String oldLocation, String newLocation) {
+ if (oldLocation.equals("Belly of the Beast") && newLocation.equals("Matriarchs Lair")) {
+ //Check inventory pearl count for AFTER they complete to see if it is the same as before + (amount available on actionbar)
+ Thread thread = new Thread(() -> {
+ try {
+ Thread.sleep(3000);
+ TimersOverlay.afterPearls = TimersOverlay.heavyPearlCount();
+ //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW+"You exited the beast with ["+EnumChatFormatting.AQUA+(TimersOverlay.afterPearls-TimersOverlay.beforePearls)+EnumChatFormatting.YELLOW+"/"+EnumChatFormatting.AQUA+TimersOverlay.availablePearls+EnumChatFormatting.YELLOW+"] Heavy Pearls!"));
+ if (TimersOverlay.afterPearls - TimersOverlay.beforePearls == TimersOverlay.availablePearls) {
+ NotEnoughUpdates.INSTANCE.config.getProfileSpecific().dailyHeavyPearlCompleted = System.currentTimeMillis();
+ //Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN+"Daily "+EnumChatFormatting.DARK_AQUA+"Heavy Pearls"+EnumChatFormatting.GREEN+" Complete!"));
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ thread.start();
+ } else if (oldLocation.equals("Matriarchs Lair") && newLocation.equals("Belly of the Beast")) {
+ //Check inventory pearl count BEFORE they complete so we can later check if it is complete.
+ TimersOverlay.beforePearls = TimersOverlay.heavyPearlCount();
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java
index eaf41ba6..7193b47f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBAnchorPoint.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mbgui;
import org.lwjgl.util.vector.Vector2f;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java
index b9e858ef..5f530c00 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBDeserializer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mbgui;
import com.google.gson.JsonObject;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java
index ad836097..3e3ab1e3 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiElement.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mbgui;
public abstract class MBGuiElement {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java
index 4540b146..b183bd1e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroup.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mbgui;
import org.lwjgl.util.vector.Vector2f;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java
index eef4b5e5..5c0cd37e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupAligned.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mbgui;
import org.lwjgl.util.vector.Vector2f;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java
index 24697cc6..c57f0b74 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mbgui/MBGuiGroupFloating.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mbgui;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -10,7 +29,11 @@ import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.gui.inventory.GuiContainer;
import org.lwjgl.util.vector.Vector2f;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
public class MBGuiGroupFloating extends MBGuiGroup {
private GuiScreen lastScreen = null;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneWarning.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneWarning.java
new file mode 100644
index 00000000..67ac4f4c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AbiphoneWarning.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.GuiElement;
+import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.core.util.render.TextRenderUtils;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import java.util.List;
+
+public class AbiphoneWarning extends GuiElement {
+ private static final AbiphoneWarning INSTANCE = new AbiphoneWarning();
+
+ private boolean showWarning = false;
+ private String contactName = null;
+ private int contactSlot = -1;
+
+ public static AbiphoneWarning getInstance() {
+ return INSTANCE;
+ }
+
+ private boolean shouldPerformCheck() {
+ if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ showWarning = false;
+ return false;
+ }
+
+ if (Utils.getOpenChestName().startsWith("Abiphone ")) {
+ return true;
+ } else {
+ showWarning = false;
+ return false;
+ }
+ }
+
+ public boolean shouldShow() {
+ return shouldPerformCheck() && showWarning;
+ }
+
+ @SubscribeEvent
+ public void onMouseClick(SlotClickEvent event) {
+ if (!shouldPerformCheck()) return;
+ if (!NotEnoughUpdates.INSTANCE.config.misc.abiphoneWarning) return;
+ if (event.slotId == -999) return;
+ if (event.clickedButton == 0) return;
+
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+
+ ItemStack clickedContact = chest.inventorySlots.getSlot(event.slotId).getStack();
+ if (clickedContact == null) return;
+
+ List<String> list = ItemUtils.getLore(clickedContact);
+ if (list.isEmpty()) return;
+
+ String last = list.get(list.size() - 1);
+ if (last.contains("Right-click to remove contact!")) {
+ showWarning = true;
+ contactName = clickedContact.getDisplayName();
+ contactSlot = event.slotId;
+ event.setCanceled(true);
+ }
+ }
+
+ public void overrideIsMouseOverSlot(Slot slot, int mouseX, int mouseY, CallbackInfoReturnable<Boolean> cir) {
+ if (shouldShow()) {
+ cir.setReturnValue(false);
+ }
+ }
+
+ @Override
+ public void render() {
+ final ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ final int width = scaledResolution.getScaledWidth();
+ final int height = scaledResolution.getScaledHeight();
+
+ GlStateManager.disableLighting();
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, 0, 500);
+
+ Gui.drawRect(0, 0, width, height, 0x80000000);
+
+ RenderUtils.drawFloatingRectDark(width / 2 - 90, height / 2 - 45, 180, 90);
+
+ int neuLength = Minecraft.getMinecraft().fontRendererObj.getStringWidth("\u00a7lNEU");
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ "\u00a7lNEU",
+ width / 2 + 90 - neuLength - 3,
+ height / 2 - 45 + 4,
+ 0xff000000
+ );
+
+ TextRenderUtils.drawStringCenteredScaledMaxWidth("Are you SURE?", Minecraft.getMinecraft().fontRendererObj,
+ width / 2, height / 2 - 45 + 10, false, 170, 0xffff4040
+ );
+
+ String sellLine = "\u00a77[ \u00a7r" + contactName + "\u00a77 ]";
+
+ TextRenderUtils.drawStringCenteredScaledMaxWidth(sellLine, Minecraft.getMinecraft().fontRendererObj,
+ width / 2, height / 2 - 45 + 25, false, 170, 0xffffffff
+ );
+
+ TextRenderUtils.drawStringCenteredScaledMaxWidth(
+ "Continue removing this contact?",
+ Minecraft.getMinecraft().fontRendererObj,
+ width / 2,
+ height / 2 - 45 + 50,
+ false,
+ 170,
+ 0xffa0a0a0
+ );
+
+ RenderUtils.drawFloatingRectDark(width / 2 - 43, height / 2 + 23, 40, 16, false);
+ RenderUtils.drawFloatingRectDark(width / 2 + 3, height / 2 + 23, 40, 16, false);
+
+ TextRenderUtils.drawStringCenteredScaledMaxWidth(
+ EnumChatFormatting.GREEN + "[Y]es",
+ Minecraft.getMinecraft().fontRendererObj,
+ width / 2 - 23,
+ height / 2 + 31,
+ true,
+ 36,
+ 0xff00ff00
+ );
+ TextRenderUtils.drawStringCenteredScaledMaxWidth(
+ EnumChatFormatting.RED + "[N]o",
+ Minecraft.getMinecraft().fontRendererObj,
+ width / 2 + 23,
+ height / 2 + 31,
+ true,
+ 36,
+ 0xffff0000
+ );
+
+ GlStateManager.popMatrix();
+ }
+
+ @Override
+ public boolean mouseInput(int mouseX, int mouseY) {
+ final ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ final int width = scaledResolution.getScaledWidth();
+ final int height = scaledResolution.getScaledHeight();
+
+ if (Mouse.getEventButtonState()) {
+ if (mouseY >= height / 2 + 23 && mouseY <= height / 2 + 23 + 16) {
+ if (mouseX >= width / 2 - 43 && mouseX <= width / 2 - 3) {
+ makeClick();
+ }
+ showWarning = false;
+ }
+
+ if (mouseX < width / 2 - 90 || mouseX > width / 2 + 90 ||
+ mouseY < height / 2 - 45 || mouseY > height / 2 + 45) {
+ showWarning = false;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean keyboardInput() {
+ if (!Keyboard.getEventKeyState()) {
+ if (Keyboard.getEventKey() == Keyboard.KEY_Y || Keyboard.getEventKey() == Keyboard.KEY_RETURN) {
+ makeClick();
+ }
+ showWarning = false;
+ }
+
+ return false;
+ }
+
+ private void makeClick() {
+ if (contactSlot != -1) {
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ Minecraft.getMinecraft().playerController.windowClick(chest.inventorySlots.windowId,
+ contactSlot, 1, 0, Minecraft.getMinecraft().thePlayer
+ );
+ contactSlot = -1;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java
new file mode 100644
index 00000000..70ac4489
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AntiCoopAdd.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.event.HoverEvent;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class AntiCoopAdd {
+
+ @SubscribeEvent
+ public void onMouseClick(SlotClickEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.misc.coopWarning) return;
+ if (event.slotId == -999) return;
+ if (!Utils.getOpenChestName().contains("Profile")) return;
+
+ ItemStack stack = event.slot.getStack();
+ if (stack == null) return;
+ if (stack.getItem() == Items.diamond && stack.getDisplayName() != null && stack.getDisplayName().contains(
+ "Co-op Request")) {
+ String ign = Utils.getOpenChestName().split("'s Profile")[0];
+ ChatComponentText storageMessage = new ChatComponentText(
+ EnumChatFormatting.YELLOW + "[NEU] " + EnumChatFormatting.YELLOW +
+ "You just clicked on the Co-op add button. If you want to coop add this person, click this chat message");
+ storageMessage.setChatStyle(Utils.createClickStyle(ClickEvent.Action.RUN_COMMAND, "/coopadd " + ign));
+ storageMessage.setChatStyle(storageMessage.getChatStyle().setChatHoverEvent(
+ new HoverEvent(
+ HoverEvent.Action.SHOW_TEXT,
+ new ChatComponentText(EnumChatFormatting.YELLOW + "Click to add " + ign + " to your coop")
+ )));
+ ChatComponentText storageChatMessage = new ChatComponentText("");
+ storageChatMessage.appendSibling(storageMessage);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(storageChatMessage);
+ event.setCanceled(true);
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java
index c76a22b4..ad9df7af 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionBINWarning.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.gson.JsonObject;
@@ -5,7 +24,7 @@ import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.GuiElement;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
import io.github.moulberry.notenoughupdates.core.util.render.TextRenderUtils;
-import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -15,6 +34,7 @@ import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@@ -35,19 +55,20 @@ public class AuctionBINWarning extends GuiElement {
private boolean showWarning = false;
private List<String> sellingTooltip;
private String sellingName;
- private int sellingPrice;
- private int lowestPrice;
+ private long sellingPrice;
+ private long lowestPrice;
+ private long buyPercentage;
+ private int sellStackAmount;
+ private boolean isALoss = true;
private boolean shouldPerformCheck() {
- if (!NotEnoughUpdates.INSTANCE.config.ahTweaks.enableBINWarning ||
- !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
sellingTooltip = null;
showWarning = false;
return false;
}
- if (Minecraft.getMinecraft().currentScreen instanceof GuiChest &&
- SBInfo.getInstance().lastOpenContainerName.startsWith("Create BIN Auction")) {
+ if (Utils.getOpenChestName().startsWith("Create BIN Auction")) {
return true;
} else {
sellingTooltip = null;
@@ -60,65 +81,73 @@ public class AuctionBINWarning extends GuiElement {
return shouldPerformCheck() && showWarning;
}
- public boolean onMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType) {
- if (!shouldPerformCheck()) return false;
+ @SubscribeEvent
+ public void onMouseClick(SlotClickEvent event) {
+ if (!shouldPerformCheck()) return;
- if (slotId == 29) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ if (event.slotId != 29) {
+ return;
+ }
- sellingPrice = -1;
+ sellingPrice = -1;
- ItemStack priceStack = chest.inventorySlots.getSlot(31).getStack();
- if (priceStack != null) {
- String displayName = priceStack.getDisplayName();
- Matcher priceMatcher = ITEM_PRICE_REGEX.matcher(displayName);
+ ItemStack priceStack = event.guiContainer.inventorySlots.getSlot(31).getStack();
+ if (priceStack != null) {
+ String displayName = priceStack.getDisplayName();
+ Matcher priceMatcher = ITEM_PRICE_REGEX.matcher(displayName);
- if (priceMatcher.matches()) {
- try {
- sellingPrice = Integer.parseInt(priceMatcher.group(1).replace(",", ""));
- } catch (NumberFormatException ignored) {
- }
+ if (priceMatcher.matches()) {
+ try {
+ sellingPrice = Long.parseLong(priceMatcher.group(1).replace(",", ""));
+ } catch (NumberFormatException ignored) {
}
}
+ }
- ItemStack sellStack = chest.inventorySlots.getSlot(13).getStack();
- String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(sellStack);
-
- if (internalname == null) {
- return false;
- }
+ ItemStack sellStack = event.guiContainer.inventorySlots.getSlot(13).getStack();
+ String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(sellStack);
+ sellStackAmount = sellStack.stackSize;
- JsonObject itemInfo = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(internalname);
- if (itemInfo == null || !itemInfo.has("displayname")) {
- sellingName = internalname;
- } else {
- sellingName = itemInfo.get("displayname").getAsString();
- }
+ if (internalname == null) {
+ return;
+ }
- sellingTooltip = sellStack.getTooltip(
- Minecraft.getMinecraft().thePlayer,
- Minecraft.getMinecraft().gameSettings.advancedItemTooltips
- );
+ JsonObject itemInfo = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(internalname);
+ if (itemInfo == null || !itemInfo.has("displayname")) {
+ sellingName = internalname;
+ } else {
+ sellingName = itemInfo.get("displayname").getAsString();
+ }
- lowestPrice = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname);
- if (lowestPrice <= 0) {
- lowestPrice = (int) NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAvgBin(internalname);
- }
+ sellingTooltip = sellStack.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
- //TODO: Add option for warning if lowest price does not exist
+ lowestPrice = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname);
+ if (lowestPrice <= 0) {
+ lowestPrice = (int) NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAvgBin(internalname);
+ }
- float factor = 1 - NotEnoughUpdates.INSTANCE.config.ahTweaks.warningThreshold / 100;
- if (factor < 0) factor = 0;
- if (factor > 1) factor = 1;
+ float undercutFactor = 1 - NotEnoughUpdates.INSTANCE.config.ahTweaks.warningThreshold / 100;
+ if (undercutFactor < 0) undercutFactor = 0;
+ if (undercutFactor > 1) undercutFactor = 1;
+ float overcutFactor = 1 - NotEnoughUpdates.INSTANCE.config.ahTweaks.overcutWarningThreshold / 100;
+ if (overcutFactor < 0) overcutFactor = 0;
+ if (overcutFactor > 1) overcutFactor = 1;
- if (sellingPrice > 0 && lowestPrice > 0 && sellingPrice < lowestPrice * factor) {
- showWarning = true;
- return true;
- } else {
- return false;
- }
+ if (lowestPrice == -1) {
+ return;
+ }
+ if (NotEnoughUpdates.INSTANCE.config.ahTweaks.underCutWarning &&
+ (sellingPrice > 0 && lowestPrice > 0 && sellingPrice < sellStackAmount * lowestPrice * undercutFactor)) {
+ showWarning = true;
+ event.setCanceled(true);
+ } else if (NotEnoughUpdates.INSTANCE.config.ahTweaks.overCutWarning &&
+ (sellingPrice > 0 && lowestPrice > 0 && sellingPrice > sellStackAmount * lowestPrice * (overcutFactor + 1))) {
+ showWarning = true;
+ event.setCanceled(true);
}
- return false;
}
public void overrideIsMouseOverSlot(Slot slot, int mouseX, int mouseY, CallbackInfoReturnable<Boolean> cir) {
@@ -155,10 +184,10 @@ public class AuctionBINWarning extends GuiElement {
);
String lowestPriceStr;
- if (lowestPrice > 999) {
- lowestPriceStr = Utils.shortNumberFormat(lowestPrice, 0);
+ if (lowestPrice * sellStackAmount > 999) {
+ lowestPriceStr = Utils.shortNumberFormat(lowestPrice * sellStackAmount, 0);
} else {
- lowestPriceStr = "" + lowestPrice;
+ lowestPriceStr = "" + lowestPrice * sellStackAmount;
}
String sellingPriceStr;
@@ -174,7 +203,9 @@ public class AuctionBINWarning extends GuiElement {
width / 2, height / 2 - 45 + 25, false, 170, 0xffffffff
);
TextRenderUtils.drawStringCenteredScaledMaxWidth(
- "has a lowest BIN of \u00a76" + lowestPriceStr + "\u00a7r coins",
+ (lowestPrice > 0
+ ? "has a lowest BIN of \u00a76" + lowestPriceStr + "\u00a7r coins"
+ : "\u00a7cWarning: No lowest BIN found!"),
Minecraft.getMinecraft().fontRendererObj,
width / 2,
height / 2 - 45 + 34,
@@ -183,8 +214,14 @@ public class AuctionBINWarning extends GuiElement {
0xffa0a0a0
);
- int buyPercentage = 100 - sellingPrice * 100 / lowestPrice;
- if (buyPercentage <= 0) buyPercentage = 1;
+ if (sellingPrice > lowestPrice * sellStackAmount) {
+ buyPercentage = sellingPrice * 100 / (lowestPrice * sellStackAmount);
+ isALoss = false;
+ } else if (sellingPrice < lowestPrice * sellStackAmount) {
+ buyPercentage = 100 - sellingPrice * 100 / (lowestPrice * sellStackAmount);
+ if (buyPercentage <= 0) buyPercentage = 1;
+ isALoss = true;
+ }
TextRenderUtils.drawStringCenteredScaledMaxWidth(
"Continue selling it for",
@@ -196,7 +233,8 @@ public class AuctionBINWarning extends GuiElement {
0xffa0a0a0
);
TextRenderUtils.drawStringCenteredScaledMaxWidth(
- "\u00a76" + sellingPriceStr + "\u00a7r coins? (\u00a7c-" + buyPercentage + "%\u00a7r)",
+ "\u00a76" + sellingPriceStr + "\u00a7r coins?" +
+ (lowestPrice > 0 ? "(\u00a7" + (isALoss ? "c-" : "a+") + buyPercentage + "%\u00a7r)" : ""),
Minecraft.getMinecraft().fontRendererObj,
width / 2,
height / 2 - 45 + 59,
@@ -218,7 +256,7 @@ public class AuctionBINWarning extends GuiElement {
0xff00ff00
);
TextRenderUtils.drawStringCenteredScaledMaxWidth(
- EnumChatFormatting.RED + "[n]o",
+ EnumChatFormatting.RED + "[N]o",
Minecraft.getMinecraft().fontRendererObj,
width / 2 + 23,
height / 2 + 31,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java
new file mode 100644
index 00000000..88ca0cc8
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionProfit.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.inventory.Container;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.opengl.GL11;
+
+public class AuctionProfit {
+
+ public static final ResourceLocation auctionProfitImage =
+ new ResourceLocation("notenoughupdates:auction_profit.png");
+
+ @SubscribeEvent
+ public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
+ if (!inAuctionPage()) return;
+
+ Minecraft minecraft = Minecraft.getMinecraft();
+ Container inventoryContainer = minecraft.thePlayer.openContainer;
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) return;
+ Gui gui = event.gui;
+ int xSize = ((AccessorGuiContainer) gui).getXSize();
+ int guiLeft = ((AccessorGuiContainer) gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) gui).getGuiTop();
+ minecraft.getTextureManager().bindTexture(auctionProfitImage);
+ GL11.glColor4f(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+ Utils.drawTexturedRect(guiLeft + xSize + 4, guiTop, 180, 101, 0, 180 / 256f, 0, 101 / 256f, GL11.GL_NEAREST);
+
+ double coinsToCollect = 0;
+ double coinsIfAllSold = 0;
+ int expiredAuctions = 0;
+ int unclaimedAuctions = 0;
+ for (ItemStack itemStack : inventoryContainer.getInventory()) {
+ boolean isBin = false;
+ if (itemStack == null || !itemStack.hasTagCompound()) continue;
+
+ NBTTagCompound tag = itemStack.getTagCompound();
+ if (tag == null) continue;
+ NBTTagCompound display = tag.getCompoundTag("display");
+ if (!display.hasKey("Lore", 9)) continue;
+ NBTTagList lore = itemStack.getTagCompound().getCompoundTag("display").getTagList("Lore", 8);
+
+ int coinsToCheck = 0;
+ for (int i = 0; i < lore.tagCount(); i++) {
+ String line = lore.getStringTagAt(i);
+ if (line.contains("§7Buy it now")) {
+ isBin = true;
+ String s = line.split("§7Buy it now: ")[1];
+ String coinsString = s.split("coins")[0];
+ int coins = tryParse(EnumChatFormatting.getTextWithoutFormattingCodes(coinsString.trim()));
+ if (coins != 0) {
+ coinsToCheck += coins;
+ }
+ }
+
+ if (line.contains("§7Top bid: ")) {
+ String s = line.split("§7Top bid: ")[1];
+ String coinsString = s.split("coins")[0];
+ String textWithoutFormattingCodes = EnumChatFormatting.getTextWithoutFormattingCodes(coinsString.trim());
+ int coins = tryParse(textWithoutFormattingCodes);
+ if (coins != 0) {
+ coinsToCheck += coins;
+ }
+ }
+
+ if (line.contains("§7Sold for: ")) {
+ String s = line.split("§7Sold for: ")[1];
+ String coinsString = s.split("coins")[0];
+ int coins = tryParse(EnumChatFormatting.getTextWithoutFormattingCodes(coinsString.trim()));
+ if (coins != 0) {
+ if (coins > 1000000) {
+ coins /= 1.1;
+ }
+ coinsToCollect += coins;
+ }
+ }
+
+ if (line.contains("§7Status: §aSold!") || line.contains("§7Status: §aEnded!")) {
+ if (coinsToCheck != 0) {
+ if (coinsToCheck > 1000000) {
+ coinsToCheck /= 1.1;
+ }
+ coinsToCollect += coinsToCheck;
+ coinsToCheck = 0;
+ }
+ unclaimedAuctions++;
+ } else if (line.contains("§7Status: §cExpired!")) {
+ expiredAuctions++;
+ }
+
+ if (isBin && line.contains("§7Ends in") && coinsToCheck != 0) {
+ coinsIfAllSold += coinsToCheck;
+ coinsToCheck = 0;
+ }
+
+ }
+
+ }
+ int a = guiLeft + xSize + 4;
+ String unclaimedAuctionsStr = EnumChatFormatting.DARK_GREEN.toString()
+ + unclaimedAuctions + EnumChatFormatting.BOLD + EnumChatFormatting.DARK_GRAY + " Unclaimed auctions";
+ String expiredAuctionsStr =
+ EnumChatFormatting.RED.toString() + expiredAuctions + EnumChatFormatting.BOLD + EnumChatFormatting.DARK_GRAY +
+ " Expired auctions";
+
+ FontRenderer fontRendererObj = minecraft.fontRendererObj;
+ fontRendererObj.drawString(unclaimedAuctionsStr, a + 6, guiTop + 6, -1, false);
+ fontRendererObj.drawString(expiredAuctionsStr, a + 6, guiTop + 16, -1, false);
+
+ String coinsToCollectStr =
+ EnumChatFormatting.BOLD + EnumChatFormatting.DARK_GRAY.toString() + "Coins to collect: " +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_GREEN + "" +
+ StringUtils.shortNumberFormat(coinsToCollect);
+ String valueIfSoldStr = EnumChatFormatting.BOLD + EnumChatFormatting.DARK_GRAY.toString() + "Value if all sold: " +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_GREEN + "" +
+ StringUtils.shortNumberFormat(coinsIfAllSold);
+
+ fontRendererObj.drawString(coinsToCollectStr, a + 6, guiTop + 32, -1, false);
+ fontRendererObj.drawString(valueIfSoldStr, a + 6, guiTop + 42, -1, false);
+ }
+
+ public static Integer tryParse(String s) {
+ try {
+ return Integer.parseInt(s.replace(",", ""));
+ } catch (NumberFormatException exception) {
+ return 0;
+ }
+ }
+
+ public static boolean inAuctionPage() {
+ if (!NotEnoughUpdates.INSTANCE.config.ahTweaks.enableAhSellValue
+ || !NotEnoughUpdates.INSTANCE.isOnSkyblock()) return false;
+
+ Minecraft minecraft = Minecraft.getMinecraft();
+ if (minecraft == null || minecraft.thePlayer == null) return false;
+
+ Container inventoryContainer = minecraft.thePlayer.openContainer;
+ if (!(inventoryContainer instanceof ContainerChest)) return false;
+ ContainerChest containerChest = (ContainerChest) inventoryContainer;
+ return containerChest.getLowerChestInventory().getDisplayName()
+ .getUnformattedText().equalsIgnoreCase("Manage Auctions");
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionSortModeWarning.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionSortModeWarning.java
index 4b526185..ed05ee79 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionSortModeWarning.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/AuctionSortModeWarning.java
@@ -1,9 +1,28 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
import io.github.moulberry.notenoughupdates.core.util.render.TextRenderUtils;
-import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiChest;
@@ -21,55 +40,51 @@ public class AuctionSortModeWarning {
private boolean isAuctionBrowser() {
return NotEnoughUpdates.INSTANCE.config.ahTweaks.enableSortWarning &&
- Minecraft.getMinecraft().currentScreen instanceof GuiChest &&
- (SBInfo.getInstance().lastOpenContainerName.startsWith("Auctions Browser") ||
- SBInfo.getInstance().lastOpenContainerName.startsWith("Auctions: \""));
+ (Utils.getOpenChestName().startsWith("Auctions Browser") ||
+ Utils.getOpenChestName().startsWith("Auctions: \""));
}
public void onPostGuiRender() {
- if (isAuctionBrowser()) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
-
- ItemStack stack = chest.inventorySlots.getSlot(50).getStack();
-
- if (stack != null) {
- List<String> tooltip = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
-
- String selectedSort = null;
- for (String line : tooltip) {
- if (line.startsWith("\u00a75\u00a7o\u00a7b\u25B6 ")) {
- selectedSort = Utils.cleanColour(line.substring("\u00a75\u00a7o\u00a7b\u25B6 ".length()));
- }
- }
-
- if (selectedSort != null) {
- if (!selectedSort.trim().equals("Lowest Price")) {
- GlStateManager.disableLighting();
- GlStateManager.pushMatrix();
- GlStateManager.translate(0, 0, 500);
-
- String selectedColour = "\u00a7e";
-
- if (selectedSort.trim().equals("Highest Price")) {
- selectedColour = "\u00a7c";
- }
-
- String warningText = "\u00a7aSort: " + selectedColour + selectedSort;
- int warningLength = Minecraft.getMinecraft().fontRendererObj.getStringWidth(warningText);
-
- int centerX = chest.guiLeft + chest.xSize / 2 + 9;
- int centerY = chest.guiTop + 26;
-
- RenderUtils.drawFloatingRectDark(centerX - warningLength / 2 - 4, centerY - 6,
- warningLength + 8, 12, false
- );
- TextRenderUtils.drawStringCenteredScaledMaxWidth(warningText, Minecraft.getMinecraft().fontRendererObj,
- centerX, centerY, true, chest.width / 2, 0xffffffff
- );
- GlStateManager.popMatrix();
- }
- }
+ if (!isAuctionBrowser()) return;
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+
+ ItemStack stack = chest.inventorySlots.getSlot(50).getStack();
+
+ if (stack == null) return;
+ List<String> tooltip = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+
+ String selectedSort = null;
+ for (String line : tooltip) {
+ if (line.startsWith("\u00a75\u00a7o\u00a7b\u25B6 ")) {
+ selectedSort = Utils.cleanColour(line.substring("\u00a75\u00a7o\u00a7b\u25B6 ".length()));
}
}
+
+ if (selectedSort == null) return;
+ if (selectedSort.trim().equals("Lowest Price")) return;
+ GlStateManager.disableLighting();
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(0, 0, 500);
+
+ String selectedColour = "\u00a7e";
+
+ if (selectedSort.trim().equals("Highest Price")) {
+ selectedColour = "\u00a7c";
+ }
+
+ String warningText = "\u00a7aSort: " + selectedColour + selectedSort;
+ int warningLength = Minecraft.getMinecraft().fontRendererObj.getStringWidth(warningText);
+
+ int centerX =
+ ((AccessorGuiContainer) chest).getGuiLeft() + ((AccessorGuiContainer) chest).getXSize() / 2 + 9;
+ int centerY = ((AccessorGuiContainer) chest).getGuiTop() + 26;
+
+ RenderUtils.drawFloatingRectDark(centerX - warningLength / 2 - 4, centerY - 6,
+ warningLength + 8, 12, false
+ );
+ TextRenderUtils.drawStringCenteredScaledMaxWidth(warningText, Minecraft.getMinecraft().fontRendererObj,
+ centerX, centerY, true, chest.width / 2, 0xffffffff
+ );
+ GlStateManager.popMatrix();
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/BetterContainers.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/BetterContainers.java
index c1ce229c..ad0b238a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/BetterContainers.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/BetterContainers.java
@@ -1,8 +1,28 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.renderer.GlStateManager;
@@ -18,6 +38,7 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import javax.imageio.ImageIO;
import java.awt.*;
@@ -69,7 +90,7 @@ public class BetterContainers {
public static void bindHook(TextureManager textureManager, ResourceLocation location) {
long currentMillis = System.currentTimeMillis();
- if (isChestOpen() && NEUEventListener.inventoryLoaded) {
+ if (isChestOpen() && RenderListener.inventoryLoaded) {
int invHashcode = lastInvHashcode;
if (currentMillis - lastHashcodeCheck > 50) {
@@ -544,4 +565,17 @@ public class BetterContainers {
return 0;
}
}
+
+ @SubscribeEvent
+ public void onMouseClick(SlotClickEvent event) {
+ if (!isOverriding()) return;
+ boolean isBlankStack = BetterContainers.isBlankStack(event.slot.slotNumber, event.slot.getStack());
+ if (!(isBlankStack ||
+ BetterContainers.isButtonStack(event.slot.slotNumber, event.slot.getStack()))) return;
+ clickSlot(event.slotId);
+ if (isBlankStack) {
+ event.usePickblockInstead();
+ }
+ }
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CollectionLogManager.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CollectionLogManager.java
deleted file mode 100644
index c550ce53..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CollectionLogManager.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package io.github.moulberry.notenoughupdates.miscfeatures;
-
-import io.github.moulberry.notenoughupdates.collectionlog.CollectionConstant;
-import io.github.moulberry.notenoughupdates.util.Constants;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.multiplayer.WorldClient;
-import net.minecraft.entity.Entity;
-import net.minecraft.entity.item.EntityArmorStand;
-
-import java.util.regex.Matcher;
-
-public class CollectionLogManager {
- private static final CollectionLogManager INSTANCE = new CollectionLogManager();
-
- public static CollectionLogManager getInstance() {
- return INSTANCE;
- }
-
- public void onEntityMetadataUpdated(int entityId) {
- System.out.println("entity created:" + entityId);
- WorldClient world = Minecraft.getMinecraft().theWorld;
- if (world != null) {
- Entity entity = world.getEntityByID(entityId);
-
- if (entity instanceof EntityArmorStand && entity.hasCustomName()) {
- String customName = entity.getName();
- System.out.println("got name:" + customName);
- for (CollectionConstant.DropEntry entry : Constants.COLLECTIONLOG.dropdata) {
- System.out.println("iter entry");
- if (entry.type.equalsIgnoreCase("itemdrop")) {
- Matcher matcher = entry.regex.matcher(customName);
- if (matcher.matches()) {
- System.out.println("Match found!");
- System.out.println("Count: " + matcher.group("count"));
- System.out.println("Name: " + matcher.group("itemname"));
- } else {
- System.out.println("Doesn't match: " + customName);
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java
new file mode 100644
index 00000000..f21d0c50
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CookieWarning.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import com.google.common.collect.Lists;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiPlayerTabOverlay;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+
+public class CookieWarning {
+
+ private static boolean hasNotified;
+
+ public static void resetNotification() {
+ hasNotified = false;
+ NotificationHandler.cancelNotification();
+ }
+
+ /**
+ * Checks the tab list for a cookie timer, and sends a notification if the timer is within the tolerance
+ */
+ public static void checkCookie() {
+ if (NotEnoughUpdates.INSTANCE.config.notifications.doBoosterNotif &&
+ NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ String[] lines;
+ try {
+ lines = ((AccessorGuiPlayerTabOverlay) Minecraft.getMinecraft().ingameGUI.getTabList())
+ .getFooter()
+ .getUnformattedText()
+ .split("\n");
+ } catch (NullPointerException e) {
+ return; // if the footer is null or somehow doesn't exist, stop
+ }
+ boolean hasCookie = true;
+ String timeLine = null; // the line that contains the cookie timer
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].startsWith("Cookie Buff")) {
+ timeLine = lines[i + 1]; // the line after the "Cookie Buff" line
+ }
+ if (lines[i].startsWith("Not active! Obtain booster cookies from the")) {
+ hasCookie = false;
+ }
+ }
+ if (!hasCookie) {
+ if (!hasNotified) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ "\u00a7cBooster Cookie Ran Out!",
+ "\u00a77Your Booster Cookie expired!",
+ "\u00a77",
+ "\u00a77Press X on your keyboard to close this notification"
+ ), true, true);
+ hasNotified = true;
+ }
+ return;
+ }
+ if (timeLine != null) {
+ String[] digits = timeLine.split(" ");
+ int minutes = 0;
+ try {
+ for (String digit : digits) {
+ if (digit.endsWith("y")) {
+ digit = digit.substring(0, digit.length() - 1);
+ minutes += Integer.parseInt(digit) * 525600;
+ } else if (digit.endsWith("d")) {
+ digit = digit.substring(0, digit.length() - 1);
+ minutes += Integer.parseInt(digit) * 1440;
+ } else if (digit.endsWith("h")) {
+ digit = digit.substring(0, digit.length() - 1);
+ minutes += Integer.parseInt(digit) * 60;
+ } else if (digit.endsWith("m")) {
+ digit = digit.substring(0, digit.length() - 1);
+ minutes += Integer.parseInt(digit);
+ } // ignore seconds
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED +
+ "NEU ran into an issue when retrieving the Booster Cookie Timer. Check the logs for details."));
+ hasNotified = true;
+ }
+ if (minutes < NotEnoughUpdates.INSTANCE.config.notifications.boosterCookieWarningMins && !hasNotified) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ "\u00a7cBooster Cookie Running Low!",
+ "\u00a77Your Booster Cookie will expire in " + timeLine,
+ "\u00a77",
+ "\u00a77Press X on your keyboard to close this notification"
+ ), true, true);
+ hasNotified = true;
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java
index 4586d190..ab9345cb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolver.java
@@ -1,32 +1,157 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag;
+import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import net.minecraft.client.Minecraft;
-import net.minecraft.util.*;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+import net.minecraft.util.Vec3i;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.stream.Collectors;
public class CrystalMetalDetectorSolver {
+ enum SolutionState {
+ NOT_STARTED,
+ MULTIPLE,
+ MULTIPLE_KNOWN,
+ FOUND,
+ FOUND_KNOWN,
+ FAILED,
+ INVALID,
+ }
+
private static final Minecraft mc = Minecraft.getMinecraft();
- private static BlockPos prevPlayerPos;
- private static double prevDistToTreasure = 0;
- private static List<BlockPos> possibleBlocks = new ArrayList<>();
- private static final List<BlockPos> locations = new ArrayList<>();
- private static Boolean chestRecentlyFound = false;
- private static long chestLastFoundMillis = 0;
+ private static Vec3Comparable prevPlayerPos;
+ private static double prevDistToTreasure;
+ private static HashSet<BlockPos> possibleBlocks = new HashSet<>();
+ private static final HashMap<Vec3Comparable, Double> evaluatedPlayerPositions = new HashMap<>();
+ private static boolean chestRecentlyFound;
+ private static long chestLastFoundMillis;
+ private static final HashSet<BlockPos> openedChestPositions = new HashSet<>();
+
+ // Keeper and Mines of Divan center location info
+ private static Vec3i minesCenter;
+ private static boolean debugDoNotUseCenter = false;
+ private static boolean visitKeeperMessagePrinted;
+ private static final String KEEPER_OF_STRING = "Keeper of ";
+ private static final String DIAMOND_STRING = "diamond";
+ private static final String LAPIS_STRING = "lapis";
+ private static final String EMERALD_STRING = "emerald";
+ private static final String GOLD_STRING = "gold";
+ private static final HashMap<String, Vec3i> keeperOffsets = new HashMap<String, Vec3i>() {{
+ put(DIAMOND_STRING, new Vec3i(33, 0, 3));
+ put(LAPIS_STRING, new Vec3i(-33, 0, -3));
+ put(EMERALD_STRING, new Vec3i(-3, 0, 33));
+ put(GOLD_STRING, new Vec3i(3, 0, -33));
+ }};
+
+ // Chest offsets from center
+ private static final HashSet<Long> knownChestOffsets = new HashSet<>(Arrays.asList(
+ -10171958951910L, // x=-38, y=-22, z=26
+ 10718829084646L, // x=38, y=-22, z=-26
+ -10721714765806L, // x=-40, y=-22, z=18
+ -10996458455018L, // x=-41, y=-20, z=22
+ -1100920913904L, // x=-5, y=-21, z=16
+ 11268584898530L, // x=40, y=-22, z=-30
+ -11271269253148L, // x=-42, y=-20, z=-28
+ -11546281377832L, // x=-43, y=-22, z=-40
+ 11818542038999L, // x=42, y=-19, z=-41
+ 12093285728240L, // x=43, y=-21, z=-16
+ -1409286164L, // x=-1, y=-22, z=-20
+ 1922736062492L, // x=6, y=-21, z=28
+ 2197613969419L, // x=7, y=-21, z=11
+ 2197613969430L, // x=7, y=-21, z=22
+ -3024999153708L, // x=-12, y=-21, z=-44
+ 3571936395295L, // x=12, y=-22, z=31
+ 3572003504106L, // x=12, y=-22, z=-22
+ 3572003504135L, // x=12, y=-21, z=7
+ 3572070612949L, // x=12, y=-21, z=-43
+ -3574822076373L, // x=-14, y=-21, z=43
+ -3574822076394L, // x=-14, y=-21, z=22
+ -4399455797228L, // x=-17, y=-21, z=20
+ -5224156626944L, // x=-20, y=-22, z=0
+ 548346527764L, // x=1, y=-21, z=20
+ 5496081743901L, // x=19, y=-22, z=29
+ 5770959650816L, // x=20, y=-22, z=0
+ 5771093868518L, // x=20, y=-21, z=-26
+ -6048790347736L, // x=-23, y=-22, z=40
+ 6320849682418L, // x=22, y=-21, z=-14
+ -6323668254708L, // x=-24, y=-22, z=12
+ 6595593371674L, // x=23, y=-22, z=26
+ 6595660480473L, // x=23, y=-22, z=-39
+ 6870471278619L, // x=24, y=-22, z=27
+ 7145349185553L, // x=25, y=-22, z=17
+ 8244995030996L, // x=29, y=-21, z=-44
+ -8247679385612L, // x=-31, y=-21, z=-12
+ -8247679385640L, // x=-31, y=-21, z=-40
+ 8519872937959L, // x=30, y=-21, z=-25
+ -8522557292584L, // x=-32, y=-21, z=-40
+ -9622068920278L, // x=-36, y=-20, z=42
+ -9896946827278L, // x=-37, y=-21, z=-14
+ -9896946827286L // x=-37, y=-21, z=-22
+ ));
+
+ static Predicate<BlockPos> treasureAllowedPredicate = CrystalMetalDetectorSolver::treasureAllowed;
+ static SolutionState currentState = SolutionState.NOT_STARTED;
+ static SolutionState previousState = SolutionState.NOT_STARTED;
+
+ public interface Predicate<BlockPos> {
+ boolean check(BlockPos blockPos);
+ }
public static void process(IChatComponent message) {
+ if (SBInfo.getInstance().getLocation() == null ||
+ !NotEnoughUpdates.INSTANCE.config.mining.metalDetectorEnabled ||
+ !SBInfo.getInstance().getLocation().equals("crystal_hollows") ||
+ !message.getUnformattedText().contains("TREASURE: ")) {
+ return;
+ }
+
+ boolean centerNewlyDiscovered = locateMinesCenterIfNeeded();
+
+ double distToTreasure = Double.parseDouble(message
+ .getUnformattedText()
+ .split("TREASURE: ")[1].split("m")[0].replaceAll("(?!\\.)\\D", ""));
+
// Delay to keep old chest location from being treated as the new chest location
if (chestRecentlyFound) {
long currentTimeMillis = System.currentTimeMillis();
if (chestLastFoundMillis == 0) {
chestLastFoundMillis = currentTimeMillis;
return;
- } else if (currentTimeMillis - chestLastFoundMillis < 1000) {
+ } else if (currentTimeMillis - chestLastFoundMillis < 1000 && distToTreasure < 5.0) {
return;
}
@@ -34,80 +159,185 @@ public class CrystalMetalDetectorSolver {
chestRecentlyFound = false;
}
- if (SBInfo.getInstance().getLocation() != null && SBInfo.getInstance().getLocation().equals("crystal_hollows")
- && message.getUnformattedText().contains("TREASURE: ")) {
- double distToTreasure = Double.parseDouble(message
- .getUnformattedText()
- .split("TREASURE: ")[1].split("m")[0].replaceAll("(?!\\.)\\D", ""));
- if (NotEnoughUpdates.INSTANCE.config.mining.metalDetectorEnabled && prevDistToTreasure == distToTreasure &&
- prevPlayerPos.getX() == mc.thePlayer.getPosition().getX() &&
- prevPlayerPos.getY() == mc.thePlayer.getPosition().getY() &&
- prevPlayerPos.getZ() == mc.thePlayer.getPosition().getZ() && !locations.contains(mc.thePlayer.getPosition())) {
- if (possibleBlocks.size() == 0) {
- locations.add(mc.thePlayer.getPosition());
- for (int zOffset = (int) Math.floor(-distToTreasure); zOffset <= Math.ceil(distToTreasure); zOffset++) {
- for (int y = 65; y <= 75; y++) {
- double calculatedDist = 0;
- int xOffset = 0;
- while (calculatedDist < distToTreasure) {
- BlockPos pos = new BlockPos(Math.floor(mc.thePlayer.posX) + xOffset,
- y, Math.floor(mc.thePlayer.posZ) + zOffset
- );
- calculatedDist = getPlayerPos().distanceTo(new Vec3(pos).addVector(0D, 1D, 0D));
- if (round(calculatedDist, 1) == distToTreasure && !possibleBlocks.contains(pos) &&
- treasureAllowed(pos) && mc.theWorld.
- getBlockState(pos.add(0, 1, 0)).getBlock().getRegistryName().equals("minecraft:air")) {
- possibleBlocks.add(pos);
- }
- xOffset++;
- }
- xOffset = 0;
- calculatedDist = 0;
- while (calculatedDist < distToTreasure) {
- BlockPos pos = new BlockPos(Math.floor(mc.thePlayer.posX) - xOffset,
- y, Math.floor(mc.thePlayer.posZ) + zOffset
- );
- calculatedDist = getPlayerPos().distanceTo(new Vec3(pos).addVector(0D, 1D, 0D));
- if (round(calculatedDist, 1) == distToTreasure && !possibleBlocks.contains(pos) &&
- treasureAllowed(pos) && mc.theWorld.
- getBlockState(pos.add(0, 1, 0)).getBlock().getRegistryName().equals("minecraft:air")) {
- possibleBlocks.add(pos);
- }
- xOffset++;
+ SolutionState originalState = currentState;
+ int originalCount = possibleBlocks.size();
+ Vec3Comparable adjustedPlayerPos = getPlayerPosAdjustedForEyeHeight();
+ findPossibleSolutions(distToTreasure, adjustedPlayerPos, centerNewlyDiscovered);
+ if (currentState != originalState || originalCount != possibleBlocks.size()) {
+ switch (currentState) {
+ case FOUND_KNOWN:
+ NEUDebugLogger.log(NEUDebugFlag.METAL, "Known location identified.");
+ // falls through
+ case FOUND:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU] Found solution."));
+ if (NEUDebugFlag.METAL.isSet() &&
+ (previousState == SolutionState.INVALID || previousState == SolutionState.FAILED)) {
+ NEUDebugLogger.log(
+ NEUDebugFlag.METAL,
+ EnumChatFormatting.AQUA + "Solution coordinates: " +
+ EnumChatFormatting.WHITE + possibleBlocks.iterator().next().toString()
+ );
+ }
+ break;
+ case INVALID:
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "[NEU] Previous solution is invalid."));
+ logDiagnosticData(false);
+ resetSolution(false);
+ break;
+ case FAILED:
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "[NEU] Failed to find a solution."));
+ logDiagnosticData(false);
+ resetSolution(false);
+ break;
+ case MULTIPLE_KNOWN:
+ NEUDebugLogger.log(NEUDebugFlag.METAL, "Multiple known locations identified:");
+ // falls through
+ case MULTIPLE:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Need another position to find solution. Possible blocks: " + possibleBlocks.size()));
+ break;
+ default:
+ throw new IllegalStateException("Metal detector is in invalid state");
+ }
+ }
+ }
+
+ static void findPossibleSolutions(double distToTreasure, Vec3Comparable playerPos, boolean centerNewlyDiscovered) {
+ if (prevDistToTreasure == distToTreasure && prevPlayerPos.equals(playerPos) &&
+ !evaluatedPlayerPositions.containsKey(playerPos)) {
+ evaluatedPlayerPositions.put(playerPos, distToTreasure);
+ if (possibleBlocks.size() == 0) {
+ for (int zOffset = (int) Math.floor(-distToTreasure); zOffset <= Math.ceil(distToTreasure); zOffset++) {
+ for (int y = 65; y <= 75; y++) {
+ double calculatedDist = 0;
+ int xOffset = 0;
+ while (calculatedDist < distToTreasure) {
+ BlockPos pos = new BlockPos(Math.floor(playerPos.xCoord) + xOffset,
+ y, Math.floor(playerPos.zCoord) + zOffset
+ );
+ calculatedDist = playerPos.distanceTo(new Vec3Comparable(pos).addVector(0D, 1D, 0D));
+ if (round(calculatedDist, 1) == distToTreasure && treasureAllowedPredicate.check(pos)) {
+ possibleBlocks.add(pos);
}
+ xOffset++;
}
- }
- sendMessage();
- } else if (possibleBlocks.size() != 1) {
- locations.add(mc.thePlayer.getPosition());
- List<BlockPos> temp = new ArrayList<>();
- for (BlockPos pos : possibleBlocks) {
- if (round(getPlayerPos().distanceTo(new Vec3(pos).addVector(0D, 1D, 0D)), 1) == distToTreasure) {
- temp.add(pos);
+ xOffset = 0;
+ calculatedDist = 0;
+ while (calculatedDist < distToTreasure) {
+ BlockPos pos = new BlockPos(Math.floor(playerPos.xCoord) - xOffset,
+ y, Math.floor(playerPos.zCoord) + zOffset
+ );
+ calculatedDist = playerPos.distanceTo(new Vec3Comparable(pos).addVector(0D, 1D, 0D));
+ if (round(calculatedDist, 1) == distToTreasure && treasureAllowedPredicate.check(pos)) {
+ possibleBlocks.add(pos);
+ }
+ xOffset++;
}
}
- possibleBlocks = temp;
- sendMessage();
- } else {
- BlockPos pos = possibleBlocks.get(0);
- if (Math.abs(distToTreasure - (getPlayerPos().distanceTo(new Vec3(pos)))) > 5) {
- mc.thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.RED + "[NEU] Previous solution is invalid."));
- reset(false);
+ }
+
+ updateSolutionState();
+ } else if (possibleBlocks.size() != 1) {
+ HashSet<BlockPos> temp = new HashSet<>();
+ for (BlockPos pos : possibleBlocks) {
+ if (round(playerPos.distanceTo(new Vec3Comparable(pos).addVector(0D, 1D, 0D)), 1) == distToTreasure) {
+ temp.add(pos);
}
}
+ possibleBlocks = temp;
+ updateSolutionState();
+ } else {
+ BlockPos pos = possibleBlocks.iterator().next();
+ if (Math.abs(distToTreasure - (playerPos.distanceTo(new Vec3Comparable(pos)))) > 5) {
+ currentState = SolutionState.INVALID;
+ }
+ }
+ } else if (centerNewlyDiscovered && possibleBlocks.size() > 1) {
+ updateSolutionState();
+ }
+
+ prevPlayerPos = playerPos;
+ prevDistToTreasure = distToTreasure;
+ }
+
+ public static void setDebugDoNotUseCenter(boolean val) {
+ debugDoNotUseCenter = val;
+ }
+
+ private static String getFriendlyBlockPositions(Collection<BlockPos> positions) {
+ if (!NEUDebugLogger.isFlagEnabled(NEUDebugFlag.METAL) || positions.size() == 0) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("\n");
+ for (BlockPos blockPos : positions) {
+ sb.append("Absolute: ");
+ sb.append(blockPos.toString());
+ if (minesCenter != Vec3i.NULL_VECTOR) {
+ BlockPos relativeOffset = blockPos.subtract(minesCenter);
+ sb.append(", Relative: ");
+ sb.append(relativeOffset.toString());
+ sb.append(" (" + relativeOffset.toLong() + ")");
+ }
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+ private static String getFriendlyEvaluatedPositions() {
+ if (!NEUDebugLogger.isFlagEnabled(NEUDebugFlag.METAL) || evaluatedPlayerPositions.size() == 0) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("\n");
+ for (Vec3Comparable vec : evaluatedPlayerPositions.keySet()) {
+ sb.append("Absolute: " + vec.toString());
+ if (minesCenter != Vec3i.NULL_VECTOR) {
+ BlockPos positionBlockPos = new BlockPos(vec);
+ BlockPos relativeOffset = positionBlockPos.subtract(minesCenter);
+ sb.append(", Relative: " + relativeOffset.toString() + " (" + relativeOffset.toLong() + ")");
}
- prevPlayerPos = mc.thePlayer.getPosition();
- prevDistToTreasure = distToTreasure;
+ sb.append(" Distance: ");
+ sb.append(evaluatedPlayerPositions.get(vec));
+
+ sb.append("\n");
}
+
+ return sb.toString();
}
- public static void reset(Boolean chestFound) {
+ public static void resetSolution(Boolean chestFound) {
+ if (chestFound) {
+ prevPlayerPos = null;
+ prevDistToTreasure = 0;
+ if (possibleBlocks.size() == 1) {
+ openedChestPositions.add(possibleBlocks.iterator().next().getImmutable());
+ }
+ }
+
chestRecentlyFound = chestFound;
possibleBlocks.clear();
- locations.clear();
+ evaluatedPlayerPositions.clear();
+ previousState = currentState;
+ currentState = SolutionState.NOT_STARTED;
+ }
+
+ public static void initWorld() {
+ minesCenter = Vec3i.NULL_VECTOR;
+ visitKeeperMessagePrinted = false;
+ openedChestPositions.clear();
+ chestLastFoundMillis = 0;
+ prevDistToTreasure = 0;
+ prevPlayerPos = null;
+ currentState = SolutionState.NOT_STARTED;
+ resetSolution(false);
}
public static void render(float partialTicks) {
@@ -117,10 +347,10 @@ public class CrystalMetalDetectorSolver {
SBInfo.getInstance().location.equals("Mines of Divan")) {
if (possibleBlocks.size() == 1) {
- BlockPos block = possibleBlocks.get(0);
+ BlockPos block = possibleBlocks.iterator().next();
RenderUtils.renderBeaconBeam(block.add(0, 1, 0), beaconRGB, 1.0f, partialTicks);
- RenderUtils.renderWayPoint("Treasure", possibleBlocks.get(0).add(0, 2.5, 0), partialTicks);
+ RenderUtils.renderWayPoint("Treasure", possibleBlocks.iterator().next().add(0, 2.5, 0), partialTicks);
} else if (possibleBlocks.size() > 1 && NotEnoughUpdates.INSTANCE.config.mining.metalDetectorShowPossible) {
for (BlockPos block : possibleBlocks) {
RenderUtils.renderBeaconBeam(block.add(0, 1, 0), beaconRGB, 1.0f, partialTicks);
@@ -130,33 +360,106 @@ public class CrystalMetalDetectorSolver {
}
}
+ private static boolean locateMinesCenterIfNeeded() {
+ if (minesCenter != Vec3i.NULL_VECTOR) {
+ return false;
+ }
+
+ List<EntityArmorStand> keeperEntities = mc.theWorld.getEntities(EntityArmorStand.class, (entity) -> {
+ if (!entity.hasCustomName()) return false;
+ return entity.getCustomNameTag().contains(KEEPER_OF_STRING);
+ });
+
+ if (keeperEntities.size() == 0) {
+ if (!visitKeeperMessagePrinted) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Approach a Keeper while holding the metal detector to enable faster treasure hunting."));
+ visitKeeperMessagePrinted = true;
+ }
+ return false;
+ }
+
+ EntityArmorStand keeperEntity = keeperEntities.get(0);
+ String keeperName = keeperEntity.getCustomNameTag();
+ NEUDebugLogger.log(NEUDebugFlag.METAL, "Locating center using Keeper: " +
+ EnumChatFormatting.WHITE + keeperEntity);
+ String keeperType = keeperName.substring(keeperName.indexOf(KEEPER_OF_STRING) + KEEPER_OF_STRING.length());
+ minesCenter = keeperEntity.getPosition().add(keeperOffsets.get(keeperType.toLowerCase()));
+ NEUDebugLogger.log(NEUDebugFlag.METAL, "Mines center: " +
+ EnumChatFormatting.WHITE + minesCenter.toString());
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.YELLOW + "[NEU] Faster treasure hunting is now enabled based on Keeper location."));
+ return true;
+ }
+
+ public static void setMinesCenter(BlockPos center) {
+ minesCenter = center;
+ }
+
private static double round(double value, int precision) {
int scale = (int) Math.pow(10, precision);
return (double) Math.round(value * scale) / scale;
}
- private static void sendMessage() {
- if (possibleBlocks.size() > 1) {
- mc.thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.YELLOW + "[NEU] Need another position to find solution. Possible blocks: "
- + possibleBlocks.size()));
- } else if (possibleBlocks.size() == 0) {
- mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED + "[NEU] Failed to find solution."));
- reset(false);
- } else {
- mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU] Found solution."));
+ private static void updateSolutionState() {
+ previousState = currentState;
+
+ if (possibleBlocks.size() == 0) {
+ currentState = SolutionState.FAILED;
+ return;
+ }
+
+ if (possibleBlocks.size() == 1) {
+ currentState = SolutionState.FOUND;
+ return;
+ }
+
+ // Narrow solutions using known locations if the mines center is known
+ if (minesCenter.equals(BlockPos.NULL_VECTOR) || debugDoNotUseCenter) {
+ currentState = SolutionState.MULTIPLE;
+ return;
+ }
+
+ HashSet<BlockPos> temp =
+ possibleBlocks.stream()
+ .filter(block -> knownChestOffsets.contains(block.subtract(minesCenter).toLong()))
+ .collect(Collectors.toCollection(HashSet::new));
+ if (temp.size() == 0) {
+ currentState = SolutionState.MULTIPLE;
+ return;
}
+
+ if (temp.size() == 1) {
+ possibleBlocks = temp;
+ currentState = SolutionState.FOUND_KNOWN;
+ return;
+
+ }
+
+ currentState = SolutionState.MULTIPLE_KNOWN;
}
- private static Vec3 getPlayerPos() {
- return new Vec3(
+ public static BlockPos getSolution() {
+ if (CrystalMetalDetectorSolver.possibleBlocks.size() != 1) {
+ return BlockPos.ORIGIN;
+ }
+
+ return CrystalMetalDetectorSolver.possibleBlocks.stream().iterator().next();
+ }
+
+ private static Vec3Comparable getPlayerPosAdjustedForEyeHeight() {
+ return new Vec3Comparable(
mc.thePlayer.posX,
mc.thePlayer.posY + (mc.thePlayer.getEyeHeight() - mc.thePlayer.getDefaultEyeHeight()),
mc.thePlayer.posZ
);
}
- private static boolean treasureAllowed(BlockPos pos) {
+ static boolean isKnownOffset(BlockPos pos) {
+ return knownChestOffsets.contains(pos.subtract(minesCenter).toLong());
+ }
+
+ static boolean isAllowedBlockType(BlockPos pos) {
return mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:gold_block") ||
mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:prismarine") ||
mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:chest") ||
@@ -165,4 +468,106 @@ public class CrystalMetalDetectorSolver {
mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:wool") ||
mc.theWorld.getBlockState(pos).getBlock().getRegistryName().equals("minecraft:stained_hardened_clay");
}
+
+ static boolean isAirAbove(BlockPos pos) {
+ return mc.theWorld.
+ getBlockState(pos.add(0, 1, 0)).getBlock().getRegistryName().equals("minecraft:air");
+ }
+
+ private static boolean treasureAllowed(BlockPos pos) {
+ boolean airAbove = isAirAbove(pos);
+ boolean allowedBlockType = isAllowedBlockType(pos);
+ return isKnownOffset(pos) || (airAbove && allowedBlockType);
+ }
+
+ static private String getDiagnosticMessage() {
+ StringBuilder diagsMessage = new StringBuilder();
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Mines Center: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((minesCenter.equals(Vec3i.NULL_VECTOR)) ? "<NOT DISCOVERED>" : minesCenter.toString());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Current Solution State: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(currentState.name());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Previous Solution State: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(previousState.name());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Previous Player Position: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((prevPlayerPos == null) ? "<NONE>" : prevPlayerPos.toString());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Previous Distance To Treasure: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((prevDistToTreasure == 0) ? "<NONE>" : prevDistToTreasure);
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Current Possible Blocks: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(possibleBlocks.size());
+ diagsMessage.append(getFriendlyBlockPositions(possibleBlocks));
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Evaluated player positions: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(evaluatedPlayerPositions.size());
+ diagsMessage.append(getFriendlyEvaluatedPositions());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Chest locations not on known list:\n");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ if (minesCenter != Vec3i.NULL_VECTOR) {
+ HashSet<BlockPos> locationsNotOnKnownList = openedChestPositions
+ .stream()
+ .filter(block -> !knownChestOffsets.contains(block.subtract(minesCenter).toLong()))
+ .map(block -> block.subtract(minesCenter))
+ .collect(Collectors.toCollection(HashSet::new));
+ if (locationsNotOnKnownList.size() > 0) {
+ for (BlockPos blockPos : locationsNotOnKnownList) {
+ diagsMessage.append(String.format(
+ "%dL,\t\t// x=%d, y=%d, z=%d",
+ blockPos.toLong(),
+ blockPos.getX(),
+ blockPos.getY(),
+ blockPos.getZ()
+ ));
+ }
+ }
+ } else {
+ diagsMessage.append("<REQUIRES MINES CENTER>");
+ }
+
+ return diagsMessage.toString();
+ }
+
+ public static void logDiagnosticData(boolean outputAlways) {
+ if (!SBInfo.getInstance().checkForSkyblockLocation()) {
+ return;
+ }
+
+ if (!NotEnoughUpdates.INSTANCE.config.mining.metalDetectorEnabled) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Metal Detector Solver is not enabled."));
+ return;
+ }
+
+ boolean metalDebugFlagSet = NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.contains(NEUDebugFlag.METAL);
+ if (outputAlways || metalDebugFlagSet) {
+ NEUDebugLogger.logAlways(getDiagnosticMessage());
+ }
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalOverlay.java
index 2b095c42..c0653742 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java
new file mode 100644
index 00000000..0ee29b4f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolver.java
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.Line;
+import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable;
+import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag;
+import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.EnumParticleTypes;
+import net.minecraft.util.Vec3i;
+import net.minecraftforge.client.ClientCommandHandler;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import net.minecraftforge.event.world.WorldEvent;
+import net.minecraftforge.fml.common.Loader;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.function.BooleanSupplier;
+import java.util.function.LongSupplier;
+
+public class CrystalWishingCompassSolver {
+ enum SolverState {
+ NOT_STARTED,
+ PROCESSING_FIRST_USE,
+ NEED_SECOND_COMPASS,
+ PROCESSING_SECOND_USE,
+ SOLVED,
+ FAILED_EXCEPTION,
+ FAILED_TIMEOUT_NO_REPEATING,
+ FAILED_TIMEOUT_NO_PARTICLES,
+ FAILED_INTERSECTION_CALCULATION,
+ FAILED_INVALID_SOLUTION,
+ }
+
+ enum CompassTarget {
+ GOBLIN_QUEEN,
+ GOBLIN_KING,
+ BAL,
+ JUNGLE_TEMPLE,
+ ODAWA,
+ PRECURSOR_CITY,
+ MINES_OF_DIVAN,
+ CRYSTAL_NUCLEUS,
+ }
+
+ enum Crystal {
+ AMBER,
+ AMETHYST,
+ JADE,
+ SAPPHIRE,
+ TOPAZ,
+ }
+
+ enum HollowsZone {
+ CRYSTAL_NUCLEUS,
+ JUNGLE,
+ MITHRIL_DEPOSITS,
+ GOBLIN_HOLDOUT,
+ PRECURSOR_REMNANTS,
+ MAGMA_FIELDS,
+ }
+
+ private static final CrystalWishingCompassSolver INSTANCE = new CrystalWishingCompassSolver();
+
+ public static CrystalWishingCompassSolver getInstance() {
+ return INSTANCE;
+ }
+
+ private static final Minecraft mc = Minecraft.getMinecraft();
+ private static boolean isSkytilsPresent = false;
+ private static final ArrayDeque<ParticleData> seenParticles = new ArrayDeque<>();
+
+ // There is a small set of breakable blocks above the nucleus at Y > 181. While this zone is reported
+ // as the Crystal Nucleus by Hypixel, for wishing compass purposes it is in the appropriate quadrant.
+ private static final AxisAlignedBB NUCLEUS_BB = new AxisAlignedBB(462, 63, 461, 564, 181, 565);
+ // Bounding box around all breakable blocks in the crystal hollows, appears as bedrock in-game
+ private static final AxisAlignedBB HOLLOWS_BB = new AxisAlignedBB(201, 30, 201, 824, 189, 824);
+
+ // Zone bounding boxes
+ private static final AxisAlignedBB PRECURSOR_REMNANTS_BB = new AxisAlignedBB(512, 63, 512, 824, 189, 824);
+ private static final AxisAlignedBB MITHRIL_DEPOSITS_BB = new AxisAlignedBB(512, 63, 201, 824, 189, 513);
+ private static final AxisAlignedBB GOBLIN_HOLDOUT_BB = new AxisAlignedBB(201, 63, 512, 513, 189, 824);
+ private static final AxisAlignedBB JUNGLE_BB = new AxisAlignedBB(201, 63, 201, 513, 189, 513);
+ private static final AxisAlignedBB MAGMA_FIELDS_BB = new AxisAlignedBB(201, 30, 201, 824, 64, 824);
+
+ // Structure bounding boxes (size + 2 in each dimension to make it an actual bounding box)
+ private static final AxisAlignedBB PRECURSOR_CITY_BB = new AxisAlignedBB(0, 0, 0, 107, 122, 107);
+ private static final AxisAlignedBB GOBLIN_KING_BB = new AxisAlignedBB(0, 0, 0, 59, 53, 56);
+ private static final AxisAlignedBB GOBLIN_QUEEN_BB = new AxisAlignedBB(0, 0, 0, 108, 114, 108);
+ private static final AxisAlignedBB JUNGLE_TEMPLE_BB = new AxisAlignedBB(0, 0, 0, 108, 120, 108);
+ private static final AxisAlignedBB ODAWA_BB = new AxisAlignedBB(0, 0, 0, 53, 46, 54);
+ private static final AxisAlignedBB MINES_OF_DIVAN_BB = new AxisAlignedBB(0, 0, 0, 108, 125, 108);
+ private static final AxisAlignedBB KHAZAD_DUM_BB = new AxisAlignedBB(0, 0, 0, 110, 46, 108);
+
+ private static final Vec3Comparable JUNGLE_DOOR_OFFSET_FROM_CRYSTAL = new Vec3Comparable(-57, 36, -21);
+
+ private static final double MAX_DISTANCE_BETWEEN_PARTICLES = 0.6;
+ private static final double MAX_DISTANCE_FROM_USE_TO_FIRST_PARTICLE = 9.0;
+
+ // 64.0 is an arbitrary value but seems to work well
+ private static final double MINIMUM_DISTANCE_SQ_BETWEEN_COMPASSES = 64.0;
+
+ // All particles typically arrive in < 3500, so 5000 should be enough buffer
+ public static final long ALL_PARTICLES_MAX_MILLIS = 5000L;
+
+ public LongSupplier currentTimeMillis = System::currentTimeMillis;
+ public BooleanSupplier kingsScentPresent = this::isKingsScentPresent;
+ public BooleanSupplier keyInInventory = this::isKeyInInventory;
+
+ public interface CrystalEnumSetSupplier {
+ EnumSet<Crystal> getAsCrystalEnumSet();
+ }
+
+ public CrystalEnumSetSupplier foundCrystals = this::getFoundCrystals;
+
+ private SolverState solverState;
+ private Compass firstCompass;
+ private Compass secondCompass;
+ private Line solutionIntersectionLine;
+ private EnumSet<CompassTarget> possibleTargets;
+ private Vec3Comparable solution;
+ private Vec3Comparable originalSolution;
+ private EnumSet<CompassTarget> solutionPossibleTargets;
+
+ public SolverState getSolverState() {
+ return solverState;
+ }
+
+ public Vec3i getSolutionCoords() {
+ return new Vec3i(solution.xCoord, solution.yCoord, solution.zCoord);
+ }
+
+ public EnumSet<CompassTarget> getPossibleTargets() {
+ return possibleTargets;
+ }
+
+ public static HollowsZone getZoneForCoords(BlockPos blockPos) {
+ return getZoneForCoords(new Vec3Comparable(blockPos));
+ }
+
+ public static HollowsZone getZoneForCoords(Vec3Comparable coords) {
+ if (NUCLEUS_BB.isVecInside(coords)) return HollowsZone.CRYSTAL_NUCLEUS;
+ if (JUNGLE_BB.isVecInside(coords)) return HollowsZone.JUNGLE;
+ if (MITHRIL_DEPOSITS_BB.isVecInside(coords)) return HollowsZone.MITHRIL_DEPOSITS;
+ if (GOBLIN_HOLDOUT_BB.isVecInside(coords)) return HollowsZone.GOBLIN_HOLDOUT;
+ if (PRECURSOR_REMNANTS_BB.isVecInside(coords)) return HollowsZone.PRECURSOR_REMNANTS;
+ if (MAGMA_FIELDS_BB.isVecInside(coords)) return HollowsZone.MAGMA_FIELDS;
+ throw new IllegalArgumentException("Coordinates do not fall in known zone: " + coords.toString());
+ }
+
+ private void resetForNewTarget() {
+ NEUDebugLogger.log(NEUDebugFlag.WISHING, "Resetting for new target");
+ solverState = SolverState.NOT_STARTED;
+ firstCompass = null;
+ secondCompass = null;
+ solutionIntersectionLine = null;
+ possibleTargets = null;
+ solution = null;
+ originalSolution = null;
+ solutionPossibleTargets = null;
+ }
+
+ public void initWorld() {
+ resetForNewTarget();
+ }
+
+ @SubscribeEvent
+ public void onWorldLoad(WorldEvent.Unload event) {
+ initWorld();
+ isSkytilsPresent = Loader.isModLoaded("skytils");
+ }
+
+ @SubscribeEvent
+ public void onPlayerInteract(PlayerInteractEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.mining.wishingCompassSolver ||
+ SBInfo.getInstance().getLocation() == null ||
+ !SBInfo.getInstance().getLocation().equals("crystal_hollows") ||
+ event.entityPlayer != mc.thePlayer ||
+ (event.action != PlayerInteractEvent.Action.RIGHT_CLICK_AIR &&
+ event.action != PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK)
+ ) {
+ return;
+ }
+
+ ItemStack heldItem = event.entityPlayer.getHeldItem();
+ if (heldItem == null || heldItem.getItem() != Items.skull) {
+ return;
+ }
+
+ String heldInternalName = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(heldItem);
+ if (heldInternalName == null || !heldInternalName.equals("WISHING_COMPASS")) {
+ return;
+ }
+
+ BlockPos playerPos = mc.thePlayer.getPosition().getImmutable();
+
+ try {
+ HandleCompassResult result = handleCompassUse(playerPos);
+ switch (result) {
+ case SUCCESS:
+ return;
+ case STILL_PROCESSING_PRIOR_USE:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Wait a little longer before using the wishing compass again."));
+ event.setCanceled(true);
+ break;
+ case LOCATION_TOO_CLOSE:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Move a little further before using the wishing compass again."));
+ event.setCanceled(true);
+ break;
+ case POSSIBLE_TARGETS_CHANGED:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Possible wishing compass targets have changed. Solver has been reset."));
+ event.setCanceled(true);
+ break;
+ case NO_PARTICLES_FOR_PREVIOUS_COMPASS:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] No particles detected for prior compass use. Need another position to solve."));
+ break;
+ case PLAYER_IN_NUCLEUS:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Wishing compass must be used outside the nucleus for accurate results."));
+ event.setCanceled(true);
+ break;
+ default:
+ throw new IllegalStateException("Unexpected wishing compass solver state: \n" + getDiagnosticMessage());
+ }
+ } catch (Exception e) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Error processing wishing compass action - see log for details"));
+ e.printStackTrace();
+ event.setCanceled(true);
+ solverState = SolverState.FAILED_EXCEPTION;
+ }
+ }
+
+ public HandleCompassResult handleCompassUse(BlockPos playerPos) {
+ long lastCompassUsedMillis = 0;
+ switch (solverState) {
+ case PROCESSING_SECOND_USE:
+ if (secondCompass != null) {
+ lastCompassUsedMillis = secondCompass.whenUsedMillis;
+ }
+ case PROCESSING_FIRST_USE:
+ if (lastCompassUsedMillis == 0 && firstCompass != null) {
+ lastCompassUsedMillis = firstCompass.whenUsedMillis;
+ }
+ if (lastCompassUsedMillis != 0 &&
+ (currentTimeMillis.getAsLong() > lastCompassUsedMillis + ALL_PARTICLES_MAX_MILLIS)) {
+ return HandleCompassResult.NO_PARTICLES_FOR_PREVIOUS_COMPASS;
+ }
+
+ return HandleCompassResult.STILL_PROCESSING_PRIOR_USE;
+ case SOLVED:
+ case FAILED_EXCEPTION:
+ case FAILED_TIMEOUT_NO_REPEATING:
+ case FAILED_TIMEOUT_NO_PARTICLES:
+ case FAILED_INTERSECTION_CALCULATION:
+ case FAILED_INVALID_SOLUTION:
+ resetForNewTarget();
+ // falls through, NOT_STARTED is the state when resetForNewTarget returns
+ case NOT_STARTED:
+ if (NUCLEUS_BB.isVecInside(new Vec3Comparable(playerPos.getX(), playerPos.getY(), playerPos.getZ()))) {
+ return HandleCompassResult.PLAYER_IN_NUCLEUS;
+ }
+
+ firstCompass = new Compass(playerPos, currentTimeMillis.getAsLong());
+ seenParticles.clear();
+ solverState = SolverState.PROCESSING_FIRST_USE;
+ possibleTargets = calculatePossibleTargets(playerPos);
+ return HandleCompassResult.SUCCESS;
+ case NEED_SECOND_COMPASS:
+ if (firstCompass.whereUsed.distanceSq(playerPos) < MINIMUM_DISTANCE_SQ_BETWEEN_COMPASSES) {
+ return HandleCompassResult.LOCATION_TOO_CLOSE;
+ }
+
+ HollowsZone firstCompassZone = getZoneForCoords(firstCompass.whereUsed);
+ HollowsZone playerZone = getZoneForCoords(playerPos);
+ if (!possibleTargets.equals(calculatePossibleTargets(playerPos)) ||
+ firstCompassZone != playerZone) {
+ resetForNewTarget();
+ return HandleCompassResult.POSSIBLE_TARGETS_CHANGED;
+ }
+
+ secondCompass = new Compass(playerPos, currentTimeMillis.getAsLong());
+ solverState = SolverState.PROCESSING_SECOND_USE;
+ return HandleCompassResult.SUCCESS;
+ }
+
+ throw new IllegalStateException("Unexpected compass state");
+ }
+
+ /*
+ * Processes particles if the wishing compass was used within the last 5 seconds.
+ *
+ * The first and the last particles are used to create a line for each wishing compass
+ * use that is then used to calculate the target.
+ *
+ * Once two lines have been calculated, the shortest line between the two is calculated
+ * with the midpoint on that line being the wishing compass target. The accuracy of this
+ * seems to be very high.
+ *
+ * The target location varies based on various criteria, including, but not limited to:
+ * Topaz Crystal (Khazad-dûm) Magma Fields
+ * Odawa (Jungle Village) Jungle w/no Jungle Key in inventory
+ * Amethyst Crystal (Jungle Temple) Jungle w/Jungle Key in inventory
+ * Sapphire Crystal (Lost Precursor City) Precursor Remnants
+ * Jade Crystal (Mines of Divan) Mithril Deposits
+ * King Yolkar Goblin Holdout without "King's Scent I" effect
+ * Goblin Queen Goblin Holdout with "King's Scent I" effect
+ * Crystal Nucleus All Crystals found and none placed
+ * per-area structure missing, or because Hypixel.
+ * Always within 1 block of X=513 Y=106 Z=551.
+ */
+ public void onSpawnParticle(
+ EnumParticleTypes particleType,
+ double x,
+ double y,
+ double z
+ ) {
+ if (!NotEnoughUpdates.INSTANCE.config.mining.wishingCompassSolver ||
+ particleType != EnumParticleTypes.VILLAGER_HAPPY ||
+ !SBInfo.getInstance().getLocation().equals("crystal_hollows")) {
+ return;
+ }
+
+ // Capture particle troubleshooting info for two minutes starting when the first compass is used.
+ // This list is reset each time the first compass is used from a NOT_STARTED state.
+ if (firstCompass != null && !solverState.equals(SolverState.SOLVED) &&
+ System.currentTimeMillis() < firstCompass.whenUsedMillis + 2 * 60 * 1000) {
+ seenParticles.add(new ParticleData(new Vec3Comparable(x, y, z), System.currentTimeMillis()));
+ }
+
+ try {
+ SolverState originalSolverState = solverState;
+ solveUsingParticle(x, y, z, currentTimeMillis.getAsLong());
+ if (solverState != originalSolverState) {
+ switch (solverState) {
+ case SOLVED:
+ showSolution();
+ break;
+ case FAILED_EXCEPTION:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Unable to determine wishing compass target."));
+ logDiagnosticData(false);
+ break;
+ case FAILED_TIMEOUT_NO_REPEATING:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Timed out waiting for repeat set of compass particles."));
+ logDiagnosticData(false);
+ break;
+ case FAILED_TIMEOUT_NO_PARTICLES:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Timed out waiting for compass particles."));
+ logDiagnosticData(false);
+ break;
+ case FAILED_INTERSECTION_CALCULATION:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Unable to determine intersection of wishing compasses."));
+ logDiagnosticData(false);
+ break;
+ case FAILED_INVALID_SOLUTION:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Failed to find solution."));
+ logDiagnosticData(false);
+ break;
+ case NEED_SECOND_COMPASS:
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW +
+ "[NEU] Need another position to determine wishing compass target."));
+ break;
+ }
+ }
+ } catch (Exception e) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Exception while calculating wishing compass solution - see log for details"));
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @param x Particle x coordinate
+ * @param y Particle y coordinate
+ * @param z Particle z coordinate
+ */
+ public void solveUsingParticle(double x, double y, double z, long currentTimeMillis) {
+ Compass currentCompass;
+ switch (solverState) {
+ case PROCESSING_FIRST_USE:
+ currentCompass = firstCompass;
+ break;
+ case PROCESSING_SECOND_USE:
+ currentCompass = secondCompass;
+ break;
+ default:
+ return;
+ }
+
+ currentCompass.processParticle(x, y, z, currentTimeMillis);
+ switch (currentCompass.compassState) {
+ case FAILED_TIMEOUT_NO_PARTICLES:
+ solverState = SolverState.FAILED_TIMEOUT_NO_PARTICLES;
+ return;
+ case FAILED_TIMEOUT_NO_REPEATING:
+ solverState = SolverState.FAILED_TIMEOUT_NO_REPEATING;
+ return;
+ case WAITING_FOR_FIRST_PARTICLE:
+ case COMPUTING_LAST_PARTICLE:
+ return;
+ case COMPLETED:
+ if (solverState == SolverState.NEED_SECOND_COMPASS) {
+ return;
+ }
+ if (solverState == SolverState.PROCESSING_FIRST_USE) {
+ solverState = SolverState.NEED_SECOND_COMPASS;
+ return;
+ }
+ break;
+ }
+
+ // First and Second compasses have completed
+ solutionIntersectionLine = firstCompass.line.getIntersectionLineSegment(secondCompass.line);
+
+ if (solutionIntersectionLine == null) {
+ solverState = SolverState.FAILED_INTERSECTION_CALCULATION;
+ return;
+ }
+
+ solution = new Vec3Comparable(solutionIntersectionLine.getMidpoint());
+
+ Vec3Comparable firstDirection = firstCompass.getDirection();
+ Vec3Comparable firstSolutionDirection = firstCompass.getDirectionTo(solution);
+ Vec3Comparable secondDirection = secondCompass.getDirection();
+ Vec3Comparable secondSolutionDirection = secondCompass.getDirectionTo(solution);
+ if (!firstDirection.signumEquals(firstSolutionDirection) ||
+ !secondDirection.signumEquals(secondSolutionDirection) ||
+ !HOLLOWS_BB.isVecInside(solution)) {
+ solverState = SolverState.FAILED_INVALID_SOLUTION;
+ return;
+ }
+
+ solutionPossibleTargets = getSolutionTargets(
+ getZoneForCoords(firstCompass.whereUsed),
+ foundCrystals.getAsCrystalEnumSet(),
+ possibleTargets,
+ solution
+ );
+
+ // Adjust the Jungle Temple solution coordinates
+ if (solutionPossibleTargets.size() == 1 &&
+ solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE)) {
+ originalSolution = solution;
+ solution = solution.add(JUNGLE_DOOR_OFFSET_FROM_CRYSTAL);
+ }
+
+ solverState = SolverState.SOLVED;
+ }
+
+ private boolean isKeyInInventory() {
+ for (ItemStack item : mc.thePlayer.inventory.mainInventory) {
+ if (item != null && item.getDisplayName().contains("Jungle Key")) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isKingsScentPresent() {
+ return SBInfo.getInstance().footer.getUnformattedText().contains("King's Scent I");
+ }
+
+ private EnumSet<Crystal> getFoundCrystals() {
+ EnumSet<Crystal> foundCrystals = EnumSet.noneOf(Crystal.class);
+ NEUConfig.HiddenProfileSpecific perProfileConfig = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
+ if (perProfileConfig == null) return foundCrystals;
+ HashMap<String, Integer> crystals = perProfileConfig.crystals;
+ for (String crystalName : crystals.keySet()) {
+ Integer crystalState = crystals.get(crystalName);
+ if (crystalState != null && crystalState > 0) {
+ foundCrystals.add(Crystal.valueOf(crystalName.toUpperCase(Locale.US).replace("İ", "I")));
+ }
+ }
+
+ return foundCrystals;
+ }
+
+ // Returns candidates based on:
+ // - Structure Y levels observed in various lobbies. It is assumed
+ // that structures other than Khazad Dum cannot have any portion
+ // in the Magma Fields.
+ //
+ // - Structure sizes & offsets into other zones that assume at least
+ // one block must be in the correct zone.
+ //
+ // - An assumption that any structure could be missing with a
+ // special exception for the Jungle Temple since it often conflicts
+ // with Bal and a lobby with a missing Jungle Temple has not been
+ // observed. This exception will remove Bal as a target if:
+ // - Target candidates include both Bal & the Jungle Temple.
+ // - The Amethyst crystal has not been acquired.
+ // - The zone that the compass was used in is the Jungle.
+ //
+ // - If the solution is the Crystal Nucleus then a copy of the
+ // passed in possible targets is returned.
+ //
+ // |----------|------------|
+ // | Jungle | Mithril |
+ // | | Deposits |
+ // |----------|----------- |
+ // | Goblin | Precursor |
+ // | Holdout | Deposits |
+ // |----------|------------|
+ static public EnumSet<CompassTarget> getSolutionTargets(
+ HollowsZone compassUsedZone,
+ EnumSet<Crystal> foundCrystals,
+ EnumSet<CompassTarget> possibleTargets,
+ Vec3Comparable solution
+ ) {
+ EnumSet<CompassTarget> solutionPossibleTargets;
+ solutionPossibleTargets = possibleTargets.clone();
+
+ HollowsZone solutionZone = getZoneForCoords(solution);
+ if (solutionZone == HollowsZone.CRYSTAL_NUCLEUS) {
+ return solutionPossibleTargets;
+ }
+
+ solutionPossibleTargets.remove(CompassTarget.CRYSTAL_NUCLEUS);
+
+ // Y coordinates are 43-71 from 13 samples
+ // Y=41/74 is the absolute min/max based on structure size if
+ // the center of the topaz crystal has to be in magma fields.
+ if (solutionPossibleTargets.contains(CompassTarget.BAL) &&
+ solution.yCoord > 75) {
+ solutionPossibleTargets.remove(CompassTarget.BAL);
+ }
+
+ // Y coordinates are 93-157 from 15 samples.
+ // Y=83/167 is the absolute min/max based on structure size
+ if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_KING) &&
+ solution.yCoord < 82 || solution.yCoord > 168) {
+ solutionPossibleTargets.remove(CompassTarget.GOBLIN_KING);
+ }
+
+ // Y coordinates are 129-139 from 10 samples
+ // Y=126/139 is the absolute min/max based on structure size
+ if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_QUEEN) &&
+ (solution.yCoord < 125 || solution.yCoord > 140)) {
+ solutionPossibleTargets.remove(CompassTarget.GOBLIN_QUEEN);
+ }
+
+ // Y coordinates are 72-80 from 10 samples
+ // Y=73/80 is the absolute min/max based on structure size
+ if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) &&
+ (solution.yCoord < 72 || solution.yCoord > 81)) {
+ solutionPossibleTargets.remove(CompassTarget.JUNGLE_TEMPLE);
+ }
+
+ // Y coordinates are 87-155 from 7 samples
+ // Y=74/155 is the absolute min/max solution based on structure size
+ if (solutionPossibleTargets.contains(CompassTarget.ODAWA) &&
+ (solution.yCoord < 73 || solution.yCoord > 155)) {
+ solutionPossibleTargets.remove(CompassTarget.ODAWA);
+ }
+
+ // Y coordinates are 122-129 from 8 samples
+ // Y=122/129 is the absolute min/max based on structure size
+ if (solutionPossibleTargets.contains(CompassTarget.PRECURSOR_CITY) &&
+ (solution.yCoord < 121 || solution.yCoord > 130)) {
+ solutionPossibleTargets.remove(CompassTarget.PRECURSOR_CITY);
+ }
+
+ // Y coordinates are 98-102 from 15 samples
+ // Y=98/100 is the absolute min/max based on structure size,
+ // but 102 has been seen - possibly with earlier code that rounded up
+ if (solutionPossibleTargets.contains(CompassTarget.MINES_OF_DIVAN) &&
+ (solution.yCoord < 97 || solution.yCoord > 102)) {
+ solutionPossibleTargets.remove(CompassTarget.MINES_OF_DIVAN);
+ }
+
+ // Now filter by structure offset
+ if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_KING) &&
+ (solution.xCoord > GOBLIN_HOLDOUT_BB.maxX + GOBLIN_KING_BB.maxX ||
+ solution.zCoord < GOBLIN_HOLDOUT_BB.minZ - GOBLIN_KING_BB.maxZ)) {
+ solutionPossibleTargets.remove(CompassTarget.GOBLIN_KING);
+ }
+
+ if (solutionPossibleTargets.contains(CompassTarget.GOBLIN_QUEEN) &&
+ (solution.xCoord > GOBLIN_HOLDOUT_BB.maxX + GOBLIN_QUEEN_BB.maxX ||
+ solution.zCoord < GOBLIN_HOLDOUT_BB.minZ - GOBLIN_QUEEN_BB.maxZ)) {
+ solutionPossibleTargets.remove(CompassTarget.GOBLIN_QUEEN);
+ }
+
+ if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) &&
+ (solution.xCoord > JUNGLE_BB.maxX + JUNGLE_TEMPLE_BB.maxX ||
+ solution.zCoord > JUNGLE_BB.maxZ + JUNGLE_TEMPLE_BB.maxZ)) {
+ solutionPossibleTargets.remove(CompassTarget.JUNGLE_TEMPLE);
+ }
+
+ if (solutionPossibleTargets.contains(CompassTarget.ODAWA) &&
+ (solution.xCoord > JUNGLE_BB.maxX + ODAWA_BB.maxX ||
+ solution.zCoord > JUNGLE_BB.maxZ + ODAWA_BB.maxZ)) {
+ solutionPossibleTargets.remove(CompassTarget.ODAWA);
+ }
+
+ if (solutionPossibleTargets.contains(CompassTarget.PRECURSOR_CITY) &&
+ (solution.xCoord < PRECURSOR_REMNANTS_BB.minX - PRECURSOR_CITY_BB.maxX ||
+ solution.zCoord < PRECURSOR_REMNANTS_BB.minZ - PRECURSOR_CITY_BB.maxZ)) {
+ solutionPossibleTargets.remove(CompassTarget.PRECURSOR_CITY);
+ }
+
+ if (solutionPossibleTargets.contains(CompassTarget.MINES_OF_DIVAN) &&
+ (solution.xCoord < MITHRIL_DEPOSITS_BB.minX - MINES_OF_DIVAN_BB.maxX ||
+ solution.zCoord > MITHRIL_DEPOSITS_BB.maxZ + MINES_OF_DIVAN_BB.maxZ)) {
+ solutionPossibleTargets.remove(CompassTarget.MINES_OF_DIVAN);
+ }
+
+ // Special case the Jungle Temple
+ if (solutionPossibleTargets.contains(CompassTarget.JUNGLE_TEMPLE) &&
+ solutionPossibleTargets.contains(CompassTarget.BAL) &&
+ !foundCrystals.contains(Crystal.AMETHYST) &&
+ compassUsedZone == HollowsZone.JUNGLE) {
+ solutionPossibleTargets.remove(CompassTarget.BAL);
+ }
+
+ return solutionPossibleTargets;
+ }
+
+ private EnumSet<CompassTarget> calculatePossibleTargets(BlockPos playerPos) {
+ EnumSet<CompassTarget> candidateTargets = EnumSet.of(CompassTarget.CRYSTAL_NUCLEUS);
+ EnumSet<Crystal> foundCrystals = this.foundCrystals.getAsCrystalEnumSet();
+
+ // Add targets based on missing crystals.
+ // NOTE:
+ // We used to assume that only the adjacent zone's targets could be returned. That turned
+ // out to be incorrect (e.g. a compass in the jungle pointed to the Precursor City when
+ // the king would have been a valid target). Now we assume that any structure could be
+ // missing (because Hypixel) and depend on the solution coordinates to filter the list.
+ for (Crystal crystal : Crystal.values()) {
+ if (foundCrystals.contains(crystal)) {
+ continue;
+ }
+
+ switch (crystal) {
+ case JADE:
+ candidateTargets.add(CompassTarget.MINES_OF_DIVAN);
+ break;
+ case AMBER:
+ candidateTargets.add(
+ kingsScentPresent.getAsBoolean() ? CompassTarget.GOBLIN_QUEEN : CompassTarget.GOBLIN_KING);
+ break;
+ case TOPAZ:
+ candidateTargets.add(CompassTarget.BAL);
+ break;
+ case AMETHYST:
+ candidateTargets.add(
+ keyInInventory.getAsBoolean() ? CompassTarget.JUNGLE_TEMPLE : CompassTarget.ODAWA);
+ break;
+ case SAPPHIRE:
+ candidateTargets.add(CompassTarget.PRECURSOR_CITY);
+ break;
+ }
+ }
+
+ return candidateTargets;
+ }
+
+ private String getFriendlyNameForCompassTarget(CompassTarget compassTarget) {
+ switch (compassTarget) {
+ case BAL:
+ return EnumChatFormatting.RED + "Bal";
+ case ODAWA:
+ return EnumChatFormatting.GREEN + "Odawa";
+ case JUNGLE_TEMPLE:
+ return EnumChatFormatting.AQUA + "the " +
+ EnumChatFormatting.GREEN + "Jungle Temple";
+ case GOBLIN_KING:
+ return EnumChatFormatting.GOLD + "King Yolkar";
+ case GOBLIN_QUEEN:
+ return EnumChatFormatting.AQUA + "the " +
+ EnumChatFormatting.YELLOW + "Goblin Queen";
+ case PRECURSOR_CITY:
+ return EnumChatFormatting.AQUA + "the " +
+ EnumChatFormatting.WHITE + "Precursor City";
+ case MINES_OF_DIVAN:
+ return EnumChatFormatting.AQUA + "the " +
+ EnumChatFormatting.BLUE + "Mines of Divan";
+ default:
+ return EnumChatFormatting.WHITE + "an undetermined location";
+ }
+ }
+
+ private String getNameForCompassTarget(CompassTarget compassTarget) {
+ boolean useSkytilsNames = (NotEnoughUpdates.INSTANCE.config.mining.wishingCompassWaypointNames == 1);
+ switch (compassTarget) {
+ case BAL:
+ return useSkytilsNames ? "internal_bal" : "Bal";
+ case ODAWA:
+ return "Odawa";
+ case JUNGLE_TEMPLE:
+ return useSkytilsNames ? "internal_temple" : "Temple";
+ case GOBLIN_KING:
+ return useSkytilsNames ? "internal_king" : "King";
+ case GOBLIN_QUEEN:
+ return useSkytilsNames ? "internal_den" : "Queen";
+ case PRECURSOR_CITY:
+ return useSkytilsNames ? "internal_city" : "City";
+ case MINES_OF_DIVAN:
+ return useSkytilsNames ? "internal_mines" : "Mines";
+ default:
+ return "WishingTarget";
+ }
+ }
+
+ private String getSolutionCoordsText() {
+ return solution == null ? "" :
+ String.format("%.0f %.0f %.0f", solution.xCoord, solution.yCoord, solution.zCoord);
+ }
+
+ private String getWishingCompassDestinationsMessage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(EnumChatFormatting.YELLOW);
+ sb.append("[NEU] ");
+ sb.append(EnumChatFormatting.AQUA);
+ sb.append("Wishing compass points to ");
+ int index = 1;
+ for (CompassTarget target : solutionPossibleTargets) {
+ if (index > 1) {
+ sb.append(EnumChatFormatting.AQUA);
+ if (index == solutionPossibleTargets.size()) {
+ sb.append(" or ");
+ } else {
+ sb.append(", ");
+ }
+ }
+ sb.append(getFriendlyNameForCompassTarget(target));
+ index++;
+ }
+
+ sb.append(EnumChatFormatting.AQUA);
+ sb.append(" (");
+ sb.append(getSolutionCoordsText());
+ sb.append(")");
+ return sb.toString();
+ }
+
+ private void showSolution() {
+ if (solution == null) return;
+
+ if (NUCLEUS_BB.isVecInside(solution)) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU] " +
+ EnumChatFormatting.AQUA + "Wishing compass target is the Crystal Nucleus"));
+ return;
+ }
+
+ String destinationMessage = getWishingCompassDestinationsMessage();
+
+ if (!isSkytilsPresent) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(destinationMessage));
+ return;
+ }
+
+ String targetNameForSkytils = solutionPossibleTargets.size() == 1 ?
+ getNameForCompassTarget(solutionPossibleTargets.iterator().next()) :
+ "WishingTarget";
+ String skytilsCommand = String.format("/sthw add %s %s", getSolutionCoordsText(), targetNameForSkytils);
+ if (NotEnoughUpdates.INSTANCE.config.mining.wishingCompassAutocreateKnownWaypoints &&
+ solutionPossibleTargets.size() == 1) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(destinationMessage));
+ int commandResult = ClientCommandHandler.instance.executeCommand(mc.thePlayer, skytilsCommand);
+ if (commandResult == 1) {
+ return;
+ }
+ mc.thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "[NEU] Failed to automatically run /sthw"));
+ }
+
+ destinationMessage += EnumChatFormatting.YELLOW + " [Add Skytils Waypoint]";
+ ChatComponentText chatMessage = new ChatComponentText(destinationMessage);
+ chatMessage.setChatStyle(Utils.createClickStyle(
+ ClickEvent.Action.RUN_COMMAND,
+ skytilsCommand,
+ EnumChatFormatting.YELLOW + "Set waypoint for wishing target"
+ ));
+ mc.thePlayer.addChatMessage(chatMessage);
+ }
+
+ private String getDiagnosticMessage() {
+ StringBuilder diagsMessage = new StringBuilder();
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Solver State: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(solverState.name());
+ diagsMessage.append("\n");
+
+ if (firstCompass == null) {
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("First Compass: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append("<NONE>");
+ diagsMessage.append("\n");
+ } else {
+ firstCompass.appendCompassDiagnostics(diagsMessage, "First Compass");
+ }
+
+ if (secondCompass == null) {
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Second Compass: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append("<NONE>");
+ diagsMessage.append("\n");
+ } else {
+ secondCompass.appendCompassDiagnostics(diagsMessage, "Second Compass");
+ }
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Intersection Line: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((solutionIntersectionLine == null) ? "<NONE>" : solutionIntersectionLine);
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Jungle Key in Inventory: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(isKeyInInventory());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("King's Scent Present: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(isKingsScentPresent());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("First Compass Targets: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(possibleTargets == null ? "<NONE>" : possibleTargets.toString());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Current Calculated Targets: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(calculatePossibleTargets(mc.thePlayer.getPosition()));
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Found Crystals: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(getFoundCrystals());
+ diagsMessage.append("\n");
+
+ if (originalSolution != null) {
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Original Solution: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(originalSolution);
+ diagsMessage.append("\n");
+ }
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Solution: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((solution == null) ? "<NONE>" : solution.toString());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Solution Targets: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((solutionPossibleTargets == null) ? "<NONE>" : solutionPossibleTargets.toString());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Seen particles:\n");
+ for (ParticleData particleData : seenParticles) {
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(particleData);
+ diagsMessage.append("\n");
+ }
+
+ return diagsMessage.toString();
+ }
+
+ public void logDiagnosticData(boolean outputAlways) {
+ if (!SBInfo.getInstance().checkForSkyblockLocation()) {
+ return;
+ }
+
+ if (!NotEnoughUpdates.INSTANCE.config.mining.wishingCompassSolver) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] Wishing Compass Solver is not enabled."));
+ return;
+ }
+
+ boolean wishingDebugFlagSet = NEUDebugFlag.WISHING.isSet();
+ if (outputAlways || wishingDebugFlagSet) {
+ NEUDebugLogger.logAlways(getDiagnosticMessage());
+ }
+ }
+
+ enum CompassState {
+ WAITING_FOR_FIRST_PARTICLE,
+ COMPUTING_LAST_PARTICLE,
+ COMPLETED,
+ FAILED_TIMEOUT_NO_REPEATING,
+ FAILED_TIMEOUT_NO_PARTICLES,
+ }
+
+ enum HandleCompassResult {
+ SUCCESS,
+ LOCATION_TOO_CLOSE,
+ STILL_PROCESSING_PRIOR_USE,
+ POSSIBLE_TARGETS_CHANGED,
+ NO_PARTICLES_FOR_PREVIOUS_COMPASS,
+ PLAYER_IN_NUCLEUS
+ }
+
+ static class Compass {
+ public CompassState compassState;
+ public Line line = null;
+
+ private final BlockPos whereUsed;
+ private final long whenUsedMillis;
+ private Vec3Comparable firstParticle = null;
+ private Vec3Comparable previousParticle = null;
+ private Vec3Comparable lastParticle = null;
+ private final ArrayList<ProcessedParticle> processedParticles;
+
+ Compass(BlockPos whereUsed, long whenUsedMillis) {
+ this.whereUsed = whereUsed;
+ this.whenUsedMillis = whenUsedMillis;
+ compassState = CompassState.WAITING_FOR_FIRST_PARTICLE;
+ processedParticles = new ArrayList<>();
+ }
+
+ public Vec3Comparable getDirection() {
+ if (firstParticle == null || lastParticle == null) {
+ return null;
+ }
+
+ return new Vec3Comparable(firstParticle.subtractReverse(lastParticle).normalize());
+ }
+
+ public Vec3Comparable getDirectionTo(Vec3Comparable target) {
+ if (firstParticle == null || target == null) {
+ return null;
+ }
+
+ return new Vec3Comparable(firstParticle.subtractReverse(target).normalize());
+ }
+
+ public double particleSpread() {
+ if (firstParticle == null || lastParticle == null) {
+ return 0.0;
+ }
+ return firstParticle.distanceTo(lastParticle);
+ }
+
+ public void processParticle(double x, double y, double z, long particleTimeMillis) {
+ if (compassState == CompassState.FAILED_TIMEOUT_NO_REPEATING ||
+ compassState == CompassState.FAILED_TIMEOUT_NO_PARTICLES ||
+ compassState == CompassState.COMPLETED) {
+ throw new UnsupportedOperationException("processParticle should not be called in a failed or completed state");
+ }
+
+ if (particleTimeMillis - this.whenUsedMillis > ALL_PARTICLES_MAX_MILLIS) {
+ // Assume we have failed if we're still trying to process particles
+ compassState = CompassState.FAILED_TIMEOUT_NO_REPEATING;
+ return;
+ }
+
+ Vec3Comparable currentParticle = new Vec3Comparable(x, y, z);
+ if (compassState == CompassState.WAITING_FOR_FIRST_PARTICLE) {
+ if (currentParticle.distanceTo(new Vec3Comparable(whereUsed)) < MAX_DISTANCE_FROM_USE_TO_FIRST_PARTICLE) {
+ processedParticles.add(new ProcessedParticle(currentParticle, particleTimeMillis));
+ firstParticle = currentParticle;
+ previousParticle = currentParticle;
+ compassState = CompassState.COMPUTING_LAST_PARTICLE;
+ }
+ return;
+ }
+
+ // State is COMPUTING_LAST_PARTICLE, keep updating the previousParticle until
+ // the first particle in the second sequence is seen.
+ if (currentParticle.distanceTo(previousParticle) <= MAX_DISTANCE_BETWEEN_PARTICLES) {
+ processedParticles.add(new ProcessedParticle(currentParticle, particleTimeMillis));
+ previousParticle = currentParticle;
+ return;
+ }
+
+ if (currentParticle.distanceTo(firstParticle) > MAX_DISTANCE_BETWEEN_PARTICLES) {
+ return;
+ }
+
+ // It's a repeating particle
+ processedParticles.add(new ProcessedParticle(currentParticle, particleTimeMillis));
+ lastParticle = previousParticle;
+ line = new Line(firstParticle, lastParticle);
+ compassState = CompassState.COMPLETED;
+ }
+
+ public void appendCompassDiagnostics(StringBuilder diagsMessage, String compassName) {
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append("Compass State: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(compassState.name());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append(compassName);
+ diagsMessage.append(" Used Millis: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(whenUsedMillis);
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append(compassName);
+ diagsMessage.append(" Used Position: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((whereUsed == null) ? "<NONE>" : whereUsed.toString());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append(compassName);
+ diagsMessage.append(" All Seen Particles: \n");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ for (ProcessedParticle particle : processedParticles) {
+ diagsMessage.append(particle.toString());
+ diagsMessage.append("\n");
+ }
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append(compassName);
+ diagsMessage.append(" Particle Spread: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append(particleSpread());
+ diagsMessage.append("\n");
+
+ diagsMessage.append(EnumChatFormatting.AQUA);
+ diagsMessage.append(compassName);
+ diagsMessage.append(" Compass Line: ");
+ diagsMessage.append(EnumChatFormatting.WHITE);
+ diagsMessage.append((line == null) ? "<NONE>" : line.toString());
+ diagsMessage.append("\n");
+ }
+
+ static class ProcessedParticle {
+ Vec3Comparable coords;
+ long particleTimeMillis;
+
+ ProcessedParticle(Vec3Comparable coords, long particleTimeMillis) {
+ this.coords = coords;
+ this.particleTimeMillis = particleTimeMillis;
+ }
+
+ @Override
+ public String toString() {
+ return coords.toString() + " " + particleTimeMillis;
+ }
+ }
+ }
+
+ private static class ParticleData {
+ Vec3Comparable particleLocation;
+ long systemTime;
+
+ public ParticleData(Vec3Comparable particleLocation, long systemTime) {
+ this.particleLocation = particleLocation;
+ this.systemTime = systemTime;
+ }
+
+ public String toString() {
+ return "Location: " + particleLocation.toString() + ", systemTime: " + systemTime;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomItemEffects.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomItemEffects.java
index e621cf78..452f8a9b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomItemEffects.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomItemEffects.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -11,7 +30,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.multiplayer.WorldClient;
-import net.minecraft.client.renderer.*;
+import net.minecraft.client.renderer.BlockRendererDispatcher;
+import net.minecraft.client.renderer.EntityRenderer;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
@@ -24,7 +47,13 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
-import net.minecraft.util.*;
+import net.minecraft.util.AxisAlignedBB;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraft.util.Vec3;
+import net.minecraft.util.Vec3i;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
@@ -36,8 +65,14 @@ import org.lwjgl.util.vector.Vector3f;
import java.awt.*;
import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
-import java.util.*;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -178,12 +213,14 @@ public class CustomItemEffects {
@SubscribeEvent
public void onGameTick(TickEvent.ClientTickEvent event) {
if (event.phase != TickEvent.Phase.END) return;
+ EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;
+ if (player == null) return;
if (!usingEtherwarp && wasUsingEtherwarp) {
- if (Minecraft.getMinecraft().thePlayer.rotationYaw > 0) {
- Minecraft.getMinecraft().thePlayer.rotationYaw -= 0.000001;
+ if (player.rotationYaw > 0) {
+ player.rotationYaw -= 0.000001;
} else {
- Minecraft.getMinecraft().thePlayer.rotationYaw += 0.000001;
+ player.rotationYaw += 0.000001;
}
}
wasUsingEtherwarp = usingEtherwarp;
@@ -238,6 +275,7 @@ public class CustomItemEffects {
private boolean usingEtherwarp = false;
private RaycastResult etherwarpRaycast = null;
private int lastEtherwarpUse = 0;
+ private String denyTpReason = null;
@SubscribeEvent
public void onOverlayDrawn(RenderGameOverlayEvent.Post event) {
@@ -246,40 +284,50 @@ public class CustomItemEffects {
ItemStack held = Minecraft.getMinecraft().thePlayer.getHeldItem();
String heldInternal = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(held);
- if (usingEtherwarp && NotEnoughUpdates.INSTANCE.config.itemOverlays.enableEtherwarpHelperOverlay) {
- String denyTpReason = null;
+ WorldClient world = Minecraft.getMinecraft().theWorld;
+ if (usingEtherwarp) {
+ denyTpReason = null;
if (etherwarpRaycast == null) {
denyTpReason = "Too far!";
} else {
BlockPos pos = etherwarpRaycast.pos;
- if (!etherwarpRaycast.state.getBlock().isCollidable() ||
- etherwarpRaycast.state.getBlock().getCollisionBoundingBox(
- Minecraft.getMinecraft().theWorld,
- etherwarpRaycast.pos,
- etherwarpRaycast.state
- ) == null) {
+ Block block = etherwarpRaycast.state.getBlock();
+ if (!block.isCollidable() ||
+ //Don't allow teleport at this block
+ block == Blocks.carpet || block == Blocks.skull ||
+ block.getCollisionBoundingBox(world, etherwarpRaycast.pos, etherwarpRaycast.state) == null &&
+ //Allow teleport at this block
+ block != Blocks.wall_sign && block != Blocks.standing_sign) {
denyTpReason = "Not solid!";
} else {
- WorldClient world = Minecraft.getMinecraft().theWorld;
- Block above = world.getBlockState(pos.add(0, 1, 0)).getBlock();
- if (above != Blocks.air && above.isCollidable() &&
- above.getCollisionBoundingBox(Minecraft.getMinecraft().theWorld, pos.add(0, 1, 0),
- world.getBlockState(pos.add(0, 1, 0))
- ) != null ||
- world.getBlockState(pos.add(0, 2, 0)).getBlock() != Blocks.air) {
+ BlockPos blockPosAbove = pos.add(0, 1, 0);
+ Block blockAbove = world.getBlockState(blockPosAbove).getBlock();
+
+ Block twoBlockAbove = world.getBlockState(pos.add(0, 2, 0)).getBlock();
+ if (blockAbove != Blocks.air &&
+ //Allow teleport to the block below this block
+ blockAbove != Blocks.carpet && blockAbove != Blocks.skull && blockAbove.isCollidable() &&
+ blockAbove.getCollisionBoundingBox(world, blockPosAbove, world.getBlockState(blockPosAbove)) != null ||
+ //Don't allow teleport to the block below this block
+ blockAbove == Blocks.wall_sign || block == Blocks.standing_sign ||
+ //Allow teleport to the block 2 blocks below this block
+ twoBlockAbove != Blocks.air && twoBlockAbove != Blocks.double_plant && twoBlockAbove != Blocks.carpet &&
+ blockAbove != Blocks.skull) {
denyTpReason = "No air above!";
}
}
}
- if (denyTpReason != null) {
- ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
- Utils.drawStringCentered(EnumChatFormatting.RED + "Can't TP: " + denyTpReason,
- Minecraft.getMinecraft().fontRendererObj,
- scaledResolution.getScaledWidth() / 2f, scaledResolution.getScaledHeight() / 2f + 10, true, 0
- );
- GlStateManager.color(1, 1, 1, 1);
+ if (NotEnoughUpdates.INSTANCE.config.itemOverlays.enableEtherwarpHelperOverlay) {
+ if (denyTpReason != null) {
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ Utils.drawStringCentered(EnumChatFormatting.RED + "Can't TP: " + denyTpReason,
+ Minecraft.getMinecraft().fontRendererObj,
+ scaledResolution.getScaledWidth() / 2f, scaledResolution.getScaledHeight() / 2f + 10, true, 0
+ );
+ GlStateManager.color(1, 1, 1, 1);
+ }
}
}
@@ -291,7 +339,7 @@ public class CustomItemEffects {
Minecraft.getMinecraft().objectMouseOver.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK &&
onPrivateIsland) {
- IBlockState hover = Minecraft.getMinecraft().theWorld.getBlockState(
+ IBlockState hover = world.getBlockState(
Minecraft.getMinecraft().objectMouseOver.getBlockPos().offset(
Minecraft.getMinecraft().objectMouseOver.sideHit, 1));
if (hover.getBlock() == Blocks.air) {
@@ -303,14 +351,14 @@ public class CustomItemEffects {
TreeMap<Float, Set<BlockPos>> candidatesOldSorted = new TreeMap<>();
IBlockState match =
- Minecraft.getMinecraft().theWorld.getBlockState(Minecraft.getMinecraft().objectMouseOver.getBlockPos());
+ world.getBlockState(Minecraft.getMinecraft().objectMouseOver.getBlockPos());
Item matchItem = Item.getItemFromBlock(match.getBlock());
if (matchItem != null) {
ItemStack matchStack = new ItemStack(matchItem, 1,
match
.getBlock()
.getDamageValue(
- Minecraft.getMinecraft().theWorld,
+ world,
Minecraft.getMinecraft().objectMouseOver.getBlockPos()
)
);
@@ -568,7 +616,8 @@ public class CustomItemEffects {
double d1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * (double) event.partialTicks;
double d2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * (double) event.partialTicks;
- if (tick - lastEtherwarpUse > 10) {
+ //Don't need to wait 10 ticks when zoom is disabled
+ if (tick - lastEtherwarpUse > 10 || !NotEnoughUpdates.INSTANCE.config.itemOverlays.etherwarpZoom) {
boolean aotv = Minecraft.getMinecraft().thePlayer.isSneaking() &&
(heldInternal.equals("ASPECT_OF_THE_VOID") || heldInternal.equals("ASPECT_OF_THE_END"));
if (aotv || heldInternal.equals("ETHERWARP_CONDUIT")) {
@@ -597,20 +646,30 @@ public class CustomItemEffects {
if (etherwarpRaycast != null &&
NotEnoughUpdates.INSTANCE.config.itemOverlays.enableEtherwarpBlockOverlay) {
- AxisAlignedBB bb = etherwarpRaycast.state.getBlock().getSelectedBoundingBox(
- Minecraft.getMinecraft().theWorld,
- etherwarpRaycast.pos
- )
- .expand(0.01D, 0.01D, 0.01D).offset(-d0, -d1, -d2);
- drawFilledBoundingBox(bb, 1f, NotEnoughUpdates.INSTANCE.config.itemOverlays.etherwarpHighlightColour);
+ if (denyTpReason == null || !NotEnoughUpdates.INSTANCE.config.itemOverlays.disableOverlayWhenFailed) {
+ AxisAlignedBB box = etherwarpRaycast.state.getBlock().getSelectedBoundingBox(
+ Minecraft.getMinecraft().theWorld,
+ etherwarpRaycast.pos
+ );
+ AxisAlignedBB bb = box.expand(0.01D, 0.01D, 0.01D).offset(-d0, -d1, -d2);
+ drawFilledBoundingBox(
+ bb,
+ 1f,
+ NotEnoughUpdates.INSTANCE.config.itemOverlays.etherwarpHighlightColour
+ );
- GlStateManager.disableDepth();
- drawOutlineBoundingBox(bb, 2f, NotEnoughUpdates.INSTANCE.config.itemOverlays.etherwarpHighlightColour);
- GlStateManager.enableDepth();
+ GlStateManager.disableDepth();
+ drawOutlineBoundingBox(
+ bb,
+ 2f,
+ NotEnoughUpdates.INSTANCE.config.itemOverlays.etherwarpHighlightColour
+ );
+ GlStateManager.enableDepth();
- GlStateManager.depthMask(true);
- GlStateManager.enableTexture2D();
- GlStateManager.disableBlend();
+ GlStateManager.depthMask(true);
+ GlStateManager.enableTexture2D();
+ GlStateManager.disableBlend();
+ }
if (NotEnoughUpdates.INSTANCE.config.itemOverlays.etherwarpZoom) {
float distFactor = 1 -
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomSkulls.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomSkulls.java
index 1157e73a..95ec0f7a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomSkulls.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/CustomSkulls.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.common.collect.Maps;
@@ -14,8 +33,17 @@ import net.minecraft.client.model.ModelSkeletonHead;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
-import net.minecraft.client.renderer.block.model.*;
-import net.minecraft.client.renderer.texture.*;
+import net.minecraft.client.renderer.block.model.BakedQuad;
+import net.minecraft.client.renderer.block.model.BlockPart;
+import net.minecraft.client.renderer.block.model.BlockPartFace;
+import net.minecraft.client.renderer.block.model.FaceBakery;
+import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
+import net.minecraft.client.renderer.block.model.ModelBlock;
+import net.minecraft.client.renderer.texture.AbstractTexture;
+import net.minecraft.client.renderer.texture.IIconCreator;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.client.renderer.texture.TextureMap;
+import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
@@ -31,7 +59,11 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class CustomSkulls implements IResourceManagerReloadListener {
private static final CustomSkulls INSTANCE = new CustomSkulls();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DamageCommas.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DamageCommas.java
index 9c93b9c5..b1ab11c1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DamageCommas.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DamageCommas.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -26,15 +45,18 @@ public class DamageCommas {
};
private static final char STAR = '\u2727';
+ private static final char OVERLOAD_STAR = '\u272F';
private static final Pattern PATTERN_CRIT = Pattern.compile(
- "\u00a7f" + STAR + "((?:\u00a7.\\d)+)\u00a7." + STAR + "(.*)");
- private static final Pattern PATTERN_NO_CRIT = Pattern.compile("\u00a77(\\d+)(.*)");
+ "\u00a7f" + STAR + "((?:\u00a7.\\d(?:§.,)?)+)\u00a7." + STAR + "(.*)");
+ private static final Pattern PATTERN_NO_CRIT = Pattern.compile("(\u00a7.)([\\d+,]*)(.*)");
+ private static final Pattern OVERLOAD_PATTERN = Pattern.compile("(\u00a7.)" + OVERLOAD_STAR + "((?:\u00a7.[\\d,])+)(\u00a7.)" + OVERLOAD_STAR + "\u00a7r");
public static IChatComponent replaceName(EntityLivingBase entity) {
if (!entity.hasCustomName()) return entity.getDisplayName();
IChatComponent name = entity.getDisplayName();
- if (NotEnoughUpdates.INSTANCE.config.misc.damageIndicatorStyle == 0) return name;
+ if (!NotEnoughUpdates.INSTANCE.config.misc.damageIndicatorStyle2) return name;
+ if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return name;
if (replacementMap.containsKey(entity)) {
ChatComponentText component = replacementMap.get(entity);
@@ -50,17 +72,23 @@ public class DamageCommas {
String suffix;
Matcher matcherCrit = PATTERN_CRIT.matcher(formatted);
+ Matcher matcherOverload = OVERLOAD_PATTERN.matcher(formatted);
if (matcherCrit.matches()) {
crit = true;
- numbers = StringUtils.cleanColour(matcherCrit.group(1));
+ numbers = StringUtils.cleanColour(matcherCrit.group(1)).replace(",", "");
prefix = "\u00a7f" + STAR;
suffix = "\u00a7f" + STAR + matcherCrit.group(2);
- } else {
+ } else if (matcherOverload.matches()) {
+ crit = true;
+ numbers = StringUtils.cleanColour(matcherOverload.group(2)).replace(",", "");
+ prefix = matcherOverload.group(1) + OVERLOAD_STAR;
+ suffix = matcherOverload.group(3) + OVERLOAD_STAR + "\u00a7r";
+ } else {
Matcher matcherNoCrit = PATTERN_NO_CRIT.matcher(formatted);
if (matcherNoCrit.matches()) {
- numbers = matcherNoCrit.group(1);
- prefix = "\u00A77";
- suffix = "\u00A7r" + matcherNoCrit.group(2);
+ numbers = matcherNoCrit.group(2).replace(",", "");
+ prefix = matcherNoCrit.group(1);
+ suffix = "\u00A7r" + matcherNoCrit.group(3);
} else {
replacementMap.put(entity, null);
return name;
@@ -72,10 +100,10 @@ public class DamageCommas {
try {
int number = Integer.parseInt(numbers);
- if (number > 999 && NotEnoughUpdates.INSTANCE.config.misc.damageIndicatorStyle == 2) {
+ if (number > 999) {
newFormatted.append(Utils.shortNumberFormat(number, 0));
} else {
- newFormatted.append(NumberFormat.getIntegerInstance().format(number));
+ return name;
}
} catch (NumberFormatException e) {
replacementMap.put(entity, null);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java
index f7f9003c..c1c7dca1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/DwarvenMinesWaypoints.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnchantingSolvers.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnchantingSolvers.java
index 16b59b05..d5cbfdde 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnchantingSolvers.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/EnchantingSolvers.java
@@ -1,6 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.inventory.GuiChest;
@@ -17,13 +37,18 @@ import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.lwjgl.input.Keyboard;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
public class EnchantingSolvers {
- private static SolverType currentSolver = SolverType.NONE;
+ public static SolverType currentSolver = SolverType.NONE;
- private enum SolverType {
+ public enum SolverType {
NONE,
CHRONOMATRON,
ULTRASEQUENCER,
@@ -72,20 +97,14 @@ public class EnchantingSolvers {
return;
}
- if (event.gui instanceof GuiChest) {
- GuiChest chest = (GuiChest) event.gui;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
- String lower = containerName.toLowerCase();
-
- if (!lower.contains("stakes")) {
- if (lower.startsWith("chronomatron")) {
- currentSolver = SolverType.CHRONOMATRON;
- } else if (lower.startsWith("ultrasequencer")) {
- currentSolver = SolverType.ULTRASEQUENCER;
- } else if (lower.startsWith("superpairs")) {
- currentSolver = SolverType.SUPERPAIRS;
- }
+ String openChestName = Utils.getOpenChestName();
+ if (!openChestName.contains("Stakes")) {
+ if (openChestName.startsWith("Chronomatron")) {
+ currentSolver = SolverType.CHRONOMATRON;
+ } else if (openChestName.startsWith("Ultrasequencer")) {
+ currentSolver = SolverType.ULTRASEQUENCER;
+ } else if (openChestName.startsWith("Superpairs")) {
+ currentSolver = SolverType.SUPERPAIRS;
}
}
}
@@ -290,97 +309,88 @@ public class EnchantingSolvers {
return false;
}
- public static boolean onStackClick(ItemStack stack, int windowId, int slotId, int mouseButtonClicked, int mode) {
- if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableEnchantingSolvers) {
- return false;
+ @SubscribeEvent
+ public void onStackClick(SlotClickEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableEnchantingSolvers
+ || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ return;
}
- if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
- return false;
+ ItemStack stack = event.slot.getStack();
+ if (stack == null || stack.getDisplayName() == null) {
+ return;
}
+ String displayName = stack.getDisplayName();
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) {
+ return;
+ }
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest container = (ContainerChest) chest.inventorySlots;
+ IInventory lower = container.getLowerChestInventory();
+
+ if (currentSolver == SolverType.CHRONOMATRON) {
+ ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5);
+ if (timerStack == null) {
+ return;
+ }
- if (stack != null && stack.getDisplayName() != null) {
- String displayName = stack.getDisplayName();
- if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- IInventory lower = container.getLowerChestInventory();
-
- if (currentSolver == SolverType.CHRONOMATRON) {
- ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5);
- if (timerStack == null) {
- return false;
- }
-
- boolean yepClock = timerStack.getItem() == Items.clock;
- if (timerStack.getItem() == Item.getItemFromBlock(Blocks.glowstone) ||
- (yepClock && (!addToChronomatron || chronomatronOrder.size() < lastChronomatronSize + 1))) {
- return true;
- } else if (yepClock) {
- long currentTime = System.currentTimeMillis();
- if (currentTime - millisLastClick < 150) {
- return true;
- }
+ boolean yepClock = timerStack.getItem() == Items.clock;
+ if (timerStack.getItem() == Item.getItemFromBlock(Blocks.glowstone) ||
+ (yepClock && (!addToChronomatron || chronomatronOrder.size() < lastChronomatronSize + 1))) {
+ event.setCanceled(true);
+ return;
+ }
+ if (yepClock) {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - millisLastClick < 150) {
+ event.setCanceled(true);
+ return;
+ }
- if (chronomatronReplayIndex < chronomatronOrder.size()) {
- String chronomatronCurrent = chronomatronOrder.get(chronomatronReplayIndex);
- if (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.preventMisclicks1 ||
- chronomatronCurrent.equals(displayName)) {
- chronomatronReplayIndex++;
- Minecraft.getMinecraft().playerController.windowClick(windowId, slotId,
- 2, mode, Minecraft.getMinecraft().thePlayer
- );
- millisLastClick = currentTime;
- }
- /*if (chronomatronCurrent.equals(displayName)) {
- chronomatronReplayIndex++;
- }
- Minecraft.getMinecraft().playerController.windowClick(windowId, slotId,
- 2, mode, Minecraft.getMinecraft().thePlayer);
- millisLastClick = currentTime;*/
- }
- return true;
- }
- } else if (currentSolver == SolverType.ULTRASEQUENCER) {
- ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5);
- if (timerStack == null) {
- return false;
+ if (chronomatronReplayIndex < chronomatronOrder.size()) {
+ String chronomatronCurrent = chronomatronOrder.get(chronomatronReplayIndex);
+ if ((!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.preventMisclicks1 ||
+ chronomatronCurrent.equals(displayName) || Keyboard.getEventKey() == Keyboard.KEY_LSHIFT) &&
+ stack.getItem() != Item.getItemFromBlock(Blocks.stained_glass_pane) && event.slotId != 4 &&
+ event.slotId != 49) {
+ chronomatronReplayIndex++;
+ millisLastClick = currentTime;
+ event.usePickblockInstead();
+ return;
}
+ }
+ event.setCanceled(true);
+ return;
+ }
+ }
+ if (currentSolver == SolverType.ULTRASEQUENCER) {
+ ItemStack timerStack = lower.getStackInSlot(lower.getSizeInventory() - 5);
+ if (timerStack == null) {
+ return;
+ }
- boolean yepClock = timerStack.getItem() == Items.clock;
- if (yepClock) {
- UltrasequencerItem current = ultraSequencerOrder.get(ultrasequencerReplayIndex);
- if (current == null) {
- return true;
- }
- long currentTime = System.currentTimeMillis();
- if (currentTime - millisLastClick > 150 &&
- (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.preventMisclicks1 ||
- current.containerIndex == slotId)) {
- ultrasequencerReplayIndex++;
- Minecraft.getMinecraft().playerController.windowClick(windowId, slotId,
- 2, mode, Minecraft.getMinecraft().thePlayer
- );
- millisLastClick = currentTime;
- }
- /*if (currentTime - millisLastClick > 150) {
- if (current.containerIndex == slotId) {
- ultrasequencerReplayIndex++;
- }
- Minecraft.getMinecraft().playerController.windowClick(windowId, slotId,
- 2, mode, Minecraft.getMinecraft().thePlayer);
- millisLastClick = currentTime;
- }*/
- return true;
- } else {
- return true;
- }
- } else if (currentSolver == SolverType.SUPERPAIRS) {
- lastSlotClicked = slotId;
+ boolean yepClock = timerStack.getItem() == Items.clock;
+ if (yepClock) {
+ UltrasequencerItem current = ultraSequencerOrder.get(ultrasequencerReplayIndex);
+ long currentTime = System.currentTimeMillis();
+ if (current == null) {
+ event.setCanceled(true);
+ return;
+ }
+ if (currentTime - millisLastClick > 150 &&
+ (!NotEnoughUpdates.INSTANCE.config.enchantingSolvers.preventMisclicks1 ||
+ current.containerIndex == event.slotId || Keyboard.getEventKey() == Keyboard.KEY_LSHIFT) &&
+ (event.slotId < 45 && event.slotId > 8)) {
+ ultrasequencerReplayIndex++;
+ millisLastClick = currentTime;
+ event.usePickblockInstead();
+ return;
}
}
+ event.setCanceled(true);
+ } else if (currentSolver == SolverType.SUPERPAIRS) {
+ lastSlotClicked = event.slotId;
}
- return false;
}
public static void processInventoryContents(boolean fromTick) {
@@ -573,4 +583,8 @@ public class EnchantingSolvers {
processInventoryContents(true);
}
+
+ public static boolean disableButtons() {
+ return currentSolver != SolverType.NONE && NotEnoughUpdates.INSTANCE.config.enchantingSolvers.hideButtons;
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java
index 725d4b9d..75f1b427 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FairySouls.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.common.reflect.TypeToken;
@@ -21,70 +40,305 @@ import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.stream.Collectors;
public class FairySouls {
+ private static FairySouls instance = null;
private static final String unknownProfile = "unknown";
- private static List<BlockPos> currentSoulList = null;
- private static List<BlockPos> currentSoulListClose = null;
- private static HashMap<String, HashMap<String, Set<Integer>>> loadedFoundSouls = new HashMap<>();
- private static HashMap<String, Set<Integer>> getFoundSoulsForProfile() {
+ private boolean trackSouls;
+ private boolean showSouls;
+ private HashMap<String, HashMap<String, Set<Integer>>> allProfilesFoundSouls = new HashMap<>();
+ private List<BlockPos> allSoulsInCurrentLocation;
+ private Set<Integer> foundSoulsInLocation;
+ private TreeMap<Double, BlockPos> missingSoulsDistanceSqMap;
+ private List<BlockPos> closestMissingSouls;
+ private String currentLocation;
+ private BlockPos lastPlayerPos;
+
+ public static FairySouls getInstance() {
+ if (instance == null) {
+ instance = new FairySouls();
+ }
+ return instance;
+ }
+
+ @SubscribeEvent
+ public void onWorldLoad(WorldEvent.Load event) {
+ currentLocation = null;
+ trackSouls = NotEnoughUpdates.INSTANCE.config.misc.trackFairySouls;
+ showSouls = NotEnoughUpdates.INSTANCE.config.misc.fariySoul;
+ }
+
+ public void initializeLocation() {
+ if (!trackSouls || currentLocation == null) {
+ return;
+ }
+
+ foundSoulsInLocation = null;
+ closestMissingSouls = new ArrayList<>();
+ missingSoulsDistanceSqMap = new TreeMap<>();
+ lastPlayerPos = BlockPos.ORIGIN;
+
+ allSoulsInCurrentLocation = loadLocationFairySoulsFromConfig(currentLocation);
+ if (allSoulsInCurrentLocation == null) {
+ return;
+ }
+
+ foundSoulsInLocation = getFoundSoulsForProfile()
+ .computeIfAbsent(currentLocation, k -> new HashSet<>());
+ refreshMissingSoulInfo(true);
+ }
+
+ private void refreshMissingSoulInfo(boolean force) {
+ if (allSoulsInCurrentLocation == null) return;
+
+ BlockPos currentPlayerPos = Minecraft.getMinecraft().thePlayer.getPosition();
+ if (lastPlayerPos.equals(currentPlayerPos) && !force) {
+ return;
+ }
+ lastPlayerPos = currentPlayerPos;
+
+ missingSoulsDistanceSqMap.clear();
+ for (int i = 0; i < allSoulsInCurrentLocation.size(); i++) {
+ if (foundSoulsInLocation.contains(i)) {
+ continue;
+ }
+ BlockPos pos = allSoulsInCurrentLocation.get(i);
+ double distSq = pos.distanceSq(lastPlayerPos);
+ missingSoulsDistanceSqMap.put(distSq, pos);
+ }
+ closestMissingSouls.clear();
+ if (missingSoulsDistanceSqMap.isEmpty()) {
+ return;
+ }
+
+ // rebuild the list of the closest ones
+ int maxSouls = 15;
+ int souls = 0;
+ for (BlockPos pos : missingSoulsDistanceSqMap.values()) {
+ closestMissingSouls.add(pos);
+ if (++souls >= maxSouls) break;
+ }
+ }
+
+ private int interpolateColors(int color1, int color2, double factor) {
+ int r1 = ((color1 >> 16) & 0xff);
+ int g1 = ((color1 >> 8) & 0xff);
+ int b1 = (color1 & 0xff);
+
+ int r2 = (color2 >> 16) & 0xff;
+ int g2 = (color2 >> 8) & 0xff;
+ int b2 = color2 & 0xff;
+
+ int r3 = r1 + (int) Math.round(factor * (r2 - r1));
+ int g3 = g1 + (int) Math.round(factor * (g2 - g1));
+ int b3 = b1 + (int) Math.round(factor * (b2 - b1));
+
+ return (r3 & 0xff) << 16 |
+ (g3 & 0xff) << 8 |
+ (b3 & 0xff);
+ }
+
+ private double normalize(double value, double min, double max) {
+ return ((value - min) / (max - min));
+ }
+
+ @SubscribeEvent
+ public void onRenderLast(RenderWorldLastEvent event) {
+ if (!showSouls || !trackSouls || currentLocation == null || closestMissingSouls.isEmpty()) {
+ return;
+ }
+
+ int closeColor = 0x772991; // 0xa839ce
+ int farColor = 0xCEB4D1;
+ double farSoulDistSq = lastPlayerPos.distanceSq(closestMissingSouls.get(closestMissingSouls.size() - 1));
+ for (BlockPos currentSoul : closestMissingSouls) {
+ double currentDistSq = lastPlayerPos.distanceSq(currentSoul);
+ double factor = normalize(currentDistSq, 0.0, farSoulDistSq);
+ int rgb = interpolateColors(closeColor, farColor, Math.min(0.40, factor));
+ RenderUtils.renderBeaconBeamOrBoundingBox(currentSoul, rgb, 1.0f, event.partialTicks);
+ }
+ }
+
+ public void setShowFairySouls(boolean enabled) {
+ NotEnoughUpdates.INSTANCE.config.misc.fariySoul = enabled;
+ showSouls = enabled;
+ }
+
+ public void setTrackFairySouls(boolean enabled) {
+ NotEnoughUpdates.INSTANCE.config.misc.trackFairySouls = enabled;
+ trackSouls = enabled;
+ }
+
+ public void markClosestSoulFound() {
+ if (!trackSouls) return;
+ int closestIndex = -1;
+ double closestDistSq = 10 * 10;
+ for (int i = 0; i < allSoulsInCurrentLocation.size(); i++) {
+ BlockPos pos = allSoulsInCurrentLocation.get(i);
+
+ double distSq = pos.distanceSq(Minecraft.getMinecraft().thePlayer.getPosition());
+
+ if (distSq < closestDistSq) {
+ closestDistSq = distSq;
+ closestIndex = i;
+ }
+ }
+ if (closestIndex != -1) {
+ foundSoulsInLocation.add(closestIndex);
+ refreshMissingSoulInfo(true);
+ }
+ }
+
+ public void markAllAsFound() {
+ if (!trackSouls) {
+ print(EnumChatFormatting.RED + "Fairy soul tracking is turned off, turn it on using /neu");
+ return;
+ }
+ if (allSoulsInCurrentLocation == null) {
+ print(EnumChatFormatting.RED + "No fairy souls found in your current world");
+ return;
+ }
+ for (int i = 0; i < allSoulsInCurrentLocation.size(); i++) {
+ foundSoulsInLocation.add(i);
+ }
+ refreshMissingSoulInfo(true);
+
+ print(EnumChatFormatting.DARK_PURPLE + "Marked all fairy souls as found");
+ }
+
+ public void markAllAsMissing() {
+ if (!trackSouls) {
+ print(EnumChatFormatting.RED + "Fairy soul tracking is turned off, turn it on using /neu");
+ return;
+ }
+ if (allSoulsInCurrentLocation == null) {
+ print(EnumChatFormatting.RED + "No fairy souls found in your current world");
+ return;
+ }
+ foundSoulsInLocation.clear();
+ refreshMissingSoulInfo(true);
+
+ print(EnumChatFormatting.DARK_PURPLE + "Marked all fairy souls as not found");
+ }
+
+ private HashMap<String, Set<Integer>> getFoundSoulsForProfile() {
String profile = SBInfo.getInstance().currentProfile;
if (profile == null) {
- if (loadedFoundSouls.containsKey(unknownProfile))
- return loadedFoundSouls.get(unknownProfile);
+ if (allProfilesFoundSouls.containsKey(unknownProfile))
+ return allProfilesFoundSouls.get(unknownProfile);
} else {
profile = profile.toLowerCase(Locale.getDefault());
- if (loadedFoundSouls.containsKey(unknownProfile)) {
- HashMap<String, Set<Integer>> unknownProfileData = loadedFoundSouls.remove(unknownProfile);
- loadedFoundSouls.put(profile, unknownProfileData);
+ if (allProfilesFoundSouls.containsKey(unknownProfile)) {
+ HashMap<String, Set<Integer>> unknownProfileData = allProfilesFoundSouls.remove(unknownProfile);
+ allProfilesFoundSouls.put(profile, unknownProfileData);
return unknownProfileData;
}
- if (loadedFoundSouls.containsKey(profile)) {
- return loadedFoundSouls.get(profile);
+ if (allProfilesFoundSouls.containsKey(profile)) {
+ return allProfilesFoundSouls.get(profile);
} else {
- //create a new entry for this profile
+ // Create a new entry for this profile
HashMap<String, Set<Integer>> profileData = new HashMap<>();
- loadedFoundSouls.put(profile, profileData);
+ allProfilesFoundSouls.put(profile, profileData);
return profileData;
}
}
return new HashMap<>();
}
- public static void load(File file, Gson gson) {
- loadedFoundSouls = new HashMap<>();
+ private static List<BlockPos> loadLocationFairySoulsFromConfig(String currentLocation) {
+ JsonObject fairySoulList = Constants.FAIRYSOULS;
+ if (fairySoulList == null) {
+ return null;
+ }
+
+ if (!fairySoulList.has(currentLocation) || !fairySoulList.get(currentLocation).isJsonArray()) {
+ return null;
+ }
+
+ JsonArray locations = fairySoulList.get(currentLocation).getAsJsonArray();
+ List<BlockPos> locationSouls = new ArrayList<>();
+ for (int i = 0; i < locations.size(); i++) {
+ try {
+ String coord = locations.get(i).getAsString();
+
+ String[] split = coord.split(",");
+ if (split.length == 3) {
+ String xS = split[0];
+ String yS = split[1];
+ String zS = split[2];
+
+ int x = Integer.parseInt(xS);
+ int y = Integer.parseInt(yS);
+ int z = Integer.parseInt(zS);
+
+ locationSouls.add(new BlockPos(x, y, z));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ if (locationSouls.size() == 0) {
+ return null;
+ }
+
+ return locationSouls;
+ }
+
+ public void loadFoundSoulsForAllProfiles(File file, Gson gson) {
+ allProfilesFoundSouls = new HashMap<>();
String fileContent;
try {
fileContent = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining(System.lineSeparator()));
} catch (FileNotFoundException e) {
+ // it is possible that the collected_fairy_souls.json won't exist
return;
}
try {
//noinspection UnstableApiUsage
Type multiProfileSoulsType = new TypeToken<HashMap<String, HashMap<String, Set<Integer>>>>() {}.getType();
- loadedFoundSouls = gson.fromJson(fileContent, multiProfileSoulsType);
+ allProfilesFoundSouls = gson.fromJson(fileContent, multiProfileSoulsType);
+ if (allProfilesFoundSouls == null){
+ allProfilesFoundSouls = new HashMap<>();
+ }
} catch (JsonSyntaxException e) {
//The file is in the old format, convert it to the new one and set the profile to unknown
try {
//noinspection UnstableApiUsage
Type singleProfileSoulsType = new TypeToken<HashMap<String, Set<Integer>>>() {}.getType();
- loadedFoundSouls.put(unknownProfile, gson.fromJson(fileContent, singleProfileSoulsType));
+ allProfilesFoundSouls.put(unknownProfile, gson.fromJson(fileContent, singleProfileSoulsType));
} catch (JsonSyntaxException e2) {
System.err.println("Can't read file containing collected fairy souls, resetting.");
}
}
}
- public static void save(File file, Gson gson) {
+ public void saveFoundSoulsForAllProfiles(File file, Gson gson) {
try {
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
@@ -95,78 +349,24 @@ public class FairySouls {
StandardCharsets.UTF_8
))
) {
- writer.write(gson.toJson(loadedFoundSouls));
+ writer.write(gson.toJson(allProfilesFoundSouls));
}
- } catch (IOException ignored) {
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
- public static void tick() {
- if (!NotEnoughUpdates.INSTANCE.config.misc.fariySoul) return;
-
- if (Minecraft.getMinecraft().theWorld == null) {
- currentSoulList = null;
- return;
- }
-
- JsonObject fairySouls = Constants.FAIRYSOULS;
- if (fairySouls == null) return;
-
+ public void tick() {
+ if (!trackSouls) return;
String location = SBInfo.getInstance().getLocation();
- if (location == null) {
- currentSoulList = null;
- return;
- }
+ if (location == null || location.isEmpty()) return;
- if (currentSoulList == null) {
- if (fairySouls.has(location) && fairySouls.get(location).isJsonArray()) {
- JsonArray locations = fairySouls.get(location).getAsJsonArray();
- currentSoulList = new ArrayList<>();
- for (int i = 0; i < locations.size(); i++) {
- try {
- String coord = locations.get(i).getAsString();
-
- String[] split = coord.split(",");
- if (split.length == 3) {
- String xS = split[0];
- String yS = split[1];
- String zS = split[2];
-
- int x = Integer.parseInt(xS);
- int y = Integer.parseInt(yS);
- int z = Integer.parseInt(zS);
-
- currentSoulList.add(new BlockPos(x, y, z));
- }
- } catch (Exception ignored) {
- }
- }
- }
+ if (!location.equals(currentLocation)) {
+ currentLocation = location;
+ initializeLocation();
}
- if (currentSoulList != null && !currentSoulList.isEmpty()) {
- TreeMap<Double, BlockPos> distanceSqMap = new TreeMap<>();
-
- HashMap<String, Set<Integer>> foundSouls = getFoundSoulsForProfile();
-
- Set<Integer> found = foundSouls.computeIfAbsent(location, k -> new HashSet<>());
-
- for (int i = 0; i < currentSoulList.size(); i++) {
- if (found.contains(i)) continue;
-
- BlockPos pos = currentSoulList.get(i);
- double distSq = pos.distanceSq(Minecraft.getMinecraft().thePlayer.getPosition());
- distanceSqMap.put(distSq, pos);
- }
-
- int maxSouls = 15;
- int souls = 0;
- currentSoulListClose = new ArrayList<>();
- for (BlockPos pos : distanceSqMap.values()) {
- currentSoulListClose.add(pos);
- if (++souls >= maxSouls) break;
- }
- }
+ refreshMissingSoulInfo(false);
}
private static void print(String s) {
@@ -186,63 +386,24 @@ public class FairySouls {
}
print(EnumChatFormatting.GOLD.toString() + EnumChatFormatting.BOLD + " Commands:");
print(EnumChatFormatting.YELLOW + "/neusouls help - Display this message");
- print(EnumChatFormatting.YELLOW + "/neusouls on/off - Enable/disable the waypoint markers");
+ print(EnumChatFormatting.YELLOW + "/neusouls on/off - Enable/disable showing waypoint markers");
print(EnumChatFormatting.YELLOW +
"/neusouls clear/unclear - Marks every waypoint in your current world as completed/uncompleted");
print("");
}
@SubscribeEvent
- public void onWorldUnload(WorldEvent.Unload event) {
- currentSoulList = null;
- }
-
- @SubscribeEvent
public void onChatReceived(ClientChatReceivedEvent event) {
- if (currentSoulList == null) return;
+ if (!trackSouls || event.type == 2) return;
- if (event.message.getFormattedText().equals("\u00A7r\u00A7dYou have already found that Fairy Soul!\u00A7r") ||
- event.message.getFormattedText().equals(
- "\u00A7d\u00A7lSOUL! \u00A7fYou found a \u00A7r\u00A7dFairy Soul\u00A7r\u00A7f!\u00A7r")) {
- String location = SBInfo.getInstance().getLocation();
- if (location == null) return;
-
- int closestIndex = -1;
- double closestDistSq = 10 * 10;
- for (int i = 0; i < currentSoulList.size(); i++) {
- BlockPos pos = currentSoulList.get(i);
-
- double distSq = pos.distanceSq(Minecraft.getMinecraft().thePlayer.getPosition());
-
- if (distSq < closestDistSq) {
- closestDistSq = distSq;
- closestIndex = i;
- }
- }
- if (closestIndex != -1) {
- HashMap<String, Set<Integer>> foundSouls = getFoundSoulsForProfile();
- Set<Integer> found = foundSouls.computeIfAbsent(location, k -> new HashSet<>());
- found.add(closestIndex);
- }
- }
- }
-
- @SubscribeEvent
- public void onRenderLast(RenderWorldLastEvent event) {
- if (!NotEnoughUpdates.INSTANCE.config.misc.fariySoul) return;
-
- String location = SBInfo.getInstance().getLocation();
- if (location == null) return;
- if (currentSoulList == null || currentSoulList.isEmpty()) return;
-
- int rgb = 0xa839ce;
- for (BlockPos currentSoul : currentSoulListClose) {
- RenderUtils.renderBeaconBeamOrBoundingBox(currentSoul, rgb, 1.0f, event.partialTicks);
+ if (event.message.getUnformattedText().equals("You have already found that Fairy Soul!") ||
+ event.message.getUnformattedText().equals(
+ "SOUL! You found a Fairy Soul!")) {
+ markClosestSoulFound();
}
}
public static class FairySoulsCommand extends ClientCommandBase {
-
public FairySoulsCommand() {
super("neusouls");
}
@@ -258,73 +419,36 @@ public class FairySouls {
printHelp();
return;
}
- String subcommand = args[0].toLowerCase();
+ String subcommand = args[0].toLowerCase();
switch (subcommand) {
case "help":
printHelp();
- return;
+ break;
case "on":
case "enable":
+ if (!FairySouls.instance.trackSouls) {
+ print(
+ EnumChatFormatting.RED + "Fairy soul tracking is off, enable it using /neu before using this command");
+ return;
+ }
print(EnumChatFormatting.DARK_PURPLE + "Enabled fairy soul waypoints");
- NotEnoughUpdates.INSTANCE.config.misc.fariySoul = true;
- return;
+ FairySouls.getInstance().setShowFairySouls(true);
+ break;
case "off":
case "disable":
+ FairySouls.getInstance().setShowFairySouls(false);
print(EnumChatFormatting.DARK_PURPLE + "Disabled fairy soul waypoints");
- NotEnoughUpdates.INSTANCE.config.misc.fariySoul = false;
- return;
- case "clear": {
- String location = SBInfo.getInstance().getLocation();
- if (currentSoulList == null || location == null) {
- print(EnumChatFormatting.RED + "No fairy souls found in your current world");
- } else {
- HashMap<String, Set<Integer>> foundSouls = getFoundSoulsForProfile();
- Set<Integer> found = foundSouls.computeIfAbsent(location, k -> new HashSet<>());
- for (int i = 0; i < currentSoulList.size(); i++) {
- found.add(i);
- }
- String profileName = SBInfo.getInstance().currentProfile;
- if (profileName == null) {
- if (loadedFoundSouls.containsKey(unknownProfile)) {
- loadedFoundSouls.get(unknownProfile).put(location, found);
- }
- } else {
- profileName = profileName.toLowerCase();
- if (!loadedFoundSouls.containsKey(profileName)) {
- HashMap<String, Set<Integer>> profileData = new HashMap<>();
- loadedFoundSouls.put(profileName, profileData);
- }
- loadedFoundSouls.get(profileName).put(location, found);
- }
- print(EnumChatFormatting.DARK_PURPLE + "Marked all fairy souls as found");
- }
- }
- return;
+ break;
+ case "clear":
+ FairySouls.getInstance().markAllAsFound();
+ break;
case "unclear":
- String location = SBInfo.getInstance().getLocation();
- if (location == null) {
- print(EnumChatFormatting.RED + "No fairy souls found in your current world");
- } else {
- String profileName = SBInfo.getInstance().currentProfile;
- if (profileName == null) {
- if (loadedFoundSouls.containsKey(unknownProfile)) {
- loadedFoundSouls.get(unknownProfile).remove(location);
- }
- } else {
- profileName = profileName.toLowerCase();
- if (!loadedFoundSouls.containsKey(profileName)) {
- HashMap<String, Set<Integer>> profileData = new HashMap<>();
- loadedFoundSouls.put(profileName, profileData);
- }
- loadedFoundSouls.get(profileName).remove(location);
- }
- print(EnumChatFormatting.DARK_PURPLE + "Marked all fairy souls as not found");
- }
- return;
+ FairySouls.getInstance().markAllAsMissing();
+ break;
+ default:
+ print(EnumChatFormatting.RED + "Unknown subcommand: " + subcommand);
}
-
- print(EnumChatFormatting.RED + "Unknown subcommand: " + subcommand);
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FancyPortals.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FancyPortals.java
deleted file mode 100644
index 12e65e65..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FancyPortals.java
+++ /dev/null
@@ -1,293 +0,0 @@
-package io.github.moulberry.notenoughupdates.miscfeatures;
-
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.Gui;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.client.renderer.RenderGlobal;
-import net.minecraft.client.renderer.WorldRenderer;
-import net.minecraft.client.renderer.chunk.CompiledChunk;
-import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
-import net.minecraft.client.renderer.vertex.VertexFormat;
-import net.minecraft.client.renderer.vertex.VertexFormatElement;
-import net.minecraft.entity.Entity;
-import net.minecraft.entity.EntityLivingBase;
-import net.minecraft.network.play.server.S07PacketRespawn;
-import net.minecraft.util.MathHelper;
-import net.minecraft.util.ResourceLocation;
-import net.minecraftforge.client.event.RenderLivingEvent;
-import net.minecraftforge.client.event.RenderWorldLastEvent;
-import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import org.lwjgl.input.Keyboard;
-import org.lwjgl.opengl.GL11;
-import org.lwjgl.util.glu.Project;
-
-import java.nio.ByteBuffer;
-import java.util.List;
-
-public class FancyPortals {
- private static final ResourceLocation[] RENDERS = new ResourceLocation[6];
-
- static {
- for (int i = 0; i < 6; i++) {
- RENDERS[i] = new ResourceLocation("notenoughupdates:portal_panoramas/nether/pansc-" + (i + 1) + ".png");
- }
- }
-
- public static int perspectiveId = -1;
-
- public static boolean overridePerspective() {
- if (perspectiveId >= 0 && !Keyboard.isKeyDown(Keyboard.KEY_K)) {
- if (perspectiveId == 0) {
- GlStateManager.matrixMode(5889);
- GlStateManager.loadIdentity();
- GlStateManager.ortho(0.0D, 7, 7, 0.0D, -100D, 100D);
- GlStateManager.scale(1, 1, -1);
- GlStateManager.matrixMode(5888);
- GlStateManager.loadIdentity();
- GlStateManager.translate(3.5F, 3.5F, -1.0F);
- GlStateManager.rotate(-90, 1, 0, 0);
- } else if (perspectiveId <= 4) {
- GlStateManager.matrixMode(5889);
- GlStateManager.loadIdentity();
- Project.gluPerspective(90, 1, 0.05F, 160 * MathHelper.SQRT_2);
- GlStateManager.matrixMode(5888);
- GlStateManager.loadIdentity();
- GlStateManager.rotate(perspectiveId * 90, 0, 1, 0);
- GlStateManager.translate(0, -3.5f, 0);
- } else {
- GlStateManager.matrixMode(5889);
- GlStateManager.loadIdentity();
- Project.gluPerspective(90, 1, 0.05F, 160 * MathHelper.SQRT_2);
- GlStateManager.matrixMode(5888);
- GlStateManager.loadIdentity();
- GlStateManager.rotate(-90, 1, 0, 0);
- GlStateManager.translate(0, -3.5f, 0);
- }
-
- return true;
- }
- return false;
- }
-
- private static WorldRenderer surfaceWorldRenderer = null;
-
- private static WorldRenderer getSurfaceWorldRenderer() {
- if (surfaceWorldRenderer != null && !Keyboard.isKeyDown(Keyboard.KEY_O)) {
- return surfaceWorldRenderer;
- }
-
- surfaceWorldRenderer = createSurfaceWorldRenderer();
-
- return surfaceWorldRenderer;
- }
-
- private static void drawPoint(WorldRenderer worldRenderer, int x, int y) {
- float xDist = 1 - Math.abs(x - 50) / 50f;
- float yDist = 1 - Math.abs(y - 50) / 50f;
- float distToEdge = Math.min(xDist, yDist);
-
- float z = 0.4142f;
- if (distToEdge < 1 / 3.5f) {
- if (y > 50 && yDist < xDist) {
- float circleH = 1.414f - distToEdge * 3.5f * 1.414f;
- z = (float) Math.sqrt(2f - circleH * circleH);
- z *= 0.4142f / 1.4142f;
- } else {
- float circleH = 1 - distToEdge * 3.5f;
- z = (float) Math.sqrt(2f - circleH * circleH) - 1;
- }
- }
-
- worldRenderer.pos(x * 7 / 100f, y * 7 / 100f, z).tex(x / 100f, y / 100f).endVertex();
- }
-
- private static WorldRenderer createSurfaceWorldRenderer() {
- WorldRenderer worldRenderer = new WorldRenderer(20 * 100 * 100);
- worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX);
-
- for (int x = 0; x < 100; x++) {
- for (int y = 0; y < 100; y++) {
- drawPoint(worldRenderer, x, y);
- drawPoint(worldRenderer, x, y + 1);
- drawPoint(worldRenderer, x + 1, y + 1);
- drawPoint(worldRenderer, x + 1, y);
- }
- }
-
- return worldRenderer;
- }
-
- private static long overridingRenderMillis = -1;
-
- public static void onRespawnPacket(S07PacketRespawn packet) {
- if (true) return;
- if (packet.getDimensionID() != Minecraft.getMinecraft().thePlayer.dimension) {
- overridingRenderMillis = System.currentTimeMillis();
- }
- }
-
- public static boolean shouldRenderLoadingScreen() {
- return false;
- }
-
- public static boolean shouldRenderWorldOverlay() {
- if (overridingRenderMillis > 0) {
- if (Minecraft.getMinecraft().theWorld != null && Minecraft.getMinecraft().thePlayer != null) {
- RenderGlobal renderGlobal = Minecraft.getMinecraft().renderGlobal;
- int loaded = 0;
- for (RenderGlobal.ContainerLocalRenderInformation info : renderGlobal.renderInfos) {
- CompiledChunk compiledchunk = info.renderChunk.compiledChunk;
-
- if (compiledchunk != CompiledChunk.DUMMY && !compiledchunk.isEmpty()) {
- if (++loaded >= 5) {
- overridingRenderMillis = -1;
- return false;
- }
- }
- }
- }
- if (System.currentTimeMillis() - overridingRenderMillis > 1000) {
- overridingRenderMillis = -1;
- return false;
- }
- return true;
- }
- return false;
- }
-
- public static void onUpdateCameraAndRender(float partialTicks, long nanoTime) {
- if (overridingRenderMillis > 0) {
- if (Minecraft.getMinecraft().theWorld != null && Minecraft.getMinecraft().thePlayer != null) {
- Minecraft.getMinecraft().thePlayer.timeInPortal = 0.3f;
- Minecraft.getMinecraft().thePlayer.prevTimeInPortal = 0.3f;
- }
-
- GlStateManager.rotate(90, 0, 1, 0);
- renderWorld();
-
- Minecraft.getMinecraft().ingameGUI.renderGameOverlay(partialTicks);
- }
- }
-
- @SubscribeEvent
- public void onRenderEntityYeeter(RenderLivingEvent.Pre<EntityLivingBase> event) {
- /*if(!Keyboard.isKeyDown(Keyboard.KEY_G)) return;
- event.setCanceled(true);
- if(event.entity instanceof EntityPlayer) {
- EntityPlayer player = (EntityPlayer) event.entity;
- if(player.getUniqueID().version() == 4) {
- event.setCanceled(true);
- }
- }*/
- }
-
- private static void renderWorld() {
- for (int i = 5; i >= 0; i--) {
- GlStateManager.pushMatrix();
-
- GlStateManager.disableDepth();
- GlStateManager.disableLighting();
-
- GlStateManager.rotate(180, 0, 0, 1);
- GlStateManager.rotate(-90, 0, 1, 0);
-
- if (i != 0) GlStateManager.translate(0, -3.49, 0);
-
- switch (i) {
- case 1:
- GlStateManager.rotate(90.0F, 0.0F, 1.0F, 0.0F);
- break;
- case 2:
- GlStateManager.rotate(180.0F, 0.0F, 1.0F, 0.0F);
- break;
- case 3:
- GlStateManager.rotate(-90.0F, 0.0F, 1.0F, 0.0F);
- break;
- case 5:
- GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F);
- break;
- case 0:
- GlStateManager.rotate(-90.0F, 1.0F, 0.0F, 0.0F);
- break;
- }
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(RENDERS[i]);
- GlStateManager.color(1, 1, 1, 1);
- if (i != 0) GlStateManager.translate(0, 0, 3.49);
-
- if (i != 0) {
- GlStateManager.translate(-3.5f, -3.5f, 0);
- WorldRenderer worldRenderer = getSurfaceWorldRenderer();
- VertexFormat vertexformat = worldRenderer.getVertexFormat();
- int stride = vertexformat.getNextOffset();
- ByteBuffer bytebuffer = worldRenderer.getByteBuffer();
- List<VertexFormatElement> list = vertexformat.getElements();
-
- for (int index = 0; index < list.size(); index++) {
- VertexFormatElement vertexformatelement = list.get(index);
- vertexformatelement.getUsage().preDraw(vertexformat, index, stride, bytebuffer);
- }
-
- GL11.glDrawArrays(worldRenderer.getDrawMode(), 0, worldRenderer.getVertexCount());
-
- for (int index = 0; index < list.size(); index++) {
- VertexFormatElement vertexformatelement = list.get(index);
- vertexformatelement.getUsage().postDraw(vertexformat, index, stride, bytebuffer);
- }
- } else {
- Utils.drawTexturedRect(-3.5f, -3.5f, 7, 7, i == 0 ? GL11.GL_NEAREST : GL11.GL_LINEAR);
- }
-
- GlStateManager.enableDepth();
-
- GlStateManager.popMatrix();
- }
- }
-
- @SubscribeEvent
- public void onRenderLast(RenderWorldLastEvent event) {
- if (true) return;
- if (!Minecraft.getMinecraft().getFramebuffer().isStencilEnabled())
- Minecraft.getMinecraft().getFramebuffer().enableStencil();
-
- GL11.glEnable(GL11.GL_STENCIL_TEST);
- GL11.glStencilFunc(GL11.GL_ALWAYS, 1, 0xFF);
- GL11.glStencilOp(GL11.GL_ZERO, GL11.GL_ZERO, GL11.GL_REPLACE);
- GL11.glStencilMask(0xFF);
- GL11.glClear(GL11.GL_STENCIL_BUFFER_BIT);
- GlStateManager.enableDepth();
- GlStateManager.enableCull();
- GlStateManager.cullFace(GL11.GL_BACK);
-
- GL11.glColorMask(false, false, false, false);
-
- Entity viewer = Minecraft.getMinecraft().getRenderViewEntity();
- double viewerX = viewer.lastTickPosX + (viewer.posX - viewer.lastTickPosX) * event.partialTicks;
- double viewerY = viewer.lastTickPosY + (viewer.posY - viewer.lastTickPosY) * event.partialTicks;
- double viewerZ = viewer.lastTickPosZ + (viewer.posZ - viewer.lastTickPosZ) * event.partialTicks;
- GlStateManager.pushMatrix();
-
- GlStateManager.translate(-viewerX + 12 + 5 / 16f, -viewerY + 100, -viewerZ + 39);
- GlStateManager.rotate(90, 0, 1, 0);
- Gui.drawRect(0, 5, 3, 0, 0xffffffff);
- GlStateManager.rotate(180, 0, 1, 0);
- GlStateManager.translate(-3, 0, -6 / 16f);
- Gui.drawRect(0, 5, 3, 0, 0xffffffff);
-
- GlStateManager.popMatrix();
-
- GL11.glColorMask(true, true, true, true);
-
- // Only pass stencil test if equal to 1
- GL11.glStencilMask(0x00);
- GL11.glStencilFunc(GL11.GL_EQUAL, 1, 0xFF);
-
- GlStateManager.translate(-viewerX + 12, -viewerY + 100, -viewerZ + 37.5f);
-
- renderWorld();
-
- GL11.glDisable(GL11.GL_STENCIL_TEST);
- GlStateManager.enableCull();
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java
index 34e849d0..13a078a2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/FishingHelper.java
@@ -1,8 +1,29 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.ChromaColour;
import io.github.moulberry.notenoughupdates.util.SpecialColour;
import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.PositionedSound;
@@ -11,8 +32,10 @@ import net.minecraft.client.particle.EntityFX;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.projectile.EntityFishHook;
+import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
@@ -21,7 +44,13 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.opengl.GL11;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class FishingHelper {
private static final FishingHelper INSTANCE = new FishingHelper();
@@ -63,46 +92,92 @@ public class FishingHelper {
private int pingDelayTicks = 0;
private final List<Integer> pingDelayList = new ArrayList<>();
private int buildupSoundDelay = 0;
+ private boolean playedSound = false;
private static final ResourceLocation FISHING_WARNING_EXCLAM = new ResourceLocation(
"notenoughupdates:fishing_warning_exclam.png");
+ public boolean renderWarning() {
+ if (warningState == PlayerWarningState.NOTHING) return false;
+
+ if (!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning &&
+ warningState == PlayerWarningState.FISH_INCOMING)
+ return false;
+ if (!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR &&
+ warningState == PlayerWarningState.FISH_HOOKED)
+ return false;
+
+ float offset = warningState == PlayerWarningState.FISH_HOOKED ? 0.5f : 0f;
+
+ float centerOffset = 0.5f / 8f;
+ Minecraft.getMinecraft().getTextureManager().bindTexture(FISHING_WARNING_EXCLAM);
+ Utils.drawTexturedRect(
+ centerOffset - 4f / 8f,
+ -20 / 8f,
+ 1f,
+ 2f,
+ 0 + offset,
+ 0.5f + offset,
+ 0,
+ 1,
+ GL11.GL_NEAREST
+ );
+ return true;
+ }
+
public void onRenderBobber(EntityFishHook hook) {
- if (Minecraft.getMinecraft().thePlayer.fishEntity == hook && warningState != PlayerWarningState.NOTHING) {
-
- if (!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarning &&
- warningState == PlayerWarningState.FISH_INCOMING)
- return;
- if (!NotEnoughUpdates.INSTANCE.config.fishing.incomingFishWarningR &&
- warningState == PlayerWarningState.FISH_HOOKED)
- return;
-
- GlStateManager.disableCull();
- GlStateManager.disableLighting();
- GL11.glDepthFunc(GL11.GL_ALWAYS);
- GlStateManager.scale(1, -1, 1);
-
- float offset = warningState == PlayerWarningState.FISH_HOOKED ? 0.5f : 0f;
-
- float centerOffset = 0.5f / 8f;
- Minecraft.getMinecraft().getTextureManager().bindTexture(FISHING_WARNING_EXCLAM);
- Utils.drawTexturedRect(
- centerOffset - 4f / 8f,
- -20 / 8f,
- 1f,
- 2f,
- 0 + offset,
- 0.5f + offset,
- 0,
- 1,
- GL11.GL_NEAREST
- );
-
- GlStateManager.scale(1, -1, 1);
- GL11.glDepthFunc(GL11.GL_LEQUAL);
- GlStateManager.enableLighting();
- GlStateManager.enableCull();
+ if (Minecraft.getMinecraft().thePlayer.fishEntity != hook) return;
+ GlStateManager.pushMatrix();
+ GlStateManager.disableCull();
+ GlStateManager.disableLighting();
+ GL11.glDepthFunc(GL11.GL_ALWAYS);
+ GlStateManager.scale(1, -1, 1);
+ boolean isExclamationMarkPresent = renderWarning();
+ GlStateManager.scale(0.1, 0.1, 1);
+ drawFishingTimer(hook, isExclamationMarkPresent);
+ GL11.glDepthFunc(GL11.GL_LEQUAL);
+ GlStateManager.enableLighting();
+ GlStateManager.enableCull();
+ GlStateManager.popMatrix();
+ }
+
+ private void drawFishingTimer(EntityFishHook hook, boolean isExclamationMarkPresent) {
+ if (!NotEnoughUpdates.INSTANCE.config.fishing.fishingTimer) return;
+ float baseHeight = isExclamationMarkPresent ? 20 : 0;
+ int ticksExisted = hook.ticksExisted;
+ float seconds = ticksExisted / 20F;
+ int color;
+ if (seconds >= 30) {
+ color = ChromaColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.fishing.fishingTimerColor30SecPlus);
+ if (NotEnoughUpdates.INSTANCE.config.fishing.fishingSound30Sec && !playedSound) {
+ ISound sound = new PositionedSound(new ResourceLocation("random.orb")) {{
+ volume = 50;
+ pitch = 2f;
+ repeat = false;
+ repeatDelay = 0;
+ attenuationType = ISound.AttenuationType.NONE;
+ }};
+
+ float oldLevel = Minecraft.getMinecraft().gameSettings.getSoundLevel(SoundCategory.RECORDS);
+ Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, 1);
+ Minecraft.getMinecraft().getSoundHandler().playSound(sound);
+ Minecraft.getMinecraft().gameSettings.setSoundLevel(SoundCategory.RECORDS, oldLevel);
+ playedSound = true;
+ }
+ } else {
+ color = ChromaColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.fishing.fishingTimerColor);
+ playedSound = false;
}
+
+ Utils.drawStringCentered(
+ String.format("%.02fs", seconds),
+ Minecraft.getMinecraft().fontRendererObj,
+ 0,
+ -baseHeight - Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT,
+ false,
+ color
+ );
+
}
public void addEntity(int entityId, Entity entity) {
@@ -257,7 +332,17 @@ public class FishingHelper {
double angle2
) {
double dY = particleY - hook.posY;
- if (Math.abs(dY) > 0.5f) {
+ double tolerance = 0.5F;
+ if (hook.worldObj != null) {
+ for (int i = -2; i < 2; i++) {
+ IBlockState state = hook.worldObj.getBlockState(new BlockPos(particleX, particleY + i, particleZ));
+ if (state != null && (state.getBlock() == Blocks.flowing_lava
+ || state.getBlock() == Blocks.flowing_water
+ || state.getBlock() == Blocks.lava))
+ tolerance = 2.0F;
+ }
+ }
+ if (Math.abs(dY) > tolerance) {
return HookPossibleRet.NOT_POSSIBLE;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java
index 96522d34..f2b13abc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCooldowns.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCustomizeManager.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCustomizeManager.java
index 655364ef..e1b9d567 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCustomizeManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemCustomizeManager.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.gson.Gson;
@@ -18,7 +37,13 @@ import org.lwjgl.opengl.GL14;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.function.Consumer;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemRarityHalo.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemRarityHalo.java
index 88c7261c..79dd18f1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemRarityHalo.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/ItemRarityHalo.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -5,7 +24,11 @@ import io.github.moulberry.notenoughupdates.util.NEUResourceManager;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
-import net.minecraft.client.renderer.*;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.OpenGlHelper;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.client.renderer.Tessellator;
+import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/MiningStuff.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/MiningStuff.java
index b56737e7..12e0301b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/MiningStuff.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/MiningStuff.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NPCRetexturing.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NPCRetexturing.java
index 05d75c26..ad0dd66d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NPCRetexturing.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NPCRetexturing.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.gson.Gson;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java
new file mode 100644
index 00000000..6244c32c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/Navigation.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
+import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent;
+import io.github.moulberry.notenoughupdates.miscgui.GuiNavigation;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.JsonUtils;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.Vec3i;
+import net.minecraftforge.client.event.RenderWorldLastEvent;
+import net.minecraftforge.event.entity.EntityJoinWorldEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.InputEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import org.lwjgl.input.Keyboard;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class Navigation {
+
+ private List<Teleporter> teleporters = new ArrayList<>();
+ private Map<String, String> areaNames = new HashMap<>();
+ private Map<String, WarpPoint> warps = new HashMap<>();
+ private Map<String, JsonObject> waypoints = new HashMap<>();
+
+ public Map<String, JsonObject> getWaypoints() {
+ return waypoints;
+ }
+
+ public static class WarpPoint {
+ public final BlockPos blockPos;
+ public final String warpName, modeName;
+
+ public WarpPoint(double x, double y, double z, String warpName, String modeName) {
+ this.blockPos = new BlockPos(x, y, z);
+ this.warpName = warpName;
+ this.modeName = modeName;
+ }
+ }
+
+ public static class Teleporter {
+ public final double x, y, z;
+ public final String from, to;
+
+ public Teleporter(double x, double y, double z, String from, String to) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.from = from;
+ this.to = to;
+ }
+ }
+
+ private NotEnoughUpdates neu;
+
+ public Navigation(NotEnoughUpdates notEnoughUpdates) {
+ neu = notEnoughUpdates;
+ }
+
+ /* JsonObject (x,y,z,island,displayname) */
+ private JsonObject currentlyTrackedWaypoint = null;
+ private BlockPos position = null;
+ private String island = null;
+ private String displayName = null;
+ private String internalname = null;
+ private String warpAgainTo = null;
+ private int lastInvHashcode = 0;
+ private Instant warpAgainTiming = null;
+
+ private Teleporter nextTeleporter = null;
+
+ public boolean isValidWaypoint(JsonObject object) {
+ return object.has("x")
+ && object.has("y")
+ && object.has("z")
+ && object.has("island")
+ && object.has("displayname")
+ && object.has("internalname");
+ }
+
+ public void trackWaypoint(String trackNow) {
+ if (trackNow == null) {
+ trackWaypoint((JsonObject) null);
+ } else {
+ JsonObject jsonObject = waypoints.get(trackNow);
+ if (jsonObject == null) {
+ showError(
+ "Could not track waypoint " + trackNow + ". This is likely due to an outdated or broken repository.",
+ true
+ );
+ return;
+ }
+ trackWaypoint(jsonObject);
+ }
+ }
+
+ public void trackWaypoint(JsonObject trackNow) {
+ if (trackNow != null && !isValidWaypoint(trackNow)) {
+ showError("Could not track waypoint. This is likely due to an outdated or broken repository.", true);
+ return;
+ }
+ if (!neu.config.hidden.hasOpenedWaypointMenu)
+ NotificationHandler.displayNotification(Arrays.asList(
+ "You just tracked a waypoint.",
+ "Press [N] to open the waypoint menu to untrack it",
+ "or to find other waypoints to track.",
+ "Press [X] to close this message."
+ ), true, false);
+ currentlyTrackedWaypoint = trackNow;
+ updateData();
+ }
+
+ @SubscribeEvent
+ public void onRepositoryReload(RepositoryReloadEvent event) {
+ JsonObject obj = Utils.getConstant("islands", neu.manager.gson);
+ List<Teleporter> teleporters = JsonUtils.getJsonArrayOrEmpty(obj, "teleporters", jsonElement -> {
+ JsonObject teleporterObj = jsonElement.getAsJsonObject();
+ return new Teleporter(
+ teleporterObj.get("x").getAsDouble(),
+ teleporterObj.get("y").getAsDouble(),
+ teleporterObj.get("z").getAsDouble(),
+ teleporterObj.get("from").getAsString(),
+ teleporterObj.get("to").getAsString()
+ );
+ });
+ for (Teleporter teleporter : teleporters) {
+ if (teleporter.from.equals(teleporter.to)) {
+ showError("Found self referencing teleporter: " + teleporter.from, true);
+ }
+ }
+ this.teleporters = teleporters;
+ this.waypoints = NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation().values().stream()
+ .filter(this::isValidWaypoint)
+ .collect(Collectors.toMap(it -> it.get("internalname").getAsString(), it -> it));
+ this.areaNames = JsonUtils.transformJsonObjectToMap(obj.getAsJsonObject("area_names"), JsonElement::getAsString);
+ this.warps = JsonUtils.getJsonArrayOrEmpty(obj, "island_warps", jsonElement -> {
+ JsonObject warpObject = jsonElement.getAsJsonObject();
+ return new WarpPoint(
+ warpObject.get("x").getAsDouble(),
+ warpObject.get("y").getAsDouble(),
+ warpObject.get("z").getAsDouble(),
+ warpObject.get("warp").getAsString(),
+ warpObject.get("mode").getAsString()
+ );
+ }).stream().collect(Collectors.toMap(it -> it.warpName, it -> it));
+ }
+
+ @SubscribeEvent
+ public void onKeybindPressed(InputEvent.KeyInputEvent event) {
+ if (!Keyboard.getEventKeyState()) return;
+ int key = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
+ if (neu.config.misc.keybindWaypoint == key) {
+ if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
+ if (currentlyTrackedWaypoint != null) {
+ useWarpCommand();
+ }
+ } else {
+ Minecraft.getMinecraft().displayGuiScreen(new GuiNavigation());
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START) return;
+ if (Minecraft.getMinecraft().theWorld == null) return;
+ if (Minecraft.getMinecraft().thePlayer == null) return;
+ if (neu.config.getProfileSpecific() == null) return;
+
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest && RenderListener.inventoryLoaded) {
+ GuiChest currentScreen = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest container = (ContainerChest) currentScreen.inventorySlots;
+ if (container.getLowerChestInventory().getDisplayName().getUnformattedText().equals("Fast Travel")) {
+ int hashCode = container.getInventory().hashCode();
+ if (hashCode == lastInvHashcode) return;
+ lastInvHashcode = hashCode;
+ for (ItemStack stackInSlot : container.getInventory()) {
+ if (stackInSlot == null) continue;
+ List<String> lore = ItemUtils.getLore(stackInSlot);
+ if (lore.isEmpty())
+ continue;
+ String warpLine = Utils.cleanColour(lore.get(0));
+ if (!warpLine.startsWith("/warp ")) continue;
+ String warpName = warpLine.substring(6);
+ boolean isUnlocked = !lore.contains("§cWarp not unlocked!");
+ neu.config.getProfileSpecific().unlockedWarpScrolls.put(warpName, isUnlocked);
+ }
+ }
+ }
+ }
+
+ public Map<String, WarpPoint> getWarps() {
+ return warps;
+ }
+
+ public WarpPoint getClosestWarp(String mode, Vec3i position, boolean checkAvailable) {
+ double minDistance = -1;
+ HashMap<String, Boolean> unlockedWarpScrolls = neu.config.getProfileSpecific().unlockedWarpScrolls;
+ WarpPoint minWarp = null;
+ for (WarpPoint value : warps.values()) {
+ if (value.modeName.equals(mode)) {
+ if (checkAvailable && !unlockedWarpScrolls.getOrDefault(value.warpName, false))
+ continue;
+ double distance = value.blockPos.distanceSq(position);
+ if (distance < minDistance || minWarp == null) {
+ minDistance = distance;
+ minWarp = value;
+ }
+ }
+ }
+ return minWarp;
+ }
+
+ public void useWarpCommand() {
+ EntityPlayerSP thePlayer = Minecraft.getMinecraft().thePlayer;
+ if (currentlyTrackedWaypoint == null || thePlayer == null) return;
+ WarpPoint closestWarp = getClosestWarp(island, position, true);
+ if (closestWarp == null) {
+ showError("Could not find an unlocked warp that could be used.", false);
+ return;
+ }
+
+ if (!island.equals(SBInfo.getInstance().mode)) {
+ warpAgainTiming = Instant.now();
+ warpAgainTo = closestWarp.warpName;
+ } else if (thePlayer.getDistanceSq(position) < closestWarp.blockPos.distanceSq(position)) {
+ showError("You are already on the same island and nearer than the closest unlocked warp scroll.", false);
+ return;
+ }
+ thePlayer.sendChatMessage("/warp " + closestWarp.warpName);
+ }
+
+ @SubscribeEvent
+ public void onTeleportDone(EntityJoinWorldEvent event) {
+ if (neu.config.misc.warpTwice
+ && event.entity == Minecraft.getMinecraft().thePlayer
+ && warpAgainTo != null
+ && warpAgainTiming != null
+ && warpAgainTiming.plusSeconds(1).isAfter(Instant.now())) {
+ warpAgainTiming = null;
+ String savedWarpAgain = warpAgainTo;
+ warpAgainTo = null;
+ Minecraft.getMinecraft().thePlayer.sendChatMessage("/warp " + savedWarpAgain);
+ }
+ }
+
+ public String getNameForAreaMode(String mode) {
+ return areaNames.get(mode);
+ }
+
+ public String getNameForAreaModeOrUnknown(String mode) {
+ return areaNames.getOrDefault(mode, "Unknown");
+ }
+
+ public void untrackWaypoint() {
+ trackWaypoint((JsonObject) null);
+ }
+
+ public JsonObject getTrackedWaypoint() {
+ return currentlyTrackedWaypoint;
+ }
+
+ public String getIsland() {
+ return island;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public BlockPos getPosition() {
+ return position;
+ }
+
+ public String getInternalname() {
+ return internalname;
+ }
+
+ private void updateData() {
+ if (currentlyTrackedWaypoint == null) {
+ position = null;
+ island = null;
+ displayName = null;
+ nextTeleporter = null;
+ internalname = null;
+ return;
+ }
+ position = new BlockPos(
+ currentlyTrackedWaypoint.get("x").getAsDouble(),
+ currentlyTrackedWaypoint.get("y").getAsDouble(),
+ currentlyTrackedWaypoint.get("z").getAsDouble()
+ );
+ internalname = currentlyTrackedWaypoint.get("internalname").getAsString();
+ island = currentlyTrackedWaypoint.get("island").getAsString();
+ displayName = currentlyTrackedWaypoint.get("displayname").getAsString();
+ recalculateNextTeleporter(SBInfo.getInstance().mode);
+ }
+
+ @SubscribeEvent
+ public void onLocationChange(LocationChangeEvent event) {
+ recalculateNextTeleporter(event.newLocation);
+ }
+
+ public Teleporter recalculateNextTeleporter(String from) {
+ String to = island;
+ if (from == null || to == null) return null;
+ List<Teleporter> nextTeleporter = findNextTeleporter0(from, to, new HashSet<>());
+ if (nextTeleporter == null || nextTeleporter.isEmpty()) {
+ this.nextTeleporter = null;
+ } else {
+ this.nextTeleporter = nextTeleporter.get(0);
+ }
+ return this.nextTeleporter;
+ }
+
+ private List<Teleporter> findNextTeleporter0(String from, String to, Set<String> visited) {
+ if (from.equals(to)) return new ArrayList<>();
+ if (visited.contains(from)) return null;
+ visited.add(from);
+ int minPathLength = 0;
+ List<Teleporter> minPath = null;
+ for (Teleporter teleporter : teleporters) {
+ if (!teleporter.from.equals(from)) continue;
+ List<Teleporter> nextTeleporter0 = findNextTeleporter0(teleporter.to, to, visited);
+ if (nextTeleporter0 == null) continue;
+ if (minPath == null || nextTeleporter0.size() < minPathLength) {
+ minPathLength = nextTeleporter0.size();
+ nextTeleporter0.add(0, teleporter);
+ minPath = nextTeleporter0;
+ }
+ }
+ visited.remove(from);
+ return minPath;
+ }
+
+ private void showError(String message, boolean log) {
+ EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;
+ if (player != null)
+ player.addChatMessage(new ChatComponentText(EnumChatFormatting.DARK_RED +
+ "[NEU-Waypoint] " + message));
+ if (log)
+ new RuntimeException("[NEU-Waypoint] " + message).printStackTrace();
+ }
+
+ @SubscribeEvent
+ public void onEvent(TickEvent.ClientTickEvent event) {
+ if (event.phase == TickEvent.Phase.END && currentlyTrackedWaypoint != null
+ && NotEnoughUpdates.INSTANCE.config.misc.untrackCloseWaypoints
+ && island.equals(SBInfo.getInstance().mode)) {
+ EntityPlayerSP thePlayer = Minecraft.getMinecraft().thePlayer;
+ if (thePlayer != null && thePlayer.getDistanceSq(position) < 16)
+ untrackWaypoint();
+ }
+ }
+
+ @SubscribeEvent
+ public void onRenderLast(RenderWorldLastEvent event) {
+ if (currentlyTrackedWaypoint != null) {
+ if (island.equals(SBInfo.getInstance().mode)) {
+ RenderUtils.renderWayPoint(displayName, position, event.partialTicks);
+ } else if (nextTeleporter != null) {
+ String to = nextTeleporter.to;
+ String toName = getNameForAreaModeOrUnknown(to);
+ RenderUtils.renderWayPoint(
+ Arrays.asList("Teleporter to " + toName, "(towards " + displayName + "§r)"),
+ new BlockPos(
+ nextTeleporter.x,
+ nextTeleporter.y,
+ nextTeleporter.z
+ ), event.partialTicks
+ );
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java
new file mode 100644
index 00000000..6036d93b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NewApiKeyHelper.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.network.play.client.C01PacketChatMessage;
+import net.minecraft.util.ChatComponentText;
+
+public class NewApiKeyHelper {
+ private static final NewApiKeyHelper INSTANCE = new NewApiKeyHelper();
+
+ public static NewApiKeyHelper getInstance() {
+ return INSTANCE;
+ }
+
+ public void hookPacketChatMessage(C01PacketChatMessage packet) {
+ String message = packet.getMessage().toLowerCase();
+ if (message.equals("/api new")) return;
+
+ if (message.replace(" ", "").startsWith("/apinew")) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "§e[NotEnoughUpdates] §7You just executed §c" + packet.getMessage() +
+ "§7. Did you mean to execute §e/api new§7?"));
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NullzeeSphere.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NullzeeSphere.java
index 927111b3..6302343e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NullzeeSphere.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/NullzeeSphere.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.util.ReverseWorldRenderer;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java
index cb2b7031..776e3647 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PetInfoOverlay.java
@@ -1,12 +1,37 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.common.collect.Lists;
-import com.google.gson.*;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
-import io.github.moulberry.notenoughupdates.NEUOverlay;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.config.Position;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpUtils;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
import io.github.moulberry.notenoughupdates.overlays.TextOverlay;
import io.github.moulberry.notenoughupdates.overlays.TextOverlayStyle;
@@ -23,10 +48,10 @@ import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.client.event.ClientChatReceivedEvent;
-import net.minecraftforge.event.entity.player.ItemTooltipEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -34,23 +59,34 @@ import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.apache.commons.lang3.text.WordUtils;
import org.lwjgl.util.vector.Vector2f;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class PetInfoOverlay extends TextOverlay {
private static final Pattern XP_BOOST_PATTERN = Pattern.compile(
"PET_ITEM_(COMBAT|FISHING|MINING|FORAGING|ALL|FARMING)_(SKILL|SKILLS)_BOOST_(COMMON|UNCOMMON|RARE|EPIC)");
private static final Pattern PET_CONTAINER_PAGE = Pattern.compile("\\((\\d)/(\\d)\\) Pets");
- private static final Pattern PET_NAME_PATTERN = Pattern.compile("\u00a77\\[Lvl \\d+] \u00a7(.+)");
- private static final Pattern XP_LINE_PATTERN = Pattern.compile(
- "-------------------- (\\d+(?:,\\d+)*(?:\\.\\d+)?)/(\\d+(?:\\.\\d+)?[B|M|k]?)");
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
@@ -70,10 +106,10 @@ public class PetInfoOverlay extends TextOverlay {
LEGENDARY(20, 4, 5, EnumChatFormatting.GOLD),
MYTHIC(20, 5, 5, EnumChatFormatting.LIGHT_PURPLE);
- public int petOffset;
- public EnumChatFormatting chatFormatting;
- public int petId;
- public int beastcreatMultiplyer;
+ public final int petOffset;
+ public final EnumChatFormatting chatFormatting;
+ public final int petId;
+ public final int beastcreatMultiplyer;
Rarity(int petOffset, int petId, int beastcreatMultiplyer, EnumChatFormatting chatFormatting) {
this.chatFormatting = chatFormatting;
@@ -97,9 +133,15 @@ public class PetInfoOverlay extends TextOverlay {
public GuiProfileViewer.PetLevel petLevel;
public String petXpType;
public String petItem;
- }
+ public String skin;
+ public int candyUsed;
- private static long lastXpGain = 0;
+ public String getPetId(boolean withoutBoost) {
+ boolean shouldDecreaseRarity = withoutBoost && "PET_ITEM_TIER_BOOST".equals(petItem);
+ return petType + ";" + (shouldDecreaseRarity ? rarity.petId - 1 : rarity.petId);
+ }
+
+ }
public static class PetConfig {
public HashMap<Integer, Pet> petMap = new HashMap<>();
@@ -129,7 +171,7 @@ public class PetInfoOverlay extends TextOverlay {
public static void loadConfig(File file) {
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(
- new FileInputStream(file),
+ Files.newInputStream(file.toPath()),
StandardCharsets.UTF_8
))
) {
@@ -146,7 +188,7 @@ public class PetInfoOverlay extends TextOverlay {
file.createNewFile();
try (
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
- new FileOutputStream(file),
+ Files.newOutputStream(file.toPath()),
StandardCharsets.UTF_8
))
) {
@@ -208,15 +250,11 @@ public class PetInfoOverlay extends TextOverlay {
}
private static Pet getClosestPet(String petType, int petId, String petItem, float petLevel) {
- Set<Pet> pets = new HashSet<Pet>() {{
- for (Pet pet : config.petMap.values()) {
- if (pet.petType.equals(petType) && pet.rarity.petId == petId) {
- add(pet);
- }
- }
- }};
+ Set<Pet> pets = config.petMap.values().stream().filter(pet -> pet.petType.equals(petType) &&
+ pet.rarity.petId == petId).collect(
+ Collectors.toSet());
- if (pets == null || pets.isEmpty()) {
+ if (pets.isEmpty()) {
return null;
}
@@ -224,15 +262,10 @@ public class PetInfoOverlay extends TextOverlay {
return pets.iterator().next();
}
- String searchItem = petItem;
-
- Set<Pet> itemMatches = new HashSet<>();
- for (Pet pet : pets) {
- if ((searchItem == null && pet.petItem == null) ||
- (searchItem != null && searchItem.equals(pet.petItem))) {
- itemMatches.add(pet);
- }
- }
+ Set<Pet> itemMatches = pets
+ .stream()
+ .filter(pet -> Objects.equals(petItem, pet.petItem))
+ .collect(Collectors.toSet());
if (itemMatches.size() == 1) {
return itemMatches.iterator().next();
@@ -253,15 +286,11 @@ public class PetInfoOverlay extends TextOverlay {
}
}
- if (closestPet != null) {
- return closestPet;
- } else {
- return pets.iterator().next();
- }
+ return closestPet;
}
private static void getAndSetPet(ProfileViewer.Profile profile) {
- JsonObject skillInfo = profile.getSkillInfo(profile.getLatestProfile());
+ Map<String, ProfileViewer.Level> skyblockInfo = profile.getSkyblockInfo(profile.getLatestProfile());
JsonObject invInfo = profile.getInventoryInfo(profile.getLatestProfile());
JsonObject profileInfo = profile.getProfileInformation(profile.getLatestProfile());
if (invInfo != null && profileInfo != null) {
@@ -300,7 +329,8 @@ public class PetInfoOverlay extends TextOverlay {
}
}
}
- if (skillInfo != null) config.tamingLevel = skillInfo.get("level_skill_taming").getAsInt();
+ if (skyblockInfo != null) config.tamingLevel = (int) skyblockInfo.get("taming").level;
+
//JsonObject petObject = profile.getPetsInfo(profile.getLatestProfile());
/*JsonObject petsJson = Constants.PETS;
if(petsJson != null) {
@@ -421,7 +451,7 @@ public class PetInfoOverlay extends TextOverlay {
String etaStr = null;
String etaMaxStr = null;
- if (currentPet.petLevel.level < 100) {
+ if (currentPet.petLevel.level < currentPet.petLevel.maxLevel) {
float remaining = currentPet.petLevel.currentLevelRequirement - currentPet.petLevel.levelXp;
if (remaining > 0) {
if (xpGain < 1000) {
@@ -433,14 +463,15 @@ public class PetInfoOverlay extends TextOverlay {
}
}
- if (currentPet.petLevel.level < 99 || !NotEnoughUpdates.INSTANCE.config.petOverlay.petOverlayText.contains(6)) {
+ if (currentPet.petLevel.level < (currentPet.petLevel.maxLevel - 1) ||
+ !NotEnoughUpdates.INSTANCE.config.petOverlay.petOverlayText.contains(6)) {
float remainingMax = currentPet.petLevel.maxXP - currentPet.petLevel.totalXp;
if (remaining > 0) {
if (xpGain < 1000) {
- etaMaxStr = EnumChatFormatting.AQUA + "Until L100: " +
+ etaMaxStr = EnumChatFormatting.AQUA + "Until L" + (int) currentPet.petLevel.maxLevel + ": " +
EnumChatFormatting.YELLOW + "N/A";
} else {
- etaMaxStr = EnumChatFormatting.AQUA + "Until L100: " +
+ etaMaxStr = EnumChatFormatting.AQUA + "Until L" + (int) currentPet.petLevel.maxLevel + ": " +
EnumChatFormatting.YELLOW + Utils.prettyTime((long) (remainingMax) * 1000 * 60 * 60 / (long) xpGain);
}
}
@@ -525,86 +556,10 @@ public class PetInfoOverlay extends TextOverlay {
}
}
- private static GuiProfileViewer.PetLevel getMaxLevel(JsonArray levels, int offset) {
- float xpTotal = 0;
- float level = 1;
- float currentLevelRequirement = 0;
-
- for (int i = offset; i < offset + 99; i++) {
- currentLevelRequirement = levels.get(i).getAsFloat();
- xpTotal += currentLevelRequirement;
- level += 1;
- }
-
- if (level <= 0) {
- level = 1;
- } else if (level > 100) {
- level = 100;
- }
- GuiProfileViewer.PetLevel levelObj = new GuiProfileViewer.PetLevel();
- levelObj.level = level;
- levelObj.currentLevelRequirement = currentLevelRequirement;
- levelObj.maxXP = xpTotal;
- levelObj.levelPercentage = 1;
- levelObj.levelXp = currentLevelRequirement - 5;
- levelObj.totalXp = xpTotal - 5;
- return levelObj;
- }
-
- private static GuiProfileViewer.PetLevel getLevel(
- JsonArray levels,
- int offset,
- float xpThisLevel,
- int xpMaxThisLevel
- ) {
- float xpTotal = 0;
- float level = 1;
- float currentLevelRequirement = 0;
- float exp = xpThisLevel;
-
- boolean addLevel = true;
-
- for (int i = offset; i < offset + 99; i++) {
- if (addLevel) {
- currentLevelRequirement = levels.get(i).getAsFloat();
- xpTotal += currentLevelRequirement;
-
- if (currentLevelRequirement >= xpMaxThisLevel) {
- addLevel = false;
- } else {
- exp += currentLevelRequirement;
- level += 1;
- }
- } else {
- xpTotal += levels.get(i).getAsFloat();
- }
- }
-
- level += xpThisLevel / currentLevelRequirement;
- if (level <= 0) {
- level = 1;
- } else if (level > 100) {
- level = 100;
- }
- GuiProfileViewer.PetLevel levelObj = new GuiProfileViewer.PetLevel();
- levelObj.level = level;
- levelObj.currentLevelRequirement = currentLevelRequirement;
- levelObj.maxXP = xpTotal;
- levelObj.levelPercentage = xpThisLevel / currentLevelRequirement;
- levelObj.levelXp = xpThisLevel;
- levelObj.totalXp = exp;
- return levelObj;
- }
-
- public static Pet getPetFromStack(String name, String[] lore) {
+ public static Pet getPetFromStack(NBTTagCompound tag) {
if (Constants.PETS == null || Constants.PETS.get("pet_levels") == null ||
Constants.PETS.get("pet_levels") instanceof JsonNull) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- "\u00a7cInvalid PET constants. Please run " + EnumChatFormatting.BOLD + "/neuresetrepo" +
- EnumChatFormatting.RESET + EnumChatFormatting.RED + " and " + EnumChatFormatting.BOLD + "restart your game" +
- EnumChatFormatting.RESET + EnumChatFormatting.RED + " in order to fix. " + EnumChatFormatting.DARK_RED +
- EnumChatFormatting.BOLD + "If that doesn't fix it" + EnumChatFormatting.RESET + EnumChatFormatting.RED +
- ", please join discord.gg/moulberry and post in #neu-support"));
+ Utils.showOutdatedRepoNotification();
return null;
}
@@ -612,132 +567,50 @@ public class PetInfoOverlay extends TextOverlay {
Rarity rarity = null;
String heldItem = null;
GuiProfileViewer.PetLevel level = null;
-
- Matcher petNameMatcher = PET_NAME_PATTERN.matcher(name);
- if (petNameMatcher.matches()) {
- String petStringMatch = petNameMatcher.group(1);
-
- char colChar = petStringMatch.charAt(0);
- EnumChatFormatting col = EnumChatFormatting.RESET;
- for (EnumChatFormatting formatting : EnumChatFormatting.values()) {
- if (formatting.toString().equals("\u00a7" + colChar)) {
- col = formatting;
- break;
- }
- }
-
- rarity = Rarity.COMMON;
- if (col != EnumChatFormatting.RESET) {
- rarity = Rarity.getRarityFromColor(col);
- }
-
- petType = Utils.cleanColour(petStringMatch.substring(1))
- .replaceAll("[^\\w ]", "").trim()
- .replace(" ", "_").toUpperCase();
- }
- if (petType == null || rarity == null) {
- return null;
- }
-
- for (String line : lore) {
- Matcher xpLineMatcher = XP_LINE_PATTERN.matcher(Utils.cleanColour(line));
- if (line.startsWith("\u00a76Held Item: ")) {
- String after = line.substring("\u00a76Held Item: ".length());
-
- if (itemMap == null) {
- itemMap = new HashMap<>();
-
- for (Map.Entry<String, JsonObject> entry : NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .entrySet()) {
- boolean petItem = false;
-
- if (entry.getKey().startsWith("PET_ITEM_")) {
- petItem = true;
- } else {
- ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(entry.getValue());
- if (stack.hasTagCompound()) {
- String[] itemLore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound());
-
- for (String itemLoreLine : itemLore) {
- if (itemLoreLine.contains("PET ITEM")) {
- petItem = true;
- break;
- }
- }
- }
- }
-
- if (petItem) {
- ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(entry.getValue());
- itemMap.put(stack.getDisplayName().replace("\u00a7f\u00a7f", ""), entry.getKey());
- }
- }
+ String skin = null;
+
+ if (tag != null && tag.hasKey("ExtraAttributes")) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ if (ea.hasKey("petInfo")) {
+ JsonObject petInfo = new JsonParser().parse(ea.getString("petInfo")).getAsJsonObject();
+ petType = petInfo.get("type").getAsString();
+ rarity = Rarity.valueOf(petInfo.get("tier").getAsString());
+ level = GuiProfileViewer.getPetLevel(
+ petType,
+ rarity.name(),
+ Utils.getElementAsFloat(petInfo.get("exp"), 0) // Should only default if from item list and repo missing exp:0
+ );
+ if (petInfo.has("heldItem")) {
+ heldItem = petInfo.get("heldItem").getAsString();
}
-
- if (itemMap.containsKey(after)) {
- heldItem = itemMap.get(after);
- }
- } else if (xpLineMatcher.matches()) {
- String xpThisLevelS = xpLineMatcher.group(1);
- String xpMaxThisLevelS = xpLineMatcher.group(2).toLowerCase();
-
- try {
- float xpThisLevel = Float.parseFloat(xpThisLevelS.replace(",", ""));
-
- int mutiplier = 1;
- char end = xpMaxThisLevelS.charAt(xpMaxThisLevelS.length() - 1);
- if (end < '0' || end > '9') {
- xpMaxThisLevelS = xpMaxThisLevelS.substring(0, xpMaxThisLevelS.length() - 1);
-
- switch (end) {
- case 'k':
- mutiplier = 1000;
- break;
- case 'm':
- mutiplier = 1000000;
- break;
- case 'b':
- mutiplier = 1000000000;
- break;
- }
- }
- int xpMaxThisLevel = (int) (Float.parseFloat(xpMaxThisLevelS) * mutiplier);
-
- level = getLevel(
- Constants.PETS.get("pet_levels").getAsJsonArray(),
- rarity.petOffset,
- xpThisLevel,
- xpMaxThisLevel
- );
- } catch (NumberFormatException ignored) {
+ if (petInfo.has("skin")) {
+ skin = "PET_SKIN_" + petInfo.get("skin").getAsString();
}
- } else if (line.equals("\u00a7b\u00a7lMAX LEVEL")) {
- level = getMaxLevel(Constants.PETS.get("pet_levels").getAsJsonArray(), rarity.petOffset);
}
}
- if (level != null) {
- Pet pet = new Pet();
- pet.petItem = heldItem;
- pet.petLevel = level;
- pet.rarity = rarity;
- pet.petType = petType;
- JsonObject petTypes = Constants.PETS.get("pet_types").getAsJsonObject();
- pet.petXpType =
- petTypes.has(pet.petType) ? petTypes.get(pet.petType.toUpperCase()).getAsString().toLowerCase() : "unknown";
-
- return pet;
+ if (petType == null) {
+ return null;
}
- return null;
+ Pet pet = new Pet();
+ pet.petItem = heldItem;
+ pet.petLevel = level;
+ pet.rarity = rarity;
+ pet.petType = petType;
+ JsonObject petTypes = Constants.PETS.get("pet_types").getAsJsonObject();
+ pet.petXpType =
+ petTypes.has(pet.petType) ? petTypes.get(pet.petType.toUpperCase()).getAsString().toLowerCase() : "unknown";
+ pet.skin = skin;
+
+ return pet;
}
private static final HashMap<Integer, Integer> removeMap = new HashMap<>();
@SubscribeEvent
public void onTick(TickEvent.ClientTickEvent event) {
- if (Minecraft.getMinecraft().currentScreen instanceof GuiChest && NEUEventListener.inventoryLoaded) {
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest && RenderListener.inventoryLoaded) {
GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
ContainerChest container = (ContainerChest) chest.inventorySlots;
IInventory lower = container.getLowerChestInventory();
@@ -761,7 +634,6 @@ public class PetInfoOverlay extends TextOverlay {
}
}
}
-
if (isPets) {
boolean hasItem = false;
for (int i = 0; i < lower.getSizeInventory(); i++) {
@@ -805,14 +677,14 @@ public class PetInfoOverlay extends TextOverlay {
}
} else {
String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound());
- Pet pet = getPetFromStack(stack.getDisplayName(), lore);
+ Pet pet = getPetFromStack(stack.getTagCompound());
if (pet != null) {
config.petMap.put(petIndex, pet);
if (currentTime - lastPetSelect > 500) {
boolean foundDespawn = false;
for (String line : lore) {
- if (line.equals("\u00a77\u00a7cClick to despawn.")) {
+ if (line.startsWith("\u00a77\u00a7cClick to despawn")) {
config.selectedPet = petIndex;
foundDespawn = true;
break;
@@ -829,6 +701,40 @@ public class PetInfoOverlay extends TextOverlay {
}
}
removeMap.keySet().retainAll(removeSet);
+ } else if (containerName.equals("Your Equipment")) {
+ ItemStack petStack = lower.getStackInSlot(47);
+ if (petStack != null && petStack.getItem() == Items.skull) {
+ NBTTagCompound tag = petStack.getTagCompound();
+
+ if (tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ if (ea.hasKey("petInfo")) {
+ JsonParser jsonParser = new JsonParser();
+
+ JsonObject petInfoObject = jsonParser.parse(ea.getString("petInfo")).getAsJsonObject();
+
+ JsonObject jsonStack = NotEnoughUpdates.INSTANCE.manager.getJsonForItem(petStack);
+ if (jsonStack == null || !jsonStack.has("lore") || !petInfoObject.has("exp")) {
+ return;
+ }
+
+ int rarity = Utils.getRarityFromLore(jsonStack.get("lore").getAsJsonArray());
+ String rarityString = Utils.getRarityFromInt(rarity);
+
+ String name = StringUtils.cleanColour(petStack.getDisplayName());
+ name = name.substring(name.indexOf(']') + 1).trim().replace(' ', '_').toUpperCase();
+
+ float petXp = petInfoObject.get("exp").getAsFloat();
+
+ double petLevel = GuiProfileViewer.getPetLevel(name, rarityString, petXp).level;
+ int index = getClosestPetIndex(name, rarity, "", (float) petLevel);
+ if (index != config.selectedPet) {
+ clearPet();
+ setCurrentPet(index);
+ }
+ }
+ }
+ }
}
}
}
@@ -885,11 +791,14 @@ public class PetInfoOverlay extends TextOverlay {
if (!NotEnoughUpdates.INSTANCE.config.petOverlay.petOverlayIcon) return;
int mythicRarity = currentPet.rarity.petId;
- if (currentPet.rarity.petId == 5) {
- mythicRarity = 4;
- }
JsonObject petItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(
- currentPet.petType + ";" + mythicRarity);
+ currentPet.skin != null ? currentPet.skin : (currentPet.petType + ";" + mythicRarity));
+
+ if (petItem == null && currentPet.rarity.petId == 5) {
+ petItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(
+ currentPet.skin != null ? currentPet.skin : (currentPet.petType + ";" + 4));
+ }
+
if (petItem != null) {
Vector2f position = getPosition(overlayWidth, overlayHeight);
int x = (int) position.x;
@@ -907,7 +816,7 @@ public class PetInfoOverlay extends TextOverlay {
Pet currentPet2 = getCurrentPet2();
if (currentPet2 != null) {
JsonObject petItem2 = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(
- currentPet2.petType + ";" + currentPet2.rarity.petId);
+ currentPet2.skin != null ? currentPet2.skin : (currentPet2.petType + ";" + currentPet2.rarity.petId));
if (petItem2 != null) {
Vector2f position = getPosition(overlayWidth, overlayHeight);
int x = (int) position.x;
@@ -954,19 +863,19 @@ public class PetInfoOverlay extends TextOverlay {
"alchemy"
);
- public static void onStackClick(ItemStack stack, int windowId, int slotId, int mouseButtonClicked, int mode) {
- if (mode != 0) return;
- if (mouseButtonClicked != 0 && mouseButtonClicked != 1) return;
+ @SubscribeEvent
+ public void onStackClick(SlotClickEvent event) {
+ if (event.clickedButton != 0 && event.clickedButton != 1 && event.clickedButton != 2) return;
- int slotIdMod = (slotId - 10) % 9;
- if (slotId >= 10 && slotId <= 43 && slotIdMod >= 0 && slotIdMod <= 6 &&
+ int slotIdMod = (event.slotId - 10) % 9;
+ if (event.slotId >= 10 && event.slotId <= 43 && slotIdMod >= 0 && slotIdMod <= 6 &&
Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
ContainerChest container = (ContainerChest) chest.inventorySlots;
IInventory lower = container.getLowerChestInventory();
String containerName = lower.getDisplayName().getUnformattedText();
- if (lower.getSizeInventory() >= 54 && windowId == container.windowId) {
+ if (lower.getSizeInventory() >= 54 && event.guiContainer.inventorySlots.windowId == container.windowId) {
int page = 0;
boolean isPets = false;
@@ -988,7 +897,7 @@ public class PetInfoOverlay extends TextOverlay {
boolean isRemoving =
removingStack != null && removingStack.getItem() == Items.dye && removingStack.getItemDamage() == 10;
- int newSelected = (slotId - 10) - (slotId - 10) / 9 * 2 + page * 28;
+ int newSelected = (event.slotId - 10) - (event.slotId - 10) / 9 * 2 + page * 28;
lastPetSelect = System.currentTimeMillis();
@@ -1001,10 +910,11 @@ public class PetInfoOverlay extends TextOverlay {
} else {
setCurrentPet(newSelected);
- String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound());
- Pet pet = getPetFromStack(stack.getDisplayName(), lore);
- if (pet != null) {
- config.petMap.put(config.selectedPet, pet);
+ if (event.slot.getStack() != null && event.slot.getStack().getTagCompound() != null) {
+ Pet pet = getPetFromStack(event.slot.getStack().getTagCompound());
+ if (pet != null) {
+ config.petMap.put(config.selectedPet, pet);
+ }
}
}
}
@@ -1013,7 +923,7 @@ public class PetInfoOverlay extends TextOverlay {
}
public static float getXpGain(Pet pet, float xp, String xpType) {
- if (pet.petLevel.level >= 100) return 0;
+ if (pet.petLevel.level >= pet.petLevel.maxLevel) return 0;
if (validXpTypes == null)
validXpTypes = Lists.newArrayList("mining", "foraging", "enchanting", "farming", "combat", "fishing", "alchemy");
@@ -1047,8 +957,6 @@ public class PetInfoOverlay extends TextOverlay {
public void updatePetLevels() {
HashMap<String, XPInformation.SkillInfo> skillInfoMap = XPInformation.getInstance().getSkillInfoMap();
- long currentTime = System.currentTimeMillis();
-
float totalGain = 0;
Pet currentPet = getCurrentPet();
@@ -1062,7 +970,6 @@ public class PetInfoOverlay extends TextOverlay {
if (skillXpLast <= 0) {
skillInfoMapLast.put(entry.getKey(), skillXp);
} else if (skillXp > skillXpLast) {
- lastXpGain = currentTime;
float deltaXp = skillXp - skillXpLast;
@@ -1106,7 +1013,7 @@ public class PetInfoOverlay extends TextOverlay {
JsonObject petsJson = Constants.PETS;
if (currentPet != null && petsJson != null) {
currentPet.petLevel = GuiProfileViewer.getPetLevel(
- currentPet.petItem,
+ currentPet.petType,
currentPet.rarity.name(),
currentPet.petLevel.totalXp
);
@@ -1136,48 +1043,6 @@ public class PetInfoOverlay extends TextOverlay {
}
private int lastLevelHovered = 0;
- private String lastItemHovered = null;
-
- private static HashMap<String, String> itemMap = null;
-
- @SubscribeEvent(priority = EventPriority.HIGHEST, receiveCanceled = true)
- public void onTooltip(ItemTooltipEvent event) {
- for (String line : event.toolTip) {
- if (line.startsWith("\u00a7o\u00a77[Lvl ")) {
- lastItemHovered = null;
-
- String after = line.substring("\u00a7o\u00a77[Lvl ".length());
- if (after.contains("]")) {
- String levelStr = after.split("]")[0];
-
- try {
- lastLevelHovered = Integer.parseInt(levelStr.trim());
- } catch (Exception ignored) {
- }
- }
- } else if (line.startsWith("\u00a75\u00a7o\u00a76Held Item: ")) {
- String after = line.substring("\u00a75\u00a7o\u00a76Held Item: ".length());
-
- if (itemMap == null) {
- itemMap = new HashMap<>();
-
- for (Map.Entry<String, JsonObject> entry : NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .entrySet()) {
- if (entry.getKey().equals("ALL_SKILLS_SUPER_BOOST") ||
- XP_BOOST_PATTERN.matcher(entry.getKey()).matches()) {
- ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(entry.getValue());
- itemMap.put(stack.getDisplayName(), entry.getKey());
- }
- }
- }
-
- if (itemMap.containsKey(after)) {
- lastItemHovered = itemMap.get(after);
- }
- }
- }
- }
private static final Pattern AUTOPET_EQUIP = Pattern.compile(
"\u00a7cAutopet \u00a7eequipped your \u00a77\\[Lvl (\\d+)] \u00a7(.{2,})\u00a7e! \u00a7a\u00a7lVIEW RULE\u00a7r");
@@ -1185,18 +1050,12 @@ public class PetInfoOverlay extends TextOverlay {
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onChatReceived(ClientChatReceivedEvent event) {
NEUConfig config = NotEnoughUpdates.INSTANCE.config;
- if (NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() &&
- (config.petOverlay.enablePetInfo || config.itemOverlays.enableMonkeyCheck || config.petOverlay.petInvDisplay)) {
+ if (config.petOverlay.enablePetInfo || config.itemOverlays.enableMonkeyCheck || config.petOverlay.petInvDisplay) {
if (event.type == 0) {
String chatMessage = Utils.cleanColour(event.message.getUnformattedText());
Matcher autopetMatcher = AUTOPET_EQUIP.matcher(event.message.getFormattedText());
- if (event.message.getUnformattedText().startsWith("You summoned your") ||
- System.currentTimeMillis() - NEUOverlay.cachedPetTimer < 500) {
- NEUOverlay.cachedPetTimer = System.currentTimeMillis();
- NEUOverlay.shouldUseCachedPet = false;
- } else if (autopetMatcher.matches()) {
- NEUOverlay.shouldUseCachedPet = false;
+ if (autopetMatcher.matches()) {
try {
lastLevelHovered = Integer.parseInt(autopetMatcher.group(1));
} catch (NumberFormatException ignored) {
@@ -1223,9 +1082,13 @@ public class PetInfoOverlay extends TextOverlay {
setCurrentPet(getClosestPetIndex(pet, rarity.petId, "", lastLevelHovered));
if (PetInfoOverlay.config.selectedPet == -1) {
- Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
- EnumChatFormatting.RED + "[NEU] Can't find pet \u00a7" + petStringMatch +
- EnumChatFormatting.RED + " try revisiting all pages of /pets."));
+ setCurrentPet(getClosestPetIndex(pet, rarity.petId - 1, "", lastLevelHovered));
+ if (!"PET_ITEM_TIER_BOOST".equals(getCurrentPet().petItem)) {
+ PetInfoOverlay.config.selectedPet = -1;
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ EnumChatFormatting.RED + "[NEU] Can't find pet \u00a7" + petStringMatch +
+ EnumChatFormatting.RED + " try revisiting all pages of /pets."));
+ }
}
} else if ((chatMessage.toLowerCase().startsWith("you despawned your")) || (chatMessage.toLowerCase().contains(
"switching to profile"))
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java
new file mode 100644
index 00000000..975bbe6e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/PowerStoneStatsDisplay.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.inventory.Container;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+
+import java.text.NumberFormat;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+public class PowerStoneStatsDisplay {
+ private static PowerStoneStatsDisplay instance = null;
+ private final NumberFormat format = NumberFormat.getInstance(Locale.US);
+ private boolean dirty = true;
+
+ public static PowerStoneStatsDisplay getInstance() {
+ if (instance == null) {
+ instance = new PowerStoneStatsDisplay();
+ }
+ return instance;
+ }
+
+ @SubscribeEvent
+ public void onTick(TickEvent event) {
+ if (!dirty) return;
+
+ if (!Utils.getOpenChestName().equals("SkyBlock Menu")) {
+ dirty = false;
+ return;
+ }
+
+ EntityPlayerSP p = Minecraft.getMinecraft().thePlayer;
+ Container openContainer = p.openContainer;
+ for (Slot slot : openContainer.inventorySlots) {
+ ItemStack stack = slot.getStack();
+ if (stack == null) continue;
+
+ String displayName = stack.getDisplayName();
+ if (!"§aAccessory Bag".equals(displayName)) continue;
+
+ for (String line : ItemUtils.getLore(stack)) {
+ if (line.startsWith("§7Magical Power: ")) {
+ String rawNumber = line.split("§6")[1].replace(",", "");
+ NEUConfig.HiddenProfileSpecific configProfileSpecific = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
+ if (configProfileSpecific == null) return;
+ configProfileSpecific.magicalPower = Integer.parseInt(rawNumber);
+ dirty = false;
+ }
+ }
+ }
+ }
+
+ @SubscribeEvent
+ public void onGuiOpen(GuiOpenEvent event) {
+ if (event.gui != null) {
+ dirty = true;
+ }
+ }
+
+ @SubscribeEvent
+ public void onItemTooltipLow(ItemTooltipEvent event) {
+ if (!NotEnoughUpdates.INSTANCE.config.tooltipTweaks.powerStoneStats) return;
+
+ ItemStack itemStack = event.itemStack;
+ if (itemStack == null) return;
+ List<String> lore = ItemUtils.getLore(itemStack);
+
+ boolean isPowerStone = false;
+ for (String line : lore) {
+ if (line.equals("§8Power Stone")) {
+ isPowerStone = true;
+ break;
+ }
+ }
+
+ if (!isPowerStone) return;
+
+ NEUConfig.HiddenProfileSpecific configProfileSpecific = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
+ if (configProfileSpecific == null) return;
+
+ int magicalPower = configProfileSpecific.magicalPower;
+ if (magicalPower < 1) return;
+
+ double scaledMagicalPower = scalePower(magicalPower);
+ double scaledCurrentPower = 0.0;
+
+ int index = 0;
+ boolean foundMagicalPower = false;
+ for (String line : new LinkedList<>(lore)) {
+ index++;
+ line = line.replace("§k", "");
+
+ if (line.startsWith("§7At ")) {
+
+ String rawNumber = StringUtils.substringBetween(StringUtils.cleanColour(line), "At ", " Magical");
+ if (rawNumber == null) return;
+
+ //This ignores old repo entries in the item browser from neu
+ if (rawNumber.equals("mmm")) return;
+
+ try {
+ scaledCurrentPower = scalePower(StringUtils.cleanAndParseInt(rawNumber));
+ } catch (NumberFormatException ignored) {
+ return;
+ }
+
+ event.toolTip.set(index, "§7At §6" + format.format((double) magicalPower) + " Magical Power§7:");
+ foundMagicalPower = true;
+ continue;
+ }
+
+ if (!foundMagicalPower) continue;
+
+ String cleanLine = StringUtils.cleanColour(line);
+ if (cleanLine.equals("")) {
+ break;
+ }
+
+ for (String operator : new String[]{"+", "-"}) {
+ if (!cleanLine.startsWith(operator)) continue;
+ String rawStat = StringUtils.cleanColour(StringUtils.substringBetween(line, operator, " "));
+
+ double currentStat;
+ try {
+ currentStat = 0.0 + StringUtils.cleanAndParseInt(rawStat.substring(0, rawStat.length() - 1));
+ } catch (NumberFormatException ignored) {
+ continue;
+ }
+ double realStat = (currentStat / scaledCurrentPower) * scaledMagicalPower;
+
+ String format = this.format.format((double) Math.round(realStat));
+ format += rawStat.substring(rawStat.length() - 1);
+
+ event.toolTip.set(index, line.replace(rawStat, format));
+ }
+ }
+ }
+
+ private double scalePower(int magicalPower) {
+ return Math.pow(29.97 * (Math.log(0.0019 * magicalPower + 1)), 1.2);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SlotLocking.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SlotLocking.java
index 743625f5..8a487739 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SlotLocking.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SlotLocking.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import com.google.gson.Gson;
@@ -5,6 +24,8 @@ import com.google.gson.GsonBuilder;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.config.KeybindHelper;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
@@ -23,16 +44,20 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import org.apache.commons.lang3.tuple.Triple;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
-import java.util.function.Consumer;
public class SlotLocking {
private static final SlotLocking INSTANCE = new SlotLocking();
@@ -200,7 +225,7 @@ public class SlotLocking {
int mouseX = Mouse.getX() * scaledWidth / Minecraft.getMinecraft().displayWidth;
int mouseY = scaledHeight - Mouse.getY() * scaledHeight / Minecraft.getMinecraft().displayHeight - 1;
- Slot slot = container.getSlotAtPosition(mouseX, mouseY);
+ Slot slot = ((AccessorGuiContainer) container).doGetSlotAtPosition(mouseX, mouseY);
if (slot != null && slot.getSlotIndex() != 8 && slot.inventory == Minecraft.getMinecraft().thePlayer.inventory) {
int slotNum = slot.getSlotIndex();
if (slotNum >= 0 && slotNum <= 39) {
@@ -280,7 +305,7 @@ public class SlotLocking {
int mouseX = Mouse.getX() * scaledWidth / Minecraft.getMinecraft().displayWidth;
int mouseY = scaledHeight - Mouse.getY() * scaledHeight / Minecraft.getMinecraft().displayHeight - 1;
- Slot slot = container.getSlotAtPosition(mouseX, mouseY);
+ Slot slot = ((AccessorGuiContainer) container).doGetSlotAtPosition(mouseX, mouseY);
if (slot != null && slot.getSlotIndex() != 8 && slot.inventory == Minecraft.getMinecraft().thePlayer.inventory) {
int slotNum = slot.getSlotIndex();
if (slotNum >= 0 && slotNum <= 39) {
@@ -378,10 +403,10 @@ public class SlotLocking {
if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) {
return;
}
- GuiContainer container = (GuiContainer) Minecraft.getMinecraft().currentScreen;
+ AccessorGuiContainer container = (AccessorGuiContainer) Minecraft.getMinecraft().currentScreen;
- int x1 = container.guiLeft + pairingSlot.xDisplayPosition + 8;
- int y1 = container.guiTop + pairingSlot.yDisplayPosition + 8;
+ int x1 = container.getGuiLeft() + pairingSlot.xDisplayPosition + 8;
+ int y1 = container.getGuiTop() + pairingSlot.yDisplayPosition + 8;
int x2 = event.mouseX;
int y2 = event.mouseY;
@@ -429,22 +454,21 @@ public class SlotLocking {
}
}
- public void onWindowClick(
- Slot slotIn,
- int slotId,
- int clickedButton,
- int clickType,
- Consumer<Triple<Integer, Integer, Integer>> consumer
- ) {
- LockedSlot locked = getLockedSlot(slotIn);
+ @SubscribeEvent
+ public void onWindowClick(SlotClickEvent slotClickEvent) {
+ LockedSlot locked = getLockedSlot(slotClickEvent.slot);
if (locked == null) {
return;
- } else if (locked.locked || (clickType == 2 && SlotLocking.getInstance().isSlotIndexLocked(clickedButton))) {
- consumer.accept(null);
- } else if (NotEnoughUpdates.INSTANCE.config.slotLocking.enableSlotBinding && clickType == 1 &&
+ }
+ if (locked.locked ||
+ (slotClickEvent.clickType == 2 && SlotLocking.getInstance().isSlotIndexLocked(slotClickEvent.clickedButton))) {
+ slotClickEvent.setCanceled(true);
+ return;
+ }
+ if (NotEnoughUpdates.INSTANCE.config.slotLocking.enableSlotBinding
+ && slotClickEvent.clickType == 1 &&
locked.boundTo != -1) {
- GuiContainer container = (GuiContainer) Minecraft.getMinecraft().currentScreen;
- Slot boundSlot = container.inventorySlots.getSlotFromInventory(
+ Slot boundSlot = slotClickEvent.guiContainer.inventorySlots.getSlotFromInventory(
Minecraft.getMinecraft().thePlayer.inventory,
locked.boundTo
);
@@ -455,29 +479,41 @@ public class SlotLocking {
LockedSlot boundLocked = getLockedSlot(boundSlot);
- int id = slotIn.getSlotIndex();
- if (id >= 9 && locked.boundTo >= 0 && locked.boundTo < 8) {
- if (!boundLocked.locked) {
- consumer.accept(Triple.of(slotId, locked.boundTo, 2));
- if (boundLocked == DEFAULT_LOCKED_SLOT) {
- LockedSlot[] lockedSlots = getDataForProfile();
- lockedSlots[locked.boundTo] = new LockedSlot();
- lockedSlots[locked.boundTo].boundTo = id;
- } else {
- boundLocked.boundTo = id;
- }
+ int from, to;
+ int id = slotClickEvent.slot.getSlotIndex();
+ if (id >= 9 && 0 <= locked.boundTo && locked.boundTo < 8 && !boundLocked.locked) {
+ from = id;
+ to = locked.boundTo;
+ if (boundLocked == DEFAULT_LOCKED_SLOT) {
+ LockedSlot[] lockedSlots = getDataForProfile();
+ lockedSlots[locked.boundTo] = new LockedSlot();
+ lockedSlots[locked.boundTo].boundTo = id;
+ } else {
+ boundLocked.boundTo = id;
}
- } else if (id >= 0 && id < 8 && locked.boundTo >= 9 && locked.boundTo <= 39) {
+ } else if (0 <= id && id < 8 && locked.boundTo >= 9 && locked.boundTo <= 39) {
if (boundLocked.locked || boundLocked.boundTo != id) {
locked.boundTo = -1;
+ return;
} else {
- int boundTo = boundSlot.slotNumber;
- consumer.accept(Triple.of(boundTo, id, 2));
+ from = boundSlot.slotNumber;
+ to = id;
}
+ } else {
+ return;
}
+ if (from == 39) from = 5;
+ if (from == 38) from = 6;
+ if (from == 37) from = 7;
+ if (from == 36) from = 8;
+ Minecraft.getMinecraft().playerController.windowClick(
+ slotClickEvent.guiContainer.inventorySlots.windowId,
+ from, to, 2, Minecraft.getMinecraft().thePlayer
+ );
+ slotClickEvent.setCanceled(true);
} else if (NotEnoughUpdates.INSTANCE.config.slotLocking.enableSlotBinding && locked.boundTo != -1 &&
NotEnoughUpdates.INSTANCE.config.slotLocking.bindingAlsoLocks) {
- consumer.accept(null);
+ slotClickEvent.setCanceled(true);
}
}
@@ -514,7 +550,7 @@ public class SlotLocking {
return;
}
- boolean hoverOverSlot = container.isMouseOverSlot(slot, mouseX, mouseY);
+ boolean hoverOverSlot = ((AccessorGuiContainer) container).doIsMouseOverSlot(slot, mouseX, mouseY);
if (hoverOverSlot || slot.getSlotIndex() >= 9) {
Minecraft.getMinecraft().getTextureManager().bindTexture(BOUND);
@@ -545,8 +581,8 @@ public class SlotLocking {
);
}
} else if (pairingSlot != null && lockKeyHeld && slot.getSlotIndex() < 8) {
- int x1 = container.guiLeft + pairingSlot.xDisplayPosition;
- int y1 = container.guiTop + pairingSlot.yDisplayPosition;
+ int x1 = ((AccessorGuiContainer) container).getGuiLeft() + pairingSlot.xDisplayPosition;
+ int y1 = ((AccessorGuiContainer) container).getGuiTop() + pairingSlot.yDisplayPosition;
if (mouseX <= x1 || mouseX >= x1 + 16 ||
mouseY <= y1 || mouseY >= y1 + 16) {
@@ -634,8 +670,8 @@ public class SlotLocking {
int mouseX = Mouse.getX() * scaledWidth / Minecraft.getMinecraft().displayWidth;
int mouseY = scaledHeight - Mouse.getY() * scaledHeight / Minecraft.getMinecraft().displayHeight - 1;
- int x1 = container.guiLeft + pairingSlot.xDisplayPosition;
- int y1 = container.guiTop + pairingSlot.yDisplayPosition;
+ int x1 = ((AccessorGuiContainer) container).getGuiLeft() + pairingSlot.xDisplayPosition;
+ int y1 = ((AccessorGuiContainer) container).getGuiTop() + pairingSlot.yDisplayPosition;
if (mouseX <= x1 || mouseX >= x1 + 16 ||
mouseY <= y1 || mouseY >= y1 + 16) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java
index 94aee789..bef07399 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StorageManager.java
@@ -1,6 +1,35 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay;
import io.github.moulberry.notenoughupdates.util.SBInfo;
@@ -9,18 +38,38 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.*;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTBase;
+import net.minecraft.nbt.NBTException;
+import net.minecraft.nbt.NBTTagByte;
+import net.minecraft.nbt.NBTTagByteArray;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagDouble;
+import net.minecraft.nbt.NBTTagFloat;
+import net.minecraft.nbt.NBTTagInt;
+import net.minecraft.nbt.NBTTagIntArray;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTTagLong;
+import net.minecraft.nbt.NBTTagShort;
+import net.minecraft.nbt.NBTTagString;
import net.minecraft.network.play.client.C0EPacketClickWindow;
import net.minecraft.network.play.server.S2DPacketOpenWindow;
import net.minecraft.network.play.server.S2EPacketCloseWindow;
import net.minecraft.network.play.server.S2FPacketSetSlot;
import net.minecraft.network.play.server.S30PacketWindowItems;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
@@ -35,11 +84,12 @@ public class StorageManager {
private static final StorageManager INSTANCE = new StorageManager();
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(ItemStack.class, new ItemStackSerializer())
- .registerTypeAdapter(ItemStack.class, new ItemStackDeserilizer()).create();
+ .registerTypeAdapter(ItemStack.class, new ItemStackDeserializer()).create();
public static class ItemStackSerializer implements JsonSerializer<ItemStack> {
@Override
public JsonElement serialize(ItemStack src, Type typeOfSrc, JsonSerializationContext context) {
+ fixPetInfo(src);
NBTTagCompound tag = src.serializeNBT();
return nbtToJson(tag);
}
@@ -47,7 +97,7 @@ public class StorageManager {
private static final Pattern JSON_FIX_REGEX = Pattern.compile("\"([^,:]+)\":");
- public static class ItemStackDeserilizer implements JsonDeserializer<ItemStack> {
+ public static class ItemStackDeserializer implements JsonDeserializer<ItemStack> {
@Override
public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
@@ -87,6 +137,63 @@ public class StorageManager {
return (JsonObject) loadJson(NBTTagCompound);
}
+ private static class PetInfo {
+ String type;
+ Boolean active;
+ Double exp;
+ String tier;
+ Boolean hideInfo;
+ Integer candyUsed;
+ String uuid;
+ Boolean hideRightClick;
+ String heldItem;
+ String skin;
+
+ private <T> void appendIfNotNull(StringBuilder builder, String key, T value) {
+ if (value != null) {
+ if (builder.indexOf("{") != builder.length()-1) {
+ builder.append(",");
+ }
+ builder.append(key).append(":");
+ if (value instanceof String) {
+ builder.append("\"").append(value).append("\"");
+ } else {
+ builder.append(value);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder object = new StringBuilder();
+ object.append("{");
+ appendIfNotNull(object, "type", type);
+ appendIfNotNull(object, "active", active);
+ appendIfNotNull(object, "exp", exp);
+ appendIfNotNull(object, "tier", tier);
+ appendIfNotNull(object, "hideInfo", hideInfo);
+ appendIfNotNull(object, "candyUsed", candyUsed);
+ appendIfNotNull(object, "uuid", uuid);
+ appendIfNotNull(object, "hideRightClick", hideRightClick);
+ appendIfNotNull(object, "heldItem", heldItem);
+ appendIfNotNull(object, "skin", skin);
+ object.append("}");
+ return object.toString();
+ }
+ }
+
+ private static void fixPetInfo(ItemStack src) {
+ if (src.getTagCompound() == null || !src.getTagCompound().hasKey("ExtraAttributes") || !src.getTagCompound().getCompoundTag("ExtraAttributes").hasKey("petInfo")) return;
+ PetInfo oldPetInfo = GSON.fromJson(src.getTagCompound().getCompoundTag("ExtraAttributes").getString("petInfo"), PetInfo.class);
+ src.getTagCompound().getCompoundTag("ExtraAttributes").removeTag("petInfo");
+ try {
+ src.getTagCompound().getCompoundTag("ExtraAttributes").setTag(
+ "petInfo",
+ JsonToNBT.getTagFromJson(oldPetInfo.toString())
+ );
+ } catch (NBTException | NullPointerException ignored) {}
+ }
+
private static JsonElement loadJson(NBTBase tag) {
if (tag instanceof NBTTagCompound) {
NBTTagCompound compoundTag = (NBTTagCompound) tag;
@@ -187,7 +294,7 @@ public class StorageManager {
private boolean shouldRenderStorageOverlayCached = false;
- private static final Pattern WINDOW_REGEX = Pattern.compile(".+ Backpack (?:\u2726 )?\\((\\d+)/(\\d+)\\)");
+ private static final Pattern WINDOW_REGEX = Pattern.compile(".+ Backpack (?:✦ )?\\(Slot #(\\d+)\\)");
private static final Pattern ECHEST_WINDOW_REGEX = Pattern.compile("Ender Chest \\((\\d+)/(\\d+)\\)");
public void loadConfig(File file) {
@@ -508,8 +615,8 @@ public class StorageManager {
int index = slot - 9;
boolean changed = false;
- if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) &&
- stack.getMetadata() == 14) {
+ if ((stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) &&
+ stack.getMetadata() == 14) || (stack.getItem() == Items.dye && stack.getMetadata() == 8)) {
if (storagePresent[index]) changed = true;
storagePresent[index] = false;
removePage(index);
@@ -549,7 +656,8 @@ public class StorageManager {
boolean changed = false;
- if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ if (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)
+ || (stack.getItem() == Items.dye && stack.getMetadata() == 8)) {
if (storagePresent[index]) changed = true;
storagePresent[index] = false;
removePage(index);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StreamerMode.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StreamerMode.java
index 064f41ca..a2951e56 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StreamerMode.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/StreamerMode.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.util.Utils;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SunTzu.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SunTzu.java
index 27cf42ac..7fc8beba 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SunTzu.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/SunTzu.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures;
import io.github.moulberry.notenoughupdates.util.Utils;
@@ -37,7 +56,8 @@ public class SunTzu {
"The wise warrior avoids the battle.",
"Great results, can be achieved with small forces.",
"Attack is the secret of defense; defense is the planning of an attack.",
- "Subscribe to Moulberry on YouTube."
+ "Subscribe to Moulberry on YouTube.",
+ "Technoblade never dies!"
};
public static void setEnabled(boolean enabled) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CrystalHollowsTextures.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CrystalHollowsTextures.java
index 36858276..7d23d922 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CrystalHollowsTextures.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CrystalHollowsTextures.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import net.minecraft.util.BlockPos;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBiomes.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBiomes.java
index 9a6f9cac..48a01187 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBiomes.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBiomes.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBlockSounds.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBlockSounds.java
index dec011d3..2a3e9ec4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBlockSounds.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/CustomBlockSounds.java
@@ -1,8 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.PositionedSoundRecord;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/DwarvenMinesTextures.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/DwarvenMinesTextures.java
index faf7eabe..1c6acc1d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/DwarvenMinesTextures.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/DwarvenMinesTextures.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import com.google.gson.JsonArray;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/IslandZoneSubdivider.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/IslandZoneSubdivider.java
index 8b00bc85..75ff566f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/IslandZoneSubdivider.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/IslandZoneSubdivider.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import net.minecraft.util.BlockPos;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/LocationChangeEvent.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/LocationChangeEvent.java
index c6f5e9c0..5a87af11 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/LocationChangeEvent.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/LocationChangeEvent.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import net.minecraftforge.fml.common.eventhandler.Event;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/SpecialBlockZone.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/SpecialBlockZone.java
index f4e8f1fc..e88e2c25 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/SpecialBlockZone.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/customblockzones/SpecialBlockZone.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscfeatures.customblockzones;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java
new file mode 100644
index 00000000..963fa793
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/AgeModifier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.mixins.AccessorEntityAgeable;
+import io.github.moulberry.notenoughupdates.mixins.AccessorEntityArmorStand;
+import net.minecraft.entity.EntityAgeable;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.entity.monster.EntityZombie;
+
+public class AgeModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ boolean baby = info.has("baby") && info.get("baby").getAsBoolean();
+ if (base instanceof EntityAgeable) {
+ ((AccessorEntityAgeable) base).setGrowingAgeDirect(baby ? -1 : 1);
+ return base;
+ }
+ if (base instanceof EntityZombie) {
+ ((EntityZombie) base).setChild(baby);
+ return base;
+ }
+ if (base instanceof EntityArmorStand) {
+ ((AccessorEntityArmorStand) base).setSmallDirect(baby);
+ return base;
+ }
+ System.out.println("Cannot apply age to a non ageable entity: " + base);
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java
new file mode 100644
index 00000000..5f452132
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/ChargedModifier.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.monster.EntityCreeper;
+
+public class ChargedModifier extends EntityViewerModifier {
+
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (base instanceof EntityCreeper) {
+ base.getDataWatcher().updateObject(17, (byte) 1);
+ return base;
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java
new file mode 100644
index 00000000..367d62d3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewer.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.inventory.GuiInventory;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.boss.EntityDragon;
+import net.minecraft.entity.boss.EntityWither;
+import net.minecraft.entity.item.EntityArmorStand;
+import net.minecraft.entity.monster.EntityBlaze;
+import net.minecraft.entity.monster.EntityCaveSpider;
+import net.minecraft.entity.monster.EntityCreeper;
+import net.minecraft.entity.monster.EntityEnderman;
+import net.minecraft.entity.monster.EntityEndermite;
+import net.minecraft.entity.monster.EntityGhast;
+import net.minecraft.entity.monster.EntityGuardian;
+import net.minecraft.entity.monster.EntityIronGolem;
+import net.minecraft.entity.monster.EntityMagmaCube;
+import net.minecraft.entity.monster.EntityPigZombie;
+import net.minecraft.entity.monster.EntitySilverfish;
+import net.minecraft.entity.monster.EntitySkeleton;
+import net.minecraft.entity.monster.EntitySlime;
+import net.minecraft.entity.monster.EntitySnowman;
+import net.minecraft.entity.monster.EntitySpider;
+import net.minecraft.entity.monster.EntityWitch;
+import net.minecraft.entity.monster.EntityZombie;
+import net.minecraft.entity.passive.EntityBat;
+import net.minecraft.entity.passive.EntityChicken;
+import net.minecraft.entity.passive.EntityCow;
+import net.minecraft.entity.passive.EntityHorse;
+import net.minecraft.entity.passive.EntityMooshroom;
+import net.minecraft.entity.passive.EntityOcelot;
+import net.minecraft.entity.passive.EntityPig;
+import net.minecraft.entity.passive.EntityRabbit;
+import net.minecraft.entity.passive.EntitySheep;
+import net.minecraft.entity.passive.EntitySquid;
+import net.minecraft.entity.passive.EntityVillager;
+import net.minecraft.entity.passive.EntityWolf;
+import net.minecraft.util.ResourceLocation;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+public class EntityViewer extends GuiScreen {
+
+ public static Map<String, Supplier<? extends EntityLivingBase>> validEntities =
+ new HashMap<String, Supplier<? extends EntityLivingBase>>() {{
+ put("Zombie", () -> new EntityZombie(null));
+ put("Chicken", () -> new EntityChicken(null));
+ put("Slime", () -> new EntitySlime(null));
+ put("Wolf", () -> new EntityWolf(null));
+ put("Skeleton", () -> new EntitySkeleton(null));
+ put("Creeper", () -> new EntityCreeper(null));
+ put("Ocelot", () -> new EntityOcelot(null));
+ put("Blaze", () -> new EntityBlaze(null));
+ put("Rabbit", () -> new EntityRabbit(null));
+ put("Sheep", () -> new EntitySheep(null));
+ put("Horse", () -> new EntityHorse(null));
+ put("Eisengolem", () -> new EntityIronGolem(null));
+ put("Silverfish", () -> new EntitySilverfish(null));
+ put("Witch", () -> new EntityWitch(null));
+ put("Endermite", () -> new EntityEndermite(null));
+ put("Snowman", () -> new EntitySnowman(null));
+ put("Villager", () -> new EntityVillager(null));
+ put("Guardian", () -> new EntityGuardian(null));
+ put("ArmorStand", () -> new EntityArmorStand(null));
+ put("Squid", () -> new EntitySquid(null));
+ put("Bat", () -> new EntityBat(null));
+ put("Spider", () -> new EntitySpider(null));
+ put("CaveSpider", () -> new EntityCaveSpider(null));
+ put("Pigman", () -> new EntityPigZombie(null));
+ put("Ghast", () -> new EntityGhast(null));
+ put("MagmaCube", () -> new EntityMagmaCube(null));
+ put("Wither", () -> new EntityWither(null));
+ put("Enderman", () -> new EntityEnderman(null));
+ put("Mooshroom", () -> new EntityMooshroom(null));
+ put("WitherSkeleton", () -> {
+ EntitySkeleton skeleton = new EntitySkeleton(null);
+ skeleton.setSkeletonType(1);
+ return skeleton;
+ });
+ put("Cow", () -> new EntityCow(null));
+ put("Dragon", () -> new EntityDragon(null));
+ put("Player", () -> new GUIClientPlayer());
+ put("Pig", () -> new EntityPig(null));
+ }};
+
+ public static Map<String, EntityViewerModifier> validModifiers = new HashMap<String, EntityViewerModifier>() {{
+ put("playerdata", new SkinModifier());
+ put("equipment", new EquipmentModifier());
+ put("riding", new RidingModifier());
+ put("charged", new ChargedModifier());
+ put("witherdata", new WitherModifier());
+ put("invisible", new InvisibleModifier());
+ put("age", new AgeModifier());
+ put("horse", new HorseModifier());
+ put("name", new NameModifier());
+ }};
+
+ public int guiLeft = 0;
+ public int guiTop = 0;
+ public int xSize = 176;
+ public int ySize = 166;
+
+ private final String label;
+ private final EntityLivingBase entity;
+ private static final ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/entity_viewer.png"
+ );
+
+ public EntityViewer(String label, EntityLivingBase entity) {
+ this.label = label;
+ this.entity = entity;
+ }
+
+ public static EntityLivingBase constructEntity(ResourceLocation resourceLocation) {
+ Gson gson = NotEnoughUpdates.INSTANCE.manager.gson;
+ try (
+ Reader is = new InputStreamReader(
+ Minecraft.getMinecraft().getResourceManager().getResource(resourceLocation).getInputStream(),
+ StandardCharsets.UTF_8
+ )
+ ) {
+ return constructEntity(gson.fromJson(is, JsonObject.class));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static EntityLivingBase constructEntity(JsonObject info) {
+ List<JsonObject> modifiers = info.has("modifiers") ?
+ StreamSupport.stream(info.get("modifiers").getAsJsonArray().spliterator(), false)
+ .map(JsonElement::getAsJsonObject).collect(Collectors.toList())
+ : Collections.emptyList();
+ return EntityViewer.constructEntity(info.get("entity").getAsString(), modifiers);
+ }
+
+ public static EntityLivingBase constructEntity(String string, String[] modifiers) {
+ Gson gson = NotEnoughUpdates.INSTANCE.manager.gson;
+ return constructEntity(
+ string,
+ Arrays.stream(modifiers).map(it -> gson.fromJson(it, JsonObject.class)).collect(Collectors.toList())
+ );
+ }
+
+ public static EntityLivingBase constructEntity(String string, List<JsonObject> modifiers) {
+ Supplier<? extends EntityLivingBase> aClass = validEntities.get(string);
+ if (aClass == null) {
+ System.err.println("Could not find entity of type: " + string);
+ return null;
+ }
+ try {
+ EntityLivingBase entity = aClass.get();
+ for (JsonObject modifier : modifiers) {
+ String type = modifier.get("type").getAsString();
+ EntityViewerModifier entityViewerModifier = validModifiers.get(type);
+ entity = entityViewerModifier.applyModifier(entity, modifier);
+ if (entity == null) break;
+ }
+ return entity;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ drawDefaultBackground();
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+
+ this.guiLeft = (width - this.xSize) / 2;
+ this.guiTop = (height - this.ySize) / 2;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ drawTexturedModalRect(guiLeft, guiTop, 0, 0, this.xSize, this.ySize);
+
+ Utils.drawStringScaledMaxWidth(label, fontRenderer, guiLeft + 10, guiTop + 10, false, 100, 0xFF00FF);
+ renderEntity(entity, guiLeft + 90, guiTop + 75, mouseX, mouseY);
+ }
+
+ public static void renderEntity(EntityLivingBase entity, int posX, int posY, int mouseX, int mouseY) {
+ GlStateManager.color(1F, 1F, 1F, 1F);
+
+ int scale = 30;
+ float bottomOffset = 0F;
+ EntityLivingBase stack = entity;
+ while (true) {
+
+ stack.ticksExisted = Minecraft.getMinecraft().thePlayer.ticksExisted;
+ GuiInventory.drawEntityOnScreen(
+ posX,
+ (int) (posY - bottomOffset * scale),
+ scale,
+ posX - mouseX,
+ (int) (posY - stack.getEyeHeight() * scale - mouseY),
+ stack
+ );
+ bottomOffset += stack.getMountedYOffset();
+ if (!(stack.riddenByEntity instanceof EntityLivingBase)) {
+ break;
+ }
+ stack = (EntityLivingBase) stack.riddenByEntity;
+ }
+
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java
new file mode 100644
index 00000000..aa6d22c9
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EntityViewerModifier.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public abstract class EntityViewerModifier {
+ public abstract EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info);
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java
new file mode 100644
index 00000000..685e161a
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/EquipmentModifier.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemArmor;
+import net.minecraft.item.ItemStack;
+
+public class EquipmentModifier extends EntityViewerModifier {
+
+ private ItemStack createItem(String item) {
+ NEUManager manager = NotEnoughUpdates.INSTANCE.manager;
+ String[] split = item.split("#");
+ if (split.length == 2) {
+ switch (split[0].intern()) {
+ case "LEATHER_LEGGINGS":
+ return coloredLeatherArmor(Items.leather_leggings, split[1]);
+ case "LEATHER_HELMET":
+ return coloredLeatherArmor(Items.leather_helmet, split[1]);
+ case "LEATHER_CHESTPLATE":
+ return coloredLeatherArmor(Items.leather_chestplate, split[1]);
+ case "LEATHER_BOOTS":
+ return coloredLeatherArmor(Items.leather_boots, split[1]);
+ default:
+ throw new RuntimeException("Unknown leather piece: " + item);
+ }
+ }
+ return manager.createItem(item);
+ }
+
+ private ItemStack coloredLeatherArmor(ItemArmor item, String colorHex) {
+ ItemStack is = new ItemStack(item);
+ item.setColor(is, Integer.parseInt(colorHex, 16));
+ return is;
+ }
+
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (info.has("hand"))
+ setCurrentItemOrArmor(base, 0, createItem(info.get("hand").getAsString()));
+ if (info.has("helmet"))
+ setCurrentItemOrArmor(base, 4, createItem(info.get("helmet").getAsString()));
+ if (info.has("chestplate"))
+ setCurrentItemOrArmor(base, 3, createItem(info.get("chestplate").getAsString()));
+ if (info.has("leggings"))
+ setCurrentItemOrArmor(base, 2, createItem(info.get("leggings").getAsString()));
+ if (info.has("feet"))
+ setCurrentItemOrArmor(base, 1, createItem(info.get("feet").getAsString()));
+ return base;
+ }
+
+ public void setCurrentItemOrArmor(EntityLivingBase entity, int slot, ItemStack itemStack) {
+ if (entity instanceof EntityPlayer) {
+ setPlayerCurrentItemOrArmor((EntityPlayer) entity, slot, itemStack);
+ } else {
+ entity.setCurrentItemOrArmor(slot, itemStack);
+ }
+ }
+
+ // Biscuit person needs to learn how to code and not fuck up valid vanilla behaviour
+ public static void setPlayerCurrentItemOrArmor(EntityPlayer player, int slot, ItemStack itemStack) {
+ if (slot == 0) {
+ player.inventory.mainInventory[player.inventory.currentItem] = itemStack;
+ } else {
+ player.inventory.armorInventory[slot - 1] = itemStack;
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java
new file mode 100644
index 00000000..8cdf2ef0
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/GUIClientPlayer.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.mojang.authlib.GameProfile;
+import net.minecraft.client.entity.AbstractClientPlayer;
+import net.minecraft.client.network.NetworkPlayerInfo;
+import net.minecraft.client.resources.DefaultPlayerSkin;
+import net.minecraft.util.ResourceLocation;
+
+import java.util.UUID;
+
+public class GUIClientPlayer extends AbstractClientPlayer {
+ public GUIClientPlayer() {
+ super(null, new GameProfile(UUID.randomUUID(), "GuiPlayer"));
+ }
+
+ ResourceLocation overrideSkin = DefaultPlayerSkin.getDefaultSkinLegacy();
+ ResourceLocation overrideCape = null;
+ boolean overrideIsSlim = false;
+ NetworkPlayerInfo playerInfo = new NetworkPlayerInfo(this.getGameProfile()) {
+ @Override
+ public String getSkinType() {
+ return overrideIsSlim ? "slim" : "default";
+ }
+
+ @Override
+ public ResourceLocation getLocationSkin() {
+ return overrideSkin;
+ }
+
+ @Override
+ public ResourceLocation getLocationCape() {
+ return overrideCape;
+ }
+ };
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ public String name;
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ protected NetworkPlayerInfo getPlayerInfo() {
+ return playerInfo;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java
new file mode 100644
index 00000000..b29152bf
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/HorseModifier.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.passive.EntityHorse;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+
+public class HorseModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (!(base instanceof EntityHorse))
+ return null;
+ EntityHorse horse = (EntityHorse) base;
+ if (info.has("kind")) {
+ String type = info.get("kind").getAsString().intern();
+ switch (type) {
+ case "skeleton":
+ horse.setHorseType(4);
+ break;
+ case "zombie":
+ horse.setHorseType(3);
+ break;
+ case "mule":
+ horse.setHorseType(2);
+ break;
+ case "donkey":
+ horse.setHorseType(1);
+ break;
+ case "horse":
+ horse.setHorseType(0);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown horse type: " + type);
+ }
+ }
+ if (info.has("armor")) {
+ JsonElement el = info.get("armor");
+ if (el.isJsonNull()) {
+ horse.setHorseArmorStack(null);
+ } else {
+ Item item;
+ switch (el.getAsString().intern()) {
+ case "iron":
+ item = Items.iron_horse_armor;
+ break;
+ case "golden":
+ item = Items.golden_horse_armor;
+ break;
+ case "diamond":
+ item = Items.diamond_horse_armor;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown horse armor: " + el.getAsString());
+ }
+ horse.setHorseArmorStack(new ItemStack(item));
+ }
+ }
+ if (info.has("saddled")) {
+ horse.setHorseSaddled(info.get("saddled").getAsBoolean());
+ }
+ return horse;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java
new file mode 100644
index 00000000..74535ce9
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/InvisibleModifier.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public class InvisibleModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ base.setInvisible(!info.has("invisible") || info.get("invisible").getAsBoolean());
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/NameModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/NameModifier.java
new file mode 100644
index 00000000..c0fd23bd
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/NameModifier.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public class NameModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (base instanceof GUIClientPlayer) {
+ ((GUIClientPlayer) base).setName(info.get("name").getAsString());
+ }
+ base.setCustomNameTag(info.get("name").getAsString());
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java
new file mode 100644
index 00000000..72dd8b73
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/RidingModifier.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+
+public class RidingModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ EntityLivingBase newEntity = EntityViewer.constructEntity(info);
+ if (newEntity == null) return null;
+ newEntity.mountEntity(base);
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java
new file mode 100644
index 00000000..076e8417
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/SkinModifier.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EnumPlayerModelParts;
+import net.minecraft.util.ResourceLocation;
+
+import java.util.Map;
+
+public class SkinModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (base instanceof GUIClientPlayer) {
+ GUIClientPlayer player = (GUIClientPlayer) base;
+ if (info.has("cape")) {
+ player.overrideCape = new ResourceLocation(info.get("cape").getAsString());
+ }
+ if (info.has("skin")) {
+ player.overrideSkin = new ResourceLocation(info.get("skin").getAsString());
+ }
+ if (info.has("slim")) {
+ player.overrideIsSlim = info.get("slim").getAsBoolean();
+ }
+ if (info.has("parts")) {
+ JsonElement parts = info.get("parts");
+ byte partBitField = player.getDataWatcher().getWatchableObjectByte(10);
+ if (parts.isJsonPrimitive() && parts.getAsJsonPrimitive().isBoolean()) {
+ partBitField = parts.getAsBoolean() ? (byte) -1 : 0;
+ } else {
+ JsonObject obj = parts.getAsJsonObject();
+ for (Map.Entry<String, JsonElement> part : obj.entrySet()) {
+ EnumPlayerModelParts modelPart = EnumPlayerModelParts.valueOf(part.getKey());
+ if (part.getValue().getAsBoolean()) {
+ partBitField |= modelPart.getPartMask();
+ } else {
+ partBitField &= ~modelPart.getPartMask();
+ }
+ }
+ }
+ player.getDataWatcher().updateObject(10, partBitField);
+ }
+ }
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java
new file mode 100644
index 00000000..3b73c26f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/entityviewer/WitherModifier.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.entityviewer;
+
+import com.google.gson.JsonObject;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.boss.EntityWither;
+
+public class WitherModifier extends EntityViewerModifier {
+ @Override
+ public EntityLivingBase applyModifier(EntityLivingBase base, JsonObject info) {
+ if (!(base instanceof EntityWither))
+ return null;
+ EntityWither wither = (EntityWither) base;
+ if (info.has("tiny")) {
+ if (info.get("tiny").getAsBoolean()) {
+ wither.setInvulTime(800);
+ } else {
+ wither.setInvulTime(0);
+ }
+ }
+ if (info.has("armored")) {
+ if (info.get("armored").getAsBoolean()) {
+ wither.setHealth(1);
+ } else {
+ wither.setHealth(wither.getMaxHealth());
+ }
+ }
+ return base;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java
new file mode 100644
index 00000000..54fcc204
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/AutoUpdater.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.updater;
+
+import com.google.common.collect.Iterables;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSyntaxException;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.MoulSigner;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.event.HoverEvent;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
+import net.minecraftforge.fml.common.Loader;
+import org.apache.commons.lang3.SystemUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class AutoUpdater {
+
+ NotEnoughUpdates neu;
+
+ public AutoUpdater(NotEnoughUpdates neu) {
+ this.neu = neu;
+ }
+
+ public void logProgress(String str) {
+ logProgress(new ChatComponentText(str));
+ }
+
+ public void logProgress(IChatComponent chatComponent) {
+ Minecraft.getMinecraft().addScheduledTask(() -> {
+ IChatComponent chatComponent1 = new ChatComponentText("");
+ chatComponent1.setChatStyle(new ChatStyle().setColor(EnumChatFormatting.AQUA));
+ chatComponent1.appendSibling(chatComponent);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("§e[NEU-AutoUpdater] ").appendSibling(
+ chatComponent1));
+ });
+ }
+
+ public UpdateLoader getUpdateLoader(URL url) {
+ if (SystemUtils.IS_OS_UNIX) {
+ return new LinuxBasedUpdater(this, url);
+ }
+ if (Loader.isModLoaded("skyblockclientupdater") && SCUCompatUpdater.IS_ENABLED) {
+ return SCUCompatUpdater.tryCreate(this, url);
+ }
+ return null;
+ }
+
+ UpdateLoader updateLoader;
+
+ public void updateFromURL(URL url) {
+ if (updateLoader != null) {
+ logProgress(
+ "There is already an update in progress, so the auto updater cannot process this update (as it might already be installed or is currently being downloaded). Please restart your client to install another update");
+ return;
+ }
+ if (!"https".equals(url.getProtocol())) {
+ logProgress("§cInvalid protocol in url: " + url + ". Only https is a valid protocol.");
+ return;
+ }
+ updateLoader = getUpdateLoader(url);
+ if (updateLoader == null) {
+ return;
+ }
+ updateLoader.greet();
+ logProgress(new ChatComponentText("[Start download now]")
+ .setChatStyle(new ChatStyle()
+ .setColor(EnumChatFormatting.GREEN)
+ .setChatHoverEvent(new HoverEvent(
+ HoverEvent.Action.SHOW_TEXT,
+ new ChatComponentText("Click to start download.")
+ ))
+ .setChatClickEvent(new ClickEvent(
+ ClickEvent.Action.RUN_COMMAND,
+ "/neuupdate scheduleDownload"
+ ))));
+ }
+
+ public void scheduleDownload() {
+ if (updateLoader == null) {
+ logProgress("§cNo update found. Try running /neuupdate check first");
+ return;
+ }
+ if (updateLoader.getState() != UpdateLoader.State.NOTHING) {
+ logProgress("§cUpdate download already started. No need to start the download again.");
+ return;
+ }
+ logProgress("Download started.");
+ updateLoader.scheduleDownload();
+ }
+
+ private void displayUpdateMessage(
+ JsonObject updateJson,
+ String updateMessage,
+ String downloadLink,
+ String directDownload
+ ) {
+ int firstWidth = -1;
+
+ for (String line : Iterables.concat(Arrays.asList(updateMessage.split("\n")), Arrays.asList("Download here"))) {
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ boolean isDownloadLink = line.equals("Download here");
+ int width = fr.getStringWidth(line);
+ if (firstWidth == -1) {
+ firstWidth = width;
+ }
+ int missingLen = firstWidth - width;
+ if (missingLen > 0) {
+ StringBuilder sb = new StringBuilder(missingLen / 4 / 2 + line.length());
+ for (int i = 0; i < missingLen / 4 / 2; i++) { /* fr.getCharWidth(' ') == 4 */
+ sb.append(" ");
+ }
+ sb.append(line);
+ line = sb.toString();
+ }
+ ChatComponentText cp = new ChatComponentText(line);
+ if (isDownloadLink)
+ cp.setChatStyle(Utils.createClickStyle(ClickEvent.Action.OPEN_URL, downloadLink));
+ Minecraft.getMinecraft().thePlayer.addChatMessage(cp);
+ }
+ neu.displayLinks(updateJson, firstWidth);
+ NotificationHandler.displayNotification(Arrays.asList(
+ "",
+ "§eThere is a new version of NotEnoughUpdates available.",
+ "§eCheck the chat for more information"
+ ), true);
+ try {
+ if (directDownload != null)
+ updateFromURL(new URL(directDownload));
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void displayUpdateMessageIfOutOfDate() {
+ File repo = neu.manager.repoLocation;
+ File updateJson = new File(repo, "update.json");
+ if (updateJson.exists()) {
+ if (!MoulSigner.verifySignature(updateJson)) {
+ NotEnoughUpdates.LOGGER.error("update.json found without signature");
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "§e[NEU] §cThere has been an error checking for updates. Check the log or join the discord for more information.").setChatStyle(
+ Utils.createClickStyle(
+ ClickEvent.Action.OPEN_URL, "https://discord.gg/moulberry")));
+ return;
+ }
+ try {
+ JsonObject o = neu.manager.getJsonFromFile(updateJson);
+
+ int fullReleaseVersion =
+ o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1;
+ int preReleaseVersion =
+ o.has("version_id") && o.get("version_id").isJsonPrimitive() ? o.get("version_id").getAsInt() : -1;
+ int hotfixVersion =
+ o.has("hotfix_id") && o.get("hotfix_id").isJsonPrimitive() ? o.get("hotfix_id").getAsInt() : -1;
+
+ boolean hasFullReleaseAvailableForUpgrade = fullReleaseVersion > NotEnoughUpdates.VERSION_ID;
+ boolean hasHotfixAvailableForUpgrade =
+ fullReleaseVersion == NotEnoughUpdates.VERSION_ID && hotfixVersion > NotEnoughUpdates.HOTFIX_VERSION_ID;
+ boolean hasPreReleaseAvailableForUpdate =
+ fullReleaseVersion == NotEnoughUpdates.VERSION_ID && preReleaseVersion > NotEnoughUpdates.PRE_VERSION_ID;
+
+ int updateChannel = NotEnoughUpdates.INSTANCE.config.notifications.updateChannel; /* 1 = Full, 2 = Pre */
+ if (hasFullReleaseAvailableForUpgrade || (hasHotfixAvailableForUpgrade && updateChannel == 1)) {
+ displayUpdateMessage(
+ o,
+ o.get("update_msg").getAsString(),
+ o.get("update_link").getAsString(),
+ o.has("update_direct") ? o.get("update_direct").getAsString() : null
+ );
+ } else if (hasPreReleaseAvailableForUpdate && updateChannel == 2) {
+ displayUpdateMessage(
+ o,
+ o.get("pre_update_msg").getAsString(),
+ o.get("pre_update_link").getAsString(),
+ o.has("pre_update_direct") ? o.get("pre_update_direct").getAsString() : null
+ );
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "§e[NEU] §cThere has been an error checking for updates. Check the log or join the discord for more information.").setChatStyle(
+ Utils.createClickStyle(
+ ClickEvent.Action.OPEN_URL, "https://discord.gg/moulberry")));
+ }
+ }
+ }
+
+ private boolean validateMcModInfo(JsonArray array) {
+ if (array.size() != 1) return false;
+ JsonElement jsonElement = array.get(0);
+ if (!jsonElement.isJsonObject()) return false;
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ if (!jsonObject.has("modid")) return false;
+ JsonElement modid = jsonObject.get("modid");
+ if (!modid.isJsonPrimitive()) return false;
+ JsonPrimitive primitive = modid.getAsJsonPrimitive();
+ if (!primitive.isString()) return false;
+ return "notenoughupdates".equals(primitive.getAsString());
+ }
+
+ public boolean isNeuJar(File sus) {
+ try (ZipFile zipFile = new ZipFile(sus)) {
+ ZipEntry entry = zipFile.getEntry("mcmod.info");
+ if (entry == null) {
+ return false;
+ }
+ try (InputStream inputStream = zipFile.getInputStream(entry)) {
+ JsonArray jsonArray = neu.manager.gson.fromJson(
+ new InputStreamReader(inputStream),
+ JsonArray.class
+ );
+ return validateMcModInfo(jsonArray);
+ }
+ } catch (IOException | JsonSyntaxException e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java
new file mode 100644
index 00000000..3118b135
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/LinuxBasedUpdater.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.updater;
+
+import java.io.File;
+import java.net.URL;
+import java.util.List;
+
+class LinuxBasedUpdater /* Based on what? */ extends UpdateLoader {
+
+ LinuxBasedUpdater(AutoUpdater updater, URL url) {
+ super(updater, url);
+ }
+
+ @Override
+ public void greet() {
+ updater.logProgress(
+ "Welcome Aristocrat! Your superior linux system configuration is supported for NEU auto updates.");
+ }
+
+ @Override
+ public void deleteFiles(List<File> toDelete) {
+ for (File toDel : toDelete) {
+ if (!toDel.delete()) {
+ updater.logProgress("§cCould not delete old version of NEU: " + toDel + ". Please manually delete file.");
+ state = State.FAILED;
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/SCUCompatUpdater.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/SCUCompatUpdater.java
new file mode 100644
index 00000000..3cb600cb
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/SCUCompatUpdater.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.updater;
+
+import java.io.File;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.List;
+
+/*
+ * Legal considerations: Skyblock Client Updater is licensed under the GNU AGPL v3.0 or later (with modifications).
+ * https://github.com/My-Name-Is-Jeff/SkyblockClient-Updater/blob/main/LICENSE
+ *
+ * However, even tho the AGPL License does not allow conveying covered work in combination with LGPL licensed code
+ * (such as our own), we do not perceive ourselves as conveying neither an unmodified version of Skyblock Client Updater
+ * nor a work based on Skyblock Client Updater (modified work) since our work is usable and functional in its entirety
+ * without presence of Skyblock Client Updater and is not to be distributed along a copy of Skyblock Client Updater
+ * unless that combined work is licensed with respect of both the LGPL and the AGPL, therefore is not adapting any part
+ * of Skyblock Client Updater unless already part of a whole distribution.
+ *
+ * In case the Copyright owner (Lily aka My-Name-Is-Jeff on Github) disagrees, we are willing to take down this module
+ * (or only convey this component of our work under a pure GPL license) with or without them providing legal grounds
+ * for this request. However, due to them not being able to be reached for comment, we will include this
+ * component for the time being.
+ * */
+public class SCUCompatUpdater extends UpdateLoader {
+
+ public static final boolean IS_ENABLED = false;
+
+ private SCUCompatUpdater(AutoUpdater updater, URL url) {
+ super(updater, url);
+ }
+
+ @Override
+ public void greet() {
+ updater.logProgress("Skyblock Client Updater compatibility layer loaded.");
+ }
+
+ @Override
+ public void deleteFiles(List<File> toDelete) {
+ try {
+ for (File f : toDelete)
+ ReflectionHolder.deleteFileOnShutdownHandle.invoke(ReflectionHolder.updateCheckerInstance, f, "");
+ } catch (Throwable e) {
+ e.printStackTrace();
+ updater.logProgress("Invoking SCU failed. Check the log for more info.");
+ state = State.FAILED;
+ }
+ }
+
+ static class ReflectionHolder {
+ static boolean isSCUFullyPresent = false;
+ static Class<?> updateChecker;
+ static Object updateCheckerInstance;
+ static Method deleteFileOnShutdown;
+ static MethodHandle deleteFileOnShutdownHandle;
+
+ static {
+ try {
+ updateChecker = Class.forName("mynameisjeff.skyblockclientupdater.utils.UpdateChecker");
+ Field instanceField = updateChecker.getDeclaredField("INSTANCE");
+ instanceField.setAccessible(true);
+ updateCheckerInstance = instanceField.get(null);
+ deleteFileOnShutdown = updateChecker.getDeclaredMethod("deleteFileOnShutdown", File.class, String.class);
+ deleteFileOnShutdownHandle = MethodHandles.publicLookup().unreflect(deleteFileOnShutdown);
+ isSCUFullyPresent = true;
+ } catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException | NoSuchMethodException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static UpdateLoader tryCreate(AutoUpdater updater, URL url) {
+ if (!ReflectionHolder.isSCUFullyPresent) {
+ updater.logProgress("§cFound Skyclient Updater Mod, however our hooks did not function properly.");
+ return null;
+ }
+ return new SCUCompatUpdater(updater, url);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java
new file mode 100644
index 00000000..1a1a8504
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscfeatures/updater/UpdateLoader.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures.updater;
+
+import io.github.moulberry.notenoughupdates.util.NetUtils;
+import net.minecraft.client.Minecraft;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+
+abstract class UpdateLoader {
+
+ enum State {
+ NOTHING, DOWNLOAD_STARTED, DOWNLOAD_FINISHED, INSTALLED, FAILED
+ }
+
+ URL url;
+ AutoUpdater updater;
+
+ State state = State.NOTHING;
+
+ UpdateLoader(AutoUpdater updater, URL url) {
+ this.url = url;
+ this.updater = updater;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public void setState(State state) {
+ this.state = state;
+ }
+
+ public URL getUrl() {
+ return url;
+ }
+
+ public void scheduleDownload() {
+ state = State.DOWNLOAD_STARTED;
+ try {
+ NetUtils.downloadAsync(url, File.createTempFile("NotEnoughUpdates-update", ".jar"))
+ .handle(
+ (f, exc) -> {
+ if (exc != null) {
+ state = State.FAILED;
+ updater.logProgress("§cError while downloading. Check your logs for more info.");
+ exc.printStackTrace();
+ return null;
+ }
+ state = State.DOWNLOAD_FINISHED;
+
+ updater.logProgress("Download completed. Trying to install");
+ launchUpdate(f);
+ return null;
+ });
+ } catch (IOException e) {
+ state = State.FAILED;
+ updater.logProgress("§cError while creating download. Check your logs for more info.");
+ e.printStackTrace();
+ }
+ }
+
+ public abstract void greet();
+
+ public void launchUpdate(File file) {
+
+ if (state != State.DOWNLOAD_FINISHED) {
+ updater.logProgress("§cUpdate is invalid state " + state + " to start update.");
+ state = State.FAILED;
+ return;
+ }
+ File mcDataDir = new File(Minecraft.getMinecraft().mcDataDir, "mods");
+ if (!mcDataDir.exists() || !mcDataDir.isDirectory() || !mcDataDir.canRead()) {
+ updater.logProgress("§cCould not find mods folder. Searched: " + mcDataDir);
+ state = State.FAILED;
+ return;
+ }
+ ArrayList<File> toDelete = new ArrayList<>();
+ File[] modFiles = mcDataDir.listFiles();
+ if (modFiles == null) {
+ updater.logProgress("§cCould not list minecraft mod folder (" + mcDataDir + ")");
+ state = State.FAILED;
+ return;
+ }
+ for (File sus : modFiles) {
+ if (sus.getName().endsWith(".jar")) {
+ if (updater.isNeuJar(sus)) {
+ updater.logProgress("Found old NEU file: " + sus + ". Deleting later.");
+ toDelete.add(sus);
+ }
+ }
+ }
+ File dest = new File(mcDataDir, file.getName());
+ try (
+ InputStream i = Files.newInputStream(file.toPath());
+ OutputStream o = Files.newOutputStream(dest.toPath());
+ ) {
+ IOUtils.copyLarge(i, o);
+ } catch (IOException e) {
+ e.printStackTrace();
+ updater.logProgress(
+ "§cFailed to copy release JAR. Not making any changes to your mod folder. Consult your logs for more info.");
+ state = State.FAILED;
+ }
+ deleteFiles(toDelete);
+ if (state != State.FAILED) {
+ state = State.INSTALLED;
+ updater.logProgress("Update successful. Thank you for your time.");
+ return;
+ }
+ updater.logProgress("§cFailure to delete some files. Please delte the old NEU version manually from your mods folder.");
+ }
+
+ public abstract void deleteFiles(List<File> toDelete);
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java
index 8996dc7a..530dcfd1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/AccessoryBagOverlay.java
@@ -1,12 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.auction.APIManager;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
import io.github.moulberry.notenoughupdates.profileviewer.PlayerStats;
import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.Utils;
@@ -33,8 +52,14 @@ import org.lwjgl.opengl.GL14;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.*;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -95,14 +120,30 @@ public class AccessoryBagOverlay {
int mouseX = Mouse.getX() / scaledResolution.getScaleFactor();
int mouseY = height - Mouse.getY() / scaledResolution.getScaleFactor();
- int xSize =
- (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "xSize", "field_146999_f");
- int ySize =
- (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "ySize", "field_147000_g");
- int guiLeft =
- (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "guiLeft", "field_147003_i");
- int guiTop =
- (int) Utils.getField(GuiContainer.class, Minecraft.getMinecraft().currentScreen, "guiTop", "field_147009_r");
+ int xSize = (int) Utils.getField(
+ GuiContainer.class,
+ Minecraft.getMinecraft().currentScreen,
+ "xSize",
+ "field_146999_f"
+ );
+ int ySize = (int) Utils.getField(
+ GuiContainer.class,
+ Minecraft.getMinecraft().currentScreen,
+ "ySize",
+ "field_147000_g"
+ );
+ int guiLeft = (int) Utils.getField(
+ GuiContainer.class,
+ Minecraft.getMinecraft().currentScreen,
+ "guiLeft",
+ "field_147003_i"
+ );
+ int guiTop = (int) Utils.getField(
+ GuiContainer.class,
+ Minecraft.getMinecraft().currentScreen,
+ "guiTop",
+ "field_147009_r"
+ );
if (mouseX < guiLeft + xSize + 3 || mouseX > guiLeft + xSize + 80 + 28) return false;
if (mouseY < guiTop || mouseY > guiTop + 166) return false;
@@ -797,7 +838,7 @@ public class AccessoryBagOverlay {
private static Comparator<String> getItemComparator() {
return (o1, o2) -> {
- float cost1;
+ double cost1;
JsonObject o1Auc = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(o1);
if (o1Auc != null && o1Auc.has("price")) {
cost1 = o1Auc.get("price").getAsFloat();
@@ -806,9 +847,9 @@ public class AccessoryBagOverlay {
if (info != null)
cost1 = info.craftCost;
else
- cost1 = 0;
+ cost1 = -1;
}
- float cost2;
+ double cost2;
JsonObject o2Auc = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(o2);
if (o2Auc != null && o2Auc.has("price")) {
cost2 = o2Auc.get("price").getAsFloat();
@@ -817,7 +858,7 @@ public class AccessoryBagOverlay {
if (info != null)
cost2 = info.craftCost;
else
- cost2 = 0;
+ cost2 = -1;
}
if (cost1 == -1 && cost2 == -1) return o1.compareTo(o2);
@@ -834,16 +875,17 @@ public class AccessoryBagOverlay {
private static boolean inAccessoryBag = false;
public static boolean isInAccessoryBag() {
- return inAccessoryBag;
+ return inAccessoryBag && NotEnoughUpdates.INSTANCE.config.accessoryBag.enableOverlay;
}
public static void renderOverlay() {
inAccessoryBag = false;
- if (Minecraft.getMinecraft().currentScreen instanceof GuiChest && NEUEventListener.inventoryLoaded) {
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest && RenderListener.inventoryLoaded) {
GuiChest eventGui = (GuiChest) Minecraft.getMinecraft().currentScreen;
ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
- if (containerName.trim().startsWith("Accessory Bag")) {
+ if (containerName.trim().startsWith("Accessory Bag") && !containerName.contains("Thaumaturgy") &&
+ !containerName.contains("Upgrades")) {
inAccessoryBag = true;
try {
int xSize = (int) Utils.getField(GuiContainer.class, eventGui, "xSize", "field_146999_f");
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java
index 98d8f11d..b1a3dca9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/CalendarOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.gson.JsonArray;
@@ -36,7 +55,12 @@ import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import java.io.File;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -51,6 +75,8 @@ public class CalendarOverlay {
private static boolean enabled = false;
+ public static boolean ableToClickCalendar = true;
+
public static void setEnabled(boolean enabled) {
CalendarOverlay.enabled = enabled;
}
@@ -455,8 +481,7 @@ public class CalendarOverlay {
guiLeft = (width - xSize) / 2;
guiTop = 5;
-
- if (mouseX >= guiLeft && mouseX <= guiLeft + xSize) {
+ if (mouseX >= guiLeft && mouseX <= guiLeft + xSize && ableToClickCalendar) {
if (mouseY >= guiTop && mouseY <= guiTop + ySize) {
ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/neucalendar");
}
@@ -659,6 +684,8 @@ public class CalendarOverlay {
}
}
}
+ } else {
+ Minecraft.getMinecraft().dispatchKeypresses();
}
}
}
@@ -839,8 +866,8 @@ public class CalendarOverlay {
SBEvent firstEvent = null;
List<SBEvent> nextFavourites = new ArrayList<>();
List<Long> nextFavouritesTime = new ArrayList<>();
- long timeUntilMajor = 0;
- SBEvent nextMajorEvent = null;
+ long timeUntilMayor = 0;
+ SBEvent nextMayorEvent = null;
List<String> eventFavourites = NotEnoughUpdates.INSTANCE.config.hidden.eventFavourites;
@@ -863,10 +890,10 @@ public class CalendarOverlay {
}
}
- if (nextMajorEvent == null && !sbEvent.id.split(":")[0].equals("jacob_farming") &&
+ if (nextMayorEvent == null && !sbEvent.id.split(":")[0].equals("jacob_farming") &&
!sbEvent.id.equals("dark_auction")) {
- nextMajorEvent = sbEvent;
- timeUntilMajor = timeUntilMillis;
+ nextMayorEvent = sbEvent;
+ timeUntilMayor = timeUntilMillis;
}
if (firstEvent == null) {
@@ -893,7 +920,7 @@ public class CalendarOverlay {
}
}
- if (nextFavourites.size() >= 3 && nextMajorEvent != null) {
+ if (nextFavourites.size() >= 3 && nextMayorEvent != null) {
break out;
}
}
@@ -974,18 +1001,18 @@ public class CalendarOverlay {
if (sbEvent.id.split(":")[0].equals("jacob_farming") && sbEvent.desc != null) {
tooltipToDisplay.addAll(sbEvent.desc);
}
- if (nextMajorEvent != null || i < nextFavourites.size() - 1) {
+ if (nextMayorEvent != null || i < nextFavourites.size() - 1) {
tooltipToDisplay.add("");
}
}
- if (nextMajorEvent != null) {
- tooltipToDisplay.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Next Major:");
- tooltipToDisplay.add(nextMajorEvent.display);
+ if (nextMayorEvent != null) {
+ tooltipToDisplay.add(EnumChatFormatting.YELLOW.toString() + EnumChatFormatting.BOLD + "Next Mayor:");
+ tooltipToDisplay.add(nextMayorEvent.display);
tooltipToDisplay.add(EnumChatFormatting.GRAY + "Starts in: " + EnumChatFormatting.YELLOW +
- prettyTime(timeUntilMajor, false));
- if (nextMajorEvent.lastsFor >= 0) {
+ prettyTime(timeUntilMayor, false));
+ if (nextMayorEvent.lastsFor >= 0) {
tooltipToDisplay.add(EnumChatFormatting.GRAY + "Lasts for: " + EnumChatFormatting.YELLOW +
- prettyTime(nextMajorEvent.lastsFor, true));
+ prettyTime(nextMayorEvent.lastsFor, true));
}
}
@@ -1000,6 +1027,21 @@ public class CalendarOverlay {
GlStateManager.translate(0, 0, -100);
}
}
+ } else if (!enabled && NotEnoughUpdates.INSTANCE.config.calendar.showEventTimerInInventory) {
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+ GlStateManager.disableFog();
+ GlStateManager.disableLighting();
+ GlStateManager.disableColorMaterial();
+
+ renderBlurredBackground(10, width, height, guiLeft + 3, guiTop + 3, xSize - 6, ySize - 6);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(DISPLAYBAR);
+ Utils.drawTexturedRect(guiLeft, guiTop, xSize, 20, GL11.GL_NEAREST);
+
+ String nextS = EnumChatFormatting.RED + "Open calendar to see events";
+ fr.drawString(nextS, guiLeft + 8, guiTop + 6, -1, false);
}
}
GlStateManager.translate(0, 0, -10);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiCustomEnchant.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiCustomEnchant.java
index f5838052..6f190ada 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiCustomEnchant.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiCustomEnchant.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.collect.Lists;
@@ -9,8 +28,11 @@ import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingFloat;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingInteger;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import io.github.moulberry.notenoughupdates.miscgui.util.OrbDisplay;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -38,7 +60,12 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.Project;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,9 +76,9 @@ public class GuiCustomEnchant extends Gui {
"textures/entity/enchanting_table_book.png");
private static final ModelBook MODEL_BOOK = new ModelBook();
- private static final int EXPERIENCE_ORB_COUNT = 30;
-
private static final Pattern XP_COST_PATTERN = Pattern.compile("\\u00a73(\\d+) Exp Levels");
+ private static final Pattern ENCHANT_LEVEL_PATTERN = Pattern.compile("(.*)_(.*)");
+ private static final Pattern ENCHANT_NAME_PATTERN = Pattern.compile("([^IVX]*) ([IVX]*)");
private enum EnchantState {
NO_ITEM,
@@ -80,6 +107,7 @@ public class GuiCustomEnchant extends Gui {
this.enchId = enchId;
this.displayLore = displayLore;
this.level = level;
+ this.enchId = ItemUtils.fixEnchantId(enchId, true);
if (Constants.ENCHANTS != null) {
if (checkConflicts && Constants.ENCHANTS.has("enchant_pools")) {
@@ -108,12 +136,18 @@ public class GuiCustomEnchant extends Gui {
if (level >= 1 && Constants.ENCHANTS.has("enchants_xp_cost")) {
JsonObject allCosts = Constants.ENCHANTS.getAsJsonObject("enchants_xp_cost");
- if (allCosts.has(enchId)) {
- JsonArray costs = allCosts.getAsJsonArray(enchId);
+ JsonObject maxLevel = null;
+ if (Constants.ENCHANTS.has("max_xp_table_levels")) {
+ maxLevel = Constants.ENCHANTS.getAsJsonObject("max_xp_table_levels");
+ }
+
+ if (allCosts.has(this.enchId)) {
+ JsonArray costs = allCosts.getAsJsonArray(this.enchId);
if (costs.size() >= 1) {
if (useMaxLevelForCost) {
- this.xpCost = costs.get(costs.size() - 1).getAsInt();
+ int cost = (maxLevel != null && maxLevel.has(this.enchId) ? maxLevel.get(this.enchId).getAsInt() : costs.size());
+ this.xpCost = costs.get(cost - 1).getAsInt();
} else if (level - 1 < costs.size()) {
this.xpCost = costs.get(level - 1).getAsInt();
} else {
@@ -127,21 +161,7 @@ public class GuiCustomEnchant extends Gui {
}
}
- public static class ExperienceOrb {
- public float x;
- public float y;
- public float xLast;
- public float yLast;
- public float xVel;
- public float yVel;
-
- public int type;
- public int rotationDeg;
- }
-
- private final List<ExperienceOrb> orbs = new ArrayList<>();
- private int orbTargetX = 0;
- private int orbTargetY = 0;
+ public OrbDisplay orbDisplay = new OrbDisplay();
private int guiLeft;
private int guiTop;
@@ -201,8 +221,15 @@ public class GuiCustomEnchant extends Gui {
}
public boolean shouldOverride(String containerName) {
+ if (containerName == null) {
+ shouldOverrideFast = false;
+ return false;
+ }
shouldOverrideFast = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableTableGUI &&
- Objects.equals("Enchant Item", containerName) &&
+ (containerName.length() >= 12 && Objects.equals(
+ "Enchant Item",
+ containerName.substring(0, "Enchant Item".length())
+ )) &&
NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard();
if (!shouldOverrideFast) {
currentState = EnchantState.NO_ITEM;
@@ -210,6 +237,13 @@ public class GuiCustomEnchant extends Gui {
removable.clear();
expectedMaxPage = 1;
}
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+ ItemStack hexStack = cc.getLowerChestInventory().getStackInSlot(50);
+ if (hexStack != null && hexStack.getItem() == Items.experience_bottle) {
+ shouldOverrideFast = false;
+ return false;
+ }
return shouldOverrideFast;
}
@@ -220,13 +254,15 @@ public class GuiCustomEnchant extends Gui {
ContainerChest cc = (ContainerChest) chest.inventorySlots;
ItemStack stack = cc.getLowerChestInventory().getStackInSlot(23);
- ItemStack enchantGuideStack = cc.getLowerChestInventory().getStackInSlot(50);
+ ItemStack arrowStack = cc.getLowerChestInventory().getStackInSlot(45);
ItemStack enchantingItemStack = cc.getLowerChestInventory().getStackInSlot(19);
+ ItemStack hexStack = cc.getLowerChestInventory().getStackInSlot(50);
int lastPage = currentPage;
this.lastState = currentState;
- if (enchantGuideStack != null && enchantGuideStack.getItem() != Items.book && enchantingItem != null) {
+ if (hexStack != null && hexStack.getItem() == Items.experience_bottle) return;
+ if (arrowStack != null && arrowStack.getItem() == Items.arrow && enchantingItem != null) {
currentState = EnchantState.ADDING_ENCHANT;
} else if (stack == null || enchantingItemStack == null) {
if (currentState == EnchantState.SWITCHING_DONT_UPDATE || currentState == EnchantState.NO_ITEM) {
@@ -280,30 +316,7 @@ public class GuiCustomEnchant extends Gui {
}
}
- List<ExperienceOrb> toRemove = new ArrayList<>();
- for (ExperienceOrb orb : orbs) {
- float targetDeltaX = guiLeft + orbTargetX - orb.x;
- float targetDeltaY = guiTop + orbTargetY - orb.y;
-
- float length = (float) Math.sqrt(targetDeltaX * targetDeltaX + targetDeltaY * targetDeltaY);
-
- if (length < 8 && orb.xVel * orb.xVel + orb.yVel * orb.yVel < 20) {
- toRemove.add(orb);
- continue;
- }
-
- orb.xVel += targetDeltaX * 2 / length;
- orb.yVel += targetDeltaY * 2 / length;
-
- orb.xVel *= 0.90;
- orb.yVel *= 0.90;
-
- orb.xLast = orb.x;
- orb.yLast = orb.y;
- orb.x += orb.xVel;
- orb.y += orb.yVel;
- }
- orbs.removeAll(toRemove);
+ orbDisplay.physicsTickOrbs();
if (++tickCounter >= 20) {
tickCounter = 0;
@@ -364,40 +377,50 @@ public class GuiCustomEnchant extends Gui {
if (ea != null) {
NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
if (enchantments != null) {
- for (String enchId : enchantments.getKeySet()) {
- String name = Utils.cleanColour(book.getDisplayName());
- if (name.equalsIgnoreCase("Bane of Arthropods")) {
- name = "Bane of Arth.";
- } else if (name.equalsIgnoreCase("Projectile Protection")) {
- name = "Projectile Prot";
- } else if (name.equalsIgnoreCase("Blast Protection")) {
- name = "Blast Prot";
- }
- Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
- Utils.getRawTooltip(book), enchantments.getInteger(enchId), false, true
- );
- enchantment.displayLore.remove(0);
+ String enchId = Utils
+ .cleanColour(book.getDisplayName())
+ .toLowerCase()
+ .replace(" ", "_")
+ .replace("-", "_")
+ .replaceAll("[^a-z_]", "");
+ String name = Utils.cleanColour(book.getDisplayName());
+ int enchLevel = -1;
+ if (name.equalsIgnoreCase("Bane of Arthropods")) {
+ name = "Bane of Arth.";
+ } else if (name.equalsIgnoreCase("Projectile Protection")) {
+ name = "Projectile Prot";
+ } else if (name.equalsIgnoreCase("Blast Protection")) {
+ name = "Blast Prot";
+ }
+ Matcher levelMatcher = ENCHANT_LEVEL_PATTERN.matcher(enchId);
+ if (levelMatcher.matches()) {
+ enchLevel = Utils.parseRomanNumeral(levelMatcher.group(2).toUpperCase());
+ enchId = levelMatcher.group(1);
+ }
+ Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
+ Utils.getRawTooltip(book), enchLevel, false, true
+ );
+ enchantment.displayLore.remove(0);
- if (removingEnchantPlayerLevel == -1 && playerEnchantIds.containsKey(enchId)) {
- removingEnchantPlayerLevel = playerEnchantIds.get(enchId);
- }
+ if (removingEnchantPlayerLevel == -1 && playerEnchantIds.containsKey(enchId)) {
+ removingEnchantPlayerLevel = playerEnchantIds.get(enchId);
+ }
- if (removingEnchantPlayerLevel >= 0 && enchantment.level < removingEnchantPlayerLevel) {
- continue;
- }
+ if (removingEnchantPlayerLevel >= 0 && enchantment.level < removingEnchantPlayerLevel) {
+ continue;
+ }
- if (enchanterCurrentEnch == null) {
+ if (enchanterCurrentEnch == null) {
+ enchanterCurrentEnch = enchantment;
+ } else if (updateLevel) {
+ if (removingEnchantPlayerLevel < 0 && enchantment.level > enchanterCurrentEnch.level) {
+ enchanterCurrentEnch = enchantment;
+ } else if (removingEnchantPlayerLevel >= 0 && enchantment.level < enchanterCurrentEnch.level) {
enchanterCurrentEnch = enchantment;
- } else if (updateLevel) {
- if (removingEnchantPlayerLevel < 0 && enchantment.level > enchanterCurrentEnch.level) {
- enchanterCurrentEnch = enchantment;
- } else if (removingEnchantPlayerLevel >= 0 && enchantment.level < enchanterCurrentEnch.level) {
- enchanterCurrentEnch = enchantment;
- }
}
-
- enchanterEnchLevels.put(enchantment.level, enchantment);
}
+
+ enchanterEnchLevels.put(enchantment.level, enchantment);
}
}
}
@@ -430,43 +453,53 @@ public class GuiCustomEnchant extends Gui {
if (ea != null) {
NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
if (enchantments != null) {
- for (String enchId : enchantments.getKeySet()) {
- String name = Utils.cleanColour(book.getDisplayName());
-
- if (searchField.getText().trim().isEmpty() ||
- name.toLowerCase().contains(searchField.getText().trim().toLowerCase())) {
- if (name.equalsIgnoreCase("Bane of Arthropods")) {
- name = "Bane of Arth.";
- } else if (name.equalsIgnoreCase("Projectile Protection")) {
- name = "Projectile Prot";
- } else if (name.equalsIgnoreCase("Blast Protection")) {
- name = "Blast Prot";
- } else if (name.equalsIgnoreCase("Luck of the Sea")) {
- name = "Luck of Sea";
- }
+ String enchId = Utils
+ .cleanColour(book.getDisplayName())
+ .toLowerCase()
+ .replace(" ", "_")
+ .replace("-", "_")
+ .replaceAll("[^a-z_]", "");
+ if (enchId.equalsIgnoreCase("_")) continue;
+ enchId = ItemUtils.fixEnchantId(enchId, true);
+ String name = Utils.cleanColour(book.getDisplayName());
+
+ if (searchField.getText().trim().isEmpty() ||
+ name.toLowerCase().contains(searchField.getText().trim().toLowerCase())) {
+ if (name.equalsIgnoreCase("Bane of Arthropods")) {
+ name = "Bane of Arth.";
+ } else if (name.equalsIgnoreCase("Projectile Protection")) {
+ name = "Projectile Prot";
+ } else if (name.equalsIgnoreCase("Blast Protection")) {
+ name = "Blast Prot";
+ } else if (name.equalsIgnoreCase("Luck of the Sea")) {
+ name = "Luck of Sea";
+ }
+ Matcher nameMatcher = ENCHANT_NAME_PATTERN.matcher(name);
+ if (nameMatcher.matches()) {
+ name = nameMatcher.group(1);
+ }
- if (playerEnchantIds.containsKey(enchId)) {
- Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
- Utils.getRawTooltip(book), playerEnchantIds.get(enchId), false, false
- );
- if (!enchantment.overMaxLevel) {
- removable.add(enchantment);
- }
- } else {
- Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
- Utils.getRawTooltip(book), enchantments.getInteger(enchId), true, true
- );
- applicable.add(enchantment);
+ if (playerEnchantIds.containsKey(enchId)) {
+ Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
+ Utils.getRawTooltip(book), playerEnchantIds.get(enchId), false, false
+ );
+ if (!enchantment.overMaxLevel) {
+ removable.add(enchantment);
}
} else {
- if (playerEnchantIds.containsKey(enchId)) {
- searchRemovedFromRemovable = true;
- } else {
- searchRemovedFromApplicable = true;
- }
+ Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
+ Utils.getRawTooltip(book), 1, true, true
+ );
+ applicable.add(enchantment);
+ }
+ } else {
+ if (playerEnchantIds.containsKey(enchId)) {
+ searchRemovedFromRemovable = true;
+ } else {
+ searchRemovedFromApplicable = true;
}
-
}
+
}
}
}
@@ -945,7 +978,7 @@ public class GuiCustomEnchant extends Gui {
GlStateManager.pushMatrix();
GlStateManager.translate(guiLeft + 102 - 8, guiTop + 191 - (inventoryStartIndex / 9 * 18 + 89), 0);
Slot slot = cc.getSlot(inventoryStartIndex + i);
- chest.drawSlot(slot);
+ ((AccessorGuiContainer) chest).doDrawSlot(slot);
GlStateManager.popMatrix();
if (mouseX >= itemX && mouseX < itemX + 18 &&
@@ -1040,7 +1073,9 @@ public class GuiCustomEnchant extends Gui {
Minecraft.getMinecraft().fontRendererObj.drawString(levelStr, left + 8 - levelWidth / 2, top + 4, colour, false);
//Enchant name
- String name = WordUtils.capitalizeFully(enchanterCurrentEnch.enchId.replace("_", " "));
+ String name = WordUtils.capitalizeFully(ItemUtils
+ .fixEnchantId(enchanterCurrentEnch.enchId, false)
+ .replace("_", " "));
if (name.equalsIgnoreCase("Bane of Arthropods")) {
name = "Bane of Arth.";
} else if (name.equalsIgnoreCase("Projectile Protection")) {
@@ -1331,37 +1366,11 @@ public class GuiCustomEnchant extends Gui {
//Orb animation
Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
- GlStateManager.color(1, 1, 1, 1);
GlStateManager.disableDepth();
- for (ExperienceOrb orb : orbs) {
- int orbX = Math.round(orb.xLast + (orb.x - orb.xLast) * partialTicks);
- int orbY = Math.round(orb.yLast + (orb.y - orb.yLast) * partialTicks);
- GlStateManager.pushMatrix();
- GlStateManager.translate(orbX, orbY, 0);
- GlStateManager.rotate(orb.rotationDeg, 0, 0, 1);
-
- float targetDeltaX = guiLeft + orbTargetX - orb.x;
- float targetDeltaY = guiTop + orbTargetY - orb.y;
- float length = (float) Math.sqrt(targetDeltaX * targetDeltaX + targetDeltaY * targetDeltaY);
- float velSq = orb.xVel * orb.xVel + orb.yVel * orb.yVel;
- float opacity = Math.min(2, Math.max(0.5f, length / 16)) * Math.min(2, Math.max(0.5f, velSq / 40));
- if (opacity > 1) opacity = 1;
- opacity = (float) Math.sqrt(opacity);
- GlStateManager.color(1, 1, 1, opacity);
-
- Utils.drawTexturedRect(
- -8,
- -8,
- 16,
- 16,
- ((orb.type % 3) * 16) / 512f,
- (16 + (orb.type % 3) * 16) / 512f,
- (217 + orb.type / 3 * 16) / 512f,
- (217 + 16 + orb.type / 3 * 16) / 512f,
- GL11.GL_NEAREST
- );
- GlStateManager.popMatrix();
- }
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(guiLeft, guiTop, 0);
+ orbDisplay.renderOrbs(partialTicks);
+ GlStateManager.popMatrix();
GlStateManager.enableDepth();
if (stackOnMouse != null) {
@@ -1378,37 +1387,6 @@ public class GuiCustomEnchant extends Gui {
GlStateManager.translate(0, 0, -300);
}
- private void spawnExperienceOrbs(int startX, int startY, int targetX, int targetY, int baseType) {
- orbs.clear();
-
- this.orbTargetX = targetX;
- this.orbTargetY = targetY;
-
- Random rand = new Random();
- for (int i = 0; i < EXPERIENCE_ORB_COUNT; i++) {
- ExperienceOrb orb = new ExperienceOrb();
- orb.x = startX;
- orb.y = startY;
- orb.xLast = startX;
- orb.yLast = startY;
- orb.xVel = rand.nextFloat() * 20 - 10;
- orb.yVel = rand.nextFloat() * 20 - 10;
- orb.type = baseType;
-
- float typeRand = rand.nextFloat();
- if (typeRand < 0.6) {
- orb.type += 0;
- } else if (typeRand < 0.9) {
- orb.type += 1;
- } else {
- orb.type += 2;
- }
- orb.rotationDeg = rand.nextInt(4) * 90;
-
- orbs.add(orb);
- }
- }
-
private void renderEnchantBook(ScaledResolution scaledresolution, float partialTicks) {
GlStateManager.enableDepth();
@@ -1515,9 +1493,9 @@ public class GuiCustomEnchant extends Gui {
EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
- ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(48);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
- chest.inventorySlots.windowId, 48, 0, 0, stack, transactionID));
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
cancelButtonAnimTime = System.currentTimeMillis();
}
@@ -1567,9 +1545,9 @@ public class GuiCustomEnchant extends Gui {
EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
- ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(48);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
- chest.inventorySlots.windowId, 48, 0, 0, stack, transactionID));
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
cancelButtonAnimTime = System.currentTimeMillis();
} else if (!isChangingEnchLevel && enchanterCurrentEnch != null &&
@@ -1592,9 +1570,9 @@ public class GuiCustomEnchant extends Gui {
int playerXpLevel = Minecraft.getMinecraft().thePlayer.experienceLevel;
if (playerXpLevel >= enchanterCurrentEnch.xpCost) {
if (removingEnchantPlayerLevel >= 0 && enchanterCurrentEnch.level == removingEnchantPlayerLevel) {
- spawnExperienceOrbs(guiLeft + X_SIZE / 2, guiTop + 66, X_SIZE / 2, 36, 3);
+ orbDisplay.spawnExperienceOrbs(X_SIZE / 2, 66, X_SIZE / 2, 36, 3);
} else {
- spawnExperienceOrbs(mouseX, mouseY, X_SIZE / 2, 66, 0);
+ orbDisplay.spawnExperienceOrbs(mouseX - guiLeft, mouseY - guiTop, X_SIZE / 2, 66, 0);
}
}
@@ -1765,9 +1743,9 @@ public class GuiCustomEnchant extends Gui {
} else if (currentState == EnchantState.ADDING_ENCHANT) {
EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
- ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(48);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
- chest.inventorySlots.windowId, 48, 0, 0, stack, transactionID));
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
cancelButtonAnimTime = System.currentTimeMillis();
}
@@ -1805,9 +1783,9 @@ public class GuiCustomEnchant extends Gui {
} else if (currentState == EnchantState.ADDING_ENCHANT) {
EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
- ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(48);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
- chest.inventorySlots.windowId, 48, 0, 0, stack, transactionID));
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
cancelButtonAnimTime = System.currentTimeMillis();
}
@@ -1852,9 +1830,9 @@ public class GuiCustomEnchant extends Gui {
EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
- ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(48);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
- chest.inventorySlots.windowId, 48, 0, 0, stack, transactionID));
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
cancelButtonAnimTime = System.currentTimeMillis();
}
@@ -1873,9 +1851,9 @@ public class GuiCustomEnchant extends Gui {
EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
- ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(48);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
- chest.inventorySlots.windowId, 48, 0, 0, stack, transactionID));
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
cancelButtonAnimTime = System.currentTimeMillis();
}
@@ -1899,6 +1877,7 @@ public class GuiCustomEnchant extends Gui {
}
return Keyboard.getEventKey() != Keyboard.KEY_ESCAPE &&
+ Keyboard.getEventKey() != Minecraft.getMinecraft().gameSettings.keyBindInventory.getKeyCode() &&
(!NotEnoughUpdates.INSTANCE.config.slotLocking.enableSlotLocking ||
Keyboard.getEventKey() != NotEnoughUpdates.INSTANCE.config.slotLocking.slotLockKey);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiEnchantColour.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiEnchantColour.java
index bd4bd680..b90b1356 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiEnchantColour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiEnchantColour.java
@@ -1,13 +1,34 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
-import com.google.gson.*;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingInteger;
import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
-import io.github.moulberry.notenoughupdates.util.Constants;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -66,7 +87,9 @@ public class GuiEnchantColour extends GuiScreen {
private static final Pattern settingPattern = Pattern.compile(".*:[>=<]:[0-9]+:[a-zA-Z0-9]+(:[a-zA-Z0-9]+)?");
private ItemStack maxedBook;
+ private ItemStack maxedAttBook;
private int maxedBookFound = 0;
+ private int maxedAttBookFound = 0;
private List<String> getEnchantColours() {
return NotEnoughUpdates.INSTANCE.config.hidden.enchantColours;
@@ -227,14 +250,42 @@ public class GuiEnchantColour extends GuiScreen {
if (maxedBookFound == 1) {
Utils.drawItemStack(maxedBook, guiLeft + xSize + 3, guiTopSidebar - 34);
}
+ if (maxedAttBookFound == 0) {
+ try {
+ if (NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("MAXED_ATTRIBUTE_SHARD")).hasDisplayName()) {
+ maxedAttBook = NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .get("MAXED_ATTRIBUTE_SHARD"));
+ maxedAttBookFound = 1;
+ } else {
+ maxedAttBookFound = 2;
+ }
+
+ } catch (Exception ignored) {
+ maxedAttBookFound = 2;
+ }
+ }
+ if (maxedAttBookFound == 1) {
+ Utils.drawItemStack(maxedAttBook, guiLeft + xSize + 3, guiTopSidebar - 52);
+ }
+
+ if (mouseX >= guiLeft + xSize + 3 && mouseX < guiLeft + xSize + 39) {
+ boolean renderingTooltip = false;
- if (mouseX >= guiLeft + xSize + 3 && mouseX < guiLeft + xSize + 19) {
if (mouseY >= guiTopSidebar - 34 && mouseY <= guiTopSidebar - 18 && maxedBookFound == 1) {
tooltipToDisplay = maxedBook.getTooltip(Minecraft.getMinecraft().thePlayer, false);
Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
tooltipToDisplay = null;
+ renderingTooltip = true;
+ }
+ if (mouseY >= guiTopSidebar - 52 && mouseY <= guiTopSidebar - 34 && maxedAttBookFound == 1 && !renderingTooltip) {
+ tooltipToDisplay = maxedAttBook.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr);
+ tooltipToDisplay = null;
+ renderingTooltip = true;
}
- if (mouseY >= guiTopSidebar - 18 && mouseY <= guiTopSidebar - 2) {
+ if (mouseY >= guiTopSidebar - 18 && mouseY <= guiTopSidebar - 2 && !renderingTooltip) {
tooltipToDisplay = Lists.newArrayList(
EnumChatFormatting.AQUA + "NEUEC Colouring Guide",
EnumChatFormatting.GREEN + "",
@@ -395,6 +446,11 @@ public class GuiEnchantColour extends GuiScreen {
}
@Override
+ public void onGuiClosed() {
+ NotEnoughUpdates.INSTANCE.saveConfig();
+ }
+
+ @Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
super.keyTyped(typedChar, keyCode);
for (int yIndex = 0; yIndex < guiElementTextFields.size(); yIndex++) {
@@ -573,10 +629,12 @@ public class GuiEnchantColour extends GuiScreen {
getEnchantOpString(guiElementTextFields.get(yIndex), comparators.get(yIndex), modifiers.get(yIndex))
);
} else if (mouseX > guiLeft + 160 && mouseX < guiLeft + 160 + 20) {
- NotEnoughUpdates.INSTANCE.config.hidden.enchantColours.remove(yIndex);
- guiElementTextFields.remove(yIndex);
- comparators.remove(yIndex);
- modifiers.remove(yIndex);
+ if (NotEnoughUpdates.INSTANCE.config.hidden.enchantColours.size() > 0) {
+ NotEnoughUpdates.INSTANCE.config.hidden.enchantColours.remove(yIndex);
+ guiElementTextFields.remove(yIndex);
+ comparators.remove(yIndex);
+ modifiers.remove(yIndex);
+ }
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiInvButtonEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiInvButtonEditor.java
index 7c74c6e2..7aa0d2ec 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiInvButtonEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiInvButtonEditor.java
@@ -1,11 +1,37 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
-import com.google.gson.*;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUOverlay;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.GlScissorStack;
import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingInteger;
import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.overlays.EquipmentOverlay;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -17,7 +43,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ResourceLocation;
-import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
@@ -29,8 +54,15 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
-import java.util.*;
+import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
@@ -53,6 +85,15 @@ public class GuiInvButtonEditor extends GuiScreen {
private int guiLeft;
private int guiTop;
+ //region getGuiCoordinates
+ public int getGuiLeft() {
+ return this.guiLeft;
+ }
+ public int getGuiTop() {
+ return this.guiTop;
+ }
+ //endregion
+
private static final int BACKGROUND_TYPES = 5;
private static final int ICON_TYPES = 3;
private int iconTypeIndex = 0;
@@ -107,8 +148,6 @@ public class GuiInvButtonEditor extends GuiScreen {
put("crypts", "skull:25d2f31ba162fe6272e831aed17f53213db6fa1c4cbe4fc827f3963cc98b9");
put("spiders den", "skull:c754318a3376f470e481dfcd6c83a59aa690ad4b4dd7577fdad1c2ef08d8aee6");
put("top of the nest", "skull:9d7e3b19ac4f3dee9c5677c135333b9d35a7f568b63d1ef4ada4b068b5a25");
- put("blazing fortress", "skull:c3687e25c632bce8aa61e0d64c24e694c3eea629ea944f4cf30dcfb4fbce071");
- put("blazing fortress magma boss", "skull:38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429");
put("the end", "skull:7840b87d52271d2a755dedc82877e0ed3df67dcc42ea479ec146176b02779a5");
put("the end dragons nest", "skull:a1cd6d2d03f135e7c6b5d6cdae1b3a68743db4eb749faf7341e9fb347aa283b");
put("the park", "skull:a221f813dacee0fef8c59f76894dbb26415478d9ddfc44c2e708a6d3b7549b");
@@ -117,11 +156,18 @@ public class GuiInvButtonEditor extends GuiScreen {
put("gold mines", "skull:73bc965d579c3c6039f0a17eb7c2e6faf538c7a5de8e60ec7a719360d0a857a9");
put("deep caverns", "skull:569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc");
put("the barn", "skull:4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b");
- put("mushroom desert", "skull:2116b9d8df346a25edd05f842e7a9345beaf16dca4118abf5a68c75bcaae10");
+ put("mushroom desert", "skull:6b20b23c1aa2be0270f016b4c90d6ee6b8330a17cfef87869d6ad60b2ffbf3b5");
put("dungeon hub", "skull:9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d");
- put("dwarven mines", "skull:569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc");
+ put("dwarven mines", "skull:51539dddf9ed255ece6348193cd75012c82c93aec381f05572cecf7379711b3b");
put("hotm heart of the mountain", "skull:86f06eaa3004aeed09b3d5b45d976de584e691c0e9cade133635de93d23b9edb");
put("bazaar dude", "skull:c232e3820897429157619b0ee099fec0628f602fff12b695de54aef11d923ad7");
+ put("museum", "skull:438cf3f8e54afc3b3f91d20a49f324dca1486007fe545399055524c17941f4dc");
+ put("crystal hollows", "skull:21dbe30b027acbceb612563bd877cd7ebb719ea6ed1399027dcee58bb9049d4a");
+ put("dwarven forge", "skull:5cbd9f5ec1ed007259996491e69ff649a3106cf920227b1bb3a71ee7a89863f");
+ put("forgotton skull", "skull:6becc645f129c8bc2faa4d8145481fab11ad2ee75749d628dcd999aa94e7");
+ put("crystal nucleus", "skull:34d42f9c461cee1997b67bf3610c6411bf852b9e5db607bbf626527cfb42912c");
+ put("void sepulture", "skull:eb07594e2df273921a77c101d0bfdfa1115abed5b9b2029eb496ceba9bdbb4b3");
+ put("crimson isle", "skull:c3687e25c632bce8aa61e0d64c24e694c3eea629ea944f4cf30dcfb4fbce071");
}};
private static LinkedHashMap<String, List<NEUConfig.InventoryButton>> presets = null;
@@ -130,7 +176,6 @@ public class GuiInvButtonEditor extends GuiScreen {
super();
reloadExtraIcons();
reloadPresets();
- Keyboard.enableRepeatEvents(true);
}
private static void reloadExtraIcons() {
@@ -282,6 +327,13 @@ public class GuiInvButtonEditor extends GuiScreen {
GlStateManager.color(1, 1, 1, 1);
Utils.drawTexturedRect(guiLeft, guiTop, xSize, ySize, 0, xSize / 256f, 0, ySize / 256f, GL11.GL_NEAREST);
+ if (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud) {
+ EquipmentOverlay.INSTANCE.renderPreviewArmorHud();
+ }
+ if (NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay) {
+ EquipmentOverlay.INSTANCE.renderPreviewPetInvHud();
+ }
+
for (NEUConfig.InventoryButton button : NotEnoughUpdates.INSTANCE.config.hidden.inventoryButtons) {
int x = guiLeft + button.x;
int y = guiTop + button.y;
@@ -292,6 +344,17 @@ public class GuiInvButtonEditor extends GuiScreen {
y += ySize;
}
+ if (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
+ x -= 25;
+ }
+ }
+ if (NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
+ x -= 25;
+ }
+ }
+
if (button.isActive()) {
GlStateManager.color(1, 1, 1, 1f);
} else {
@@ -324,7 +387,7 @@ public class GuiInvButtonEditor extends GuiScreen {
Minecraft.getMinecraft().getTextureManager().bindTexture(custom_ench_colour);
GlStateManager.color(1, 1, 1, 1);
Utils.drawTexturedRect(
- guiLeft - 88 - 2 - 22,
+ guiLeft - 88 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0),
guiTop + 2,
88,
20,
@@ -335,7 +398,7 @@ public class GuiInvButtonEditor extends GuiScreen {
GL11.GL_NEAREST
);
Utils.drawTexturedRect(
- guiLeft - 88 - 2 - 22,
+ guiLeft - 88 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0),
guiTop + 2 + 24,
88,
20,
@@ -348,7 +411,7 @@ public class GuiInvButtonEditor extends GuiScreen {
Utils.drawStringCenteredScaledMaxWidth(
"Load preset",
fontRendererObj,
- guiLeft - 44 - 2 - 22,
+ guiLeft - 44 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0),
guiTop + 8,
false,
86,
@@ -357,7 +420,7 @@ public class GuiInvButtonEditor extends GuiScreen {
Utils.drawStringCenteredScaledMaxWidth(
"from Clipboard",
fontRendererObj,
- guiLeft - 44 - 2 - 22,
+ guiLeft - 44 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0),
guiTop + 16,
false,
86,
@@ -366,7 +429,7 @@ public class GuiInvButtonEditor extends GuiScreen {
Utils.drawStringCenteredScaledMaxWidth(
"Save preset",
fontRendererObj,
- guiLeft - 44 - 2 - 22,
+ guiLeft - 44 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0),
guiTop + 8 + 24,
false,
86,
@@ -375,7 +438,7 @@ public class GuiInvButtonEditor extends GuiScreen {
Utils.drawStringCenteredScaledMaxWidth(
"to Clipboard",
fontRendererObj,
- guiLeft - 44 - 2 - 22,
+ guiLeft - 44 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0),
guiTop + 16 + 24,
false,
86,
@@ -383,7 +446,7 @@ public class GuiInvButtonEditor extends GuiScreen {
);
if (!validShareContents()) {
- Gui.drawRect(guiLeft - 88 - 2 - 22, guiTop + 2, guiLeft - 2 - 22, guiTop + 2 + 20, 0x80000000);
+ Gui.drawRect(guiLeft - 88 - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0), guiTop + 2, guiLeft - 2 - 22 - (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud ? 25 : 0), guiTop + 2 + 20, 0x80000000);
}
GlStateManager.color(1, 1, 1, 1);
@@ -427,6 +490,17 @@ public class GuiInvButtonEditor extends GuiScreen {
y += ySize;
}
+ if (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
+ x -= 25;
+ }
+ }
+ if (NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
+ x -= 25;
+ }
+ }
+
GlStateManager.translate(0, 0, 300);
editorLeft = x + 8 - editorXSize / 2;
editorTop = y + 18 + 2;
@@ -707,6 +781,17 @@ public class GuiInvButtonEditor extends GuiScreen {
y += ySize;
}
+ if (NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop && y < guiTop + 84) {
+ x -= 25;
+ }
+ }
+ if (NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay) {
+ if (x < guiLeft + xSize - 150 && x > guiLeft + xSize - 200 && y > guiTop + 60 && y < guiTop + 120) {
+ x -= 25;
+ }
+ }
+
if (mouseX >= x && mouseY >= y &&
mouseX <= x + 18 && mouseY <= y + 18) {
if (editingButton == button) {
@@ -826,6 +911,11 @@ public class GuiInvButtonEditor extends GuiScreen {
private final ExecutorService searchES = Executors.newSingleThreadExecutor();
private final AtomicInteger searchId = new AtomicInteger(0);
+ @Override
+ public void onGuiClosed() {
+ NotEnoughUpdates.INSTANCE.saveConfig();
+ }
+
public void search() {
final int thisSearchId = searchId.incrementAndGet();
final String searchString = iconTextField.getText();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemCustomize.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemCustomize.java
index 222a0f88..7d541296 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemCustomize.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemCustomize.java
@@ -1,7 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.collect.Lists;
-import io.github.moulberry.notenoughupdates.core.*;
+import io.github.moulberry.notenoughupdates.core.ChromaColour;
+import io.github.moulberry.notenoughupdates.core.GlScissorStack;
+import io.github.moulberry.notenoughupdates.core.GuiElement;
+import io.github.moulberry.notenoughupdates.core.GuiElementBoolean;
+import io.github.moulberry.notenoughupdates.core.GuiElementColour;
+import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingFloat;
import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
@@ -199,6 +223,7 @@ public class GuiItemCustomize extends GuiScreen {
EnumChatFormatting.GREEN + "",
EnumChatFormatting.GREEN + "Type \"&&\" to use colour codes",
EnumChatFormatting.GREEN + "Type \"**\" for \u272A",
+ EnumChatFormatting.GREEN + "Type \"*1-9\" for \u278A-\u2792",
EnumChatFormatting.GREEN + "",
EnumChatFormatting.GREEN + "Available colour codes:",
Utils.chromaString("\u00B6z = Chroma"),
@@ -355,8 +380,6 @@ public class GuiItemCustomize extends GuiScreen {
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
- Keyboard.enableRepeatEvents(true);
-
if (textFieldRename.getFocus()) {
if (keyCode == Keyboard.KEY_ESCAPE) {
textFieldRename.setFocus(false);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
index 63a4d6d8..e06c271f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiItemRecipe.java
@@ -1,17 +1,39 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.collect.ImmutableList;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.recipes.NeuRecipe;
import io.github.moulberry.notenoughupdates.recipes.RecipeSlot;
+import io.github.moulberry.notenoughupdates.recipes.RecipeType;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.input.Keyboard;
@@ -21,52 +43,79 @@ import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class GuiItemRecipe extends GuiScreen {
public static final ResourceLocation resourcePacksTexture = new ResourceLocation("textures/gui/resource_packs.png");
+ public static final ResourceLocation tabsTexture = new ResourceLocation("notenoughupdates", "textures/gui/tab.png");
public static final int SLOT_SIZE = 16;
public static final int SLOT_SPACING = SLOT_SIZE + 2;
public static final int BUTTON_WIDTH = 7;
public static final int BUTTON_HEIGHT = 11;
- public static final int BUTTON_POSITION_Y = 63;
- public static final int BUTTON_POSITION_LEFT_X = 110;
- public static final int BUTTON_POSITION_RIGHT_X = 147;
- public static final int PAGE_STRING_X = 132;
- public static final int PAGE_STRING_Y = 69;
public static final int TITLE_X = 28;
public static final int TITLE_Y = 6;
public static final int HOTBAR_SLOT_X = 8;
- public static final int HOTBAR_SLOT_Y = 142;
+ public static final int HOTBAR_SLOT_Y = 197;
public static final int PLAYER_INVENTORY_X = 8;
- public static final int PLAYER_INVENTORY_Y = 84;
+ public static final int PLAYER_INVENTORY_Y = 140;
+ public static final int TAB_POS_X = -26;
+ public static final int TAB_POS_Y = 8;
+ public static final int TAB_OFFSET_Y = 30;
+ public static final int TAB_SIZE_X = 26;
+ public static final int TAB_SIZE_Y = 30;
+ public static final int TAB_TEXTURE_SIZE_X = 29;
private int currentIndex = 0;
+ private int currentTab = 0;
- private final String title;
- private final List<NeuRecipe> craftingRecipes;
+ private final Map<RecipeType, List<NeuRecipe>> craftingRecipes = new HashMap<>();
+ private final List<RecipeType> tabs = new ArrayList<>();
private final NEUManager manager;
public int guiLeft = 0;
public int guiTop = 0;
public int xSize = 176;
- public int ySize = 166;
+ public int ySize = 222;
- public GuiItemRecipe(String title, List<NeuRecipe> craftingRecipes, NEUManager manager) {
- this.craftingRecipes = craftingRecipes;
+ public GuiItemRecipe(List<NeuRecipe> unsortedRecipes, NEUManager manager) {
this.manager = manager;
- this.title = title;
+
+ for (NeuRecipe recipe : unsortedRecipes) {
+ craftingRecipes.computeIfAbsent(recipe.getType(), ignored -> new ArrayList<>()).add(recipe);
+ if (!tabs.contains(recipe.getType()))
+ tabs.add(recipe.getType());
+ }
+ changeRecipe(0, 0);
+ }
+
+ @Override
+ public void initGui() {
+ this.guiLeft = (width - this.xSize) / 2;
+ this.guiTop = (height - this.ySize) / 2;
}
public NeuRecipe getCurrentRecipe() {
- currentIndex = MathHelper.clamp_int(currentIndex, 0, craftingRecipes.size());
- return craftingRecipes.get(currentIndex);
+ List<NeuRecipe> currentRecipes = getCurrentRecipeList();
+ currentIndex = MathHelper.clamp_int(currentIndex, 0, currentRecipes.size() - 1);
+ return currentRecipes.get(currentIndex);
+ }
+
+ public List<NeuRecipe> getCurrentRecipeList() {
+ return craftingRecipes.get(getCurrentTab());
+ }
+
+ public RecipeType getCurrentTab() {
+ currentTab = MathHelper.clamp_int(currentTab, 0, tabs.size() - 1);
+ return tabs.get(currentTab);
}
public boolean isWithinRect(int x, int y, int topLeftX, int topLeftY, int width, int height) {
- return topLeftX <= x && x <= topLeftX + width
- && topLeftY <= y && y <= topLeftY + height;
+ return topLeftX <= x && x < topLeftX + width
+ && topLeftY <= y && y < topLeftY + height;
}
private ImmutableList<RecipeSlot> getAllRenderedSlots() {
@@ -80,9 +129,6 @@ public class GuiItemRecipe extends GuiScreen {
drawDefaultBackground();
FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj;
- this.guiLeft = (width - this.xSize) / 2;
- this.guiTop = (height - this.ySize) / 2;
-
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
NeuRecipe currentRecipe = getCurrentRecipe();
@@ -90,17 +136,19 @@ public class GuiItemRecipe extends GuiScreen {
Minecraft.getMinecraft().getTextureManager().bindTexture(currentRecipe.getBackground());
this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, this.xSize, this.ySize);
+ drawTabs();
+
currentRecipe.drawExtraBackground(this, mouseX, mouseY);
List<RecipeSlot> slots = getAllRenderedSlots();
for (RecipeSlot slot : slots) {
- Utils.drawItemStack(slot.getItemStack(), slot.getX(this), slot.getY(this));
+ Utils.drawItemStack(slot.getItemStack(), slot.getX(this), slot.getY(this), true);
}
- if (craftingRecipes.size() > 1) drawArrows(mouseX, mouseY);
+ drawArrows(currentRecipe, mouseX, mouseY);
Utils.drawStringScaledMaxWidth(
- title,
+ currentRecipe.getTitle(),
fontRendererObj,
guiLeft + TITLE_X,
guiTop + TITLE_Y,
@@ -110,7 +158,7 @@ public class GuiItemRecipe extends GuiScreen {
);
currentRecipe.drawExtraInfo(this, mouseX, mouseY);
-
+ super.drawScreen(mouseX, mouseY, partialTicks);
for (RecipeSlot slot : slots) {
if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) {
if (slot.getItemStack() == null) continue;
@@ -126,42 +174,104 @@ public class GuiItemRecipe extends GuiScreen {
}
}
currentRecipe.drawHoverInformation(this, mouseX, mouseY);
+ drawTabHoverInformation(mouseX, mouseY);
+ }
+
+ private void drawTabHoverInformation(int mouseX, int mouseY) {
+ if (tabs.size() < 2) return;
+ for (int i = 0; i < tabs.size(); i++) {
+ if (isWithinRect(
+ mouseX - guiLeft,
+ mouseY - guiTop,
+ TAB_POS_X,
+ TAB_POS_Y + TAB_OFFSET_Y * i,
+ TAB_SIZE_X,
+ TAB_SIZE_Y
+ )) {
+ RecipeType type = tabs.get(i);
+ Utils.drawHoveringText(
+ Arrays.asList(
+ "" + EnumChatFormatting.RESET + EnumChatFormatting.GREEN + type.getLabel(),
+ "" + EnumChatFormatting.RESET + EnumChatFormatting.GRAY + craftingRecipes.get(type).size() + " Recipes"
+ ),
+ mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj
+ );
+ return;
+ }
+ }
+ }
+
+ private void drawTabs() {
+ if (tabs.size() < 2) return;
+ for (int i = 0; i < tabs.size(); i++) {
+ RecipeType recipeType = tabs.get(i);
+ int tabPosX = guiLeft + TAB_POS_X, tabPosY = guiTop + TAB_OFFSET_Y * i + TAB_POS_Y;
+ int textureOffset = 0;
+ if (currentTab == i) {
+ textureOffset = 30;
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(tabsTexture);
+ drawTexturedModalRect(
+ tabPosX, tabPosY,
+ 0, textureOffset,
+ TAB_TEXTURE_SIZE_X, TAB_SIZE_Y
+ );
+ Utils.drawItemStack(recipeType.getIcon(), tabPosX + 7, tabPosY + 7);
+ }
}
- private void drawArrows(int mouseX, int mouseY) {
+ public static final int BUTTON_POSITION_RIGHT_OFFSET_X = 37;
+ public static final int PAGE_STRING_OFFSET_X = 22;
+ public static final int PAGE_STRING_OFFSET_Y = 6;
+
+ private void drawArrows(
+ NeuRecipe currentRecipe,
+ int mouseX,
+ int mouseY
+ ) {
+ int recipeCount = getCurrentRecipeList().size();
+ if (recipeCount < 2) return;
+ int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner();
+ int buttonPositionLeftX = topLeft[0];
+ int buttonPositionRightX = buttonPositionLeftX + BUTTON_POSITION_RIGHT_OFFSET_X;
+ int pageStringX = buttonPositionLeftX + PAGE_STRING_OFFSET_X;
+ int buttonPositionY = topLeft[1];
+ int pageStringY = buttonPositionY + PAGE_STRING_OFFSET_Y;
+
boolean leftSelected = isWithinRect(
mouseX - guiLeft,
mouseY - guiTop,
- BUTTON_POSITION_LEFT_X,
- BUTTON_POSITION_Y,
+ buttonPositionLeftX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
);
boolean rightSelected = isWithinRect(
mouseX - guiLeft,
mouseY - guiTop,
- BUTTON_POSITION_RIGHT_X,
- BUTTON_POSITION_Y,
+ buttonPositionRightX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
);
-
Minecraft.getMinecraft().getTextureManager().bindTexture(resourcePacksTexture);
- Utils.drawTexturedRect(guiLeft + BUTTON_POSITION_LEFT_X, guiTop + BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT,
- 34 / 256f, 48 / 256f,
- leftSelected ? 37 / 256f : 5 / 256f, leftSelected ? 59 / 256f : 27 / 256f
- );
- Utils.drawTexturedRect(guiLeft + BUTTON_POSITION_RIGHT_X, guiTop + BUTTON_POSITION_Y, BUTTON_WIDTH, BUTTON_HEIGHT,
- 10 / 256f, 24 / 256f,
- rightSelected ? 37 / 256f : 5 / 256f, rightSelected ? 59 / 256f : 27 / 256f
- );
+ if (currentIndex != 0)
+ Utils.drawTexturedRect(guiLeft + buttonPositionLeftX, guiTop + buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT,
+ 34 / 256f, 48 / 256f,
+ leftSelected ? 37 / 256f : 5 / 256f, leftSelected ? 59 / 256f : 27 / 256f
+ );
+ if (currentIndex != recipeCount - 1)
+ Utils.drawTexturedRect(guiLeft + buttonPositionRightX, guiTop + buttonPositionY, BUTTON_WIDTH, BUTTON_HEIGHT,
+ 10 / 256f, 24 / 256f,
+ rightSelected ? 37 / 256f : 5 / 256f, rightSelected ? 59 / 256f : 27 / 256f
+ );
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
- String selectedPage = (currentIndex + 1) + "/" + craftingRecipes.size();
+ String selectedPage = (currentIndex + 1) + "/" + recipeCount;
Utils.drawStringCenteredScaledMaxWidth(selectedPage, fontRendererObj,
- guiLeft + PAGE_STRING_X, guiTop + PAGE_STRING_Y, false, 24, Color.BLACK.getRGB()
+ guiLeft + pageStringX, guiTop + pageStringY, false, 24, Color.BLACK.getRGB()
);
}
@@ -196,12 +306,12 @@ public class GuiItemRecipe extends GuiScreen {
int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
int keyPressed = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
-
+ if (Keyboard.getEventKeyState()) return;
for (RecipeSlot slot : getAllRenderedSlots()) {
if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) {
ItemStack itemStack = slot.getItemStack();
- if (keyPressed == manager.keybindViewRecipe.getKeyCode()) { // TODO: rework this so it doesnt skip recipe chains
- manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), "");
+ if (keyPressed == manager.keybindViewRecipe.getKeyCode()) {
+ manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack));
} else if (keyPressed == manager.keybindViewUsages.getKeyCode()) {
manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack));
}
@@ -209,19 +319,37 @@ public class GuiItemRecipe extends GuiScreen {
}
}
+ public void changeRecipe(int tabIndex, int recipeIndex) {
+ buttonList.removeAll(getCurrentRecipe().getExtraButtons(this));
+ currentTab = tabIndex;
+ currentIndex = recipeIndex;
+ buttonList.addAll(getCurrentRecipe().getExtraButtons(this));
+ }
+
+ @Override
+ protected void actionPerformed(GuiButton p_actionPerformed_1_) throws IOException {
+ getCurrentRecipe().actionPerformed(p_actionPerformed_1_);
+ }
+
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton);
+ NeuRecipe currentRecipe = getCurrentRecipe();
+ int[] topLeft = currentRecipe.getPageFlipPositionLeftTopCorner();
+ int buttonPositionLeftX = topLeft[0];
+ int buttonPositionRightX = buttonPositionLeftX + BUTTON_POSITION_RIGHT_OFFSET_X;
+ int buttonPositionY = topLeft[1];
if (isWithinRect(
mouseX - guiLeft,
mouseY - guiTop,
- BUTTON_POSITION_LEFT_X,
- BUTTON_POSITION_Y,
+ buttonPositionLeftX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
- )) {
- currentIndex = currentIndex == 0 ? 0 : currentIndex - 1;
+ ) &&
+ currentIndex > 0) {
+ changeRecipe(currentTab, currentIndex - 1);
Utils.playPressSound();
return;
}
@@ -229,25 +357,45 @@ public class GuiItemRecipe extends GuiScreen {
if (isWithinRect(
mouseX - guiLeft,
mouseY - guiTop,
- BUTTON_POSITION_RIGHT_X,
- BUTTON_POSITION_Y,
+ buttonPositionRightX,
+ buttonPositionY,
BUTTON_WIDTH,
BUTTON_HEIGHT
- )) {
- currentIndex = currentIndex == craftingRecipes.size() - 1 ? currentIndex : currentIndex + 1;
+ ) &&
+ currentIndex < getCurrentRecipeList().size()) {
+ changeRecipe(currentTab, currentIndex + 1);
Utils.playPressSound();
return;
}
+ for (int i = 0; i < tabs.size(); i++) {
+ if (isWithinRect(
+ mouseX - guiLeft,
+ mouseY - guiTop,
+ TAB_POS_X,
+ TAB_POS_Y + TAB_OFFSET_Y * i,
+ TAB_SIZE_X,
+ TAB_SIZE_Y
+ )) {
+ changeRecipe(i, currentIndex);
+ Utils.playPressSound();
+ return;
+ }
+ }
+
for (RecipeSlot slot : getAllRenderedSlots()) {
if (isWithinRect(mouseX, mouseY, slot.getX(this), slot.getY(this), SLOT_SIZE, SLOT_SIZE)) {
ItemStack itemStack = slot.getItemStack();
if (mouseButton == 0) {
- manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack), "");
+ manager.displayGuiItemRecipe(manager.getInternalNameForItem(itemStack));
+ return;
} else if (mouseButton == 1) {
manager.displayGuiItemUsages(manager.getInternalNameForItem(itemStack));
+ return;
}
}
}
+
+ currentRecipe.mouseClicked(this, mouseX, mouseY, mouseButton);
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiNavigation.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiNavigation.java
new file mode 100644
index 00000000..dcb1344c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiNavigation.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.util.ResourceLocation;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class GuiNavigation extends GuiScreen {
+
+ public static ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/navigation.png"
+ );
+
+ public static final int PIN_POSITION_U = 182;
+ public static final int PIN_POSITION_V = 3;
+ public static final int TICK_POSITION_U = 182;
+ public static final int TICK_POSITION_V = 34;
+ public static final int ICON_SIZE = 26;
+
+ public static final int SEARCH_BAR_X = 14;
+ public static final int SEARCH_BAR_Y = 11;
+ public static final int SEARCH_BAR_WIDTH = 151;
+ public static final int SEARCH_BAR_HEIGHT = 24;
+
+ public static final int LIST_START_X = 14;
+ public static final int LIST_START_Y = 43;
+ public static final int LIST_OFFSET_Y = 28;
+ public static final int TEXT_OFFSET_X = 28;
+ public static final int LIST_COUNT = 6;
+
+ List<String> searchResults = new ArrayList<>();
+
+ public int xSize = 176;
+ public int ySize = 222;
+ public int guiLeft, guiTop;
+
+ public GuiElementTextField textField = new GuiElementTextField("", SEARCH_BAR_WIDTH, SEARCH_BAR_HEIGHT, 0);
+
+ @Override
+ public void initGui() {
+ super.initGui();
+ NotEnoughUpdates.INSTANCE.config.hidden.hasOpenedWaypointMenu = true;
+ guiLeft = (width - xSize) / 2;
+ guiTop = (height - ySize) / 2;
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ drawDefaultBackground();
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ this.drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
+ textField.render(guiLeft + SEARCH_BAR_X, guiTop + SEARCH_BAR_Y);
+
+ refreshResults();
+ for (int i = 0; i < LIST_COUNT; i++) {
+ if (i < searchResults.size()) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ String name = searchResults.get(i);
+ JsonObject json = NotEnoughUpdates.INSTANCE.navigation.getWaypoints().get(name);
+ boolean selected = name.equals(NotEnoughUpdates.INSTANCE.navigation.getInternalname());
+ int baseX = guiLeft + LIST_START_X;
+ int baseY = guiTop + LIST_START_Y + LIST_OFFSET_Y * i;
+
+ GlStateManager.color(1F, 1F, 1F);
+ drawTexturedModalRect(
+ baseX,
+ baseY,
+ selected ? TICK_POSITION_U : PIN_POSITION_U, selected ? TICK_POSITION_V : PIN_POSITION_V,
+ ICON_SIZE, ICON_SIZE
+ );
+ Utils.drawStringF(
+ json.get("displayname").getAsString(),
+ Minecraft.getMinecraft().fontRendererObj,
+ baseX + TEXT_OFFSET_X,
+ baseY + LIST_OFFSET_Y / 2F - Minecraft.getMinecraft().fontRendererObj.FONT_HEIGHT / 2F,
+ false,
+ 0x000000
+ );
+ }
+ }
+ }
+
+ private void refreshResults() {
+ String text = textField.getText().toLowerCase();
+ List<String> results = NotEnoughUpdates.INSTANCE.navigation
+ .getWaypoints()
+ .values()
+ .stream()
+ .filter(it ->
+ it.get("internalname").getAsString().toLowerCase().contains(text)
+ || it.get("displayname").getAsString().toLowerCase().contains(text))
+ .map(it -> it.get("internalname").getAsString())
+ .sorted(Comparator.comparing(String::length)
+ .thenComparing(String.CASE_INSENSITIVE_ORDER))
+ .collect(Collectors.toList());
+
+ String internalname = NotEnoughUpdates.INSTANCE.navigation.getInternalname();
+ if (internalname != null) {
+ results.remove(internalname);
+ results.add(0, internalname);
+ }
+ searchResults = results;
+ }
+
+ @Override
+ protected void keyTyped(char p_keyTyped_1_, int p_keyTyped_2_) throws IOException {
+ super.keyTyped(p_keyTyped_1_, p_keyTyped_2_);
+ textField.keyTyped(p_keyTyped_1_, p_keyTyped_2_);
+ }
+
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ super.mouseClicked(mouseX, mouseY, mouseButton);
+ if (Utils.isWithinRect(
+ mouseX,
+ mouseY,
+ guiLeft + SEARCH_BAR_X,
+ guiTop + SEARCH_BAR_Y,
+ SEARCH_BAR_WIDTH,
+ SEARCH_BAR_HEIGHT
+ )) {
+ textField.mouseClicked(mouseX, mouseY, mouseButton);
+ } else {
+ textField.setFocus(false);
+ }
+ for (int i = 0; i < LIST_COUNT; i++) {
+ if (i < searchResults.size()) {
+ int baseX = guiLeft + LIST_START_X;
+ int baseY = guiTop + LIST_START_Y + LIST_OFFSET_Y * i;
+ if (Utils.isWithinRect(mouseX, mouseY, baseX, baseY, ICON_SIZE, ICON_SIZE)) {
+ String thing = searchResults.get(i);
+ boolean selected = thing.equals(NotEnoughUpdates.INSTANCE.navigation.getInternalname());
+ if (selected) {
+ NotEnoughUpdates.INSTANCE.navigation.untrackWaypoint();
+ } else {
+ NotEnoughUpdates.INSTANCE.navigation.trackWaypoint(thing);
+ }
+ Utils.playPressSound();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
index 3955b35f..71a23ffb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/GuiPriceGraph.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.reflect.TypeToken;
@@ -17,14 +36,26 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@@ -36,11 +67,11 @@ public class GuiPriceGraph extends GuiScreen {
private final ResourceLocation TEXTURE;
private static final int X_SIZE = 364;
private static final int Y_SIZE = 215;
- private Data dataPoints;
- private float highestValue;
+ private ItemData itemData;
+ private double highestValue;
private long firstTime;
private long lastTime;
- private Float lowestValue = null;
+ private Double lowestValue = null;
private String itemName;
private final String itemId;
private int guiLeft;
@@ -117,27 +148,27 @@ public class GuiPriceGraph extends GuiScreen {
Utils.drawStringCentered("Loading...", Minecraft.getMinecraft().fontRendererObj,
guiLeft + 166, guiTop + 116, false, 0xffffff00
);
- else if (dataPoints == null || dataPoints.get() == null || dataPoints.get().size() <= 1)
+ else if (
+ itemData == null || itemData.get() == null || itemData.get().size() <= 1 || lowestValue == null)
Utils.drawStringCentered("No data found.", Minecraft.getMinecraft().fontRendererObj,
guiLeft + 166, guiTop + 116, false, 0xffff0000
);
else {
-
int graphColor = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.ahGraph.graphColor);
int graphColor2 = SpecialColour.specialToChromaRGB(NotEnoughUpdates.INSTANCE.config.ahGraph.graphColor2);
Integer lowestDist = null;
Long lowestDistTime = null;
HashMap<Integer, Integer> secondLineData = new HashMap<>();
- for (int i = (dataPoints.isBz() ? 1 : 0); i >= 0; i--) {
+ for (int i = (itemData.isBz() ? 1 : 0); i >= 0; i--) {
Utils.drawGradientRect(0, guiLeft + 17, guiTop + 35, guiLeft + 315, guiTop + 198,
changeAlpha(i == 0 ? graphColor : graphColor2, 120), changeAlpha(i == 0 ? graphColor : graphColor2, 10)
);
Integer prevX = null;
Integer prevY = null;
- for (Long time : dataPoints.get().keySet()) {
- float price = dataPoints.isBz()
- ? i == 0 ? dataPoints.bz.get(time).b : dataPoints.bz.get(time).s
- : dataPoints.ah.get(time);
+ for (Long time : itemData.get().keySet()) {
+ double price = itemData.isBz()
+ ? i == 0 ? itemData.bz.get(time).b : itemData.bz.get(time).s
+ : itemData.ah.get(time);
int xPos = (int) map(time, firstTime, lastTime, guiLeft + 17, guiLeft + 315);
int yPos = (int) map(price, highestValue + 10d, lowestValue - 10d, guiTop + 35, guiTop + 198);
if (prevX != null) {
@@ -160,7 +191,7 @@ public class GuiPriceGraph extends GuiScreen {
);
if (i == 0) {
Utils.drawLine(prevX, prevY + 0.5f, xPos, yPos + 0.5f, 2, graphColor);
- if (dataPoints.isBz())
+ if (itemData.isBz())
Utils.drawLine(
prevX,
secondLineData.get(prevX) + 0.5f,
@@ -219,8 +250,8 @@ public class GuiPriceGraph extends GuiScreen {
Utils.drawDottedLine(customStart, guiTop + 197, customEnd, guiTop + 197, 2, 10, 0xFFc6c6c6);
}
if (lowestDist != null && !customSelecting) {
- float price = dataPoints.isBz() ? dataPoints.bz.get(lowestDistTime).b : dataPoints.ah.get(lowestDistTime);
- Float price2 = dataPoints.isBz() ? dataPoints.bz.get(lowestDistTime).s : null;
+ double price = itemData.isBz() ? itemData.bz.get(lowestDistTime).b : itemData.ah.get(lowestDistTime);
+ Float price2 = itemData.isBz() ? itemData.bz.get(lowestDistTime).s : null;
int xPos = (int) map(lowestDistTime, firstTime, lastTime, guiLeft + 17, guiLeft + 315);
int yPos = (int) map(price, highestValue + 10d, lowestValue - 10d, guiTop + 35, guiTop + 198);
int yPos2 = price2 != null
@@ -244,7 +275,7 @@ public class GuiPriceGraph extends GuiScreen {
NumberFormat nf = NumberFormat.getInstance();
ArrayList<String> text = new ArrayList<>();
text.add(displayFormat.format(date));
- if (dataPoints.isBz()) {
+ if (itemData.isBz()) {
text.add(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "Bazaar Insta-Buy: " +
EnumChatFormatting.GOLD + EnumChatFormatting.BOLD + nf.format(price));
text.add(EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "Bazaar Insta-Sell: " +
@@ -321,7 +352,7 @@ public class GuiPriceGraph extends GuiScreen {
}
private void loadData() {
- dataPoints = null;
+ itemData = null;
loaded = false;
new Thread(() -> {
File dir = new File("config/notenoughupdates/prices");
@@ -330,46 +361,46 @@ public class GuiPriceGraph extends GuiScreen {
return;
}
File[] files = dir.listFiles();
- Data data = new Data();
+ ItemData itemData = new ItemData();
if (files == null) return;
for (File file : files) {
if (!file.getName().endsWith(".gz")) continue;
- HashMap<String, Data> data2 = load(file);
+ HashMap<String, ItemData> data2 = load(file);
if (data2 == null || !data2.containsKey(itemId)) continue;
if (data2.get(itemId).isBz()) {
- if (data.bz == null) data.bz = data2.get(itemId).bz;
- else data.bz.putAll(data2.get(itemId).bz);
- } else if (data.ah == null) data.ah = data2.get(itemId).ah;
- else data.ah.putAll(data2.get(itemId).ah);
+ if (itemData.bz == null) itemData.bz = data2.get(itemId).bz;
+ else itemData.bz.putAll(data2.get(itemId).bz);
+ } else if (itemData.ah == null) itemData.ah = data2.get(itemId).ah;
+ else itemData.ah.putAll(data2.get(itemId).ah);
}
- if (data.get() != null && !data.get().isEmpty()) {
+ if (itemData.get() != null && !itemData.get().isEmpty()) {
if (mode < 3)
- data = new Data(
- new TreeMap<>(data.get().entrySet().stream()
- .filter(e -> e.getKey() > System.currentTimeMillis() / 1000 -
- (mode == 0 ? 3600 : mode == 1 ? 86400 : 604800))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
- data.isBz()
+ itemData = new ItemData(
+ new TreeMap<>(itemData.get().entrySet().stream()
+ .filter(e -> e.getKey() > System.currentTimeMillis() / 1000 -
+ (mode == 0 ? 3600 : mode == 1 ? 86400 : 604800))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
+ itemData.isBz()
);
else if (mode == 4)
- data = new Data(
- new TreeMap<>(data.get().entrySet().stream()
- .filter(e -> e.getKey() >= customStart && e.getKey() <= customEnd)
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
- data.isBz()
+ itemData = new ItemData(
+ new TreeMap<>(itemData.get().entrySet().stream()
+ .filter(e -> e.getKey() >= customStart && e.getKey() <= customEnd)
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))),
+ itemData.isBz()
);
- if (data.get() == null || data.get().isEmpty()) {
+ if (itemData.get() == null || itemData.get().isEmpty()) {
loaded = true;
return;
}
- dataPoints = trimData(data);
- firstTime = dataPoints.get().firstKey();
- lastTime = dataPoints.get().lastKey();
+ this.itemData = trimData(itemData);
+ firstTime = this.itemData.get().firstKey();
+ lastTime = this.itemData.get().lastKey();
highestValue = 0;
lowestValue = null;
- for (long key : dataPoints.get().keySet()) {
- float value1 = dataPoints.isBz() ? dataPoints.bz.get(key).b : dataPoints.ah.get(key);
- Float value2 = dataPoints.isBz() ? dataPoints.bz.get(key).s : null;
+ for (long key : this.itemData.get().keySet()) {
+ double value1 = this.itemData.isBz() ? this.itemData.bz.get(key).b : this.itemData.ah.get(key);
+ Float value2 = this.itemData.isBz() ? this.itemData.bz.get(key).s : null;
if (value1 > highestValue) {
highestValue = value1;
}
@@ -380,7 +411,7 @@ public class GuiPriceGraph extends GuiScreen {
lowestValue = value1;
}
if (value2 != null && value2 < lowestValue) {
- lowestValue = value2;
+ lowestValue = Double.valueOf(value2);
}
}
}
@@ -399,37 +430,19 @@ public class GuiPriceGraph extends GuiScreen {
if (!file.getName().endsWith(".gz")) continue;
if (file.lastModified() <
System.currentTimeMillis() - NotEnoughUpdates.INSTANCE.config.ahGraph.dataRetention * 86400000L)
+ //noinspection ResultOfMethodCallIgnored
file.delete();
}
Date date = new Date();
Long epochSecond = date.toInstant().getEpochSecond();
File file = new File(dir, "prices_" + format.format(date) + ".gz");
- HashMap<String, Data> prices = new HashMap<>();
- if (file.exists())
- prices = load(file);
- if (prices == null) return;
+ HashMap<String, ItemData> prices = new HashMap<>();
+ if (file.exists()) {
+ HashMap<String, ItemData> tempPrices = load(file);
+ if (tempPrices != null) prices = tempPrices;
+ }
for (Map.Entry<String, JsonElement> item : items.entrySet()) {
- if (prices.containsKey(item.getKey())) {
- if (bazaar && item.getValue().getAsJsonObject().has("curr_buy") && item.getValue().getAsJsonObject().has(
- "curr_sell"))
- prices.get(item.getKey()).bz.put(epochSecond, new BzData(
- item.getValue().getAsJsonObject().get("curr_buy").getAsFloat(),
- item.getValue().getAsJsonObject().get("curr_sell").getAsFloat()
- ));
- else if (!bazaar)
- prices.get(item.getKey()).ah.put(epochSecond, item.getValue().getAsInt());
- } else {
- TreeMap<Long, Object> mapData = new TreeMap<>();
- if (bazaar && item.getValue().getAsJsonObject().has("curr_buy") && item.getValue().getAsJsonObject().has(
- "curr_sell"))
- mapData.put(epochSecond, new BzData(
- item.getValue().getAsJsonObject().get("curr_buy").getAsFloat(),
- item.getValue().getAsJsonObject().get("curr_sell").getAsFloat()
- ));
- else if (!bazaar)
- mapData.put(epochSecond, item.getValue().getAsLong());
- prices.put(item.getKey(), new Data(mapData, bazaar));
- }
+ addOrUpdateItemPriceInfo(item, prices, epochSecond, bazaar);
}
//noinspection ResultOfMethodCallIgnored
file.createNewFile();
@@ -446,16 +459,71 @@ public class GuiPriceGraph extends GuiScreen {
}
}
- private Data trimData(Data data) {
- long first = data.get().firstKey();
- long last = data.get().lastKey();
- Data trimmed = new Data();
- if (data.isBz())
+ private static void addOrUpdateItemPriceInfo(
+ Map.Entry<String, JsonElement> item,
+ HashMap<String, ItemData> prices,
+ long timestamp,
+ boolean bazaar
+ ) {
+ String itemName = item.getKey();
+ ItemData existingItemData = null;
+ if (prices.containsKey(itemName)) {
+ existingItemData = prices.get(itemName);
+ }
+
+ // Handle transitions from ah to bz (the other direction typically doesn't happen)
+ if (existingItemData != null) {
+ if (existingItemData.isBz() && !bazaar) {
+ return;
+ }
+
+ if (!existingItemData.isBz() && bazaar) {
+ prices.remove(itemName);
+ existingItemData = null;
+ }
+ }
+
+ if (bazaar) {
+ if (!item.getValue().getAsJsonObject().has("curr_buy") ||
+ !item.getValue().getAsJsonObject().has("curr_sell")
+ ) {
+ return;
+ }
+
+ BzData bzData = new BzData(
+ item.getValue().getAsJsonObject().get("curr_buy").getAsFloat(),
+ item.getValue().getAsJsonObject().get("curr_sell").getAsFloat()
+ );
+
+ if (existingItemData != null) {
+ existingItemData.bz.put(timestamp, bzData);
+ } else {
+ TreeMap<Long, Object> mapData = new TreeMap<>();
+ mapData.put(timestamp, bzData);
+ prices.put(item.getKey(), new ItemData(mapData, true));
+ }
+ } else {
+ if (existingItemData != null) {
+ prices.get(item.getKey()).ah.put(timestamp, item.getValue().getAsBigDecimal().longValue());
+ } else {
+ TreeMap<Long, Object> mapData = new TreeMap<>();
+ mapData.put(timestamp, item.getValue().getAsLong());
+ prices.put(item.getKey(), new ItemData(mapData, false));
+ }
+ }
+ }
+
+ private ItemData trimData(ItemData itemData) {
+ long first = itemData.get().firstKey();
+ long last = itemData.get().lastKey();
+ ItemData trimmed = new ItemData();
+ if (itemData.isBz())
trimmed.bz = new TreeMap<>();
else
trimmed.ah = new TreeMap<>();
int zones = NotEnoughUpdates.INSTANCE.config.ahGraph.graphZones;
- Long[] dataArray = !data.isBz() ? data.ah.keySet().toArray(new Long[0]) : data.bz.keySet().toArray(new Long[0]);
+ Long[] dataArray =
+ !itemData.isBz() ? itemData.ah.keySet().toArray(new Long[0]) : itemData.bz.keySet().toArray(new Long[0]);
int prev = 0;
for (int i = 0; i < zones; i++) {
long lowest = (long) map(i, 0, zones, first, last);
@@ -466,24 +534,24 @@ public class GuiPriceGraph extends GuiScreen {
for (int l = prev; l < dataArray.length; l++) {
if (dataArray[l] >= lowest && dataArray[l] <= highest) {
amount++;
- sumBuy += data.isBz() ? data.bz.get(dataArray[l]).b : data.ah.get(dataArray[l]);
- if (data.isBz()) sumSell += data.bz.get(dataArray[l]).s;
+ sumBuy += itemData.isBz() ? itemData.bz.get(dataArray[l]).b : itemData.ah.get(dataArray[l]);
+ if (itemData.isBz()) sumSell += itemData.bz.get(dataArray[l]).s;
prev = l + 1;
} else if (dataArray[l] > highest)
break;
}
if (amount > 0) {
- if (data.isBz())
+ if (itemData.isBz())
trimmed.bz.put(lowest, new BzData((float) (sumBuy / amount), (float) (sumSell / amount)));
else
- trimmed.ah.put(lowest, (int) (sumBuy / amount));
+ trimmed.ah.put(lowest, (long) (sumBuy / amount));
}
}
return trimmed;
}
- private static HashMap<String, Data> load(File file) {
- Type type = new TypeToken<HashMap<String, Data>>() {
+ private static HashMap<String, ItemData> load(File file) {
+ Type type = new TypeToken<HashMap<String, ItemData>>() {
}.getType();
if (file.exists()) {
try (
@@ -493,7 +561,10 @@ public class GuiPriceGraph extends GuiScreen {
))
) {
return GSON.fromJson(reader, type);
- } catch (Exception ignored) {
+ } catch (Exception e) {
+ System.out.println("Deleting " + file.getName() + " because it is probably corrupted.");
+ //noinspection ResultOfMethodCallIgnored
+ file.delete();
}
}
return null;
@@ -521,18 +592,18 @@ public class GuiPriceGraph extends GuiScreen {
}
}
-class Data {
- public TreeMap<Long, Integer> ah = null;
+class ItemData {
+ public TreeMap<Long, Long> ah = null;
public TreeMap<Long, BzData> bz = null;
- public Data() {
+ public ItemData() {
}
- public Data(TreeMap<Long, ?> map, boolean bz) {
+ public ItemData(TreeMap<Long, ?> map, boolean bz) {
if (bz)
this.bz = (TreeMap<Long, BzData>) map;
else
- this.ah = (TreeMap<Long, Integer>) map;
+ this.ah = (TreeMap<Long, Long>) map;
}
public TreeMap<Long, ?> get() {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/InventoryStorageSelector.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/InventoryStorageSelector.java
index 3932c9d5..0abf3f11 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/InventoryStorageSelector.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/InventoryStorageSelector.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/KatSitterOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/KatSitterOverlay.java
index 107d4db2..62aba35b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/KatSitterOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/KatSitterOverlay.java
@@ -1,9 +1,29 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import io.github.moulberry.notenoughupdates.util.Utils;
-import io.github.moulberry.notenoughupdates.util.XPInformation;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.inventory.GuiChest;
@@ -49,8 +69,8 @@ public class KatSitterOverlay {
boolean nextRarityPresent = katSlot.getStack() != null && katSlot.getStack().getItem() != Item.getItemFromBlock(
Blocks.barrier) && upgradedRarity != null;
renderPetInformation(
- (int) XPInformation.getInstance().getPetLevel(petId, xp, rarity),
- nextRarityPresent ? (int) XPInformation.getInstance().getPetLevel(petId, xp, upgradedRarity) : null,
+ (int) GuiProfileViewer.getPetLevel(petId, rarity, (float) xp).level,
+ nextRarityPresent ? (int) GuiProfileViewer.getPetLevel(petId, upgradedRarity, (float) xp).level : null,
gui
);
}
@@ -61,12 +81,23 @@ public class KatSitterOverlay {
int currentWidth = font.getStringWidth(currentText);
String upgradedText = "Upgraded pet level: " + upgradedLevel;
int upgradedWidth = font.getStringWidth(upgradedText);
- int left = gui.guiLeft - 30 - (upgradedLevel == null ? Math.max(upgradedWidth, currentWidth) : currentWidth);
+ int left = ((AccessorGuiContainer) gui).getGuiLeft() - 30 - (upgradedLevel == null ? Math.max(
+ upgradedWidth,
+ currentWidth
+ ) : currentWidth);
GlStateManager.disableLighting();
GlStateManager.color(1F, 1F, 1F, 1F);
- Utils.drawStringScaled(currentText, font, left, gui.guiTop + 25, false, 0xFFD700, 1F);
+ Utils.drawStringScaled(currentText, font, left, ((AccessorGuiContainer) gui).getGuiTop() + 25, false, 0xFFD700, 1F);
if (upgradedLevel != null)
- Utils.drawStringScaled(upgradedText, font, left, gui.guiTop + 45, false, 0xFFD700, 1F);
+ Utils.drawStringScaled(
+ upgradedText,
+ font,
+ left,
+ ((AccessorGuiContainer) gui).getGuiTop() + 45,
+ false,
+ 0xFFD700,
+ 1F
+ );
}
public String nextRarity(String currentRarity) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NEUOverlayPlacements.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NEUOverlayPlacements.java
index f95302ef..ac96f527 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NEUOverlayPlacements.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NEUOverlayPlacements.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
new file mode 100644
index 00000000..f7306f2a
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/NeuSearchCalculator.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Calculator;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+
+public class NeuSearchCalculator {
+
+ static String lastInput = "";
+ static String lastResult = null;
+
+ public static String format(String text) {
+ String calculate = calculateInSearchBar(text);
+ return text + (calculate != null ? " §e= §a" + calculate : "");
+ }
+
+ private static String calculateInSearchBar(String input) {
+ int calculationMode = NotEnoughUpdates.INSTANCE.config.misc.calculationMode;
+ if (input.isEmpty() || calculationMode == 0 || (calculationMode == 1 && !input.startsWith("!"))) return null;
+ input = calculationMode == 1 ? input.substring(1) : input;
+
+ if (!lastInput.equals(input)) {
+ lastInput = input;
+ try {
+ BigDecimal calculate = Calculator.calculate(input);
+ lastResult = new DecimalFormat("#,##0.##").format(calculate);
+ } catch (Calculator.CalculatorException ignored) {
+ lastResult = null;
+ }
+ }
+
+ return lastResult;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/SignCalculator.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/SignCalculator.java
new file mode 100644
index 00000000..ac676a98
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/SignCalculator.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.SignSubmitEvent;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiEditSign;
+import io.github.moulberry.notenoughupdates.util.Calculator;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.inventory.GuiEditSign;
+import net.minecraft.tileentity.TileEntitySign;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.text.DecimalFormat;
+import java.math.BigDecimal;
+import java.util.Objects;
+
+public class SignCalculator {
+
+ String lastSource = null;
+ BigDecimal lastResult = null;
+ Calculator.CalculatorException lastException = null;
+
+ private boolean isEnabled() {
+ return NotEnoughUpdates.INSTANCE.config.misc.calculationMode != 0;
+ }
+
+ @SubscribeEvent
+ public void onSignDrawn(GuiScreenEvent.DrawScreenEvent.Post event) {
+ if (!(event.gui instanceof GuiEditSign))
+ return;
+ if (!isEnabled()) return;
+ GuiEditSign guiEditSign = (GuiEditSign) event.gui;
+ TileEntitySign tileSign = ((AccessorGuiEditSign) guiEditSign).getTileSign();
+ if (!tileSign.signText[1].getUnformattedText().equals("^^^^^^^^^^^^^^^") &&
+ !tileSign.signText[1].getUnformattedText().equals("^^^^^^")) return;
+ String source = tileSign.signText[0].getUnformattedText();
+ refresh(source);
+
+ int calculationMode = NotEnoughUpdates.INSTANCE.config.misc.calculationMode;
+ if ((calculationMode == 1 && !source.startsWith("!"))) return;
+
+ Utils.drawStringCentered(
+ getRenderedString(),
+ Minecraft.getMinecraft().fontRendererObj,
+ guiEditSign.width / 2F,
+ 58,
+ false,
+ 0x808080FF
+ );
+ }
+
+ @SubscribeEvent
+ public void onSignSubmitted(SignSubmitEvent event) {
+ if (!isEnabled()) return;
+ if (Objects.equals(event.lines[1], "^^^^^^^^^^^^^^^") || Objects.equals(event.lines[1], "^^^^^^")) {
+ refresh(event.lines[0]);
+ if (lastResult != null) {
+ event.lines[0] = lastResult.toPlainString();
+ }
+ }
+ }
+
+ public String getRenderedString() {
+ if (lastResult != null) {
+ DecimalFormat formatter = new DecimalFormat("#,##0.##");
+ String lr = formatter.format(lastResult);
+ if (Minecraft.getMinecraft().fontRendererObj.getStringWidth(lr) > 90) {
+ return EnumChatFormatting.WHITE + lastSource + " " + EnumChatFormatting.YELLOW + "= " + EnumChatFormatting.RED +
+ "Result too long";
+ }
+ return EnumChatFormatting.WHITE + lastSource + " " + EnumChatFormatting.YELLOW + "= " + EnumChatFormatting.GREEN +
+ lr;
+ } else if (lastException != null) {
+ return EnumChatFormatting.RED + lastException.getMessage();
+ }
+ return EnumChatFormatting.RED + "No calculation has been done.";
+ }
+
+ private void refresh(String source) {
+ if (Objects.equals(source, lastSource)) return;
+ lastSource = source;
+ int calculationMode = NotEnoughUpdates.INSTANCE.config.misc.calculationMode;
+ if (source.isEmpty() || calculationMode == 0 || (calculationMode == 1 && !source.startsWith("!"))) {
+ lastResult = null;
+ lastException = null;
+ return;
+ }
+ try {
+ lastResult = Calculator.calculate(calculationMode == 1 ? source.substring(1) : source);
+ lastException = null;
+ } catch (Calculator.CalculatorException ex) {
+ lastException = ex;
+ lastResult = null;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java
index bce5bfbd..8878c284 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/StorageOverlay.java
@@ -1,14 +1,38 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.common.collect.Lists;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.core.*;
+import io.github.moulberry.notenoughupdates.core.BackgroundBlur;
+import io.github.moulberry.notenoughupdates.core.ChromaColour;
+import io.github.moulberry.notenoughupdates.core.GlScissorStack;
+import io.github.moulberry.notenoughupdates.core.GuiElement;
+import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
import io.github.moulberry.notenoughupdates.core.config.KeybindHelper;
import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingInteger;
import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
import io.github.moulberry.notenoughupdates.util.SpecialColour;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
@@ -21,13 +45,17 @@ import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.shader.Framebuffer;
+import net.minecraft.event.ClickEvent;
+import net.minecraft.event.HoverEvent;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.Slot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
+import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.IChatComponent;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.ClientCommandHandler;
import org.lwjgl.input.Keyboard;
@@ -38,19 +66,17 @@ import org.lwjgl.util.vector.Vector2f;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.awt.*;
+import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
-import java.util.*;
+import java.util.Map;
+import java.util.Set;
public class StorageOverlay extends GuiElement {
+ public static final ResourceLocation[] STORAGE_PREVIEW_TEXTURES = new ResourceLocation[4];
private static final int CHEST_TOP_OFFSET = 17;
private static final int CHEST_SLOT_SIZE = 18;
private static final int CHEST_BOTTOM_OFFSET = 215;
-
- private Framebuffer framebuffer = null;
-
- private final Set<Vector2f> enchantGlintRenderLocations = new HashSet<>();
-
- public static final ResourceLocation[] STORAGE_PREVIEW_TEXTURES = new ResourceLocation[4];
private static final ResourceLocation[] STORAGE_TEXTURES = new ResourceLocation[4];
private static final ResourceLocation STORAGE_ICONS_TEXTURE = new ResourceLocation(
"notenoughupdates:storage_gui/storage_icons.png");
@@ -58,6 +84,9 @@ public class StorageOverlay extends GuiElement {
"notenoughupdates:storage_gui/storage_gui_pane_ctm.png");
private static final ResourceLocation[] LOAD_CIRCLE_SEQ = new ResourceLocation[11];
private static final ResourceLocation[] NOT_RICKROLL_SEQ = new ResourceLocation[19];
+ private static final StorageOverlay INSTANCE = new StorageOverlay();
+ private static final String CHROMA_STR = "230:255:255:0:0";
+ private static final ResourceLocation RES_ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
static {
for (int i = 0; i < STORAGE_TEXTURES.length; i++) {
@@ -81,52 +110,193 @@ public class StorageOverlay extends GuiElement {
LOAD_CIRCLE_SEQ[10] = new ResourceLocation("notenoughupdates:loading_circle_seq/1.png");
}
- private static final StorageOverlay INSTANCE = new StorageOverlay();
-
- public static StorageOverlay getInstance() {
- return INSTANCE;
- }
-
+ private final Set<Vector2f> enchantGlintRenderLocations = new HashSet<>();
private final GuiElementTextField searchBar = new GuiElementTextField("", 88, 10,
GuiElementTextField.SCALE_TEXT | GuiElementTextField.DISABLE_BG
);
private final GuiElementTextField renameStorageField = new GuiElementTextField("", 100, 13,
GuiElementTextField.COLOUR
);
-
+ private final int[][] isPaneCaches = new int[40][];
+ private final int[][] ctmIndexCaches = new int[40][];
+ private final LerpingInteger scroll = new LerpingInteger(0, 200);
+ private Framebuffer framebuffer = null;
private int editingNameId = -1;
-
private int guiLeft;
private int guiTop;
-
private boolean fastRender = false;
-
private int loadCircleIndex = 0;
private int rollIndex = 0;
private int loadCircleRotation = 0;
-
private long millisAccumIndex = 0;
private long millisAccumRoll = 0;
private long millisAccumRotation = 0;
-
private long lastMillis = 0;
-
private int scrollVelocity = 0;
private long lastScroll = 0;
-
- private final int[][] isPaneCaches = new int[40][];
- private final int[][] ctmIndexCaches = new int[40][];
-
private int desiredHeightSwitch = -1;
private int desiredHeightMX = -1;
private int desiredHeightMY = -1;
-
private boolean dirty = false;
private boolean allowTypingInSearchBar = true;
-
private int scrollGrabOffset = -1;
- private final LerpingInteger scroll = new LerpingInteger(0, 200);
+ public static StorageOverlay getInstance() {
+ return INSTANCE;
+ }
+
+ private static boolean shouldConnect(int paneIndex1, int paneIndex2) {
+ if (paneIndex1 == 16 || paneIndex2 == 16) return false;
+ if (paneIndex1 < 1 || paneIndex2 < 1) return false;
+ return paneIndex1 == paneIndex2;
+
+ }
+
+ public static int getCTMIndex(StorageManager.StoragePage page, int index, int[] isPaneCache, int[] ctmIndexCache) {
+ if (page.items[index] == null) {
+ ctmIndexCache[index] = -1;
+ return -1;
+ }
+
+ int paneType = getPaneType(page.items[index], index, isPaneCache);
+
+ int upIndex = index - 9;
+ int leftIndex = index % 9 > 0 ? index - 1 : -1;
+ int rightIndex = index % 9 < 8 ? index + 1 : -1;
+ int downIndex = index + 9;
+ int upleftIndex = index % 9 > 0 ? index - 10 : -1;
+ int uprightIndex = index % 9 < 8 ? index - 8 : -1;
+ int downleftIndex = index % 9 > 0 ? index + 8 : -1;
+ int downrightIndex = index % 9 < 8 ? index + 10 : -1;
+
+ boolean up = upIndex >= 0 && upIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[upIndex],
+ upIndex,
+ isPaneCache
+ ), paneType);
+ boolean left = leftIndex >= 0 && leftIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[leftIndex],
+ leftIndex,
+ isPaneCache
+ ), paneType);
+ boolean down = downIndex >= 0 && downIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[downIndex],
+ downIndex,
+ isPaneCache
+ ), paneType);
+ boolean right = rightIndex >= 0 && rightIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[rightIndex],
+ rightIndex,
+ isPaneCache
+ ), paneType);
+ boolean upleft = upleftIndex >= 0 && upleftIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[upleftIndex],
+ upleftIndex,
+ isPaneCache
+ ), paneType);
+ boolean upright = uprightIndex >= 0 && uprightIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[uprightIndex],
+ uprightIndex,
+ isPaneCache
+ ), paneType);
+ boolean downleft = downleftIndex >= 0 && downleftIndex < isPaneCache.length && shouldConnect(getPaneType(
+ page.items[downleftIndex],
+ downleftIndex,
+ isPaneCache
+ ), paneType);
+ boolean downright = downrightIndex >= 0 && downrightIndex < isPaneCache.length &&
+ shouldConnect(getPaneType(page.items[downrightIndex], downrightIndex, isPaneCache), paneType);
+
+ int ctmIndex = BetterContainers.getCTMIndex(up, right, down, left, upleft, upright, downright, downleft);
+ ctmIndexCache[index] = ctmIndex;
+ return ctmIndex;
+ }
+
+ public static int getRGBFromPane(int paneType) {
+ int rgb = -1;
+ EnumChatFormatting formatting = EnumChatFormatting.WHITE;
+ switch (paneType) {
+ case 0:
+ formatting = EnumChatFormatting.WHITE;
+ break;
+ case 1:
+ formatting = EnumChatFormatting.GOLD;
+ break;
+ case 2:
+ formatting = EnumChatFormatting.LIGHT_PURPLE;
+ break;
+ case 3:
+ formatting = EnumChatFormatting.BLUE;
+ break;
+ case 4:
+ formatting = EnumChatFormatting.YELLOW;
+ break;
+ case 5:
+ formatting = EnumChatFormatting.GREEN;
+ break;
+ case 6:
+ rgb = 0xfff03c96;
+ break;
+ case 7:
+ formatting = EnumChatFormatting.DARK_GRAY;
+ break;
+ case 8:
+ formatting = EnumChatFormatting.GRAY;
+ break;
+ case 9:
+ formatting = EnumChatFormatting.DARK_AQUA;
+ break;
+ case 10:
+ formatting = EnumChatFormatting.DARK_PURPLE;
+ break;
+ case 11:
+ formatting = EnumChatFormatting.DARK_BLUE;
+ break;
+ case 12:
+ rgb = 0xffA0522D;
+ break;
+ case 13:
+ formatting = EnumChatFormatting.DARK_GREEN;
+ break;
+ case 14:
+ formatting = EnumChatFormatting.DARK_RED;
+ break;
+ case 15:
+ rgb = 0x00000000;
+ break;
+ case 16:
+ rgb = SpecialColour.specialToChromaRGB(CHROMA_STR);
+ break;
+ }
+ if (rgb != -1) return rgb;
+ return 0xff000000 | Minecraft.getMinecraft().fontRendererObj.getColorCode(formatting.toString().charAt(1));
+ }
+
+ public static int getPaneType(ItemStack stack, int index, int[] cache) {
+ if (cache != null && cache[index] != 0) return cache[index];
+
+ if (NotEnoughUpdates.INSTANCE.config.storageGUI.fancyPanes == 2) {
+ if (cache != null) cache[index] = -1;
+ return -1;
+ }
+
+ if (stack != null &&
+ (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) || stack.getItem() == Item.getItemFromBlock(
+ Blocks.glass_pane))) {
+ String internalName = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack);
+ if (internalName != null) {
+ if (internalName.startsWith("STAINED_GLASS_PANE")) {
+ if (cache != null) cache[index] = stack.getItemDamage() + 1;
+ return stack.getItemDamage() + 1;
+ } else if (internalName.startsWith("THIN_GLASS")) {
+ if (cache != null) cache[index] = 17;
+ return 17;
+ }
+ }
+ }
+ if (cache != null) cache[index] = -1;
+ return -1;
+ }
private int getMaximumScroll() {
synchronized (StorageManager.getInstance().storageConfig.displayToStorageIdMapRender) {
@@ -194,6 +364,7 @@ public class StorageOverlay extends GuiElement {
@Override
public void render() {
if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChest)) return;
+
GuiChest guiChest = (GuiChest) Minecraft.getMinecraft().currentScreen;
ContainerChest containerChest = (ContainerChest) guiChest.inventorySlots;
@@ -247,7 +418,7 @@ public class StorageOverlay extends GuiElement {
if (stackOnMouse != null) {
String stackDisplay = Utils.cleanColour(stackOnMouse.getDisplayName());
if (stackDisplay.startsWith("Backpack Slot ") || stackDisplay.startsWith("Empty Backpack Slot ") ||
- stackDisplay.startsWith("Ender Chest Page ")) {
+ stackDisplay.startsWith("Ender Chest Page ") || stackDisplay.startsWith("Locked Backpack Slot ")) {
stackOnMouse = null;
}
}
@@ -590,7 +761,7 @@ public class StorageOverlay extends GuiElement {
if (storageId == currentPage) {
Utils.hasEffectOverride = true;
GlStateManager.translate(storageX - 7, storageY - 17 - 18, 0);
- guiChest.drawSlot(containerChest.getSlot(k + 9));
+ ((AccessorGuiContainer) guiChest).doDrawSlot(containerChest.getSlot(k + 9));
GlStateManager.translate(-storageX + 7, -storageY + 17 + 18, 0);
Utils.hasEffectOverride = false;
} else {
@@ -605,7 +776,7 @@ public class StorageOverlay extends GuiElement {
} else if (storageId == currentPage) {
Utils.hasEffectOverride = true;
GlStateManager.translate(storageX - 7, storageY - 17 - 18, 0);
- guiChest.drawSlot(containerChest.getSlot(k + 9));
+ ((AccessorGuiContainer) guiChest).doDrawSlot(containerChest.getSlot(k + 9));
GlStateManager.translate(-storageX + 7, -storageY + 17 + 18, 0);
Utils.hasEffectOverride = false;
} else {
@@ -1099,8 +1270,8 @@ public class StorageOverlay extends GuiElement {
if (fastRender) {
fontRendererObj.drawString(
- "Fast render does not work with Storage overlay.",
- sizeX / 2 - fontRendererObj.getStringWidth("Fast render does not work with Storage overlay.") / 2,
+ "Fast render and antialiasing do not work with Storage overlay.",
+ sizeX / 2 - fontRendererObj.getStringWidth("Fast render and antialiasing do not work with Storage overlay.") / 2,
-10,
0xFFFF0000
);
@@ -1121,7 +1292,7 @@ public class StorageOverlay extends GuiElement {
GlStateManager.pushMatrix();
GlStateManager.translate(181 - 8, storageViewSize + 18 - (inventoryStartIndex / 9 * 18 + 31), 0);
- guiChest.drawSlot(containerChest.inventorySlots.get(inventoryStartIndex + i));
+ ((AccessorGuiContainer) guiChest).doDrawSlot(containerChest.inventorySlots.get(inventoryStartIndex + i));
GlStateManager.popMatrix();
if (!searchBar.getText().isEmpty()) {
@@ -1155,7 +1326,7 @@ public class StorageOverlay extends GuiElement {
//Utils.drawItemStack(playerItems[i+9], itemX, itemY);
GlStateManager.pushMatrix();
GlStateManager.translate(181 - 8, storageViewSize + 18 - (inventoryStartIndex / 9 * 18 + 31), 0);
- guiChest.drawSlot(containerChest.inventorySlots.get(inventoryStartIndex + 9 + i));
+ ((AccessorGuiContainer) guiChest).doDrawSlot(containerChest.inventorySlots.get(inventoryStartIndex + 9 + i));
GlStateManager.popMatrix();
if (!searchBar.getText().isEmpty()) {
@@ -1537,161 +1708,6 @@ public class StorageOverlay extends GuiElement {
GlStateManager.translate(0, 0, -300);
}
- private static boolean shouldConnect(int paneIndex1, int paneIndex2) {
- if (paneIndex1 == 16 || paneIndex2 == 16) return false;
- if (paneIndex1 < 1 || paneIndex2 < 1) return false;
- return paneIndex1 == paneIndex2;
-
- }
-
- public static int getCTMIndex(StorageManager.StoragePage page, int index, int[] isPaneCache, int[] ctmIndexCache) {
- if (page.items[index] == null) {
- ctmIndexCache[index] = -1;
- return -1;
- }
-
- int paneType = getPaneType(page.items[index], index, isPaneCache);
-
- int upIndex = index - 9;
- int leftIndex = index % 9 > 0 ? index - 1 : -1;
- int rightIndex = index % 9 < 8 ? index + 1 : -1;
- int downIndex = index + 9;
- int upleftIndex = index % 9 > 0 ? index - 10 : -1;
- int uprightIndex = index % 9 < 8 ? index - 8 : -1;
- int downleftIndex = index % 9 > 0 ? index + 8 : -1;
- int downrightIndex = index % 9 < 8 ? index + 10 : -1;
-
- boolean up = upIndex >= 0 && upIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[upIndex],
- upIndex,
- isPaneCache
- ), paneType);
- boolean left = leftIndex >= 0 && leftIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[leftIndex],
- leftIndex,
- isPaneCache
- ), paneType);
- boolean down = downIndex >= 0 && downIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[downIndex],
- downIndex,
- isPaneCache
- ), paneType);
- boolean right = rightIndex >= 0 && rightIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[rightIndex],
- rightIndex,
- isPaneCache
- ), paneType);
- boolean upleft = upleftIndex >= 0 && upleftIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[upleftIndex],
- upleftIndex,
- isPaneCache
- ), paneType);
- boolean upright = uprightIndex >= 0 && uprightIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[uprightIndex],
- uprightIndex,
- isPaneCache
- ), paneType);
- boolean downleft = downleftIndex >= 0 && downleftIndex < isPaneCache.length && shouldConnect(getPaneType(
- page.items[downleftIndex],
- downleftIndex,
- isPaneCache
- ), paneType);
- boolean downright = downrightIndex >= 0 && downrightIndex < isPaneCache.length &&
- shouldConnect(getPaneType(page.items[downrightIndex], downrightIndex, isPaneCache), paneType);
-
- int ctmIndex = BetterContainers.getCTMIndex(up, right, down, left, upleft, upright, downright, downleft);
- ctmIndexCache[index] = ctmIndex;
- return ctmIndex;
- }
-
- private static final String CHROMA_STR = "230:255:255:0:0";
-
- public static int getRGBFromPane(int paneType) {
- int rgb = -1;
- EnumChatFormatting formatting = EnumChatFormatting.WHITE;
- switch (paneType) {
- case 0:
- formatting = EnumChatFormatting.WHITE;
- break;
- case 1:
- formatting = EnumChatFormatting.GOLD;
- break;
- case 2:
- formatting = EnumChatFormatting.LIGHT_PURPLE;
- break;
- case 3:
- formatting = EnumChatFormatting.BLUE;
- break;
- case 4:
- formatting = EnumChatFormatting.YELLOW;
- break;
- case 5:
- formatting = EnumChatFormatting.GREEN;
- break;
- case 6:
- rgb = 0xfff03c96;
- break;
- case 7:
- formatting = EnumChatFormatting.DARK_GRAY;
- break;
- case 8:
- formatting = EnumChatFormatting.GRAY;
- break;
- case 9:
- formatting = EnumChatFormatting.DARK_AQUA;
- break;
- case 10:
- formatting = EnumChatFormatting.DARK_PURPLE;
- break;
- case 11:
- formatting = EnumChatFormatting.DARK_BLUE;
- break;
- case 12:
- rgb = 0xffA0522D;
- break;
- case 13:
- formatting = EnumChatFormatting.DARK_GREEN;
- break;
- case 14:
- formatting = EnumChatFormatting.DARK_RED;
- break;
- case 15:
- rgb = 0x00000000;
- break;
- case 16:
- rgb = SpecialColour.specialToChromaRGB(CHROMA_STR);
- break;
- }
- if (rgb != -1) return rgb;
- return 0xff000000 | Minecraft.getMinecraft().fontRendererObj.getColorCode(formatting.toString().charAt(1));
- }
-
- public static int getPaneType(ItemStack stack, int index, int[] cache) {
- if (cache != null && cache[index] != 0) return cache[index];
-
- if (NotEnoughUpdates.INSTANCE.config.storageGUI.fancyPanes == 2) {
- if (cache != null) cache[index] = -1;
- return -1;
- }
-
- if (stack != null &&
- (stack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane) || stack.getItem() == Item.getItemFromBlock(
- Blocks.glass_pane))) {
- String internalName = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack);
- if (internalName != null) {
- if (internalName.startsWith("STAINED_GLASS_PANE")) {
- if (cache != null) cache[index] = stack.getItemDamage() + 1;
- return stack.getItemDamage() + 1;
- } else if (internalName.startsWith("THIN_GLASS")) {
- if (cache != null) cache[index] = 17;
- return 17;
- }
- }
- }
- if (cache != null) cache[index] = -1;
- return -1;
- }
-
private List<String> createTooltip(String title, int selectedOption, String... options) {
String selPrefix = EnumChatFormatting.DARK_AQUA + " \u25b6 ";
String unselPrefix = EnumChatFormatting.GRAY.toString();
@@ -1710,16 +1726,6 @@ public class StorageOverlay extends GuiElement {
return list;
}
- private static class IntPair {
- int x;
- int y;
-
- public IntPair(int x, int y) {
- this.x = x;
- this.y = y;
- }
- }
-
public IntPair getPageCoords(int displayId) {
if (displayId < 0) displayId = 0;
@@ -1964,6 +1970,16 @@ public class StorageOverlay extends GuiElement {
switch (buttonIndex) {
case 0:
NotEnoughUpdates.INSTANCE.config.storageGUI.enableStorageGUI3 = false;
+ ChatComponentText storageMessage = new ChatComponentText(
+ EnumChatFormatting.YELLOW + "[NEU] " + EnumChatFormatting.YELLOW +
+ "You just disabled the custom storage gui, did you mean to do that? If not click this message to turn it back on.");
+ storageMessage.setChatStyle(Utils.createClickStyle(ClickEvent.Action.RUN_COMMAND, "/neuenablestorage"));
+ storageMessage.setChatStyle(storageMessage.getChatStyle().setChatHoverEvent(
+ new HoverEvent(HoverEvent.Action.SHOW_TEXT,
+ new ChatComponentText(EnumChatFormatting.YELLOW + "Click to enable the custom storage gui."))));
+ ChatComponentText storageChatMessage = new ChatComponentText("");
+ storageChatMessage.appendSibling(storageMessage);
+ Minecraft.getMinecraft().thePlayer.addChatMessage(storageChatMessage);
break;
case 1:
int size =
@@ -2202,7 +2218,7 @@ public class StorageOverlay extends GuiElement {
for (Slot slot : container.inventorySlots.inventorySlots) {
if (slot != null &&
slot.inventory == Minecraft.getMinecraft().thePlayer.inventory &&
- container.isMouseOverSlot(slot, mouseX, mouseY)) {
+ ((AccessorGuiContainer) container).doIsMouseOverSlot(slot, mouseX, mouseY)) {
SlotLocking.getInstance().toggleLock(slot.getSlotIndex());
return true;
}
@@ -2246,8 +2262,6 @@ public class StorageOverlay extends GuiElement {
return true;
}
- private static final ResourceLocation RES_ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
-
private void renderEnchOverlay(Set<Vector2f> locations) {
float f = (float) (Minecraft.getSystemTime() % 3000L) / 3000.0F / 8.0F;
float f1 = (float) (Minecraft.getSystemTime() % 4873L) / 4873.0F / 8.0F;
@@ -2304,16 +2318,18 @@ public class StorageOverlay extends GuiElement {
}
public void fastRenderCheck() {
- if (!OpenGlHelper.isFramebufferEnabled() && NotEnoughUpdates.INSTANCE.config.storageGUI.enableStorageGUI3) {
+ if (!OpenGlHelper.isFramebufferEnabled() && NotEnoughUpdates.INSTANCE.config.notifications.doFastRenderNotif &&
+ NotEnoughUpdates.INSTANCE.config.storageGUI.enableStorageGUI3) {
this.fastRender = true;
- NEUEventListener.displayNotification(Lists.newArrayList(
- "\u00a74Fast Render Warning",
- "\u00a77Due to the way fast render works, it's not compatible with NEU.",
- "\u00a77Please disable fast render in your options under",
- "\u00a77ESC > Options > Video Settings > Performance > Fast Render",
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ "\u00a74Warning",
+ "\u00a77Due to the way fast render and antialiasing work, they're not compatible with NEU.",
+ "\u00a77Please disable fast render and antialiasing in your options under",
+ "\u00a77ESC > Options > Video Settings > Performance > \u00A7cFast Render",
+ "\u00a77ESC > Options > Video Settings > Quality > \u00A7cAntialiasing",
"\u00a77This can't be fixed.",
"\u00a77",
- "\u00a77Press X on your keyboard to close this notifcation"
+ "\u00a77Press X on your keyboard to close this notification"
), true, true);
return;
}
@@ -2321,4 +2337,14 @@ public class StorageOverlay extends GuiElement {
this.fastRender = false;
}
+ private static class IntPair {
+ int x;
+ int y;
+
+ public IntPair(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TradeWindow.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TradeWindow.java
index 1ba155d5..16b5015b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TradeWindow.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TradeWindow.java
@@ -1,9 +1,30 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.auction.APIManager;
import io.github.moulberry.notenoughupdates.core.config.KeybindHelper;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
@@ -26,8 +47,14 @@ import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.io.ByteArrayInputStream;
import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.*;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -95,28 +122,34 @@ public class TradeWindow {
);
}
- private static int getPrice(String internalname) {
- int pricePer = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalname);
+ private static long getPrice(String internalName) {
+ long pricePer = NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalName);
if (pricePer == -1) {
- JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalname);
+ JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(internalName);
if (bazaarInfo != null && bazaarInfo.has("avg_buy")) {
- pricePer = (int) bazaarInfo.get("avg_buy").getAsFloat();
+ pricePer = (long) bazaarInfo.get("avg_buy").getAsDouble();
}
}
if (pricePer == -1) {
- JsonObject info = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalname);
- if (info != null && !NotEnoughUpdates.INSTANCE.manager.auctionManager.isVanillaItem(internalname) &&
+ JsonObject info = NotEnoughUpdates.INSTANCE.manager.auctionManager.getItemAuctionInfo(internalName);
+ if (info != null && !NotEnoughUpdates.INSTANCE.manager.auctionManager.isVanillaItem(internalName) &&
info.has("price") && info.has("count")) {
- int auctionPricePer = (int) (info.get("price").getAsFloat() / info.get("count").getAsFloat());
+ long auctionPricePer = (long) (info.get("price").getAsDouble() / info.get("count").getAsDouble());
pricePer = auctionPricePer;
}
}
+ if (pricePer == -1) {
+ APIManager.CraftInfo craftCost = NotEnoughUpdates.INSTANCE.manager.auctionManager.getCraftCost(internalName);
+ if (craftCost != null) {
+ pricePer = (int) craftCost.craftCost;
+ }
+ }
return pricePer;
}
- private static int processTopItems(
- ItemStack stack, Map<Integer, Set<String>> topItems,
+ private static long processTopItems(
+ ItemStack stack, Map<Long, Set<String>> topItems,
Map<String, ItemStack> topItemsStack, Map<String, Integer> topItemsCount
) {
String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack);
@@ -155,9 +188,9 @@ public class TradeWindow {
topItemsStack.putIfAbsent("TRADE_COINS", stack);
- int existingPrice = coins;
- Set<Integer> toRemove = new HashSet<>();
- for (Map.Entry<Integer, Set<String>> entry : topItems.entrySet()) {
+ long existingPrice = coins;
+ Set<Long> toRemove = new HashSet<>();
+ for (Map.Entry<Long, Set<String>> entry : topItems.entrySet()) {
if (entry.getValue().contains("TRADE_COINS")) {
entry.getValue().remove("TRADE_COINS");
existingPrice += entry.getKey();
@@ -175,12 +208,12 @@ public class TradeWindow {
}
}
} else {
- int pricePer = getPrice(internalname);
+ long pricePer = getPrice(internalname);
if (pricePer > 0) {
topItemsStack.putIfAbsent(internalname, stack);
- int price = pricePer * stack.stackSize;
- int priceInclBackpack = price;
+ long price = pricePer * stack.stackSize;
+ long priceInclBackpack = price;
NBTTagCompound tag = stack.getTagCompound();
if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
@@ -221,9 +254,9 @@ public class TradeWindow {
}
}
- int existingPrice = price;
- Set<Integer> toRemove = new HashSet<>();
- for (Map.Entry<Integer, Set<String>> entry : topItems.entrySet()) {
+ long existingPrice = price;
+ Set<Long> toRemove = new HashSet<>();
+ for (Map.Entry<Long, Set<String>> entry : topItems.entrySet()) {
if (entry.getValue().contains(internalname)) {
entry.getValue().remove(internalname);
existingPrice += entry.getKey();
@@ -267,7 +300,7 @@ public class TradeWindow {
NBTTagCompound nbt = items.getCompoundTagAt(k).getCompoundTag("tag");
String internalname2 = NotEnoughUpdates.INSTANCE.manager.getInternalnameFromNBT(nbt);
if (internalname2 != null) {
- int pricePer2 = getPrice(internalname2);
+ long pricePer2 = getPrice(internalname2);
if (pricePer2 > 0) {
int count2 = items.getCompoundTagAt(k).getByte("Count");
price += pricePer2 * count2;
@@ -300,7 +333,7 @@ public class TradeWindow {
//Set index mappings
//Our slots
- TreeMap<Integer, List<Integer>> ourTradeMap = new TreeMap<>();
+ TreeMap<Long, List<Integer>> ourTradeMap = new TreeMap<>();
for (int i = 0; i < 16; i++) {
ourTradeIndexes[i] = -1;
@@ -345,19 +378,19 @@ public class TradeWindow {
try {
int coins = (int) (Float.parseFloat(sb.toString()) * mult);
- List<Integer> list = ourTradeMap.computeIfAbsent(coins, k -> new ArrayList<>());
+ List<Integer> list = ourTradeMap.computeIfAbsent((long) coins, k -> new ArrayList<>());
list.add(containerIndex);
} catch (Exception ignored) {
- List<Integer> list = ourTradeMap.computeIfAbsent(-1, k -> new ArrayList<>());
+ List<Integer> list = ourTradeMap.computeIfAbsent(-1L, k -> new ArrayList<>());
list.add(containerIndex);
}
} else {
- List<Integer> list = ourTradeMap.computeIfAbsent(-1, k -> new ArrayList<>());
+ List<Integer> list = ourTradeMap.computeIfAbsent(-1L, k -> new ArrayList<>());
list.add(containerIndex);
}
} else {
- int price = getPrice(internalname);
+ long price = getPrice(internalname);
if (price == -1) price = 0;
price += getBackpackValue(stack);
@@ -468,7 +501,7 @@ public class TradeWindow {
}
}
int ourTradeIndex = 0;
- for (Map.Entry<Integer, List<Integer>> entry : ourTradeMap.descendingMap().entrySet()) {
+ for (Map.Entry<Long, List<Integer>> entry : ourTradeMap.descendingMap().entrySet()) {
for (Integer index : entry.getValue()) {
ourTradeIndexes[ourTradeIndex++] = index;
}
@@ -553,8 +586,12 @@ public class TradeWindow {
int y = 104 + 18 * (index / 9);
if (index < 9) y = 180;
- chest.drawSlot(new Slot(Minecraft.getMinecraft().thePlayer.inventory, index, guiLeft + x, guiTop + y));
- //Utils.drawItemStack(stack, guiLeft+x, guiTop+y);
+ ((AccessorGuiContainer) chest).doDrawSlot(new Slot(
+ Minecraft.getMinecraft().thePlayer.inventory,
+ index,
+ guiLeft + x,
+ guiTop + y
+ ));
int col = 0x80ffffff;
if (SlotLocking.getInstance().isSlotIndexLocked(index)) {
@@ -796,10 +833,10 @@ public class TradeWindow {
}
if (NotEnoughUpdates.INSTANCE.config.tradeMenu.customTradePrices) {
- TreeMap<Integer, Set<String>> ourTopItems = new TreeMap<>();
+ TreeMap<Long, Set<String>> ourTopItems = new TreeMap<>();
TreeMap<String, ItemStack> ourTopItemsStack = new TreeMap<>();
TreeMap<String, Integer> ourTopItemsCount = new TreeMap<>();
- int ourPrice = 0;
+ double ourPrice = 0;
for (int i = 0; i < 16; i++) {
int x = i % 4;
int y = i / 4;
@@ -810,10 +847,10 @@ public class TradeWindow {
ourPrice += processTopItems(stack, ourTopItems, ourTopItemsStack, ourTopItemsCount);
}
- TreeMap<Integer, Set<String>> theirTopItems = new TreeMap<>();
+ TreeMap<Long, Set<String>> theirTopItems = new TreeMap<>();
TreeMap<String, ItemStack> theirTopItemsStack = new TreeMap<>();
TreeMap<String, Integer> theirTopItemsCount = new TreeMap<>();
- int theirPrice = 0;
+ double theirPrice = 0;
for (int i = 0; i < 16; i++) {
int x = i % 4;
int y = i / 4;
@@ -842,7 +879,7 @@ public class TradeWindow {
int ourTopIndex = Math.max(0, 3 - ourTopItemsStack.size());
out:
- for (Map.Entry<Integer, Set<String>> entry : ourTopItems.descendingMap().entrySet()) {
+ for (Map.Entry<Long, Set<String>> entry : ourTopItems.descendingMap().entrySet()) {
for (String ourTopItemInternal : entry.getValue()) {
ItemStack stack = ourTopItemsStack.get(ourTopItemInternal);
if (stack == null) continue;
@@ -905,7 +942,7 @@ public class TradeWindow {
int theirTopIndex = Math.max(0, 3 - theirTopItemsStack.size());
out:
- for (Map.Entry<Integer, Set<String>> entry : theirTopItems.descendingMap().entrySet()) {
+ for (Map.Entry<Long, Set<String>> entry : theirTopItems.descendingMap().entrySet()) {
for (String theirTopItemInternal : entry.getValue()) {
ItemStack stack = theirTopItemsStack.get(theirTopItemInternal);
if (stack == null) continue;
@@ -1041,7 +1078,7 @@ public class TradeWindow {
!SlotLocking.getInstance().isSlotLocked(slot)) {
Minecraft.getMinecraft().playerController.windowClick(
chest.inventorySlots.windowId,
- slot.slotNumber, 2, 3, Minecraft.getMinecraft().thePlayer
+ slot.slotNumber, 0, 0, Minecraft.getMinecraft().thePlayer
);
}
return;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java
new file mode 100644
index 00000000..e6c4dc74
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/TrophyRewardOverlay.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.inventory.Container;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.event.entity.player.ItemTooltipEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TrophyRewardOverlay {
+ private static TrophyRewardOverlay instance = null;
+
+ private final Map<String, Integer> data = new HashMap<>();
+ private boolean reloadNeeded = true;
+
+ public static final ResourceLocation trophyProfitImage =
+ new ResourceLocation("notenoughupdates:trophy_profit.png");
+
+ public static TrophyRewardOverlay getInstance() {
+ if (instance == null) {
+ instance = new TrophyRewardOverlay();
+ }
+ return instance;
+ }
+
+ /**
+ * This adds support for the /neureloadrepo command
+ */
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ public void onRepoReload(RepositoryReloadEvent event) {
+ reloadNeeded = true;
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOW)
+ public void onItemTooltipLow(ItemTooltipEvent event) {
+ if (!inTrophyFishingInventory()) return;
+
+ ItemStack itemStack = event.itemStack;
+ if (itemStack == null) return;
+ if (!"§aFillet Trophy Fish".equals(itemStack.getDisplayName())) return;
+
+ event.toolTip.add(4, getToolTip());
+ event.toolTip.add(4, "");
+ }
+
+ private String getToolTip() {
+ List<String> line = createText();
+ if (line.size() == 1) {
+ return line.get(0);
+ }
+
+ return line.get(1);
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ public void onDrawBackground(GuiScreenEvent.BackgroundDrawnEvent event) {
+ if (!inTrophyFishingInventory()) return;
+
+ GuiScreen screen = Minecraft.getMinecraft().currentScreen;
+ if (!(screen instanceof GuiChest)) return;
+ Gui gui = event.gui;
+ int xSize = ((AccessorGuiContainer) gui).getXSize();
+ int guiLeft = ((AccessorGuiContainer) gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) gui).getGuiTop();
+
+ List<String> list = createText();
+ int removed = 0;
+ if (list.size() > 11) {
+ while (list.size() > 10) {
+ removed++;
+ list.remove(9);
+ }
+ list.add("§8And " + removed + " more..");
+ }
+ renderBasicOverlay(event, guiLeft + xSize + 3, guiTop, list);
+ }
+
+ private void load() {
+ data.clear();
+
+ JsonObject jsonObject = Constants.TROPHYFISH;
+ if (jsonObject == null) {
+ return;
+ }
+
+ String[] tiers = new String[]{"_BRONZE", "_SILVER", "_GOLD", "_DIAMOND"};
+
+ for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
+ String name = entry.getKey();
+
+ int i = 0;
+ for (JsonElement element : entry.getValue().getAsJsonArray()) {
+ int price = element.getAsInt();
+ data.put(name + tiers[i], price);
+ i++;
+ }
+ }
+ }
+
+ private List<String> createText() {
+ if (reloadNeeded) {
+ load();
+ reloadNeeded = false;
+ }
+
+ List<String> texts = new ArrayList<>();
+ if (data.isEmpty()) {
+ texts.add("§cNo data in Repo found!");
+ return texts;
+ }
+
+ Map<String, Integer> totalAmount = new HashMap<>();
+ Map<String, Integer> totalExchange = new HashMap<>();
+ readInventory(totalAmount, totalExchange);
+
+ int total = totalExchange.values().stream().mapToInt(value -> value).sum();
+ texts.add("Trophy Fish Exchange");
+ texts.add("Magma Fish: §e" + total);
+
+ for (Map.Entry<String, Integer> entry : sortByValue(totalExchange).entrySet()) {
+ String name = entry.getKey();
+ int amount = totalAmount.get(name);
+ String[] split = name.split(" ");
+ String rarity = split[split.length - 1];
+ name = name.substring(0, name.length() - rarity.length() - 1);
+
+ if (name.length() > 20) {
+ name = name.substring(0, 18) + "..";
+ }
+
+ String rarityColor = rarity.replace("§l", "").substring(0, 2);
+ texts.add(String.format("%s%dx §r%s§f: §e%d", rarityColor, amount, name, entry.getValue()));
+ }
+
+ return texts;
+ }
+
+ private void readInventory(Map<String, Integer> totalAmount, Map<String, Integer> totalExchange) {
+ if (Minecraft.getMinecraft().thePlayer.openContainer instanceof ContainerChest) {
+
+ for (Slot slot : Minecraft.getMinecraft().thePlayer.openContainer.inventorySlots) {
+ if (!slot.getHasStack()) continue;
+ ItemStack stack = slot.getStack();
+ if (stack != null) {
+ String internalId = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack);
+ if (data.containsKey(internalId)) {
+ String displayName = stack.getDisplayName();
+ int stackSize = stack.stackSize;
+
+ int amount = totalAmount.getOrDefault(displayName, 0) + stackSize;
+ totalAmount.put(displayName, amount);
+
+ int exchangeRate = data.get(internalId);
+ int exchangeValue = totalExchange.getOrDefault(displayName, 0) + exchangeRate * stackSize;
+ totalExchange.put(displayName, exchangeValue);
+ }
+ }
+ }
+ }
+ }
+
+ //TODO move into utils class maybe?
+ public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
+ List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
+ list.sort(Map.Entry.comparingByValue());
+ Collections.reverse(list);
+
+ Map<K, V> result = new LinkedHashMap<>();
+ for (Map.Entry<K, V> entry : list) {
+ result.put(entry.getKey(), entry.getValue());
+ }
+
+ return result;
+ }
+
+ private void renderBasicOverlay(
+ GuiScreenEvent.BackgroundDrawnEvent event,
+ int x,
+ int y,
+ List<String> texts
+ ) {
+
+ Gui gui = event.gui;
+ int xSize = ((AccessorGuiContainer) gui).getXSize();
+ int guiLeft = ((AccessorGuiContainer) gui).getGuiLeft();
+ int guiTop = ((AccessorGuiContainer) gui).getGuiTop();
+ Minecraft minecraft = Minecraft.getMinecraft();
+ minecraft.getTextureManager().bindTexture(trophyProfitImage);
+ GL11.glColor4f(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+
+ Utils.drawTexturedRect(guiLeft + xSize + 4, guiTop, 158, 128, 0, 1, 0, 1, GL11.GL_NEAREST);
+
+ int a = guiLeft + xSize + 4;
+ FontRenderer fontRendererObj = minecraft.fontRendererObj;
+
+ //Render first two header lines
+ int i = 0;
+ for (String text : texts) {
+ fontRendererObj.drawString("§8" + text, a + 10, guiTop + 6 + i, -1, false);
+ i += 10;
+ if (i == 20) break;
+ }
+
+ //Render all other lines
+ i = 25;
+ int index = 0;
+ for (String text : texts) {
+ if (index > 1) {
+ fontRendererObj.drawString(text, a + 10, guiTop + 6 + i, -1, false);
+ i += 10;
+ } else {
+ index++;
+ }
+ }
+ }
+
+ public static boolean inTrophyFishingInventory() {
+ if (!NotEnoughUpdates.INSTANCE.isOnSkyblock()) return false;
+ if (!NotEnoughUpdates.INSTANCE.config.fishing.trophyRewardOverlay) return false;
+
+ Minecraft minecraft = Minecraft.getMinecraft();
+ if (minecraft == null || minecraft.thePlayer == null) return false;
+
+ Container inventoryContainer = minecraft.thePlayer.openContainer;
+ if (!(inventoryContainer instanceof ContainerChest)) return false;
+ ContainerChest containerChest = (ContainerChest) inventoryContainer;
+ return containerChest.getLowerChestInventory().getDisplayName()
+ .getUnformattedText().equalsIgnoreCase("Trophy Fishing");
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/EnchantState.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/EnchantState.java
new file mode 100644
index 00000000..08e720a2
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/EnchantState.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui.hex;
+
+enum EnchantState {
+ NO_ITEM,
+ ADDING_ENCHANT,
+ SWITCHING_DONT_UPDATE,
+ INVALID_ITEM,
+ HAS_ITEM,
+ HAS_ITEM_IN_HEX,
+ HAS_ITEM_IN_BOOKS,
+ ADDING_BOOK,
+ NO_ITEM_IN_HEX,
+ INVALID_ITEM_HEX,
+ HAS_ITEM_IN_GEMSTONE,
+ ADDING_GEMSTONE,
+ APPLYING_GEMSTONE
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/GuiCustomHex.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/GuiCustomHex.java
new file mode 100644
index 00000000..5361ae89
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/GuiCustomHex.java
@@ -0,0 +1,4885 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui.hex;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.GlScissorStack;
+import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingFloat;
+import io.github.moulberry.notenoughupdates.core.util.lerp.LerpingInteger;
+import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import io.github.moulberry.notenoughupdates.miscgui.CalendarOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.util.OrbDisplay;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityPlayerSP;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.gui.inventory.GuiContainer;
+import net.minecraft.client.model.ModelBook;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.Slot;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.network.play.client.C0EPacketClickWindow;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.ResourceLocation;
+import org.apache.commons.lang3.text.WordUtils;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.util.glu.Project;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Random;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class GuiCustomHex extends Gui {
+ private static final GuiCustomHex INSTANCE = new GuiCustomHex();
+ private static final ResourceLocation TEXTURE = new ResourceLocation("notenoughupdates:custom_enchant_gui.png");
+ private static final ResourceLocation ENCHANTMENT_TABLE_BOOK_TEXTURE = new ResourceLocation(
+ "textures/entity/enchanting_table_book.png");
+ private static final ModelBook MODEL_BOOK = new ModelBook();
+
+ private static final int EXPERIENCE_ORB_COUNT = 30;
+
+ private static final Pattern XP_COST_PATTERN = Pattern.compile("\\u00a73(\\d+) Exp Levels");
+ private static final Pattern ENCHANT_LEVEL_PATTERN = Pattern.compile("(.*)_(.*)");
+ private static final Pattern ENCHANT_NAME_PATTERN = Pattern.compile("([^IVX]*) ([IVX]*)");
+
+ public static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
+
+ public class Enchantment {
+ public int slotIndex;
+ public String enchantName;
+ public String enchId;
+ public List<String> displayLore;
+ public int level;
+ public int xpCost = -1;
+ public boolean overMaxLevel = false;
+ public boolean conflicts = false;
+ public int price = -1;
+
+ public Enchantment(
+ int slotIndex, String enchantName, String enchId, List<String> displayLore, int level,
+ boolean useMaxLevelForCost, boolean checkConflicts
+ ) {
+ this.slotIndex = slotIndex;
+ this.enchantName = enchantName;
+ this.enchId = enchId;
+ this.displayLore = displayLore;
+ this.level = level;
+ boolean isUlt = false;
+ for (String lore : displayLore) {
+ if (lore.contains("§l")) isUlt = true;
+ break;
+ }
+ JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(
+ (isUlt ? "ULTIMATE_" : "") + enchId.toUpperCase() + ";" + level);
+ if (bazaarInfo != null && bazaarInfo.get("curr_buy") != null) {
+ this.price = bazaarInfo.get("curr_buy").getAsInt();
+ }
+ this.enchId = ItemUtils.fixEnchantId(this.enchId, true);
+
+ if (Constants.ENCHANTS != null) {
+ if (checkConflicts && Constants.ENCHANTS.has("enchant_pools")) {
+ JsonArray pools = Constants.ENCHANTS.getAsJsonArray("enchant_pools");
+ out:
+ for (int i = 0; i < pools.size(); i++) {
+ JsonArray pool = pools.get(i).getAsJsonArray();
+
+ boolean hasThis = false;
+ boolean hasApplied = false;
+
+ for (int j = 0; j < pool.size(); j++) {
+ String enchIdPoolElement = pool.get(j).getAsString();
+ if (this.enchId.equalsIgnoreCase(enchIdPoolElement)) {
+ hasThis = true;
+ } else if (playerEnchantIds.containsKey(enchIdPoolElement)) {
+ hasApplied = true;
+ }
+ if (hasThis && hasApplied) {
+ this.conflicts = true;
+ break out;
+ }
+ }
+ }
+ }
+
+ if (level >= 1 && Constants.ENCHANTS.has("enchants_xp_cost")) {
+ JsonObject allCosts = Constants.ENCHANTS.getAsJsonObject("enchants_xp_cost");
+ JsonObject maxLevel = null;
+ if (NotEnoughUpdates.INSTANCE.config.enchantingSolvers.maxEnchLevel && Constants.ENCHANTS.has(
+ "max_xp_table_levels")) {
+ maxLevel = Constants.ENCHANTS.getAsJsonObject("max_xp_table_levels");
+ }
+
+ if (allCosts.has(this.enchId)) {
+ JsonArray costs = allCosts.getAsJsonArray(this.enchId);
+
+ if (costs.size() >= 1) {
+ if (useMaxLevelForCost) {
+ int cost =
+ (maxLevel != null && maxLevel.has(this.enchId) ? maxLevel.get(this.enchId).getAsInt() : costs.size());
+ this.xpCost = costs.get(cost - 1).getAsInt();
+ } else if (level - 1 < costs.size()) {
+ this.xpCost = costs.get(level - 1).getAsInt();
+ } else {
+ overMaxLevel = true;
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+
+ public OrbDisplay orbDisplay = new OrbDisplay();
+
+ private int guiLeft;
+ private int guiTop;
+ private boolean shouldOverrideFast = false;
+ private boolean shouldOverrideET = false;
+ private boolean shouldOverrideGemstones = false;
+ private boolean shouldOverrideXp = false;
+ public float pageOpen;
+ public float pageOpenLast;
+ public float pageOpenRandom;
+ public float pageOpenVelocity;
+ public float bookOpen;
+ public float bookOpenLast;
+
+ private int currentPage;
+ private int expectedMaxPage;
+
+ private boolean isScrollingLeft = true;
+
+ private ItemStack enchantingItem = null;
+
+ private int removingEnchantPlayerLevel = -1;
+
+ private final GuiElementTextField searchField = new GuiElementTextField("", GuiElementTextField.SCISSOR_TEXT);
+
+ private final HashMap<String, Integer> playerEnchantIds = new HashMap<>();
+
+ private boolean searchRemovedFromApplicable = false;
+ private boolean searchRemovedFromRemovable = false;
+ private final List<Enchantment> applicable = new ArrayList<>();
+ private final List<Enchantment> removable = new ArrayList<>();
+
+ private final List<HexItem> applicableItem = new ArrayList<>();
+ private final List<HexItem> removableItem = new ArrayList<>();
+ private final HashMap<Integer, Enchantment> enchanterEnchLevels = new HashMap<>();
+ private final HashMap<Integer, HexItem> enchanterItemLevels = new HashMap<>();
+ private Enchantment enchanterCurrentEnch = null;
+ private HexItem enchanterCurrentItem = null;
+
+ public Random random = new Random();
+
+ private EnchantState currentState = EnchantState.NO_ITEM;
+ private EnchantState lastState = EnchantState.NO_ITEM;
+
+ private final LerpingInteger leftScroll = new LerpingInteger(0, 150);
+ private final LerpingInteger rightScroll = new LerpingInteger(0, 150);
+
+ private final LerpingFloat arrowAmount = new LerpingFloat(0, 100);
+
+ private static final int X_SIZE = 364;
+ private static final int Y_SIZE = 215;
+
+ private int clickedScrollOffset = -1;
+ private boolean isClickedScrollLeft = true;
+
+ private boolean isChangingEnchLevel = false;
+
+ private long cancelButtonAnimTime = 0;
+ private long confirmButtonAnimTime = 0;
+
+ public static GuiCustomHex getInstance() {
+ return INSTANCE;
+ }
+
+ public boolean shouldOverride(String containerName) {
+ CalendarOverlay.ableToClickCalendar = true;
+ if (containerName == null) {
+ shouldOverrideET = false;
+ shouldOverrideFast = false;
+ shouldOverrideGemstones = false;
+ shouldOverrideXp = false;
+ searchField.setText("");
+ return false;
+ }
+ boolean config = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableHexGUI;
+ final List<String> gemList = new ArrayList<>(Arrays.asList(
+ "\u2764",
+ "\u2748",
+ "\u270e",
+ "\u2618",
+ "\u2e15",
+ "\u2727",
+ "\u2741",
+ "\u2742"
+ ));
+ shouldOverrideFast = config &&
+ (containerName.length() >= 7 && Objects.equals("The Hex", containerName.substring(0, "The Hex".length()))) &&
+ NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard();
+
+ shouldOverrideET = config &&
+ (containerName.length() >= 12 && Objects.equals(
+ "Enchant Item",
+ containerName.substring(0, "Enchant Item".length())
+ )) && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard();
+
+ shouldOverrideGemstones = config &&
+ (containerName.length() >= 12 && Objects.equals(
+ "Gemstones ➜",
+ containerName.substring(0, "Gemstones ➜".length())
+ )) && NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard();
+ if (shouldOverrideGemstones) {
+ for (String string : gemList) {
+ if (containerName.contains(string)) {
+ shouldOverrideGemstones = false;
+ break;
+ }
+ }
+ }
+
+ shouldOverrideXp = config &&
+ (containerName.length() >= 21 && Objects.equals(
+ "Bottles of Enchanting",
+ containerName.substring(0, "Bottles of Enchanting".length())
+ )) &&
+ NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard();
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+ ItemStack hexStack = cc.getLowerChestInventory().getStackInSlot(50);
+ CalendarOverlay.ableToClickCalendar =
+ !(shouldOverrideET || shouldOverrideFast || shouldOverrideGemstones || shouldOverrideXp);
+ if (hexStack != null && hexStack.getItem() == Items.experience_bottle)
+ return (shouldOverrideET || shouldOverrideFast);
+ if (!shouldOverrideFast && !shouldOverrideET && !shouldOverrideGemstones && !shouldOverrideXp) {
+ currentState = EnchantState.NO_ITEM;
+ applicable.clear();
+ removable.clear();
+ applicableItem.clear();
+ removableItem.clear();
+ expectedMaxPage = 1;
+ enchanterCurrentItem = null;
+ searchField.setText("");
+ }
+ return (shouldOverrideFast || shouldOverrideGemstones || shouldOverrideXp);
+ }
+
+ private int tickCounter = 0;
+
+ public void tick(String containerName) {
+ if (containerName.equals("The Hex")) {
+ currentState = EnchantState.HAS_ITEM_IN_HEX;
+ tickHex();
+ } else if (containerName.contains("Enchant Item")) {
+ tickEnchants();
+ } else if (containerName.contains("Books") || containerName.contains("Modifiers") || containerName.contains(
+ "Reforges") || containerName.contains("Item Upgrades") || containerName.equals("Bottles of Enchanting")) {
+ tickBooks();
+ } else if (containerName.contains("Gemstones")) {
+ tickGemstones();
+ } else {
+ tickBooks();
+ }
+ }
+
+ private void tickEnchants() {
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ //ItemStack hexStack = cc.getLowerChestInventory().getStackInSlot(12);
+ ItemStack enchantingItemStack = cc.getLowerChestInventory().getStackInSlot(19);
+ //ItemStack stack = cc.getLowerChestInventory().getStackInSlot(23);
+ ItemStack hopperStack = cc.getLowerChestInventory().getStackInSlot(51);
+
+ int lastPage = currentPage;
+
+ this.lastState = currentState;
+
+ if (hopperStack != null && hopperStack.getItem() != Item.getItemFromBlock(Blocks.hopper) &&
+ enchantingItem != null) {
+ currentState = EnchantState.ADDING_ENCHANT;
+ } else if (enchantingItemStack == null) {
+ if (currentState == EnchantState.SWITCHING_DONT_UPDATE || currentState == EnchantState.NO_ITEM) {
+ currentState = EnchantState.NO_ITEM;
+ } else {
+ currentState = EnchantState.SWITCHING_DONT_UPDATE;
+ }
+ } else {
+ ItemStack sanityCheckStack = cc.getLowerChestInventory().getStackInSlot(12);
+ if (sanityCheckStack == null || sanityCheckStack.getItem() == Items.enchanted_book) {
+ currentState = EnchantState.HAS_ITEM;
+ enchantingItem = enchantingItemStack;
+ } else {
+ currentState = EnchantState.SWITCHING_DONT_UPDATE;
+ }
+ }
+
+ if (currentState == EnchantState.HAS_ITEM) {
+ ItemStack pageUpStack = cc.getLowerChestInventory().getStackInSlot(17);
+ ItemStack pageDownStack = cc.getLowerChestInventory().getStackInSlot(35);
+ if (pageUpStack != null && pageDownStack != null) {
+ currentPage = 0;
+ boolean upIsGlass = pageUpStack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane);
+ boolean downIsGlass = pageDownStack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane);
+ int page = -1;
+
+ expectedMaxPage = 1;
+ if (!downIsGlass) {
+ try {
+ page = Integer.parseInt(Utils.getRawTooltip(pageDownStack).get(1).substring(11)) - 1;
+ expectedMaxPage = page + 1;
+ } catch (Exception ignored) {
+ }
+ }
+ if (page == -1 && !upIsGlass) {
+ try {
+ page = Integer.parseInt(Utils.getRawTooltip(pageUpStack).get(1).substring(11)) + 1;
+ expectedMaxPage = page;
+ } catch (Exception ignored) {
+ }
+ }
+ if (page == -1) {
+ currentPage = 1;
+ } else {
+ currentPage = page;
+ }
+ }
+ }
+
+ orbDisplay.physicsTickOrbs();
+
+ if (++tickCounter >= 20) {
+ tickCounter = 0;
+ }
+
+ boolean updateItems = tickCounter == 0;
+
+ if (currentState == EnchantState.ADDING_ENCHANT) {
+ if (arrowAmount.getTarget() != 1) {
+ arrowAmount.setTarget(1);
+ arrowAmount.resetTimer();
+ }
+ } else {
+ if (arrowAmount.getTarget() != 0) {
+ arrowAmount.setTarget(0);
+ arrowAmount.resetTimer();
+ }
+ }
+
+ // Set<EnchantState> allowedSwitchStates = Sets.newHashSet(EnchantState.ADDING_ENCHANT, EnchantState.HAS_ITEM, EnchantState.SWITCHING_DONT_UPDATE);
+ if (lastState != currentState || lastPage != currentPage) {
+ // if (!allowedSwitchStates.contains(lastState) || !allowedSwitchStates.contains(currentState)) {
+ leftScroll.setValue(0);
+ rightScroll.setValue(0);
+ // }
+ updateItems = true;
+ }
+
+ if (updateItems && currentState != EnchantState.SWITCHING_DONT_UPDATE) {
+ enchanterEnchLevels.clear();
+
+ if (enchantingItem != null) {
+ playerEnchantIds.clear();
+ NBTTagCompound tag = enchantingItem.getTagCompound();
+ if (tag != null) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
+ if (enchantments != null) {
+ for (String enchId : enchantments.getKeySet()) {
+ playerEnchantIds.put(enchId, enchantments.getInteger(enchId));
+ }
+ }
+ }
+ }
+ }
+
+ if (currentState == EnchantState.ADDING_ENCHANT) {
+ removingEnchantPlayerLevel = -1;
+ boolean updateLevel = enchanterCurrentEnch == null;
+ boolean hasXpBottle = false;
+ for (int i = 0; i < 27; i++) {
+ int slotIndex = 9 + i;
+ ItemStack book = cc.getLowerChestInventory().getStackInSlot(slotIndex);
+ ItemStack xpBottle = cc.getLowerChestInventory().getStackInSlot(50);
+ if (!hasXpBottle && xpBottle != null &&
+ xpBottle.getItem() == Items.experience_bottle) {
+ String name = "Buy Xp Bottles";
+ String id = "XP_BOTTLE";
+ Enchantment xpBottleEnch = new Enchantment(50, name, id,
+ Utils.getRawTooltip(xpBottle), 1, true, false
+ );
+ boolean hasHasXpBottle = false;
+ for (Enchantment ench : applicable) {
+ if (ench.enchId.equals("XP_BOTTLE")) {
+ hasHasXpBottle = true;
+ break;
+ }
+ }
+ if (!hasHasXpBottle) applicable.add(xpBottleEnch);
+ hasXpBottle = true;
+ }
+ if (book != null && book.getItem() == Items.enchanted_book) {
+ NBTTagCompound tagBook = book.getTagCompound();
+ if (tagBook != null) {
+ NBTTagCompound ea = tagBook.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
+ if (enchantments != null) {
+ String enchId = Utils
+ .cleanColour(book.getDisplayName())
+ .toLowerCase()
+ .replace(" ", "_")
+ .replace("-", "_")
+ .replaceAll("[^a-z_]", "");
+ String name = Utils.cleanColour(book.getDisplayName());
+ int enchLevel = -1;
+ if (name.equalsIgnoreCase("Bane of Arthropods")) {
+ name = "Bane of Arth.";
+ } else if (name.equalsIgnoreCase("Projectile Protection")) {
+ name = "Projectile Prot";
+ } else if (name.equalsIgnoreCase("Blast Protection")) {
+ name = "Blast Prot";
+ } else if (name.equalsIgnoreCase("Turbo-Mushrooms")) {
+ name = "Turbo-Mush";
+ }
+ Matcher levelMatcher = ENCHANT_LEVEL_PATTERN.matcher(enchId);
+ if (levelMatcher.matches()) {
+ enchLevel = Utils.parseRomanNumeral(levelMatcher.group(2).toUpperCase());
+ enchId = levelMatcher.group(1);
+ }
+ Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
+ Utils.getRawTooltip(book), enchLevel, false, true
+ );
+ int index = 0;
+ for (String lore : enchantment.displayLore) {
+ if (lore.contains("N/A") && enchantment.price > 0) {
+ String price = numberFormat.format(enchantment.price);
+ enchantment.displayLore.set(index, "\u00a76" + price + ".0 Coins");
+ }
+ if (lore.contains("Loading...")) {
+ if (enchantment.price > 0) {
+ enchantment.displayLore.set(index, "\u00a7eClick to buy on the Bazaar!");
+ } else {
+ enchantment.displayLore.set(index, "\u00a7cNot enough supply on the Bazaar!");
+ }
+ }
+ index++;
+ }
+ enchantment.displayLore.remove(0);
+
+ if (removingEnchantPlayerLevel == -1 && playerEnchantIds.containsKey(enchId)) {
+ removingEnchantPlayerLevel = playerEnchantIds.get(enchId);
+ }
+
+ if (removingEnchantPlayerLevel >= 0 && enchantment.level < removingEnchantPlayerLevel) {
+ continue;
+ }
+
+ boolean aboveMaxLevelFromEt = false;
+ if (NotEnoughUpdates.INSTANCE.config.enchantingSolvers.maxEnchLevel && Constants.ENCHANTS != null) {
+ JsonObject maxLevel = null;
+ if (Constants.ENCHANTS.has("max_xp_table_levels")) {
+ maxLevel = Constants.ENCHANTS.getAsJsonObject("max_xp_table_levels");
+ }
+ if (maxLevel != null && maxLevel.has(enchId)) {
+ if (enchantment.level > maxLevel.get(enchId).getAsInt()) {
+ aboveMaxLevelFromEt = true;
+ }
+ }
+ }
+
+ if (enchanterCurrentEnch == null) {
+ enchanterCurrentEnch = enchantment;
+ } else if (updateLevel) {
+ if (removingEnchantPlayerLevel < 0 && enchantment.level > enchanterCurrentEnch.level && !aboveMaxLevelFromEt) {
+ enchanterCurrentEnch = enchantment;
+ } else if (removingEnchantPlayerLevel >= 0 && enchantment.level < enchanterCurrentEnch.level) {
+ enchanterCurrentEnch = enchantment;
+ }
+ }
+
+ enchanterEnchLevels.put(enchantment.level, enchantment);
+ }
+ }
+ }
+ }
+ }
+ if (enchanterCurrentEnch != null && removingEnchantPlayerLevel >= 0) {
+ for (String line : enchanterCurrentEnch.displayLore) {
+ Matcher matcher = XP_COST_PATTERN.matcher(line);
+ if (matcher.find()) {
+ enchanterCurrentEnch.xpCost = Integer.parseInt(matcher.group(1));
+ }
+ }
+ }
+ } else {
+ isChangingEnchLevel = false;
+ enchanterCurrentEnch = null;
+
+ searchRemovedFromRemovable = false;
+ searchRemovedFromApplicable = false;
+ applicable.clear();
+ removable.clear();
+ boolean hasXpBottle = false;
+ if (currentState == EnchantState.HAS_ITEM) {
+ for (int i = 0; i < 15; i++) {
+ int slotIndex = 12 + (i % 5) + (i / 5) * 9;
+ ItemStack book = cc.getLowerChestInventory().getStackInSlot(slotIndex);
+ ItemStack xpBottle = cc.getLowerChestInventory().getStackInSlot(50);
+ if (!hasXpBottle && xpBottle != null &&
+ xpBottle.getItem() == Items.experience_bottle) {
+ String name = "Buy Xp Bottles";
+ String id = "XP_BOTTLE";
+ Enchantment xpBottleEnch = new Enchantment(50, name, id,
+ Utils.getRawTooltip(xpBottle), 1, true, false
+ );
+ applicable.add(xpBottleEnch);
+ hasXpBottle = true;
+ }
+ if (book != null) {
+ NBTTagCompound tagBook = book.getTagCompound();
+ if (tagBook != null) {
+ NBTTagCompound ea = tagBook.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
+ if (enchantments != null) {
+ String enchId = Utils
+ .cleanColour(book.getDisplayName())
+ .toLowerCase()
+ .replace(" ", "_")
+ .replace("-", "_")
+ .replaceAll("[^a-z_]", "");
+ if (enchId.equalsIgnoreCase("_")) continue;
+ enchId = ItemUtils.fixEnchantId(enchId, true);
+ String name = Utils.cleanColour(book.getDisplayName());
+
+ if (searchField.getText().trim().isEmpty() ||
+ name.toLowerCase().contains(searchField.getText().trim().toLowerCase())) {
+ if (name.equalsIgnoreCase("Bane of Arthropods")) {
+ name = "Bane of Arth.";
+ } else if (name.equalsIgnoreCase("Projectile Protection")) {
+ name = "Projectile Prot";
+ } else if (name.equalsIgnoreCase("Blast Protection")) {
+ name = "Blast Prot";
+ } else if (name.equalsIgnoreCase("Turbo-Mushrooms")) {
+ name = "Turbo-Mush";
+ }
+ Matcher nameMatcher = ENCHANT_NAME_PATTERN.matcher(name);
+ if (nameMatcher.matches()) {
+ name = nameMatcher.group(1);
+ }
+
+ if (playerEnchantIds.containsKey(enchId)) {
+ Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
+ Utils.getRawTooltip(book), playerEnchantIds.get(enchId), false, false
+ );
+ if (!enchantment.overMaxLevel) {
+ removable.add(enchantment);
+ }
+ } else {
+ Enchantment enchantment = new Enchantment(slotIndex, name, enchId,
+ Utils.getRawTooltip(book), 1, true, true
+ );
+ applicable.add(enchantment);
+ }
+ } else {
+ if (playerEnchantIds.containsKey(enchId)) {
+ searchRemovedFromRemovable = true;
+ } else {
+ searchRemovedFromApplicable = true;
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ NEUConfig cfg = NotEnoughUpdates.INSTANCE.config;
+ int mult = cfg.enchantingSolvers.enchantOrdering == 0 ? 1 : -1;
+ Comparator<Enchantment> comparator = cfg.enchantingSolvers.enchantSorting == 0 ?
+ Comparator.comparingInt(e -> mult * e.xpCost) :
+ (c1, c2) -> mult *
+ c1.enchId.toLowerCase().compareTo(c2.enchId.toLowerCase());
+ removable.sort(comparator);
+ applicable.sort(comparator);
+ }
+ }
+ }
+
+ //Update book model state
+ if (lastState != currentState) {
+ do {
+ this.pageOpenRandom += (float) (this.random.nextInt(4) - this.random.nextInt(4));
+
+ } while (!(this.pageOpen > this.pageOpenRandom + 1.0F) && !(this.pageOpen < this.pageOpenRandom - 1.0F));
+ }
+
+ this.pageOpenLast = this.pageOpen;
+ this.bookOpenLast = this.bookOpen;
+
+ if (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.ADDING_ENCHANT) {
+ this.bookOpen += 0.2F;
+ } else {
+ this.bookOpen -= 0.2F;
+ }
+
+ this.bookOpen = MathHelper.clamp_float(this.bookOpen, 0.0F, 1.0F);
+ float f1 = (this.pageOpenRandom - this.pageOpen) * 0.4F;
+ f1 = MathHelper.clamp_float(f1, -0.2F, 0.2F);
+ this.pageOpenVelocity += (f1 - this.pageOpenVelocity) * 0.9F;
+ this.pageOpen += this.pageOpenVelocity;
+ }
+
+ private void tickBooks() {
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ ItemStack enchantingItemStack = cc.getLowerChestInventory().getStackInSlot(19);
+ ItemStack anvilStack = cc.getLowerChestInventory().getStackInSlot(28);
+
+ this.lastState = currentState;
+
+ if (anvilStack != null && anvilStack.getItem() == Item.getItemFromBlock(Blocks.anvil) &&
+ currentState != EnchantState.ADDING_BOOK) {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ enchantingItem = enchantingItemStack;
+ } else if (currentState == EnchantState.HAS_ITEM_IN_BOOKS && enchantingItem == null &&
+ enchantingItemStack != null) {
+ enchantingItem = enchantingItemStack;
+ } else if (anvilStack != null && anvilStack.getItem() == Item.getItemFromBlock(Blocks.enchanting_table) &&
+ currentState != EnchantState.ADDING_BOOK) {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ enchantingItem = enchantingItemStack;
+ }
+
+ orbDisplay.physicsTickOrbs();
+
+ if (++tickCounter >= 20) {
+ tickCounter = 0;
+ }
+
+ if (currentState == EnchantState.ADDING_BOOK) {
+ if (arrowAmount.getTarget() != 1) {
+ arrowAmount.setTarget(1);
+ arrowAmount.resetTimer();
+ }
+ } else {
+ if (arrowAmount.getTarget() != 0) {
+ arrowAmount.setTarget(0);
+ arrowAmount.resetTimer();
+ }
+ }
+
+ isChangingEnchLevel = false;
+
+ searchRemovedFromRemovable = false;
+ searchRemovedFromApplicable = false;
+ if (applicableItem.size() < 6) leftScroll.setValue(0);
+ applicableItem.clear();
+ removableItem.clear();
+ if (currentState == EnchantState.HAS_ITEM_IN_BOOKS || currentState == EnchantState.ADDING_BOOK) {
+ boolean hasRandomReforge = false;
+ for (int i = 0; i < 15; i++) {
+ int slotIndex = 12 + (i % 5) + (i / 5) * 9;
+ ItemStack book = cc.getLowerChestInventory().getStackInSlot(slotIndex);
+ ItemStack randomReforge = cc.getLowerChestInventory().getStackInSlot(48);
+ if (!hasRandomReforge && randomReforge != null &&
+ randomReforge.getItem() == Item.getItemFromBlock(Blocks.anvil)) {
+ String name = Utils.cleanColour(randomReforge.getDisplayName());
+ String id = Utils.cleanColour(randomReforge.getDisplayName());
+ if (name.equals("Convert to Dungeon Item")) {
+ name = "Dungeonize Item";
+ id = "CONVERT_TO_DUNGEON";
+ } else if (name.equals("Random Basic Reforge")) {
+ name = "Basic Reforge";
+ id = "RANDOM_REFORGE";
+ }
+ HexItem reforgeItem = new HexItem(48, name, id,
+ Utils.getRawTooltip(randomReforge), true, true
+ );
+ boolean hasAdded = false;
+ for (String lore : reforgeItem.displayLore) {
+ if (lore.contains("This item is already a Dungeon")) {
+ removableItem.add(reforgeItem);
+ hasAdded = true;
+ break;
+ }
+ }
+ if (!hasAdded) applicableItem.add(reforgeItem);
+ hasRandomReforge = true;
+ }
+ if (book != null) {
+ NBTTagCompound tagBook = book.getTagCompound();
+ if (tagBook != null) {
+ NBTTagCompound ea = tagBook.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
+ if (enchantments != null) {
+ String itemId = Utils.cleanColour(book.getDisplayName()).toUpperCase().replace(" ", "_").replace(
+ "-",
+ "_"
+ );
+ String name = Utils.cleanColour(book.getDisplayName());
+ if (itemId.equalsIgnoreCase("_")) continue;
+ if (itemId.equalsIgnoreCase("Item_Maxed_Out")) continue;
+ if (searchField.getText().trim().isEmpty() ||
+ name.toLowerCase().contains(searchField.getText().trim().toLowerCase())) {
+ if (name.equalsIgnoreCase("Hot Potato Book")) {
+ name = "Hot Potato";
+ } else if (name.equalsIgnoreCase("Fuming Potato Book")) {
+ name = "Fuming Potato";
+ } else if (name.equalsIgnoreCase("Recombobulator 3000")) {
+ name = "Recombobulator";
+ } else if (name.contains("Power Scroll")) {
+ name = name.replace("Power ", "");
+ } else if (name.contains("\u272a")) {
+ name = name.replaceAll("[^✪]*", "");
+ } else if (name.equalsIgnoreCase("First Master Star")) {
+ name = "Master Star \u00a7c➊";
+ } else if (name.equalsIgnoreCase("Second Master Star")) {
+ name = "Master Star \u00a7c➋";
+ } else if (name.equalsIgnoreCase("Third Master Star")) {
+ name = "Master Star \u00a7c➌";
+ } else if (name.equalsIgnoreCase("Fourth Master Star")) {
+ name = "Master Star \u00a7c➍";
+ } else if (name.equalsIgnoreCase("Fifth Master Star")) {
+ name = "Master Star \u00a7c➎";
+ } else if (name.equalsIgnoreCase("The Art Of Peace")) {
+ name = "Art Of Peace";
+ } else if (name.equalsIgnoreCase("Mana Disintegrator")) {
+ name = "M Disintegrator";
+ }
+ /*if (playerEnchantIds.containsKey(itemId)) {
+ HexItem item = new HexItem(slotIndex, name, itemId,
+ Utils.getRawTooltip(book), false, false
+ );
+ if (!item.overMaxLevel) {
+ removableItem.add(item);
+ }
+ enchanterItemLevels.put(item.level, item);
+ } else */
+ {
+ HexItem item = new HexItem(slotIndex, name, itemId,
+ Utils.getRawTooltip(book), true, true
+ );
+ enchanterItemLevels.put(item.level, item);
+ if (item.itemType != ItemType.UNKNOWN) {
+ int potatoCount = 0;
+ int killCount = 0;
+ int warCount = 0;
+ int ffdCount = 0;
+ int recombCount = 0;
+ int effLevel = 0;
+ int starCount = 0;
+ int singularityCount = 0;
+ int tunerCount = 0;
+ int peaceCount = 0;
+ int manaDisintegratorCount = 0;
+ boolean shadowWarp = false;
+ boolean witherShield = false;
+ boolean implosion = false;
+ String reforge = "";
+ if (enchantingItem != null) {
+ NBTTagCompound tagItem = enchantingItem.getTagCompound();
+ if (tagItem != null) {
+ NBTTagCompound extra = tagItem.getCompoundTag("ExtraAttributes");
+ if (extra != null) {
+ potatoCount = extra.getInteger("hot_potato_count");
+ killCount = extra.getInteger("stats_book");
+ warCount = extra.getInteger("art_of_war_count");
+ ffdCount = extra.getInteger("farming_for_dummies_count");
+ recombCount = extra.getInteger("rarity_upgrades");
+ starCount = extra.getInteger("upgrade_level");
+ singularityCount = extra.getInteger("wood_singularity_count");
+ tunerCount = extra.getInteger("tuned_transmission");
+ peaceCount = extra.getInteger("art_of_peace_count");
+ manaDisintegratorCount = extra.getInteger("mana_disintegrator_count");
+ reforge = extra.getString("modifier");
+ NBTTagCompound enchs = extra.getCompoundTag("enchantments");
+ NBTTagList scrolls = extra.getTagList("ability_scroll", 8);
+ if (enchs != null) {
+ effLevel = enchs.getInteger("efficiency");
+ }
+ if (scrolls != null) {
+ for (int index = 0; index < scrolls.tagCount(); index++) {
+ if (scrolls.getStringTagAt(index).equals("IMPLOSION_SCROLL")) {
+ implosion = true;
+ } else if (scrolls.getStringTagAt(index).equals("SHADOW_WARP_SCROLL")) {
+ shadowWarp = true;
+ } else if (scrolls.getStringTagAt(index).equals("WITHER_SHIELD_SCROLL")) {
+ witherShield = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (item.itemName.length() > 14) item.itemName = item.itemName.substring(0, 14);
+
+ if (item.itemType == ItemType.HOT_POTATO) {
+ if (potatoCount < 10) applicableItem.add(item);
+ else removableItem.add(item);
+
+ } else if (item.itemType == ItemType.FUMING_POTATO) {
+ if (potatoCount >= 10 && potatoCount < 15) applicableItem.add(item);
+ else if (potatoCount >= 15) removableItem.add(item);
+
+ } else if (item.itemType == ItemType.BOOK_OF_STATS) {
+ if (killCount > 0) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.ART_OF_WAR) {
+ if (warCount > 0) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.FARMING_DUMMY) {
+ if (ffdCount < 5) applicableItem.add(item);
+ else removableItem.add(item);
+
+ } else if (item.itemType == ItemType.RECOMB) {
+ if (recombCount > 0) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.SILEX) {
+ if (effLevel >= 5 && effLevel < 10) applicableItem.add(item);
+ else if (effLevel == 10) removableItem.add(item);
+
+ } else if (item.isPowerScroll()) {
+ applicableItem.add(item);
+
+ } else if (item.isMasterStar()) {
+ applicableItem.add(item);
+
+ } else if (item.isDungeonStar()) {
+ if (starCount >= item.itemType.getStarLevel()) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.WOOD_SINGULARITY) {
+ if (singularityCount > 0) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.isHypeScroll()) {
+ if (shadowWarp) removableItem.add(item);
+ else if (implosion) removableItem.add(item);
+ else if (witherShield) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.TUNER) {
+ if (tunerCount >= 4) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.REFORGE) {
+ if (item.getReforge().equalsIgnoreCase(reforge) && !reforge.equals("")) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.ART_OF_PEACE) {
+ if (peaceCount > 0) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else if (item.itemType == ItemType.MANA_DISINTEGRATOR) {
+ if (manaDisintegratorCount >= 10) removableItem.add(item);
+ else applicableItem.add(item);
+
+ } else {
+ applicableItem.add(item);
+ }
+ } else {
+ applicableItem.add(item);
+ }
+ }
+ } else {
+ if (playerEnchantIds.containsKey(itemId)) {
+ searchRemovedFromRemovable = true;
+ } else {
+ searchRemovedFromApplicable = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ NEUConfig cfg = NotEnoughUpdates.INSTANCE.config;
+ int mult = cfg.enchantingSolvers.enchantOrdering == 0 ? 1 : -1;
+ Comparator<HexItem> comparator = cfg.enchantingSolvers.enchantSorting == 0 ?
+ Comparator.comparingInt(e -> (int) (mult * e.price)) :
+ (c1, c2) -> mult *
+ c1.itemId.toLowerCase().compareTo(c2.itemId.toLowerCase());
+ removableItem.sort(comparator);
+ applicableItem.sort(comparator);
+ }
+ }
+
+ private void tickHex() {
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ ItemStack enchantingItemStack = cc.getLowerChestInventory().getStackInSlot(22);
+ ItemStack glassStack = cc.getLowerChestInventory().getStackInSlot(12);
+ //ItemStack anvilStack = cc.getLowerChestInventory().getStackInSlot(28);
+
+ this.lastState = currentState;
+
+ if (enchantingItemStack != null) {
+ if (glassStack.getItem() != null && glassStack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ if (glassStack.getItemDamage() == 14) {
+ currentState = EnchantState.INVALID_ITEM_HEX;
+ } else if (glassStack.getItemDamage() == 10) {
+ currentState = EnchantState.HAS_ITEM_IN_HEX;
+ } else {
+ currentState = EnchantState.NO_ITEM_IN_HEX;
+ }
+ enchantingItem = enchantingItemStack;
+ }
+ } else {
+ currentState = EnchantState.NO_ITEM_IN_HEX;
+ }
+
+ orbDisplay.physicsTickOrbs();
+
+ if (++tickCounter >= 20) {
+ tickCounter = 0;
+ }
+
+ if (currentState == EnchantState.ADDING_BOOK) {
+ if (arrowAmount.getTarget() != 1) {
+ arrowAmount.setTarget(1);
+ arrowAmount.resetTimer();
+ }
+ } else {
+ if (arrowAmount.getTarget() != 0) {
+ arrowAmount.setTarget(0);
+ arrowAmount.resetTimer();
+ }
+ }
+
+ isChangingEnchLevel = false;
+
+ searchRemovedFromRemovable = false;
+ searchRemovedFromApplicable = false;
+ applicableItem.clear();
+ removableItem.clear();
+ boolean hasHexItem = false;
+ if (currentState == EnchantState.HAS_ITEM_IN_HEX) {
+ for (int i = 0; i < 9; i++) {
+ int slotIndex = 15 + (i % 3) + (i / 3) * 9;
+ ItemStack book = cc.getLowerChestInventory().getStackInSlot(slotIndex);
+ if (!hasHexItem && glassStack != null) {
+ HexItem item = new HexItem(slotIndex, "Total Upgrades", "TOTAL_UPGRADES",
+ Utils.getRawTooltip(glassStack), true, true
+ );
+ removableItem.add(item);
+ hasHexItem = true;
+ }
+ if (book != null) {
+ NBTTagCompound tagBook = book.getTagCompound();
+ if (tagBook != null) {
+ NBTTagCompound ea = tagBook.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
+ if (enchantments != null) {
+ String itemId = Utils.cleanColour(book.getDisplayName()).toUpperCase().replace(" ", "_").replace(
+ "-",
+ "_"
+ );
+ String name = Utils.cleanColour(book.getDisplayName());
+ if (itemId.equalsIgnoreCase("_")) continue;
+ if (itemId.equalsIgnoreCase("Item_Maxed_Out")) continue;
+ if (searchField.getText().trim().isEmpty() ||
+ name.toLowerCase().contains(searchField.getText().trim().toLowerCase())) {
+ if (name.equalsIgnoreCase("Ultimate Enchantments")) {
+ name = "Ult Enchants";
+ }
+ /*if (playerEnchantIds.containsKey(itemId)) {
+ HexItem item = new HexItem(slotIndex, name, itemId,
+ Utils.getRawTooltip(book), false, false
+ );
+ if (!item.overMaxLevel) {
+ removableItem.add(item);
+ }
+ enchanterItemLevels.put(item.level, item);
+ } else */
+ {
+ HexItem item = new HexItem(slotIndex, name, "HEX_ITEM" + i,
+ Utils.getRawTooltip(book), true, true
+ );
+ enchanterItemLevels.put(item.level, item);
+ applicableItem.add(item);
+ }
+ } else {
+ if (playerEnchantIds.containsKey(itemId)) {
+ searchRemovedFromRemovable = true;
+ } else {
+ searchRemovedFromApplicable = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ NEUConfig cfg = NotEnoughUpdates.INSTANCE.config;
+ int mult = cfg.enchantingSolvers.enchantOrdering == 0 ? 1 : -1;
+ Comparator<HexItem> comparator = cfg.enchantingSolvers.enchantSorting == 0 ?
+ Comparator.comparingInt(e -> (int) (mult * e.price)) :
+ (c1, c2) -> mult *
+ c1.itemId.toLowerCase().compareTo(c2.itemId.toLowerCase());
+ removableItem.sort(comparator);
+ applicableItem.sort(comparator);
+ }
+ }
+
+ private void tickGemstones() {
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ ItemStack enchantingItemStack = cc.getLowerChestInventory().getStackInSlot(19);
+ ItemStack portalStack = cc.getLowerChestInventory().getStackInSlot(28);
+
+ int lastPage = currentPage;
+ this.lastState = currentState;
+ if (portalStack != null && portalStack.getItem() == Item.getItemFromBlock(Blocks.end_portal_frame) &&
+ currentState != EnchantState.ADDING_GEMSTONE && !shouldOverrideGemstones &&
+ currentState != EnchantState.APPLYING_GEMSTONE) {
+ currentState = EnchantState.HAS_ITEM_IN_GEMSTONE;
+ enchantingItem = enchantingItemStack;
+ } else if (portalStack != null && portalStack.getItem() == Item.getItemFromBlock(Blocks.end_portal_frame) &&
+ shouldOverrideGemstones && currentState != EnchantState.APPLYING_GEMSTONE) {
+ currentState = EnchantState.ADDING_GEMSTONE;
+ } else if (currentState == EnchantState.HAS_ITEM_IN_GEMSTONE && enchantingItem == null &&
+ enchantingItemStack != null) {
+ enchantingItem = enchantingItemStack;
+ } else if (currentState != EnchantState.APPLYING_GEMSTONE) {
+ currentState = EnchantState.HAS_ITEM_IN_GEMSTONE;
+ }
+
+ if (currentState == EnchantState.APPLYING_GEMSTONE || currentState == EnchantState.ADDING_GEMSTONE) {
+ ItemStack pageUpStack = cc.getLowerChestInventory().getStackInSlot(17);
+ ItemStack pageDownStack = cc.getLowerChestInventory().getStackInSlot(35);
+ if (pageUpStack != null && pageDownStack != null) {
+ currentPage = 0;
+ boolean upIsGlass = pageUpStack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane);
+ boolean downIsGlass = pageDownStack.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane);
+ int page = -1;
+
+ expectedMaxPage = 1;
+ if (!downIsGlass) {
+ try {
+ page = Integer.parseInt(Utils.getRawTooltip(pageDownStack).get(1).substring(11)) - 1;
+ expectedMaxPage = page + 1;
+ } catch (Exception ignored) {
+ }
+ }
+ if (page == -1 && !upIsGlass) {
+ try {
+ page = Integer.parseInt(Utils.getRawTooltip(pageUpStack).get(1).substring(11)) + 1;
+ expectedMaxPage = page;
+ } catch (Exception ignored) {
+ }
+ }
+ if (page == -1) {
+ currentPage = 1;
+ } else {
+ currentPage = page;
+ }
+ }
+ }
+
+ orbDisplay.physicsTickOrbs();
+
+ if (++tickCounter >= 20) {
+ tickCounter = 0;
+ }
+
+ if (lastState != currentState || lastPage != currentPage) {
+ leftScroll.setValue(0);
+ rightScroll.setValue(0);
+ }
+
+ if (currentState == EnchantState.APPLYING_GEMSTONE) {
+ if (arrowAmount.getTarget() != 1) {
+ arrowAmount.setTarget(1);
+ arrowAmount.resetTimer();
+ }
+ } else {
+ if (arrowAmount.getTarget() != 0) {
+ arrowAmount.setTarget(0);
+ arrowAmount.resetTimer();
+ }
+ }
+
+ isChangingEnchLevel = false;
+
+ searchRemovedFromRemovable = false;
+ searchRemovedFromApplicable = false;
+ applicableItem.clear();
+ removableItem.clear();
+ if (isInGemstones()) {
+ for (int i = 0; i < 15; i++) {
+ int slotIndex = 12 + (i % 5) + (i / 5) * 9;
+ ItemStack book = cc.getLowerChestInventory().getStackInSlot(slotIndex);
+ if (book != null) {
+ NBTTagCompound tagBook = book.getTagCompound();
+ if (tagBook != null) {
+ NBTTagCompound ea = tagBook.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ NBTTagCompound enchantments = ea.getCompoundTag("enchantments");
+ if (enchantments != null) {
+ String itemId = Utils.cleanColour(book.getDisplayName()).toUpperCase().replace(" ", "_").replace(
+ "-",
+ "_"
+ );
+ String name = Utils.cleanColour(book.getDisplayName());
+ if (itemId.equalsIgnoreCase("_")) continue;
+ if (itemId.equalsIgnoreCase("Item_Maxed_Out")) continue;
+ if (searchField.getText().trim().isEmpty() ||
+ name.toLowerCase().contains(searchField.getText().trim().toLowerCase())) {
+ /*if (playerEnchantIds.containsKey(itemId)) {
+ HexItem item = new HexItem(slotIndex, name, itemId,
+ Utils.getRawTooltip(book), false, false
+ );
+ if (!item.overMaxLevel) {
+ removableItem.add(item);
+ }
+ enchanterItemLevels.put(item.level, item);
+ } else */
+ {
+ HexItem item = new HexItem(slotIndex, name, itemId,
+ Utils.getRawTooltip(book), true, true
+ );
+ enchanterItemLevels.put(item.level, item);
+ if (item.isGemstone()) {
+ if (book.getItem() == Items.dye) {
+ item.conflicts = true;
+ }
+ boolean removed = false;
+ for (String lore : item.displayLore) {
+ if (lore.contains("Click to remove!")) {
+ removableItem.add(item);
+ removed = true;
+ break;
+ }
+ }
+ if (!removed) {
+ applicableItem.add(item);
+ }
+ if (item.itemName.length() > 14) item.itemName = item.itemName.substring(0, 14);
+ } else {
+ applicableItem.add(item);
+ }
+ }
+ } else {
+ if (playerEnchantIds.containsKey(itemId)) {
+ searchRemovedFromRemovable = true;
+ } else {
+ searchRemovedFromApplicable = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ NEUConfig cfg = NotEnoughUpdates.INSTANCE.config;
+ int mult = cfg.enchantingSolvers.enchantOrdering == 0 ? 1 : -1;
+ Comparator<HexItem> comparator = cfg.enchantingSolvers.enchantSorting == 0 ?
+ Comparator.comparingInt(e -> (int) (mult * e.price)) :
+ (c1, c2) -> mult *
+ c1.itemId.toLowerCase().compareTo(c2.itemId.toLowerCase());
+ removableItem.sort(comparator);
+ applicableItem.sort(comparator);
+ }
+ this.pageOpenLast = this.pageOpen;
+ }
+
+ private List<String> createTooltip(String title, int selectedOption, String... options) {
+ String selPrefix = EnumChatFormatting.DARK_AQUA + " \u25b6 ";
+ String unselPrefix = EnumChatFormatting.GRAY.toString();
+
+ for (int i = 0; i < options.length; i++) {
+ if (i == selectedOption) {
+ options[i] = selPrefix + options[i];
+ } else {
+ options[i] = unselPrefix + options[i];
+ }
+ }
+
+ List<String> list = Lists.newArrayList(options);
+ list.add(0, "");
+ list.add(0, EnumChatFormatting.GREEN + title);
+ return list;
+ }
+
+ public void render(float partialTicks, String containerName) {
+ if (containerName == null) return;
+ if (containerName.equals("The Hex")) {
+ renderHex(partialTicks);
+ } else if (containerName.contains("Enchant Item")) {
+ renderEnchantment(partialTicks);
+ } else if (containerName.contains("Books") || containerName.contains("Modifiers") || containerName.contains(
+ "Bottles of Enchanting")) {
+ renderBooks(partialTicks);
+ } else if (containerName.contains("Gemstones")) {
+ renderGemstones(partialTicks);
+ } else {
+ renderBooks(partialTicks);
+ }
+ }
+
+ private void renderEnchantment(float partialTicks) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return;
+
+ int playerXpLevel = Minecraft.getMinecraft().thePlayer.experienceLevel;
+
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ leftScroll.tick();
+ rightScroll.tick();
+ arrowAmount.tick();
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ guiLeft = (width - X_SIZE) / 2;
+ guiTop = (height - Y_SIZE) / 2;
+
+ List<String> tooltipToDisplay = null;
+ boolean disallowClick = false;
+ ItemStack stackOnMouse = Minecraft.getMinecraft().thePlayer.inventory.getItemStack();
+ int itemHoverX = -1;
+ int itemHoverY = -1;
+ boolean hoverLocked = false;
+
+ drawGradientRect(0, 0, width, height, 0xc0101010, 0xd0101010);
+
+ renderBaseTexture();
+
+ Minecraft.getMinecraft().fontRendererObj.drawString("Applicable", guiLeft + 7, guiTop + 7, 0x404040, false);
+ Minecraft.getMinecraft().fontRendererObj.drawString("Removable", guiLeft + 247, guiTop + 7, 0x404040, false);
+
+ //Page Text
+ if (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.ADDING_ENCHANT) {
+ String pageStr = "Page: " + currentPage + "/" + expectedMaxPage;
+ int pageStrLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(pageStr);
+ Utils.drawStringCentered(pageStr, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 14, false, 0x404040
+ );
+
+ //Page Arrows
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - pageStrLen / 2 - 2 - 15, guiTop + 6, 15, 15,
+ 0, 15 / 512f, 372 / 512f, 387 / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + pageStrLen / 2 + 2, guiTop + 6, 15, 15,
+ 15 / 512f, 30 / 512f, 372 / 512f, 387 / 512f, GL11.GL_NEAREST
+ );
+ }
+
+ tooltipToDisplay = renderSettings(mouseX, mouseY, tooltipToDisplay);
+
+ renderScrollBars(applicable, removable, mouseY);
+
+ //Enchant book model
+ renderEnchantBook(scaledResolution, partialTicks);
+
+ //Can't be enchanted text
+ if (currentState == EnchantState.INVALID_ITEM) {
+ GlStateManager.disableDepth();
+ Utils.drawStringCentered("This item can't", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 88, true, 0xffff5555
+ );
+ Utils.drawStringCentered("be enchanted", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 98, true, 0xffff5555
+ );
+ GlStateManager.enableDepth();
+ }
+
+ renderArrow();
+
+ //Text if no enchants appear
+ if (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.ADDING_ENCHANT) {
+ if (applicable.isEmpty() && removable.isEmpty() && searchRemovedFromApplicable) {
+ Utils.drawStringCentered("Can't find that", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchant, perhaps", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("it is on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 48, true, 0xffff5555
+ );
+ Utils.drawStringCentered("another page?", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 58, true, 0xffff5555
+ );
+ } else if (applicable.isEmpty() && !searchRemovedFromApplicable) {
+ Utils.drawStringCentered("No applicable", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchants on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("this page...", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 48, true, 0xffff5555
+ );
+ }
+ if (applicable.isEmpty() && removable.isEmpty() && searchRemovedFromRemovable) {
+ Utils.drawStringCentered("Can't find that", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchant, perhaps", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("it is on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 48, true, 0xffff5555
+ );
+ Utils.drawStringCentered("another page?", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 58, true, 0xffff5555
+ );
+ } else if (removable.isEmpty() && !searchRemovedFromRemovable) {
+ Utils.drawStringCentered("No removable", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchants on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("this page...", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 48, true, 0xffff5555
+ );
+ }
+ }
+ //Available enchants (left)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+
+ if (applicable.size() <= index) break;
+ Enchantment ench = applicable.get(index);
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentEnch != null && enchanterCurrentEnch.enchId.equals(ench.enchId) ? 16 : 0;
+ int uOffset = ench.conflicts ? 112 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 8, top, 96, 16,
+ uOffset / 512f, (96 + uOffset) / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (ench.displayLore != null) {
+ tooltipToDisplay = ench.displayLore;
+ }
+ }
+
+ String levelStr = "" + ench.xpCost;
+ int colour = 0xc8ff8f;
+ if (ench.xpCost > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ ench.enchantName,
+ guiLeft + 8 + 16 + 2 + textOffset,
+ top + 4 + textOffset,
+ 0xffffffdd,
+ true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Removable enchants (right)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+
+ if (removable.size() <= index) break;
+ Enchantment ench = removable.get(index);
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentEnch != null && enchanterCurrentEnch.enchId.equals(ench.enchId) ? 16 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 248, top, 96, 16,
+ 0, 96 / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (ench.displayLore != null) {
+ tooltipToDisplay = ench.displayLore;
+ }
+ }
+
+ String levelStr = "" + ench.xpCost;
+ if (ench.xpCost < 0) levelStr = "?";
+ int colour = 0xc8ff8f;
+ if (ench.xpCost > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(ench.enchantName,
+ guiLeft + 248 + 16 + 2 + textOffset, top + 4 + textOffset, 0xffffffdd, true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Player Inventory Items
+ Minecraft.getMinecraft().fontRendererObj.drawString(Minecraft.getMinecraft().thePlayer.inventory
+ .getDisplayName()
+ .getUnformattedText(),
+ guiLeft + 102, guiTop + Y_SIZE - 96 + 2, 0x404040
+ );
+ int inventoryStartIndex = cc.getLowerChestInventory().getSizeInventory();
+ GlStateManager.enableDepth();
+ for (int i = 0; i < 36; i++) {
+ int itemX = guiLeft + 102 + 18 * (i % 9);
+ int itemY = guiTop + 133 + 18 * (i / 9);
+
+ if (i >= 27) {
+ itemY += 4;
+ }
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(guiLeft + 102 - 8, guiTop + 191 - (inventoryStartIndex / 9 * 18 + 89), 0);
+ Slot slot = cc.getSlot(inventoryStartIndex + i);
+ ((AccessorGuiContainer) chest).doDrawSlot(slot);
+ GlStateManager.popMatrix();
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+ hoverLocked = SlotLocking.getInstance().isSlotLocked(slot);
+
+ if (slot.getHasStack()) {
+ tooltipToDisplay = slot.getStack().getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ //Search bar
+ if (currentState == EnchantState.HAS_ITEM) {
+ if (searchField.getText().isEmpty() && !searchField.getFocus()) {
+ searchField.setSize(90, 14);
+ searchField.setPrependText("\u00a77Search...");
+ } else {
+ if (searchField.getFocus()) {
+ int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(searchField.getTextDisplay()) + 10;
+ searchField.setSize(Math.max(90, len), 14);
+ } else {
+ searchField.setSize(90, 14);
+ }
+ searchField.setPrependText("");
+ }
+ searchField.render(guiLeft + X_SIZE / 2 - searchField.getWidth() / 2, guiTop + 83);
+ } else if (currentState == EnchantState.ADDING_ENCHANT &&
+ enchanterCurrentEnch != null && !enchanterEnchLevels.isEmpty()) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ int uOffset = enchanterCurrentEnch.conflicts ? 112 : 0;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(left, top, 112, 16,
+ uOffset / 512f, (112 + uOffset) / 512f, 249 / 512f, (249 + 16) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (enchanterCurrentEnch.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentEnch.displayLore;
+ }
+ }
+
+ //Enchant cost
+ String levelStr = "" + enchanterCurrentEnch.xpCost;
+ if (enchanterCurrentEnch.xpCost < 0) levelStr = "?";
+
+ int colour = 0xc8ff8f;
+ if (enchanterCurrentEnch.xpCost > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(levelStr, left + 8 - levelWidth / 2, top + 4, colour, false);
+
+ String priceStr = "" + numberFormat.format(enchanterCurrentEnch.price) + " Coins";
+ if (enchanterCurrentEnch.price < 0) priceStr = "";
+ int priceWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(priceStr);
+ int priceTop = guiTop + 16;
+ int x = 180;
+ int color = 0x2d2102;
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2 - 1,
+ priceTop + 4,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2 + 1,
+ priceTop + 4,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2,
+ priceTop + 4 - 1,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2,
+ priceTop + 4 + 1,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2,
+ priceTop + 4,
+ 0xfcba03,
+ false
+ );
+
+ //Enchant name
+ String name = WordUtils.capitalizeFully(ItemUtils
+ .fixEnchantId(enchanterCurrentEnch.enchId, false)
+ .replace("_", " "));
+ if (name.equalsIgnoreCase("Bane of Arthropods")) {
+ name = "Bane of Arth.";
+ } else if (name.equalsIgnoreCase("Projectile Protection")) {
+ name = "Projectile Prot";
+ } else if (name.equalsIgnoreCase("Blast Protection")) {
+ name = "Blast Prot";
+ } else if (name.equalsIgnoreCase("Luck of the Sea")) {
+ name = "Luck of Sea";
+ } else if (name.equalsIgnoreCase("Turbo Mushrooms")) {
+ name = "Turbo-Mush";
+ }
+ Utils.drawStringCentered(
+ name,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2,
+ top + 8,
+ true,
+ 0xffffffdd
+ );
+
+ if (isChangingEnchLevel) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(left + 96, top, 16, 16,
+ 96 / 512f, 112 / 512f, 265 / 512f, (265 + 16) / 512f, GL11.GL_NEAREST
+ );
+ }
+
+ //Enchant level
+ levelStr = "" + enchanterCurrentEnch.level;
+ if (enchanterCurrentEnch.xpCost < 0) levelStr = "?";
+ levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 4,
+ 0xea82ff,
+ false
+ );
+
+ //Confirm button
+
+ String confirmText = "Apply";
+ if (removingEnchantPlayerLevel >= 0) {
+ if (removingEnchantPlayerLevel == enchanterCurrentEnch.level) {
+ confirmText = "Remove";
+ } else if (enchanterCurrentEnch.level > removingEnchantPlayerLevel) {
+ confirmText = "Upgrade";
+ } else {
+ confirmText = "Bad Level";
+ }
+ }
+ if (System.currentTimeMillis() - confirmButtonAnimTime < 500 && !(playerXpLevel < enchanterCurrentEnch.xpCost)) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered(confirmText, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 - 1 - 23, top + 18 + 9, false, 0x408040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered(confirmText, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 - 1 - 24, top + 18 + 8, false, 0x408040
+ );
+
+ if (playerXpLevel < enchanterCurrentEnch.xpCost) {
+ Gui.drawRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, guiLeft + X_SIZE / 2 - 1, top + 18 + 14, 0x80000000);
+ }
+ }
+
+ //Cancel button
+ if (System.currentTimeMillis() - cancelButtonAnimTime < 500) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 25, top + 18 + 9, false, 0xa04040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 24, top + 18 + 8, false, 0xa04040
+ );
+ }
+
+ if (mouseY > top + 18 && mouseY <= top + 18 + 16) {
+ if (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1) {
+ disallowClick = true;
+ if (enchanterCurrentEnch.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentEnch.displayLore;
+ }
+ } else if (mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48) {
+ disallowClick = true;
+ tooltipToDisplay = Lists.newArrayList("\u00a7cCancel");
+ }
+ }
+
+ //Enchant level switcher
+ if (isChangingEnchLevel) {
+ tooltipToDisplay = null;
+
+ List<Enchantment> before = new ArrayList<>();
+ List<Enchantment> after = new ArrayList<>();
+
+ for (Enchantment ench : enchanterEnchLevels.values()) {
+ if (ench.level < enchanterCurrentEnch.level) {
+ before.add(ench);
+ } else if (ench.level > enchanterCurrentEnch.level) {
+ after.add(ench);
+ }
+ }
+
+ before.sort(Comparator.comparingInt(o -> -o.level));
+ after.sort(Comparator.comparingInt(o -> o.level));
+
+ int bSize = before.size();
+ int aSize = after.size();
+ GlStateManager.disableDepth();
+ for (int i = 0; i < bSize + aSize; i++) {
+ Enchantment ench;
+ int yIndex;
+ if (i < bSize) {
+ ench = before.get(i);
+ yIndex = -i - 1;
+ } else {
+ ench = after.get(i - bSize);
+ yIndex = i - bSize + 1;
+ }
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+
+ int type = 0;
+ if (i == bSize) {
+ type = 2;
+ } else if (i == 0) {
+ type = 1;
+ }
+
+ if (mouseX > left + 96 && mouseX <= left + 96 + 16 &&
+ mouseY > top + 16 * yIndex && mouseY <= top + 16 * yIndex + 16) {
+ tooltipToDisplay = new ArrayList<>(ench.displayLore);
+ if (tooltipToDisplay.size() > 2) {
+ tooltipToDisplay.remove(tooltipToDisplay.size() - 1);
+ tooltipToDisplay.remove(tooltipToDisplay.size() - 1);
+ }
+ itemHoverX = -1;
+ itemHoverY = -1;
+ }
+
+ Utils.drawTexturedRect(left + 96, top + 16 * yIndex, 16, 16,
+ 16 * type / 512f, (16 + 16 * type) / 512f, 356 / 512f, (356 + 16) / 512f, GL11.GL_NEAREST
+ );
+
+ levelStr = "" + ench.level;
+ levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2 - 1,
+ top + 16 * yIndex + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2 + 1,
+ top + 16 * yIndex + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 16 * yIndex + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 16 * yIndex + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 16 * yIndex + 4,
+ 0xea82ff,
+ false
+ );
+ }
+ GlStateManager.enableDepth();
+ }
+
+ if (mouseX > left + 96 && mouseX <= left + 96 + 16 &&
+ mouseY > top && mouseY <= top + 16) {
+ if (isChangingEnchLevel) {
+ tooltipToDisplay = Lists.newArrayList("\u00a7cCancel level change");
+ } else {
+ tooltipToDisplay = Lists.newArrayList("\u00a7aChange enchant level");
+ }
+ }
+ }
+
+ if (currentState == EnchantState.HAS_ITEM) {
+ renderCancel();
+ }
+
+ //Item enchant input
+ ItemStack itemEnchantInput;
+ if (currentState == EnchantState.HAS_ITEM_IN_HEX) {
+ itemEnchantInput = cc.getSlot(22).getStack();
+ } else {
+ itemEnchantInput = cc.getSlot(19).getStack();
+ }
+ if (itemEnchantInput != null && itemEnchantInput.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ itemEnchantInput = enchantingItem;
+ }
+ {
+ int itemX = guiLeft + 174;
+ int itemY = guiTop + 58;
+
+ if (itemEnchantInput == null) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(itemX, itemY, 16, 16,
+ 0, 16 / 512f, 281 / 512f, (281 + 16) / 512f, GL11.GL_NEAREST
+ );
+ } else {
+ Utils.drawItemStack(itemEnchantInput, itemX, itemY);
+ }
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+
+ if (itemEnchantInput != null) {
+ tooltipToDisplay = itemEnchantInput.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ if (!isChangingEnchLevel && itemHoverX >= 0 && itemHoverY >= 0) {
+ GlStateManager.disableDepth();
+ GlStateManager.colorMask(true, true, true, false);
+ Gui.drawRect(itemHoverX, itemHoverY, itemHoverX + 16, itemHoverY + 16,
+ hoverLocked ? 0x80ff8080 : 0x80ffffff
+ );
+ GlStateManager.colorMask(true, true, true, true);
+ GlStateManager.enableDepth();
+ }
+
+ GlStateManager.translate(0, 0, 300);
+
+ renderOrbAnim(partialTicks);
+
+ renderMouseStack(stackOnMouse, disallowClick, mouseX, mouseY,
+ width, height, tooltipToDisplay
+ );
+ GlStateManager.translate(0, 0, -300);
+ }
+
+ private void renderBooks(float partialTicks) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return;
+
+ int playerXpLevel = Minecraft.getMinecraft().thePlayer.experienceLevel;
+
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ leftScroll.tick();
+ rightScroll.tick();
+ arrowAmount.tick();
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ guiLeft = (width - X_SIZE) / 2;
+ guiTop = (height - Y_SIZE) / 2;
+
+ List<String> tooltipToDisplay = null;
+ boolean disallowClick = false;
+ ItemStack stackOnMouse = Minecraft.getMinecraft().thePlayer.inventory.getItemStack();
+ int itemHoverX = -1;
+ int itemHoverY = -1;
+ boolean hoverLocked = false;
+
+ drawGradientRect(0, 0, width, height, 0xc0101010, 0xd0101010);
+
+ renderBaseTexture();
+
+ Minecraft.getMinecraft().fontRendererObj.drawString("Applicable", guiLeft + 7, guiTop + 7, 0x404040, false);
+ Minecraft.getMinecraft().fontRendererObj.drawString("Applied", guiLeft + 247, guiTop + 7, 0x404040, false);
+
+ //Page Text
+ /*if (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.ADDING_ENCHANT) {
+ String pageStr = "Page: " + currentPage + "/" + expectedMaxPage;
+ int pageStrLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(pageStr);
+ Utils.drawStringCentered(pageStr, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 14, false, 0x404040
+ );
+
+ //Page Arrows
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - pageStrLen / 2 - 2 - 15, guiTop + 6, 15, 15,
+ 0, 15 / 512f, 372 / 512f, 387 / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + pageStrLen / 2 + 2, guiTop + 6, 15, 15,
+ 15 / 512f, 30 / 512f, 372 / 512f, 387 / 512f, GL11.GL_NEAREST
+ );
+ }*/
+
+ tooltipToDisplay = renderSettings(mouseX, mouseY, tooltipToDisplay);
+
+ renderScrollBars(applicableItem, applicableItem, mouseY);
+
+ //Enchant book model
+ renderEnchantBook(scaledResolution, partialTicks);
+
+ //Can't be enchanted text
+ /*if (currentState == EnchantState.INVALID_ITEM) {
+ GlStateManager.disableDepth();
+ Utils.drawStringCentered("This item can't", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 88, true, 0xffff5555
+ );
+ Utils.drawStringCentered("be enchanted", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 98, true, 0xffff5555
+ );
+ GlStateManager.enableDepth();
+ }*/
+
+ renderArrow();
+
+ //Text if no enchants appear
+ if (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.ADDING_ENCHANT ||
+ currentState == EnchantState.HAS_ITEM_IN_BOOKS || currentState == EnchantState.ADDING_BOOK) {
+ if (applicableItem.isEmpty() && removableItem.isEmpty() && searchRemovedFromApplicable) {
+ Utils.drawStringCentered("Can't find that", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchant, perhaps", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("it is on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 48, true, 0xffff5555
+ );
+ Utils.drawStringCentered("another page?", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 58, true, 0xffff5555
+ );
+ } else if (applicableItem.isEmpty() && !searchRemovedFromApplicable) {
+ Utils.drawStringCentered("No applicable", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchants on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("this page...", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 8 + 48, guiTop + 48, true, 0xffff5555
+ );
+ }
+ if (applicableItem.isEmpty() && removableItem.isEmpty() && searchRemovedFromRemovable) {
+ Utils.drawStringCentered("Can't find that", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchant, perhaps", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("it is on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 48, true, 0xffff5555
+ );
+ Utils.drawStringCentered("another page?", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 58, true, 0xffff5555
+ );
+ } else if (removableItem.isEmpty() && !searchRemovedFromRemovable) {
+ Utils.drawStringCentered("No removable", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 28, true, 0xffff5555
+ );
+ Utils.drawStringCentered("enchants on", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 38, true, 0xffff5555
+ );
+ Utils.drawStringCentered("this page...", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 248 + 48, guiTop + 48, true, 0xffff5555
+ );
+ }
+ }
+ //Available enchants (left)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+
+ if (applicableItem.size() <= index) break;
+ HexItem item = applicableItem.get(index);
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentItem != null && enchanterCurrentItem.itemId.equals(item.itemId) ? 16 : 0;
+ int uOffset = item.conflicts ? 112 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 8, top, 96, 16,
+ uOffset / 512f, (96 + uOffset) / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (item.displayLore != null) {
+ tooltipToDisplay = item.displayLore;
+ }
+ }
+
+ String levelStr = getIconStr(item);
+ int colour = 0xc8ff8f;
+ if (item.price > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ item.itemName,
+ guiLeft + 8 + 16 + 2 + textOffset,
+ top + 4 + textOffset,
+ 0xffffffdd,
+ true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Removable enchants (right)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+
+ if (removableItem.size() <= index) break;
+ HexItem item = removableItem.get(index);
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentItem != null && enchanterCurrentItem.itemId.equals(item.itemId) ? 16 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 248, top, 96, 16,
+ 0, 96 / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (item.displayLore != null) {
+ tooltipToDisplay = item.displayLore;
+ }
+ }
+
+ String levelStr = getIconStr(item);
+ int colour = 0xc8ff8f;
+ /*if (item.price > playerXpLevel) {
+ colour = 0xff5555;
+ }*/
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(item.itemName,
+ guiLeft + 248 + 16 + 2 + textOffset, top + 4 + textOffset, 0xffffffdd, true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Player Inventory Items
+ Minecraft.getMinecraft().fontRendererObj.drawString(Minecraft.getMinecraft().thePlayer.inventory
+ .getDisplayName()
+ .getUnformattedText(),
+ guiLeft + 102, guiTop + Y_SIZE - 96 + 2, 0x404040
+ );
+ int inventoryStartIndex = cc.getLowerChestInventory().getSizeInventory();
+ GlStateManager.enableDepth();
+ for (int i = 0; i < 36; i++) {
+ int itemX = guiLeft + 102 + 18 * (i % 9);
+ int itemY = guiTop + 133 + 18 * (i / 9);
+
+ if (i >= 27) {
+ itemY += 4;
+ }
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(guiLeft + 102 - 8, guiTop + 191 - (inventoryStartIndex / 9 * 18 + 89), 0);
+ Slot slot = cc.getSlot(inventoryStartIndex + i);
+ ((AccessorGuiContainer) chest).doDrawSlot(slot);
+ GlStateManager.popMatrix();
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+ hoverLocked = SlotLocking.getInstance().isSlotLocked(slot);
+
+ if (slot.getHasStack()) {
+ tooltipToDisplay = slot.getStack().getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ //Search bar
+ if (currentState == EnchantState.HAS_ITEM) {
+ if (searchField.getText().isEmpty() && !searchField.getFocus()) {
+ searchField.setSize(90, 14);
+ searchField.setPrependText("\u00a77Search...");
+ } else {
+ if (searchField.getFocus()) {
+ int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(searchField.getTextDisplay()) + 10;
+ searchField.setSize(Math.max(90, len), 14);
+ } else {
+ searchField.setSize(90, 14);
+ }
+ searchField.setPrependText("");
+ }
+ searchField.render(guiLeft + X_SIZE / 2 - searchField.getWidth() / 2, guiTop + 83);
+ } else if (currentState == EnchantState.ADDING_BOOK &&
+ enchanterCurrentItem != null /*&& !enchanterItemLevels.isEmpty()*/) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ int uOffset = enchanterCurrentItem.conflicts ? 112 : 0;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(left, top, 112, 16,
+ uOffset / 512f, (112 + uOffset) / 512f, 249 / 512f, (249 + 16) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (enchanterCurrentItem.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentItem.displayLore;
+ }
+ }
+
+ String priceStr = "" + numberFormat.format(enchanterCurrentItem.getPrice()) + " Coins";
+ if (enchanterCurrentItem.price < 0) priceStr = "";
+ int priceWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(priceStr);
+ int priceTop = guiTop + 10;
+ int x = 180;
+ int color = 0x2d2102;
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2 - 1,
+ priceTop + 4,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2 + 1,
+ priceTop + 4,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2,
+ priceTop + 4 - 1,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2,
+ priceTop + 4 + 1,
+ color,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ priceStr,
+ guiLeft + x - priceWidth / 2,
+ priceTop + 4,
+ 0xfcba03,
+ false
+ );
+
+ //Enchant name
+ String name = WordUtils.capitalizeFully(enchanterCurrentItem.itemId.replace("_", " "));
+ if (name.equalsIgnoreCase("Hot Potato Book")) {
+ name = "Hot Potato";
+ } else if (name.equalsIgnoreCase("Fuming Potato Book")) {
+ name = "Fuming Potato";
+ } else if (name.equalsIgnoreCase("Recombobulator 3000")) {
+ name = "Recombobulator";
+ } else if (name.contains("Power Scroll")) {
+ name = name.replace("Power ", "");
+ } else if (name.contains("\u272a")) {
+ name = name.replaceAll("[^✪]*", "");
+ } else if (name.equalsIgnoreCase("First Master Star")) {
+ name = "Master Star \u00a7c➊";
+ } else if (name.equalsIgnoreCase("Second Master Star")) {
+ name = "Master Star \u00a7c➋";
+ } else if (name.equalsIgnoreCase("Third Master Star")) {
+ name = "Master Star \u00a7c➌";
+ } else if (name.equalsIgnoreCase("Fourth Master Star")) {
+ name = "Master Star \u00a7c➍";
+ } else if (name.equalsIgnoreCase("Fifth Master Star")) {
+ name = "Master Star \u00a7c➎";
+ } else if (name.equalsIgnoreCase("The Art Of Peace")) {
+ name = "Art Of Peace";
+ } else if (name.equalsIgnoreCase("Mana Disintegrator")) {
+ name = "M Disintegrator";
+ }
+ Utils.drawStringCentered(
+ name,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2,
+ top + 8,
+ true,
+ 0xffffffdd
+ );
+
+ //Confirm button
+ String confirmText = "Apply";
+ if (removingEnchantPlayerLevel >= 0) {
+ if (removingEnchantPlayerLevel == enchanterCurrentItem.level) {
+ confirmText = "Remove";
+ } else if (enchanterCurrentItem.level > removingEnchantPlayerLevel) {
+ confirmText = "Upgrade";
+ } else {
+ confirmText = "Bad Level";
+ }
+ }
+ if (System.currentTimeMillis() - confirmButtonAnimTime < 500 && !(playerXpLevel < enchanterCurrentItem.price)) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered(confirmText, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 - 1 - 23, top + 18 + 9, false, 0x408040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered(confirmText, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 - 1 - 24, top + 18 + 8, false, 0x408040
+ );
+
+ /*if (playerXpLevel < enchanterCurrentItem.price) {
+ Gui.drawRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, guiLeft + X_SIZE / 2 - 1, top + 18 + 14, 0x80000000);
+ }*/
+ }
+
+ //Cancel button
+ if (System.currentTimeMillis() - cancelButtonAnimTime < 500) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 25, top + 18 + 9, false, 0xa04040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 24, top + 18 + 8, false, 0xa04040
+ );
+ }
+
+ if (mouseY > top + 18 && mouseY <= top + 18 + 16) {
+ if (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1) {
+ disallowClick = true;
+ if (enchanterCurrentItem.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentItem.displayLore;
+ }
+ } else if (mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48) {
+ disallowClick = true;
+ tooltipToDisplay = Lists.newArrayList("\u00a7cCancel");
+ }
+ }
+ }
+
+ if (currentState == EnchantState.HAS_ITEM_IN_BOOKS || currentState == EnchantState.ADDING_BOOK) {
+ renderCancel();
+ }
+
+ //Item enchant input
+ ItemStack itemEnchantInput;
+ if (currentState == EnchantState.HAS_ITEM_IN_HEX) {
+ itemEnchantInput = cc.getSlot(22).getStack();
+ } else {
+ itemEnchantInput = cc.getSlot(19).getStack();
+ }
+ if (itemEnchantInput != null && itemEnchantInput.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ itemEnchantInput = enchantingItem;
+ }
+ {
+ int itemX = guiLeft + 174;
+ int itemY = guiTop + 58;
+
+ if (itemEnchantInput == null) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(itemX, itemY, 16, 16,
+ 0, 16 / 512f, 281 / 512f, (281 + 16) / 512f, GL11.GL_NEAREST
+ );
+ } else {
+ Utils.drawItemStack(itemEnchantInput, itemX, itemY);
+ }
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+
+ if (itemEnchantInput != null) {
+ tooltipToDisplay = itemEnchantInput.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ if (!isChangingEnchLevel && itemHoverX >= 0 && itemHoverY >= 0) {
+ GlStateManager.disableDepth();
+ GlStateManager.colorMask(true, true, true, false);
+ Gui.drawRect(itemHoverX, itemHoverY, itemHoverX + 16, itemHoverY + 16,
+ hoverLocked ? 0x80ff8080 : 0x80ffffff
+ );
+ GlStateManager.colorMask(true, true, true, true);
+ GlStateManager.enableDepth();
+ }
+
+ GlStateManager.translate(0, 0, 300);
+
+ renderOrbAnim(partialTicks);
+
+ renderMouseStack(stackOnMouse, disallowClick, mouseX, mouseY,
+ width, height, tooltipToDisplay
+ );
+ GlStateManager.translate(0, 0, -300);
+ }
+
+ private void renderHex(float partialTicks) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return;
+
+ int playerXpLevel = Minecraft.getMinecraft().thePlayer.experienceLevel;
+
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ leftScroll.tick();
+ //rightScroll.tick();
+ //arrowAmount.tick();
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ guiLeft = (width - X_SIZE) / 2;
+ guiTop = (height - Y_SIZE) / 2;
+
+ List<String> tooltipToDisplay = null;
+ boolean disallowClick = false;
+ ItemStack stackOnMouse = Minecraft.getMinecraft().thePlayer.inventory.getItemStack();
+ int itemHoverX = -1;
+ int itemHoverY = -1;
+ boolean hoverLocked = false;
+
+ drawGradientRect(0, 0, width, height, 0xc0101010, 0xd0101010);
+
+ renderBaseTexture();
+
+ Minecraft.getMinecraft().fontRendererObj.drawString("The Hex", guiLeft + 7, guiTop + 7, 0x404040, false);
+ //Minecraft.getMinecraft().fontRendererObj.drawString("Applied", guiLeft + 247, guiTop + 7, 0x404040, false);
+
+ tooltipToDisplay = renderSettings(mouseX, mouseY, tooltipToDisplay);
+
+ renderScrollBars(applicableItem, applicableItem, mouseY);
+
+ //Enchant book model
+ renderEnchantBook(scaledResolution, partialTicks);
+
+ //Can't be enchanted text
+ if (currentState == EnchantState.INVALID_ITEM_HEX) {
+ GlStateManager.disableDepth();
+ Utils.drawStringCentered("This item can't", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 88, true, 0xffff5555
+ );
+ Utils.drawStringCentered("be enchanted", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 98, true, 0xffff5555
+ );
+ GlStateManager.enableDepth();
+ }
+
+ renderArrow();
+
+ //Available enchants (left)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+
+ if (applicableItem.size() <= index) break;
+ HexItem item = applicableItem.get(index);
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentItem != null && enchanterCurrentItem.itemId.equals(item.itemId) ? 16 : 0;
+ int uOffset = item.conflicts ? 112 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 8, top, 96, 16,
+ uOffset / 512f, (96 + uOffset) / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (item.displayLore != null) {
+ tooltipToDisplay = item.displayLore;
+ }
+ }
+
+ String levelStr = getIconStr(item);
+ int colour = 0xc8ff8f;
+ if (item.price > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ item.itemName,
+ guiLeft + 8 + 16 + 2 + textOffset,
+ top + 4 + textOffset,
+ 0xffffffdd,
+ true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Removable enchants (right)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+
+ if (removableItem.size() <= index) break;
+ HexItem item = removableItem.get(index);
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentItem != null && enchanterCurrentItem.itemId.equals(item.itemId) ? 16 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 248, top, 96, 16,
+ 0, 96 / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (item.displayLore != null) {
+ tooltipToDisplay = item.displayLore;
+ }
+ }
+
+ String levelStr = getIconStr(item);
+ int colour = 0xc8ff8f;
+ if (item.price > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(item.itemName,
+ guiLeft + 248 + 16 + 2 + textOffset, top + 4 + textOffset, 0xffffffdd, true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Player Inventory Items
+ Minecraft.getMinecraft().fontRendererObj.drawString(Minecraft.getMinecraft().thePlayer.inventory
+ .getDisplayName()
+ .getUnformattedText(),
+ guiLeft + 102, guiTop + Y_SIZE - 96 + 2, 0x404040
+ );
+ int inventoryStartIndex = cc.getLowerChestInventory().getSizeInventory();
+ GlStateManager.enableDepth();
+ for (int i = 0; i < 36; i++) {
+ int itemX = guiLeft + 102 + 18 * (i % 9);
+ int itemY = guiTop + 133 + 18 * (i / 9);
+
+ if (i >= 27) {
+ itemY += 4;
+ }
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(guiLeft + 102 - 8, guiTop + 191 - (inventoryStartIndex / 9 * 18 + 89), 0);
+ Slot slot = cc.getSlot(inventoryStartIndex + i);
+ ((AccessorGuiContainer) chest).doDrawSlot(slot);
+ GlStateManager.popMatrix();
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+ hoverLocked = SlotLocking.getInstance().isSlotLocked(slot);
+
+ if (slot.getHasStack()) {
+ tooltipToDisplay = slot.getStack().getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ if (currentState == EnchantState.ADDING_BOOK &&
+ enchanterCurrentItem != null /*&& !enchanterItemLevels.isEmpty()*/) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ int uOffset = enchanterCurrentItem.conflicts ? 112 : 0;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(left, top, 112, 16,
+ uOffset / 512f, (112 + uOffset) / 512f, 249 / 512f, (249 + 16) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (enchanterCurrentItem.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentItem.displayLore;
+ }
+ }
+
+ if (mouseY > top + 18 && mouseY <= top + 18 + 16) {
+ if (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1) {
+ disallowClick = true;
+ if (enchanterCurrentItem.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentItem.displayLore;
+ }
+ } else if (mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48) {
+ disallowClick = true;
+ tooltipToDisplay = Lists.newArrayList("\u00a7cCancel");
+ }
+ }
+ }
+
+ if (currentState == EnchantState.HAS_ITEM_IN_BOOKS || currentState == EnchantState.ADDING_BOOK) {
+ renderCancel();
+ }
+
+ //Item enchant input
+ ItemStack itemEnchantInput;
+ if (isInHex()) {
+ itemEnchantInput = cc.getSlot(22).getStack();
+ } else {
+ itemEnchantInput = cc.getSlot(19).getStack();
+ }
+ if (itemEnchantInput != null && itemEnchantInput.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ itemEnchantInput = enchantingItem;
+ }
+ {
+ int itemX = guiLeft + 174;
+ int itemY = guiTop + 58;
+
+ if (itemEnchantInput == null) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(itemX, itemY, 16, 16,
+ 0, 16 / 512f, 281 / 512f, (281 + 16) / 512f, GL11.GL_NEAREST
+ );
+ } else {
+ Utils.drawItemStack(itemEnchantInput, itemX, itemY);
+ }
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+
+ if (itemEnchantInput != null) {
+ tooltipToDisplay = itemEnchantInput.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ if (!isChangingEnchLevel && itemHoverX >= 0 && itemHoverY >= 0) {
+ GlStateManager.disableDepth();
+ GlStateManager.colorMask(true, true, true, false);
+ Gui.drawRect(itemHoverX, itemHoverY, itemHoverX + 16, itemHoverY + 16,
+ hoverLocked ? 0x80ff8080 : 0x80ffffff
+ );
+ GlStateManager.colorMask(true, true, true, true);
+ GlStateManager.enableDepth();
+ }
+
+ GlStateManager.translate(0, 0, 300);
+
+ renderOrbAnim(partialTicks);
+
+ renderMouseStack(stackOnMouse, disallowClick, mouseX, mouseY,
+ width, height, tooltipToDisplay
+ );
+ GlStateManager.translate(0, 0, -300);
+ }
+
+ private void renderGemstones(float partialTicks) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return;
+
+ int playerXpLevel = Minecraft.getMinecraft().thePlayer.experienceLevel;
+
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+ ContainerChest cc = (ContainerChest) chest.inventorySlots;
+
+ leftScroll.tick();
+ rightScroll.tick();
+ arrowAmount.tick();
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ guiLeft = (width - X_SIZE) / 2;
+ guiTop = (height - Y_SIZE) / 2;
+
+ List<String> tooltipToDisplay = null;
+ boolean disallowClick = false;
+ ItemStack stackOnMouse = Minecraft.getMinecraft().thePlayer.inventory.getItemStack();
+ int itemHoverX = -1;
+ int itemHoverY = -1;
+ boolean hoverLocked = false;
+
+ drawGradientRect(0, 0, width, height, 0xc0101010, 0xd0101010);
+
+ renderBaseTexture();
+
+ Minecraft.getMinecraft().fontRendererObj.drawString("Applicable", guiLeft + 7, guiTop + 7, 0x404040, false);
+ Minecraft.getMinecraft().fontRendererObj.drawString("Applied", guiLeft + 247, guiTop + 7, 0x404040, false);
+
+ //Page Text
+ if (currentState == EnchantState.ADDING_GEMSTONE || currentState == EnchantState.APPLYING_GEMSTONE) {
+ String pageStr = "Page: " + currentPage + "/" + expectedMaxPage;
+ int pageStrLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(pageStr);
+ Utils.drawStringCentered(pageStr, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2, guiTop + 14, false, 0x404040
+ );
+
+ //Page Arrows
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - pageStrLen / 2 - 2 - 15, guiTop + 6, 15, 15,
+ 0, 15 / 512f, 372 / 512f, 387 / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + pageStrLen / 2 + 2, guiTop + 6, 15, 15,
+ 15 / 512f, 30 / 512f, 372 / 512f, 387 / 512f, GL11.GL_NEAREST
+ );
+ }
+
+ //Confirm button
+ {
+ int top = guiTop + 83;
+ if (currentState == EnchantState.APPLYING_GEMSTONE) {
+ String confirmText = "Apply";
+ if (removingEnchantPlayerLevel >= 0) {
+ if (removingEnchantPlayerLevel == enchanterCurrentItem.level) {
+ confirmText = "Remove";
+ } else if (enchanterCurrentItem.level > removingEnchantPlayerLevel) {
+ confirmText = "Upgrade";
+ } else {
+ confirmText = "Bad Level";
+ }
+ }
+ if (System.currentTimeMillis() - confirmButtonAnimTime < 500) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered(confirmText, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 - 1 - 23, top + 18 + 9, false, 0x408040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered(confirmText, Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 - 1 - 24, top + 18 + 8, false, 0x408040
+ );
+ }
+ }
+
+ //Cancel button
+
+ if (System.currentTimeMillis() - cancelButtonAnimTime < 500) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 25, top + 18 + 9, false, 0xa04040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 24, top + 18 + 8, false, 0xa04040
+ );
+ }
+ }
+
+ tooltipToDisplay = renderSettings(mouseX, mouseY, tooltipToDisplay);
+
+ renderScrollBars(applicableItem, applicableItem, mouseY);
+
+ //Enchant book model
+ renderEnchantBook(scaledResolution, partialTicks);
+
+ renderArrow();
+
+ //Available enchants (left)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+
+ if (applicableItem.size() <= index) break;
+ HexItem item = applicableItem.get(index);
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentItem != null && enchanterCurrentItem.itemId.equals(item.itemId) ? 16 : 0;
+ int uOffset = item.conflicts ? 112 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 8, top, 96, 16,
+ uOffset / 512f, (96 + uOffset) / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (item.displayLore != null) {
+ tooltipToDisplay = item.displayLore;
+ }
+ }
+
+ String levelStr = getIconStr(item);
+ int colour = 0xc8ff8f;
+ if (item.price > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 16 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ item.itemName,
+ guiLeft + 8 + 16 + 2 + textOffset,
+ top + 4 + textOffset,
+ 0xffffffdd,
+ true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Removable enchants (right)
+ GlScissorStack.push(0, guiTop + 18, width, guiTop + 18 + 96, scaledResolution);
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+
+ if (removableItem.size() <= index) break;
+ HexItem item = removableItem.get(index);
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ int vOffset = enchanterCurrentItem != null && enchanterCurrentItem.itemId.equals(item.itemId) ? 16 : 0;
+ int textOffset = vOffset / 16;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 248, top, 96, 16,
+ 0, 96 / 512f, (249 + vOffset) / 512f, (249 + 16 + vOffset) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (item.displayLore != null) {
+ tooltipToDisplay = item.displayLore;
+ }
+ }
+
+ String levelStr = getIconStr(item);
+ int colour = 0xc8ff8f;
+ if (item.price > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ guiLeft + 256 - levelWidth / 2,
+ top + 4,
+ colour,
+ false
+ );
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(item.itemName,
+ guiLeft + 248 + 16 + 2 + textOffset, top + 4 + textOffset, 0xffffffdd, true
+ );
+ }
+ GlScissorStack.pop(scaledResolution);
+
+ //Player Inventory Items
+ Minecraft.getMinecraft().fontRendererObj.drawString(Minecraft.getMinecraft().thePlayer.inventory
+ .getDisplayName()
+ .getUnformattedText(),
+ guiLeft + 102, guiTop + Y_SIZE - 96 + 2, 0x404040
+ );
+ int inventoryStartIndex = cc.getLowerChestInventory().getSizeInventory();
+ GlStateManager.enableDepth();
+ for (int i = 0; i < 36; i++) {
+ int itemX = guiLeft + 102 + 18 * (i % 9);
+ int itemY = guiTop + 133 + 18 * (i / 9);
+
+ if (i >= 27) {
+ itemY += 4;
+ }
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(guiLeft + 102 - 8, guiTop + 191 - (inventoryStartIndex / 9 * 18 + 89), 0);
+ Slot slot = cc.getSlot(inventoryStartIndex + i);
+ ((AccessorGuiContainer) chest).doDrawSlot(slot);
+ GlStateManager.popMatrix();
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+ hoverLocked = SlotLocking.getInstance().isSlotLocked(slot);
+
+ if (slot.getHasStack()) {
+ tooltipToDisplay = slot.getStack().getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ if (currentState == EnchantState.APPLYING_GEMSTONE &&
+ enchanterCurrentItem != null /*&& !enchanterItemLevels.isEmpty()*/) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ int uOffset = enchanterCurrentItem.conflicts ? 112 : 0;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(left, top, 112, 16,
+ uOffset / 512f, (112 + uOffset) / 512f, 249 / 512f, (249 + 16) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ disallowClick = true;
+ if (enchanterCurrentItem.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentItem.displayLore;
+ }
+ }
+
+ if (mouseY > top + 18 && mouseY <= top + 18 + 16) {
+ if (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1) {
+ disallowClick = true;
+ if (enchanterCurrentItem.displayLore != null) {
+ tooltipToDisplay = enchanterCurrentItem.displayLore;
+ }
+ } else if (mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48) {
+ disallowClick = true;
+ tooltipToDisplay = Lists.newArrayList("\u00a7cCancel");
+ }
+ }
+ }
+
+ if (currentState == EnchantState.HAS_ITEM_IN_BOOKS || currentState == EnchantState.ADDING_BOOK) {
+ renderCancel();
+ }
+
+ //Item enchant input
+ ItemStack itemEnchantInput;
+ if (isInHex()) {
+ itemEnchantInput = cc.getSlot(22).getStack();
+ } else {
+ itemEnchantInput = cc.getSlot(19).getStack();
+ }
+ if (itemEnchantInput != null && itemEnchantInput.getItem() == Item.getItemFromBlock(Blocks.stained_glass_pane)) {
+ itemEnchantInput = enchantingItem;
+ }
+ {
+ int itemX = guiLeft + 174;
+ int itemY = guiTop + 58;
+
+ if (itemEnchantInput == null) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(itemX, itemY, 16, 16,
+ 0, 16 / 512f, 281 / 512f, (281 + 16) / 512f, GL11.GL_NEAREST
+ );
+ } else {
+ Utils.drawItemStack(itemEnchantInput, itemX, itemY);
+ }
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ itemHoverX = itemX;
+ itemHoverY = itemY;
+
+ if (itemEnchantInput != null) {
+ tooltipToDisplay = itemEnchantInput.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+
+ if (currentState == EnchantState.APPLYING_GEMSTONE) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+ //Enchant cost
+ String levelStr = getIconStr(enchanterCurrentItem);
+
+ int colour = 0xc8ff8f;
+ if (enchanterCurrentItem.price > playerXpLevel) {
+ colour = 0xff5555;
+ }
+
+ int levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 8 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(levelStr, left + 8 - levelWidth / 2, top + 4, colour, false);
+
+ //Enchant name
+ String name = WordUtils.capitalizeFully(enchanterCurrentItem.itemName);
+ if (name.equalsIgnoreCase("Bane of Arthropods")) {
+ name = "Bane of Arth.";
+ } else if (name.equalsIgnoreCase("Projectile Protection")) {
+ name = "Projectile Prot";
+ } else if (name.equalsIgnoreCase("Blast Protection")) {
+ name = "Blast Prot";
+ } else if (name.equalsIgnoreCase("Luck of the Sea")) {
+ name = "Luck of Sea";
+ } else if (name.equalsIgnoreCase("Turbo Mushrooms")) {
+ name = "Turbo-Mush";
+ }
+ Utils.drawStringCentered(
+ name,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2,
+ top + 8,
+ true,
+ 0xffffffdd
+ );
+
+ if (isChangingEnchLevel) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(left + 96, top, 16, 16,
+ 96 / 512f, 112 / 512f, 265 / 512f, (265 + 16) / 512f, GL11.GL_NEAREST
+ );
+ }
+
+ //Enchant level
+ levelStr = "";
+ levelWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(levelStr);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2 - 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2 + 1,
+ top + 4,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 4 - 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 4 + 1,
+ 0x2d2102,
+ false
+ );
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ levelStr,
+ left + 96 + 8 - levelWidth / 2,
+ top + 4,
+ 0xea82ff,
+ false
+ );
+ }
+
+ if (!isChangingEnchLevel && itemHoverX >= 0 && itemHoverY >= 0) {
+ GlStateManager.disableDepth();
+ GlStateManager.colorMask(true, true, true, false);
+ Gui.drawRect(itemHoverX, itemHoverY, itemHoverX + 16, itemHoverY + 16,
+ hoverLocked ? 0x80ff8080 : 0x80ffffff
+ );
+ GlStateManager.colorMask(true, true, true, true);
+ GlStateManager.enableDepth();
+ }
+
+ GlStateManager.translate(0, 0, 300);
+
+ renderOrbAnim(partialTicks);
+
+ renderMouseStack(stackOnMouse, disallowClick, mouseX, mouseY,
+ width, height, tooltipToDisplay
+ );
+ GlStateManager.translate(0, 0, -300);
+ }
+
+ private String getIconStr(HexItem item) {
+ String levelStr = "";
+ if (item.itemType != ItemType.UNKNOWN) {
+ int potatoCount = 0;
+ int killCount = 0;
+ int warCount = 0;
+ int ffdCount = 0;
+ int recombCount = 0;
+ int effLevel = 0;
+ int starCount = 0;
+ int singularityCount = 0;
+ int tunerCount = 0;
+ int manaDisintegratorCount = 0;
+ int peaceCount = 0;
+ int dungeonItem = 0;
+ boolean shadowWarp = false;
+ boolean witherShield = false;
+ boolean implosion = false;
+ String reforge = "";
+ if (enchantingItem != null) {
+ NBTTagCompound tagItem = enchantingItem.getTagCompound();
+ if (tagItem != null) {
+ NBTTagCompound ea = tagItem.getCompoundTag("ExtraAttributes");
+ if (ea != null) {
+ potatoCount = ea.getInteger("hot_potato_count");
+ killCount = ea.getInteger("stats_book");
+ warCount = ea.getInteger("art_of_war_count");
+ ffdCount = ea.getInteger("farming_for_dummies_count");
+ recombCount = ea.getInteger("rarity_upgrades");
+ starCount = ea.getInteger("upgrade_level");
+ singularityCount = ea.getInteger("wood_singularity_count");
+ tunerCount = ea.getInteger("tuned_transmission");
+ peaceCount = ea.getInteger("art_of_peace_count");
+ manaDisintegratorCount = ea.getInteger("mana_disintegrator_count");
+ dungeonItem = ea.getInteger("dungeon_item");
+ reforge = ea.getString("modifier");
+ NBTTagCompound enchs = ea.getCompoundTag("enchantments");
+ NBTTagList scrolls = ea.getTagList("ability_scroll", 8);
+ if (enchs != null) {
+ effLevel = enchs.getInteger("efficiency");
+ }
+ if (scrolls != null) {
+ for (int index = 0; index < scrolls.tagCount(); index++) {
+ if (scrolls.getStringTagAt(index).equals("IMPLOSION_SCROLL")) {
+ implosion = true;
+ } else if (scrolls.getStringTagAt(index).equals("SHADOW_WARP_SCROLL")) {
+ shadowWarp = true;
+ } else if (scrolls.getStringTagAt(index).equals("WITHER_SHIELD_SCROLL")) {
+ witherShield = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (item.itemType == ItemType.HOT_POTATO) {
+ if (potatoCount < 10) levelStr = "" + potatoCount;
+ else levelStr = "✔";
+
+ } else if (item.itemType == ItemType.FUMING_POTATO) {
+ if (potatoCount <= 10) levelStr = "" + 0;
+ else if (potatoCount < 15) levelStr = "" + (potatoCount - 10);
+ else levelStr = "✔";
+
+ } else if (item.itemType == ItemType.BOOK_OF_STATS) {
+ if (killCount > 0) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.ART_OF_WAR) {
+ if (warCount > 0) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.FARMING_DUMMY) {
+ if (ffdCount < 5) levelStr = "" + ffdCount;
+ else levelStr = "✔";
+
+ } else if (item.itemType == ItemType.RECOMB) {
+ if (recombCount > 0) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.SILEX) {
+ if (effLevel < 10) levelStr = "✖";
+ else levelStr = "✔";
+
+ } else if (item.isPowerScroll()) {
+ levelStr = "✖";
+
+ } else if (item.isMasterStar()) {
+ levelStr = "✖";
+
+ } else if (item.isDungeonStar()) {
+ if (starCount >= item.itemType.getStarLevel()) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.WOOD_SINGULARITY) {
+ if (singularityCount > 0) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.isHypeScroll()) {
+ if (shadowWarp) levelStr = "✔";
+ else if (implosion) levelStr = "✔";
+ else if (witherShield) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.TUNER) {
+ if (tunerCount >= 4) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.REFORGE) {
+ if (item.getReforge().equalsIgnoreCase(reforge)) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.RANDOM_REFORGE) {
+ levelStr = "?";
+
+ } else if (item.itemType == ItemType.ART_OF_PEACE) {
+ if (peaceCount > 0) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.MANA_DISINTEGRATOR) {
+ if (manaDisintegratorCount >= 10) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.CONVERT_TO_DUNGEON) {
+ if (dungeonItem > 0) levelStr = "✔";
+ else levelStr = "✖";
+
+ } else if (item.itemType == ItemType.RUBY_GEMSTONE) {
+ levelStr = "❤";
+
+ } else if (item.itemType == ItemType.AMETHYST_GEMSTONE) {
+ levelStr = "❈";
+
+ } else if (item.itemType == ItemType.SAPPHIRE_GEMSTONE) {
+ levelStr = "✎";
+
+ } else if (item.itemType == ItemType.JADE_GEMSTONE) {
+ levelStr = "☘";
+
+ } else if (item.itemType == ItemType.AMBER_GEMSTONE) {
+ levelStr = "⸕";
+
+ } else if (item.itemType == ItemType.TOPAZ_GEMSTONE) {
+ levelStr = "✧";
+
+ } else if (item.itemType == ItemType.JASPER_GEMSTONE) {
+ levelStr = "❁";
+
+ } else if (item.itemType == ItemType.OPAL_GEMSTONE) {
+ levelStr = "❂";
+ }
+ } else {
+ levelStr = "?";
+ }
+ return levelStr;
+ }
+
+ private void renderBaseTexture() {
+ //Base Texture
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft, guiTop, X_SIZE, Y_SIZE,
+ 0, X_SIZE / 512f, 0, Y_SIZE / 512f, GL11.GL_NEAREST
+ );
+ }
+
+ private List<String> renderSettings(int mouseX, int mouseY, List<String> tooltipToDisplay) {
+ //Settings Buttons
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ //On Settings Button
+ Utils.drawTexturedRect(guiLeft + 295, guiTop + 147, 16, 16,
+ 0, 16 / 512f, 387 / 512f, (387 + 16) / 512f, GL11.GL_NEAREST
+ );
+ //Sorting Settings Button
+ float sortingMinU = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantSorting * 16 / 512f;
+ Utils.drawTexturedRect(guiLeft + 295, guiTop + 147 + 18, 16, 16,
+ sortingMinU, sortingMinU + 16 / 512f, 419 / 512f, (419 + 16) / 512f, GL11.GL_NEAREST
+ );
+ //Ordering Settings Button
+ float orderingMinU = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantOrdering * 16 / 512f;
+ Utils.drawTexturedRect(guiLeft + 295 + 18, guiTop + 147 + 18, 16, 16,
+ orderingMinU, orderingMinU + 16 / 512f, 435 / 512f, (435 + 16) / 512f, GL11.GL_NEAREST
+ );
+
+ if (mouseX >= guiLeft + 294 && mouseX < guiLeft + 294 + 36 &&
+ mouseY >= guiTop + 146 && mouseY < guiTop + 146 + 36) {
+ int index = (mouseX - (guiLeft + 295)) / 18 + (mouseY - (guiTop + 147)) / 18 * 2;
+ switch (index) {
+ case 0:
+ Gui.drawRect(guiLeft + 295, guiTop + 147, guiLeft + 295 + 16, guiTop + 147 + 16, 0x80ffffff);
+ tooltipToDisplay = createTooltip("Enable GUI", 0, "On", "Off");
+ break;
+ case 1:
+ Gui.drawRect(guiLeft + 295 + 18, guiTop + 147, guiLeft + 295 + 16 + 18, guiTop + 147 + 16, 0x80ffffff);
+ tooltipToDisplay = createTooltip("Max Level",
+ (NotEnoughUpdates.INSTANCE.config.enchantingSolvers.maxEnchLevel ? 0 : 1),
+ "Enabled", "Disabled");
+ tooltipToDisplay.add(1, EnumChatFormatting.GRAY + "Show max level of enchant");
+ tooltipToDisplay.add(2, EnumChatFormatting.GRAY + "from either hex or enchantment table");
+ tooltipToDisplay.add(3, EnumChatFormatting.GRAY + "max level");
+ break;
+ case 2:
+ Gui.drawRect(guiLeft + 295, guiTop + 147 + 18, guiLeft + 295 + 16, guiTop + 147 + 16 + 18, 0x80ffffff);
+ tooltipToDisplay = createTooltip("Sort enchants...",
+ NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantSorting,
+ "By Cost", "Alphabetically"
+ );
+ break;
+ case 3:
+ Gui.drawRect(
+ guiLeft + 295 + 18,
+ guiTop + 147 + 18,
+ guiLeft + 295 + 16 + 18,
+ guiTop + 147 + 16 + 18,
+ 0x80ffffff
+ );
+ tooltipToDisplay = createTooltip("Order enchants...",
+ NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantOrdering,
+ "Ascending", "Descending"
+ );
+ break;
+ }
+ }
+ return tooltipToDisplay;
+ }
+
+ private void renderScrollBars(List applicable, List removable, int mouseY) {
+ //Left scroll bar
+ {
+ int offset;
+ if (applicable.size() <= 6) {
+ offset = 0;
+ } else if (isScrollingLeft && clickedScrollOffset >= 0) {
+ offset = mouseY - clickedScrollOffset;
+ if (offset < 0) offset = 0;
+ if (offset > 96 - 15) offset = 96 - 15;
+ } else {
+ offset = Math.round((96 - 15) * (leftScroll.getValue() / (float) ((applicable.size() - 6) * 16)));
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 104, guiTop + 18 + offset, 12, 15,
+ 0, 12 / 512f, 313 / 512f, (313 + 15) / 512f, GL11.GL_NEAREST
+ );
+ }
+ //Right scroll bar
+ {
+ int offset;
+ if (removable.size() <= 6) {
+ offset = 0;
+ } else if (!isScrollingLeft && clickedScrollOffset >= 0) {
+ offset = mouseY - clickedScrollOffset;
+ if (offset < 0) offset = 0;
+ if (offset > 96 - 15) offset = 96 - 15;
+ } else {
+ offset = Math.round((96 - 15) * (rightScroll.getValue() / (float) ((removable.size() - 6) * 16)));
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + 344, guiTop + 18 + offset, 12, 15,
+ 0, 12 / 512f, 313 / 512f, (313 + 15) / 512f, GL11.GL_NEAREST
+ );
+ }
+ }
+
+ private void renderArrow() {
+ //Enchant arrow
+ if (arrowAmount.getValue() > 0) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ float w = 22 * arrowAmount.getValue();
+ if (removingEnchantPlayerLevel < 0) {
+ Utils.drawTexturedRect(guiLeft + 134, guiTop + 58, w, 16,
+ 0, w / 512f, 297 / 512f, (297 + 16) / 512f, GL11.GL_NEAREST
+ );
+ } else {
+ Utils.drawTexturedRect(guiLeft + 230 - w, guiTop + 58, w, 16,
+ (44 - w) / 512f, 44 / 512f, 297 / 512f, (297 + 16) / 512f, GL11.GL_NEAREST
+ );
+ }
+ }
+ }
+
+ private void renderCancel() {
+ int top = guiTop + 83;
+ //Cancel button
+ if (System.currentTimeMillis() - cancelButtonAnimTime < 500) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 342 / 512f, (342 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 25, top + 18 + 9, false, 0xa04040
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawStringCentered("Cancel", Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + X_SIZE / 2 + 1 + 24, top + 18 + 8, false, 0xa04040
+ );
+ }
+ }
+
+ private void renderOrbAnim(float partialTicks) {
+ //Orb animation
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(guiLeft, guiTop, 0);
+ orbDisplay.renderOrbs(partialTicks);
+ GlStateManager.popMatrix();
+ }
+
+ private void renderMouseStack(
+ ItemStack stackOnMouse, boolean disallowClick,
+ int mouseX, int mouseY, int width, int height,
+ List<String> tooltipToDisplay
+ ) {
+ if (stackOnMouse != null) {
+ if (disallowClick) {
+ Utils.drawItemStack(new ItemStack(Item.getItemFromBlock(Blocks.barrier)), mouseX - 8, mouseY - 8);
+ } else {
+ Utils.drawItemStack(stackOnMouse, mouseX - 8, mouseY - 8);
+ }
+ } else if (tooltipToDisplay != null) {
+ Utils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+
+ private void renderEnchantBook(ScaledResolution scaledresolution, float partialTicks) {
+ GlStateManager.enableDepth();
+
+ GlStateManager.pushMatrix();
+ GlStateManager.matrixMode(5889);
+ GlStateManager.pushMatrix();
+ GlStateManager.loadIdentity();
+ GlStateManager.viewport((scaledresolution.getScaledWidth() - 320) / 2 * scaledresolution.getScaleFactor(),
+ (scaledresolution.getScaledHeight() - 240) / 2 * scaledresolution.getScaleFactor(),
+ 320 * scaledresolution.getScaleFactor(), 240 * scaledresolution.getScaleFactor()
+ );
+ GlStateManager.translate(0.0F, 0.33F, 0.0F);
+ Project.gluPerspective(90.0F, 1.3333334F, 9.0F, 80.0F);
+ GlStateManager.matrixMode(5888);
+ GlStateManager.loadIdentity();
+ RenderHelper.enableStandardItemLighting();
+ GlStateManager.translate(0.0F, 3.3F, -16.0F);
+ GlStateManager.scale(5, 5, 5);
+ GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(ENCHANTMENT_TABLE_BOOK_TEXTURE);
+ GlStateManager.rotate(20.0F, 1.0F, 0.0F, 0.0F);
+ float bookOpenAngle = this.bookOpenLast + (this.bookOpen - this.bookOpenLast) * partialTicks;
+ GlStateManager.translate(
+ (1.0F - bookOpenAngle) * 0.2F,
+ (1.0F - bookOpenAngle) * 0.1F,
+ (1.0F - bookOpenAngle) * 0.25F
+ );
+ GlStateManager.rotate(-(1.0F - bookOpenAngle) * 90.0F - 90.0F, 0.0F, 1.0F, 0.0F);
+ GlStateManager.rotate(180.0F, 1.0F, 0.0F, 0.0F);
+ float pageAngle1 = this.pageOpenLast + (this.pageOpen - this.pageOpenLast) * partialTicks + 0.25F;
+ float pageAngle2 = this.pageOpenLast + (this.pageOpen - this.pageOpenLast) * partialTicks + 0.75F;
+ pageAngle1 = (pageAngle1 - (float) MathHelper.truncateDoubleToInt(pageAngle1)) * 1.6F - 0.3F;
+ pageAngle2 = (pageAngle2 - (float) MathHelper.truncateDoubleToInt(pageAngle2)) * 1.6F - 0.3F;
+
+ if (pageAngle1 < 0.0F) pageAngle1 = 0.0F;
+ if (pageAngle1 > 1.0F) pageAngle1 = 1.0F;
+ if (pageAngle2 < 0.0F) pageAngle2 = 0.0F;
+ if (pageAngle2 > 1.0F) pageAngle2 = 1.0F;
+
+ GlStateManager.enableRescaleNormal();
+ MODEL_BOOK.render(null, 0.0F, pageAngle1, pageAngle2, bookOpenAngle, 0.0F, 0.0625F);
+ GlStateManager.disableRescaleNormal();
+ RenderHelper.disableStandardItemLighting();
+ GlStateManager.matrixMode(5889);
+ GlStateManager.viewport(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight);
+ GlStateManager.popMatrix();
+ GlStateManager.matrixMode(5888);
+ GlStateManager.popMatrix();
+ RenderHelper.disableStandardItemLighting();
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+
+ GlStateManager.enableDepth();
+ }
+
+ private boolean isInEnchanting() {
+ return currentState == EnchantState.ADDING_ENCHANT || currentState == EnchantState.HAS_ITEM ||
+ currentState == EnchantState.SWITCHING_DONT_UPDATE;
+ }
+
+ private boolean isInHex() {
+ return currentState == EnchantState.HAS_ITEM_IN_HEX || currentState == EnchantState.INVALID_ITEM_HEX ||
+ currentState == EnchantState.NO_ITEM_IN_HEX;
+ }
+
+ private boolean isInGemstones() {
+ return currentState == EnchantState.HAS_ITEM_IN_GEMSTONE || currentState == EnchantState.ADDING_GEMSTONE ||
+ currentState == EnchantState.APPLYING_GEMSTONE;
+ }
+
+ public void overrideIsMouseOverSlot(Slot slot, int mouseX, int mouseY, CallbackInfoReturnable<Boolean> cir) {
+ if ((shouldOverrideFast || shouldOverrideGemstones || shouldOverrideXp) &&
+ currentState != EnchantState.ADDING_ENCHANT) {
+ boolean playerInv = slot.inventory == Minecraft.getMinecraft().thePlayer.inventory;
+ int slotId = slot.getSlotIndex();
+ if (playerInv && slotId < 36) {
+ slotId -= 9;
+ if (slotId < 0) slotId += 36;
+
+ int itemX = guiLeft + 102 + 18 * (slotId % 9);
+ int itemY = guiTop + 133 + 18 * (slotId / 9);
+
+ if (slotId >= 27) {
+ itemY += 4;
+ }
+
+ if (mouseX >= itemX && mouseX < itemX + 18 &&
+ mouseY >= itemY && mouseY < itemY + 18) {
+ cir.setReturnValue(true);
+ } else {
+ cir.setReturnValue(false);
+ }
+ } else if ((slotId == 19 && !isInHex()) || (slotId == 22 && isInHex())) {
+ cir.setReturnValue(mouseX >= guiLeft + 173 && mouseX < guiLeft + 173 + 18 &&
+ mouseY >= guiTop + 57 && mouseY < guiTop + 57 + 18);
+ }
+ }
+ }
+
+ public boolean mouseInput(int mouseX, int mouseY) {
+ if (Mouse.getEventButtonState() &&
+ (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.ADDING_ENCHANT ||
+ currentState == EnchantState.HAS_ITEM_IN_HEX || currentState == EnchantState.ADDING_BOOK ||
+ currentState == EnchantState.ADDING_GEMSTONE || currentState == EnchantState.APPLYING_GEMSTONE)) {
+ if (mouseY > guiTop + 6 && mouseY < guiTop + 6 + 15) {
+ String pageStr = "Page: " + currentPage + "/" + expectedMaxPage;
+ int pageStrLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(pageStr);
+
+ int click = -1;
+ if (mouseX > guiLeft + X_SIZE / 2 - pageStrLen / 2 - 2 - 15 &&
+ mouseX <= guiLeft + X_SIZE / 2 - pageStrLen / 2 - 2) {
+ click = 17;
+ } else if (mouseX > guiLeft + X_SIZE / 2 + pageStrLen / 2 + 2 &&
+ mouseX <= guiLeft + X_SIZE / 2 + pageStrLen / 2 + 2 + 15) {
+ click = 35;
+ }
+
+ if (click >= 0) {
+ if (currentState == EnchantState.ADDING_ENCHANT || currentState == EnchantState.ADDING_BOOK) {
+ if (Mouse.getEventButtonState()) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ }
+ } else {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(click);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, click, 0, 0, stack, transactionID));
+ }
+ return true;
+ }
+ }
+ }
+
+ // Cancel button
+ if (currentState == EnchantState.HAS_ITEM ||
+ currentState == EnchantState.HAS_ITEM_IN_BOOKS || currentState == EnchantState.HAS_ITEM_IN_GEMSTONE) {
+ if (Mouse.getEventButtonState()) {
+ int top = guiTop + 83;
+
+ if (!isChangingEnchLevel && mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ leftScroll.setValue(0);
+ rightScroll.setValue(0);
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState != EnchantState.ADDING_BOOK) {
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+ if (isInGemstones()) {
+ currentState = EnchantState.HAS_ITEM_IN_GEMSTONE;
+ }
+ } else {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ }
+ searchField.setText("");
+ cancelButtonAnimTime = System.currentTimeMillis();
+ enchanterCurrentItem = null;
+ }
+
+ if (mouseX > guiLeft + X_SIZE / 2 - searchField.getWidth() / 2 &&
+ mouseX < guiLeft + X_SIZE / 2 + searchField.getWidth() / 2 &&
+ mouseY > guiTop + 80 && mouseY < guiTop + 96) {
+ searchField.mouseClicked(mouseX, mouseY, Mouse.getEventButton());
+ } else {
+ searchField.setFocus(false);
+ }
+ } else if (Mouse.getEventButton() < 0 && searchField.getFocus() && Mouse.isButtonDown(0)) {
+ searchField.mouseClickMove(mouseX, mouseY, 0, 0);
+ }
+ } else if (currentState == EnchantState.ADDING_ENCHANT && !enchanterEnchLevels.isEmpty()) {
+ if (Mouse.getEventButtonState()) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+
+ if (!isChangingEnchLevel && mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ } else if (!isChangingEnchLevel && enchanterCurrentEnch != null &&
+ (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) ||
+ (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14)) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(
+ enchanterCurrentEnch.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ enchanterCurrentEnch.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ int playerXpLevel = Minecraft.getMinecraft().thePlayer.experienceLevel;
+ if (playerXpLevel >= enchanterCurrentEnch.xpCost) {
+ if (removingEnchantPlayerLevel >= 0 && enchanterCurrentEnch.level == removingEnchantPlayerLevel) {
+ orbDisplay.spawnExperienceOrbs(X_SIZE / 2, 66, X_SIZE / 2, 36, 3);
+ } else {
+ orbDisplay.spawnExperienceOrbs(mouseX - guiLeft, mouseY - guiTop, X_SIZE / 2, 66, 0);
+ }
+ }
+
+ confirmButtonAnimTime = System.currentTimeMillis();
+ } else if (mouseX > left + 96 && mouseX <= left + 96 + 16) {
+ if (!isChangingEnchLevel) {
+ if (mouseY > top && mouseY < top + 16) {
+ isChangingEnchLevel = true;
+ return true;
+ }
+ } else {
+ List<Enchantment> before = new ArrayList<>();
+ List<Enchantment> after = new ArrayList<>();
+
+ for (Enchantment ench : enchanterEnchLevels.values()) {
+ if (ench.level < enchanterCurrentEnch.level) {
+ before.add(ench);
+ } else if (ench.level > enchanterCurrentEnch.level) {
+ after.add(ench);
+ }
+ }
+
+ before.sort(Comparator.comparingInt(o -> -o.level));
+ after.sort(Comparator.comparingInt(o -> o.level));
+
+ int bSize = before.size();
+ int aSize = after.size();
+ for (int i = 0; i < bSize + aSize; i++) {
+ Enchantment ench;
+ int yIndex;
+ if (i < bSize) {
+ yIndex = -i - 1;
+ ench = before.get(i);
+ } else {
+ yIndex = i - bSize + 1;
+ ench = after.get(i - bSize);
+ }
+
+ if (mouseY > top + 16 * yIndex && mouseY <= top + 16 * yIndex + 16) {
+ enchanterCurrentEnch = ench;
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (isChangingEnchLevel) {
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ } else if (currentState == EnchantState.ADDING_BOOK) {
+ if (Mouse.getEventButtonState()) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+
+ if (!isChangingEnchLevel && mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ /*GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));*/
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ enchanterCurrentItem = null;
+ } else if (!isChangingEnchLevel && enchanterCurrentItem != null &&
+ (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) ||
+ (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14)) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(
+ enchanterCurrentItem.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ enchanterCurrentItem.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ if (removingEnchantPlayerLevel >= 0 && enchanterCurrentItem.level == removingEnchantPlayerLevel) {
+ orbDisplay.spawnExperienceOrbs(X_SIZE / 2, 66, X_SIZE / 2, 36, 3);
+ } else {
+ orbDisplay.spawnExperienceOrbs(mouseX - guiLeft, mouseY - guiTop, X_SIZE / 2, 66, 0);
+ }
+
+ confirmButtonAnimTime = System.currentTimeMillis();
+ enchanterCurrentItem = null;
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ } else if (mouseX > left + 96 && mouseX <= left + 96 + 16) {
+ if (!isChangingEnchLevel) {
+ if (mouseY > top && mouseY < top + 16) {
+ isChangingEnchLevel = true;
+ return true;
+ }
+ } else {
+ List<HexItem> before = new ArrayList<>();
+ List<HexItem> after = new ArrayList<>();
+
+ for (HexItem item : enchanterItemLevels.values()) {
+ if (item.level < enchanterCurrentItem.level) {
+ before.add(item);
+ } else if (item.level > enchanterCurrentItem.level) {
+ after.add(item);
+ }
+ }
+
+ before.sort(Comparator.comparingInt(o -> -o.level));
+ after.sort(Comparator.comparingInt(o -> o.level));
+
+ int bSize = before.size();
+ int aSize = after.size();
+ for (int i = 0; i < bSize + aSize; i++) {
+ HexItem item;
+ int yIndex;
+ if (i < bSize) {
+ yIndex = -i - 1;
+ item = before.get(i);
+ } else {
+ yIndex = i - bSize + 1;
+ item = after.get(i - bSize);
+ }
+
+ if (mouseY > top + 16 * yIndex && mouseY <= top + 16 * yIndex + 16) {
+ enchanterCurrentItem = item;
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (isChangingEnchLevel) {
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ } else if (currentState == EnchantState.HAS_ITEM_IN_HEX) {
+ if (Mouse.getEventButtonState()) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+
+ if (!isChangingEnchLevel && mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14) {
+ /*if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ enchanterCurrentItem = null;*/
+ } else if (!isChangingEnchLevel && enchanterCurrentItem != null &&
+ (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) ||
+ (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14)) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(
+ enchanterCurrentItem.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ enchanterCurrentItem.slotIndex, 0, 0, stack, transactionID
+ ));
+ enchantingItem = null;
+ if (removingEnchantPlayerLevel >= 0 && enchanterCurrentItem.level == removingEnchantPlayerLevel) {
+ orbDisplay.spawnExperienceOrbs(X_SIZE / 2, 66, X_SIZE / 2, 36, 3);
+ } else {
+ orbDisplay.spawnExperienceOrbs(mouseX - guiLeft, mouseY - guiTop, X_SIZE / 2, 66, 0);
+ }
+
+ confirmButtonAnimTime = System.currentTimeMillis();
+ //enchanterCurrentItem = null;
+ //currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ } else if (mouseX > left + 96 && mouseX <= left + 96 + 16) {
+ if (!isChangingEnchLevel) {
+ if (mouseY > top && mouseY < top + 16) {
+ isChangingEnchLevel = true;
+ return true;
+ }
+ } else {
+ List<HexItem> before = new ArrayList<>();
+ List<HexItem> after = new ArrayList<>();
+
+ for (HexItem item : enchanterItemLevels.values()) {
+ if (item.level < enchanterCurrentItem.level) {
+ before.add(item);
+ } else if (item.level > enchanterCurrentItem.level) {
+ after.add(item);
+ }
+ }
+
+ before.sort(Comparator.comparingInt(o -> -o.level));
+ after.sort(Comparator.comparingInt(o -> o.level));
+
+ int bSize = before.size();
+ int aSize = after.size();
+ for (int i = 0; i < bSize + aSize; i++) {
+ HexItem item;
+ int yIndex;
+ if (i < bSize) {
+ yIndex = -i - 1;
+ item = before.get(i);
+ } else {
+ yIndex = i - bSize + 1;
+ item = after.get(i - bSize);
+ }
+
+ if (mouseY > top + 16 * yIndex && mouseY <= top + 16 * yIndex + 16) {
+ enchanterCurrentItem = item;
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (isChangingEnchLevel) {
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ } else if (currentState == EnchantState.ADDING_GEMSTONE || currentState == EnchantState.APPLYING_GEMSTONE) {
+ if (Mouse.getEventButtonState()) {
+ int left = guiLeft + X_SIZE / 2 - 56;
+ int top = guiTop + 83;
+
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 - 1 - 48, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+ Utils.drawTexturedRect(guiLeft + X_SIZE / 2 + 1, top + 18, 48, 14,
+ 0, 48 / 512f, 328 / 512f, (328 + 14) / 512f, GL11.GL_NEAREST
+ );
+
+ if (!isChangingEnchLevel && mouseX > guiLeft + X_SIZE / 2 + 1 && mouseX <= guiLeft + X_SIZE / 2 + 1 + 48 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState != EnchantState.APPLYING_GEMSTONE) {
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ currentState = EnchantState.HAS_ITEM_IN_GEMSTONE;
+ enchanterCurrentItem = null;
+ } else {
+ currentState = EnchantState.ADDING_ENCHANT;
+ enchanterCurrentItem = null;
+ }
+ } else if (!isChangingEnchLevel && enchanterCurrentItem != null &&
+ (mouseX > left + 16 && mouseX <= left + 96 &&
+ mouseY > top && mouseY <= top + 16) ||
+ (mouseX > guiLeft + X_SIZE / 2 - 1 - 48 && mouseX <= guiLeft + X_SIZE / 2 - 1 &&
+ mouseY > top + 18 && mouseY <= top + 18 + 14) && currentState == EnchantState.APPLYING_GEMSTONE) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(
+ enchanterCurrentItem.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ enchanterCurrentItem.slotIndex, 0, 0, stack, transactionID
+ ));
+ enchantingItem = null;
+ if (removingEnchantPlayerLevel >= 0 && enchanterCurrentItem.level == removingEnchantPlayerLevel) {
+ orbDisplay.spawnExperienceOrbs(X_SIZE / 2, 66, X_SIZE / 2, 36, 3);
+ } else {
+ orbDisplay.spawnExperienceOrbs(mouseX - guiLeft, mouseY - guiTop, X_SIZE / 2, 66, 0);
+ }
+
+ confirmButtonAnimTime = System.currentTimeMillis();
+ enchanterCurrentItem = null;
+ currentState = EnchantState.ADDING_GEMSTONE;
+ } else if (mouseX > left + 96 && mouseX <= left + 96 + 16) {
+ if (!isChangingEnchLevel) {
+ if (mouseY > top && mouseY < top + 16) {
+ isChangingEnchLevel = true;
+ return true;
+ }
+ } else {
+ List<HexItem> before = new ArrayList<>();
+ List<HexItem> after = new ArrayList<>();
+
+ for (HexItem item : enchanterItemLevels.values()) {
+ if (item.level < enchanterCurrentItem.level) {
+ before.add(item);
+ } else if (item.level > enchanterCurrentItem.level) {
+ after.add(item);
+ }
+ }
+
+ before.sort(Comparator.comparingInt(o -> -o.level));
+ after.sort(Comparator.comparingInt(o -> o.level));
+
+ int bSize = before.size();
+ int aSize = after.size();
+ for (int i = 0; i < bSize + aSize; i++) {
+ HexItem item;
+ int yIndex;
+ if (i < bSize) {
+ yIndex = -i - 1;
+ item = before.get(i);
+ } else {
+ yIndex = i - bSize + 1;
+ item = after.get(i - bSize);
+ }
+
+ if (mouseY > top + 16 * yIndex && mouseY <= top + 16 * yIndex + 16) {
+ enchanterCurrentItem = item;
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (isChangingEnchLevel) {
+ isChangingEnchLevel = false;
+ return true;
+ }
+ }
+ }
+
+ if (!Mouse.getEventButtonState() && Mouse.getEventButton() < 0 && clickedScrollOffset != -1) {
+ if (isInEnchanting()) {
+ LerpingInteger lerpingInteger = isClickedScrollLeft ? leftScroll : rightScroll;
+ List<Enchantment> enchantsList = isClickedScrollLeft ? applicable : removable;
+
+ if (enchantsList.size() > 6) {
+ int newOffset = mouseY - clickedScrollOffset;
+
+ int newScroll = Math.round(newOffset * (float) ((enchantsList.size() - 6) * 16) / (96 - 15));
+ int max = (enchantsList.size() - 6) * 16;
+
+ if (newScroll > max) newScroll = max;
+ if (newScroll < 0) newScroll = 0;
+
+ lerpingInteger.setValue(newScroll);
+ }
+ } else {
+ LerpingInteger lerpingInteger = isClickedScrollLeft ? leftScroll : rightScroll;
+ List<HexItem> itemsList = isClickedScrollLeft ? applicableItem : removableItem;
+
+ if (itemsList.size() > 6) {
+ int newOffset = mouseY - clickedScrollOffset;
+
+ int newScroll = Math.round(newOffset * (float) ((itemsList.size() - 6) * 16) / (96 - 15));
+ int max = (itemsList.size() - 6) * 16;
+
+ if (newScroll > max) newScroll = max;
+ if (newScroll < 0) newScroll = 0;
+
+ lerpingInteger.setValue(newScroll);
+ }
+ }
+ }
+
+ //Config options
+ if (Mouse.getEventButtonState()) {
+ if (mouseX >= guiLeft + 294 && mouseX < guiLeft + 294 + 36 &&
+ mouseY >= guiTop + 146 && mouseY < guiTop + 146 + 36) {
+ int index = (mouseX - (guiLeft + 295)) / 18 + (mouseY - (guiTop + 147)) / 18 * 2;
+
+ int direction = Mouse.getEventButton() == 0 ? 1 : -1;
+
+ switch (index) {
+ case 0: {
+ NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enableHexGUI = false;
+ break;
+ }
+ case 1: {
+ NotEnoughUpdates.INSTANCE.config.enchantingSolvers.maxEnchLevel = !NotEnoughUpdates.INSTANCE.config.enchantingSolvers.maxEnchLevel;
+ break;
+ }
+ case 2: {
+ int val = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantSorting;
+ val += direction;
+ if (val < 0) val = 1;
+ if (val > 1) val = 0;
+ NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantSorting = val;
+ break;
+ }
+ case 3: {
+ int val = NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantOrdering;
+ val += direction;
+ if (val < 0) val = 1;
+ if (val > 1) val = 0;
+ NotEnoughUpdates.INSTANCE.config.enchantingSolvers.enchantOrdering = val;
+ break;
+ }
+ }
+ }
+ }
+
+ if (Mouse.getEventButton() == 0) {
+ if (Mouse.getEventButtonState()) {
+ if (isInEnchanting()) {
+ if (mouseX > guiLeft + 104 && mouseX < guiLeft + 104 + 12) {
+ int offset;
+ if (applicable.size() <= 6) {
+ offset = 0;
+ } else {
+ offset = Math.round((96 - 15) * (leftScroll.getValue() / (float) ((applicable.size() - 6) * 16)));
+ }
+ if (mouseY >= guiTop + 18 + offset && mouseY < guiTop + 18 + offset + 15) {
+ isClickedScrollLeft = true;
+ clickedScrollOffset = mouseY - offset;
+ }
+ } else if (mouseX > guiLeft + 344 && mouseX < guiLeft + 344 + 12) {
+ int offset;
+ if (removable.size() <= 6) {
+ offset = 0;
+ } else {
+ offset = Math.round((96 - 15) * (rightScroll.getValue() / (float) ((removable.size() - 6) * 16)));
+ }
+ if (mouseY >= guiTop + 18 + offset && mouseY < guiTop + 18 + offset + 15) {
+ isClickedScrollLeft = false;
+ clickedScrollOffset = mouseY - offset;
+ }
+ }
+ } else {
+ if (mouseX > guiLeft + 104 && mouseX < guiLeft + 104 + 12) {
+ int offset;
+ if (applicableItem.size() <= 6) {
+ offset = 0;
+ } else {
+ offset = Math.round((96 - 15) * (leftScroll.getValue() / (float) ((applicableItem.size() - 6) * 16)));
+ }
+ if (mouseY >= guiTop + 18 + offset && mouseY < guiTop + 18 + offset + 15) {
+ isClickedScrollLeft = true;
+ clickedScrollOffset = mouseY - offset;
+ }
+ } else if (mouseX > guiLeft + 344 && mouseX < guiLeft + 344 + 12) {
+ int offset;
+ if (removableItem.size() <= 6) {
+ offset = 0;
+ } else {
+ offset = Math.round((96 - 15) * (rightScroll.getValue() / (float) ((removableItem.size() - 6) * 16)));
+ }
+ if (mouseY >= guiTop + 18 + offset && mouseY < guiTop + 18 + offset + 15) {
+ isClickedScrollLeft = false;
+ clickedScrollOffset = mouseY - offset;
+ }
+ }
+ }
+ } else {
+ clickedScrollOffset = -1;
+ }
+ }
+
+ if (mouseY > guiTop + 18 && mouseY < guiTop + 18 + 96) {
+ if (mouseX > guiLeft + 8 && mouseX < guiLeft + 8 + 96) {
+ if (Mouse.getEventButton() == 0 && Mouse.getEventButtonState() &&
+ Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
+ if (isInEnchanting()) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+ if (applicable.size() <= index) break;
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ Enchantment ench = applicable.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState == EnchantState.HAS_ITEM) {
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(ench.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ ench.slotIndex, 0, 0, stack, transactionID
+ ));
+ } else if (currentState == EnchantState.ADDING_ENCHANT) {
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ }
+
+ return true;
+ }
+ }
+ } else if (!isInHex() && !isInGemstones()) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+ if (applicableItem.size() <= index) break;
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ HexItem item = applicableItem.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState == EnchantState.HAS_ITEM_IN_BOOKS) {
+ currentState = EnchantState.ADDING_BOOK;
+ enchanterCurrentItem = item;
+ } else if (currentState == EnchantState.ADDING_BOOK && enchanterCurrentItem == item) {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(item.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ item.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ } else {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ enchanterCurrentItem = null;
+ }
+
+ return true;
+ }
+ }
+ } else if (isInHex() && !isInGemstones()) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+ if (applicableItem.size() <= index) break;
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ HexItem item = applicableItem.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(item.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ item.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ //cancelButtonAnimTime = System.currentTimeMillis();
+
+ return true;
+ }
+ }
+ } else if (currentState == EnchantState.ADDING_GEMSTONE || currentState == EnchantState.APPLYING_GEMSTONE) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+ if (applicableItem.size() <= index) break;
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ HexItem item = applicableItem.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState == EnchantState.ADDING_GEMSTONE) {
+ currentState = EnchantState.APPLYING_GEMSTONE;
+ enchanterCurrentItem = item;
+ } else if (currentState == EnchantState.APPLYING_GEMSTONE && enchanterCurrentItem == item) {
+ currentState = EnchantState.ADDING_GEMSTONE;
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(item.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ item.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ } else {
+ currentState = EnchantState.ADDING_GEMSTONE;
+ enchanterCurrentItem = null;
+ }
+
+ //cancelButtonAnimTime = System.currentTimeMillis();
+
+ return true;
+ }
+ }
+ } else if (currentState == EnchantState.HAS_ITEM_IN_GEMSTONE) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + leftScroll.getValue() / 16;
+ if (applicableItem.size() <= index) break;
+
+ int top = guiTop - (leftScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 8 && mouseX <= guiLeft + 8 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ HexItem item = applicableItem.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(item.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ item.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+
+ //cancelButtonAnimTime = System.currentTimeMillis();
+
+ return true;
+ }
+ }
+ }
+ }
+
+ isScrollingLeft = true;
+ } else if (mouseX > guiLeft + 248 && mouseX < guiLeft + 248 + 96) {
+ if (Mouse.getEventButton() == 0 && Mouse.getEventButtonState() &&
+ Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
+ if (isInEnchanting()) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+ if (removable.size() <= index) break;
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ Enchantment ench = removable.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState == EnchantState.HAS_ITEM || currentState == EnchantState.HAS_ITEM_IN_HEX) {
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(ench.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ ench.slotIndex, 0, 0, stack, transactionID
+ ));
+ } else if (currentState == EnchantState.ADDING_ENCHANT) {
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ }
+
+ return true;
+ }
+ }
+ } else if (currentState == EnchantState.ADDING_GEMSTONE) {
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+ if (removableItem.size() <= index) break;
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ HexItem item = removableItem.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState == EnchantState.ADDING_GEMSTONE) {
+ currentState = EnchantState.APPLYING_GEMSTONE;
+ enchanterCurrentItem = item;
+ } else if (currentState == EnchantState.APPLYING_GEMSTONE && enchanterCurrentItem == item) {
+ currentState = EnchantState.ADDING_GEMSTONE;
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(item.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ item.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ } else {
+ currentState = EnchantState.ADDING_GEMSTONE;
+ enchanterCurrentItem = null;
+ }
+
+ return true;
+ }
+ }
+
+ } else {
+ for (int i = 0; i < 7; i++) {
+ int index = i + rightScroll.getValue() / 16;
+ if (removableItem.size() <= index) break;
+
+ int top = guiTop - (rightScroll.getValue() % 16) + 18 + 16 * i;
+ if (mouseX > guiLeft + 248 && mouseX <= guiLeft + 248 + 96 &&
+ mouseY > top && mouseY <= top + 16) {
+ HexItem item = removableItem.get(index);
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ if (currentState == EnchantState.HAS_ITEM_IN_BOOKS) {
+ currentState = EnchantState.ADDING_BOOK;
+ enchanterCurrentItem = item;
+ } else if (currentState == EnchantState.ADDING_BOOK && enchanterCurrentItem == item) {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack =
+ ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(item.slotIndex);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId,
+ item.slotIndex, 0, 0, stack, transactionID
+ ));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ } else {
+ currentState = EnchantState.HAS_ITEM_IN_BOOKS;
+ enchanterCurrentItem = null;
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+ isScrollingLeft = false;
+ }
+ }
+ if (Mouse.getEventDWheel() != 0) {
+ int scroll = Mouse.getEventDWheel();
+ if (scroll > 0) {
+ scroll = -16;
+ } else {
+ scroll = 16;
+ }
+
+ LerpingInteger lerpingInteger = isScrollingLeft ? leftScroll : rightScroll;
+ int elementsCount;
+ if (isInEnchanting()) {
+ elementsCount = isScrollingLeft ? applicable.size() : removable.size();
+ } else {
+ elementsCount = isScrollingLeft ? applicableItem.size() : removableItem.size();
+ }
+ int max = (elementsCount - 6) * 16;
+
+ int newTarget = lerpingInteger.getTarget() + scroll;
+ if (newTarget > max) newTarget = max;
+ if (newTarget < 0) newTarget = 0;
+
+ if (newTarget != lerpingInteger.getTarget()) {
+ lerpingInteger.resetTimer();
+ lerpingInteger.setTarget(newTarget);
+ }
+ }
+
+ if (mouseX > guiLeft + 102 && mouseX < guiLeft + 102 + 160) {
+ if ((mouseY > guiTop + 133 && mouseY < guiTop + 133 + 54) ||
+ (mouseY > guiTop + 133 + 54 + 4 && mouseY < guiTop + 133 + 54 + 4 + 18)) {
+ if (currentState == EnchantState.ADDING_ENCHANT) {
+ if (Mouse.getEventButtonState()) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ if (mouseX >= guiLeft + 173 && mouseX < guiLeft + 173 + 18 &&
+ mouseY >= guiTop + 57 && mouseY < guiTop + 57 + 18) {
+ if (currentState == EnchantState.ADDING_ENCHANT) {
+ if (Mouse.getEventButtonState()) {
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiContainer)) return true;
+ GuiContainer chest = ((GuiContainer) Minecraft.getMinecraft().currentScreen);
+
+ EntityPlayerSP playerIn = Minecraft.getMinecraft().thePlayer;
+ short transactionID = playerIn.openContainer.getNextTransactionID(playerIn.inventory);
+ ItemStack stack = ((ContainerChest) chest.inventorySlots).getLowerChestInventory().getStackInSlot(45);
+ Minecraft.getMinecraft().getNetHandler().addToSendQueue(new C0EPacketClickWindow(
+ chest.inventorySlots.windowId, 45, 0, 0, stack, transactionID));
+
+ cancelButtonAnimTime = System.currentTimeMillis();
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean keyboardInput() {
+ if (currentState == EnchantState.HAS_ITEM && searchField.getFocus()) {
+ if (Keyboard.getEventKeyState()) {
+ searchField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey());
+ }
+ return true;
+ }
+ if (Keyboard.getEventKey() == Minecraft.getMinecraft().gameSettings.keyBindScreenshot.getKeyCode()) {
+ return false;
+ }
+
+ return Keyboard.getEventKey() != Keyboard.KEY_ESCAPE &&
+ Keyboard.getEventKey() != Minecraft.getMinecraft().gameSettings.keyBindInventory.getKeyCode() &&
+ (!NotEnoughUpdates.INSTANCE.config.slotLocking.enableSlotLocking ||
+ Keyboard.getEventKey() != NotEnoughUpdates.INSTANCE.config.slotLocking.slotLockKey);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/HexItem.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/HexItem.java
new file mode 100644
index 00000000..5b3b30ea
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/HexItem.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui.hex;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.util.StringUtils;
+
+import java.util.List;
+
+public class HexItem {
+ public int slotIndex;
+ public String itemName;
+ public String itemId;
+ public List<String> displayLore;
+ public int level;
+ public int price = -1;
+ public boolean overMaxLevel = false;
+ public boolean conflicts = false;
+ public ItemType itemType;
+ public int gemstoneLevel = -1;
+
+ public HexItem(
+ int slotIndex, String itemName, String itemId, List<String> displayLore,
+ boolean useMaxLevelForCost, boolean checkConflicts
+ ) {
+ this.slotIndex = slotIndex;
+ this.itemName = itemName;
+ this.itemId = itemId.replace("'S", "");
+ this.displayLore = displayLore;
+ switch (itemId) {
+ default:
+ this.itemType = ItemType.UNKNOWN;
+ break;
+ case "HOT_POTATO_BOOK":
+ this.itemType = ItemType.HOT_POTATO;
+ break;
+ case "FUMING_POTATO_BOOK":
+ this.itemType = ItemType.FUMING_POTATO;
+ break;
+ case "BOOK_OF_STATS":
+ this.itemType = ItemType.BOOK_OF_STATS;
+ break;
+ case "THE_ART_OF_WAR":
+ this.itemType = ItemType.ART_OF_WAR;
+ break;
+ case "FARMING_FOR_DUMMIES":
+ this.itemType = ItemType.FARMING_DUMMY;
+ break;
+ case "THE_ART_OF_PEACE":
+ this.itemType = ItemType.ART_OF_PEACE;
+ break;
+ case "RECOMBOBULATOR_3000":
+ this.itemType = ItemType.RECOMB;
+ break;
+ case "SILEX":
+ this.itemId = "SIL_EX";
+ this.itemType = ItemType.SILEX;
+ break;
+ case "RUBY_POWER_SCROLL":
+ this.itemType = ItemType.RUBY_SCROLL;
+ break;
+ case "SAPPHIRE_POWER_SCROLL":
+ this.itemType = ItemType.SAPPHIRE_SCROLL;
+ break;
+ case "JASPER_POWER_SCROLL":
+ this.itemType = ItemType.JASPER_SCROLL;
+ break;
+ case "AMETHYST_POWER_SCROLL":
+ this.itemType = ItemType.AMETHYST_SCROLL;
+ break;
+ case "AMBER_POWER_SCROLL":
+ this.itemType = ItemType.AMBER_SCROLL;
+ break;
+ case "OPAL_POWER_SCROLL":
+ this.itemType = ItemType.OPAL_SCROLL;
+ break;
+ case "FIRST_MASTER_STAR":
+ this.itemType = ItemType.FIRST_MASTER_STAR;
+ break;
+ case "SECOND_MASTER_STAR":
+ this.itemType = ItemType.SECOND_MASTER_STAR;
+ break;
+ case "THIRD_MASTER_STAR":
+ this.itemType = ItemType.THIRD_MASTER_STAR;
+ break;
+ case "FOURTH_MASTER_STAR":
+ this.itemType = ItemType.FOURTH_MASTER_STAR;
+ break;
+ case "FIFTH_MASTER_STAR":
+ this.itemType = ItemType.FIFTH_MASTER_STAR;
+ break;
+ case "WOOD_SINGULARITY":
+ this.itemType = ItemType.WOOD_SINGULARITY;
+ break;
+ case "IMPLOSION":
+ this.itemType = ItemType.IMPLOSION_SCROLL;
+ break;
+ case "WITHER_SHIELD":
+ this.itemType = ItemType.WITHER_SHIELD_SCROLL;
+ break;
+ case "SHADOW_WARP":
+ this.itemType = ItemType.SHADOW_WARP_SCROLL;
+ break;
+ case "TRANSMISSION_TUNER":
+ this.itemType = ItemType.TUNER;
+ break;
+ case "RANDOM_REFORGE":
+ this.itemType = ItemType.RANDOM_REFORGE;
+ break;
+ case "MANA_DISINTEGRATOR":
+ this.itemType = ItemType.MANA_DISINTEGRATOR;
+ break;
+ case "TOTAL_UPGRADES":
+ this.itemType = ItemType.TOTAL_UPGRADES;
+ break;
+ case "CONVERT_TO_DUNGEON":
+ this.itemType = ItemType.CONVERT_TO_DUNGEON;
+ break;
+ case "EXPERIENCE_BOTTLE":
+ this.itemType = ItemType.EXPERIENCE_BOTTLE;
+ break;
+ case "GRAND_EXPERIENCE_BOTTLE":
+ this.itemType = ItemType.GRAND_EXPERIENCE_BOTTLE;
+ break;
+ case "TITANIC_EXPERIENCE_BOTTLE":
+ this.itemType = ItemType.TITANIC_EXPERIENCE_BOTTLE;
+ break;
+ case "COLOSSAL_EXPERIENCE_BOTTLE":
+ this.itemType = ItemType.COLOSSAL_EXPERIENCE_BOTTLE;
+ break;
+ }
+ if (this.itemType == ItemType.UNKNOWN) {
+ for (String string : displayLore) {
+ if ((string.contains("Applies the") && string.contains("reforge")) ||
+ string.contains("reforge when combined")) {
+ this.itemType = ItemType.REFORGE;
+ break;
+ }
+ }
+ }
+ if (!this.isMasterStar() && itemId.contains("✪")) {
+ if (itemId.contains("✪✪✪✪✪")) this.itemType = ItemType.FIFTH_STAR;
+ else if (itemId.contains("✪✪✪✪")) this.itemType = ItemType.FOURTH_STAR;
+ else if (itemId.contains("✪✪✪")) this.itemType = ItemType.THIRD_STAR;
+ else if (itemId.contains("✪✪")) this.itemType = ItemType.SECOND_STAR;
+ else if (itemId.contains("✪")) this.itemType = ItemType.FIRST_STAR;
+ }
+ if (this.itemId.contains("EXPERIENCE_BOTTLE")) {
+ this.itemId = this.itemId.replace("EXPERIENCE_BOTTLE", "EXP_BOTTLE");
+ }
+ if (this.itemId.contains("END_STONE_GEODE")) {
+ this.itemId = this.itemId.replace("END_STONE_GEODE", "ENDSTONE_GEODE");
+ }
+ if (itemId.contains("HEX_ITEM")) this.itemType = ItemType.HEX_ITEM;
+ JsonObject bazaarInfo = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(this.itemId);
+ if (bazaarInfo != null && bazaarInfo.get("curr_buy") != null) {
+ this.price = bazaarInfo.get("curr_buy").getAsInt();
+ }
+ if ("SIL_EX".equals(this.itemId)) this.itemId = "SILEX";
+ if (itemName.contains("Amethyst Gemstone")) this.itemType = ItemType.AMETHYST_GEMSTONE;
+ if (itemName.contains("Ruby Gemstone")) this.itemType = ItemType.RUBY_GEMSTONE;
+ if (itemName.contains("Sapphire Gemstone")) this.itemType = ItemType.SAPPHIRE_GEMSTONE;
+ if (itemName.contains("Jasper Gemstone")) this.itemType = ItemType.JASPER_GEMSTONE;
+ if (itemName.contains("Jade Gemstone")) this.itemType = ItemType.JADE_GEMSTONE;
+ if (itemName.contains("Amber Gemstone")) this.itemType = ItemType.AMBER_GEMSTONE;
+ if (itemName.contains("Opal Gemstone")) this.itemType = ItemType.OPAL_GEMSTONE;
+ if (itemName.contains("Topaz Gemstone")) this.itemType = ItemType.TOPAZ_GEMSTONE;
+ if (itemName.contains("Gemstone Slot")) this.itemType = ItemType.GEMSTONE_SLOT;
+ if (this.itemName.contains(" Gemstone")) {
+ this.itemName = this.itemName.replace(" Gemstone", "").substring(2);
+ } else if (this.itemName.contains(" Experience Bottle")) {
+ this.itemName = this.itemName.replace("Experience Bottle", "");
+ } else if (this.itemName.equals("Experience Bottle")) {
+ this.itemName = "Exp Bottle";
+ }
+ if (isGemstone()) {
+ if (this.itemName.contains("Rough")) this.gemstoneLevel = 0;
+ if (this.itemName.contains("Flawed")) this.gemstoneLevel = 1;
+ if (this.itemName.contains("Fine")) this.gemstoneLevel = 2;
+ if (this.itemName.contains("Flawless")) this.gemstoneLevel = 3;
+ if (this.itemName.contains("Perfect")) this.gemstoneLevel = 4;
+ }
+ }
+
+ public boolean isPowerScroll() {
+ return itemType == ItemType.RUBY_SCROLL || itemType == ItemType.SAPPHIRE_SCROLL ||
+ itemType == ItemType.JASPER_SCROLL || itemType == ItemType.AMETHYST_SCROLL ||
+ itemType == ItemType.AMBER_SCROLL || itemType == ItemType.OPAL_SCROLL;
+ }
+
+ public boolean isDungeonStar() {
+ return itemType == ItemType.FIRST_STAR || itemType == ItemType.SECOND_STAR ||
+ itemType == ItemType.THIRD_STAR || itemType == ItemType.FOURTH_STAR ||
+ itemType == ItemType.FIFTH_STAR;
+ }
+
+ public boolean isMasterStar() {
+ return itemType == ItemType.FIRST_MASTER_STAR || itemType == ItemType.SECOND_MASTER_STAR ||
+ itemType == ItemType.THIRD_MASTER_STAR || itemType == ItemType.FOURTH_MASTER_STAR ||
+ itemType == ItemType.FIFTH_MASTER_STAR;
+ }
+
+ public String getReforge() {
+ JsonObject reforgeStones = Constants.REFORGESTONES;
+ if (reforgeStones != null && reforgeStones.has(this.itemId.toUpperCase())) {
+ JsonObject reforgeInfo = reforgeStones.get(this.itemId.toUpperCase()).getAsJsonObject();
+ if (reforgeInfo != null) {
+ return Utils.getElementAsString(reforgeInfo.get("reforgeName"), "");
+ }
+
+ }
+ return "";
+ }
+
+ public int getPrice() {
+ if (this.itemType == ItemType.RANDOM_REFORGE) {
+ for (String string : displayLore) {
+ if (string.contains("Coins")) {
+ try {
+ price = Integer.parseInt(StringUtils
+ .stripControlCodes(string)
+ .replace(" Coins", "")
+ .replace(",", "")
+ .trim());
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ }
+ }
+ return price;
+ }
+
+ public boolean isHypeScroll() {
+ return itemType == ItemType.IMPLOSION_SCROLL || itemType == ItemType.WITHER_SHIELD_SCROLL ||
+ itemType == ItemType.SHADOW_WARP_SCROLL;
+ }
+
+ public boolean isGemstone() {
+ return itemType == ItemType.RUBY_GEMSTONE || itemType == ItemType.AMETHYST_GEMSTONE ||
+ itemType == ItemType.SAPPHIRE_GEMSTONE || itemType == ItemType.JASPER_GEMSTONE ||
+ itemType == ItemType.JADE_GEMSTONE || itemType == ItemType.AMBER_GEMSTONE ||
+ itemType == ItemType.OPAL_GEMSTONE || itemType == ItemType.TOPAZ_GEMSTONE;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/ItemType.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/ItemType.java
new file mode 100644
index 00000000..3b47a86d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/hex/ItemType.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui.hex;
+
+enum ItemType {
+ HOT_POTATO,
+ FUMING_POTATO,
+ BOOK_OF_STATS,
+ ART_OF_WAR,
+ ART_OF_PEACE,
+ FARMING_DUMMY,
+ RECOMB,
+ SILEX,
+ RUBY_SCROLL,
+ SAPPHIRE_SCROLL,
+ JASPER_SCROLL,
+ AMETHYST_SCROLL,
+ AMBER_SCROLL,
+ OPAL_SCROLL,
+ FIRST_STAR(1),
+ SECOND_STAR(2),
+ THIRD_STAR(3),
+ FOURTH_STAR(4),
+ FIFTH_STAR(5),
+ FIRST_MASTER_STAR(6),
+ SECOND_MASTER_STAR(7),
+ THIRD_MASTER_STAR(8),
+ FOURTH_MASTER_STAR(9),
+ FIFTH_MASTER_STAR(10),
+ WOOD_SINGULARITY,
+ IMPLOSION_SCROLL,
+ SHADOW_WARP_SCROLL,
+ WITHER_SHIELD_SCROLL,
+ TUNER,
+ REFORGE,
+ RANDOM_REFORGE,
+ MANA_DISINTEGRATOR,
+ HEX_ITEM,
+ TOTAL_UPGRADES,
+ RUBY_GEMSTONE,
+ AMETHYST_GEMSTONE,
+ SAPPHIRE_GEMSTONE,
+ JASPER_GEMSTONE,
+ JADE_GEMSTONE,
+ AMBER_GEMSTONE,
+ OPAL_GEMSTONE,
+ TOPAZ_GEMSTONE,
+ CONVERT_TO_DUNGEON,
+ GEMSTONE_SLOT,
+ EXPERIENCE_BOTTLE,
+ GRAND_EXPERIENCE_BOTTLE,
+ TITANIC_EXPERIENCE_BOTTLE,
+ COLOSSAL_EXPERIENCE_BOTTLE,
+ UNKNOWN;
+
+ private int starLevel = -1;
+
+ ItemType() {}
+
+ ItemType(int starLevel) {
+ this.starLevel = starLevel;
+ }
+
+ public int getStarLevel() {
+ return starLevel;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuConfigTutorial.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuConfigTutorial.java
index 938f3f98..6a2602f8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuConfigTutorial.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuConfigTutorial.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui.tutorials;
public class NeuConfigTutorial extends TutorialBase {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuTutorial.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuTutorial.java
index 24c6bb7f..c0a5d8c8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuTutorial.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/NeuTutorial.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui.tutorials;
import net.minecraft.client.Minecraft;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/TutorialBase.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/TutorialBase.java
index 433bb996..27172ed8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/TutorialBase.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/tutorials/TutorialBase.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.miscgui.tutorials;
import com.google.gson.JsonArray;
@@ -43,7 +62,6 @@ public class TutorialBase extends GuiScreen {
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
- Keyboard.enableRepeatEvents(true);
super.keyTyped(typedChar, keyCode);
if (keyCode == Keyboard.KEY_LEFT) {
page--;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/ExperienceOrb.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/ExperienceOrb.java
new file mode 100644
index 00000000..9da4f553
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/ExperienceOrb.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui.util;
+
+import org.lwjgl.util.vector.Vector2f;
+
+public class ExperienceOrb {
+ public Vector2f position;
+ public Vector2f positionLast;
+ public Vector2f velocity;
+ public Vector2f target;
+
+ public int type;
+ public int rotationDeg;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/OrbDisplay.java b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/OrbDisplay.java
new file mode 100644
index 00000000..42e935f5
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/miscgui/util/OrbDisplay.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscgui.util;
+
+import io.github.moulberry.notenoughupdates.core.util.lerp.LerpUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.util.vector.Vector2f;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Random;
+
+public class OrbDisplay {
+ private static final ResourceLocation TEXTURE = new ResourceLocation("notenoughupdates:custom_enchant_gui.png");
+ private static final int DEFAULT_COUNT = 30;
+
+ private final List<ExperienceOrb> experienceOrbList = new ArrayList<>();
+
+ public ExperienceOrb spawnExperienceOrb(Random random, Vector2f start, Vector2f target, int baseType) {
+ ExperienceOrb orb = new ExperienceOrb();
+ orb.position = new Vector2f(start);
+ orb.positionLast = new Vector2f(orb.position);
+ orb.velocity = new Vector2f(
+ random.nextFloat() * 20 - 10,
+ random.nextFloat() * 20 - 10
+ );
+ orb.target = new Vector2f(target);
+ orb.type = baseType;
+ orb.rotationDeg = random.nextInt(4) * 90;
+
+ float v = random.nextFloat();
+ if (v > 0.6) {
+ orb.type += 1;
+ }
+ if (v > 0.9) {
+ orb.type += 1;
+ }
+
+ experienceOrbList.add(orb);
+
+ return orb;
+ }
+
+ public void spawnExperienceOrbs(int startX, int startY, int targetX, int targetY, int baseType) {
+ spawnExperienceOrbs(new Random(),new Vector2f(startX, startY), new Vector2f(targetX, targetY), baseType, DEFAULT_COUNT);
+ }
+
+ public void spawnExperienceOrbs(Random random, Vector2f start, Vector2f target, int baseType, int count) {
+ for (int i = 0; i < count; i++) {
+ spawnExperienceOrb(random, start, target, baseType);
+ }
+ }
+
+ public void physicsTickOrbs() {
+ for (ListIterator<ExperienceOrb> it = experienceOrbList.listIterator(); it.hasNext(); ) {
+ ExperienceOrb orb = it.next();
+
+ Vector2f delta = Vector2f.sub(orb.target, orb.position, null);
+ float length = delta.length();
+
+ // Remove close Orbs
+ if (length < 8 && orb.velocity.lengthSquared() < 20) {
+ it.remove();
+ continue;
+ }
+
+ // Update velocity
+ Vector2f.add(orb.velocity, (Vector2f) delta.scale(2 / length), orb.velocity);
+ orb.velocity.scale(0.9F);
+
+ // Update position
+ orb.positionLast.set(orb.position);
+ Vector2f.add(orb.position, orb.velocity, orb.position);
+ }
+ }
+
+ public void renderOrbs(float partialTicks) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TEXTURE);
+ GlStateManager.disableDepth();
+
+ for (ExperienceOrb orb : experienceOrbList) {
+ int orbX = Math.round(LerpUtils.lerp(orb.position.x, orb.positionLast.x, partialTicks));
+ int orbY = Math.round(LerpUtils.lerp(orb.position.y, orb.positionLast.y, partialTicks));
+
+ GlStateManager.pushMatrix();
+
+ GlStateManager.translate(orbX, orbY, 0);
+ GlStateManager.rotate(orb.rotationDeg, 0, 0, 1);
+
+ Vector2f delta = Vector2f.sub(orb.position, orb.target, null);
+
+ float length = delta.length();
+ float velocitySquared = orb.velocity.lengthSquared();
+ float opacity = (float) Math.sqrt(
+ Math.min(
+ 1,
+ Math.min(2, Math.max(0.5F, length / 16))
+ * Math.min(2, Math.max(0.5F, velocitySquared / 40))
+ ));
+ GlStateManager.color(1, 1, 1, opacity);
+
+ int orbU = (orb.type % 3) * 16;
+ int orbV = (orb.type / 3) * 16 + 217;
+
+ Utils.drawTexturedRect(
+ -8, -8, 16, 16,
+ orbU / 512f,
+ (orbU + 16) / 512f,
+ orbV / 512f,
+ (orbV + 16) / 512f,
+ GL11.GL_NEAREST
+ );
+
+ GlStateManager.popMatrix();
+ }
+
+ GlStateManager.enableDepth();
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java
new file mode 100644
index 00000000..d30cb9b3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityAgeable.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.EntityAgeable;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(EntityAgeable.class)
+public interface AccessorEntityAgeable {
+ @Accessor(value = "growingAge")
+ void setGrowingAgeDirect(int newValue);
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java
new file mode 100644
index 00000000..50bbe135
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorEntityArmorStand.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.item.EntityArmorStand;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(EntityArmorStand.class)
+public interface AccessorEntityArmorStand {
+ @Invoker(value = "setSmall")
+ void setSmallDirect(boolean isSmall);
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiContainer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiContainer.java
new file mode 100644
index 00000000..a12cd9c8
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiContainer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.client.gui.inventory.GuiContainer;
+import net.minecraft.inventory.Slot;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(GuiContainer.class)
+public interface AccessorGuiContainer {
+
+ @Invoker("getSlotAtPosition")
+ Slot doGetSlotAtPosition(int x, int y);
+
+ @Invoker("drawSlot")
+ void doDrawSlot(Slot slot);
+
+ @Invoker("isMouseOverSlot")
+ boolean doIsMouseOverSlot(Slot slot, int x, int y);
+
+ @Accessor("guiLeft")
+ int getGuiLeft();
+
+ @Accessor("guiTop")
+ int getGuiTop();
+
+ @Accessor("xSize")
+ int getXSize();
+
+ @Accessor("ySize")
+ int getYSize();
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiEditSign.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiEditSign.java
new file mode 100644
index 00000000..d1cd7069
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiEditSign.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.client.gui.inventory.GuiEditSign;
+import net.minecraft.tileentity.TileEntitySign;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(GuiEditSign.class)
+public interface AccessorGuiEditSign {
+ @Accessor("tileSign")
+ TileEntitySign getTileSign();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiPlayerTabOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiPlayerTabOverlay.java
new file mode 100644
index 00000000..0189e2fc
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorGuiPlayerTabOverlay.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.client.gui.GuiPlayerTabOverlay;
+import net.minecraft.util.IChatComponent;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+@Mixin(GuiPlayerTabOverlay.class)
+public interface AccessorGuiPlayerTabOverlay {
+ @Accessor("footer")
+ IChatComponent getFooter();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java
new file mode 100644
index 00000000..6d8c941c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/AccessorMinecraft.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.resources.IResourcePack;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.gen.Accessor;
+
+import java.util.List;
+
+@Mixin(Minecraft.class)
+public interface AccessorMinecraft {
+ @Accessor(value = "defaultResourcePacks")
+ List<IResourcePack> onGetDefaultResourcePacks();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinAbstractClientPlayer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinAbstractClientPlayer.java
index 5c81c758..685528e0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinAbstractClientPlayer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinAbstractClientPlayer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.NPCRetexturing;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinContainer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinContainer.java
index 80d79712..53643fb0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinContainer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinContainer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEffectRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEffectRenderer.java
index 8d0b291a..451fff3a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEffectRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEffectRenderer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntity.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntity.java
index 86995647..39951ba4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntity.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntity.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import net.minecraft.entity.Entity;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java
index b8f07b53..d9b60a13 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityAgeable.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import net.minecraft.entity.EntityAgeable;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java
new file mode 100644
index 00000000..50eb15ba
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityHorse.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.passive.EntityHorse;
+import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(EntityHorse.class)
+public class MixinEntityHorse {
+ @Redirect(method = "updateHorseSlots", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;isRemote:Z"))
+ public boolean onUpdateHorseSlots(World instance) {
+ if (instance == null)
+ return true;
+ return instance.isRemote;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java
index e15d18eb..573b2ad5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
@@ -8,7 +27,7 @@ import net.minecraft.scoreboard.ScorePlayerTeam;
import net.minecraft.scoreboard.Scoreboard;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
-import org.spongepowered.asm.lib.Opcodes;
+import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayerSP.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayerSP.java
index 573eac22..765ed372 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayerSP.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityPlayerSP.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java
index 26923726..12ff1cb4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntityRenderer.java
@@ -1,39 +1,53 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects;
-import io.github.moulberry.notenoughupdates.miscfeatures.FancyPortals;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.entity.Entity;
-import net.minecraft.util.MathHelper;
import net.minecraftforge.client.ForgeHooksClient;
-import org.lwjgl.util.glu.Project;
import org.lwjgl.util.vector.Vector3f;
-import org.spongepowered.asm.lib.Opcodes;
+import org.objectweb.asm.Opcodes;
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.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(EntityRenderer.class)
public abstract class MixinEntityRenderer {
@Shadow
- protected abstract float getFOVModifier(float partialTicks, boolean useFOVSetting);
-
- @Shadow
private Minecraft mc;
-
@Shadow
private float farPlaneDistance;
@Shadow
+ protected abstract float getFOVModifier(float partialTicks, boolean useFOVSetting);
+
+ @Shadow
protected abstract void orientCamera(float partialTicks);
@Inject(method = "getFOVModifier", at = @At("RETURN"), cancellable = true)
@@ -52,38 +66,6 @@ public abstract class MixinEntityRenderer {
@Redirect(method = "renderWorldPass", at = @At(
value = "INVOKE",
- target = "Lorg/lwjgl/util/glu/Project;gluPerspective(FFFF)V",
- remap = false)
- )
- public void perspective(float f1, float f2, float f3, float f4) {
- if (!FancyPortals.overridePerspective()) {
- Project.gluPerspective(f1, f2, f3, f4);
- }
- }
-
- @Inject(method = "updateCameraAndRender", at = @At("RETURN"))
- public void onUpdateCameraAndRender(float partialTicks, long nanoTime, CallbackInfo ci) {
- if (Minecraft.getMinecraft().getRenderViewEntity() == null) return;
-
- if (FancyPortals.shouldRenderWorldOverlay()) {
- GlStateManager.matrixMode(5889);
- GlStateManager.loadIdentity();
- Project.gluPerspective(getFOVModifier(partialTicks, true),
- (float) mc.displayWidth / (float) this.mc.displayHeight, 0.05F,
- farPlaneDistance * MathHelper.SQRT_2
- );
- GlStateManager.matrixMode(5888);
- GlStateManager.loadIdentity();
- orientCamera(partialTicks);
-
- FancyPortals.onUpdateCameraAndRender(partialTicks, nanoTime);
-
- Minecraft.getMinecraft().entityRenderer.setupOverlayRendering();
- }
- }
-
- @Redirect(method = "renderWorldPass", at = @At(
- value = "INVOKE",
target = "Lnet/minecraftforge/client/ForgeHooksClient;dispatchRenderLast(Lnet/minecraft/client/renderer/RenderGlobal;F)V",
remap = false)
)
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java
new file mode 100644
index 00000000..49c7ccb2
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinEntitySkeleton.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import net.minecraft.entity.monster.EntitySkeleton;
+import net.minecraft.world.World;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(EntitySkeleton.class)
+public class MixinEntitySkeleton {
+ @Redirect(method = "setCurrentItemOrArmor", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;isRemote:Z"))
+ public boolean onSetCurrentItemOrArmor(World instance) {
+ if (instance == null)
+ return true;
+ return instance.isRemote;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java
index c0d5627d..94b1c704 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiChest.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
@@ -41,7 +60,7 @@ public class MixinGuiChest {
private static final String TARGET_SBADRAWSTRING = "Lcodes/biscuit/skyblockaddons/asm/hooks/GuiChestHook;" +
"drawString(Lnet/minecraft/client/gui/FontRenderer;Ljava/lang/String;III)I";
- @Redirect(method = "drawGuiContainerForegroundLayer", at = @At(value = "INVOKE", target = TARGET_SBADRAWSTRING, remap = false))
+ @Redirect(method = "drawGuiContainerForegroundLayer", at = @At(value = "INVOKE", target = TARGET_SBADRAWSTRING, remap = false), expect = 0)
public int drawGuiContainerForegroundLayer_SBA_drawString(
FontRenderer fontRenderer,
String text,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
index 4d1545b6..81918939 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiContainer.java
@@ -1,11 +1,37 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.NEUOverlay;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.miscfeatures.*;
+import io.github.moulberry.notenoughupdates.events.SlotClickEvent;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
+import io.github.moulberry.notenoughupdates.miscfeatures.AbiphoneWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.AuctionBINWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.AuctionSortModeWarning;
+import io.github.moulberry.notenoughupdates.miscfeatures.BetterContainers;
+import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
+import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
import io.github.moulberry.notenoughupdates.miscgui.GuiCustomEnchant;
import io.github.moulberry.notenoughupdates.miscgui.StorageOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.hex.GuiCustomHex;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -33,7 +59,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
@Mixin(GuiContainer.class)
public abstract class MixinGuiContainer extends GuiScreen {
@@ -70,8 +95,9 @@ public abstract class MixinGuiContainer extends GuiScreen {
NBTTagCompound tag = eventGui.inventorySlots.inventorySlots.get(22).getStack().getTagCompound();
if (tag.hasKey("SkullOwner") && tag.getCompoundTag("SkullOwner").hasKey("Name")) {
String tagName = tag.getCompoundTag("SkullOwner").getString("Name");
- String displayname = Utils.cleanColour(cc.inventorySlots.get(22).getStack().getDisplayName());
- if (tagName.equals(displayname.substring(displayname.length() - tagName.length()))) {
+ String displayName = Utils.cleanColour(cc.inventorySlots.get(22).getStack().getDisplayName());
+ if (displayName.length() - tagName.length() >= 0 && tagName.equals(displayName.substring(
+ displayName.length() - tagName.length()))) {
ci.cancel();
this.zLevel = 100.0F;
@@ -100,7 +126,8 @@ public abstract class MixinGuiContainer extends GuiScreen {
else if (!($this instanceof GuiChest))
BetterContainers.profileViewerStackIndex = -1;
- if (slot.getStack() == null && NotEnoughUpdates.INSTANCE.overlay.searchMode && NEUEventListener.drawingGuiScreen) {
+ if (slot.getStack() == null && NotEnoughUpdates.INSTANCE.overlay.searchMode && RenderListener.drawingGuiScreen &&
+ NotEnoughUpdates.INSTANCE.isOnSkyblock()) {
GlStateManager.pushMatrix();
GlStateManager.translate(0, 0, 100 + Minecraft.getMinecraft().getRenderItem().zLevel);
GlStateManager.depthMask(false);
@@ -164,7 +191,9 @@ public abstract class MixinGuiContainer extends GuiScreen {
public void isMouseOverSlot(Slot slotIn, int mouseX, int mouseY, CallbackInfoReturnable<Boolean> cir) {
StorageOverlay.getInstance().overrideIsMouseOverSlot(slotIn, mouseX, mouseY, cir);
GuiCustomEnchant.getInstance().overrideIsMouseOverSlot(slotIn, mouseX, mouseY, cir);
+ GuiCustomHex.getInstance().overrideIsMouseOverSlot(slotIn, mouseX, mouseY, cir);
AuctionBINWarning.getInstance().overrideIsMouseOverSlot(slotIn, mouseX, mouseY, cir);
+ AbiphoneWarning.getInstance().overrideIsMouseOverSlot(slotIn, mouseX, mouseY, cir);
}
@Redirect(method = "drawScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/inventory/GuiContainer;drawGradientRect(IIIIII)V"))
@@ -274,60 +303,20 @@ public abstract class MixinGuiContainer extends GuiScreen {
@Inject(method = "handleMouseClick", at = @At(value = "HEAD"), cancellable = true)
public void handleMouseClick(Slot slotIn, int slotId, int clickedButton, int clickType, CallbackInfo ci) {
+ if (slotIn == null) return;
GuiContainer $this = (GuiContainer) (Object) this;
-
- if (AuctionBINWarning.getInstance().onMouseClick(slotIn, slotId, clickedButton, clickType)) {
+ SlotClickEvent event = new SlotClickEvent($this, slotIn, slotId, clickedButton, clickType);
+ event.post();
+ if (event.isCanceled()) {
ci.cancel();
return;
}
-
- AtomicBoolean ret = new AtomicBoolean(false);
- SlotLocking.getInstance().onWindowClick(slotIn, slotId, clickedButton, clickType, (tuple) -> {
+ if (event.usePickblockInstead) {
+ $this.mc.playerController.windowClick(
+ $this.inventorySlots.windowId,
+ slotId, 2, 3, $this.mc.thePlayer
+ );
ci.cancel();
-
- if (tuple == null) {
- ret.set(true);
- } else {
- int newSlotId = tuple.getLeft();
- int newClickedButton = tuple.getMiddle();
- int newClickedType = tuple.getRight();
-
- ret.set(true);
- $this.mc.playerController.windowClick(
- $this.inventorySlots.windowId,
- newSlotId,
- newClickedButton,
- newClickedType,
- $this.mc.thePlayer
- );
- }
- });
- if (ret.get()) return;
-
- if (slotIn != null && slotIn.getStack() != null) {
- if (EnchantingSolvers.onStackClick(slotIn.getStack(), $this.inventorySlots.windowId,
- slotId, clickedButton, clickType
- )) {
- ci.cancel();
- } else {
- PetInfoOverlay.onStackClick(slotIn.getStack(), $this.inventorySlots.windowId,
- slotId, clickedButton, clickType
- );
- }
- }
- if (slotIn != null && BetterContainers.isOverriding() && (BetterContainers.isBlankStack(
- slotIn.slotNumber,
- slotIn.getStack()
- ) ||
- BetterContainers.isButtonStack(slotIn.slotNumber, slotIn.getStack()))) {
- BetterContainers.clickSlot(slotIn.getSlotIndex());
-
- if (BetterContainers.isBlankStack(slotIn.slotNumber, slotIn.getStack())) {
- $this.mc.playerController.windowClick($this.inventorySlots.windowId, slotId, 2, clickType, $this.mc.thePlayer);
- ci.cancel();
- } else {
- Utils.playPressSound();
- }
}
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiEditSign.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiEditSign.java
new file mode 100644
index 00000000..bfdf05ab
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiEditSign.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.mixins;
+
+import io.github.moulberry.notenoughupdates.events.SignSubmitEvent;
+import net.minecraft.client.gui.inventory.GuiEditSign;
+import net.minecraft.tileentity.TileEntitySign;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.IChatComponent;
+import org.objectweb.asm.Opcodes;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Redirect;
+
+@Mixin(GuiEditSign.class)
+public class MixinGuiEditSign {
+
+ @Redirect(method = "onGuiClosed", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/tileentity/TileEntitySign;signText:[Lnet/minecraft/util/IChatComponent;"))
+ public IChatComponent[] onOnGuiClosed(TileEntitySign instance) {
+ String[] x = new String[4];
+ for (int i = 0; i < 4; i++) {
+ x[i] = instance.signText[i].getUnformattedText();
+ }
+ SignSubmitEvent signSubmitEvent = new SignSubmitEvent((GuiEditSign) (Object) this, x);
+ signSubmitEvent.post();
+ IChatComponent[] arr = new IChatComponent[4];
+ for (int i = 0; i < 4; i++) {
+ arr[i] = new ChatComponentText(signSubmitEvent.lines[i]);
+ }
+ return arr;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java
index 7f7f25c8..381f5934 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiIngame.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -24,7 +43,7 @@ public class MixinGuiIngame {
@Redirect(method = "renderScoreboard", at = @At(value = "INVOKE", target = TARGET))
public String renderScoreboard_formatPlayerName(Team team, String name) {
- if (NotEnoughUpdates.INSTANCE.isOnSkyblock() && NotEnoughUpdates.INSTANCE.config.misc.streamerMode) {
+ if (NotEnoughUpdates.INSTANCE.config.misc.streamerMode) {
return StreamerMode.filterScoreboard(ScorePlayerTeam.formatPlayerName(team, name));
}
return ScorePlayerTeam.formatPlayerName(team, name);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiInventory.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiInventory.java
index 25b036ab..86ed9b8f 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiInventory.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiInventory.java
@@ -1,7 +1,28 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.GuiInventoryBackgroundDrawnEvent;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
+import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.gui.inventory.GuiInventory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -13,8 +34,13 @@ public class MixinGuiInventory {
@Inject(method = "drawGuiContainerForegroundLayer", at = @At("HEAD"), cancellable = true)
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY, CallbackInfo ci) {
if (NotEnoughUpdates.INSTANCE.config.inventoryButtons.hideCrafting ||
- NEUEventListener.disableCraftingText) {
+ RenderListener.disableCraftingText) {
ci.cancel();
}
}
+
+ @Inject(method = "drawGuiContainerBackgroundLayer", at = @At("TAIL"))
+ public void onDrawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY, CallbackInfo ci) {
+ new GuiInventoryBackgroundDrawnEvent((GuiContainer) (Object) this, partialTicks).post();
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiScreen.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiScreen.java
index eac2b2d5..b978b433 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiScreen.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinGuiScreen.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.util.SBInfo;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java
index fb5707fe..dbcb260d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryEffectRenderer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryPlayer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryPlayer.java
index 345b5171..de117002 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryPlayer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinInventoryPlayer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemCameraTransforms.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemCameraTransforms.java
index da2b2e08..bbe0f842 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemCameraTransforms.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemCameraTransforms.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.CustomSkulls;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemRenderer.java
index d691b79f..c2739ad8 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemRenderer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscgui.InventoryStorageSelector;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java
index 25109704..83379a18 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinItemStack.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerArmorBase.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerArmorBase.java
index a085c5d1..773e7ebe 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerArmorBase.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerArmorBase.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.core.ChromaColour;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerCustomHead.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerCustomHead.java
index a2785ec7..90101696 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerCustomHead.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLayerCustomHead.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import com.mojang.authlib.GameProfile;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLoadingScreenRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLoadingScreenRenderer.java
deleted file mode 100644
index dbdad65a..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinLoadingScreenRenderer.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.github.moulberry.notenoughupdates.mixins;
-
-import io.github.moulberry.notenoughupdates.miscfeatures.FancyPortals;
-import net.minecraft.client.LoadingScreenRenderer;
-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;
-
-@Mixin(LoadingScreenRenderer.class)
-public class MixinLoadingScreenRenderer {
- @Inject(method = "setLoadingProgress", at = @At(value = "HEAD"), cancellable = true)
- public void setLoadingProgress(int progress, CallbackInfo ci) {
- if (progress < 0 && !FancyPortals.shouldRenderLoadingScreen()) {
- ci.cancel();
- }
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMinecraft.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMinecraft.java
index b01e9609..abc9d8c6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMinecraft.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMinecraft.java
@@ -1,8 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
import net.minecraft.client.Minecraft;
-import org.spongepowered.asm.lib.Opcodes;
+import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMouseHelper.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMouseHelper.java
index 4d8df949..a89893b9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMouseHelper.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinMouseHelper.java
@@ -1,6 +1,25 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
import net.minecraft.util.MouseHelper;
import org.lwjgl.input.Mouse;
import org.spongepowered.asm.mixin.Mixin;
@@ -12,7 +31,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinMouseHelper {
@Inject(method = {"ungrabMouseCursor"}, at = {@At("HEAD")}, cancellable = true)
public void ungrabMouseCursor(final CallbackInfo ci) {
- if (System.currentTimeMillis() - NEUEventListener.lastGuiClosed < 150L) {
+ if (System.currentTimeMillis() - RenderListener.lastGuiClosed < 150L) {
ci.cancel();
Mouse.setGrabbed(false);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java
index d47dce2c..0b33609d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinNetHandlerPlayClient.java
@@ -1,13 +1,45 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
-import io.github.moulberry.notenoughupdates.miscfeatures.*;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver;
+import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects;
+import io.github.moulberry.notenoughupdates.miscfeatures.EnchantingSolvers;
+import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper;
+import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns;
+import io.github.moulberry.notenoughupdates.miscfeatures.MiningStuff;
+import io.github.moulberry.notenoughupdates.miscfeatures.NewApiKeyHelper;
+import io.github.moulberry.notenoughupdates.miscfeatures.StorageManager;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.Packet;
+import net.minecraft.network.play.client.C01PacketChatMessage;
import net.minecraft.network.play.client.C0EPacketClickWindow;
-import net.minecraft.network.play.server.*;
+import net.minecraft.network.play.server.S23PacketBlockChange;
+import net.minecraft.network.play.server.S2DPacketOpenWindow;
+import net.minecraft.network.play.server.S2EPacketCloseWindow;
+import net.minecraft.network.play.server.S2FPacketSetSlot;
+import net.minecraft.network.play.server.S30PacketWindowItems;
+import net.minecraft.network.play.server.S47PacketPlayerListHeaderFooter;
import net.minecraft.util.EnumParticleTypes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -47,6 +79,12 @@ public class MixinNetHandlerPlayClient {
double xCoord, double yCoord, double zCoord,
double xOffset, double yOffset, double zOffset, int[] params
) {
+ CrystalWishingCompassSolver.getInstance().onSpawnParticle(
+ particleTypes,
+ xCoord,
+ yCoord,
+ zCoord
+ );
boolean override = FishingHelper.getInstance().onSpawnParticle(
particleTypes,
xCoord,
@@ -61,11 +99,6 @@ public class MixinNetHandlerPlayClient {
}
}
- @Inject(method = "handleSpawnMob", at = @At("RETURN"))
- public void handleSpawnMob(S0FPacketSpawnMob packetIn, CallbackInfo ci) {
- //CollectionLogManager.getInstance().onEntityMetadataUpdated(packetIn.getEntityID());
- }
-
@Inject(method = "handleSetSlot", at = @At("RETURN"))
public void handleSetSlot(S2FPacketSetSlot packetIn, CallbackInfo ci) {
EnchantingSolvers.processInventoryContents(false);
@@ -87,25 +120,20 @@ public class MixinNetHandlerPlayClient {
StorageManager.getInstance().setItemsPacket(packetIn);
}
- @Inject(method = "handleRespawn", at = @At(
- value = "INVOKE",
- target = "Lnet/minecraft/network/PacketThreadUtil;checkThreadAndEnqueue(Lnet/minecraft/network/Packet;Lnet/minecraft/network/INetHandler;Lnet/minecraft/util/IThreadListener;)V",
- shift = At.Shift.AFTER))
- public void handleOpenWindow(S07PacketRespawn packetIn, CallbackInfo ci) {
- FancyPortals.onRespawnPacket(packetIn);
- }
-
@Inject(method = "handleBlockChange", at = @At("HEAD"))
public void handleBlockChange(S23PacketBlockChange packetIn, CallbackInfo ci) {
MiningStuff.processBlockChangePacket(packetIn);
ItemCooldowns.processBlockChangePacket(packetIn);
}
- @Inject(method = "addToSendQueue", at = @At("HEAD"))
+ @Inject(method = "addToSendQueue", at = @At("HEAD"), cancellable = true)
public void addToSendQueue(Packet packet, CallbackInfo ci) {
if (packet instanceof C0EPacketClickWindow) {
StorageManager.getInstance().clientSendWindowClick((C0EPacketClickWindow) packet);
}
+ if (packet instanceof C01PacketChatMessage) {
+ NewApiKeyHelper.getInstance().hookPacketChatMessage((C01PacketChatMessage) packet);
+ }
}
@Inject(method = "handlePlayerListHeaderFooter", at = @At("HEAD"))
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinPlayerControllerMP.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinPlayerControllerMP.java
index b4481a73..fc8fee02 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinPlayerControllerMP.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinPlayerControllerMP.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.events.OnBlockBreakSoundEffect;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java
index 14aad887..db35fcb9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRender.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java
index 9e989311..ca40c5e7 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderFish.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -178,4 +197,4 @@ public abstract class MixinRenderFish extends Render<EntityFishHook> {
private static double mathLerp(double var1, double var2, double var3) {
return var2 + var1 * (var3 - var2);
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java
index fc3347bf..30c6b36e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderGlobal.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.cosmetics.CapeManager;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
index 630874ab..7c2cfcbf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderItem.java
@@ -1,11 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
-import io.github.moulberry.notenoughupdates.NEUEventListener;
import io.github.moulberry.notenoughupdates.NEUOverlay;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.ChromaColour;
+import io.github.moulberry.notenoughupdates.listener.RenderListener;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCooldowns;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
@@ -176,7 +196,7 @@ public abstract class MixinRenderItem {
@Inject(method = "renderItemIntoGUI", at = @At("HEAD"))
public void renderItemHead(ItemStack stack, int x, int y, CallbackInfo ci) {
- if (NotEnoughUpdates.INSTANCE.overlay.searchMode && NEUEventListener.drawingGuiScreen) {
+ if (NotEnoughUpdates.INSTANCE.overlay.searchMode && RenderListener.drawingGuiScreen && NotEnoughUpdates.INSTANCE.isOnSkyblock() && !(Minecraft.getMinecraft().currentScreen instanceof GuiProfileViewer)) {
boolean matches = false;
GuiTextField textField = NotEnoughUpdates.INSTANCE.overlay.getTextField();
@@ -202,7 +222,7 @@ public abstract class MixinRenderItem {
@Inject(method = "renderItemIntoGUI", at = @At("RETURN"))
public void renderItemReturn(ItemStack stack, int x, int y, CallbackInfo ci) {
if (stack != null && stack.stackSize != 1) return;
- if (NotEnoughUpdates.INSTANCE.overlay.searchMode && NEUEventListener.drawingGuiScreen) {
+ if (NotEnoughUpdates.INSTANCE.overlay.searchMode && RenderListener.drawingGuiScreen && NotEnoughUpdates.INSTANCE.isOnSkyblock() && !(Minecraft.getMinecraft().currentScreen instanceof GuiProfileViewer)) {
boolean matches = false;
GuiTextField textField = NotEnoughUpdates.INSTANCE.overlay.getTextField();
@@ -233,7 +253,7 @@ public abstract class MixinRenderItem {
CallbackInfo ci
) {
if (stack != null && stack.stackSize != 1) {
- if (NotEnoughUpdates.INSTANCE.overlay.searchMode && NEUEventListener.drawingGuiScreen) {
+ if (NotEnoughUpdates.INSTANCE.overlay.searchMode && RenderListener.drawingGuiScreen && NotEnoughUpdates.INSTANCE.isOnSkyblock() && !(Minecraft.getMinecraft().currentScreen instanceof GuiProfileViewer)) {
boolean matches = false;
GuiTextField textField = NotEnoughUpdates.INSTANCE.overlay.getTextField();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java
index 8c1cc247..e7782bcd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRenderList.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRendererLivingEntity.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRendererLivingEntity.java
index 16c6c99c..5503c8cf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRendererLivingEntity.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinRendererLivingEntity.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTextureManager.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTextureManager.java
index de6d1537..d8a48ecd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTextureManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTextureManager.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.ItemCustomizeManager;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySkullRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySkullRenderer.java
index 71750fec..0b70f790 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySkullRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySkullRenderer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import com.mojang.authlib.GameProfile;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java
index f93608b1..2f342614 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinTileEntitySpecialRenderer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java
index 73cb19d3..22448944 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinVboRenderList.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.dungeons.DungeonBlocks;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorld.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorld.java
index 86073984..b738359a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorld.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorld.java
@@ -1,8 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes;
import io.github.moulberry.notenoughupdates.miscfeatures.CustomItemEffects;
+import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.CustomBiomes;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.biome.BiomeGenBase;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorldClient.java b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorldClient.java
index b20ff8fd..84e6da86 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorldClient.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/mixins/MixinWorldClient.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.mixins;
import io.github.moulberry.notenoughupdates.miscfeatures.FishingHelper;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
index 470b0381..4d04bfbc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfig.java
@@ -1,6 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options;
import com.google.common.collect.Lists;
+import com.google.gson.JsonObject;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
@@ -8,20 +28,52 @@ import io.github.moulberry.notenoughupdates.core.config.Config;
import io.github.moulberry.notenoughupdates.core.config.Position;
import io.github.moulberry.notenoughupdates.core.config.annotations.Category;
import io.github.moulberry.notenoughupdates.core.config.gui.GuiPositionEditor;
+import io.github.moulberry.notenoughupdates.miscfeatures.FairySouls;
import io.github.moulberry.notenoughupdates.miscgui.GuiEnchantColour;
import io.github.moulberry.notenoughupdates.miscgui.GuiInvButtonEditor;
import io.github.moulberry.notenoughupdates.miscgui.NEUOverlayPlacements;
-import io.github.moulberry.notenoughupdates.options.seperateSections.*;
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag;
+import io.github.moulberry.notenoughupdates.options.seperateSections.AHGraph;
+import io.github.moulberry.notenoughupdates.options.seperateSections.AHTweaks;
+import io.github.moulberry.notenoughupdates.options.seperateSections.AccessoryBag;
+import io.github.moulberry.notenoughupdates.options.seperateSections.ApiData;
+import io.github.moulberry.notenoughupdates.options.seperateSections.BazaarTweaks;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Calendar;
import io.github.moulberry.notenoughupdates.options.seperateSections.CustomArmour;
+import io.github.moulberry.notenoughupdates.options.seperateSections.DungeonMapConfig;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Dungeons;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Enchanting;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Fishing;
+import io.github.moulberry.notenoughupdates.options.seperateSections.ImprovedSBMenu;
+import io.github.moulberry.notenoughupdates.options.seperateSections.InventoryButtons;
+import io.github.moulberry.notenoughupdates.options.seperateSections.ItemOverlays;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Itemlist;
+import io.github.moulberry.notenoughupdates.options.seperateSections.LocationEdit;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Mining;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Misc;
+import io.github.moulberry.notenoughupdates.options.seperateSections.MiscOverlays;
+import io.github.moulberry.notenoughupdates.options.seperateSections.NeuAuctionHouse;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Notifications;
+import io.github.moulberry.notenoughupdates.options.seperateSections.PetOverlay;
+import io.github.moulberry.notenoughupdates.options.seperateSections.ProfileViewer;
+import io.github.moulberry.notenoughupdates.options.seperateSections.SkillOverlays;
+import io.github.moulberry.notenoughupdates.options.seperateSections.SlayerOverlay;
+import io.github.moulberry.notenoughupdates.options.seperateSections.SlotLocking;
+import io.github.moulberry.notenoughupdates.options.seperateSections.StorageGUI;
+import io.github.moulberry.notenoughupdates.options.seperateSections.Toolbar;
+import io.github.moulberry.notenoughupdates.options.seperateSections.TooltipTweaks;
+import io.github.moulberry.notenoughupdates.options.seperateSections.TradeMenu;
import io.github.moulberry.notenoughupdates.overlays.MiningOverlay;
import io.github.moulberry.notenoughupdates.overlays.OverlayManager;
import io.github.moulberry.notenoughupdates.overlays.TextOverlay;
+import io.github.moulberry.notenoughupdates.util.NotificationHandler;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import net.minecraft.client.Minecraft;
import net.minecraftforge.client.ClientCommandHandler;
import org.lwjgl.util.vector.Vector2f;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -49,6 +101,8 @@ public class NEUConfig extends Config {
}
switch (runnableId) {
+ case -1:
+ return;
case 0:
ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/neumap");
return;
@@ -100,6 +154,10 @@ public class NEUConfig extends Config {
case 14:
editOverlay(activeConfigCategory, OverlayManager.fishingSkillOverlay, skillOverlays.fishingPosition);
return;
+ case 15:
+ String command = NotEnoughUpdates.INSTANCE.config.misc.fariySoul ? "/neusouls on" : "/neusouls off";
+ ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, command);
+ return;
case 16:
ClientCommandHandler.instance.executeCommand(Minecraft.getMinecraft().thePlayer, "/neusouls clear");
return;
@@ -111,7 +169,36 @@ public class NEUConfig extends Config {
return;
case 19:
editOverlay(activeConfigCategory, OverlayManager.combatSkillOverlay, skillOverlays.combatPosition);
-
+ return;
+ case 20:
+ FairySouls.getInstance().setTrackFairySouls(NotEnoughUpdates.INSTANCE.config.misc.trackFairySouls);
+ return;
+ case 21:
+ NotEnoughUpdates.INSTANCE.overlay.updateSearch();
+ return;
+ case 22:
+ NotEnoughUpdates.INSTANCE.manager
+ .userFacingRepositoryReload()
+ .thenAccept(strings ->
+ NotificationHandler.displayNotification(strings, true, true));
+ Minecraft.getMinecraft().displayGuiScreen(null);
+ return;
+ case 23:
+ NotEnoughUpdates.INSTANCE.config.apiData.repoUser = "NotEnoughUpdates";
+ NotEnoughUpdates.INSTANCE.config.apiData.repoName = "NotEnoughUpdates-REPO";
+ NotEnoughUpdates.INSTANCE.config.apiData.repoBranch = "master";
+ NotEnoughUpdates.INSTANCE.openGui =
+ new GuiScreenElementWrapper(new NEUConfigEditor(NotEnoughUpdates.INSTANCE.config, "apis"));
+ return;
+ case 24:
+ NotEnoughUpdates.INSTANCE.config.apiData.repoUser = "NotEnoughUpdates";
+ NotEnoughUpdates.INSTANCE.config.apiData.repoName = "NotEnoughUpdates-REPO";
+ NotEnoughUpdates.INSTANCE.config.apiData.repoBranch = "dangerous";
+ NotEnoughUpdates.INSTANCE.openGui =
+ new GuiScreenElementWrapper(new NEUConfigEditor(NotEnoughUpdates.INSTANCE.config, "apis"));
+ return;
+ default:
+ System.err.printf("Unknown runnableId = %d in category %s%n", runnableId, activeConfigCategory);
}
}
@@ -250,8 +337,8 @@ public class NEUConfig extends Config {
@Expose
@Category(
- name = "Custom Armour Hud",
- desc = "Custom Armour Hud"
+ name = "Equipment Hud",
+ desc = "Equipment Hud"
)
public CustomArmour customArmour = new CustomArmour();
@@ -285,6 +372,13 @@ public class NEUConfig extends Config {
@Expose
@Category(
+ name = "Bazaar Tweaks",
+ desc = "Tweaks for the Bazaar"
+ )
+ public BazaarTweaks bazaarTweaks = new BazaarTweaks();
+
+ @Expose
+ @Category(
name = "AH/BZ Graph",
desc = "Graph of auction and bazaar prices"
)
@@ -299,10 +393,26 @@ public class NEUConfig extends Config {
@Expose
@Category(
- name = "Api Key",
- desc = "Api Key"
+ name = "Profile Viewer",
+ desc = "Profile Viewer"
)
- public ApiKey apiKey = new ApiKey();
+ public ProfileViewer profileViewer = new ProfileViewer();
+
+ @Expose
+ @Category(
+ name = "Apis",
+ desc = "Api Data"
+ )
+ public ApiData apiData = new ApiData();
+
+ @Expose
+ public LegacyApiKey apiKey = null;
+
+ public static class LegacyApiKey {
+ // Blame Ironmoon for this (still better than my idea tho)
+ @Expose
+ public String apiKey = null;
+ }
@Expose
public Hidden hidden = new Hidden();
@@ -319,12 +429,10 @@ public class NEUConfig extends Config {
public List<NEUConfig.InventoryButton> inventoryButtons = createDefaultInventoryButtons();
@Expose
- public boolean enableItemEditing = false;
+ public EnumSet<NEUDebugFlag> debugFlags = EnumSet.noneOf(NEUDebugFlag.class);
@Expose
public boolean cacheRenderedItempane = true;
@Expose
- public boolean autoupdate = true;
- @Expose
public String overlaySearchBar = "";
@Expose
public String overlayQuickCommand = "";
@@ -345,15 +453,13 @@ public class NEUConfig extends Config {
@Expose
public ArrayList<String> previousAuctionSearches = new ArrayList<>();
@Expose
+ public ArrayList<String> previousBazaarSearches = new ArrayList<>();
+ @Expose
public ArrayList<String> eventFavourites = new ArrayList<>();
@Expose
public ArrayList<String> quickCommands = createDefaultQuickCommands();
@Expose
public ArrayList<String> enchantColours = createDefaultEnchantColours();
- @Expose
- public String repoURL = "https://github.com/Moulberry/NotEnoughUpdates-REPO/archive/master.zip";
- @Expose
- public String repoCommitsURL = "https://api.github.com/repos/Moulberry/NotEnoughUpdates-REPO/commits/master";
@Expose
public boolean firstTimeSearchFocus = true;
@@ -366,6 +472,9 @@ public class NEUConfig extends Config {
@Expose
public boolean npcRetextureOnSelf = false;
+ @Expose
+ public boolean hasOpenedWaypointMenu = false;
+
}
public static ArrayList<String> createDefaultEnchantColours() {
@@ -459,6 +568,14 @@ public class NEUConfig extends Config {
public long dailyGemstonePowderCompleted = 0L;
@Expose
public long dailyMithrilPowerCompleted = 0L;
+ @Expose
+ public HashMap<String, Boolean> unlockedWarpScrolls = new HashMap<>();
+ @Expose
+ public long dailyHeavyPearlCompleted = 0L;
+ @Expose
+ public HashMap<Integer, JsonObject> savedEquipment = new HashMap<>();
+ @Expose
+ public int magicalPower = 0;
}
public HiddenLocationSpecific getLocationSpecific() {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfigEditor.java b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfigEditor.java
index 6681a994..17bc57e9 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfigEditor.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/NEUConfigEditor.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options;
import com.google.common.collect.Lists;
@@ -27,14 +46,22 @@ import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.net.URI;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
-import java.util.*;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
-import static io.github.moulberry.notenoughupdates.util.GuiTextures.*;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.DISCORD;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.GITHUB;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.PATREON;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.TWITCH;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.TWITTER;
+import static io.github.moulberry.notenoughupdates.util.GuiTextures.YOUTUBE;
public class NEUConfigEditor extends GuiElement {
- public static NEUConfigEditor editor = new NEUConfigEditor(NotEnoughUpdates.INSTANCE.config);
-
private static final ResourceLocation[] socialsIco = new ResourceLocation[]{
DISCORD,
GITHUB,
@@ -51,27 +78,25 @@ public class NEUConfigEditor extends GuiElement {
"https://patreon.com/moulberry",
"https://www.twitch.tv/moulberry2"
};
-
private static final ResourceLocation SEARCH_ICON = new ResourceLocation("notenoughupdates:core/search.png");
-
+ public static NEUConfigEditor editor = new NEUConfigEditor(NotEnoughUpdates.INSTANCE.config);
private final long openedMillis;
-
- private String selectedCategory = null;
-
private final LerpingInteger optionsScroll = new LerpingInteger(0, 150);
private final LerpingInteger categoryScroll = new LerpingInteger(0, 150);
-
private final LinkedHashMap<String, ConfigProcessor.ProcessedCategory> processedConfig;
private final TreeMap<String, Set<ConfigProcessor.ProcessedOption>> searchOptionMap = new TreeMap<>();
private final HashMap<ConfigProcessor.ProcessedOption, ConfigProcessor.ProcessedCategory> categoryForOption =
new HashMap<>();
-
+ private final LerpingInteger minimumSearchSize = new LerpingInteger(0, 150);
+ private final GuiElementTextField searchField = new GuiElementTextField("", 0, 20, 0);
+ private String selectedCategory = null;
private Set<ConfigProcessor.ProcessedCategory> searchedCategories = null;
private Map<ConfigProcessor.ProcessedCategory, Set<Integer>> searchedAccordions = null;
private Set<ConfigProcessor.ProcessedOption> searchedOptions = null;
-
- private final LerpingInteger minimumSearchSize = new LerpingInteger(0, 150);
- private final GuiElementTextField searchField = new GuiElementTextField("", 0, 20, 0);
+ private float optionsBarStart;
+ private float optionsBarend;
+ private int lastMouseX = 0;
+ private int keyboardScrollXCutoff = 0;
public NEUConfigEditor(Config config) {
this(config, null);
@@ -160,15 +185,15 @@ public class NEUConfigEditor extends GuiElement {
return selectedCategory;
}
- public String getSelectedCategoryName() {
- return processedConfig.get(selectedCategory).name;
- }
-
private void setSelectedCategory(String category) {
selectedCategory = category;
optionsScroll.setValue(0);
}
+ public String getSelectedCategoryName() {
+ return processedConfig.get(selectedCategory).name;
+ }
+
public void search() {
String search = searchField.getText().trim().replaceAll("[^a-zA-Z_ ]", "").toLowerCase();
searchedCategories = null;
@@ -215,6 +240,7 @@ public class NEUConfigEditor extends GuiElement {
public void render() {
optionsScroll.tick();
categoryScroll.tick();
+ handleKeyboardPresses();
List<String> tooltipToDisplay = null;
@@ -486,10 +512,10 @@ public class NEUConfigEditor extends GuiElement {
}
GL11.glEnable(GL11.GL_SCISSOR_TEST);
- float barStart = optionsScroll.getValue() / (float) (optionY + optionsScroll.getValue());
- float barEnd = barStart + barSize;
- if (barEnd > 1) {
- barEnd = 1;
+ optionsBarStart = optionsScroll.getValue() / (float) (optionY + optionsScroll.getValue());
+ optionsBarend = optionsBarStart + barSize;
+ if (optionsBarend > 1) {
+ optionsBarend = 1;
if (optionsScroll.getTarget() / (float) (optionY + optionsScroll.getValue()) + barSize < 1) {
int target = optionsScroll.getTarget();
optionsScroll.setValue((int) Math.ceil(
@@ -504,9 +530,9 @@ public class NEUConfigEditor extends GuiElement {
Gui.drawRect(innerRight - 10, innerTop + 5, innerRight - 5, innerBottom - 5, 0xff101010);
Gui.drawRect(
innerRight - 9,
- innerTop + 6 + (int) (dist * barStart),
+ innerTop + 6 + (int) (dist * optionsBarStart),
innerRight - 6,
- innerTop + 6 + (int) (dist * barEnd),
+ innerTop + 6 + (int) (dist * optionsBarend),
0xff303030
);
@@ -533,6 +559,7 @@ public class NEUConfigEditor extends GuiElement {
}
public boolean mouseInput(int mouseX, int mouseY) {
+ lastMouseX = mouseX;
ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
int width = scaledResolution.getScaledWidth();
int height = scaledResolution.getScaledHeight();
@@ -551,7 +578,40 @@ public class NEUConfigEditor extends GuiElement {
int innerLeft = x + 149 + innerPadding;
int innerRight = x + xSize - 5 - innerPadding;
+ int dist = innerBottom - innerTop - 12;
+ int optionsBarStartY = innerTop + 6 + (int) (dist * optionsBarStart);
+ int optionsBarEndY = innerTop + 6 + (int) (dist * optionsBarend);
+ int optionsBarStartX = innerRight - 12;
+ int optionsBarEndX = innerRight - 3;
+
+ int categoryY = -categoryScroll.getValue();
+ categoryY += 15 * getCurrentConfigEditing().size();
+ int catDist = innerBottom - innerTop - 12;
+ float catBarStart = categoryScroll.getValue() / (float) (categoryY + categoryScroll.getValue());
+ float categoryBarSize = LerpUtils.clampZeroOne(
+ (float) (innerBottom - innerTop - 2) / (categoryY + 5 + categoryScroll.getValue()));
+ float catBarEnd = catBarStart + categoryBarSize;
+ int categoryBarStartY = innerTop + 6 + (int) (catDist * catBarStart);
+ int categoryBarEndY = innerTop + 6 + (int) (catDist * catBarEnd);
+ int categoryBarStartX = x + innerPadding + 7;
+ int categoryBarEndX = x + innerPadding + 12;
+ keyboardScrollXCutoff = innerLeft - 10;
if (Mouse.getEventButtonState()) {
+ if ((mouseY < optionsBarStartY || mouseY > optionsBarEndY) &&
+ (mouseX >= optionsBarStartX && mouseX <= optionsBarEndX) && mouseY > innerTop + 6 && mouseY < innerBottom - 6) {
+ optionsScroll.setTimeToReachTarget(200);
+ optionsScroll.resetTimer();
+ optionsScroll.setTarget(mouseY - innerTop);
+ return true;
+ } else if ((mouseY < categoryBarStartY || mouseY > categoryBarEndY) &&
+ (mouseX >= categoryBarStartX && mouseX <= categoryBarEndX) && mouseY > innerTop + 6 &&
+ mouseY < innerBottom - 6) {
+ categoryScroll.setTimeToReachTarget(200);
+ categoryScroll.resetTimer();
+ categoryScroll.setTarget(mouseY - innerTop);
+ return true;
+ }
+
searchField.setFocus(mouseX >= innerRight - 20 && mouseX <= innerRight - 2 &&
mouseY >= innerTop - (20 + innerPadding) / 2 - 9 && mouseY <= innerTop - (20 + innerPadding) / 2 + 9);
@@ -788,7 +848,6 @@ public class NEUConfigEditor extends GuiElement {
int innerWidth = xSize - 154 - innerPadding * 2;
if (Keyboard.getEventKeyState()) {
- Keyboard.enableRepeatEvents(true);
String old = searchField.getText();
searchField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey());
searchField.setText(Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(
@@ -832,4 +891,22 @@ public class NEUConfigEditor extends GuiElement {
return true;
}
+
+ private void handleKeyboardPresses() {
+ LerpingInteger target = lastMouseX < keyboardScrollXCutoff ? categoryScroll : optionsScroll;
+ if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
+ target.setTimeToReachTarget(50);
+ target.resetTimer();
+ target.setTarget(target.getTarget() + 5);
+ } else if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
+ target.setTimeToReachTarget(50);
+ target.resetTimer();
+ if (target.getTarget() >= 0) {
+ target.setTarget(target.getTarget() - 5);
+ }
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
+ NotEnoughUpdates.INSTANCE.saveConfig();
+ }
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java b/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java
new file mode 100644
index 00000000..50f459c0
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.customtypes;
+
+import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public enum NEUDebugFlag {
+ // NOTE: Removing enum values causes gson to remove all debugFlags on load if any removed value is present
+ METAL("Metal Detector Solver"),
+ WISHING("Wishing Compass Solver"),
+ MAP("Dungeon Map Player Information"),
+ SEARCH("SearchString Matches"),
+ ;
+
+ private final String description;
+
+ NEUDebugFlag(String description) {
+ this.description = description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public boolean isSet() {
+ return NEUDebugLogger.isFlagEnabled(this);
+ }
+
+ public static String getFlagList() {
+ return renderFlagInformation(Arrays.asList(values()));
+ }
+
+ public static String getEnabledFlags() {
+ return renderFlagInformation(Arrays.stream(values())
+ .filter(NEUDebugFlag::isSet)
+ .collect(Collectors.toList()));
+ }
+
+ public static String renderFlagInformation(List<NEUDebugFlag> flags) {
+ int maxNameLength = flags.stream()
+ .mapToInt(it -> it.name().length())
+ .max()
+ .orElse(0);
+ return flags.stream()
+ .map(it -> (CharSequence) String.format(
+ "%-" + maxNameLength + "s" + " - %s",
+ it.name(),
+ it.getDescription()
+ ))
+ .collect(Collectors.joining("\n"));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHGraph.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHGraph.java
index 8d3acaf9..ce931392 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHGraph.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHGraph.java
@@ -1,7 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
import org.lwjgl.input.Keyboard;
public class AHGraph {
@@ -27,7 +51,7 @@ public class AHGraph {
desc = "Change the style of the graph GUI"
)
@ConfigEditorDropdown(
- values = {"Minecraft", "Dark", "PacksHQ Dark", "FSR"}
+ values = {"Minecraft", "Grey", "PacksHQ Dark", "FSR"}
)
public int graphStyle = 0;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHTweaks.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHTweaks.java
index 0d21a96f..298ddeda 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHTweaks.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AHTweaks.java
@@ -1,7 +1,30 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
public class AHTweaks {
@ConfigOption(
@@ -57,17 +80,26 @@ public class AHTweaks {
@Expose
@ConfigOption(
- name = "Enable BIN Warning",
+ name = "Enable Undercut BIN Warning",
desc = "Ask for confirmation when BINing an item for below X% of lowestbin"
)
@ConfigEditorBoolean
@ConfigAccordionId(id = 1)
- public boolean enableBINWarning = true;
+ public boolean underCutWarning = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Overcut BIN Warning",
+ desc = "Ask for confirmation when BINing an item for over X% of lowestbin"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean overCutWarning = true;
@Expose
@ConfigOption(
- name = "Warning Threshold",
- desc = "Threshold for BIN warning\nExample: 10% means warn if sell price is 10% lower than lowestbin"
+ name = "Undercut Warning Threshold",
+ desc = "Threshold for BIN warning\nExample: 10% means warn if sell price is 10% lower than lowest bin"
)
@ConfigEditorSlider(
minValue = 0.0f,
@@ -77,6 +109,19 @@ public class AHTweaks {
@ConfigAccordionId(id = 1)
public float warningThreshold = 10f;
+ @Expose
+ @ConfigOption(
+ name = "Overcut Warning Threshold",
+ desc = "Threshold for BIN warning\nExample: 50% means warn if sell price is 50% higher than lowest bin"
+ )
+ @ConfigEditorSlider(
+ minValue = 0.0f,
+ maxValue = 100.0f,
+ minStep = 5f
+ )
+ @ConfigAccordionId(id = 1)
+ public float overcutWarningThreshold = 50f;
+
@ConfigOption(
name = "Sort Warning",
desc = ""
@@ -92,4 +137,13 @@ public class AHTweaks {
@ConfigEditorBoolean
@ConfigAccordionId(id = 2)
public boolean enableSortWarning = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable AH Sell Value",
+ desc = "Display profit information (coins to collect, value if all sold, expired and unclaimed auctions)"
+ )
+ @ConfigEditorBoolean
+ public boolean enableAhSellValue = true;
+
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AccessoryBag.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AccessoryBag.java
index 9a3d0946..b87db1d6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AccessoryBag.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/AccessoryBag.java
@@ -1,15 +1,34 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class AccessoryBag {
- @Expose
- @ConfigOption(
- name = "Enable Accessory Bag Overlay",
- desc = "Show an overlay on the accessory bag screen which gives useful information about your accessories"
- )
- @ConfigEditorBoolean
- public boolean enableOverlay = true;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class AccessoryBag {
+ @Expose
+ @ConfigOption(
+ name = "Enable Accessory Bag Overlay",
+ desc = "Show an overlay on the accessory bag screen which gives useful information about your accessories"
+ )
+ @ConfigEditorBoolean
+ public boolean enableOverlay = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java
new file mode 100644
index 00000000..9ed09ac3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorText;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class ApiData {
+ @Expose
+ @ConfigOption(
+ name = "Api Key",
+ desc = "Hypixel api key\nYou can run §a/api new§r to autofill this value."
+ )
+ @ConfigEditorText
+ public String apiKey = "";
+
+ @ConfigEditorAccordion(id = 0)
+ @ConfigOption(name = "Repository", desc = "")
+ public boolean repository = false;
+
+ @Expose
+ @ConfigOption(name = "Automatically Update Repository", desc = "Update the repository on every startup")
+ @ConfigEditorBoolean()
+ @ConfigAccordionId(id = 0)
+ public boolean autoupdate = true;
+
+ @ConfigAccordionId(id = 0)
+ @ConfigOption(name = "Update Repository now", desc = "Refresh your repository")
+ @ConfigEditorButton(runnableId = 22, buttonText = "Update")
+ public int updateRepositoryButton = 0;
+
+ @ConfigEditorAccordion(id = 1)
+ @ConfigAccordionId(id = 0)
+ @ConfigOption(name = "Repository Location", desc = "")
+ public boolean repositoryLocation = false;
+
+ @ConfigAccordionId(id = 1)
+ @ConfigOption(name = "Use default repository", desc = "The latest, most up to date item list for the official NEU releases.")
+ @ConfigEditorButton(runnableId = 23, buttonText = "Reset")
+ public int setRepositoryToDefaultButton = 0;
+
+ @ConfigAccordionId(id = 1)
+ @ConfigOption(name = "Use pre-release repository", desc = "The latest, most up to date item list for the NEU pre-releases.\n§4Use §lonly§r§4 with the pre-releases.")
+ @ConfigEditorButton(runnableId = 24, buttonText = "Use")
+ public int setRepositoryToDangerousButton = 0;
+
+ @Expose
+ @ConfigAccordionId(id = 1)
+ @ConfigOption(name = "Repository User", desc = "Repository User")
+ @ConfigEditorText
+ public String repoUser = "NotEnoughUpdates";
+
+ @Expose
+ @ConfigAccordionId(id = 1)
+ @ConfigOption(name = "Repository Name", desc = "Repository Name")
+ @ConfigEditorText
+ public String repoName = "NotEnoughUpdates-REPO";
+
+ @Expose
+ @ConfigAccordionId(id = 1)
+ @ConfigOption(name = "Repository Branch", desc = "Repository Branch")
+ @ConfigEditorText
+ public String repoBranch = "master";
+
+ @Expose
+ @ConfigAccordionId(id = 0)
+ @ConfigOption(name = "Edit Mode", desc = "Enables you to edit items in the item list.\n§4Recommended for repository maintainers only.\n§4§lRemember: §rTurn off auto update as well")
+ @ConfigEditorBoolean
+ public boolean repositoryEditing = false;
+
+ @Expose
+ @ConfigOption(name = "Lowestbin API", desc = "§4Do §lNOT §r§4change this, unless you know exactly what you are doing\n§fDefault: §amoulberry.codes")
+ @ConfigEditorText
+ public String moulberryCodesApi = "moulberry.codes";
+
+ public String getCommitApiUrl() {
+ return String.format("https://api.github.com/repos/%s/%s/commits/%s", repoUser, repoName, repoBranch);
+ }
+
+ public String getDownloadUrl(String commitId) {
+ return String.format("https://github.com/%s/%s/archive/%s.zip", repoUser, repoName, commitId);
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiKey.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiKey.java
deleted file mode 100644
index 0c5e4d2d..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiKey.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorText;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class ApiKey {
- @Expose
- @ConfigOption(
- name = "Api Key",
- desc = "Hypixel api key"
- )
- @ConfigEditorText
- public String apiKey = "";
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/BazaarTweaks.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/BazaarTweaks.java
new file mode 100644
index 00000000..954af02d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/BazaarTweaks.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class BazaarTweaks {
+
+ @ConfigOption(
+ name = "Search GUI",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean searchAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Search GUI",
+ desc = "Use the advanced search GUI with autocomplete and history instead of the normal sign GUI"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableSearchOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Keep Previous Search",
+ desc = "Don't clear the search bar after closing the GUI"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean keepPreviousSearch = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Past Searches",
+ desc = "Show past searches below the autocomplete box"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean showPastSearches = true;
+
+ @Expose
+ @ConfigOption(
+ name = "ESC to Full Close",
+ desc = "Make pressing ESCAPE close the search GUI without opening up the Bazaar again\n" +
+ "ENTER can still be used to search"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean escFullClose = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Calendar.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Calendar.java
index 332f5e8d..fe593f56 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Calendar.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Calendar.java
@@ -1,53 +1,72 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class Calendar {
- @Expose
- @ConfigOption(
- name = "Event Notifications",
- desc = "Display notifications for skyblock calendar events"
- )
- @ConfigEditorBoolean
- public boolean eventNotifications = true;
-
- @Expose
- @ConfigOption(
- name = "Starting Soon Time",
- desc = "Display a notification before events start, time in seconds.\n" +
- "0 = No prior notification"
- )
- @ConfigEditorSlider(
- minValue = 0f,
- maxValue = 600f,
- minStep = 30f
- )
- public int startingSoonTime = 300;
-
- @Expose
- @ConfigOption(
- name = "Timer In Inventory",
- desc = "Displays the time until the next event at the top of your screen when in inventories"
- )
- @ConfigEditorBoolean
- public boolean showEventTimerInInventory = true;
-
- @Expose
- @ConfigOption(
- name = "Notification Sounds",
- desc = "Play a sound whenever events start"
- )
- @ConfigEditorBoolean
- public boolean eventNotificationSounds = true;
-
- @Expose
- @ConfigOption(
- name = "Spooky Night Notification",
- desc = "Send a notification during spooky event when the time reaches 7pm"
- )
- @ConfigEditorBoolean
- public boolean spookyNightNotification = true;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class Calendar {
+ @Expose
+ @ConfigOption(
+ name = "Event Notifications",
+ desc = "Display notifications for skyblock calendar events"
+ )
+ @ConfigEditorBoolean
+ public boolean eventNotifications = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Starting Soon Time",
+ desc = "Display a notification before events start, time in seconds.\n" +
+ "0 = No prior notification"
+ )
+ @ConfigEditorSlider(
+ minValue = 0f,
+ maxValue = 600f,
+ minStep = 30f
+ )
+ public int startingSoonTime = 300;
+
+ @Expose
+ @ConfigOption(
+ name = "Timer In Inventory",
+ desc = "Displays the time until the next event at the top of your screen when in inventories"
+ )
+ @ConfigEditorBoolean
+ public boolean showEventTimerInInventory = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Notification Sounds",
+ desc = "Play a sound whenever events start"
+ )
+ @ConfigEditorBoolean
+ public boolean eventNotificationSounds = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Spooky Night Notification",
+ desc = "Send a notification during spooky event when the time reaches 7pm"
+ )
+ @ConfigEditorBoolean
+ public boolean spookyNightNotification = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/CustomArmour.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/CustomArmour.java
index 57a5e1d7..92b4b2ab 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/CustomArmour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/CustomArmour.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
@@ -9,27 +28,28 @@ public class CustomArmour {
@Expose
@ConfigOption(
- name = "Enable Custom Armour Hud",
- desc = "Shows an overlay in your inventory showing your 4 extra armour slots"
+ name = "Enable Equipment Hud",
+ desc = "Shows an overlay in your inventory showing your 4 extra armour slots\n" +
+ "\u00A7cRequires Hide Potion Effects to be enabled"
)
@ConfigEditorBoolean
public boolean enableArmourHud = true;
@Expose
@ConfigOption(
- name = "Click To Open Wardrobe",
- desc = "Click on the hud to open /wardrobe"
+ name = "Click To Open Equipment Menu",
+ desc = "Click on the hud to open /equipment"
)
@ConfigEditorBoolean
public boolean sendWardrobeCommand = true;
@Expose
@ConfigOption(
- name = "GUI Colour",
+ name = "GUI Style",
desc = "Change the colour of the GUI"
)
@ConfigEditorDropdown(
- values = {"Vanilla", "Grey", "Dark", "Transparent", "FSR"}
+ values = {"Minecraft", "Grey", "PacksHQ Dark", "Transparent", "FSR"}
)
public int colourStyle = 0;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/DungeonMapConfig.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/DungeonMapConfig.java
index b46eafd9..8e211bd6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/DungeonMapConfig.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/DungeonMapConfig.java
@@ -1,142 +1,161 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class DungeonMapConfig {
- @Expose
- @ConfigOption(
- name = "Border Size",
- desc = "Changes the size of the map border, without changing the size of the contents"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 5,
- minStep = 0.25f
- )
- public float dmBorderSize = 1;
-
- @Expose
- @ConfigOption(
- name = "Room Size",
- desc = "Changes the size of rooms. Useful for higher dungeons with larger maps"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 5,
- minStep = 0.25f
- )
- public float dmRoomSize = 1;
-
- @Expose
- @ConfigOption(
- name = "Icon Size",
- desc = "Changes the scale of room indicators and player icons"
- )
- @ConfigEditorSlider(
- minValue = 0.5f,
- maxValue = 3f,
- minStep = 0.25f
- )
- public float dmIconScale = 1.0f;
-
- @Expose
- @ConfigOption(
- name = "Border Style",
- desc = "Various custom borders from various talented artists.\nUse 'custom' if your texture pack has a custom border"
- )
- public int dmBorderStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Show Dungeon Map",
- desc = "Show/hide the NEU dungeon map"
- )
- public boolean dmEnable = true;
-
- @Expose
- @ConfigOption(
- name = "Map Center",
- desc = "Center on rooms, or center on your player"
- )
- public boolean dmCenterPlayer = true;
-
- @Expose
- @ConfigOption(
- name = "Rotate with Player",
- desc = "Rotate the map to face the same direction as your player"
- )
- public boolean dmRotatePlayer = true;
-
- @Expose
- @ConfigOption(
- name = "Orient Checkmarks",
- desc = "Checkmarks will always show vertically, regardless of rotation"
- )
- public boolean dmOrientCheck = true;
-
- @Expose
- @ConfigOption(
- name = "Center Checkmarks",
- desc = "Checkmarks will show closer to the center of rooms"
- )
- public boolean dmCenterCheck = false;
-
- @Expose
- @ConfigOption(
- name = "Player Icon Style",
- desc = "Various player icon styles"
- )
- public int dmPlayerHeads = 0;
-
- @Expose
- @ConfigOption(
- name = "Interpolate Far Players",
- desc = "Will make players far away move smoothly"
- )
- public boolean dmPlayerInterp = true;
-
- @Expose
- @ConfigOption(
- name = "OpenGL Compatibility",
- desc = "Compatiblity options for people with bad computers. ONLY use this if you know what you are doing, otherwise the map will look worse"
- )
- public int dmCompat = 0;
-
- @Expose
- @ConfigOption(
- name = "Background Colour",
- desc = "Colour of the map background. Supports opacity & chroma"
- )
- public String dmBackgroundColour = "00:170:75:75:75";
-
- @Expose
- @ConfigOption(
- name = "Border Colour",
- desc = "Colour of the map border. Supports opacity & chroma. Turn off custom borders to see"
- )
- public String dmBorderColour = "00:0:0:0:0";
-
- @Expose
- @ConfigOption(
- name = "Chroma Border Mode",
- desc = "Applies a hue offset around the map border"
- )
- public boolean dmChromaBorder = false;
-
- @Expose
- @ConfigOption(
- name = "Background Blur Factor",
- desc = "Changes the blur factor behind the map. Set to 0 to disable blur"
- )
- public float dmBackgroundBlur = 0;
-
- @Expose
- @ConfigOption(
- name = "Position",
- desc = "The position of the map"
- )
- public Position dmPosition = new Position(10, 10);
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.Position;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class DungeonMapConfig {
+ @Expose
+ @ConfigOption(
+ name = "Border Size",
+ desc = "Changes the size of the map border, without changing the size of the contents"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 5,
+ minStep = 0.25f
+ )
+ public float dmBorderSize = 1;
+
+ @Expose
+ @ConfigOption(
+ name = "Room Size",
+ desc = "Changes the size of rooms. Useful for higher dungeons with larger maps"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 5,
+ minStep = 0.25f
+ )
+ public float dmRoomSize = 1;
+
+ @Expose
+ @ConfigOption(
+ name = "Icon Size",
+ desc = "Changes the scale of room indicators and player icons"
+ )
+ @ConfigEditorSlider(
+ minValue = 0.5f,
+ maxValue = 3f,
+ minStep = 0.25f
+ )
+ public float dmIconScale = 1.0f;
+
+ @Expose
+ @ConfigOption(
+ name = "Border Style",
+ desc = "Various custom borders from various talented artists.\nUse 'custom' if your texture pack has a custom border"
+ )
+ public int dmBorderStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Dungeon Map",
+ desc = "Show/hide the NEU dungeon map"
+ )
+ public boolean dmEnable = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Map Center",
+ desc = "Center on rooms, or center on your player"
+ )
+ public boolean dmCenterPlayer = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Rotate with Player",
+ desc = "Rotate the map to face the same direction as your player"
+ )
+ public boolean dmRotatePlayer = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Orient Checkmarks",
+ desc = "Checkmarks will always show vertically, regardless of rotation"
+ )
+ public boolean dmOrientCheck = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Center Checkmarks",
+ desc = "Checkmarks will show closer to the center of rooms"
+ )
+ public boolean dmCenterCheck = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Player Icon Style",
+ desc = "Various player icon styles"
+ )
+ public int dmPlayerHeads = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Interpolate Far Players",
+ desc = "Will make players far away move smoothly"
+ )
+ public boolean dmPlayerInterp = true;
+
+ @Expose
+ @ConfigOption(
+ name = "OpenGL Compatibility",
+ desc = "Compatiblity options for people with bad computers. ONLY use this if you know what you are doing, otherwise the map will look worse"
+ )
+ public int dmCompat = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Background Colour",
+ desc = "Colour of the map background. Supports opacity & chroma"
+ )
+ public String dmBackgroundColour = "00:170:75:75:75";
+
+ @Expose
+ @ConfigOption(
+ name = "Border Colour",
+ desc = "Colour of the map border. Supports opacity & chroma. Turn off custom borders to see"
+ )
+ public String dmBorderColour = "00:0:0:0:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Chroma Border Mode",
+ desc = "Applies a hue offset around the map border"
+ )
+ public boolean dmChromaBorder = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Background Blur Factor",
+ desc = "Changes the blur factor behind the map. Set to 0 to disable blur"
+ )
+ public float dmBackgroundBlur = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Position",
+ desc = "Change the position of the map"
+ )
+ public Position dmPosition = new Position(10, 10);
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java
index ce164c9a..c94bd181 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Dungeons.java
@@ -1,229 +1,275 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-public class Dungeons {
- @ConfigOption(
- name = "Dungeon Map",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean dungeonMapAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "\u00A7cWarning",
- desc = "If you are on Entrance, Floor 1 or Master 1 the map wont work properly"
- )
- @ConfigEditorFSR(
- runnableId = 12,
- buttonText = ""
- )
- @ConfigAccordionId(id = 0)
- public boolean dungeonF1Warning = false;
-
- @Expose
- @ConfigOption(
- name = "Edit Dungeon Map",
- desc = "The NEU dungeon map has it's own editor (/neumap).\n" +
- "Click the button on the left to open it"
- )
- @ConfigEditorButton(
- runnableId = 0,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 0)
- public int editDungeonMap = 0;
-
- @Expose
- @ConfigOption(
- name = "Show Own Head As Marker",
- desc = "If you have the \"Head\" icon style selected, don't replace your green marker with a head"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean showOwnHeadAsMarker = false;
-
- @ConfigOption(
- name = "Dungeon Profit",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- public boolean dungeonProfitAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Profit Type",
- desc = "Set the price dataset used for calculating profit"
- )
- @ConfigEditorDropdown(
- values = {"Lowest BIN", "24 AVG Lowest Bin", "Auction AVG"}
- )
- @ConfigAccordionId(id = 1)
- public int profitType = 0;
-
- @Expose
- @ConfigOption(
- name = "Profit Display Location",
- desc = "Set where the profit information is displayed\n" +
- "Overlay = Overlay on right side of inventory\n" +
- "GUI Title = Text displayed next to the inventory title\n" +
- "Lore = Inside the \"Open Reward Chest\" item"
- )
- @ConfigEditorDropdown(
- values = {"Overlay", "GUI Title", "Lore", "Off"}
- )
- @ConfigAccordionId(id = 1)
- public int profitDisplayLoc = 0;
-
- @Expose
- @ConfigOption(
- name = "Include Kismet Feather",
- desc = "Include Kismet Feathers in the Profit Calculation after rerolling"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean useKismetOnDungeonProfit = true;
-
- @ConfigOption(
- name = "Dungeon Win Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 3)
- public boolean dungeonWinAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Dungeon Win",
- desc = "Show a fancy win screen and stats when completing a dungeon"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean enableDungeonWin = true;
-
- @Expose
- @ConfigOption(
- name = "Dungeon Win Time",
- desc = "Change the amount of time (milliseconds) that the win screen shows for"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 20000,
- minStep = 500
- )
- @ConfigAccordionId(id = 3)
- public int dungeonWinMillis = 8000;
-
- @ConfigOption(
- name = "Dungeon Block Overlay",
- desc = ""
- )
-
- @ConfigEditorAccordion(id = 2)
- public boolean dungeonBlocksAccordion = false;
- @ConfigOption(
- name = "\u00A7cWarning",
- desc = "You need Fast Render and Antialiasing off for these settings to work\n" +
- "You can find these in your video settings"
- )
- @ConfigEditorFSR(
- runnableId = 12,
- buttonText = ""
- )
- @ConfigAccordionId(id = 2)
- public boolean dungeonBlockWarning = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Block Overlay",
- desc = "Change the colour of certain blocks / entities while inside dungeons, but keeps the normal texture outside of dungeons"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean enableDungBlockOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Show Overlay Everywhere",
- desc = "Show the dungeon block overlay even when not inside dungeons. Should only be used for testing."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean dungeonBlocksEverywhere = false;
-
- @Expose
- @ConfigOption(
- name = "Slow Update",
- desc = "Updates the colour every second instead of every tick.\n" +
- "\u00A7cWARNING: This will cause all texture animations (eg. flowing water) to update slowly.\n" +
- "This should only be used on low-end machines"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean slowDungeonBlocks = false;
-
- @Expose
- @ConfigOption(
- name = "Cracked Bricks",
- desc = "Change the colour of: Cracked Bricks"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungCrackedColour = "0:255:7:255:217";
-
- @Expose
- @ConfigOption(
- name = "Dispensers",
- desc = "Change the colour of: Dispensers"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungDispenserColour = "0:255:255:76:0";
-
- @Expose
- @ConfigOption(
- name = "Levers",
- desc = "Change the colour of: Levers"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungLeverColour = "0:252:24:249:255";
-
- @Expose
- @ConfigOption(
- name = "Tripwire String",
- desc = "Change the colour of: Tripwire String"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungTripWireColour = "0:255:255:0:0";
-
- @Expose
- @ConfigOption(
- name = "Normal Chests",
- desc = "Change the colour of: Normal Chests"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungChestColour = "0:255:0:163:36";
-
- @Expose
- @ConfigOption(
- name = "Trapped Chests",
- desc = "Change the colour of: Trapped Chests"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungTrappedChestColour = "0:255:0:163:36";
-
- @Expose
- @ConfigOption(
- name = "Bats",
- desc = "Change the colour of: Bats"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String dungBatColour = "0:255:12:255:0";
-
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class Dungeons {
+
+ @ConfigOption(
+ name = "Dungeon Map",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean dungeonMapAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "\u00A7cWarning",
+ desc = "If you are on Entrance, Floor 1 or Master 1 the map wont work properly"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12,
+ buttonText = ""
+ )
+ @ConfigAccordionId(id = 0)
+ public boolean dungeonF1Warning = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Dungeon Map",
+ desc = "The NEU dungeon map has it's own editor (/neumap).\n" +
+ "Click the button on the left to open it"
+ )
+ @ConfigEditorButton(
+ runnableId = 0,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 0)
+ public int editDungeonMap = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Own Head As Marker",
+ desc = "If you have the \"Head\" icon style selected, don't replace your green marker with a head"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean showOwnHeadAsMarker = false;
+
+ @ConfigOption(
+ name = "Dungeon Profit",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean dungeonProfitAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Profit Type",
+ desc = "Set the price dataset used for calculating profit"
+ )
+ @ConfigEditorDropdown(
+ values = {"Lowest BIN", "24 AVG Lowest Bin", "Auction AVG"}
+ )
+ @ConfigAccordionId(id = 1)
+ public int profitType = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Profit Display Location",
+ desc = "Set where the profit information is displayed\n" +
+ "Overlay = Overlay on right side of inventory\n" +
+ "GUI Title = Text displayed next to the inventory title\n" +
+ "Lore = Inside the \"Open Reward Chest\" item"
+ )
+ @ConfigEditorDropdown(
+ values = {"Overlay", "GUI Title", "Lore", "Off"}
+ )
+ @ConfigAccordionId(id = 1)
+ public int profitDisplayLoc = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Include Kismet Feather",
+ desc = "Include Kismet Feathers in the Profit Calculation after rerolling"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean useKismetOnDungeonProfit = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Include Essence Cost",
+ desc = "Include Bazaar Essence Sell Cost in the Profit Calculation for Dungeon Chests"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean useEssenceCostFromBazaar = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Warning if Derpy active",
+ desc = "Shows a warning if the mayor Derpy is active"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean shouldWarningDerpy = true;
+
+ @ConfigOption(
+ name = "Dungeon Win Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 3)
+ public boolean dungeonWinAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Dungeon Win",
+ desc = "Show a fancy win screen and stats when completing a dungeon"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean enableDungeonWin = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Dungeon Win Time",
+ desc = "Change the amount of time (milliseconds) that the win screen shows for"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 20000,
+ minStep = 500
+ )
+ @ConfigAccordionId(id = 3)
+ public int dungeonWinMillis = 8000;
+
+ @ConfigOption(
+ name = "Dungeon Block Overlay",
+ desc = ""
+ )
+
+ @ConfigEditorAccordion(id = 2)
+ public boolean dungeonBlocksAccordion = false;
+ @ConfigOption(
+ name = "\u00A7cWarning",
+ desc = "You need Fast Render and Antialiasing off for these settings to work\n" +
+ "You can find these in your video settings"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12,
+ buttonText = ""
+ )
+ @ConfigAccordionId(id = 2)
+ public boolean dungeonBlockWarning = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Block Overlay",
+ desc = "Change the colour of certain blocks / entities while inside dungeons, but keeps the normal texture outside of dungeons"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean enableDungBlockOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Overlay Everywhere",
+ desc = "Show the dungeon block overlay even when not inside dungeons. Should only be used for testing."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean dungeonBlocksEverywhere = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Slow Update",
+ desc = "Updates the colour every second instead of every tick.\n" +
+ "\u00A7cWARNING: This will cause all texture animations (eg. flowing water) to update slowly.\n" +
+ "This should only be used on low-end machines"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean slowDungeonBlocks = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Cracked Bricks",
+ desc = "Change the colour of: Cracked Bricks"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungCrackedColour = "0:255:7:255:217";
+
+ @Expose
+ @ConfigOption(
+ name = "Dispensers",
+ desc = "Change the colour of: Dispensers"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungDispenserColour = "0:255:255:76:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Levers",
+ desc = "Change the colour of: Levers"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungLeverColour = "0:252:24:249:255";
+
+ @Expose
+ @ConfigOption(
+ name = "Tripwire String",
+ desc = "Change the colour of: Tripwire String"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungTripWireColour = "0:255:255:0:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Normal Chests",
+ desc = "Change the colour of: Normal Chests"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungChestColour = "0:255:0:163:36";
+
+ @Expose
+ @ConfigOption(
+ name = "Trapped Chests",
+ desc = "Change the colour of: Trapped Chests"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungTrappedChestColour = "0:255:0:163:36";
+
+ @Expose
+ @ConfigOption(
+ name = "Bats",
+ desc = "Change the colour of: Bats"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String dungBatColour = "0:255:12:255:0";
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Enchanting.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Enchanting.java
index e9add7b4..b596d180 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Enchanting.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Enchanting.java
@@ -1,11 +1,34 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
public class Enchanting {
@ConfigOption(
- name = "Enchant Table GUI",
+ name = "Enchant Table / Hex GUI",
desc = ""
)
@ConfigEditorAccordion(id = 1)
@@ -20,6 +43,15 @@ public class Enchanting {
@ConfigAccordionId(id = 1)
public boolean enableTableGUI = true;
+ @Expose
+ @ConfigOption(
+ name = "Enable Hex GUI",
+ desc = "Show a custom GUI when using the Hex"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean enableHexGUI = true;
+
/*@Expose
@ConfigOption(
name = "Incompatible Enchants",
@@ -53,6 +85,15 @@ public class Enchanting {
@ConfigAccordionId(id = 1)
public int enchantOrdering = 0;
+ @Expose
+ @ConfigOption(
+ name = "Use highest level from /et in /hex",
+ desc = "Show max level from /et in hex instead of highest possible"
+ )
+ @ConfigEditorBoolean()
+ @ConfigAccordionId(id = 1)
+ public boolean maxEnchLevel = false;
+
@ConfigOption(
name = "Enchanting Solvers",
desc = ""
@@ -91,7 +132,7 @@ public class Enchanting {
@Expose
@ConfigOption(
name = "Ultrasequencer Numbers",
- desc = "Replace the items in the supersequencer with only numbers"
+ desc = "Replace the items in the Ultrasequencer with only numbers"
)
@ConfigEditorBoolean
@ConfigAccordionId(id = 0)
@@ -108,6 +149,15 @@ public class Enchanting {
@Expose
@ConfigOption(
+ name = "Hide Buttons",
+ desc = "Hide Inventory Buttons and Quick Commands while in the experimentation table"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean hideButtons = false;
+
+ @Expose
+ @ConfigOption(
name = "Ultrasequencer Next",
desc = "Set the colour of the glass pane shown behind the element in the ultrasequencer which is next"
)
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Fishing.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Fishing.java
index aa2bacd3..b6075794 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Fishing.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Fishing.java
@@ -1,207 +1,301 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-public class Fishing {
- @Expose
- @ConfigOption(
- name = "Hide Other Players Fishing",
- desc = "Convenience option to easily hide \u00a7lother players'\u00a7r bobbers, rod lines and fishing particles\n" +
- "The advanced options below allow you to set the precise colour, particles, etc."
- )
- @ConfigEditorBoolean
- public boolean hideOtherPlayerAll = false;
-
- @ConfigOption(
- name = "Incoming Fish Warning",
- desc = ""
- )
- @ConfigEditorAccordion(id = 3)
- public boolean incomingFishAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Fish Warning (R)",
- desc = "Display a red '!' when you need to pull the fish up. The warning takes your ping into account"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean incomingFishWarningR = true;
-
- @Expose
- @ConfigOption(
- name = "Enable Fish Warning (Y)",
- desc = "Display a yellow '!' when a fish is approaching your bobber"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean incomingFishWarning = true;
-
- @Expose
- @ConfigOption(
- name = "Enable Hooked Sound",
- desc = "Play a high-pitched ding sound when the '!' turns red"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean incomingFishHookedSounds = true;
-
- @Expose
- @ConfigOption(
- name = "Enable Approach Sound",
- desc = "Play low-pitched ding sounds while the yellow '!' is visible"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean incomingFishIncSounds = false;
-
- @ConfigOption(
- name = "Volumes",
- desc = ""
- )
- @ConfigAccordionId(id = 3)
- @ConfigEditorAccordion(id = 5)
- public boolean incomingFishVolumeAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Hooked Sound Vol.",
- desc = "Set the volume of the hooked sound"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 100,
- minStep = 1
- )
- @ConfigAccordionId(id = 5)
- public float incomingFishHookedSoundsVol = 25;
-
- @Expose
- @ConfigOption(
- name = "Approach Sound Vol.",
- desc = "Set the volume of the approaching sound"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 100,
- minStep = 1
- )
- @ConfigAccordionId(id = 5)
- public float incomingFishIncSoundsVol = 10;
-
- @ConfigOption(
- name = "Fishing Particles",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean particleAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Custom Particles",
- desc = "Allow you to modify the particles that appear when a fish is incoming for you and other players"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean enableCustomParticles = false;
-
- @ConfigOption(
- name = "Your Particles",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- @ConfigAccordionId(id = 0)
- public boolean yourParticlesAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Particle Type",
- desc = "Change the type of the particle that is spawned\n" +
- "Particle types with (RGB) support custom colours\n" +
- "Set to 'NONE' to disable particles"
- )
- @ConfigEditorDropdown(
- values = {"Default", "None", "Spark (RGB)", "Swirl (RGB)", "Dust (RGB)", "Flame", "Crit", "Magic Crit"}
- )
- @ConfigAccordionId(id = 1)
- public int yourParticleType = 0;
-
- @Expose
- @ConfigOption(
- name = "Custom Colour",
- desc = "Set a custom colour for the particle\n" +
- "Only works for particle types with (RGB)"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 1)
- public String yourParticleColour = "0:255:255:255:255";
-
- @ConfigOption(
- name = "Other Players' Particles",
- desc = ""
- )
- @ConfigEditorAccordion(id = 2)
- @ConfigAccordionId(id = 0)
- public boolean otherParticlesAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Particle Type",
- desc = "Change the type of the particle that is spawned\n" +
- "Particle types with (RGB) support custom colours\n" +
- "Set to 'NONE' to disable particles"
- )
- @ConfigEditorDropdown(
- values = {"Default", "None", "Spark (RGB)", "Swirl (RGB)", "Dust (RGB)", "Flame", "Crit", "Magic Crit"}
- )
- @ConfigAccordionId(id = 2)
- public int otherParticleType = 0;
-
- @Expose
- @ConfigOption(
- name = "Custom Colour",
- desc = "Set a custom colour for the particle\n" +
- "Only works for particle types with (RGB)"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 2)
- public String otherParticleColour = "0:255:255:255:255";
-
- @ConfigOption(
- name = "Rod Line Colours",
- desc = ""
- )
- @ConfigEditorAccordion(id = 4)
- public boolean rodAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Rod Line Colours",
- desc = "Change the colour of your and other players' rod lines\n" +
- "Also fixes the position of the rod line"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 4)
- public boolean enableRodColours = true;
-
- @Expose
- @ConfigOption(
- name = "Own Rod Colour",
- desc = "Change the colour of your own rod lines\n" +
- "You can set the opacity to '0' to HIDE"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 4)
- public String ownRodColour = "0:255:0:0:0";
-
- @Expose
- @ConfigOption(
- name = "Other Rod Colour",
- desc = "Change the colour of other players' rod lines\n" +
- "You can set the opacity to '0' to HIDE"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 4)
- public String otherRodColour = "0:255:0:0:0";
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class Fishing {
+ @Expose
+ @ConfigOption(
+ name = "Hide Other Players Fishing",
+ desc = "Convenience option to easily hide \u00a7lother players'\u00a7r bobbers, rod lines and fishing particles\n" +
+ "The advanced options below allow you to set the precise colour, particles, etc."
+ )
+ @ConfigEditorBoolean
+ public boolean hideOtherPlayerAll = false;
+
+ @ConfigOption(
+ name = "Incoming Fish Warning",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 3)
+ public boolean incomingFishAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Fish Warning (R)",
+ desc = "Display a red '!' when you need to pull the fish up. The warning takes your ping into account"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean incomingFishWarningR = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Fish Warning (Y)",
+ desc = "Display a yellow '!' when a fish is approaching your bobber"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean incomingFishWarning = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Hooked Sound",
+ desc = "Play a high-pitched ding sound when the '!' turns red"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean incomingFishHookedSounds = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Approach Sound",
+ desc = "Play low-pitched ding sounds while the yellow '!' is visible"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean incomingFishIncSounds = false;
+
+ @ConfigOption(
+ name = "Volumes",
+ desc = ""
+ )
+ @ConfigAccordionId(id = 3)
+ @ConfigEditorAccordion(id = 5)
+ public boolean incomingFishVolumeAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Hooked Sound Vol.",
+ desc = "Set the volume of the hooked sound"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 100,
+ minStep = 1
+ )
+ @ConfigAccordionId(id = 5)
+ public float incomingFishHookedSoundsVol = 25;
+
+ @Expose
+ @ConfigOption(
+ name = "Approach Sound Vol.",
+ desc = "Set the volume of the approaching sound"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 100,
+ minStep = 1
+ )
+ @ConfigAccordionId(id = 5)
+ public float incomingFishIncSoundsVol = 10;
+
+ @ConfigOption(
+ name = "Fishing Particles",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean particleAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Custom Particles",
+ desc = "Allow you to modify the particles that appear when a fish is incoming for you and other players"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableCustomParticles = false;
+
+ @ConfigOption(
+ name = "Your Particles",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ @ConfigAccordionId(id = 0)
+ public boolean yourParticlesAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Particle Type",
+ desc = "Change the type of the particle that is spawned\n" +
+ "Particle types with (RGB) support custom colours\n" +
+ "Set to 'NONE' to disable particles"
+ )
+ @ConfigEditorDropdown(
+ values = {"Default", "None", "Spark (RGB)", "Swirl (RGB)", "Dust (RGB)", "Flame", "Crit", "Magic Crit"}
+ )
+ @ConfigAccordionId(id = 1)
+ public int yourParticleType = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Custom Colour",
+ desc = "Set a custom colour for the particle\n" +
+ "Only works for particle types with (RGB)"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 1)
+ public String yourParticleColour = "0:255:255:255:255";
+
+ @ConfigOption(
+ name = "Other Players' Particles",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 2)
+ @ConfigAccordionId(id = 0)
+ public boolean otherParticlesAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Particle Type",
+ desc = "Change the type of the particle that is spawned\n" +
+ "Particle types with (RGB) support custom colours\n" +
+ "Set to 'NONE' to disable particles"
+ )
+ @ConfigEditorDropdown(
+ values = {"Default", "None", "Spark (RGB)", "Swirl (RGB)", "Dust (RGB)", "Flame", "Crit", "Magic Crit"}
+ )
+ @ConfigAccordionId(id = 2)
+ public int otherParticleType = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Custom Colour",
+ desc = "Set a custom colour for the particle\n" +
+ "Only works for particle types with (RGB)"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 2)
+ public String otherParticleColour = "0:255:255:255:255";
+
+ @ConfigOption(
+ name = "Rod Line Colours",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 4)
+ public boolean rodAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Rod Line Colours",
+ desc = "Change the colour of your and other players' rod lines\n" +
+ "Also fixes the position of the rod line"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean enableRodColours = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Own Rod Colour",
+ desc = "Change the colour of your own rod lines\n" +
+ "You can set the opacity to '0' to HIDE"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 4)
+ public String ownRodColour = "0:255:0:0:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Other Rod Colour",
+ desc = "Change the colour of other players' rod lines\n" +
+ "You can set the opacity to '0' to HIDE"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 4)
+ public String otherRodColour = "0:255:0:0:0";
+
+ @ConfigOption(
+ name = "Fishing Timer",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 6)
+ public boolean fishingAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Display a Fishing Timer",
+ desc = "Display a timer above your bobber showing your current time"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 6)
+ public boolean fishingTimer = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Fishing timer color",
+ desc = "Color of the fishing timer"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 6)
+ public String fishingTimerColor = "0:255:0:0:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Fishing timer color (30s)",
+ desc = "Color of the fishing timer after 30 seconds or more have passed"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 6)
+ public String fishingTimerColor30SecPlus = "0:255:0:0:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Fishing timer ping (30s)",
+ desc = "Play a sound after 30 seconds passed"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 6)
+ public boolean fishingSound30Sec = true;
+
+ @ConfigOption(
+ name = "Trophy Reward",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 7)
+ public boolean trophyReward = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Trophy Reward Overlay",
+ desc = "Displays an overlay at Odger that shows information about your trophies"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 7)
+ public boolean trophyRewardOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Trophy Reward Tooltips",
+ desc = "Displays the exchange of your trophies as a tooltip in the Odger Inventory"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 7)
+ public boolean trophyRewardTooltips = true;
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ImprovedSBMenu.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ImprovedSBMenu.java
index 7d943501..8216c892 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ImprovedSBMenu.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ImprovedSBMenu.java
@@ -1,50 +1,69 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class ImprovedSBMenu {
- @Expose
- @ConfigOption(
- name = "Enable Improved SB Menus",
- desc = "Change the way that skyblock menus (eg. /sbmenu) look"
- )
- @ConfigEditorBoolean
- public boolean enableSbMenus = true;
-
- @Expose
- @ConfigOption(
- name = "Menu Background Style",
- desc = "Change the style of the background of skyblock menus"
- )
- @ConfigEditorDropdown(
- values = {
- "Dark 1", "Dark 2", "Transparent", "Light 1", "Light 2", "Light 3",
- "Unused 1", "Unused 2", "Unused 3", "Unused 4"
- }
- )
- public int backgroundStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Button Background Style",
- desc = "Change the style of the foreground elements in skyblock menus"
- )
- @ConfigEditorDropdown(
- values = {
- "Dark 1", "Dark 2", "Transparent", "Light 1", "Light 2", "Light 3",
- "Unused 1", "Unused 2", "Unused 3", "Unused 4"
- }
- )
- public int buttonStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Hide Empty Tooltips",
- desc = "Hide the tooltips of glass panes with no text"
- )
- @ConfigEditorBoolean
- public boolean hideEmptyPanes = true;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class ImprovedSBMenu {
+ @Expose
+ @ConfigOption(
+ name = "Enable Improved SB Menus",
+ desc = "Change the way that skyblock menus (eg. /sbmenu) look"
+ )
+ @ConfigEditorBoolean
+ public boolean enableSbMenus = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Menu Background Style",
+ desc = "Change the style of the background of skyblock menus"
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Dark 1", "Dark 2", "Transparent", "Light 1", "Light 2", "Light 3",
+ "Unused 1", "Unused 2", "Unused 3", "Unused 4"
+ }
+ )
+ public int backgroundStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Button Background Style",
+ desc = "Change the style of the foreground elements in skyblock menus"
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Dark 1", "Dark 2", "Transparent", "Light 1", "Light 2", "Light 3",
+ "Unused 1", "Unused 2", "Unused 3", "Unused 4"
+ }
+ )
+ public int buttonStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide Empty Tooltips",
+ desc = "Hide the tooltips of glass panes with no text"
+ )
+ @ConfigEditorBoolean
+ public boolean hideEmptyPanes = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/InventoryButtons.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/InventoryButtons.java
index 9c698b9c..685aeb98 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/InventoryButtons.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/InventoryButtons.java
@@ -1,35 +1,54 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class InventoryButtons {
- @Expose
- @ConfigOption(
- name = "Open Button Editor",
- desc = "Open button editor GUI (/neubuttons)"
- )
- @ConfigEditorButton(runnableId = 7, buttonText = "Open")
- public boolean openEditorButton = true;
-
- @Expose
- @ConfigOption(
- name = "Always Hide \"Crafting\" Text",
- desc = "Hide crafting text in inventory, even when no button is there"
- )
- @ConfigEditorBoolean
- public boolean hideCrafting = false;
-
- @Expose
- @ConfigOption(
- name = "Button Click Type",
- desc = "Change the click type needed to trigger commands"
- )
- @ConfigEditorDropdown(
- values = {"Mouse Down", "Mouse Up"}
- )
- public int clickType = 0;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class InventoryButtons {
+ @Expose
+ @ConfigOption(
+ name = "Open Button Editor",
+ desc = "Open button editor GUI (/neubuttons)"
+ )
+ @ConfigEditorButton(runnableId = 7, buttonText = "Open")
+ public boolean openEditorButton = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Always Hide \"Crafting\" Text",
+ desc = "Hide crafting text in inventory, even when no button is there"
+ )
+ @ConfigEditorBoolean
+ public boolean hideCrafting = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Button Click Type",
+ desc = "Change the click type needed to trigger commands"
+ )
+ @ConfigEditorDropdown(
+ values = {"Mouse Down", "Mouse Up"}
+ )
+ public int clickType = 0;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ItemOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ItemOverlays.java
index 7d08d038..5fde76a5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ItemOverlays.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ItemOverlays.java
@@ -1,356 +1,392 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class ItemOverlays {
- @ConfigOption(
- name = "Treecapitator Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean treecapAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Treecap Overlay",
- desc = "Show which blocks will be broken when using a Jungle Axe or Treecapitator"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean enableTreecapOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Show in Item durability",
- desc = "Show the cooldown of the Treecapitator in the item durability"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean enableCooldownInItemDurability = true;
-
- @Expose
- @ConfigOption(
- name = "Overlay Colour",
- desc = "Change the colour of the overlay"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 0)
- public String treecapOverlayColour = "00:50:64:224:208";
-
- @Expose
- @ConfigOption(
- name = "Enable Monkey Pet Check",
- desc = "Will check using the API to check what pet you're using\nto determine the cooldown based off of if you have a monkey pet."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean enableMonkeyCheck = true;
-
- @ConfigOption(
- name = "Builder's Wand Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- public boolean wandAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Wand Overlay",
- desc = "Show which blocks will be placed when using the Builder's Wand"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean enableWandOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Wand Block Count",
- desc = "Shows the total count of a block in your inventory"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean wandBlockCount = true;
-
- @Expose
- @ConfigOption(
- name = "Overlay Colour",
- desc = "Change the colour of the ghost block outline"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 1)
- public String wandOverlayColour = "00:50:64:224:208";
-
- @ConfigOption(
- name = "Block Zapper Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 6)
- public boolean zapperAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Zapper Overlay",
- desc = "Show which blocks will be destroyed when using the Block Zapper"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 6)
- public boolean enableZapperOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Overlay Colour",
- desc = "Change the colour of the ghost block outline"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 6)
- public String zapperOverlayColour = "0:102:171:5:0";
-
- @ConfigOption(
- name = "Smooth AOTE/AOTV/Hyp",
- desc = ""
- )
- @ConfigEditorAccordion(id = 2)
- public boolean aoteAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Smooth AOTE",
- desc = "Teleport smoothly to your destination when using AOTE or AOTV"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean enableSmoothAOTE = true;
-
- @Expose
- @ConfigOption(
- name = "Enable Smooth Hyperion",
- desc = "Teleport smoothly to your destination when using Hyperion"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean enableSmoothHyperion = true;
-
- @Expose
- @ConfigOption(
- name = "Smooth TP Time",
- desc = "Change the amount of time (milliseconds) taken to teleport"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 500,
- minStep = 25
- )
- @ConfigAccordionId(id = 2)
- public int smoothTpMillis = 125;
-
- @Expose
- @ConfigOption(
- name = "Smooth TP Time (Etherwarp)",
- desc = "Teleport smoothly to your destination when using AOTV Etherwarp"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 500,
- minStep = 25
- )
- @ConfigAccordionId(id = 2)
- public int smoothTpMillisEtherwarp = 50;
-
- @Expose
- @ConfigOption(
- name = "Disable Hyperion Particles",
- desc = "Remove the explosion effect when using a hyperion"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean disableHyperionParticles = true;
-
- @ConfigOption(
- name = "Etherwarp",
- desc = ""
- )
- @ConfigEditorAccordion(id = 7)
- public boolean etherwarpAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Etherwarp Zoom",
- desc = "Zoom in on targeted blocks with etherwarp, making it easier to adjust at a distance"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 7)
- public boolean etherwarpZoom = true;
-
- @Expose
- @ConfigOption(
- name = "Enable etherwarp helper overlay",
- desc = "Display an overlay which tells you if the etherwarp will fail."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 7)
- public boolean enableEtherwarpHelperOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Enable etherwarp block overlay",
- desc = "Display an overlay that tells you what block you will TP to."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 7)
- public boolean enableEtherwarpBlockOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Highlight Colour",
- desc = "Change the colour of the etherwarp target block outline"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 7)
- public String etherwarpHighlightColour = "00:70:156:8:96";
-
- @ConfigOption(
- name = "Bonemerang Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 3)
- public boolean bonemerangAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Bonemerang Overlay",
- desc = "Shows info about the bonemerang while holding it."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean enableBonemerangOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Highlight Targeted Entities",
- desc = "Highlight entities that will be hit by your bonemerang"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean highlightTargeted = true;
-
- @Expose
- @ConfigOption(
- name = "Bonemerang Overlay Position",
- desc = "The position of the Bonemerang overlay."
- )
- @ConfigEditorButton(
- runnableId = 9,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 3)
- public Position bonemerangPosition = new Position(-1, -1);
-
- @Expose
- @ConfigOption(
- name = "Bonemerang Overlay Text",
- desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
- "\u00a7rHold a Bonemerang to display the overlay"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7cBonemerang will break!",
- "\u00a77Targets: \u00a76\u00a7l10"
- }
- )
- @ConfigAccordionId(id = 3)
- public List<Integer> bonemerangOverlayText = new ArrayList<>(Arrays.asList(0, 1));
-
- @Expose
- @ConfigOption(
- name = "Bonemerang Overlay Style",
- desc = "Change the style of the Bonemerang overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow Only", "Full Shadow"}
- )
- @ConfigAccordionId(id = 3)
- public int bonemerangOverlayStyle = 0;
- @Expose
- @ConfigOption(
- name = "Fast update",
- desc = "Updates the bonemerang overlay faster.\n" +
- "Might cause some lag."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean bonemerangFastUpdate = false;
-
- @ConfigOption(
- name = "Minion Crystal Radius Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 5)
- public boolean crystalAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Crystal Overlay",
- desc = "Show a block overlay for the effective radius of minion crystals (farming, mining, etc)."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 5)
- public boolean enableCrystalOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Always Show Crystal Overlay",
- desc = "Show the crystal overlay, even when a minion crystal is not being held."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 5)
- public boolean alwaysShowCrystal = false;
-
- @ConfigOption(
- name = "Farming Overlays",
- desc = ""
- )
- @ConfigEditorAccordion(id = 6)
- public boolean farmingAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Prismapump Overlay",
- desc = "Show a block overlay for the effected blocks of prismapump's ability."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 6)
- public boolean enablePrismapumpOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Enable Hoe Of Tilling Overlay",
- desc = "Show a block overlay for the effected blocks of the hoe of tilling's ability."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 6)
- public boolean enableHoeOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Enable Dirt Wand Overlay",
- desc = "Show a block overlay for the effected blocks of dirt wand's ability."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 6)
- public boolean enableDirtWandOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Pickaxe Ability Cooldown",
- desc = "Show the cooldown duration off the pickaxe ability as the durability."
- )
- @ConfigEditorBoolean
- public boolean pickaxeAbility = true;
-
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.Position;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ItemOverlays {
+ @ConfigOption(
+ name = "Treecapitator Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean treecapAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Treecap Overlay",
+ desc = "Show which blocks will be broken when using a Jungle Axe or Treecapitator"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableTreecapOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show in Item durability",
+ desc = "Show the cooldown of the Treecapitator in the item durability"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableCooldownInItemDurability = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Overlay Colour",
+ desc = "Change the colour of the overlay"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 0)
+ public String treecapOverlayColour = "00:50:64:224:208";
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Monkey Pet Check",
+ desc = "Will check using the API to check what pet you're using\nto determine the cooldown based off of if you have a monkey pet."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableMonkeyCheck = true;
+
+ @ConfigOption(
+ name = "Builder's Wand Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean wandAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Wand Overlay",
+ desc = "Show which blocks will be placed when using the Builder's Wand"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean enableWandOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Wand Block Count",
+ desc = "Shows the total count of a block in your inventory"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean wandBlockCount = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Overlay Colour",
+ desc = "Change the colour of the ghost block outline"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 1)
+ public String wandOverlayColour = "00:50:64:224:208";
+
+ @ConfigOption(
+ name = "Block Zapper Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 6)
+ public boolean zapperAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Zapper Overlay",
+ desc = "Show which blocks will be destroyed when using the Block Zapper"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 6)
+ public boolean enableZapperOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Overlay Colour",
+ desc = "Change the colour of the ghost block outline"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 6)
+ public String zapperOverlayColour = "0:102:171:5:0";
+
+ @ConfigOption(
+ name = "Smooth AOTE/AOTV/Hyp",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 2)
+ public boolean aoteAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Smooth AOTE",
+ desc = "Teleport smoothly to your destination when using AOTE or AOTV"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean enableSmoothAOTE = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Smooth Hyperion",
+ desc = "Teleport smoothly to your destination when using Hyperion"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean enableSmoothHyperion = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Smooth TP Time",
+ desc = "Change the amount of time (milliseconds) taken to teleport"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 500,
+ minStep = 25
+ )
+ @ConfigAccordionId(id = 2)
+ public int smoothTpMillis = 125;
+
+ @Expose
+ @ConfigOption(
+ name = "Smooth TP Time (Etherwarp)",
+ desc = "Teleport smoothly to your destination when using AOTV Etherwarp"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 500,
+ minStep = 25
+ )
+ @ConfigAccordionId(id = 2)
+ public int smoothTpMillisEtherwarp = 50;
+
+ @Expose
+ @ConfigOption(
+ name = "Disable Hyperion Particles",
+ desc = "Remove the explosion effect when using a hyperion"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean disableHyperionParticles = true;
+
+ @ConfigOption(
+ name = "Etherwarp",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 7)
+ public boolean etherwarpAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Etherwarp Zoom",
+ desc = "Zoom in on targeted blocks with etherwarp, making it easier to adjust at a distance"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 7)
+ public boolean etherwarpZoom = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable etherwarp helper overlay",
+ desc = "Display an overlay which tells you if the etherwarp will fail."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 7)
+ public boolean enableEtherwarpHelperOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable etherwarp block overlay",
+ desc = "Display an overlay that tells you what block you will TP to."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 7)
+ public boolean enableEtherwarpBlockOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Disable overlay when fail",
+ desc = "Don't display the etherwarp block overlay when you can't TP to the block"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 7)
+ public boolean disableOverlayWhenFailed = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Highlight Colour",
+ desc = "Change the colour of the etherwarp target block outline"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 7)
+ public String etherwarpHighlightColour = "00:70:156:8:96";
+
+ @ConfigOption(
+ name = "Bonemerang Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 3)
+ public boolean bonemerangAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Bonemerang Overlay",
+ desc = "Shows info about the bonemerang while holding it."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean enableBonemerangOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Highlight Targeted Entities",
+ desc = "Highlight entities that will be hit by your bonemerang"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean highlightTargeted = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Bonemerang Overlay Position",
+ desc = "Change the position of the Bonemerang overlay."
+ )
+ @ConfigEditorButton(
+ runnableId = 9,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 3)
+ public Position bonemerangPosition = new Position(-1, -1);
+
+ @Expose
+ @ConfigOption(
+ name = "Bonemerang Overlay Text",
+ desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
+ "\u00a7rHold a Bonemerang to display the overlay"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7cBonemerang will break!",
+ "\u00a77Targets: \u00a76\u00a7l10"
+ }
+ )
+ @ConfigAccordionId(id = 3)
+ public List<Integer> bonemerangOverlayText = new ArrayList<>(Arrays.asList(0, 1));
+
+ @Expose
+ @ConfigOption(
+ name = "Bonemerang Overlay Style",
+ desc = "Change the style of the Bonemerang overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow Only", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 3)
+ public int bonemerangOverlayStyle = 0;
+ @Expose
+ @ConfigOption(
+ name = "Fast update",
+ desc = "Updates the bonemerang overlay faster.\n" +
+ "Might cause some lag."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean bonemerangFastUpdate = false;
+
+ @ConfigOption(
+ name = "Minion Crystal Radius Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 5)
+ public boolean crystalAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Crystal Overlay",
+ desc = "Show a block overlay for the effective radius of minion crystals (farming, mining, etc)."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 5)
+ public boolean enableCrystalOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Always Show Crystal Overlay",
+ desc = "Show the crystal overlay, even when a minion crystal is not being held."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 5)
+ public boolean alwaysShowCrystal = false;
+
+ @ConfigOption(
+ name = "Farming Overlays",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 6)
+ public boolean farmingAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Prismapump Overlay",
+ desc = "Show a block overlay for the effected blocks of prismapump's ability."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 6)
+ public boolean enablePrismapumpOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Hoe Of Tilling Overlay",
+ desc = "Show a block overlay for the effected blocks of the hoe of tilling's ability."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 6)
+ public boolean enableHoeOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Dirt Wand Overlay",
+ desc = "Show a block overlay for the effected blocks of dirt wand's ability."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 6)
+ public boolean enableDirtWandOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Pickaxe Ability Cooldown",
+ desc = "Show the cooldown duration of the pickaxe ability as the durability."
+ )
+ @ConfigEditorBoolean
+ public boolean pickaxeAbility = true;
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java
index e1c11f99..72a45930 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Itemlist.java
@@ -1,110 +1,152 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-public class Itemlist {
- @Expose
- @ConfigOption(
- name = "Show Vanilla Items",
- desc = "Vanilla items are included in the item list"
- )
- @ConfigEditorBoolean
- public boolean showVanillaItems = true;
-
- @Expose
- @ConfigOption(
- name = "Open Itemlist Arrow",
- desc = "Creates an arrow on the right-side to open the item list when hovered"
- )
- @ConfigEditorBoolean
- public boolean tabOpen = true;
-
- @Expose
- @ConfigOption(
- name = "Keep Open",
- desc = "Keeps the Itemlist open after the inventory is closed"
- )
- @ConfigEditorBoolean
- public boolean keepopen = false;
-
- @Expose
- @ConfigOption(
- name = "Item Style",
- desc = "Sets the style of the background behind items"
- )
- @ConfigEditorDropdown(
- values = {"Round", "Square"}
- )
- public int itemStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Pane Gui Scale",
- desc = "Change the gui scale of the Itemlist"
- )
- @ConfigEditorDropdown(
- values = {"Default", "Small", "Medium", "Large", "Auto"}
- )
- public int paneGuiScale = 0;
-
- @Expose
- @ConfigOption(
- name = "Background Blur",
- desc = "Change the blur amount behind the Itemlist. 0 = off"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 20,
- minStep = 1
- )
- public int bgBlurFactor = 5;
-
- @Expose
- @ConfigOption(
- name = "Pane Width Multiplier",
- desc = "Change the width of the Itemlist"
- )
- @ConfigEditorSlider(
- minValue = 0.5f,
- maxValue = 1.5f,
- minStep = 0.1f
- )
- public float paneWidthMult = 1.0f;
-
- @Expose
- @ConfigOption(
- name = "Pane Padding",
- desc = "Change the padding around the Itemlist"
- )
- @ConfigEditorSlider(
- minValue = 0f,
- maxValue = 20f,
- minStep = 1f
- )
- public int panePadding = 10;
-
- @Expose
- @ConfigOption(
- name = "Foreground Colour",
- desc = "Change the colour of foreground elements in the Itemlist"
- )
- @ConfigEditorColour
- public String foregroundColour = "00:255:100:100:100";
-
- @Expose
- @ConfigOption(
- name = "Favourite Colour",
- desc = "Change the colour of favourited elements in the Itemlist"
- )
- @ConfigEditorColour
- public String favouriteColour = "00:255:200:150:50";
-
- @Expose
- @ConfigOption(
- name = "Pane Background Colour",
- desc = "Change the colour of the Itemlist background"
- )
- @ConfigEditorColour
- public String backgroundColour = "15:6:0:0:255";
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class Itemlist {
+ @Expose
+ @ConfigOption(
+ name = "Show Vanilla Items",
+ desc = "Vanilla items are included in the item list"
+ )
+ @ConfigEditorBoolean
+ public boolean showVanillaItems = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Open Itemlist Arrow",
+ desc = "Creates an arrow on the right-side to open the item list when hovered"
+ )
+ @ConfigEditorBoolean
+ public boolean tabOpen = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Keep Open",
+ desc = "Keeps the Itemlist open after the inventory is closed"
+ )
+ @ConfigEditorBoolean
+ public boolean keepopen = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Open when searching",
+ desc = "Open the Itemlist when in container search mode by double clicking the search bar"
+ )
+ @ConfigEditorBoolean
+ public boolean openWhenSearching = true;
+
+
+ @Expose
+ @ConfigOption(
+ name = "Item Style",
+ desc = "Sets the style of the background behind items"
+ )
+ @ConfigEditorDropdown(
+ values = {"Round", "Square"}
+ )
+ public int itemStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Pane Gui Scale",
+ desc = "Change the gui scale of the Itemlist"
+ )
+ @ConfigEditorDropdown(
+ values = {"Default", "Small", "Medium", "Large", "Auto"}
+ )
+ public int paneGuiScale = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Background Blur",
+ desc = "Change the blur amount behind the Itemlist. 0 = off"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 20,
+ minStep = 1
+ )
+ public int bgBlurFactor = 5;
+
+ @Expose
+ @ConfigOption(
+ name = "Pane Width Multiplier",
+ desc = "Change the width of the Itemlist"
+ )
+ @ConfigEditorSlider(
+ minValue = 0.5f,
+ maxValue = 1.5f,
+ minStep = 0.1f
+ )
+ public float paneWidthMult = 1.0f;
+
+ @Expose
+ @ConfigOption(
+ name = "Pane Padding",
+ desc = "Change the padding around the Itemlist"
+ )
+ @ConfigEditorSlider(
+ minValue = 0f,
+ maxValue = 20f,
+ minStep = 1f
+ )
+ public int panePadding = 10;
+
+ @Expose
+ @ConfigOption(
+ name = "Foreground Colour",
+ desc = "Change the colour of foreground elements in the Itemlist"
+ )
+ @ConfigEditorColour
+ public String foregroundColour = "00:255:100:100:100";
+
+ @Expose
+ @ConfigOption(
+ name = "Favourite Colour",
+ desc = "Change the colour of favourited elements in the Itemlist"
+ )
+ @ConfigEditorColour
+ public String favouriteColour = "00:255:200:150:50";
+
+ @Expose
+ @ConfigOption(
+ name = "Pane Background Colour",
+ desc = "Change the colour of the Itemlist background"
+ )
+ @ConfigEditorColour
+ public String backgroundColour = "15:6:0:0:255";
+
+ @Expose
+ @ConfigOption(
+ name = "Always show Monsters",
+ desc = "Always show Monster Items in the item list"
+ )
+ @ConfigEditorBoolean(
+ runnableId = 21
+ )
+ public boolean alwaysShowMonsters = false;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/LocationEdit.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/LocationEdit.java
index 385a3cc1..42316592 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/LocationEdit.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/LocationEdit.java
@@ -1,8 +1,30 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
public class LocationEdit {
@Expose
@@ -20,7 +42,7 @@ public class LocationEdit {
@Expose
@ConfigOption(
name = "Edit Pet Info Position",
- desc = "The position of the pet info overlay."
+ desc = "Change the position of the pet info overlay"
)
@ConfigEditorButton(
runnableId = 4,
@@ -37,13 +59,12 @@ public class LocationEdit {
runnableId = 5,
buttonText = "Edit"
)
- @ConfigAccordionId(id = 0)
public Position todoPosition = new Position(100, 0);
@Expose
@ConfigOption(
name = "Edit Bonemerang Overlay Position",
- desc = "The position of the Bonemerang overlay."
+ desc = "Change the position of the Bonemerang overlay"
)
@ConfigEditorButton(
runnableId = 9,
@@ -72,7 +93,7 @@ public class LocationEdit {
@Expose
@ConfigOption(
name = "Edit Toolbar Positions",
- desc = "Edit the position of the QuickCommands / Search Bar"
+ desc = "Change the position of the QuickCommands / Search Bar"
)
@ConfigAccordionId(id = 1)
@ConfigEditorButton(runnableId = 6, buttonText = "Edit")
@@ -109,7 +130,7 @@ public class LocationEdit {
@Expose
@ConfigOption(
name = "Edit Crystal Overlay Position",
- desc = "Change the position of the Crystal Hollows Overlay."
+ desc = "Change the position of the Crystal Hollows Overlay"
)
@ConfigEditorButton(
runnableId = 10,
@@ -121,7 +142,7 @@ public class LocationEdit {
@Expose
@ConfigOption(
name = "Edit Fuel Bar Position",
- desc = "Set the position of the drill fuel bar"
+ desc = "Change the position of the drill fuel bar"
)
@ConfigEditorButton(
runnableId = 2,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java
index 6ebd7f42..727ad329 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Mining.java
@@ -1,710 +1,782 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class Mining {
- @ConfigOption(
- name = "Waypoints",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean waypointsAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Mines Waypoints",
- desc = "Show waypoints in the Dwarven mines to the various locations\n" +
- "Use \"Commissions Only\" to only show active commission locations"
- )
- @ConfigEditorDropdown(
- values = {"Hide", "Commissions Only", "Always"},
- initialIndex = 1
- )
- @ConfigAccordionId(id = 0)
- public int locWaypoints = 1;
-
- @Expose
- @ConfigOption(
- name = "Hide waypoints when at Location",
- desc = "Hides the Commission Waypoints if you are already at the location of the waypoint.\n" +
- "Only active if Waypoints are set to \"Commissions Only\""
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean hideWaypointIfAtLocation = true;
-
- @Expose
- @ConfigOption(
- name = "Emissary Waypoints",
- desc = "Show waypoints in the Dwarven mines to emissaries\n" +
- "Use \"Commission End\" to only show after finishing commissions"
- )
- @ConfigEditorDropdown(
- values = {"Hide", "Commission End", "Always"},
- initialIndex = 1
- )
- @ConfigAccordionId(id = 0)
- public int emissaryWaypoints = 1;
-
- @ConfigOption(
- name = "Drill Fuel Bar",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- public boolean drillAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Drill Fuel Bar",
- desc = "Show a fancy drill fuel bar when holding a drill in mining areas"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean drillFuelBar = true;
-
- @Expose
- @ConfigOption(
- name = "Fuel Bar Width",
- desc = "Change the width of the drill fuel bar"
- )
- @ConfigEditorSlider(
- minValue = 50,
- maxValue = 400,
- minStep = 10
- )
- @ConfigAccordionId(id = 1)
- public int drillFuelBarWidth = 200;
-
- @Expose
- @ConfigOption(
- name = "Edit Fuel Bar Position",
- desc = "Set the position of the drill fuel bar"
- )
- @ConfigEditorButton(
- runnableId = 2,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 1)
- public Position drillFuelBarPosition = new Position(0, -100, true, false);
-
- @ConfigOption(
- name = "Dwarven Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 2)
- public boolean overlayAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Dwarven Overlay",
- desc = "Show an Overlay with useful information on the screen while in Dwarven Mines"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean dwarvenOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Dwarven Text",
- desc = "\u00a7eDrag text to change the appearance of the Overlay\n" +
- "\u00a7rGo to the Dwarven Mines to show this Overlay with useful information"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a73Goblin Slayer: \u00a7626.5%\n\u00a73Lucky Raffle: \u00a7c0.0%",
- "\u00a73Mithril Powder: \u00a726,243",
- "\u00a73Gemstone Powder: \u00a7d6,243",
- "\u00a73Forge 1) \u00a79Diamonite\u00a77: \u00a7aReady!",
- "\u00a73Pickaxe CD: \u00a7a78s"
- }
- )
- @ConfigAccordionId(id = 2)
- public List<Integer> dwarvenText2 = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
-
- @Expose
- @ConfigOption(
- name = "Edit Dwarven Overlay Position",
- desc = "Change the position of the Dwarven Mines information Overlay (commisions, powder & forge statuses)"
- )
- @ConfigEditorButton(
- runnableId = 1,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 2)
- public Position overlayPosition = new Position(10, 100);
-
- @Expose
- @ConfigOption(
- name = "Overlay Style",
- desc = "Change the style of the Dwarven Mines information Overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
- )
- @ConfigAccordionId(id = 2)
- public int overlayStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Show Icons",
- desc = "Show Icons representing the part of the overlay."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 2)
- public boolean dwarvenOverlayIcons = true;
-
- @Expose
- @ConfigOption(
- name = "Forge Display",
- desc = "Change what gets shown in the Forge Display"
- )
- @ConfigEditorDropdown(
- values = {"Only Done", "Only Working", "Everything Except Locked", "Everything"}
- )
- @ConfigAccordionId(id = 2)
- public int forgeDisplay = 1;
-
- @Expose
- @ConfigOption(
- name = "Forge Location",
- desc = "Change when the forge display gets shown"
- )
- @ConfigEditorDropdown(
- values = {"Dwarven Mines+Crystal Hollows", "Everywhere except dungeons", "Everywhere"}
- )
- @ConfigAccordionId(id = 2)
- public int forgeDisplayEnabledLocations = 0;
-
- @ConfigOption(
- name = "Metal Detector Solver",
- desc = ""
- )
- @ConfigEditorAccordion(id = 3)
- public boolean metalDetectorSolverAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Waypoints",
- desc =
- "Enabled the metal detector solver for Mines of Divan, to use this stand still to calculate possible blocks and then if required stand" +
- " still on another block."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean metalDetectorEnabled = true;
-
- @Expose
- @ConfigOption(
- name = "Show Possible Blocks",
- desc = "Show waypoints on possible locations when NEU isn't sure about what block the treasure is."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean metalDetectorShowPossible = false;
-
- @ConfigOption(
- name = "Crystal Hollows Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 4)
- public boolean crystalHollowOverlayAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Crystal Overlay",
- desc = "Enables the Crystal Hollows Overlay."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 4)
- public boolean crystalHollowOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Edit Crystal Overlay Position",
- desc = "Change the position of the Crystal Hollows Overlay."
- )
- @ConfigEditorButton(
- runnableId = 10,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 4)
- public Position crystalHollowOverlayPosition = new Position(200, 0);
-
- @Expose
- @ConfigOption(
- name = "Options",
- desc = "Drag text to change the appearance of the overlay!\n" +
- "Click add to add extra things!"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a73Amber Crystal: \u00a7aPlaced\n" +
- "\u00a73Sapphire Crystal: \u00a7eCollected\n" +
- "\u00a73Jade Crystal: \u00a7eMissing\n" +
- "\u00a73Amethyst Crystal: \u00a7cMissing\n" +
- "\u00a73Topaz Crystal: \u00a7cMissing\n",
- "\u00a73Crystals: \u00a7a4/5",
- "\u00a73Crystals: \u00a7a80%",
- "\u00a73Electron Transmitter: \u00a7aDone\n" +
- "\u00a73Robotron Reflector: \u00a7eIn Storage\n" +
- "\u00a73Superlite Motor: \u00a7eIn Inventory\n" +
- "\u00a73Synthetic Hearth: \u00a7cMissing\n" +
- "\u00a73Control Switch: \u00a7cMissing\n" +
- "\u00a73FTX 3070: \u00a7cMissing",
- "\u00a73Electron Transmitter: \u00a7a3\n" +
- "\u00a73Robotron Reflector: \u00a7e2\n" +
- "\u00a73Superlite Motor: \u00a7e1\n" +
- "\u00a73Synthetic Hearth: \u00a7c0\n" +
- "\u00a73Control Switch: \u00a7c0\n" +
- "\u00a73FTX 3070: \u00a7c0",
- "\u00a73Automaton parts: \u00a7a5/6",
- "\u00a73Automaton parts: \u00a7a83%",
- "\u00a73Scavenged Lapis Sword: \u00a7aDone\n" +
- "\u00a73Scavenged Golden Hammer: \u00a7eIn Storage\n" +
- "\u00a73Scavenged Diamond Axe: \u00a7eIn Inventory\n" +
- "\u00a73Scavenged Emerald Hammer: \u00a7cMissing\n",
- "\u00a73Scavenged Lapis Sword: \u00a7a3\n" +
- "\u00a73Scavenged Golden Hammer: \u00a7e2\n" +
- "\u00a73Scavenged Diamond Axe: \u00a7e1\n" +
- "\u00a73Scavenged Emerald Hammer: \u00a7c0\n",
- "\u00a73Mines of Divan parts: \u00a7a3/4",
- "\u00a73Mines of Divan parts: \u00a7a75%"
- }
- )
- @ConfigAccordionId(id = 4)
- public List<Integer> crystalHollowText = new ArrayList<>(Arrays.asList(0, 3, 7));
-
- @Expose
- @ConfigOption(
- name = "Style",
- desc = "Change the style of the Crystal Hollows Overlay."
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
- )
- @ConfigAccordionId(id = 4)
- public int crystalHollowOverlayStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Show Icons",
- desc = "Show icons in the Overlay that represent the part."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 4)
- public boolean crystalHollowIcons = true;
-
- @Expose
- @ConfigOption(
- name = "Hide Done",
- desc = "Don't show parts you've given to the NPC."
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 4)
- public boolean crystalHollowHideDone = false;
-
- @ConfigOption(
- name = "Locations",
- desc = ""
- )
- @ConfigEditorAccordion(id = 5)
- @ConfigAccordionId(id = 4)
- public boolean crystalHollowLocationAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Show Automaton",
- desc = "Change where to show Automaton parts."
- )
- @ConfigEditorDropdown(
- values = {"Crystal Hollows", "Precursor Remnants", "Lost Precursor City"}
- )
- @ConfigAccordionId(id = 5)
- public int crystalHollowAutomatonLocation = 2;
-
- @Expose
- @ConfigOption(
- name = "Show Divan",
- desc = "Change where to show Mines of Divan parts."
- )
- @ConfigEditorDropdown(
- values = {"Crystal Hollows", "Mithril Deposits", "Mines of Divan"}
- )
- @ConfigAccordionId(id = 5)
- public int crystalHollowDivanLocation = 2;
-
- @Expose
- @ConfigOption(
- name = "Show Crystal",
- desc = "Change where to show Collected Crystals."
- )
- @ConfigEditorDropdown(
- values = {"Crystal Hollows", "When No Other Overlays"}
- )
- @ConfigAccordionId(id = 5)
- public int crystalHollowCrystalLocation = 1;
-
- @ConfigOption(
- name = "Colours",
- desc = ""
- )
- @ConfigEditorAccordion(id = 6)
- @ConfigAccordionId(id = 4)
- public boolean crystalHollowColourAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Main Color",
- desc = "Change the main color of the overlay."
-
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowPartColor = 3;
-
- @Expose
- @ConfigOption(
- name = "Done Color",
- desc = "Change the colour when the part is given to the NPC."
-
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
-
- @ConfigAccordionId(id = 6)
- public int crystalHollowDoneColor = 10;
-
- @Expose
- @ConfigOption(
- name = "In Inventory Color",
- desc = "Change the colour when the part is in the inventory."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowInventoryColor = 14;
-
- @Expose
- @ConfigOption(
- name = "In Storage Color",
- desc = "Change the colour when the part is in the storage."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowStorageColor = 14;
-
- @Expose
- @ConfigOption(
- name = "Missing Color",
- desc = "Change the colour when the part is missing."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowMissingColor = 12;
-
- @Expose
- @ConfigOption(
- name = "Placed Color",
- desc = "Change the colour when the crystal is placed."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowPlacedColor = 10;
-
- @Expose
- @ConfigOption(
- name = "Collected Color",
- desc = "Change the colour when the crystal is collected"
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowCollectedColor = 14;
-
- @Expose
- @ConfigOption(
- name = "All Color",
- desc = "Change the colour when you have 2/3-all of the parts collected in the count overlay."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowAllColor = 10;
-
- @Expose
- @ConfigOption(
- name = "1/3 Color",
- desc = "Change the colour when you have 1/3-2/3 of the parts collected in the count overlay."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowMiddleColor = 14;
-
- @Expose
- @ConfigOption(
- name = "0 Color",
- desc = "Change the colour when you have 0-1/3 of the parts collected in the count overlay."
- )
- @ConfigEditorDropdown(
- values = {
- "Black",
- "Dark Blue",
- "Dark Green",
- "Dark Aqua",
- "Dark Red",
- "Dark Purple",
- "Gold",
- "Gray",
- "Dark Gray",
- "Blue",
- "Green",
- "Aqua",
- "Red",
- "Light Purple",
- "Yellow",
- "White"
- }
- )
- @ConfigAccordionId(id = 6)
- public int crystalHollowNoneColor = 12;
-
- @Expose
- @ConfigOption(
- name = "Puzzler Solver",
- desc = "Show the correct block to mine for the puzzler puzzle in Dwarven Mines"
- )
- @ConfigEditorBoolean
- public boolean puzzlerSolver = true;
-
- @Expose
- @ConfigOption(
- name = "Titanium Alert",
- desc = "Show an alert whenever titanium appears nearby"
- )
- @ConfigEditorBoolean
- public boolean titaniumAlert = true;
-
- @Expose
- @ConfigOption(
- name = "Titanium must touch air",
- desc = "Only show an alert if the Titanium touches air. (kinda sus)"
- )
- @ConfigEditorBoolean
- public boolean titaniumAlertMustBeVisible = false;
-
- @ConfigOption(
- name = "Custom Textures",
- desc = ""
- )
- @ConfigEditorAccordion(id = 7)
- public boolean texturesAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Dwarven Mines Textures",
- desc = "Allows texture packs to retexture blocks in the Dwarven Mines. If you don't have a texture pack that does this, you should leave this off"
- )
- @ConfigAccordionId(id = 7)
- @ConfigEditorBoolean
- public boolean dwarvenTextures = false;
- @Expose
- @ConfigOption(
- name = "Crystal Hollows Textures",
- desc = "Allows texture packs to retexture blocks in the Crystal Hollows. If you don't have a texture pack that does this, you should leave this off"
- )
- @ConfigAccordionId(id = 7)
- @ConfigEditorBoolean
- public boolean crystalHollowTextures = false;
-
- @Expose
- @ConfigOption(
- name = "Replace Gemstone sounds",
- desc = "Replace the break sounds of crystals in the Crystal Hollows. Requires a texture pack with this feature"
- )
- @ConfigAccordionId(id = 7)
- @ConfigEditorBoolean
- public boolean gemstoneSounds = false;
-
- @Expose
- @ConfigOption(
- name = "Replace Mithril sounds",
- desc = "Replace the break sounds of mithril and titanium in the Dwarven mines. Requires a texture pack with this feature"
- )
- @ConfigAccordionId(id = 7)
- @ConfigEditorBoolean
- public boolean mithrilSounds = false;
-
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.Position;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Mining {
+ @ConfigOption(
+ name = "Waypoints",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean waypointsAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Mines Waypoints",
+ desc = "Show waypoints in the Dwarven mines to the various locations\n" +
+ "Use \"Commissions Only\" to only show active commission locations"
+ )
+ @ConfigEditorDropdown(
+ values = {"Hide", "Commissions Only", "Always"},
+ initialIndex = 1
+ )
+ @ConfigAccordionId(id = 0)
+ public int locWaypoints = 1;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide waypoints when at Location",
+ desc = "Hides the Commission Waypoints if you are already at the location of the waypoint.\n" +
+ "Only active if Waypoints are set to \"Commissions Only\""
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean hideWaypointIfAtLocation = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Emissary Waypoints",
+ desc = "Show waypoints in the Dwarven mines to emissaries\n" +
+ "Use \"Commission End\" to only show after finishing commissions"
+ )
+ @ConfigEditorDropdown(
+ values = {"Hide", "Commission End", "Always"},
+ initialIndex = 1
+ )
+ @ConfigAccordionId(id = 0)
+ public int emissaryWaypoints = 1;
+
+ @ConfigOption(
+ name = "Drill Fuel Bar",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean drillAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Drill Fuel Bar",
+ desc = "Show a fancy drill fuel bar when holding a drill in mining areas"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean drillFuelBar = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Fuel Bar Width",
+ desc = "Change the width of the drill fuel bar"
+ )
+ @ConfigEditorSlider(
+ minValue = 50,
+ maxValue = 400,
+ minStep = 10
+ )
+ @ConfigAccordionId(id = 1)
+ public int drillFuelBarWidth = 200;
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Fuel Bar Position",
+ desc = "Change the position of the drill fuel bar"
+ )
+ @ConfigEditorButton(
+ runnableId = 2,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 1)
+ public Position drillFuelBarPosition = new Position(0, -100, true, false);
+
+ @ConfigOption(
+ name = "Dwarven Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 2)
+ public boolean overlayAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Dwarven Overlay",
+ desc = "Show an Overlay with useful information on the screen while in Dwarven Mines"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean dwarvenOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Dwarven Text",
+ desc = "\u00a7eDrag text to change the appearance of the Overlay\n" +
+ "\u00a7rGo to the Dwarven Mines to show this Overlay with useful information"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a73Goblin Slayer: \u00a7626.5%\n\u00a73Lucky Raffle: \u00a7c0.0%",
+ "\u00a73Mithril Powder: \u00a726,243",
+ "\u00a73Gemstone Powder: \u00a7d6,243",
+ "\u00a73Forge 1) \u00a79Diamonite\u00a77: \u00a7aReady!",
+ "\u00a73Pickaxe CD: \u00a7a78s"
+ }
+ )
+ @ConfigAccordionId(id = 2)
+ public List<Integer> dwarvenText2 = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Dwarven Overlay Position",
+ desc = "Change the position of the Dwarven Mines information Overlay (commisions, powder & forge statuses)"
+ )
+ @ConfigEditorButton(
+ runnableId = 1,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 2)
+ public Position overlayPosition = new Position(10, 100);
+
+ @Expose
+ @ConfigOption(
+ name = "Overlay Style",
+ desc = "Change the style of the Dwarven Mines information Overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 2)
+ public int overlayStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Icons",
+ desc = "Show Icons representing the part of the overlay."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean dwarvenOverlayIcons = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Forge Display",
+ desc = "Change what gets shown in the Forge Display"
+ )
+ @ConfigEditorDropdown(
+ values = {"Only Done", "Only Working", "Everything Except Locked", "Everything"}
+ )
+ @ConfigAccordionId(id = 2)
+ public int forgeDisplay = 1;
+
+ @Expose
+ @ConfigOption(
+ name = "Forge Location",
+ desc = "Change when the forge display gets shown"
+ )
+ @ConfigEditorDropdown(
+ values = {"Dwarven Mines+Crystal Hollows", "Everywhere except dungeons", "Everywhere"}
+ )
+ @ConfigAccordionId(id = 2)
+ public int forgeDisplayEnabledLocations = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Forge Tab",
+ desc = "Only show the forge display when tab list is open\n" +
+ "\u00A7cThis only works outside of Dwarven Caves!"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 2)
+ public boolean forgeDisplayOnlyShowTab = false;
+
+ @ConfigOption(
+ name = "Metal Detector Solver",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 3)
+ public boolean metalDetectorSolverAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Waypoints",
+ desc =
+ "Enabled the metal detector solver for Mines of Divan, to use this stand still to calculate possible blocks and then if required stand" +
+ " still on another block."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean metalDetectorEnabled = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Possible Blocks",
+ desc = "Show waypoints on possible locations when NEU isn't sure about what block the treasure is."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean metalDetectorShowPossible = false;
+
+ @ConfigOption(
+ name = "Crystal Hollows Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 4)
+ public boolean crystalHollowOverlayAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Crystal Overlay",
+ desc = "Enables the Crystal Hollows Overlay."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean crystalHollowOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Crystal Overlay Position",
+ desc = "Change the position of the Crystal Hollows Overlay."
+ )
+ @ConfigEditorButton(
+ runnableId = 10,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 4)
+ public Position crystalHollowOverlayPosition = new Position(200, 0);
+
+ @Expose
+ @ConfigOption(
+ name = "Options",
+ desc = "Drag text to change the appearance of the overlay!\n" +
+ "Click add to add extra things!"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a73Amber Crystal: \u00a7aPlaced\n" +
+ "\u00a73Sapphire Crystal: \u00a7eCollected\n" +
+ "\u00a73Jade Crystal: \u00a7eMissing\n" +
+ "\u00a73Amethyst Crystal: \u00a7cMissing\n" +
+ "\u00a73Topaz Crystal: \u00a7cMissing\n",
+ "\u00a73Crystals: \u00a7a4/5",
+ "\u00a73Crystals: \u00a7a80%",
+ "\u00a73Electron Transmitter: \u00a7aDone\n" +
+ "\u00a73Robotron Reflector: \u00a7eIn Storage\n" +
+ "\u00a73Superlite Motor: \u00a7eIn Inventory\n" +
+ "\u00a73Synthetic Hearth: \u00a7cMissing\n" +
+ "\u00a73Control Switch: \u00a7cMissing\n" +
+ "\u00a73FTX 3070: \u00a7cMissing",
+ "\u00a73Electron Transmitter: \u00a7a3\n" +
+ "\u00a73Robotron Reflector: \u00a7e2\n" +
+ "\u00a73Superlite Motor: \u00a7e1\n" +
+ "\u00a73Synthetic Hearth: \u00a7c0\n" +
+ "\u00a73Control Switch: \u00a7c0\n" +
+ "\u00a73FTX 3070: \u00a7c0",
+ "\u00a73Automaton parts: \u00a7a5/6",
+ "\u00a73Automaton parts: \u00a7a83%",
+ "\u00a73Scavenged Lapis Sword: \u00a7aDone\n" +
+ "\u00a73Scavenged Golden Hammer: \u00a7eIn Storage\n" +
+ "\u00a73Scavenged Diamond Axe: \u00a7eIn Inventory\n" +
+ "\u00a73Scavenged Emerald Hammer: \u00a7cMissing\n",
+ "\u00a73Scavenged Lapis Sword: \u00a7a3\n" +
+ "\u00a73Scavenged Golden Hammer: \u00a7e2\n" +
+ "\u00a73Scavenged Diamond Axe: \u00a7e1\n" +
+ "\u00a73Scavenged Emerald Hammer: \u00a7c0\n",
+ "\u00a73Mines of Divan parts: \u00a7a3/4",
+ "\u00a73Mines of Divan parts: \u00a7a75%"
+ }
+ )
+ @ConfigAccordionId(id = 4)
+ public List<Integer> crystalHollowText = new ArrayList<>(Arrays.asList(0, 3, 7));
+
+ @Expose
+ @ConfigOption(
+ name = "Style",
+ desc = "Change the style of the Crystal Hollows Overlay."
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 4)
+ public int crystalHollowOverlayStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Icons",
+ desc = "Show icons in the Overlay that represent the part."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean crystalHollowIcons = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide Done",
+ desc = "Don't show parts you've given to the NPC."
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean crystalHollowHideDone = false;
+
+ @ConfigOption(
+ name = "Locations",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 5)
+ @ConfigAccordionId(id = 4)
+ public boolean crystalHollowLocationAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Automaton",
+ desc = "Change where to show Automaton parts."
+ )
+ @ConfigEditorDropdown(
+ values = {"Crystal Hollows", "Precursor Remnants", "Lost Precursor City"}
+ )
+ @ConfigAccordionId(id = 5)
+ public int crystalHollowAutomatonLocation = 2;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Divan",
+ desc = "Change where to show Mines of Divan parts."
+ )
+ @ConfigEditorDropdown(
+ values = {"Crystal Hollows", "Mithril Deposits", "Mines of Divan"}
+ )
+ @ConfigAccordionId(id = 5)
+ public int crystalHollowDivanLocation = 2;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Crystal",
+ desc = "Change where to show Collected Crystals."
+ )
+ @ConfigEditorDropdown(
+ values = {"Crystal Hollows", "When No Other Overlays"}
+ )
+ @ConfigAccordionId(id = 5)
+ public int crystalHollowCrystalLocation = 1;
+
+ @ConfigOption(
+ name = "Colours",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 6)
+ @ConfigAccordionId(id = 4)
+ public boolean crystalHollowColourAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Main Color",
+ desc = "Change the main color of the overlay."
+
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowPartColor = 3;
+
+ @Expose
+ @ConfigOption(
+ name = "Done Color",
+ desc = "Change the colour when the part is given to the NPC."
+
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowDoneColor = 10;
+
+ @Expose
+ @ConfigOption(
+ name = "In Inventory Color",
+ desc = "Change the colour when the part is in the inventory."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowInventoryColor = 14;
+
+ @Expose
+ @ConfigOption(
+ name = "In Storage Color",
+ desc = "Change the colour when the part is in the storage."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowStorageColor = 14;
+
+ @Expose
+ @ConfigOption(
+ name = "Missing Color",
+ desc = "Change the colour when the part is missing."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowMissingColor = 12;
+
+ @Expose
+ @ConfigOption(
+ name = "Placed Color",
+ desc = "Change the colour when the crystal is placed."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowPlacedColor = 10;
+
+ @Expose
+ @ConfigOption(
+ name = "Collected Color",
+ desc = "Change the colour when the crystal is collected"
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowCollectedColor = 14;
+
+ @Expose
+ @ConfigOption(
+ name = "All Color",
+ desc = "Change the colour when you have 2/3-all of the parts collected in the count overlay."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowAllColor = 10;
+
+ @Expose
+ @ConfigOption(
+ name = "1/3 Color",
+ desc = "Change the colour when you have 1/3-2/3 of the parts collected in the count overlay."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowMiddleColor = 14;
+
+ @Expose
+ @ConfigOption(
+ name = "0 Color",
+ desc = "Change the colour when you have 0-1/3 of the parts collected in the count overlay."
+ )
+ @ConfigEditorDropdown(
+ values = {
+ "Black",
+ "Dark Blue",
+ "Dark Green",
+ "Dark Aqua",
+ "Dark Red",
+ "Dark Purple",
+ "Gold",
+ "Gray",
+ "Dark Gray",
+ "Blue",
+ "Green",
+ "Aqua",
+ "Red",
+ "Light Purple",
+ "Yellow",
+ "White"
+ }
+ )
+ @ConfigAccordionId(id = 6)
+ public int crystalHollowNoneColor = 12;
+
+ @ConfigOption(
+ name = "Wishing Compass Solver",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 7)
+ public boolean wishingCompassSolverAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Solver",
+ desc = "Show wishing compass target coordinates based on two samples"
+ )
+ @ConfigAccordionId(id = 7)
+ @ConfigEditorBoolean
+ public boolean wishingCompassSolver = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Skytils Waypoints",
+ desc = "Automatically create Skytils waypoints for well-known targets"
+ )
+ @ConfigAccordionId(id = 7)
+ @ConfigEditorBoolean
+ public boolean wishingCompassAutocreateKnownWaypoints = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Waypoint Names",
+ desc = "NOTE: Skytils overwrites waypoint coordinates with less accurate values for Skytils names."
+ )
+ @ConfigAccordionId(id = 7)
+ @ConfigEditorDropdown(
+ values = {"NEU", "Skytils"}
+ )
+ public int wishingCompassWaypointNames = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Puzzler Solver",
+ desc = "Show the correct block to mine for the puzzler puzzle in Dwarven Mines"
+ )
+ @ConfigEditorBoolean
+ public boolean puzzlerSolver = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Titanium Alert",
+ desc = "Show an alert whenever titanium appears nearby"
+ )
+ @ConfigEditorBoolean
+ public boolean titaniumAlert = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Titanium must touch air",
+ desc = "Only show an alert if the Titanium touches air. (kinda sus)"
+ )
+ @ConfigEditorBoolean
+ public boolean titaniumAlertMustBeVisible = false;
+
+ @ConfigOption(
+ name = "Custom Textures",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 8)
+ public boolean texturesAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Dwarven Mines Textures",
+ desc = "Allows texture packs to retexture blocks in the Dwarven Mines. If you don't have a texture pack that does this, you should leave this off"
+ )
+ @ConfigAccordionId(id = 8)
+ @ConfigEditorBoolean
+ public boolean dwarvenTextures = false;
+ @Expose
+ @ConfigOption(
+ name = "Crystal Hollows Textures",
+ desc = "Allows texture packs to retexture blocks in the Crystal Hollows. If you don't have a texture pack that does this, you should leave this off"
+ )
+ @ConfigAccordionId(id = 8)
+ @ConfigEditorBoolean
+ public boolean crystalHollowTextures = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Replace Gemstone sounds",
+ desc = "Replace the break sounds of crystals in the Crystal Hollows. Requires a texture pack with this feature"
+ )
+ @ConfigAccordionId(id = 8)
+ @ConfigEditorBoolean
+ public boolean gemstoneSounds = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Replace Mithril sounds",
+ desc = "Replace the break sounds of mithril and titanium in the Dwarven mines. Requires a texture pack with this feature"
+ )
+ @ConfigAccordionId(id = 8)
+ @ConfigEditorBoolean
+ public boolean mithrilSounds = false;
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
index 01a4576d..c6f00182 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Misc.java
@@ -1,144 +1,240 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-public class Misc {
- @Expose
- @ConfigOption(
- name = "Only Show on Skyblock",
- desc = "The item list and some other GUI elements will only show on skyblock"
- )
- @ConfigEditorBoolean
- public boolean onlyShowOnSkyblock = true;
-
- @Expose
- @ConfigOption(
- name = "Hide Potion Effects",
- desc = "Hide the potion effects inside your inventory while on skyblock"
- )
- @ConfigEditorBoolean
- public boolean hidePotionEffect = true;
-
- @Expose
- @ConfigOption(
- name = "Streamer Mode",
- desc = "Randomize lobby names in the scoreboard and chat messages to help prevent stream sniping"
- )
- @ConfigEditorBoolean
- public boolean streamerMode = false;
-
- @ConfigOption(
- name = "Fairy Soul Waypoints",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean fariySoulAccordion = false;
- @Expose
- @ConfigOption(
- name = "Fairy Souls Finder",
- desc = "Shows waypoints to fairy souls (/neusouls)"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean fariySoul = false;
-
- @Expose
- @ConfigOption(
- name = "Clear Fairy Souls",
- desc = "Clears waypoints to fairy souls (/neusouls clear)"
- )
- @ConfigEditorButton(
- runnableId = 16,
- buttonText = "Clear"
- )
- @ConfigAccordionId(id = 0)
- public boolean fariySoulClear = false;
-
- @Expose
- @ConfigOption(
- name = "Unclear Fairy Souls",
- desc = "Shows all waypoints to fairy souls (/neusouls unclear)"
- )
- @ConfigEditorButton(
- runnableId = 17,
- buttonText = "Unclear"
- )
- @ConfigAccordionId(id = 0)
- public boolean fariySoulUnclear = false;
-
- @Expose
- @ConfigOption(
- name = "GUI Click Sounds",
- desc = "Play click sounds in various NEU-related GUIs when pressing buttons"
- )
- @ConfigEditorBoolean
- public boolean guiButtonClicks = true;
-
- @Expose
- @ConfigOption(
- name = "Replace Chat Social Options",
- desc = "Replace Hypixel's chat social options with NEU's profile viewer or with /ah"
- )
- @ConfigEditorDropdown(
- values = {"Off", "/pv", "/ah"}
- )
- public int replaceSocialOptions1 = 1;
-
- @Expose
- @ConfigOption(
- name = "Damage Indicator Style",
- desc = "Change the style of Skyblock damage indicators to be easier to read\n" +
- "\u00A7cSome old animations mods break this feature"
- )
- @ConfigEditorDropdown(
- values = {"Off", "Commas", "Shortened"}
- )
- public int damageIndicatorStyle = 1;
-
- @Expose
- @ConfigOption(
- name = "Profile Viewer",
- desc = "Brings up the profile viewer (/pv)\n" +
- "Shows stats and networth of players"
- )
- @ConfigEditorButton(runnableId = 13, buttonText = "Open")
- public boolean openPV = true;
-
- @Expose
- @ConfigOption(
- name = "Edit Enchant Colours",
- desc = "Change the colours of certain skyblock enchants (/neuec)"
- )
- @ConfigEditorButton(runnableId = 8, buttonText = "Open")
- public boolean editEnchantColoursButton = true;
-
- @Expose
- @ConfigOption(
- name = "Chroma Text Speed",
- desc = "Change the speed of chroma text for items names (/neucustomize) and enchant colours (/neuec) with the chroma colour code (&z)"
- )
- @ConfigEditorSlider(
- minValue = 10,
- maxValue = 500,
- minStep = 10
- )
- public int chromaSpeed = 100;
-
- @Expose
- @ConfigOption(
- name = "Disable Skull retexturing",
- desc = "Disables the skull retexturing."
- )
- @ConfigEditorBoolean
- public boolean disableSkullRetexturing = false;
-
- @Expose
- @ConfigOption(
- name = "Disable NPC retexturing",
- desc = "Disables the NPC retexturing."
- )
- @ConfigEditorBoolean
- public boolean disableNPCRetexturing = false;
-
-} \ No newline at end of file
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import org.lwjgl.input.Keyboard;
+
+public class Misc {
+ @Expose
+ @ConfigOption(
+ name = "Only Show on Skyblock",
+ desc = "The item list and some other GUI elements will only show on skyblock"
+ )
+ @ConfigEditorBoolean
+ public boolean onlyShowOnSkyblock = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide Potion Effects",
+ desc = "Hide the potion effects inside your inventory while on skyblock"
+ )
+ @ConfigEditorBoolean
+ public boolean hidePotionEffect = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Streamer Mode",
+ desc = "Randomize lobby names in the scoreboard and chat messages to help prevent stream sniping"
+ )
+ @ConfigEditorBoolean
+ public boolean streamerMode = false;
+
+ @ConfigOption(
+ name = "Fairy Soul Waypoints",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean fariySoulAccordion = false;
+ @Expose
+ @ConfigOption(
+ name = "Track Fairy Souls",
+ desc = "Track Found Fairy Souls"
+ )
+ @ConfigEditorBoolean(runnableId = 20)
+ @ConfigAccordionId(id = 0)
+ public boolean trackFairySouls = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Waypoints",
+ desc = "Show Fairy Soul Waypoints (Requires fairy soul tracking)"
+ )
+ @ConfigEditorBoolean(
+ runnableId = 15
+ )
+ @ConfigAccordionId(id = 0)
+ public boolean fariySoul = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Mark All As Found",
+ desc = "Mark all fairy souls in current location as found"
+ )
+ @ConfigEditorButton(
+ runnableId = 16,
+ buttonText = "Clear"
+ )
+ @ConfigAccordionId(id = 0)
+ public boolean fariySoulClear = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Mark All As Missing",
+ desc = "Mark all fairy souls in current location as missing"
+ )
+ @ConfigEditorButton(
+ runnableId = 17,
+ buttonText = "Unclear"
+ )
+ @ConfigAccordionId(id = 0)
+ public boolean fariySoulUnclear = false;
+
+ @Expose
+ @ConfigOption(
+ name = "GUI Click Sounds",
+ desc = "Play click sounds in various NEU-related GUIs when pressing buttons"
+ )
+ @ConfigEditorBoolean
+ public boolean guiButtonClicks = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Replace Chat Social Options",
+ desc = "Replace Hypixel's chat social options with NEU's profile viewer or with /ah"
+ )
+ @ConfigEditorDropdown(
+ values = {"Off", "/pv", "/ah"}
+ )
+ public int replaceSocialOptions1 = 1;
+
+ @Expose
+ @ConfigOption(
+ name = "Damage Indicator Style",
+ desc = "Change Skyblock damage indicators to use shortened numbers\n" +
+ "\u00A7cSome old animations mods break this feature"
+ )
+ @ConfigEditorBoolean
+ public boolean damageIndicatorStyle2 = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Profile Viewer",
+ desc = "Brings up the profile viewer (/pv)\n" +
+ "Shows stats and networth of players"
+ )
+ @ConfigEditorButton(runnableId = 13, buttonText = "Open")
+ public boolean openPV = true;
+
+ @Expose
+ @ConfigOption(
+
+ name = "Edit Enchant Colours",
+ desc = "Change the colours of certain skyblock enchants (/neuec)"
+ )
+ @ConfigEditorButton(runnableId = 8, buttonText = "Open")
+ public boolean editEnchantColoursButton = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Chroma Text Speed",
+ desc = "Change the speed of chroma text for items names (/neucustomize) and enchant colours (/neuec) with the chroma colour code (&z)"
+ )
+ @ConfigEditorSlider(
+ minValue = 10,
+ maxValue = 500,
+ minStep = 10
+ )
+ public int chromaSpeed = 100;
+
+ @Expose
+ @ConfigOption(
+ name = "Disable Skull retexturing",
+ desc = "Disables the skull retexturing."
+ )
+ @ConfigEditorBoolean
+ public boolean disableSkullRetexturing = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Disable NPC retexturing",
+ desc = "Disables the NPC retexturing."
+ )
+ @ConfigEditorBoolean
+ public boolean disableNPCRetexturing = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Wiki",
+ desc = "The wiki to use in the wiki renderer."
+ )
+ @ConfigEditorDropdown(values = {
+ "Hypixel",
+ "Fandom"
+ })
+ public int wiki = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Waypoint Keybind",
+ desc = "Press this keybind to show waypoints to various NPCs"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
+ public int keybindWaypoint = Keyboard.KEY_NONE;
+
+ @Expose
+ @ConfigOption(
+ name = "Untrack close Waypoints",
+ desc = "Automatically untrack waypoints once you get close to them."
+ )
+ @ConfigEditorBoolean
+ public boolean untrackCloseWaypoints = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Warp twice",
+ desc = "Warp twice when using SHIFT+<waypoint keybind> to /warp to a waypoint."
+ )
+ @ConfigEditorBoolean
+ public boolean warpTwice = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Calculator",
+ desc = "Replace calculations like §9\"1+2\"§7 with the calculation result in sign popups (AH/BZ) and in the neu search bar"
+ )
+ @ConfigEditorDropdown(values = {"Off", "Enabled with ! Prefix", "Always enabled"})
+ public int calculationMode = 2;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Abiphone Warning",
+ desc = "Asks for confirmation when removing a contact in the abiphone"
+ )
+ @ConfigEditorBoolean
+ public boolean abiphoneWarning = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Coop Warning",
+ desc = "Asks for confirmation when clicking the coop diamond in profile menu"
+ )
+ @ConfigEditorBoolean
+ public boolean coopWarning = true;
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java
index 849f5823..18b89733 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/MiscOverlays.java
@@ -1,8 +1,33 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
import java.util.ArrayList;
import java.util.Arrays;
@@ -27,6 +52,15 @@ public class MiscOverlays {
@Expose
@ConfigOption(
+ name = "Todo Overlay Tab",
+ desc = "Only show the todo overlay when tab list is open"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean todoOverlayOnlyShowTab = false;
+
+ @Expose
+ @ConfigOption(
name = "Todo Text",
desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
"\u00a7rIf you want to see the time until something is available, click \"Add\" and then the respective timer"
@@ -40,12 +74,13 @@ public class MiscOverlays {
"\u00a73Fetchur: \u00a7e3h38m",
"\u00a73Commissions: \u00a7e3h38m",
"\u00a73Experiments: \u00a7e3h38m",
- "\u00a73Daily Mithril Powder: \u00a7e3h38m",
- "\u00a73Daily Gemstone Powder: \u00a7e3h38m",
+ "\u00a73Mithril Powder: \u00a7e3h38m",
+ "\u00a73Gemstone Powder: \u00a7e3h38m",
+ "\u00a73Heavy Pearls: \u00a7e3h38m",
}
)
@ConfigAccordionId(id = 0)
- public List<Integer> todoText2 = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8));
+ public List<Integer> todoText2 = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
@ConfigOption(
name = "Show Only If Soon",
@@ -141,8 +176,8 @@ public class MiscOverlays {
@Expose
@ConfigOption(
- name = "Daily Mithril Powder Display",
- desc = "Change the way the daily mithril powder displays\n" +
+ name = "Mithril Powder Display",
+ desc = "Change the way the mithril powder displays\n" +
"Only when ready, When very Soon, When soon, When kinda soon or always."
)
@ConfigAccordionId(id = 1)
@@ -153,8 +188,8 @@ public class MiscOverlays {
@Expose
@ConfigOption(
- name = "Daily Gemstone Powder Display",
- desc = "Change the way the daily gemstone powder displays\n" +
+ name = "Gemstone Powder Display",
+ desc = "Change the way the gemstone powder displays\n" +
"Only when ready, When very Soon, When soon, When kinda soon or always."
)
@ConfigAccordionId(id = 1)
@@ -163,6 +198,19 @@ public class MiscOverlays {
)
public int dailyGemstonePowderDisplay = 0;
+ @Expose
+ @ConfigOption(
+ name = "Heavy Pearl Display",
+ desc = "Change the way the heavy pearl displays\n" +
+ "Only when ready, When very Soon, When soon, When kinda soon or always."
+ )
+ @ConfigAccordionId(id = 1)
+ @ConfigEditorDropdown(
+ values = {"Only when ready", "When very Soon", "When soon", "When Kinda Soon", "Always"}
+ )
+
+ public int dailyHeavyPearlDisplay = 0;
+
@ConfigOption(
name = "Colours",
desc = ""
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java
index 82b0f22a..6c55fd09 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/NeuAuctionHouse.java
@@ -1,45 +1,73 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class NeuAuctionHouse {
- @Expose
- @ConfigOption(
- name = "Enable NeuAH",
- desc = "Turn on the NEU Auction House. \u00A7cWARNING: May negatively impact performance on low-end machines"
- )
- @ConfigEditorBoolean
- public boolean enableNeuAuctionHouse = false;
-
- @Expose
- @ConfigOption(
- name = "Disable AH Scroll",
- desc = "Disable scrolling using the scroll wheel inside NeuAH.\n" +
- "This should be used if you want to be able to scroll through tooltips"
- )
- @ConfigEditorBoolean
- public boolean disableAhScroll = false;
-
- @Expose
- @ConfigOption(
- name = "AH Notification (Mins)",
- desc = "Change the amount of time (in minutes) before the \"Ending Soon\" notification for an auction you have bid on"
- )
- @ConfigEditorSlider(
- minValue = 1f,
- maxValue = 10f,
- minStep = 1f
- )
- public int ahNotification = 5;
-
- @Expose
- @ConfigOption(
- name = "Price Filtering in NEU AH",
- desc = "The ability to filter the price of items and their respective average BIN values"
- )
- @ConfigEditorBoolean
- public boolean priceFiltering = false;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class
+NeuAuctionHouse {
+ @Expose
+ @ConfigOption(
+ name = "Enable NeuAH",
+ desc = "Turn on the NEU Auction House. \u00A7cWARNING: May negatively impact performance on low-end machines"
+ )
+ @ConfigEditorBoolean
+ public boolean enableNeuAuctionHouse = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Disable AH Scroll",
+ desc = "Disable scrolling using the scroll wheel inside NeuAH.\n" +
+ "This should be used if you want to be able to scroll through tooltips"
+ )
+ @ConfigEditorBoolean
+ public boolean disableAhScroll = false;
+
+ @Expose
+ @ConfigOption(
+ name = "AH Notification (Mins)",
+ desc = "Change the amount of time (in minutes) before the \"Ending Soon\" notification for an auction you have bid on"
+ )
+ @ConfigEditorSlider(
+ minValue = 1f,
+ maxValue = 10f,
+ minStep = 1f
+ )
+ public int ahNotification = 5;
+
+ @Expose
+ @ConfigOption(
+ name = "Price Filtering in NEU AH",
+ desc = "The ability to filter the price of items and their respective average BIN values"
+ )
+ @ConfigEditorBoolean
+ public boolean priceFiltering = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Save Last Search",
+ desc = "Saving the last query when closing the neuah"
+ )
+ @ConfigEditorBoolean
+ public boolean saveLastSearch = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java
index 9fae1d01..85ad2093 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Notifications.java
@@ -1,32 +1,89 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class Notifications {
- @Expose
- @ConfigOption(
- name = "Update Messages",
- desc = "Give a notification in chat whenever a new version of NEU is released"
- )
- @ConfigEditorBoolean
- public boolean showUpdateMsg = true;
-
- @Expose
- @ConfigOption(
- name = "RAM Warning",
- desc = "Warning when game starts with lots of RAM allocated\n" +
- "\u00a7cBefore disabling this, please seriously read the message. If you complain about FPS issues without listening to the warning, that's your fault."
- )
- @ConfigEditorBoolean
- public boolean doRamNotif = true;
-
- /*@Expose
- @ConfigOption(
- name = "Wrong Pet",
- desc = "Gives a notification in chat whenever you're using a pet that doesnt match the same xp you're gathering."
- )
- @ConfigEditorBoolean
- public boolean showWrongPetMsg = false;*/
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class Notifications {
+ @Expose
+ @ConfigOption(
+ name = "Update Messages",
+ desc = "Give a notification in chat whenever a new version of NEU is released"
+ )
+ @ConfigEditorDropdown(values = {"Off", "Releases", "Pre-Releases"})
+ public int updateChannel = 1;
+
+ @Expose
+ @ConfigOption(
+ name = "Missing repo warning",
+ desc = "Warning when repo data is missing or out of date"
+ )
+ @ConfigEditorBoolean
+ public boolean outdatedRepo = true;
+
+ @Expose
+ @ConfigOption(
+ name = "RAM Warning",
+ desc = "Warning when game starts with lots of RAM allocated\n" +
+ "\u00a7cBefore disabling this, please seriously read the message. If you complain about FPS issues without listening to the warning, that's your fault."
+ )
+ @ConfigEditorBoolean
+ public boolean doRamNotif = true;
+
+ @Expose
+ @ConfigOption(
+ name = "OldAnimations Warning",
+ desc = "Warning when an unsupported OldAnimations mod is used"
+ )
+ @ConfigEditorBoolean
+ public boolean doOamNotif = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Fast Render Warning",
+ desc = "\u00a7cIf and ONLY if you have Fast Render disabled and are still seeing the warning, you can disable it here.\nDisabling it with Fast Render still on will lead to broken features."
+ )
+ @ConfigEditorBoolean
+ public boolean doFastRenderNotif = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Booster Cookie Warning",
+ desc = "Warning when a booster cookie is about to expire"
+ )
+ @ConfigEditorBoolean
+ public boolean doBoosterNotif = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Booster Cookie Warning Minutes",
+ desc = "Change the minimum time required for the Booster Cookie warning to activate"
+ )
+ @ConfigEditorSlider(
+ minValue = 10,
+ maxValue = 5760,
+ minStep = 25
+ )
+ public int boosterCookieWarningMins = 1440;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java
index f0d0c22c..353c4e08 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/PetOverlay.java
@@ -1,118 +1,141 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class PetOverlay {
- @Expose
- @ConfigOption(
- name = "Enable Pet Info Overlay",
- desc = "Shows current active pet and pet exp on screen."
- )
- @ConfigEditorBoolean
- public boolean enablePetInfo = false;
-
- @Expose
- @ConfigOption(
- name = "Edit Pet Info Position",
- desc = "The position of the pet info."
- )
- @ConfigEditorButton(
- runnableId = 4,
- buttonText = "Edit"
- )
- public Position petInfoPosition = new Position(-1, -1);
-
- @Expose
- @ConfigOption(
- name = "Pet Overlay Text",
- desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
- "\u00a7rEquip a pet to show the overlay"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7a[Lvl 37] \u00a7fRock",
- "\u00a7b2,312.9/2,700\u00a7e (85.7%)",
- "\u00a7b2.3k/2.7k\u00a7e (85.7%)",
- "\u00a7bXP/h: \u00a7e27,209",
- "\u00a7bTotal XP: \u00a7e30,597.9",
- "\u00a7bHeld Item: \u00a7fMining Exp Boost",
- "\u00a7bUntil L38: \u00a7e5m13s",
- "\u00a7bUntil L100: \u00a7e2d13h"
- }
- )
- public List<Integer> petOverlayText = new ArrayList<>(Arrays.asList(0, 2, 3, 6, 4));
-
- @Expose
- @ConfigOption(
- name = "Pet Overlay Icon",
- desc = "Show the icon of the pet you have equiped in the overlay"
- )
- @ConfigEditorBoolean
- public boolean petOverlayIcon = true;
-
- @Expose
- @ConfigOption(
- name = "Pet Info Overlay Style",
- desc = "Change the style of the Pet Info overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow Only", "Full Shadow"}
- )
- public int petInfoOverlayStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Show Last Pet",
- desc = "Show 2 pets on the overlay\nUseful if training two pets at once with autopet"
- )
- @ConfigEditorBoolean
- public boolean dualPets = false;
-
- @Expose
- @ConfigOption(
- name = "Pet Inventory Display",
- desc = "Shows an overlay in your inventory showing your current pet"
- )
- @ConfigEditorBoolean
- public boolean petInvDisplay = false;
-
- @Expose
- @ConfigOption(
- name = "GUI Colour",
- desc = "Change the colour of the GUI"
- )
- @ConfigEditorDropdown(
- values = {"Vanilla", "Grey", "Dark", "Transparent", "FSR"}
- )
- public int colourStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Click To Open Pets",
- desc = "Click on the hud to open /pets"
- )
- @ConfigEditorBoolean
- public boolean sendPetsCommand = true;
-
- @Expose
- @ConfigOption(
- name = "Hide Pet Inventory Tooltip",
- desc = "Hides the tooltip of your active in your inventory"
- )
- @ConfigEditorBoolean
- public boolean hidePetTooltip = false;
-
- @Expose
- @ConfigOption(
- name = "Show upgraded Pet Level",
- desc = "Show the estimated pet level after an upgrade at Kats"
- )
- @ConfigEditorBoolean
- public boolean showKatSitting = true;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.Position;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class PetOverlay {
+ @Expose
+ @ConfigOption(
+ name = "Enable Pet Info Overlay",
+ desc = "Shows current active pet and pet exp on screen."
+ )
+ @ConfigEditorBoolean
+ public boolean enablePetInfo = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Pet Info Position",
+ desc = "Change the position of the pet info overlay"
+ )
+ @ConfigEditorButton(
+ runnableId = 4,
+ buttonText = "Edit"
+ )
+ public Position petInfoPosition = new Position(-1, -1);
+
+ @Expose
+ @ConfigOption(
+ name = "Pet Overlay Text",
+ desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
+ "\u00a7rEquip a pet to show the overlay"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7a[Lvl 37] \u00a7fRock",
+ "\u00a7b2,312.9/2,700\u00a7e (85.7%)",
+ "\u00a7b2.3k/2.7k\u00a7e (85.7%)",
+ "\u00a7bXP/h: \u00a7e27,209",
+ "\u00a7bTotal XP: \u00a7e30,597.9",
+ "\u00a7bHeld Item: \u00a7fMining Exp Boost",
+ "\u00a7bUntil L38: \u00a7e5m13s",
+ "\u00a7bUntil L100: \u00a7e2d13h"
+ }
+ )
+ public List<Integer> petOverlayText = new ArrayList<>(Arrays.asList(0, 2, 3, 6, 4));
+
+ @Expose
+ @ConfigOption(
+ name = "Pet Overlay Icon",
+ desc = "Show the icon of the pet you have equiped in the overlay"
+ )
+ @ConfigEditorBoolean
+ public boolean petOverlayIcon = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Pet Info Overlay Style",
+ desc = "Change the style of the Pet Info overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ public int petInfoOverlayStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Last Pet",
+ desc = "Show 2 pets on the overlay\nUseful if training two pets at once with autopet"
+ )
+ @ConfigEditorBoolean
+ public boolean dualPets = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Pet Inventory Display",
+ desc = "Shows an overlay in your inventory showing your current pet"
+ )
+ @ConfigEditorBoolean
+ public boolean petInvDisplay = false;
+
+ @Expose
+ @ConfigOption(
+ name = "GUI Style",
+ desc = "Change the colour of the GUI"
+ )
+ @ConfigEditorDropdown(
+ values = {"Minecraft", "Grey", "PacksHQ Dark", "Transparent", "FSR"}
+ )
+ public int colourStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Click To Open Pets",
+ desc = "Click on the hud to open /pets"
+ )
+ @ConfigEditorBoolean
+ public boolean sendPetsCommand = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide Pet Inventory Tooltip",
+ desc = "Hides the tooltip of your active in your inventory"
+ )
+ @ConfigEditorBoolean
+ public boolean hidePetTooltip = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Show upgraded Pet Level",
+ desc = "Show the estimated pet level after an upgrade at Kats"
+ )
+ @ConfigEditorBoolean
+ public boolean showKatSitting = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java
new file mode 100644
index 00000000..673e1015
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ProfileViewer.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.BuildFlags;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ProfileViewer {
+
+ @ConfigOption(
+ name = "Profile Viewer info",
+ desc =
+ "The Profile Viewer requires you to have an \u00A72api key\u00A77 set (if you don't have one set do \u00A72/api new\u00A77)\n"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12,
+ buttonText = ""
+ )
+ public boolean pvInfo = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Open Profile Viewer",
+ desc = "Brings up the profile viewer (/pv)\n" +
+ "Shows stats and networth of players"
+ )
+ @ConfigEditorButton(
+ runnableId = 13,
+ buttonText = "Open"
+ )
+ public boolean openPV = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Page layout",
+ desc = "\u00a7rSelect the order of the pages at the top of the Profile Viewer\n" +
+ "\u00a7eDrag text to rearrange"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7eBasic Info",
+ "\u00a7eDungeons",
+ "\u00a7eExtra Info",
+ "\u00a7eInventories",
+ "\u00a7eCollections",
+ "\u00a7ePets",
+ "\u00a7eMining",
+ "\u00a7eBingo",
+ "\u00a7eTrophy Fish",
+ "\u00a7eBestiary",
+ },
+ allowDeleting = false
+ )
+ public List<Integer> pageLayout = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+
+ @Expose
+ @ConfigOption(
+ name = "Always show bingo tab",
+ desc = "Always show bingo tab or only show it when the bingo profile is selected"
+ )
+ @ConfigEditorBoolean
+ public boolean alwaysShowBingoTab = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Pronouns in /pv",
+ desc = "Shows the pronouns of a player in /pv. Data sourced from pronoundb.org"
+ )
+ @ConfigEditorBoolean
+ public boolean showPronounsInPv = BuildFlags.ENABLE_PRONOUNS_IN_PV_BY_DEFAULT;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java
index 71b41329..943417e6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SkillOverlays.java
@@ -1,317 +1,346 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-import org.lwjgl.input.Keyboard;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class SkillOverlays {
- @ConfigOption(
- name = "Skill Overlay info",
- desc =
- "The skill trackers need you to have an \u00A72api key\u00A77 set (if you don't have one set do \u00A72/api new\u00A77)\n" +
- "For the overlays to show you need a \u00A7bmathematical hoe\u00A77 or an axe with \u00A7bcultivating\u00A77 " +
- "enchant for farming, a pickaxe with \u00A7bcompact\u00A77 for mining or a rod with \u00A7bexpertise\u00A77"
- )
- @ConfigEditorFSR(
- runnableId = 12,
- buttonText = ""
- )
- public boolean skillInfo = false;
- @ConfigOption(
- name = "Farming",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean farmingAccordion = false;
- @Expose
- @ConfigOption(
- name = "Enable Farming Overlay",
- desc = "Show an overlay while farming with useful information"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean farmingOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Farming Text",
- desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
- "\u00a7rHold a mathematical hoe or use an axe with cultivating enchantment while gaining farming xp to show the overlay"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7bCounter: \u00a7e37,547,860",
- "\u00a7bCrops/m: \u00a7e38.29",
- "\u00a7bFarm: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
- "\u00a7bCurrent XP: \u00a7e6,734",
- "\u00a7bRemaining XP: \u00a7e3,265",
- "\u00a7bXP/h: \u00a7e238,129",
- "\u00a7bYaw: \u00a7e68.25\u00a7l\u1D52",
- "\u00a7bETA: \u00a7e13h12m",
- "\u00a7bPitch: \u00a7e69.42\u00a7l\u1D52",
- "\u00a7bCultivating: \u00a7e10,137,945/20,000,000",
- "\u00a7bCoins/m \u00a7e57,432"
- }
- )
- @ConfigAccordionId(id = 0)
- public List<Integer> farmingText = new ArrayList<>(Arrays.asList(0, 9, 10, 1, 2, 3, 4, 5, 7, 6));
-
- @Expose
- @ConfigOption(
- name = "Use BZ Price For Coins/m",
- desc = "Uses the bazzar price instead of NPC price for coins/m"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean useBZPrice = true;
-
- @Expose
- @ConfigOption(
- name = "Edit Farming Overlay Position",
- desc = "Change the position of the Farming overlay"
- )
- @ConfigEditorButton(
- runnableId = 3,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 0)
- public Position farmingPosition = new Position(10, 200);
-
- @Expose
- @ConfigOption(
- name = "Farming Style",
- desc = "Change the style of the Farming overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
- )
- @ConfigAccordionId(id = 0)
- public int farmingStyle = 0;
- @ConfigOption(
- name = "Mining",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- public boolean miningAccordion = false;
- @Expose
- @ConfigOption(
- name = "Enable Mining Overlay",
- desc = "Show an overlay while Mining with useful information"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean miningSkillOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Mining Text",
- desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
- "\u00a7rHold a pickaxe with compact while gaining mining xp to show the overlay"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7bCompact: \u00a7e547,860",
- "\u00a7bBlocks/m: \u00a7e38.29",
- "\u00a7bMine: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
- "\u00a7bCurrent XP: \u00a7e6,734",
- "\u00a7bRemaining XP: \u00a7e3,265",
- "\u00a7bXP/h: \u00a7e238,129",
- "\u00a7bYaw: \u00a7e68.25\u00a7l\u1D52",
- "\u00a7bETA: \u00a7e13h12m",
- "\u00a7bCompact Progress: \u00a7e137,945/150,000"
- }
- )
- @ConfigAccordionId(id = 1)
- public List<Integer> miningText = new ArrayList<>(Arrays.asList(0, 8, 1, 2, 3, 4, 5, 7));
-
- @Expose
- @ConfigOption(
- name = "Edit Mining Overlay Position",
- desc = "Change the position of the Mining overlay"
- )
- @ConfigEditorButton(
- runnableId = 11,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 1)
- public Position miningPosition = new Position(10, 200);
-
- @Expose
- @ConfigOption(
- name = "Mining Style",
- desc = "Change the style of the Mining overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
- )
- @ConfigAccordionId(id = 1)
- public int miningStyle = 0;
-
- @ConfigOption(
- name = "Fishing",
- desc = ""
- )
- @ConfigEditorAccordion(id = 3)
- public boolean fishingAccordion = false;
- @Expose
- @ConfigOption(
- name = "Enable Fishing Overlay",
- desc = "Show an overlay while Fishing with useful information"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 3)
- public boolean FishingSkillOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Fishing Text",
- desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
- "\u00a7rHold a fishing rod with expertise enchantment while gaining fishing xp to show the overlay"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7bExpertise: \u00a7e7,945/10,000",
- //"\u00a7bCatches/m: \u00a7e38.29",
- "\u00a7bFishing: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
- "\u00a7bCurrent XP: \u00a7e6,734",
- "\u00a7bRemaining XP: \u00a7e3,265",
- "\u00a7bXP/h: \u00a7e238,129",
- //"\u00a7bYaw: \u00a7e68.25\u00a7l\u1D52",
- "\u00a7bETA: \u00a7e13h12m",
- //"\u00a7bExpertise Progress: \u00a7e7,945/10,000",
- "\u00a7bTimer: \u00a7e1m15s"
- }
- )
- @ConfigAccordionId(id = 3)
- public List<Integer> fishingText = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6));
-
- @Expose
- @ConfigOption(
- name = "Edit Fishing Overlay Position",
- desc = "Change the position of the Fishing overlay"
- )
- @ConfigEditorButton(
- runnableId = 14,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 3)
- public Position fishingPosition = new Position(10, 200);
-
- @Expose
- @ConfigOption(
- name = "Fishing Style",
- desc = "Change the style of the Fishing overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
- )
- @ConfigAccordionId(id = 3)
- public int fishingStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Toggle Fishing timer",
- desc = "Start or stop the timer on the fishing overlay\n" +
- "Also can plays a ding customizable below"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_END)
- @ConfigAccordionId(id = 3)
- public int fishKey = Keyboard.KEY_END;
-
- @Expose
- @ConfigOption(
- name = "Fishing Timer Alert",
- desc = "Change the amount of time (seconds) until the timer dings"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 600,
- minStep = 20
- )
- @ConfigAccordionId(id = 3)
- public int customFishTimer = 300;
-
- @ConfigOption(
- name = "Combat",
- desc = ""
- )
- @ConfigEditorAccordion(id = 4)
- public boolean combatAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "\u00A7cWarning",
- desc = "The combat display will only show if you have a Book of Stats on the item you are using"
- )
- @ConfigEditorFSR(
- runnableId = 12,
- buttonText = ""
- )
- @ConfigAccordionId(id = 4)
- public boolean combatInfo = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Combat Overlay",
- desc = "Show an overlay while Combat with useful information"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 4)
- public boolean combatSkillOverlay = true;
-
- @Expose
- @ConfigOption(
- name = "Combat Text",
- desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
- "\u00a7rHold an item with Book of Stats to show the display"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7bKills: \u00a7e547,860",
- "\u00a7bCombat: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
- "\u00a7bCurrent XP: \u00a7e6,734",
- "\u00a7bRemaining XP: \u00a7e3,265",
- "\u00a7bXP/h: \u00a7e238,129",
- "\u00a7bETA: \u00a7e13h12m"
- }
- )
- @ConfigAccordionId(id = 4)
- public List<Integer> combatText = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5));
-
- @Expose
- @ConfigOption(
- name = "Edit Combat Overlay Position",
- desc = "Change the position of the Combat overlay"
- )
- @ConfigEditorButton(
- runnableId = 19,
- buttonText = "Edit"
- )
- @ConfigAccordionId(id = 4)
- public Position combatPosition = new Position(10, 200);
-
- @Expose
- @ConfigOption(
- name = "Combat Style",
- desc = "Change the style of the Combat overlay"
- )
- @ConfigEditorDropdown(
- values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
- )
- @ConfigAccordionId(id = 4)
- public int combatStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Always show combat overlay",
- desc = "Shows combat overlay even if you dont have Book of Stats"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 4)
- public boolean alwaysShowCombatOverlay = false;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.Position;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class SkillOverlays {
+ @ConfigOption(
+ name = "Skill Overlay info",
+ desc =
+ "The skill trackers need you to have an \u00A72api key\u00A77 set (if you don't have one set do \u00A72/api new\u00A77)\n" +
+ "For the overlays to show you need a \u00A7bmathematical hoe\u00A77 or an axe with \u00A7bcultivating\u00A77 " +
+ "enchant for farming, a pickaxe with \u00A7bcompact\u00A77 for mining or a rod with \u00A7bexpertise\u00A77"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12,
+ buttonText = ""
+ )
+ public boolean skillInfo = false;
+ @ConfigOption(
+ name = "Farming",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean farmingAccordion = false;
+ @Expose
+ @ConfigOption(
+ name = "Enable Farming Overlay",
+ desc = "Show an overlay while farming with useful information"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean farmingOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Farming Text",
+ desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
+ "\u00a7rHold a mathematical hoe or use an axe with cultivating enchantment while gaining farming xp to show the overlay"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7bCounter: \u00a7e37,547,860",
+ "\u00a7bCrops/m: \u00a7e38.29",
+ "\u00a7bFarming: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
+ "\u00a7bCurrent XP: \u00a7e6,734",
+ "\u00a7bRemaining XP: \u00a7e3,265",
+ "\u00a7bXP/h: \u00a7e238,129",
+ "\u00a7bYaw: \u00a7e68.25\u00a7l\u1D52",
+ "\u00a7bETA: \u00a7e13h12m",
+ "\u00a7bPitch: \u00a7e69.42\u00a7l\u1D52",
+ "\u00a7bCultivating: \u00a7e10,137,945/20,000,000",
+ "\u00a7bCoins/m \u00a7e57,432"
+ }
+ )
+ @ConfigAccordionId(id = 0)
+ public List<Integer> farmingText = new ArrayList<>(Arrays.asList(0, 9, 10, 1, 2, 3, 4, 5, 7, 6));
+
+ @Expose
+ @ConfigOption(
+ name = "Use BZ Price For Coins/m",
+ desc = "Uses the bazzar price instead of NPC price for coins/m"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean useBZPrice = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Farming Overlay Position",
+ desc = "Change the position of the Farming overlay"
+ )
+ @ConfigEditorButton(
+ runnableId = 3,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 0)
+ public Position farmingPosition = new Position(10, 200);
+
+ @Expose
+ @ConfigOption(
+ name = "Farming Style",
+ desc = "Change the style of the Farming overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 0)
+ public int farmingStyle = 0;
+ @ConfigOption(
+ name = "Mining",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean miningAccordion = false;
+ @Expose
+ @ConfigOption(
+ name = "Enable Mining Overlay",
+ desc = "Show an overlay while Mining with useful information"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean miningSkillOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Mining Text",
+ desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
+ "\u00a7rHold a pickaxe with compact while gaining mining xp to show the overlay"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7bCompact: \u00a7e547,860",
+ "\u00a7bBlocks/m: \u00a7e38.29",
+ "\u00a7bMining: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
+ "\u00a7bCurrent XP: \u00a7e6,734",
+ "\u00a7bRemaining XP: \u00a7e3,265",
+ "\u00a7bXP/h: \u00a7e238,129",
+ "\u00a7bYaw: \u00a7e68.25\u00a7l\u1D52",
+ "\u00a7bETA: \u00a7e13h12m",
+ "\u00a7bCompact Progress: \u00a7e137,945/150,000"
+ }
+ )
+ @ConfigAccordionId(id = 1)
+ public List<Integer> miningText = new ArrayList<>(Arrays.asList(0, 8, 1, 2, 3, 4, 5, 7));
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Mining Overlay Position",
+ desc = "Change the position of the Mining overlay"
+ )
+ @ConfigEditorButton(
+ runnableId = 11,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 1)
+ public Position miningPosition = new Position(10, 200);
+
+ @Expose
+ @ConfigOption(
+ name = "Mining Style",
+ desc = "Change the style of the Mining overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 1)
+ public int miningStyle = 0;
+
+ @ConfigOption(
+ name = "Fishing",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 3)
+ public boolean fishingAccordion = false;
+ @Expose
+ @ConfigOption(
+ name = "Enable Fishing Overlay",
+ desc = "Show an overlay while Fishing with useful information"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 3)
+ public boolean FishingSkillOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Fishing Text",
+ desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
+ "\u00a7rHold a fishing rod with expertise enchantment while gaining fishing xp to show the overlay"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7bExpertise: \u00a7e7,945/10,000",
+ //"\u00a7bCatches/m: \u00a7e38.29",
+ "\u00a7bFishing: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
+ "\u00a7bCurrent XP: \u00a7e6,734",
+ "\u00a7bRemaining XP: \u00a7e3,265",
+ "\u00a7bXP/h: \u00a7e238,129",
+ //"\u00a7bYaw: \u00a7e68.25\u00a7l\u1D52",
+ "\u00a7bETA: \u00a7e13h12m",
+ //"\u00a7bExpertise Progress: \u00a7e7,945/10,000",
+ "\u00a7bTimer: \u00a7e1m15s"
+ }
+ )
+ @ConfigAccordionId(id = 3)
+ public List<Integer> fishingText = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4, 5, 6));
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Fishing Overlay Position",
+ desc = "Change the position of the Fishing overlay"
+ )
+ @ConfigEditorButton(
+ runnableId = 14,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 3)
+ public Position fishingPosition = new Position(10, 200);
+
+ @Expose
+ @ConfigOption(
+ name = "Fishing Style",
+ desc = "Change the style of the Fishing overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 3)
+ public int fishingStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Toggle Fishing timer",
+ desc = "Start or stop the timer on the fishing overlay\n" +
+ "Also can plays a ding customizable below"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_END)
+ @ConfigAccordionId(id = 3)
+ public int fishKey = Keyboard.KEY_END;
+
+ @Expose
+ @ConfigOption(
+ name = "Fishing Timer Alert",
+ desc = "Change the amount of time (seconds) until the timer dings"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 600,
+ minStep = 20
+ )
+ @ConfigAccordionId(id = 3)
+ public int customFishTimer = 300;
+
+ @ConfigOption(
+ name = "Combat",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 4)
+ public boolean combatAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "\u00A7cWarning",
+ desc = "The combat display will only show if you have a Book of Stats or the Champion enchant"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12,
+ buttonText = ""
+ )
+ @ConfigAccordionId(id = 4)
+ public boolean combatInfo = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Combat Overlay",
+ desc = "Show an overlay while Combat with useful information"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean combatSkillOverlay = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Combat Text",
+ desc = "\u00a7eDrag text to change the appearance of the overlay\n" +
+ "\u00a7rHold an item with Book of Stats to show the display"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7bKills: \u00a7e547,860",
+ "\u00a7bCombat: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
+ "\u00a7bCurrent XP: \u00a7e6,734",
+ "\u00a7bRemaining XP: \u00a7e3,265",
+ "\u00a7bXP/h: \u00a7e238,129",
+ "\u00a7bETA: \u00a7e13h12m",
+ "\u00a7bChampion XP: \u00a7e3,523"
+ }
+ )
+ @ConfigAccordionId(id = 4)
+ public List<Integer> combatText = new ArrayList<>(Arrays.asList(0, 6, 1, 2, 3, 4, 5));
+
+ @Expose
+ @ConfigOption(
+ name = "Edit Combat Overlay Position",
+ desc = "Change the position of the Combat overlay"
+ )
+ @ConfigEditorButton(
+ runnableId = 19,
+ buttonText = "Edit"
+ )
+ @ConfigAccordionId(id = 4)
+ public Position combatPosition = new Position(10, 200);
+
+ @Expose
+ @ConfigOption(
+ name = "Combat Style",
+ desc = "Change the style of the Combat overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Background", "No Shadow", "Shadow", "Full Shadow"}
+ )
+ @ConfigAccordionId(id = 4)
+ public int combatStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Always show combat overlay",
+ desc = "Shows combat overlay even if you dont have Book of Stats or the Champion enchant"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 4)
+ public boolean alwaysShowCombatOverlay = false;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlayerOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlayerOverlay.java
index 220b992b..927d00e5 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlayerOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlayerOverlay.java
@@ -1,8 +1,32 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.options.seperateSections;
import com.google.gson.annotations.Expose;
import io.github.moulberry.notenoughupdates.core.config.Position;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlotLocking.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlotLocking.java
index f9d1eef1..22286808 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlotLocking.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/SlotLocking.java
@@ -1,91 +1,114 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-import org.lwjgl.input.Keyboard;
-
-public class SlotLocking {
- @Expose
- @ConfigOption(
- name = "\u00A7cWarning",
- desc = "Make sure you have SBA's locked slots off before you turn NEU's on"
- )
- @ConfigEditorFSR(
- runnableId = 12
- )
- public boolean slotLockWarning = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Slot Locking",
- desc = "Allows you to lock slots and create slot bindings"
- )
- @ConfigEditorBoolean
- public boolean enableSlotLocking = false;
-
- @Expose
- @ConfigOption(
- name = "Enable Slot Binding",
- desc = "Allows you to create slot bindings\nNote: \"Enable Slot Locking\" must be on"
- )
- @ConfigEditorBoolean
- public boolean enableSlotBinding = true;
-
- @Expose
- @ConfigOption(
- name = "Don't Drop Bound Slots",
- desc = "Slot bindings also act as locked slots (prevents dropping / moving in inventory)"
- )
- @ConfigEditorBoolean
- public boolean bindingAlsoLocks = false;
-
- @Expose
- @ConfigOption(
- name = "Slot Lock Key",
- desc = "Click this key to LOCK a slot\n" +
- "Hold this key and drag to BIND a slot"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_L)
- public int slotLockKey = Keyboard.KEY_L;
-
- @Expose
- @ConfigOption(
- name = "Lock Slots in Trade",
- desc = "Prevents trading locked items in the custom trade windows"
- )
- @ConfigEditorBoolean
- public boolean lockSlotsInTrade = true;
-
- @Expose
- /*@ConfigOption(
- name = "Item Swap drop delay",
- desc = "Set the delay between swapping to another item and being able to drop it.\n"+
- "This is to fix a bug that allowed you to drop slot locked items."
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 500,
- minStep = 5
- )*/
- public int slotLockSwapDelay = 100;
-
- @Expose
- @ConfigOption(
- name = "Slot Lock Sound",
- desc = "Play a ding when locking/unlocking slots"
- )
- @ConfigEditorBoolean
- public boolean slotLockSound = true;
-
- @Expose
- @ConfigOption(
- name = "Slot Lock Sound Vol.",
- desc = "Set the volume of the ding sound"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 100,
- minStep = 1
- )
- public float slotLockSoundVol = 20;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import org.lwjgl.input.Keyboard;
+
+public class SlotLocking {
+ @Expose
+ @ConfigOption(
+ name = "\u00A7cWarning",
+ desc = "Make sure you have SBA's locked slots off before you turn NEU's on"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12
+ )
+ public boolean slotLockWarning = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Slot Locking",
+ desc = "Allows you to lock slots and create slot bindings"
+ )
+ @ConfigEditorBoolean
+ public boolean enableSlotLocking = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Enable Slot Binding",
+ desc = "Allows you to create slot bindings\nNote: \"Enable Slot Locking\" must be on"
+ )
+ @ConfigEditorBoolean
+ public boolean enableSlotBinding = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Don't Drop Bound Slots",
+ desc = "Slot bindings also act as locked slots (prevents dropping / moving in inventory)"
+ )
+ @ConfigEditorBoolean
+ public boolean bindingAlsoLocks = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Slot Lock Key",
+ desc = "Click this key to LOCK a slot\n" +
+ "Hold this key and drag to BIND a slot"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_L)
+ public int slotLockKey = Keyboard.KEY_L;
+
+ @Expose
+ @ConfigOption(
+ name = "Lock Slots in Trade",
+ desc = "Prevents trading locked items in the custom trade windows"
+ )
+ @ConfigEditorBoolean
+ public boolean lockSlotsInTrade = true;
+
+ @Expose
+ /*@ConfigOption(
+ name = "Item Swap drop delay",
+ desc = "Set the delay between swapping to another item and being able to drop it.\n"+
+ "This is to fix a bug that allowed you to drop slot locked items."
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 500,
+ minStep = 5
+ )*/
+ public int slotLockSwapDelay = 100;
+
+ @Expose
+ @ConfigOption(
+ name = "Slot Lock Sound",
+ desc = "Play a ding when locking/unlocking slots"
+ )
+ @ConfigEditorBoolean
+ public boolean slotLockSound = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Slot Lock Sound Vol.",
+ desc = "Set the volume of the ding sound"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 100,
+ minStep = 1
+ )
+ public float slotLockSoundVol = 20;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/StorageGUI.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/StorageGUI.java
index a2d50409..e43fa5cf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/StorageGUI.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/StorageGUI.java
@@ -1,260 +1,287 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-import org.lwjgl.input.Keyboard;
-
-public class StorageGUI {
- @ConfigOption(
- name = "Storage Overlay",
- desc = ""
- )
- @ConfigEditorAccordion(id = 1)
- public boolean storageOverlayAccordion = false;
-
- @Expose
- public int selectedIndex = 0;
- @ConfigOption(
- name = "\u00A7cWarning",
- desc = "You need Fast Render and Antialiasing off for these settings to work\n" +
- "You can find these in your video settings"
- )
- @ConfigEditorFSR(
- runnableId = 12,
- buttonText = ""
- )
- @ConfigAccordionId(id = 1)
- public boolean storageGUIWarning = false;
- @Expose
- @ConfigOption(
- name = "Enable Storage GUI",
- desc = "Show a custom storage overlay when accessing /storage. " +
- "Makes switching between pages much easier and also allows for searching through all storages"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean enableStorageGUI3 = true;
-
- @Expose
- @ConfigOption(
- name = "Storage Height",
- desc = "Change the height of the storage preview section. Increasing this allows more storages to be seen at once"
- )
- @ConfigEditorSlider(
- minValue = 104,
- maxValue = 312,
- minStep = 26
- )
- @ConfigAccordionId(id = 1)
- public int storageHeight = 208;
-
- @Expose
- @ConfigOption(
- name = "Storage Style",
- desc = "Change the visual style of the overlay"
- )
- @ConfigEditorDropdown(
- values = {"Transparent", "Minecraft", "Dark", "Custom"}
- )
- @ConfigAccordionId(id = 1)
- public int displayStyle = 0;
-
- @Expose
- @ConfigOption(
- name = "Enderchest Preview",
- desc = "Preview Enderchest pages when hovering over the selector on the left side"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean enderchestPreview = true;
-
- @Expose
- @ConfigOption(
- name = "Backpack Preview",
- desc = "Preview Backpacks when hovering over the selector on the left side"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean backpackPreview = true;
-
- @Expose
- @ConfigOption(
- name = "Compact Vertically",
- desc = "Remove the space between backpacks when there is a size discrepancy"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean masonryMode = false;
-
- @Expose
- @ConfigOption(
- name = "Fancy Glass Panes",
- desc = "Replace the glass pane textures in your storage containers with a fancy connected texture"
- )
- @ConfigEditorDropdown(
- values = {"On", "Locked", "Off"}
- )
- @ConfigAccordionId(id = 1)
- public int fancyPanes = 0;
-
- @Expose
- @ConfigOption(
- name = "Search Bar Autofocus",
- desc = "Automatically focus the search bar when pressing keys"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean searchBarAutofocus = true;
-
- @Expose
- @ConfigOption(
- name = "Show Enchant Glint",
- desc = "Toggle enchant glint in storage GUI"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 1)
- public boolean showEnchantGlint = true;
-
- @Expose
- @ConfigOption(
- name = "Selected Storage Colour",
- desc = "Change the colour used to draw the selected backpack border"
- )
- @ConfigEditorColour
- @ConfigAccordionId(id = 1)
- public String selectedStorageColour = "0:255:255:223:0";
-
- @Expose
- @ConfigOption(
- name = "Scrollable Tooltips",
- desc = "Support for scrolling tooltips for users with small monitors\n" +
- "This will prevent the menu from scrolling while holding the key, allowing you to scroll tooltips"
- )
- @ConfigEditorKeybind(defaultKey = 0)
- @ConfigAccordionId(id = 1)
- public int cancelScrollKey = 0;
-
- @ConfigOption(
- name = "Inventory Backpacks",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean inventorySlotAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Inventory Backpacks",
- desc = "Add a \"10th slot\" to your inventory which allows you to quickly access your backpacks"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean showInvBackpack = false;
-
- //public boolean showInvBackpack = false;
- @Expose
- @ConfigOption(
- name = "Scroll to Backpack",
- desc = "Allow scrolling to the backpack using the mouse wheel.\n" +
- "\"Scroll (Key)\" = Allow scrolling to 10th slot only while 'Backpack Scroll Key' (default: SHIFT) is pressed"
- )
- @ConfigEditorDropdown(
- values = {"Scroll (Key)", "Scroll (Always)", "Don't Scroll"}
- )
- @ConfigAccordionId(id = 0)
- public int scrollToBackpack2 = 0;
-
- @Expose
- @ConfigOption(
- name = "Backpack Side",
- desc = "Set which side of the hotbar the backpack slot shows"
- )
- @ConfigEditorDropdown(
- values = {"Left", "Right"}
- )
- @ConfigAccordionId(id = 0)
- public int backpackHotbarSide = 0;
-
- @Expose
- @ConfigOption(
- name = "Backpack Peeking",
- desc = "When the backpack is selected, show it's contents on your screen"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean showInvBackpackPreview = true;
-
- @Expose
- @ConfigOption(
- name = "Backpack Opacity%",
- desc = "Change the opacity of the backpack preview background"
- )
- @ConfigEditorSlider(
- minValue = 0,
- maxValue = 100,
- minStep = 5
- )
- @ConfigAccordionId(id = 0)
- public int backpackOpacity = 50;
-
- @Expose
- @ConfigOption(
- name = "Backpack Scroll Key",
- desc = "Change the key which needs to be pressed in order to allow backpacks to be scrolled between"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_LSHIFT)
- @ConfigAccordionId(id = 0)
- public int backpackScrollKey = Keyboard.KEY_LSHIFT;
-
- @Expose
- @ConfigOption(
- name = "Backpack Hotkey",
- desc = "Hotkey to quickly switch to the backpack slot"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_GRAVE)
- @ConfigAccordionId(id = 0)
- public int backpackHotkey = Keyboard.KEY_GRAVE;
-
- @Expose
- @ConfigOption(
- name = "Arrow Key Backpacks",
- desc = "Use arrow keys [LEFT],[RIGHT] to move between backpacks and [DOWN] to navigate backpack even when the slot is not selected. Keys are customizable below"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean arrowKeyBackpacks = false;
-
- @ConfigOption(
- name = "Arrow Key Backpack Keybinds",
- desc = ""
- )
- @ConfigEditorAccordion(id = 2)
- @ConfigAccordionId(id = 0)
- public boolean backpackArrowAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Backpack Left",
- desc = "Select the backpack to the left"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_LEFT)
- @ConfigAccordionId(id = 2)
- public int arrowLeftKey = Keyboard.KEY_LEFT;
-
- @Expose
- @ConfigOption(
- name = "Backpack Right",
- desc = "Select the backpack to the right"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_RIGHT)
- @ConfigAccordionId(id = 2)
- public int arrowRightKey = Keyboard.KEY_RIGHT;
-
- @Expose
- @ConfigOption(
- name = "Backpack Open",
- desc = "Open the selected backpack"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_DOWN)
- @ConfigAccordionId(id = 2)
- public int arrowDownKey = Keyboard.KEY_DOWN;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorColour;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorFSR;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import org.lwjgl.input.Keyboard;
+
+public class StorageGUI {
+ @ConfigOption(
+ name = "Storage Overlay",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean storageOverlayAccordion = false;
+
+ @Expose
+ public int selectedIndex = 0;
+ @ConfigOption(
+ name = "\u00A7cWarning",
+ desc = "You need Fast Render and Antialiasing off for these settings to work\n" +
+ "You can find these in your video settings"
+ )
+ @ConfigEditorFSR(
+ runnableId = 12,
+ buttonText = ""
+ )
+ @ConfigAccordionId(id = 1)
+ public boolean storageGUIWarning = false;
+ @Expose
+ @ConfigOption(
+ name = "Enable Storage GUI",
+ desc = "Show a custom storage overlay when accessing /storage. " +
+ "Makes switching between pages much easier and also allows for searching through all storages"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean enableStorageGUI3 = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Storage Height",
+ desc = "Change the height of the storage preview section. Increasing this allows more storages to be seen at once"
+ )
+ @ConfigEditorSlider(
+ minValue = 104,
+ maxValue = 312,
+ minStep = 26
+ )
+ @ConfigAccordionId(id = 1)
+ public int storageHeight = 208;
+
+ @Expose
+ @ConfigOption(
+ name = "Storage Style",
+ desc = "Change the visual style of the overlay"
+ )
+ @ConfigEditorDropdown(
+ values = {"Transparent", "Minecraft", "Grey", "Custom"}
+ )
+ @ConfigAccordionId(id = 1)
+ public int displayStyle = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Enderchest Preview",
+ desc = "Preview Enderchest pages when hovering over the selector on the left side"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean enderchestPreview = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Preview",
+ desc = "Preview Backpacks when hovering over the selector on the left side"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean backpackPreview = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Compact Vertically",
+ desc = "Remove the space between backpacks when there is a size discrepancy"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean masonryMode = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Fancy Glass Panes",
+ desc = "Replace the glass pane textures in your storage containers with a fancy connected texture"
+ )
+ @ConfigEditorDropdown(
+ values = {"On", "Locked", "Off"}
+ )
+ @ConfigAccordionId(id = 1)
+ public int fancyPanes = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Search Bar Autofocus",
+ desc = "Automatically focus the search bar when pressing keys"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean searchBarAutofocus = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Enchant Glint",
+ desc = "Toggle enchant glint in storage GUI"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean showEnchantGlint = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Selected Storage Colour",
+ desc = "Change the colour used to draw the selected backpack border"
+ )
+ @ConfigEditorColour
+ @ConfigAccordionId(id = 1)
+ public String selectedStorageColour = "0:255:255:223:0";
+
+ @Expose
+ @ConfigOption(
+ name = "Scrollable Tooltips",
+ desc = "Support for scrolling tooltips for users with small monitors\n" +
+ "This will prevent the menu from scrolling while holding the key, allowing you to scroll tooltips"
+ )
+ @ConfigEditorKeybind(defaultKey = 0)
+ @ConfigAccordionId(id = 1)
+ public int cancelScrollKey = 0;
+
+ @ConfigOption(
+ name = "Inventory Backpacks",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean inventorySlotAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Inventory Backpacks",
+ desc = "Add a \"10th slot\" to your inventory which allows you to quickly access your backpacks"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean showInvBackpack = false;
+
+ //public boolean showInvBackpack = false;
+ @Expose
+ @ConfigOption(
+ name = "Scroll to Backpack",
+ desc = "Allow scrolling to the backpack using the mouse wheel.\n" +
+ "\"Scroll (Key)\" = Allow scrolling to 10th slot only while 'Backpack Scroll Key' (default: SHIFT) is pressed"
+ )
+ @ConfigEditorDropdown(
+ values = {"Scroll (Key)", "Scroll (Always)", "Don't Scroll"}
+ )
+ @ConfigAccordionId(id = 0)
+ public int scrollToBackpack2 = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Side",
+ desc = "Set which side of the hotbar the backpack slot shows"
+ )
+ @ConfigEditorDropdown(
+ values = {"Left", "Right"}
+ )
+ @ConfigAccordionId(id = 0)
+ public int backpackHotbarSide = 0;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Peeking",
+ desc = "When the backpack is selected, show it's contents on your screen"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean showInvBackpackPreview = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Opacity%",
+ desc = "Change the opacity of the backpack preview background"
+ )
+ @ConfigEditorSlider(
+ minValue = 0,
+ maxValue = 100,
+ minStep = 5
+ )
+ @ConfigAccordionId(id = 0)
+ public int backpackOpacity = 50;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Scroll Key",
+ desc = "Change the key which needs to be pressed in order to allow backpacks to be scrolled between"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_LSHIFT)
+ @ConfigAccordionId(id = 0)
+ public int backpackScrollKey = Keyboard.KEY_LSHIFT;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Hotkey",
+ desc = "Hotkey to quickly switch to the backpack slot"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_GRAVE)
+ @ConfigAccordionId(id = 0)
+ public int backpackHotkey = Keyboard.KEY_GRAVE;
+
+ @Expose
+ @ConfigOption(
+ name = "Arrow Key Backpacks",
+ desc = "Use arrow keys [LEFT],[RIGHT] to move between backpacks and [DOWN] to navigate backpack even when the slot is not selected. Keys are customizable below"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean arrowKeyBackpacks = false;
+
+ @ConfigOption(
+ name = "Arrow Key Backpack Keybinds",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 2)
+ @ConfigAccordionId(id = 0)
+ public boolean backpackArrowAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Left",
+ desc = "Select the backpack to the left"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_LEFT)
+ @ConfigAccordionId(id = 2)
+ public int arrowLeftKey = Keyboard.KEY_LEFT;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Right",
+ desc = "Select the backpack to the right"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_RIGHT)
+ @ConfigAccordionId(id = 2)
+ public int arrowRightKey = Keyboard.KEY_RIGHT;
+
+ @Expose
+ @ConfigOption(
+ name = "Backpack Open",
+ desc = "Open the selected backpack"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_DOWN)
+ @ConfigAccordionId(id = 2)
+ public int arrowDownKey = Keyboard.KEY_DOWN;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Toolbar.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Toolbar.java
index 39674459..7d2f4fc4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Toolbar.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/Toolbar.java
@@ -1,101 +1,126 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-
-public class Toolbar {
- @Expose
- @ConfigOption(
- name = "Edit Toolbar Positions",
- desc = "Edit the position of the QuickCommands / Search Bar"
- )
- @ConfigEditorButton(runnableId = 6, buttonText = "Edit")
- public boolean positionButton = true;
-
- @ConfigOption(
- name = "Search Bar",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean searchBarAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Show Search Bar",
- desc = "Show Itemlist search bar in the NEU toolbar"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean searchBar = true;
-
- @Expose
- @ConfigOption(
- name = "Show a quick settings button",
- desc = "Show quick settings button in the NEU toolbar"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean enableSettingsButton = true;
-
- @Expose
- @ConfigOption(
- name = "Show a help settings button",
- desc = "Show quick settings button in the NEU toolbar"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean enableHelpButton = true;
-
- @Expose
- @ConfigOption(
- name = "Search Bar Width",
- desc = "Change the width of the search bar"
- )
- @ConfigEditorSlider(
- minValue = 50f,
- maxValue = 300f,
- minStep = 10f
- )
- @ConfigAccordionId(id = 0)
- public int searchBarWidth = 200;
-
- @Expose
- @ConfigOption(
- name = "Search Bar Height",
- desc = "Change the height of the search bar"
- )
- @ConfigEditorSlider(
- minValue = 15f,
- maxValue = 50f,
- minStep = 1f
- )
- @ConfigAccordionId(id = 0)
- public int searchBarHeight = 40;
-
- @Expose
- @ConfigOption(
- name = "Auto turnoff search mode",
- desc = "Turns off the inventory search mode after 2 minutes"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean autoTurnOffSearchMode = true;
-
- @Expose
- @ConfigOption(
- name = "Show Quick Commands",
- desc = "Show QuickCommands\u2122 in the NEU toolbar"
- )
- @ConfigEditorBoolean
- public boolean quickCommands = false;
-
- @Expose
- @ConfigOption(
- name = "Quick Commands Click Type",
- desc = "Change the click type needed to trigger quick commands"
- )
- @ConfigEditorDropdown(
- values = {"Mouse Up", "Mouse Down"}
- )
- public int quickCommandsClickType = 0;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorButton;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDropdown;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class Toolbar {
+ @Expose
+ @ConfigOption(
+ name = "Edit Toolbar Positions",
+ desc = "Change the position of the QuickCommands / Search Bar"
+ )
+ @ConfigEditorButton(runnableId = 6, buttonText = "Edit")
+ public boolean positionButton = true;
+
+ @ConfigOption(
+ name = "Search Bar",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean searchBarAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Search Bar",
+ desc = "Show Itemlist search bar in the NEU toolbar"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean searchBar = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show a quick settings button",
+ desc = "Show quick settings button in the NEU toolbar"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableSettingsButton = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show a help settings button",
+ desc = "Show quick settings button in the NEU toolbar"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean enableHelpButton = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Search Bar Width",
+ desc = "Change the width of the search bar"
+ )
+ @ConfigEditorSlider(
+ minValue = 50f,
+ maxValue = 300f,
+ minStep = 10f
+ )
+ @ConfigAccordionId(id = 0)
+ public int searchBarWidth = 200;
+
+ @Expose
+ @ConfigOption(
+ name = "Search Bar Height",
+ desc = "Change the height of the search bar"
+ )
+ @ConfigEditorSlider(
+ minValue = 15f,
+ maxValue = 50f,
+ minStep = 1f
+ )
+ @ConfigAccordionId(id = 0)
+ public int searchBarHeight = 40;
+
+ @Expose
+ @ConfigOption(
+ name = "Auto turnoff search mode",
+ desc = "Turns off the inventory search mode after 2 minutes"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean autoTurnOffSearchMode = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Quick Commands",
+ desc = "Show QuickCommands\u2122 in the NEU toolbar"
+ )
+ @ConfigEditorBoolean
+ public boolean quickCommands = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Quick Commands Click Type",
+ desc = "Change the click type needed to trigger quick commands"
+ )
+ @ConfigEditorDropdown(
+ values = {"Mouse Up", "Mouse Down"}
+ )
+ public int quickCommandsClickType = 0;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TooltipTweaks.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TooltipTweaks.java
index 52d2a5d1..1edc0921 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TooltipTweaks.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TooltipTweaks.java
@@ -1,142 +1,225 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.*;
-import org.lwjgl.input.Keyboard;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class TooltipTweaks {
- @ConfigOption(
- name = "Tooltip Price Information",
- desc = ""
- )
- @ConfigEditorAccordion(id = 0)
- public boolean priceInfoAccordion = false;
-
- @Expose
- @ConfigOption(
- name = "Price Info (Auc)",
- desc = "\u00a7rSelect what price information you would like to see on auctionable item tooltips\n" +
- "\u00a7eDrag text to rearrange"
- )
- @ConfigEditorDraggableList(
- exampleText = {
- "\u00a7eLowest BIN",
- "\u00a7eAH Price",
- "\u00a7eAH Sales",
- "\u00a7eRaw Craft Cost",
- "\u00a7eAVG Lowest BIN",
- "\u00a7eDungeon Costs"
- }
- )
- @ConfigAccordionId(id = 0)
- public List<Integer> priceInfoAuc = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 5));
-
- @Expose
- @ConfigOption(
- name = "Price Info (Baz)",
- desc = "\u00a7rSelect what price information you would like to see on bazaar item tooltips\n" +
- "\u00a7eDrag text to rearrange"
- )
- @ConfigEditorDraggableList(
- exampleText = {"\u00a7eBuy", "\u00a7eSell", "\u00a7eBuy (Insta)", "\u00a7eSell (Insta)", "\u00a7eRaw Craft Cost"}
- )
- @ConfigAccordionId(id = 0)
- public List<Integer> priceInfoBaz = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
-
- @Expose
- @ConfigOption(
- name = "Use Short Number Format",
- desc = "Use Short Numbers (5.1m) instead of 5,130,302"
- )
- @ConfigEditorBoolean
- @ConfigAccordionId(id = 0)
- public boolean shortNumberFormatPrices = false;
-
- @Expose
- @ConfigOption(
- name = "Price Info (Inv)",
- desc = "Show price information for items in your inventory"
- )
- @ConfigEditorBoolean
- public boolean showPriceInfoInvItem = true;
-
- @Expose
- @ConfigOption(
- name = "Price Info (AH)",
- desc = "Show price information for auctioned items"
- )
- @ConfigEditorBoolean
- public boolean showPriceInfoAucItem = true;
-
- @Expose
- @ConfigOption(
- name = "Price info keybind",
- desc = "Only show price info if holding a key."
- )
- @ConfigEditorBoolean
- public boolean disablePriceKey = false;
-
- @Expose
- @ConfigOption(
- name = "Show Price info Keybind",
- desc = "Hold this key to show a price info tooltip"
- )
- @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
- public int disablePriceKeyKeybind = Keyboard.KEY_NONE;
-
- @Expose
- @ConfigOption(
- name = "Show reforge stats",
- desc = "Show statistics a reforge stone will apply."
- )
- @ConfigEditorBoolean
- public boolean showReforgeStats = true;
-
- @Expose
- @ConfigOption(
- name = "Hide default reforge stats",
- desc = "Hides the reforge stats only for Legendary items that Hypixel adds to the Reforge stones"
- )
- @ConfigEditorBoolean
- public boolean hideDefaultReforgeStats = true;
-
- @Expose
- @ConfigOption(
- name = "Missing Enchant List",
- desc = "Show which enchants are missing on an item when pressing LSHIFT"
- )
- @ConfigEditorBoolean
- public boolean missingEnchantList = true;
-
- @Expose
- @ConfigOption(
- name = "Expand Pet Exp Requirement",
- desc = "Show which the full amount of pet xp required"
- )
- @ConfigEditorBoolean
- public boolean petExtendExp = false;
-
- @Expose
- @ConfigOption(
- name = "Tooltip Border Colours",
- desc = "Make the borders of tooltips match the rarity of the item (NEU Tooltips Only)"
- )
- @ConfigEditorBoolean
- public boolean tooltipBorderColours = true;
-
- @Expose
- @ConfigOption(
- name = "Tooltip Border Opacity",
- desc = "Change the opacity of the rarity highlight (NEU Tooltips Only)"
- )
- @ConfigEditorSlider(
- minValue = 0f,
- maxValue = 255f,
- minStep = 1f
- )
- public int tooltipBorderOpacity = 200;
-} \ No newline at end of file
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigAccordionId;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorAccordion;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorDraggableList;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorKeybind;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorSlider;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class TooltipTweaks {
+ @ConfigOption(
+ name = "Tooltip Price Information",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 0)
+ public boolean priceInfoAccordion = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Price Info (Auc)",
+ desc = "\u00a7rSelect what price information you would like to see on auctionable item tooltips\n" +
+ "\u00a7eDrag text to rearrange"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {
+ "\u00a7eLowest BIN",
+ "\u00a7eAH Price",
+ "\u00a7eAH Sales",
+ "\u00a7eRaw Craft Cost",
+ "\u00a7eAVG Lowest BIN",
+ "\u00a7eDungeon Costs"
+ }
+ )
+ @ConfigAccordionId(id = 0)
+ public List<Integer> priceInfoAuc = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 5));
+
+ @Expose
+ @ConfigOption(
+ name = "Price Info (Baz)",
+ desc = "\u00a7rSelect what price information you would like to see on bazaar item tooltips\n" +
+ "\u00a7eDrag text to rearrange"
+ )
+ @ConfigEditorDraggableList(
+ exampleText = {"\u00a7eBuy", "\u00a7eSell", "\u00a7eBuy (Insta)", "\u00a7eSell (Insta)", "\u00a7eRaw Craft Cost"}
+ )
+ @ConfigAccordionId(id = 0)
+ public List<Integer> priceInfoBaz = new ArrayList<>(Arrays.asList(0, 1, 2, 3, 4));
+
+ @Expose
+ @ConfigOption(
+ name = "Use Short Number Format",
+ desc = "Use Short Numbers (5.1m) instead of 5,130,302"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 0)
+ public boolean shortNumberFormatPrices = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Price Info (Inv)",
+ desc = "Show price information for items in your inventory"
+ )
+ @ConfigEditorBoolean
+ public boolean showPriceInfoInvItem = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Price Info (AH)",
+ desc = "Show price information for auctioned items"
+ )
+ @ConfigEditorBoolean
+ public boolean showPriceInfoAucItem = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Price info keybind",
+ desc = "Only show price info if holding a key."
+ )
+ @ConfigEditorBoolean
+ public boolean disablePriceKey = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Show Price info Keybind",
+ desc = "Hold this key to show a price info tooltip"
+ )
+ @ConfigEditorKeybind(defaultKey = Keyboard.KEY_NONE)
+ public int disablePriceKeyKeybind = Keyboard.KEY_NONE;
+
+ @Expose
+ @ConfigOption(
+ name = "Always show required dungeon items",
+ desc = "Always show the required items to upgrade to the next star if more than just Essence is needed"
+ )
+ @ConfigEditorBoolean
+ public boolean alwaysShowRequiredItems = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Show reforge stats",
+ desc = "Show statistics a reforge stone will apply."
+ )
+ @ConfigEditorBoolean
+ public boolean showReforgeStats = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Hide default reforge stats",
+ desc = "Hides the reforge stats only for Legendary items that Hypixel adds to the Reforge stones"
+ )
+ @ConfigEditorBoolean
+ public boolean hideDefaultReforgeStats = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Missing Enchant List",
+ desc = "Show which enchants are missing on an item when pressing LSHIFT"
+ )
+ @ConfigEditorBoolean
+ public boolean missingEnchantList = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Expand Pet Exp Requirement",
+ desc = "Show which the full amount of pet xp required"
+ )
+ @ConfigEditorBoolean
+ public boolean petExtendExp = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Tooltip Border Colours",
+ desc = "Make the borders of tooltips match the rarity of the item (NEU Tooltips Only)"
+ )
+ @ConfigEditorBoolean
+ public boolean tooltipBorderColours = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Tooltip Border Opacity",
+ desc = "Change the opacity of the rarity highlight (NEU Tooltips Only)"
+ )
+ @ConfigEditorSlider(
+ minValue = 0f,
+ maxValue = 255f,
+ minStep = 1f
+ )
+ public int tooltipBorderOpacity = 200;
+
+ @Expose
+ @ConfigOption(
+ name = "Power Stone Stats",
+ desc = "Show your real magical power and real stat increase on power stones"
+ )
+ @ConfigEditorBoolean
+ public boolean powerStoneStats = true;
+
+ @ConfigOption(
+ name = "RNG Meter",
+ desc = ""
+ )
+ @ConfigEditorAccordion(id = 1)
+ public boolean rngMeter = false;
+
+ @Expose
+ @ConfigOption(
+ name = "Fraction Display",
+ desc = "Show the fraction instead of the percentage in the slayer and dungeon rng meter inventory"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean rngMeterFractionDisplay = true;
+
+ @Expose
+ @ConfigOption(
+ name = " Profit Per Score/XP",
+ desc = "Show the amount of coins per Score/XP in the rng meter inventory"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean rngMeterProfitPerUnit = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Dungeon/Slayer Needed Counter",
+ desc = "Show the amount of dungeon runs or slayer bosses needed for the rng meter to fill up"
+ )
+ @ConfigEditorBoolean
+ @ConfigAccordionId(id = 1)
+ public boolean rngMeterRunsNeeded = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Essence Price In Shop",
+ desc = "Show the essence price in the essence shop in the dungeon hub"
+ )
+ @ConfigEditorBoolean
+ public boolean essencePriceInEssenceShop = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TradeMenu.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TradeMenu.java
index cb0c5dd1..d2b4e0bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TradeMenu.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/TradeMenu.java
@@ -1,26 +1,45 @@
-package io.github.moulberry.notenoughupdates.options.seperateSections;
-
-import com.google.gson.annotations.Expose;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
-import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
-
-public class TradeMenu {
- @Expose
- @ConfigOption(
- name = "Enable Custom Trade Menu",
- desc = "When trading with other players in skyblock, display a special GUI designed to prevent scamming"
- )
- @ConfigEditorBoolean
- public boolean enableCustomTrade = true;
-
- @Expose
- @ConfigOption(
- name = "Price Information",
- desc = "Show the price of items in the trade window on both sides"
- )
- @ConfigEditorBoolean
- public boolean customTradePrices = true;
-
- @Expose
- public boolean customTradePriceStyle = true;
-}
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.options.seperateSections;
+
+import com.google.gson.annotations.Expose;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigEditorBoolean;
+import io.github.moulberry.notenoughupdates.core.config.annotations.ConfigOption;
+
+public class TradeMenu {
+ @Expose
+ @ConfigOption(
+ name = "Enable Custom Trade Menu",
+ desc = "When trading with other players in skyblock, display a special GUI designed to prevent scamming"
+ )
+ @ConfigEditorBoolean
+ public boolean enableCustomTrade = true;
+
+ @Expose
+ @ConfigOption(
+ name = "Price Information",
+ desc = "Show the price of items in the trade window on both sides"
+ )
+ @ConfigEditorBoolean
+ public boolean customTradePrices = true;
+
+ @Expose
+ public boolean customTradePriceStyle = true;
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/AuctionSearchOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/AuctionSearchOverlay.java
index 7281eecf..fcea79dd 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/AuctionSearchOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/AuctionSearchOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import com.google.common.base.Splitter;
@@ -5,9 +24,9 @@ import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiEditSign;
import io.github.moulberry.notenoughupdates.options.NEUConfigEditor;
import io.github.moulberry.notenoughupdates.util.Constants;
-import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -24,7 +43,11 @@ import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
@@ -35,6 +58,8 @@ public class AuctionSearchOverlay {
private static final ResourceLocation SEARCH_OVERLAY_TEXTURE_TAB_COMPLETED = new ResourceLocation(
"notenoughupdates:auc_search/ah_search_overlay_tab_completed.png");
private static final ResourceLocation STAR = new ResourceLocation("notenoughupdates:auc_search/star.png");
+ private static final ResourceLocation MASTER_STAR =
+ new ResourceLocation("notenoughupdates:auc_search/master_star.png");
private static final ResourceLocation STAR_BOARD = new ResourceLocation("notenoughupdates:auc_search/star_board.png");
private static final GuiElementTextField textField = new GuiElementTextField("", 200, 20, 0);
@@ -47,6 +72,7 @@ public class AuctionSearchOverlay {
private static int selectedStars = 0;
private static boolean atLeast = true;
+ private static boolean onlyLevel100 = false;
private static final int AUTOCOMPLETE_HEIGHT = 118;
@@ -80,12 +106,10 @@ public class AuctionSearchOverlay {
return false;
}
- String lastContainer = SBInfo.getInstance().lastOpenContainerName;
-
- if (lastContainer == null) return false;
+ String lastContainer = Utils.getLastOpenChestName();
if (!lastContainer.equals("Auctions Browser") && !lastContainer.startsWith("Auctions: ")) return false;
- TileEntitySign tes = ((GuiEditSign) Minecraft.getMinecraft().currentScreen).tileSign;
+ TileEntitySign tes = ((AccessorGuiEditSign) Minecraft.getMinecraft().currentScreen).getTileSign();
if (tes == null) return false;
if (tes.getPos().getY() != 0) return false;
@@ -114,22 +138,38 @@ public class AuctionSearchOverlay {
Utils.drawTexturedRect(width / 2 - 100, topY - 1, 203, h, 0, 203 / 512f, 0, h / 256f, GL11.GL_NEAREST);
Minecraft.getMinecraft().getTextureManager().bindTexture(STAR_BOARD);
- Utils.drawTexturedRect(width / 2 + 105, topY + 27, 55, 13, GL11.GL_NEAREST);
+ Utils.drawTexturedRect(width / 2 + 105, topY + 27, 105, 13, GL11.GL_NEAREST);
Minecraft.getMinecraft().getTextureManager().bindTexture(STAR);
GlStateManager.color(1, 1, 1, 1);
- int stars = atLeast && selectedStars > 0 ? 5 : selectedStars;
+ int stars = atLeast && selectedStars > 0 ? 10 : selectedStars;
for (int i = 0; i < stars; i++) {
+ if (i >= 5) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(MASTER_STAR);
+ GlStateManager.color(1, 1, 1, 1);
+ }
if (i >= selectedStars) {
GlStateManager.color(1, 1, 1, 0.3f);
}
Utils.drawTexturedRect(width / 2 + 108 + 10 * i, topY + 29, 9, 10, GL11.GL_NEAREST);
}
- Gui.drawRect(width / 2 + 106, topY + 42, width / 2 + 115, topY + 51, 0xffffffff);
- Gui.drawRect(width / 2 + 107, topY + 43, width / 2 + 114, topY + 50, 0xff000000);
- if (atLeast) Gui.drawRect(width / 2 + 108, topY + 44, width / 2 + 113, topY + 49, 0xffffffff);
- Minecraft.getMinecraft().fontRendererObj.drawString("At Least?", width / 2 + 117, topY + 43, 0xffffff);
+ if (selectedStars < 6) {
+ Gui.drawRect(width / 2 + 106, topY + 42, width / 2 + 115, topY + 51, 0xffffffff);
+ Gui.drawRect(width / 2 + 107, topY + 43, width / 2 + 114, topY + 50, 0xff000000);
+ Minecraft.getMinecraft().fontRendererObj.drawString("At Least?", width / 2 + 117, topY + 43, 0xffffff);
+
+ if (atLeast) {
+ Gui.drawRect(width / 2 + 108, topY + 44, width / 2 + 113, topY + 49, 0xffffffff);
+ }
+ }
+
+ Gui.drawRect(width / 2 + 106, topY + 53, width / 2 + 115, topY + 62, 0xffffffff);
+ Gui.drawRect(width / 2 + 107, topY + 54, width / 2 + 114, topY + 61, 0xff000000);
+ if (onlyLevel100) {
+ Gui.drawRect(width / 2 + 108, topY + 55, width / 2 + 113, topY + 60, 0xffffffff);
+ }
+ Minecraft.getMinecraft().fontRendererObj.drawString("Level 100 pets only?", width / 2 + 117, topY + 54, 0xffffff);
Minecraft.getMinecraft().fontRendererObj.drawString("Enter Query:", width / 2 - 100, topY - 10, 0xdddddd, true);
@@ -258,17 +298,13 @@ public class AuctionSearchOverlay {
}
String searchString = autocompletedItems.toArray()[i].toString();
JsonObject repoObject = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(searchString);
- String displayname = repoObject.get("displayname").getAsString();
- if (displayname.contains("Enchanted Book")) {
- String lore = repoObject.get("lore").getAsJsonArray().get(0).getAsString();
- String name = lore.substring(0, lore.lastIndexOf(" "));
- return Utils.cleanColour(name);
- } else {
- return Utils.cleanColour(displayname);
+ if (repoObject != null) {
+ ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(repoObject);
+ return Utils.cleanColour(stack.getDisplayName().replaceAll("\\[.+]", ""));
}
- } else {
- return null;
+
}
+ return null;
}
public static void close() {
@@ -284,12 +320,18 @@ public class AuctionSearchOverlay {
}
}
- TileEntitySign tes = ((GuiEditSign) Minecraft.getMinecraft().currentScreen).tileSign;
+ TileEntitySign tes = ((AccessorGuiEditSign) Minecraft.getMinecraft().currentScreen).getTileSign();
- String search = searchString.trim();
- if (searchStringExtra != null && !searchStringExtra.isEmpty()) {
- search += " " + searchStringExtra.trim();
+ StringBuilder stringBuilder = new StringBuilder(searchString.trim());
+ if (!searchStringExtra.isEmpty()) {
+ stringBuilder.append(searchStringExtra);
+ }
+ if (onlyLevel100) {
+ stringBuilder.insert(0, "[Lvl 100] ");
}
+
+ String search = stringBuilder.toString();
+
if (search.length() <= 15) {
tes.signText[0] = new ChatComponentText(search.substring(0, Math.min(search.length(), 15)));
} else {
@@ -507,10 +549,10 @@ public class AuctionSearchOverlay {
topY = height / 2 - h / 2 + 5;
}
- if (Mouse.getEventButtonState() && mouseX > width / 2 + 105 && mouseX < width / 2 + 105 + 55 &&
+ if (Mouse.getEventButtonState() && mouseX > width / 2 + 105 && mouseX < width / 2 + 105 + 105 &&
mouseY > topY + 27 && mouseY < topY + 40) {
- int starClicked = 5;
- for (int i = 1; i <= 5; i++) {
+ int starClicked = 10;
+ for (int i = 1; i <= 10; i++) {
if (mouseX < width / 2 + 108 + 10 * i) {
starClicked = i;
break;
@@ -530,6 +572,12 @@ public class AuctionSearchOverlay {
return;
}
+ if (Mouse.getEventButtonState() && mouseX >= width / 2 + 106 && mouseX <= width / 2 + 116 &&
+ mouseY >= topY + 53 && mouseY <= topY + 62) {
+ onlyLevel100 = !onlyLevel100;
+ return;
+ }
+
if (!Mouse.getEventButtonState() && Mouse.getEventButton() == -1 && searchFieldClicked) {
textField.mouseClickMove(mouseX - 2, topY + 10, 0, 0);
}
@@ -559,7 +607,7 @@ public class AuctionSearchOverlay {
close();
Minecraft.getMinecraft().thePlayer.sendQueue.addToSendQueue(new C0DPacketCloseWindow(Minecraft.getMinecraft().thePlayer.openContainer.windowId));
NotEnoughUpdates.INSTANCE.openGui = new GuiScreenElementWrapper(new NEUConfigEditor(
- NotEnoughUpdates.INSTANCE.config, "AH Search GUI"));
+ NotEnoughUpdates.INSTANCE.config, "AH Tweaks"));
}
}
} else if (Mouse.getEventButton() == 0) {
@@ -581,12 +629,30 @@ public class AuctionSearchOverlay {
}
JsonObject essenceCosts = Constants.ESSENCECOSTS;
- searchStringExtra = "";
+ searchStringExtra = " ";
if (essenceCosts != null && essenceCosts.has(str) && selectedStars > 0) {
for (int i = 0; i < selectedStars; i++) {
+ if (i > 4) break;
searchStringExtra += "\u272A";
}
- if (selectedStars < 5 && !atLeast) {
+ switch (selectedStars) {
+ case 6:
+ searchStringExtra += "\u278A";
+ break;
+ case 7:
+ searchStringExtra += "\u278B";
+ break;
+ case 8:
+ searchStringExtra += "\u278C";
+ break;
+ case 9:
+ searchStringExtra += "\u278D";
+ break;
+ case 10:
+ searchStringExtra += "\u278E";
+ break;
+ }
+ if (selectedStars < 6 && !atLeast) {
searchStringExtra += " ";
searchStringExtra += stack.getItem().getItemStackDisplayName(stack).substring(0, 1);
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/BazaarSearchOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/BazaarSearchOverlay.java
new file mode 100644
index 00000000..66dacda3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/BazaarSearchOverlay.java
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.overlays;
+
+import com.google.common.base.Splitter;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.core.GuiScreenElementWrapper;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiEditSign;
+import io.github.moulberry.notenoughupdates.options.NEUConfigEditor;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.gui.inventory.GuiEditSign;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.item.ItemStack;
+import net.minecraft.network.play.client.C0DPacketCloseWindow;
+import net.minecraft.tileentity.TileEntitySign;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class BazaarSearchOverlay {
+ private static final ResourceLocation SEARCH_OVERLAY_TEXTURE = new ResourceLocation(
+ "notenoughupdates:auc_search/ah_search_overlay.png");
+ private static final ResourceLocation SEARCH_OVERLAY_TEXTURE_TAB_COMPLETED = new ResourceLocation(
+ "notenoughupdates:auc_search/ah_search_overlay_tab_completed.png");
+
+ private static final GuiElementTextField textField = new GuiElementTextField("", 200, 20, 0);
+ private static boolean searchFieldClicked = false;
+ private static String searchString = "";
+ private static String searchStringExtra = "";
+ private static final Splitter SPACE_SPLITTER = Splitter.on(" ").omitEmptyStrings().trimResults();
+ private static boolean tabCompleted = false;
+ private static int tabCompletionIndex = -1;
+
+ private static final int AUTOCOMPLETE_HEIGHT = 118;
+
+ private static final Set<String> autocompletedItems = new LinkedHashSet<>();
+
+ private static final Comparator<String> salesComparator = (o1, o2) -> {
+ JsonObject bazaarInfo1 = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(o1);
+ JsonObject bazaarInfo2 = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarInfo(o2);
+
+ boolean auc1Invalid = bazaarInfo1 == null || !bazaarInfo1.has("curr_sell");
+ boolean auc2Invalid = bazaarInfo2 == null || !bazaarInfo2.has("curr_sell");
+
+ if (auc1Invalid && auc2Invalid) return o1.compareTo(o2);
+ if (auc1Invalid) return -1;
+ if (auc2Invalid) return 1;
+
+ int sales1 = bazaarInfo1.get("curr_sell").getAsInt();
+ int sales2 = bazaarInfo2.get("curr_sell").getAsInt();
+
+ if (sales1 == sales2) return o1.compareTo(o2);
+ if (sales1 > sales2) return -1;
+ return 1;
+ };
+
+ public static boolean shouldReplace() {
+ if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return false;
+ if (!NotEnoughUpdates.INSTANCE.config.bazaarTweaks.enableSearchOverlay) return false;
+
+ if (!(Minecraft.getMinecraft().currentScreen instanceof GuiEditSign)) {
+ if (!NotEnoughUpdates.INSTANCE.config.bazaarTweaks.keepPreviousSearch) searchString = "";
+ return false;
+ }
+
+ String lastContainer = Utils.getLastOpenChestName();
+ if (!lastContainer.startsWith("Bazaar ➜ ")) return false;
+
+ TileEntitySign tes = ((AccessorGuiEditSign) Minecraft.getMinecraft().currentScreen).getTileSign();
+
+ if (tes == null) return false;
+ if (tes.getPos().getY() != 0) return false;
+ if (!tes.signText[2].getUnformattedText().equals("^^^^^^^^^^^^^^^")) return false;
+ return tes.signText[3].getUnformattedText().equals("Enter query");
+ }
+
+ public static void render() {
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ Utils.drawGradientRect(0, 0, width, height, -1072689136, -804253680);
+
+ int h = NotEnoughUpdates.INSTANCE.config.bazaarTweaks.showPastSearches ? 219 : 145;
+
+ int topY = height / 4;
+ if (scaledResolution.getScaleFactor() >= 4) {
+ topY = height / 2 - h / 2 + 5;
+ }
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(SEARCH_OVERLAY_TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(width / 2 - 100, topY - 1, 203, h, 0, 203 / 512f, 0, h / 256f, GL11.GL_NEAREST);
+
+ Minecraft.getMinecraft().fontRendererObj.drawString("Enter Query:", width / 2 - 100, topY - 10, 0xdddddd, true);
+
+ textField.setFocus(true);
+ textField.setText(searchString);
+ textField.setSize(149, 20);
+ textField.setCustomBorderColour(0xffffff);
+ textField.render(width / 2 - 100 + 1, topY + 1);
+
+ if (textField.getText().trim().isEmpty()) autocompletedItems.clear();
+
+ List<String> tooltipToDisplay = null;
+
+ int num = 0;
+ synchronized (autocompletedItems) {
+ String[] autoCompletedItemsArray = autocompletedItems.toArray(new String[0]);
+ for (int i = 0; i < autoCompletedItemsArray.length; i++) {
+ String str = autoCompletedItemsArray[i];
+ JsonObject obj = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(str);
+ if (obj != null) {
+ ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(obj);
+ if (i == tabCompletionIndex) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(SEARCH_OVERLAY_TEXTURE_TAB_COMPLETED);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(
+ width / 2 - 96 + 1,
+ topY + 30 + num * 22 + 1,
+ 193,
+ 21,
+ 0 / 512f,
+ 193 / 512f,
+ 0,
+ 21 / 256f,
+ GL11.GL_NEAREST
+ );
+ } else {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(SEARCH_OVERLAY_TEXTURE);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(
+ width / 2 - 96 + 1,
+ topY + 30 + num * 22 + 1,
+ 193,
+ 21,
+ 214 / 512f,
+ 407 / 512f,
+ 0,
+ 21 / 256f,
+ GL11.GL_NEAREST
+ );
+
+ }
+ String itemName = Utils.trimIgnoreColour(stack.getDisplayName().replaceAll("\\[.+]", ""));
+ if (itemName.contains("Enchanted Book") && str.contains(";")) {
+ String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound());
+ itemName = lore[0].trim();
+ }
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(
+ itemName,
+ 165
+ ),
+ width / 2 - 74, topY + 35 + num * 22 + 1, 0xdddddd, true
+ );
+
+ GlStateManager.enableDepth();
+ Utils.drawItemStack(stack, width / 2 - 94 + 2, topY + 32 + num * 22 + 1);
+
+ if (mouseX > width / 2 - 96 && mouseX < width / 2 + 96 && mouseY > topY + 30 + num * 22 &&
+ mouseY < topY + 30 + num * 22 + 20) {
+ tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+
+ if (++num >= 5) break;
+ }
+ }
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.bazaarTweaks.showPastSearches) {
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ "Past Searches:",
+ width / 2 - 100,
+ topY + 25 + AUTOCOMPLETE_HEIGHT + 5,
+ 0xdddddd,
+ true
+ );
+
+ for (int i = 0; i < 5; i++) {
+ if (i >= NotEnoughUpdates.INSTANCE.config.hidden.previousBazaarSearches.size()) break;
+
+ String s = NotEnoughUpdates.INSTANCE.config.hidden.previousBazaarSearches.get(i);
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ s,
+ width / 2 - 95 + 1,
+ topY + 45 + AUTOCOMPLETE_HEIGHT + i * 10 + 2,
+ 0xdddddd,
+ true
+ );
+ }
+
+ if (tooltipToDisplay != null) {
+ Utils.drawHoveringText(
+ tooltipToDisplay,
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+
+ }
+
+ private static final ExecutorService searchES = Executors.newSingleThreadExecutor();
+ private static final AtomicInteger searchId = new AtomicInteger(0);
+
+ private static String getItemIdAtIndex(int i) {
+ if (!autocompletedItems.isEmpty()) {
+ if ((i > autocompletedItems.size() - 1) || i < 0 || i > 4) {
+ return "";
+ }
+ String searchString = autocompletedItems.toArray()[i].toString();
+ JsonObject repoObject = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(searchString);
+ if (repoObject != null) {
+ ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(repoObject);
+ return Utils.cleanColour(stack.getDisplayName().replaceAll("\\[.+]", ""));
+ }
+
+ }
+ return null;
+ }
+
+ public static void close() {
+ if (tabCompleted) {
+ tabCompletionIndex = -1;
+ tabCompleted = false;
+ }
+ if (NotEnoughUpdates.INSTANCE.config.bazaarTweaks.keepPreviousSearch) {
+ search();
+ } else {
+ synchronized (autocompletedItems) {
+ autocompletedItems.clear();
+ }
+ }
+
+ TileEntitySign tes = ((AccessorGuiEditSign) Minecraft.getMinecraft().currentScreen).getTileSign();
+
+ StringBuilder stringBuilder = new StringBuilder(searchString.trim());
+ if (!searchStringExtra.isEmpty()) {
+ stringBuilder.append(searchStringExtra);
+ }
+
+ String search = stringBuilder.toString();
+
+ if (search.length() <= 15) {
+ tes.signText[0] = new ChatComponentText(search.substring(0, Math.min(search.length(), 15)));
+ } else {
+ List<String> words = SPACE_SPLITTER.splitToList(search);
+
+ StringBuilder line0 = new StringBuilder();
+ StringBuilder line1 = new StringBuilder();
+
+ int currentLine = 0;
+ for (String word : words) {
+ if (currentLine == 0) {
+ if (line0.length() + word.length() > 15) {
+ currentLine++;
+ } else {
+ line0.append(word);
+ if (line0.length() >= 15) {
+ currentLine++;
+ continue;
+ } else {
+ line0.append(" ");
+ }
+ }
+ }
+ if (currentLine == 1) {
+ if (line1.length() + word.length() > 15) {
+ line1.append(word, 0, 15 - line1.length());
+ break;
+ } else {
+ line1.append(word);
+ if (line1.length() >= 15) {
+ break;
+ } else {
+ line1.append(" ");
+ }
+ }
+ }
+ if (line1.length() >= 15) break;
+ }
+
+ tes.signText[0] = new ChatComponentText(line0.toString().trim());
+ tes.signText[1] = new ChatComponentText(line1.toString().trim());
+ }
+
+ if (!searchString.trim().isEmpty()) {
+ List<String> previousBazaarSearches = NotEnoughUpdates.INSTANCE.config.hidden.previousBazaarSearches;
+ previousBazaarSearches.remove(searchString);
+ previousBazaarSearches.remove(searchString);
+ previousBazaarSearches.add(0, searchString);
+ while (previousBazaarSearches.size() > 5) {
+ previousBazaarSearches.remove(previousBazaarSearches.size() - 1);
+ }
+ }
+
+ Minecraft.getMinecraft().displayGuiScreen(null);
+
+ if (Minecraft.getMinecraft().currentScreen == null) {
+ Minecraft.getMinecraft().setIngameFocus();
+ }
+ }
+
+ private static boolean updateTabCompletedSearch(int key) {
+ String id;
+ if (key == Keyboard.KEY_DOWN || key == Keyboard.KEY_TAB) {
+ id = getItemIdAtIndex(tabCompletionIndex + 1);
+ if (id == null) {
+ textField.setFocus(true);
+ textField.setText(searchString);
+ tabCompleted = false;
+ tabCompletionIndex = -1;
+ return true;
+ } else if (id.equals("")) {
+ tabCompletionIndex = 0;
+ return true;
+ } else {
+ searchString = id;
+ tabCompletionIndex += 1;
+ return true;
+ }
+ } else if (key == Keyboard.KEY_UP) {
+ id = getItemIdAtIndex(tabCompletionIndex - 1);
+ if (id == null) {
+ textField.setFocus(true);
+ textField.setText(searchString);
+ tabCompleted = false;
+ tabCompletionIndex = -1;
+ return true;
+ } else if (id.equals("")) {
+ if (autocompletedItems.size() > 4) tabCompletionIndex = 4;
+ else tabCompletionIndex = autocompletedItems.size() - 1;
+ tabCompletionIndex = autocompletedItems.size() - 1;
+ return true;
+ } else {
+ searchString = id;
+ tabCompletionIndex -= 1;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static void search() {
+ final int thisSearchId = searchId.incrementAndGet();
+
+ searchES.submit(() -> {
+ if (thisSearchId != searchId.get()) return;
+
+ List<String> title = new ArrayList<>(NotEnoughUpdates.INSTANCE.manager.search("title:" + searchString.trim()));
+
+ if (thisSearchId != searchId.get()) return;
+
+ if (!searchString.trim().contains(" ")) {
+ StringBuilder sb = new StringBuilder();
+ for (char c : searchString.toCharArray()) {
+ sb.append(c).append(" ");
+ }
+ title.addAll(NotEnoughUpdates.INSTANCE.manager.search("title:" + sb.toString().trim()));
+ }
+
+ if (thisSearchId != searchId.get()) return;
+
+ List<String> desc = new ArrayList<>(NotEnoughUpdates.INSTANCE.manager.search("desc:" + searchString.trim()));
+ desc.removeAll(title);
+
+ if (thisSearchId != searchId.get()) return;
+
+ Set<String> bazaarItems = NotEnoughUpdates.INSTANCE.manager.auctionManager.getBazaarKeySet();
+ // Amalgamated Crimsonite (Old) // TODO remove from repo
+ bazaarItems.remove("AMALGAMATED_CRIMSONITE");
+
+ title.retainAll(bazaarItems);
+ desc.retainAll(bazaarItems);
+
+ title.sort(salesComparator);
+ desc.sort(salesComparator);
+
+ if (thisSearchId != searchId.get()) return;
+
+ synchronized (autocompletedItems) {
+ autocompletedItems.clear();
+ autocompletedItems.addAll(title);
+ autocompletedItems.addAll(desc);
+ }
+ });
+ }
+
+ public static void keyEvent() {
+ boolean ignoreKey = false;
+
+ if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
+ searchStringExtra = "";
+ close();
+ if (NotEnoughUpdates.INSTANCE.config.bazaarTweaks.escFullClose) {
+ Minecraft.getMinecraft().thePlayer.sendQueue.addToSendQueue(new C0DPacketCloseWindow(Minecraft.getMinecraft().thePlayer.openContainer.windowId));
+ }
+ return;
+ } else if (Keyboard.getEventKey() == Keyboard.KEY_RETURN) {
+ searchStringExtra = "";
+ close();
+ return;
+ } else if (Keyboard.getEventKey() == Keyboard.KEY_TAB) {
+ //autocomplete to first item in the list
+ if (!tabCompleted) {
+ tabCompleted = true;
+ ignoreKey = true;
+ String id = getItemIdAtIndex(0);
+ if (id == null) {
+ tabCompleted = false;
+ textField.setFocus(true);
+ textField.setText(searchString);
+ } else {
+ tabCompletionIndex = 0;
+ searchString = id;
+ }
+ }
+ }
+
+ if (Keyboard.getEventKeyState()) {
+ if (tabCompleted) {
+ if (!ignoreKey) {
+ boolean success = updateTabCompletedSearch(Keyboard.getEventKey());
+ if (success) return;
+ textField.setFocus(true);
+ textField.setText(searchString);
+ tabCompleted = false;
+ tabCompletionIndex = -1;
+ } else return;
+
+ }
+ textField.setFocus(true);
+ textField.setText(searchString);
+ textField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey());
+ searchString = textField.getText();
+
+ search();
+ }
+ }
+
+ public static void mouseEvent() {
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ int h = NotEnoughUpdates.INSTANCE.config.bazaarTweaks.showPastSearches ? 219 : 145;
+
+ int topY = height / 4;
+ if (scaledResolution.getScaleFactor() >= 4) {
+ topY = height / 2 - h / 2 + 5;
+ }
+
+ if (!Mouse.getEventButtonState() && Mouse.getEventButton() == -1 && searchFieldClicked) {
+ textField.mouseClickMove(mouseX - 2, topY + 10, 0, 0);
+ }
+
+ if (Mouse.getEventButton() != -1) {
+ searchFieldClicked = false;
+ }
+
+ if (Mouse.getEventButtonState()) {
+ if (mouseY > topY && mouseY < topY + 20) {
+ if (mouseX > width / 2 - 100) {
+ if (mouseX < width / 2 + 49) {
+ searchFieldClicked = true;
+ textField.mouseClicked(mouseX - 2, mouseY, Mouse.getEventButton());
+
+ if (Mouse.getEventButton() == 1) {
+ searchString = "";
+ synchronized (autocompletedItems) {
+ autocompletedItems.clear();
+ }
+ }
+ } else if (mouseX < width / 2 + 75) {
+ searchStringExtra = "";
+ close();
+ } else if (mouseX < width / 2 + 100) {
+ searchStringExtra = "";
+ close();
+ Minecraft.getMinecraft().thePlayer.sendQueue.addToSendQueue(new C0DPacketCloseWindow(Minecraft.getMinecraft().thePlayer.openContainer.windowId));
+ NotEnoughUpdates.INSTANCE.openGui = new GuiScreenElementWrapper(new NEUConfigEditor(
+ NotEnoughUpdates.INSTANCE.config, "Bazaar Tweaks"));
+ }
+ }
+ } else if (Mouse.getEventButton() == 0) {
+ int num = 0;
+ synchronized (autocompletedItems) {
+ for (String str : autocompletedItems) {
+ JsonObject obj = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(str);
+ if (obj != null) {
+ ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(obj);
+ if (mouseX >= width / 2 - 96 && mouseX <= width / 2 + 96 && mouseY >= topY + 30 + num * 22 &&
+ mouseY <= topY + 30 + num * 22 + 20) {
+ searchString = Utils.cleanColour(stack.getDisplayName().replaceAll("\\[.+]", "")).trim();
+ if (searchString.contains("Enchanted Book") && str.contains(";")) {
+ String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound());
+ if (lore != null) {
+ searchString = Utils.cleanColour(lore[0]);
+ }
+ }
+
+ searchStringExtra = " ";
+
+ close();
+ return;
+ }
+
+ if (++num >= 5) break;
+ }
+ }
+ }
+
+ if (NotEnoughUpdates.INSTANCE.config.bazaarTweaks.showPastSearches) {
+ for (int i = 0; i < 5; i++) {
+ if (i >= NotEnoughUpdates.INSTANCE.config.hidden.previousBazaarSearches.size()) break;
+
+ String s = NotEnoughUpdates.INSTANCE.config.hidden.previousBazaarSearches.get(i);
+ if (mouseX >= width / 2 - 95 && mouseX <= width / 2 + 95 &&
+ mouseY >= topY + 45 + AUTOCOMPLETE_HEIGHT + i * 10 &&
+ mouseY <= topY + 45 + AUTOCOMPLETE_HEIGHT + i * 10 + 10) {
+ searchString = s;
+ searchStringExtra = "";
+ close();
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/BonemerangOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/BonemerangOverlay.java
index aa8a15ce..e8447699 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/BonemerangOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/BonemerangOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -14,7 +33,11 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.Vec3;
import org.lwjgl.util.vector.Vector3f;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import java.util.function.Supplier;
public class BonemerangOverlay extends TextOverlay {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/CombatSkillOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/CombatSkillOverlay.java
index 6d46dfd6..d73b5eb2 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/CombatSkillOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/CombatSkillOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -22,6 +41,10 @@ public class CombatSkillOverlay
private long lastUpdate = -1;
private int killLast = -1;
private int kill = -1;
+ private int championTier = -1;
+ private String championTierAmount = "1";
+ private int championXp = -1;
+ private int championXpLast = -1;
private final LinkedList<Integer> killQueue = new LinkedList<>();
private XPInformation.SkillInfo skillInfo = null;
@@ -59,14 +82,17 @@ public class CombatSkillOverlay
public void update() {
if (!NotEnoughUpdates.INSTANCE.config.skillOverlays.combatSkillOverlay) {
kill = -1;
+ championXp = -1;
overlayStrings = null;
return;
}
lastUpdate = System.currentTimeMillis();
killLast = kill;
+ championXpLast = championXp;
xpGainHourLast = xpGainHour;
kill = -1;
+ championXp = -1;
if (Minecraft.getMinecraft().thePlayer == null) return;
@@ -81,9 +107,67 @@ public class CombatSkillOverlay
kill = ea.getInteger("stats_book");
killQueue.add(0, kill);
}
+ if (ea.hasKey("champion_combat_xp", 99)) {
+ championXp = (int) ea.getDouble("champion_combat_xp");
+ }
}
}
+ if (championXp < 50000) {
+ championTier = 1;
+ } else if (championXp < 100000) {
+ championTier = 2;
+ } else if (championXp < 250000) {
+ championTier = 3;
+ } else if (championXp < 500000) {
+ championTier = 4;
+ } else if (championXp < 1000000) {
+ championTier = 5;
+ } else if (championXp < 1500000) {
+ championTier = 6;
+ } else if (championXp < 2000000) {
+ championTier = 7;
+ } else if (championXp < 2500000) {
+ championTier = 8;
+ } else if (championXp < 3000000) {
+ championTier = 9;
+ } else if (championXp > 3000000) {
+ championTier = 10;
+ }
+
+ switch (championTier) {
+ case 1:
+ championTierAmount = "50,000";
+ break;
+ case 2:
+ championTierAmount = "100,000";
+ break;
+ case 3:
+ championTierAmount = "250,000";
+ break;
+ case 4:
+ championTierAmount = "500,000";
+ break;
+ case 5:
+ championTierAmount = "1,000,000";
+ break;
+ case 6:
+ championTierAmount = "1,500,000";
+ break;
+ case 7:
+ championTierAmount = "2,000,000";
+ break;
+ case 8:
+ championTierAmount = "2,500,000";
+ break;
+ case 9:
+ championTierAmount = "3,000,000";
+ break;
+ case 10:
+ championTierAmount = "Maxed";
+ break;
+ }
+
String internalname = NotEnoughUpdates.INSTANCE.manager.getInternalNameForItem(stack);
skillInfoLast = skillInfo;
@@ -134,7 +218,7 @@ public class CombatSkillOverlay
killQueue.removeLast();
}
- if (kill != -1) {
+ if (kill != -1 || championXp != -1) {
overlayStrings = new ArrayList<>();
} else {
overlayStrings = null;
@@ -146,7 +230,7 @@ public class CombatSkillOverlay
public void updateFrequent() {
super.updateFrequent();
- if (kill < 0 && !NotEnoughUpdates.INSTANCE.config.skillOverlays.alwaysShowCombatOverlay) {
+ if ((kill < 0 && championXp < 0) && !NotEnoughUpdates.INSTANCE.config.skillOverlays.alwaysShowCombatOverlay) {
overlayStrings = null;
} else {
HashMap<Integer, String> lineMap = new HashMap<>();
@@ -161,6 +245,23 @@ public class CombatSkillOverlay
lineMap.put(0, EnumChatFormatting.AQUA + "Kills: " + EnumChatFormatting.YELLOW + format.format(counterInterp));
}
+ if (championTier <= 9) {
+ int counterInterp = (int) interp(championXp, championXpLast);
+ lineMap.put(
+ 6,
+ EnumChatFormatting.AQUA + "Champion: " + EnumChatFormatting.YELLOW + format.format(counterInterp) + "/" +
+ championTierAmount
+ );
+ }
+ if (championTier == 10) {
+ int counterInterp = (int) interp(championXp, championXpLast);
+ lineMap.put(
+ 6,
+ EnumChatFormatting.AQUA + "Champion: " + EnumChatFormatting.YELLOW + format.format(counterInterp) + " " +
+ EnumChatFormatting.RED + championTierAmount
+ );
+ }
+
float xpInterp = xpGainHour;
if (xpGainHourLast == xpGainHour && xpGainHour <= 0) {
lineMap.put(4, EnumChatFormatting.AQUA + "XP/h: " + EnumChatFormatting.YELLOW + "N/A");
@@ -255,4 +356,4 @@ public class CombatSkillOverlay
if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null;
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/CrystalHollowOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/CrystalHollowOverlay.java
index 529f132a..aae5d028 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/CrystalHollowOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/CrystalHollowOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -7,13 +26,19 @@ import io.github.moulberry.notenoughupdates.options.NEUConfig;
import io.github.moulberry.notenoughupdates.util.SBInfo;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.util.vector.Vector2f;
import java.text.DecimalFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,6 +74,60 @@ public class CrystalHollowOverlay extends TextOverlay {
super(position, dummyStrings, styleSupplier);
}
+ private final Pattern hotmCrystalNotFoundPattern = Pattern.compile("(?<crystal>[a-zA-Z]+) \\u2716 Not Found");
+ private final Pattern hotmCrystalNotPlacedPattern = Pattern.compile("(?<crystal>[a-zA-Z]+) \\u2716 Not Placed");
+ private final Pattern hotmCrystalPlacedPattern = Pattern.compile("(?<crystal>[a-zA-Z]+) \\u2714 Placed");
+
+ private void updateHotmCrystalState(IInventory lower) {
+ NEUConfig.HiddenProfileSpecific perProfileConfig = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
+ if (perProfileConfig == null) return;
+
+ ItemStack crystalStateStack = lower.getStackInSlot(50);
+ if (crystalStateStack == null || !crystalStateStack.hasTagCompound()) {
+ return;
+ }
+
+ String name = Utils.cleanColour(crystalStateStack.getDisplayName()).trim();
+ if (!name.equals("Crystal Hollows Crystals")) {
+ return;
+ }
+
+ String[] lore = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(crystalStateStack.getTagCompound());
+ for (String line : lore) {
+ if (line == null) {
+ continue;
+ }
+ String cleanLine = Utils.cleanColour(line).trim();
+ Matcher hotmCrystalNotPlacedMatcher = hotmCrystalNotPlacedPattern.matcher(cleanLine);
+ Matcher hotmCrystalNotFoundMatcher = hotmCrystalNotFoundPattern.matcher(cleanLine);
+ Matcher hotmCrystalPlacedMatcher = hotmCrystalPlacedPattern.matcher(cleanLine);
+ if (hotmCrystalNotFoundMatcher.matches() &&
+ perProfileConfig.crystals.containsKey(hotmCrystalNotFoundMatcher.group("crystal"))) {
+ perProfileConfig.crystals.put(hotmCrystalNotFoundMatcher.group("crystal"), 0);
+ } else if (hotmCrystalNotPlacedMatcher.matches() && perProfileConfig.crystals.containsKey(
+ hotmCrystalNotPlacedMatcher.group("crystal"))) {
+ perProfileConfig.crystals.put(hotmCrystalNotPlacedMatcher.group("crystal"), 1);
+ } else if (hotmCrystalPlacedMatcher.matches() &&
+ perProfileConfig.crystals.containsKey(hotmCrystalPlacedMatcher.group("crystal"))) {
+ perProfileConfig.crystals.put(hotmCrystalPlacedMatcher.group("crystal"), 2);
+ }
+ }
+ }
+
+ @Override
+ public void updateFrequent() {
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest container = (ContainerChest) chest.inventorySlots;
+ IInventory lower = container.getLowerChestInventory();
+ String containerName = lower.getDisplayName().getUnformattedText();
+
+ if (containerName.equals("Heart of the Mountain") && lower.getSizeInventory() >= 54) {
+ updateHotmCrystalState(lower);
+ }
+ }
+ }
+
@Override
public void update() {
overlayStrings = null;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java
new file mode 100644
index 00000000..5cd8f6b3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/EquipmentOverlay.java
@@ -0,0 +1,461 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.overlays;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.events.GuiInventoryBackgroundDrawnEvent;
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.miscgui.GuiInvButtonEditor;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
+import io.github.moulberry.notenoughupdates.options.NEUConfig;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.gui.inventory.GuiInventory;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.client.event.GuiScreenEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.TickEvent;
+import net.minecraftforge.fml.relauncher.Side;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class EquipmentOverlay {
+ public static EquipmentOverlay INSTANCE = new EquipmentOverlay();
+
+ // <editor-fold desc="resources">
+ private static final ResourceLocation ARMOR_DISPLAY = new ResourceLocation(
+ "notenoughupdates:armordisplay/armordisplay.png");
+ private static final ResourceLocation ARMOR_DISPLAY_GREY = new ResourceLocation(
+ "notenoughupdates:armordisplay/armordisplay_grey.png");
+ private static final ResourceLocation ARMOR_DISPLAY_DARK = new ResourceLocation(
+ "notenoughupdates:armordisplay/armordisplay_phq_dark.png");
+ private static final ResourceLocation ARMOR_DISPLAY_FSR = new ResourceLocation(
+ "notenoughupdates:armordisplay/armordisplay_fsr.png");
+ private static final ResourceLocation ARMOR_DISPLAY_TRANSPARENT = new ResourceLocation(
+ "notenoughupdates:armordisplay/armordisplay_transparent.png");
+ private static final ResourceLocation ARMOR_DISPLAY_TRANSPARENT_PET = new ResourceLocation(
+ "notenoughupdates:armordisplay/armordisplay_transparent_pet.png");
+
+ private static final ResourceLocation QUESTION_MARK = new ResourceLocation("notenoughupdates:pv_unknown.png");
+
+ private static final ResourceLocation PET_DISPLAY = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplaysolo.png");
+ private static final ResourceLocation PET_DISPLAY_GREY = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplaysolo_dark.png");
+ private static final ResourceLocation PET_DISPLAY_DARK = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplaysolo_phqdark.png");
+ private static final ResourceLocation PET_DISPLAY_FSR = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplaysolo_fsr.png");
+ private static final ResourceLocation PET_DISPLAY_TRANSPARENT = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplaysolo_transparent.png");
+
+ private static final ResourceLocation PET_ARMOR_DISPLAY = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplayarmor.png");
+ private static final ResourceLocation PET_ARMOR_DISPLAY_GREY = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplayarmor_dark.png");
+ private static final ResourceLocation PET_ARMOR_DISPLAY_DARK = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplayarmor_phqdark.png");
+ private static final ResourceLocation PET_ARMOR_DISPLAY_FSR = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplayarmor_fsr.png");
+ private static final ResourceLocation PET_ARMOR_DISPLAY_TRANSPARENT = new ResourceLocation(
+ "notenoughupdates:petdisplay/petdisplayarmor_transparent.png");
+ //</editor-fold>
+
+ //<editor-fold desc="dynamic resources">
+ public ResourceLocation getCustomEquipmentTexture(boolean isPetRendering) {
+ switch (NotEnoughUpdates.INSTANCE.config.customArmour.colourStyle) {
+ case 0:
+ return ARMOR_DISPLAY;
+ case 1:
+ return ARMOR_DISPLAY_GREY;
+ case 2:
+ return ARMOR_DISPLAY_DARK;
+ case 3:
+ return NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle == 3 && isPetRendering ? ARMOR_DISPLAY_TRANSPARENT_PET : ARMOR_DISPLAY_TRANSPARENT;
+ case 4:
+ return ARMOR_DISPLAY_FSR;
+ }
+ return null;
+ }
+
+ public ResourceLocation getCustomPetTexture(boolean isArmorRendering) {
+ switch (NotEnoughUpdates.INSTANCE.config.petOverlay.colourStyle) {
+ case 0:
+ return isArmorRendering ? PET_ARMOR_DISPLAY : PET_DISPLAY;
+ case 1:
+ return isArmorRendering ? PET_ARMOR_DISPLAY_GREY : PET_DISPLAY_GREY;
+ case 2:
+ return isArmorRendering ? PET_ARMOR_DISPLAY_DARK : PET_DISPLAY_DARK;
+ case 3:
+ return isArmorRendering ? PET_ARMOR_DISPLAY_TRANSPARENT : PET_DISPLAY_TRANSPARENT;
+ case 4:
+ return isArmorRendering ? PET_ARMOR_DISPLAY_FSR : PET_DISPLAY_FSR;
+ }
+ return null;
+ }
+ //</editor-fold>
+
+ //<editor-fold desc="pixel constants">
+ public static final int EQUIPMENT_SLOT_OFFSET_Y = 8;
+ public static final int ARMOR_OVERLAY_OVERHAND_WIDTH = 24;
+ public static final int ARMOR_OVERLAY_HEIGHT = 86;
+ public static final int ARMOR_OVERLAY_WIDTH = 31;
+ final static int PET_OVERLAY_HEIGHT = 32;
+ final static int PET_OVERLAY_WIDTH = 31;
+ public static final int PET_OVERLAY_OFFSET_Y = ARMOR_OVERLAY_HEIGHT - 14 /* overlaying pixels */;
+ //</editor-fold>
+
+
+ public boolean shouldRenderPets;
+ public boolean shouldRenderArmorHud;
+
+ public ItemStack petStack;
+
+ //<editor-fold desc="events">
+
+ @SubscribeEvent
+ public void onGuiTick(TickEvent.ClientTickEvent event) {
+ if (event.phase != TickEvent.Phase.START || event.side != Side.CLIENT) return;
+ updateGuiInfo(Minecraft.getMinecraft().currentScreen);
+ }
+
+ @SubscribeEvent
+ public void onGuiInit(GuiScreenEvent.InitGuiEvent event) {
+ updateGuiInfo(event.gui);
+ }
+
+ @SubscribeEvent
+ public void onRenderGuiPost(GuiInventoryBackgroundDrawnEvent event) {
+ if (!(event.getContainer() instanceof GuiInventory)) return;
+ GuiInventory inventory = ((GuiInventory) event.getContainer());
+ renderGuis(inventory);
+ }
+
+ //</editor-fold>
+
+ public void renderGuis(GuiInventory inventory) {
+ int width = Utils.peekGuiScale().getScaledWidth();
+ int height = Utils.peekGuiScale().getScaledHeight();
+ int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth;
+ int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1;
+
+ GL11.glColor4f(1F, 1F, 1F, 1F);
+ if (shouldRenderArmorHud) {
+ renderEquipmentGui(inventory, mouseX, mouseY, width, height);
+ }
+
+ if (shouldRenderPets) {
+ renderPets(inventory, mouseX, mouseY, width, height);
+ }
+ }
+
+ public void renderEquipmentGui(GuiInventory guiScreen, int mouseX, int mouseY, int width, int height) {
+ AccessorGuiContainer container = ((AccessorGuiContainer) guiScreen);
+
+ int overlayLeft = container.getGuiLeft() - ARMOR_OVERLAY_OVERHAND_WIDTH;
+ int overlayTop = container.getGuiTop();
+
+ ResourceLocation equipmentTexture = getCustomEquipmentTexture(shouldRenderPets);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(equipmentTexture);
+
+ Utils.drawTexturedRect(overlayLeft, overlayTop, ARMOR_OVERLAY_WIDTH, ARMOR_OVERLAY_HEIGHT, GL11.GL_NEAREST);
+
+ List<String> tooltipToDisplay = new ArrayList<>();
+ drawSlot(slot1, overlayLeft + 8, overlayTop + EQUIPMENT_SLOT_OFFSET_Y, mouseX, mouseY, tooltipToDisplay);
+ drawSlot(slot2, overlayLeft + 8, overlayTop + EQUIPMENT_SLOT_OFFSET_Y + 18, mouseX, mouseY, tooltipToDisplay);
+ drawSlot(slot3, overlayLeft + 8, overlayTop + EQUIPMENT_SLOT_OFFSET_Y + 36, mouseX, mouseY, tooltipToDisplay);
+ drawSlot(slot4, overlayLeft + 8, overlayTop + EQUIPMENT_SLOT_OFFSET_Y + 54, mouseX, mouseY, tooltipToDisplay);
+
+ if (slot1 == null) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(QUESTION_MARK);
+ GlStateManager.color(1, 1, 1, 1);
+ Utils.drawTexturedRect(overlayLeft + 8, overlayTop + EQUIPMENT_SLOT_OFFSET_Y, 16, 16, GL11.GL_NEAREST);
+
+ tooltipToDisplay = Lists.newArrayList(
+ EnumChatFormatting.RED + "Warning",
+ EnumChatFormatting.GREEN + "You need to open /equipment",
+ EnumChatFormatting.GREEN + "to cache your armour"
+ );
+ if (Utils.isWithinRect(mouseX, mouseY, overlayLeft + 8, overlayTop + 8, 16, 16)
+ && NotEnoughUpdates.INSTANCE.config.customArmour.sendWardrobeCommand
+ && Mouse.getEventButtonState()
+ && Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null) {
+ NotEnoughUpdates.INSTANCE.trySendCommand("/equipment");
+ }
+
+ }
+ if (tooltipToDisplay.size() > 0 &&
+ Utils.isWithinRect(
+ mouseX, mouseY,
+ overlayLeft, overlayTop,
+ ARMOR_OVERLAY_OVERHAND_WIDTH, ARMOR_OVERLAY_HEIGHT
+ )) {
+ Utils.drawHoveringText(
+ tooltipToDisplay,
+ mouseX - calculateTooltipXOffset(tooltipToDisplay, Minecraft.getMinecraft().fontRendererObj),
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+
+ }
+
+ private ItemStack getRepoPetStack() {
+ NEUManager manager = NotEnoughUpdates.INSTANCE.manager;
+ PetInfoOverlay.Pet currentPet = PetInfoOverlay.getCurrentPet();
+ if (currentPet == null) return null;
+
+ ItemStack item = ItemUtils.createPetItemstackFromPetInfo(currentPet);
+ item = ItemUtils.petToolTipXPExtendPetOverlay(item);
+
+ if (item != null) {
+ return item;
+ }
+ item = manager.createItem(currentPet.getPetId(true));
+ return item;
+ }
+
+ private void updateGuiInfo(GuiScreen screen) {
+ if (getWardrobeSlot(10) != null) {
+ slot1 = getWardrobeSlot(10);
+ slot2 = getWardrobeSlot(19);
+ slot3 = getWardrobeSlot(28);
+ slot4 = getWardrobeSlot(37);
+ }
+
+ if ((screen instanceof GuiChest || screen instanceof GuiInventory) && NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay){
+ petStack = getRepoPetStack();
+ }
+ if ((!(screen instanceof GuiInventory) && !(screen instanceof GuiInvButtonEditor))
+ || !NotEnoughUpdates.INSTANCE.config.misc.hidePotionEffect
+ || !NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) {
+ shouldRenderPets = shouldRenderArmorHud = false;
+ return;
+ }
+ shouldRenderPets = NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay && petStack != null;
+ shouldRenderArmorHud = NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud;
+ }
+
+ private void drawSlot(ItemStack stack, int x, int y, int mouseX, int mouseY, List<String> tooltip) {
+ if (stack == null) return;
+ Utils.drawItemStack(stack, x, y, true);
+ if (Utils.isWithinRect(mouseX, mouseY, x, y, 16, 16)) {
+ List<String> tt = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ if (shouldShowEquipmentTooltip(tt))
+ tooltip.addAll(tt);
+ if (NotEnoughUpdates.INSTANCE.config.customArmour.sendWardrobeCommand
+ && Mouse.getEventButtonState()) {
+ NotEnoughUpdates.INSTANCE.trySendCommand("/equipment");
+ }
+ }
+ }
+
+ public void renderPets(GuiInventory inventory, int mouseX, int mouseY, int width, int height) {
+ ItemUtils.getOrCreateTag(petStack).setBoolean(
+ "NEUHIDEPETTOOLTIP",
+ NotEnoughUpdates.INSTANCE.config.petOverlay.hidePetTooltip
+ );
+ ItemStack petInfo = petStack;
+
+ ResourceLocation customPetTexture = getCustomPetTexture(isRenderingArmorHud());
+ Minecraft.getMinecraft().getTextureManager().bindTexture(customPetTexture);
+ GlStateManager.color(1, 1, 1, 1);
+
+ AccessorGuiContainer container = ((AccessorGuiContainer) inventory);
+
+ int overlayLeft = container.getGuiLeft() - ARMOR_OVERLAY_OVERHAND_WIDTH;
+ int overlayTop = container.getGuiTop() + PET_OVERLAY_OFFSET_Y;
+
+ Utils.drawTexturedRect(overlayLeft, overlayTop, PET_OVERLAY_WIDTH, PET_OVERLAY_HEIGHT, GL11.GL_NEAREST);
+ GlStateManager.bindTexture(0);
+
+ Utils.drawItemStack(petInfo, overlayLeft + 8, overlayTop + 8, true);
+
+ List<String> tooltipToDisplay;
+ if (Utils.isWithinRect(mouseX, mouseY, overlayLeft + 8, overlayTop + 8, 16, 16)) {
+ if (NotEnoughUpdates.INSTANCE.config.petOverlay.sendPetsCommand
+ && Minecraft.getMinecraft().thePlayer.inventory.getItemStack() == null
+ && Mouse.getEventButtonState()) {
+ NotEnoughUpdates.INSTANCE.trySendCommand("/pets");
+ }
+ tooltipToDisplay = petInfo.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ Utils.drawHoveringText(
+ tooltipToDisplay,
+ mouseX - calculateTooltipXOffset(tooltipToDisplay, Minecraft.getMinecraft().fontRendererObj),
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+
+ private ItemStack getWardrobeSlot(int armourSlot) {
+ if (SBInfo.getInstance().currentProfile == null) {
+ return null;
+ }
+
+ if (!Objects.equals(SBInfo.getInstance().currentProfile, lastProfile)) {
+ lastProfile = SBInfo.getInstance().currentProfile;
+ slot1 = null;
+ slot2 = null;
+ slot3 = null;
+ slot4 = null;
+ }
+
+ NEUConfig.HiddenProfileSpecific profileSpecific = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
+ if (profileSpecific == null) return null;
+
+ if (isInNamedGui("Your Equipment")) {
+ ItemStack itemStack = getChestSlotsAsItemStack(armourSlot);
+ if (itemStack != null) {
+ JsonObject itemToSave = NotEnoughUpdates.INSTANCE.manager.getJsonForItem(itemStack);
+ if (!itemToSave.has("internalname")) {
+ //would crash without internalName when trying to construct the ItemStack again
+ itemToSave.add("internalname", new JsonPrimitive("_"));
+ }
+ profileSpecific.savedEquipment.put(armourSlot, itemToSave);
+ return itemStack;
+ }
+ } else {
+ if (profileSpecific.savedEquipment.containsKey(armourSlot)) {
+ //don't use cache since the internalName is identical in most cases
+ JsonObject jsonObject = profileSpecific.savedEquipment
+ .get(armourSlot);
+ if (jsonObject != null) return NotEnoughUpdates.INSTANCE.manager.jsonToStack(jsonObject
+ .getAsJsonObject(), false);
+ }
+ }
+ return null;
+ }
+
+ private boolean wardrobeOpen = false;
+
+ private boolean isInNamedGui(String guiName) {
+ GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
+ if (guiScreen instanceof GuiChest) {
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ ContainerChest container = (ContainerChest) chest.inventorySlots;
+ IInventory lower = container.getLowerChestInventory();
+ String containerName = lower.getDisplayName().getUnformattedText();
+ wardrobeOpen = containerName.contains(guiName);
+ }
+ if (guiScreen instanceof GuiInventory) {
+ wardrobeOpen = false;
+ }
+ return wardrobeOpen;
+ }
+
+ private ItemStack getChestSlotsAsItemStack(int slot) {
+ GuiScreen guiScreen = Minecraft.getMinecraft().currentScreen;
+ if (guiScreen instanceof GuiChest) {
+ GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
+ return chest.inventorySlots.getSlot(slot).getStack();
+ } else {
+ return null;
+ }
+ }
+
+ public static boolean isRenderingArmorHud() {
+ return INSTANCE.shouldRenderArmorHud;
+ }
+
+ public static boolean isRenderingPetHud() {
+ return INSTANCE.shouldRenderPets;
+ }
+
+ private boolean shouldShowEquipmentTooltip(List<String> toolTip) {
+ return !toolTip.get(0).equals("§o§7Empty Equipment Slot§r");
+ }
+
+ /**
+ * Calculates the width of the longest String in the tooltip, which can be used to offset the entire tooltip to the left more precisely
+ *
+ * @param tooltipToDisplay tooltip
+ * @param fr FontRenderer object
+ * @return offset to apply
+ */
+ private int calculateTooltipXOffset(List<String> tooltipToDisplay, FontRenderer fr) {
+ int offset = 0;
+ if (tooltipToDisplay != null) {
+ for (String line : tooltipToDisplay) {
+ int lineWidth = fr.getStringWidth(line);
+ if (lineWidth > offset) {
+ offset = lineWidth;
+ }
+ }
+ }
+ return offset + 20;
+ }
+
+ public void renderPreviewArmorHud() {
+ if (!NotEnoughUpdates.INSTANCE.config.customArmour.enableArmourHud || !(Minecraft.getMinecraft().currentScreen instanceof GuiInvButtonEditor)) return;
+ GuiInvButtonEditor container = (GuiInvButtonEditor) Minecraft.getMinecraft().currentScreen;
+
+ int overlayLeft = container.getGuiLeft() - ARMOR_OVERLAY_OVERHAND_WIDTH;
+ int overlayTop = container.getGuiTop();
+
+ ResourceLocation equipmentTexture = getCustomEquipmentTexture(shouldRenderPets);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(equipmentTexture);
+
+ Utils.drawTexturedRect(overlayLeft, overlayTop, ARMOR_OVERLAY_WIDTH, ARMOR_OVERLAY_HEIGHT, GL11.GL_NEAREST);
+ }
+
+ public void renderPreviewPetInvHud() {
+ if (!NotEnoughUpdates.INSTANCE.config.petOverlay.petInvDisplay || !(Minecraft.getMinecraft().currentScreen instanceof GuiInvButtonEditor)) return;
+ GuiInvButtonEditor container = (GuiInvButtonEditor) Minecraft.getMinecraft().currentScreen;
+ int overlayLeft = container.getGuiLeft() - ARMOR_OVERLAY_OVERHAND_WIDTH;
+ int overlayTop = container.getGuiTop() + PET_OVERLAY_OFFSET_Y;
+
+ ResourceLocation petHudTexture = getCustomPetTexture(shouldRenderArmorHud);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(petHudTexture);
+
+ Utils.drawTexturedRect(overlayLeft, overlayTop, PET_OVERLAY_WIDTH, PET_OVERLAY_HEIGHT, GL11.GL_NEAREST);
+ }
+
+ public ItemStack slot1 = null;
+ public ItemStack slot2 = null;
+ public ItemStack slot3 = null;
+ public ItemStack slot4 = null;
+ private String lastProfile;
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingOverlay.java
index f2c7e396..970c74ab 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FarmingOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import com.google.gson.JsonObject;
@@ -175,18 +194,17 @@ public class FarmingOverlay extends TextOverlay {
}
if (!NotEnoughUpdates.INSTANCE.config.skillOverlays.useBZPrice || internalname != null && (internalname.equals(
- "TREECAPITATOR_AXE"))
- || internalname != null && (internalname.equals("JUNGLE_AXE"))) {
- if (internalname != null && internalname.startsWith("THEORETICAL_HOE_WARTS") ||
- (internalname != null && internalname.equals("COCO_CHOPPER"))) {
+ "TREECAPITATOR_AXE")) || internalname != null && (internalname.equals("JUNGLE_AXE"))) {
+ if ((internalname != null && internalname.equals("COCO_CHOPPER"))) {
Coins = 3;
} else if (internalname != null && internalname.startsWith("THEORETICAL_HOE_POTATO") ||
- (internalname != null && internalname.startsWith("THEORETICAL_HOE_CARROT"))
- || (internalname != null && internalname.equals("CACTUS_KNIFE")) ||
+ (internalname != null && internalname.startsWith("THEORETICAL_HOE_CARROT")) ||
+ (internalname != null && internalname.equals("CACTUS_KNIFE")) ||
(internalname != null && internalname.startsWith("THEORETICAL_HOE_WHEAT"))) {
Coins = 1;
- } else if (internalname != null && internalname.startsWith("THEORETICAL_HOE_CANE") ||
- (internalname != null && internalname.equals("TREECAPITATOR_AXE"))
+ } else if (internalname != null && internalname.startsWith("THEORETICAL_HOE_CANE")
+ || (internalname != null && internalname.equals("TREECAPITATOR_AXE"))
+ || (internalname != null && internalname.startsWith("THEORETICAL_HOE_WARTS"))
|| (internalname != null && internalname.equals("JUNGLE_AXE"))) {
Coins = 2;
} else if ((internalname != null && internalname.equals("PUMPKIN_DICER")) ||
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FishingSkillOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FishingSkillOverlay.java
index 6f7b21d8..717ff944 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FishingSkillOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FishingSkillOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -402,4 +421,4 @@ public class FishingSkillOverlay
if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null;
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FuelBar.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FuelBar.java
index fa2db8b5..d180efcf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/FuelBar.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/FuelBar.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java
index bfbe367f..03fe9eff 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import com.google.common.collect.ComparisonChain;
@@ -24,16 +43,29 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.WorldSettings;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+import org.lwjgl.input.Keyboard;
import org.lwjgl.util.vector.Vector2f;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import static net.minecraft.util.EnumChatFormatting.*;
+import static net.minecraft.util.EnumChatFormatting.BLUE;
+import static net.minecraft.util.EnumChatFormatting.BOLD;
+import static net.minecraft.util.EnumChatFormatting.DARK_AQUA;
+import static net.minecraft.util.EnumChatFormatting.GOLD;
+import static net.minecraft.util.EnumChatFormatting.GREEN;
+import static net.minecraft.util.EnumChatFormatting.RED;
+import static net.minecraft.util.EnumChatFormatting.RESET;
+import static net.minecraft.util.EnumChatFormatting.YELLOW;
-public class MiningOverlay extends TextOverlay {
+public class MiningOverlay extends TextTabOverlay {
public MiningOverlay(
Position position,
Supplier<List<String>> dummyStrings,
@@ -54,7 +86,7 @@ public class MiningOverlay extends TextOverlay {
String containerName = lower.getDisplayName().getUnformattedText();
if (containerName.equals("Commissions") && lower.getSizeInventory() >= 27) {
- UpdateCommissions(lower);
+ updateCommissions(lower);
} else if (containerName.equals("Forge") && lower.getSizeInventory() >= 36) {
updateForge(lower);
}
@@ -127,7 +159,7 @@ public class MiningOverlay extends TextOverlay {
}
}
- private void UpdateCommissions(IInventory lower) {
+ private void updateCommissions(IInventory lower) {
// Get the location (type) of the currently shown commissions
ItemStack commTypeStack = lower.getStackInSlot(27);
if (commTypeStack == null || !commTypeStack.hasTagCompound()) {
@@ -202,93 +234,32 @@ public class MiningOverlay extends TextOverlay {
"\\xA77Time Remaining: \\xA7a((?<Completed>Completed!)|(((?<days>[0-9]+)d)? ?((?<hours>[0-9]+)h)? ?((?<minutes>[0-9]+)m)? ?((?<seconds>[0-9]+)s)?))");
private static final Pattern timeRemainingTab = Pattern.compile(
".*[1-5]\\) (?<ItemName>.*): ((?<Ready>Ready!)|(((?<days>[0-9]+)d)? ?((?<hours>[0-9]+)h)? ?((?<minutes>[0-9]+)m)? ?((?<seconds>[0-9]+)s)?))");
+ private static final Pattern forgesHeaderPattern = Pattern.compile(
+ "\\xa7r\\xa79\\xa7lForges \\xa7r(?:\\xa7f\\(\\+1 more\\)\\xa7r)?");
@Override
public void update() {
overlayStrings = null;
- NEUConfig.HiddenProfileSpecific hidden = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
-
-
- /*if(Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
- GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
- ContainerChest container = (ContainerChest) chest.inventorySlots;
- String containerName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
-
-
- long currentTime = System.currentTimeMillis();
- if(currentTime - lastSkymallSync > 60*1000) {
- if(CapeManager.getInstance().lastJsonSync != null) {
- JsonObject obj = CapeManager.getInstance().lastJsonSync;
- if(obj.has("skymall") && obj.get("skymall").isJsonPrimitive()) {
- activeSkymall = obj.get("skymall").getAsString();
- }
- }
- }
-
- if(containerName.equals("Heart of the Mountain") && container.getLowerChestInventory().getSizeInventory() > 10) {
- System.out.println("HOTM Container");
- ItemStack stack = container.getLowerChestInventory().getStackInSlot(10);
- if(stack != null && stack.getDisplayName().equals(GREEN+"Sky Mall")) {
- NotEnoughUpdates.INSTANCE.config.hidden.skymallActive = false;
-
- String[] lines = NotEnoughUpdates.INSTANCE.manager.getLoreFromNBT(stack.getTagCompound());
-
- for(String line : lines) {
- if(line.equals("\u00a7aYour Current Effect")) {
- System.out.println("Current effect");
- NotEnoughUpdates.INSTANCE.config.hidden.skymallActive = true;
- } else if(NotEnoughUpdates.INSTANCE.config.hidden.skymallActive) {
- String prevActiveSkymall = activeSkymall;
- System.out.println("Setting");
- if(line.contains("Gain \u00a7a+100 \u00a76\u2E15 Mining Speed")) {
- activeSkymall = "mining_speed";
- } else if(line.contains("Gain \u00a7a+50 \u00a76\u2618 Mining Fortune")) {
- activeSkymall = "mining_fortune";
- } else if(line.contains("Gain \u00a7a+15% \u00a77Powder from mining")) {
- activeSkymall = "powder";
- } else if(line.contains("Reduce Pickaxe Ability cooldown")) {
- activeSkymall = "pickaxe_ability";
- } else if(line.contains("10x \u00a77chance to find Goblins")) {
- activeSkymall = "goblin";
- } else if(line.contains("Gain \u00a7a5x \u00a79Titanium \u00a77drops")) {
- activeSkymall = "titanium";
- } else {
- System.out.println("Unknown");
- activeSkymall = "unknown";
- }
- if(!activeSkymall.equals(prevActiveSkymall)) {
- System.out.println("Maybe sending to server");
- if(currentTime - lastSkymallSync > 60*1000) {
- lastSkymallSync = currentTime;
- System.out.println("Sending to server");
- NotEnoughUpdates.INSTANCE.manager.hypixelApi.getMyApiAsync("skymall?"+activeSkymall, (jsonObject) -> {
- System.out.println("Success!");
- }, () -> {
- System.out.println("Error!");
- });
- }
- }
- break;
- }
- }
- }
- }
- }*/
+ NEUConfig.HiddenProfileSpecific profileConfig = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
if (!NotEnoughUpdates.INSTANCE.config.mining.dwarvenOverlay &&
NotEnoughUpdates.INSTANCE.config.mining.emissaryWaypoints == 0 &&
!NotEnoughUpdates.INSTANCE.config.mining.titaniumAlert &&
- NotEnoughUpdates.INSTANCE.config.mining.locWaypoints == 0) return;
+ NotEnoughUpdates.INSTANCE.config.mining.locWaypoints == 0) {
+ return;
+ }
+
+ // Get commission and forge info even if the overlay isn't going to be rendered since it is used elsewhere
//thanks to "Pure Genie#7250" for helping with this (makes tita alert and waypoints work without mine overlay)
if (SBInfo.getInstance().getLocation() == null) return;
- if (SBInfo.getInstance().getLocation().equals("mining_3") || SBInfo.getInstance().getLocation().equals(
- "crystal_hollows")) {
-
- overlayStrings = new ArrayList<>();
+ if (SBInfo.getInstance().getLocation().equals("mining_3") ||
+ SBInfo.getInstance().getLocation().equals("crystal_hollows")) {
commissionProgress.clear();
- String mithrilPowder = null;
- String gemstonePowder = null;
+ // These strings will be displayed one after the other when the player list is disabled
+ String mithrilPowder = RED + "[NEU] Failed to get data from your tablist";
+ String gemstonePowder = RED + "Please enable player list info in your skyblock settings";
+
int forgeInt = 0;
boolean commissions = false;
boolean forges = false;
@@ -298,48 +269,43 @@ public class MiningOverlay extends TextOverlay {
for (NetworkPlayerInfo info : players) {
String name = Minecraft.getMinecraft().ingameGUI.getTabList().getPlayerName(info);
if (name.contains("Mithril Powder:")) {
- mithrilPowder = DARK_AQUA + Utils.trimIgnoreColour(name).replaceAll("\u00a7[f|F|r]", "");
- continue;
- } else if (mithrilPowder == null) {
- mithrilPowder = RED + "[NEU] Failed to get data from your tablist";
+ mithrilPowder = DARK_AQUA + Utils.trimWhitespaceAndFormatCodes(name).replaceAll("\u00a7[f|F|r]", "");
continue;
}
if (name.contains("Gemstone Powder:")) {
- gemstonePowder = DARK_AQUA + Utils.trimIgnoreColour(name).replaceAll("\u00a7[f|F|r]", "");
- continue;
- } else if (gemstonePowder == null) {
- gemstonePowder = RED + "Please enable player list info in your skyblock settings";
+ gemstonePowder = DARK_AQUA + Utils.trimWhitespaceAndFormatCodes(name).replaceAll("\u00a7[f|F|r]", "");
continue;
}
- if (name.matches("\\xa7r\\xa79\\xa7lForges \\xa7r(?:\\xa7f\\(\\+1 more\\)\\xa7r)?") && hidden != null) {
+ Matcher forgesMatcher = forgesHeaderPattern.matcher(name);
+ if (forgesMatcher.matches() && profileConfig != null) {
commissions = false;
forges = true;
continue;
- } else if (name.equals(RESET.toString() + BLUE + BOLD + "Commissions" + RESET) && hidden != null) {
+ }
+
+ // Commissions appear after Forges, start enumerating Commissions instead of Forges
+ if (name.equals(RESET.toString() + BLUE + BOLD + "Commissions" + RESET) && profileConfig != null) {
commissions = true;
forges = false;
continue;
}
- String clean = StringUtils.cleanColour(name);
- if (forges && clean.startsWith(" ") && hidden != null) {
- char firstChar = clean.trim().charAt(0);
+ String cleanName = StringUtils.cleanColour(name);
+ if (forges && cleanName.startsWith(" ") && profileConfig != null) {
+ char firstChar = cleanName.trim().charAt(0);
if (firstChar < '0' || firstChar > '9') {
forges = false;
} else {
if (name.contains("LOCKED")) {
ForgeItem item = new ForgeItem(forgeInt, 1, true);
- replaceForgeOrAdd(item, hidden.forgeItems, true);
+ replaceForgeOrAdd(item, profileConfig.forgeItems, true);
} else if (name.contains("EMPTY")) {
ForgeItem item = new ForgeItem(forgeInt, 0, true);
- replaceForgeOrAdd(item, hidden.forgeItems, true);
- //forgeStringsEmpty.add(DARK_AQUA+"Forge "+ Utils.trimIgnoreColour(name).replaceAll("\u00a7[f|F|r]", ""));
+ replaceForgeOrAdd(item, profileConfig.forgeItems, true);
} else {
- String cleanName = Utils.cleanColour(name);
-
Matcher matcher = timeRemainingTab.matcher(cleanName);
if (matcher.matches()) {
@@ -348,7 +314,7 @@ public class MiningOverlay extends TextOverlay {
if (matcher.group("Ready") != null && !matcher.group("Ready").equals("")) {
ForgeItem item = new ForgeItem(Utils.cleanColour(itemName), 0, forgeInt, true);
- replaceForgeOrAdd(item, hidden.forgeItems, true);
+ replaceForgeOrAdd(item, profileConfig.forgeItems, true);
} else {
long duration = 0;
try {
@@ -374,15 +340,15 @@ public class MiningOverlay extends TextOverlay {
forgeInt,
true
);
- replaceForgeOrAdd(item, hidden.forgeItems, false);
+ replaceForgeOrAdd(item, profileConfig.forgeItems, false);
}
}
}
}
forgeInt++;
}
- } else if (commissions && clean.startsWith(" ") && hidden != null) {
- String[] split = clean.trim().split(": ");
+ } else if (commissions && cleanName.startsWith(" ") && profileConfig != null) {
+ String[] split = cleanName.trim().split(": ");
if (split.length == 2) {
if (split[1].endsWith("%")) {
try {
@@ -400,8 +366,8 @@ public class MiningOverlay extends TextOverlay {
forges = false;
}
}
+
if (!NotEnoughUpdates.INSTANCE.config.mining.dwarvenOverlay) {
- overlayStrings = null;
return;
}
@@ -430,22 +396,6 @@ public class MiningOverlay extends TextOverlay {
}
}
}
- /*boolean hasAny = false;
- if(NotEnoughUpdates.INSTANCE.config.mining.dwarvenOverlay) {
- overlayStrings.addAll(commissionsStrings);
- hasAny = true;
- }
- if(NotEnoughUpdates.INSTANCE.config.mining.powderOverlay) {
- if(mithrilPowder != null) {
- if(hasAny) overlayStrings.add(null);
- overlayStrings.add(DARK_AQUA+mithrilPowder);
- hasAny = true;
- }
- }
- if(NotEnoughUpdates.INSTANCE.config.mining.forgeOverlay) {
- if(hasAny) overlayStrings.add(null);
- overlayStrings.addAll(forgeStrings);
- }*/
String pickaxeCooldown;
if (ItemCooldowns.pickaxeUseCooldownMillisRemaining <= 0) {
@@ -455,6 +405,7 @@ public class MiningOverlay extends TextOverlay {
DARK_AQUA + "Pickaxe CD: \u00a7a" + (ItemCooldowns.pickaxeUseCooldownMillisRemaining / 1000) + "s";
}
+ overlayStrings = new ArrayList<>();
for (int index : NotEnoughUpdates.INSTANCE.config.mining.dwarvenText2) {
switch (index) {
case 0:
@@ -467,8 +418,8 @@ public class MiningOverlay extends TextOverlay {
overlayStrings.add(gemstonePowder);
break;
case 3:
- if (hidden != null) {
- overlayStrings.addAll(getForgeStrings(hidden.forgeItems));
+ if (profileConfig != null) {
+ overlayStrings.addAll(getForgeStrings(profileConfig.forgeItems));
}
break;
case 4:
@@ -479,8 +430,7 @@ public class MiningOverlay extends TextOverlay {
}
}
} else {
- overlayStrings = new ArrayList<>();
- if (hidden == null) {
+ if (profileConfig == null) {
return;
}
boolean forgeDisplay = false;
@@ -490,16 +440,21 @@ public class MiningOverlay extends TextOverlay {
}
}
if (forgeDisplay) {
- if (NotEnoughUpdates.INSTANCE.config.mining.forgeDisplayEnabledLocations == 1 &&
- !SBInfo.getInstance().isInDungeon) {
- overlayStrings.addAll(getForgeStrings(hidden.forgeItems));
- } else if (NotEnoughUpdates.INSTANCE.config.mining.forgeDisplayEnabledLocations == 2) {
- overlayStrings.addAll(getForgeStrings(hidden.forgeItems));
+ overlayStrings = new ArrayList<>();
+
+ if (!NotEnoughUpdates.INSTANCE.config.mining.forgeDisplayOnlyShowTab ||
+ Keyboard.isKeyDown(Minecraft.getMinecraft().gameSettings.keyBindPlayerList.getKeyCode())) {
+ if (NotEnoughUpdates.INSTANCE.config.mining.forgeDisplayEnabledLocations == 1 &&
+ !SBInfo.getInstance().isInDungeon) {
+ overlayStrings.addAll(getForgeStrings(profileConfig.forgeItems));
+ } else if (NotEnoughUpdates.INSTANCE.config.mining.forgeDisplayEnabledLocations == 2) {
+ overlayStrings.addAll(getForgeStrings(profileConfig.forgeItems));
+ }
}
}
}
- if (overlayStrings.isEmpty()) overlayStrings = null;
+ if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null;
}
private static List<String> getForgeStrings(List<ForgeItem> forgeItems) {
@@ -851,6 +806,7 @@ public class MiningOverlay extends TextOverlay {
.getItemInformation()
.get("ANVIL"))
);
+ put("First Event", new ItemStack(Items.fireworks, 1, 0));
}};
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningSkillOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningSkillOverlay.java
index fb7cdab5..a20b1d27 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningSkillOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/MiningSkillOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -358,4 +377,4 @@ public class MiningSkillOverlay
if (overlayStrings != null && overlayStrings.isEmpty()) overlayStrings = null;
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java
index 8c25594e..fef11a45 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/OverlayManager.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import com.google.common.collect.Lists;
@@ -31,8 +50,8 @@ public class OverlayManager {
"\u00a73Fetchur: \u00a7eReady!",
"\u00a73Commissions: \u00a7eReady!",
"\u00a73Experiments: \u00a7eReady!",
- "\u00a73Daily Mithril Powder: \u00a7eReady",
- "\u00a73Daily Gemstone Powder: \u00a7eReady",
+ "\u00a73Mithril Powder: \u00a7eReady",
+ "\u00a73Gemstone Powder: \u00a7eReady",
"\u00a73Cakes: \u00a7e1d21h",
"\u00a73Cookie Buff: \u00a7e2d23h",
"\u00a73Godpot: \u00a7e19h",
@@ -40,8 +59,8 @@ public class OverlayManager {
"\u00a73Fetchur: \u00a7e3h38m",
"\u00a73Commissions: \u00a7e3h38m",
"\u00a73Experiments: \u00a7e3h38m",
- "\u00a73Daily Mithril Powder: \u00a7e3h38m",
- "\u00a73Daily Gemstone Powder: \u00a7e3h38m"
+ "\u00a73Mithril Powder: \u00a7e3h38m",
+ "\u00a73Gemstone Powder: \u00a7e3h38m"
);
textOverlays.add(
timersOverlay = new TimersOverlay(NotEnoughUpdates.INSTANCE.config.miscOverlays.todoPosition, () -> {
@@ -81,7 +100,7 @@ public class OverlayManager {
List<String> farmingDummy = Lists.newArrayList(
"\u00a7bCounter: \u00a7e37,547,860",
"\u00a7bCrops/m: \u00a7e38.29",
- "\u00a7bFarm: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
+ "\u00a7bFarming: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
"\u00a7bCurrent XP: \u00a7e6,734",
"\u00a7bRemaining XP: \u00a7e3,265",
"\u00a7bXP/h: \u00a7e238,129",
@@ -103,7 +122,7 @@ public class OverlayManager {
List<String> miningSkillDummy = Lists.newArrayList(
"\u00a7bCompact: \u00a7e547,860",
"\u00a7bBlocks/m: \u00a7e38.29",
- "\u00a7bMine: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
+ "\u00a7bMining: \u00a7e12\u00a77 [\u00a7e|||||||||||||||||\u00a78||||||||\u00a77] \u00a7e67%",
"\u00a7bCurrent XP: \u00a7e6,734",
"\u00a7bRemaining XP: \u00a7e3,265",
"\u00a7bXP/h: \u00a7e238,129",
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/RancherBootOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/RancherBootOverlay.java
index 94bd53a2..2a30f6f1 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/RancherBootOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/RancherBootOverlay.java
@@ -1,7 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.core.GuiElementTextField;
import io.github.moulberry.notenoughupdates.core.util.GuiElementSlider;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiEditSign;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
@@ -31,7 +51,7 @@ public class RancherBootOverlay {
if (!(Minecraft.getMinecraft().currentScreen instanceof GuiEditSign)) return false;
- TileEntitySign tes = ((GuiEditSign) Minecraft.getMinecraft().currentScreen).tileSign;
+ TileEntitySign tes = ((AccessorGuiEditSign) Minecraft.getMinecraft().currentScreen).getTileSign();
if (tes == null) return false;
if (tes.getPos().getY() != 0) return false;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/SlayerOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/SlayerOverlay.java
index 89fce0f2..00e13016 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/SlayerOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/SlayerOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -8,7 +27,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.util.EnumChatFormatting;
import java.text.NumberFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.function.Supplier;
public class SlayerOverlay extends TextOverlay {
@@ -66,6 +89,9 @@ public class SlayerOverlay extends TextOverlay {
case "Enderman":
if (!locrawLocation.equals("combat_3")) return false;
break;
+ case "Blaze":
+ if (!locrawLocation.equals("crimson_isle")) return false;
+ break;
default:
//A new slayer would need an update (see SBInfo)
return false;
@@ -97,10 +123,11 @@ public class SlayerOverlay extends TextOverlay {
slayerIntXP = 0;
isSlayerNine = false;
}
- //System.out.println(slayerEXP);
+
if (SBInfo.getInstance().slayer.equals("Tarantula") || SBInfo.getInstance().slayer.equals("Revenant")) {
useSmallXpNext = true;
- } else if (SBInfo.getInstance().slayer.equals("Sven") || SBInfo.getInstance().slayer.equals("Enderman")) {
+ } else if (SBInfo.getInstance().slayer.equals("Sven") || SBInfo.getInstance().slayer.equals("Enderman") ||
+ SBInfo.getInstance().slayer.equals("Blaze")) {
useSmallXpNext = false;
}
switch (slayerLVL) {
@@ -185,7 +212,7 @@ public class SlayerOverlay extends TextOverlay {
HashMap<Integer, String> lineMap = new HashMap<>();
NumberFormat format = NumberFormat.getIntegerInstance();
- //System.out.println(SBInfo.getInstance().isSlain);
+
overlayStrings = new ArrayList<>();
lineMap.put(
0,
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlay.java
index 5fe066f2..f8e02fef 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.core.config.Position;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlayStyle.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlayStyle.java
index 4a3a2b73..2ccc3ace 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlayStyle.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextOverlayStyle.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
public enum TextOverlayStyle {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextTabOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextTabOverlay.java
new file mode 100644
index 00000000..fa263db7
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TextTabOverlay.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.overlays;
+
+import io.github.moulberry.notenoughupdates.core.config.Position;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiChat;
+import org.lwjgl.input.Keyboard;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+public abstract class TextTabOverlay extends TextOverlay {
+ public TextTabOverlay(
+ Position position,
+ Supplier<List<String>> dummyStrings,
+ Supplier<TextOverlayStyle> styleSupplier
+ ) {
+ super(position, dummyStrings, styleSupplier);
+ }
+
+ private boolean lastTabState = false;
+ private boolean shouldUpdateOverlay = true;
+
+ @Override
+ public void tick() {
+ if (shouldUpdateOverlay) {
+ update();
+ }
+ }
+
+ public void realTick() {
+ shouldUpdateOverlay = shouldUpdate();
+ if (shouldUpdateOverlay) {
+ int keycode = Minecraft.getMinecraft().gameSettings.keyBindPlayerList.getKeyCode();
+ boolean currentTabState;
+ if (keycode > 0) {
+ currentTabState = Keyboard.isKeyDown(keycode);
+ } else {
+ currentTabState = false;
+ }
+ if (lastTabState != currentTabState) {
+ lastTabState = currentTabState;
+ update();
+ }
+ }
+ }
+
+ private boolean shouldUpdate() {
+ //prevent rendering when tab completing a command
+ if (Minecraft.getMinecraft().currentScreen instanceof GuiChat) {
+ return false;
+ }
+
+ //prevent rendering when tab completing in ah search overlay
+ if (AuctionSearchOverlay.shouldReplace()) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java
index ede30448..4d82ebaf 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/overlays/TimersOverlay.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.overlays;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
@@ -13,10 +32,12 @@ import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.client.event.ClientChatReceivedEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import org.lwjgl.input.Keyboard;
import org.lwjgl.util.vector.Vector2f;
import java.time.ZoneId;
@@ -30,7 +51,7 @@ import java.util.regex.Pattern;
import static net.minecraft.util.EnumChatFormatting.DARK_AQUA;
-public class TimersOverlay extends TextOverlay {
+public class TimersOverlay extends TextTabOverlay {
private static final Pattern PATTERN_ACTIVE_EFFECTS = Pattern.compile(
"\u00a7r\u00a7r\u00a77You have a \u00a7r\u00a7cGod Potion \u00a7r\u00a77active! \u00a7r\u00a7d([0-9]*?:?[0-9]*?:?[0-9]*)\u00a7r");
@@ -176,16 +197,21 @@ public class TimersOverlay extends TextOverlay {
case "Cookie Buff":
icon = COOKIE_ICON;
break;
- case "Daily Mithril Powder":
+ case "Mithril Powder":
icon = NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
.getItemInformation()
.get("MITHRIL_ORE"));
break;
- case "Daily Gemstone Powder":
+ case "Gemstone Powder":
icon = NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
.getItemInformation()
.get("PERFECT_AMETHYST_GEM"));
break;
+ case "Heavy Pearls":
+ icon = NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .get("HEAVY_PEARL"));
+ break;
}
if (icon != null) {
@@ -209,6 +235,12 @@ public class TimersOverlay extends TextOverlay {
NEUConfig.HiddenProfileSpecific hidden = NotEnoughUpdates.INSTANCE.config.getProfileSpecific();
if (hidden == null) return;
+ if (NotEnoughUpdates.INSTANCE.config.miscOverlays.todoOverlayOnlyShowTab &&
+ !Keyboard.isKeyDown(Minecraft.getMinecraft().gameSettings.keyBindPlayerList.getKeyCode())) {
+ overlayStrings = null;
+ return;
+ }
+
if (Minecraft.getMinecraft().currentScreen instanceof GuiChest) {
GuiChest chest = (GuiChest) Minecraft.getMinecraft().currentScreen;
ContainerChest container = (ContainerChest) chest.inventorySlots;
@@ -529,6 +561,7 @@ public class TimersOverlay extends TextOverlay {
}
long midnightReset = (currentTime - 18000000) / 86400000 * 86400000 + 18000000; // 12am est
+ long pearlsReset = midnightReset - 18000000; //8pm est
long catacombsReset = currentTime / 86400000 * 86400000; // 7pm est
long timeDiffMidnightNow = midnightReset + 86400000 - currentTime;
long catacombsDiffNow = catacombsReset + 86400000 - currentTime;
@@ -627,7 +660,7 @@ public class TimersOverlay extends TextOverlay {
6,
DARK_AQUA + "Experiments: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.verySoonColour] +
- Utils.prettyTime(catacombsReset)
+ Utils.prettyTime(catacombsReset + 86400000 - currentTime)
);
} else if (NotEnoughUpdates.INSTANCE.config.miscOverlays.experimentationDisplay >= DISPLAYTYPE.SOON.ordinal() &&
(hidden.experimentsCompleted < (midnightReset - TimeEnums.HOUR.time))) {
@@ -635,7 +668,7 @@ public class TimersOverlay extends TextOverlay {
6,
DARK_AQUA + "Experiments: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.soonColour] +
- Utils.prettyTime(catacombsReset)
+ Utils.prettyTime(catacombsReset + 86400000 - currentTime)
);
} else if (
NotEnoughUpdates.INSTANCE.config.miscOverlays.experimentationDisplay >= DISPLAYTYPE.KINDASOON.ordinal() &&
@@ -644,14 +677,14 @@ public class TimersOverlay extends TextOverlay {
6,
DARK_AQUA + "Experiments: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.kindaSoonColour] +
- Utils.prettyTime(catacombsReset)
+ Utils.prettyTime(catacombsReset + 86400000 - currentTime)
);
} else if (NotEnoughUpdates.INSTANCE.config.miscOverlays.experimentationDisplay >= DISPLAYTYPE.ALWAYS.ordinal()) {
map.put(
6,
DARK_AQUA + "Experiments: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.defaultColour] +
- Utils.prettyTime(catacombsReset)
+ Utils.prettyTime(catacombsReset + 86400000 - currentTime)
);
}
@@ -661,7 +694,7 @@ public class TimersOverlay extends TextOverlay {
if (hidden.dailyMithrilPowerCompleted < midnightReset) {
map.put(
7,
- DARK_AQUA + "Daily Mithril Powder: " +
+ DARK_AQUA + "Mithril Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.readyColour] + "Ready!"
);
} else if (
@@ -669,7 +702,7 @@ public class TimersOverlay extends TextOverlay {
(hidden.dailyMithrilPowerCompleted < (midnightReset - TimeEnums.HALFANHOUR.time))) {
map.put(
7,
- DARK_AQUA + "Daily Mithril Powder: " +
+ DARK_AQUA + "Mithril Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.verySoonColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -677,7 +710,7 @@ public class TimersOverlay extends TextOverlay {
(hidden.dailyMithrilPowerCompleted < (midnightReset - TimeEnums.HOUR.time))) {
map.put(
7,
- DARK_AQUA + "Daily Mithril Powder: " +
+ DARK_AQUA + "Mithril Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.soonColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -686,7 +719,7 @@ public class TimersOverlay extends TextOverlay {
(hidden.dailyMithrilPowerCompleted < (midnightReset - (TimeEnums.HOUR.time * 3)))) {
map.put(
7,
- DARK_AQUA + "Daily Mithril Powder: " +
+ DARK_AQUA + "Mithril Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.kindaSoonColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -694,7 +727,7 @@ public class TimersOverlay extends TextOverlay {
DISPLAYTYPE.ALWAYS.ordinal()) {
map.put(
7,
- DARK_AQUA + "Daily Mithril Powder: " +
+ DARK_AQUA + "Mithril Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.defaultColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -704,7 +737,7 @@ public class TimersOverlay extends TextOverlay {
if (hidden.dailyGemstonePowderCompleted < midnightReset) {
map.put(
8,
- DARK_AQUA + "Daily Gemstone Powder: " +
+ DARK_AQUA + "Gemstone Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.readyColour] + "Ready!"
);
} else if (
@@ -712,7 +745,7 @@ public class TimersOverlay extends TextOverlay {
(hidden.dailyGemstonePowderCompleted < (midnightReset - TimeEnums.HALFANHOUR.time))) {
map.put(
8,
- DARK_AQUA + "Daily Gemstone Powder: " +
+ DARK_AQUA + "Gemstone Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.verySoonColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -720,7 +753,7 @@ public class TimersOverlay extends TextOverlay {
(hidden.dailyGemstonePowderCompleted < (midnightReset - TimeEnums.HOUR.time))) {
map.put(
8,
- DARK_AQUA + "Daily Gemstone Powder: " +
+ DARK_AQUA + "Gemstone Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.soonColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -729,7 +762,7 @@ public class TimersOverlay extends TextOverlay {
(hidden.dailyGemstonePowderCompleted < (midnightReset - (TimeEnums.HOUR.time * 3)))) {
map.put(
8,
- DARK_AQUA + "Daily Gemstone Powder: " +
+ DARK_AQUA + "Gemstone Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.kindaSoonColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
@@ -737,12 +770,55 @@ public class TimersOverlay extends TextOverlay {
DISPLAYTYPE.ALWAYS.ordinal()) {
map.put(
8,
- DARK_AQUA + "Daily Gemstone Powder: " +
+ DARK_AQUA + "Gemstone Powder: " +
EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.defaultColour] +
Utils.prettyTime(timeDiffMidnightNow)
);
}
+ //Daily Heavy Pearl Display
+ if (hidden.dailyHeavyPearlCompleted < pearlsReset) {
+ map.put(
+ 9,
+ DARK_AQUA + "Heavy Pearls: " +
+ EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.readyColour] + "Ready!"
+ );
+ } else if (
+ NotEnoughUpdates.INSTANCE.config.miscOverlays.dailyHeavyPearlDisplay >= DISPLAYTYPE.VERYSOON.ordinal() &&
+ (hidden.dailyHeavyPearlCompleted < (pearlsReset - TimeEnums.HALFANHOUR.time))) {
+ map.put(
+ 9,
+ DARK_AQUA + "Heavy Pearls: " +
+ EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.verySoonColour] +
+ Utils.prettyTime(pearlsReset + 86400000 - currentTime)
+ );
+ } else if (NotEnoughUpdates.INSTANCE.config.miscOverlays.dailyHeavyPearlDisplay >= DISPLAYTYPE.SOON.ordinal() &&
+ (hidden.dailyHeavyPearlCompleted < (pearlsReset - TimeEnums.HOUR.time))) {
+ map.put(
+ 9,
+ DARK_AQUA + "Heavy Pearls: " +
+ EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.soonColour] +
+ Utils.prettyTime(pearlsReset + 86400000 - currentTime)
+ );
+ } else if (
+ NotEnoughUpdates.INSTANCE.config.miscOverlays.dailyHeavyPearlDisplay >= DISPLAYTYPE.KINDASOON.ordinal() &&
+ (hidden.dailyHeavyPearlCompleted < (pearlsReset - (TimeEnums.HOUR.time * 3)))) {
+ map.put(
+ 9,
+ DARK_AQUA + "Heavy Pearls: " +
+ EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.kindaSoonColour] +
+ Utils.prettyTime(pearlsReset + 86400000 - currentTime)
+ );
+ } else if (NotEnoughUpdates.INSTANCE.config.miscOverlays.dailyHeavyPearlDisplay >=
+ DISPLAYTYPE.ALWAYS.ordinal()) {
+ map.put(
+ 9,
+ DARK_AQUA + "Heavy Pearls: " +
+ EnumChatFormatting.values()[NotEnoughUpdates.INSTANCE.config.miscOverlays.defaultColour] +
+ Utils.prettyTime(pearlsReset + 86400000 - currentTime)
+ );
+ }
+
overlayStrings = new ArrayList<>();
for (int index : NotEnoughUpdates.INSTANCE.config.miscOverlays.todoText2) {
if (map.containsKey(index)) {
@@ -752,8 +828,41 @@ public class TimersOverlay extends TextOverlay {
if (overlayStrings.isEmpty()) overlayStrings = null;
}
- public String compactRemaining(int amount) {
- return (5 - amount) + " remaining";
+ public static int beforePearls = -1;
+ public static int afterPearls = -1;
+ public static int availablePearls = -1;
+
+ public static int heavyPearlCount() {
+ int heavyPearls = 0;
+
+ List<ItemStack> inventory = Minecraft.getMinecraft().thePlayer.inventoryContainer.getInventory();
+ for (ItemStack item : inventory) {
+ if (item == null) {
+ continue;
+ } else if (!item.hasTagCompound()) {
+ continue;
+ }
+ NBTTagCompound itemData = item.getSubCompound("ExtraAttributes", false);
+ if (itemData == null) {
+ continue;
+ }
+ if (itemData.getString("id").equals("HEAVY_PEARL")) {
+ heavyPearls += item.stackSize;
+ }
+ }
+ return heavyPearls;
+ }
+
+ public static void processActionBar(String msg) {
+ if (SBInfo.getInstance().location.equals("Belly of the Beast")) {
+ try {
+ msg = Utils.cleanColour(msg);
+ msg = msg.substring(msg.indexOf("Pearls Collected: ") + 18);
+ availablePearls = Integer.parseInt(msg.substring(msg.indexOf("/") + 1));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
}
private enum TimeEnums {
@@ -777,4 +886,3 @@ public class TimersOverlay extends TextOverlay {
ALWAYS,
}
}
-
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
new file mode 100644
index 00000000..a72e0a24
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BasicPage.java
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.common.base.Splitter;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.mojang.authlib.GameProfile;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.lily.LilyWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.PronounDB;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.entity.EntityOtherPlayerMP;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.OpenGlHelper;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.client.renderer.entity.RenderManager;
+import net.minecraft.client.resources.DefaultPlayerSkin;
+import net.minecraft.enchantment.Enchantment;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.player.EnumPlayerModelParts;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import static io.github.moulberry.notenoughupdates.util.Utils.roundToNearestInt;
+
+public class BasicPage extends GuiProfileViewerPage {
+
+ private static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png");
+ private static final ExecutorService profileLoader = Executors.newFixedThreadPool(1);
+ public EntityOtherPlayerMP entityPlayer = null;
+ private ResourceLocation playerLocationSkin = null;
+ private ResourceLocation playerLocationCape = null;
+ private String skinType = null;
+ private boolean loadingProfile = false;
+
+ private int backgroundClickedX = -1;
+
+ public BasicPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ ProfileViewer.Profile profile = GuiProfileViewer.getProfile();
+ String profileId = GuiProfileViewer.getProfileId();
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ String location = null;
+ JsonObject status = profile.getPlayerStatus();
+ if (status != null && status.has("mode")) {
+ location = status.get("mode").getAsString();
+ }
+
+ int extraRotation = 0;
+ if (Mouse.isButtonDown(0) || Mouse.isButtonDown(1)) {
+ if (backgroundClickedX == -1) {
+ if (mouseX > guiLeft + 23 && mouseX < guiLeft + 23 + 81) {
+ if (mouseY > guiTop + 44 && mouseY < guiTop + 44 + 108) {
+ backgroundClickedX = mouseX;
+ }
+ }
+ }
+ } else {
+ if (backgroundClickedX != -1) {
+ getInstance().backgroundRotation += mouseX - backgroundClickedX;
+ backgroundClickedX = -1;
+ }
+ }
+ if (backgroundClickedX == -1) {
+ getInstance().backgroundRotation += (getInstance().currentTime - getInstance().lastTime) / 400f;
+ } else {
+ extraRotation = mouseX - backgroundClickedX;
+ }
+ getInstance().backgroundRotation %= 360;
+
+ String panoramaIdentifier = "day";
+ if (SBInfo.getInstance().currentTimeDate != null) {
+ if (SBInfo.getInstance().currentTimeDate.getHours() <= 6 ||
+ SBInfo.getInstance().currentTimeDate.getHours() >= 20) {
+ panoramaIdentifier = "night";
+ }
+ }
+
+ Panorama.drawPanorama(
+ -getInstance().backgroundRotation - extraRotation,
+ guiLeft + 23,
+ guiTop + 44,
+ 81,
+ 108,
+ 0.37f,
+ 0.8f,
+ Panorama.getPanoramasForLocation(location == null ? "unknown" : location, panoramaIdentifier)
+ );
+
+ if (Utils.isWithinRect(mouseX, mouseY, guiLeft + 23, guiTop + 44, 81, 108)) {
+ Optional<PronounDB.PronounChoice> pronounChoice =
+ GuiProfileViewer.pronouns
+ .peekValue()
+ .flatMap(it -> it); // Flatten: First optional is whether it loaded, second optional is whether it was successful
+ if (pronounChoice.isPresent()) {
+ PronounDB.PronounChoice pronouns = pronounChoice.get();
+ if (pronouns.isConsciousChoice()) {
+ getInstance().tooltipToDisplay = pronouns.render();
+ }
+ }
+ }
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_basic);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+
+ if (entityPlayer != null && profile.getHypixelProfile() != null) {
+ String playerName = null;
+ if (profile.getHypixelProfile().has("prefix")) {
+ playerName = Utils.getElementAsString(profile.getHypixelProfile().get("prefix"), "") + " " +
+ entityPlayer.getName();
+ } else {
+ String rank = Utils.getElementAsString(
+ profile.getHypixelProfile().get("rank"),
+ Utils.getElementAsString(profile.getHypixelProfile().get("newPackageRank"), "NONE")
+ );
+ String monthlyPackageRank = Utils.getElementAsString(
+ profile.getHypixelProfile().get("monthlyPackageRank"),
+ "NONE"
+ );
+ if (!rank.equals("YOUTUBER") && !monthlyPackageRank.equals("NONE")) {
+ rank = monthlyPackageRank;
+ }
+ EnumChatFormatting rankPlusColorECF = EnumChatFormatting.getValueByName(
+ Utils.getElementAsString(profile.getHypixelProfile().get("rankPlusColor"), "GOLD")
+ );
+ String rankPlusColor = EnumChatFormatting.GOLD.toString();
+ if (rankPlusColorECF != null) {
+ rankPlusColor = rankPlusColorECF.toString();
+ }
+
+ JsonObject misc = Constants.MISC;
+ if (misc != null) {
+ if (misc.has("ranks")) {
+ String rankName = Utils.getElementAsString(Utils.getElement(misc, "ranks." + rank + ".tag"), null);
+ String rankColor = Utils.getElementAsString(Utils.getElement(misc, "ranks." + rank + ".color"), "7");
+ String rankPlus = Utils.getElementAsString(Utils.getElement(misc, "ranks." + rank + ".plus"), "");
+
+ String name = entityPlayer.getName();
+
+ if (misc.has("special_bois")) {
+ JsonArray special_bois = misc.get("special_bois").getAsJsonArray();
+ for (int i = 0; i < special_bois.size(); i++) {
+ if (special_bois.get(i).getAsString().equals(profile.getUuid())) {
+ name = Utils.chromaString(name);
+ break;
+ }
+ }
+ }
+
+ playerName = EnumChatFormatting.GRAY + name;
+ if (rankName != null) {
+ playerName =
+ "\u00A7" + rankColor + "[" + rankName + rankPlusColor + rankPlus + "\u00A7" + rankColor + "] " + name;
+ }
+ }
+ }
+ }
+ if (playerName != null) {
+ int rankPrefixLen = fr.getStringWidth(playerName);
+ int halfRankPrefixLen = rankPrefixLen / 2;
+
+ int x = guiLeft + 63;
+ int y = guiTop + 54;
+
+ GuiScreen.drawRect(
+ x - halfRankPrefixLen - 1,
+ y - 1,
+ x + halfRankPrefixLen + 1,
+ y + 8,
+ new Color(0, 0, 0, 64).getRGB()
+ );
+
+ fr.drawString(playerName, x - halfRankPrefixLen, y, 0, true);
+ }
+ }
+
+ long networth = profile.getNetWorth(profileId);
+ if (networth > 0) {
+ Utils.drawStringCentered(
+ EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(networth),
+ fr,
+ guiLeft + 63,
+ guiTop + 38,
+ true,
+ 0
+ );
+ try {
+ double networthInCookies =
+ (
+ networth /
+ NotEnoughUpdates.INSTANCE.manager.auctionManager
+ .getBazaarInfo("BOOSTER_COOKIE")
+ .get("avg_buy")
+ .getAsDouble()
+ );
+ String networthIRLMoney = Long.toString(Math.round(((networthInCookies * 325) / 675) * 4.99));
+ if (
+ mouseX > guiLeft + 8 &&
+ mouseX < guiLeft + 8 + fr.getStringWidth("Net Worth: " + GuiProfileViewer.numberFormat.format(networth))
+ ) {
+ if (mouseY > guiTop + 32 && mouseY < guiTop + 32 + fr.FONT_HEIGHT) {
+ getInstance().tooltipToDisplay = new ArrayList<>();
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Net worth in IRL money: " +
+ EnumChatFormatting.DARK_GREEN +
+ "$" +
+ EnumChatFormatting.GOLD +
+ networthIRLMoney
+ );
+ getInstance().tooltipToDisplay.add("");
+ if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+ getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "This is calculated using the current");
+ getInstance().tooltipToDisplay.add(
+ EnumChatFormatting.RED + "price of booster cookies on bazaar and the price");
+ getInstance().tooltipToDisplay.add(
+ EnumChatFormatting.RED + "for cookies using gems, then the price of gems");
+ getInstance().tooltipToDisplay.add(
+ EnumChatFormatting.RED + "is where we get the amount of IRL money you");
+ getInstance().tooltipToDisplay.add(
+ EnumChatFormatting.RED + "theoretically have on skyblock in net worth.");
+ } else {
+ getInstance().tooltipToDisplay.add(EnumChatFormatting.GRAY + "[SHIFT for Info]");
+ }
+ if (!NotEnoughUpdates.INSTANCE.config.hidden.dev) {
+ getInstance().tooltipToDisplay.add("");
+ getInstance().tooltipToDisplay.add(EnumChatFormatting.RED + "THIS IS IN NO WAY ENDORSING IRL TRADING!");
+ }
+ }
+ }
+ } catch (Exception ignored) {
+ }
+ }
+
+ if (status != null) {
+ JsonElement onlineElement = Utils.getElement(status, "online");
+ boolean online = onlineElement != null && onlineElement.isJsonPrimitive() && onlineElement.getAsBoolean();
+ String statusStr = online ? EnumChatFormatting.GREEN + "ONLINE" : EnumChatFormatting.RED + "OFFLINE";
+ String locationStr = null;
+ if (profile.getUuid().equals("20934ef9488c465180a78f861586b4cf")) {
+ locationStr = "Ignoring DMs";
+ } else if (profile.getUuid().equals("b876ec32e396476ba1158438d83c67d4")) {
+ statusStr = EnumChatFormatting.LIGHT_PURPLE + "Long live Potato King";
+ ItemStack potato_crown = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("POTATO_CROWN")
+ );
+ potato_crown.addEnchantment(Enchantment.unbreaking, 1656638942); // this number may be useful
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(
+ new ItemStack(Items.potato),
+ guiLeft + 35,
+ guiTop + 160
+ );
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(potato_crown, guiLeft + 50, guiTop + 162);
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(
+ new ItemStack(Items.potato),
+ guiLeft + 63,
+ guiTop + 160
+ );
+ } else if (online) {
+ locationStr = NotEnoughUpdates.INSTANCE.navigation.getNameForAreaModeOrUnknown(location);
+ }
+ if (locationStr != null) {
+ statusStr += EnumChatFormatting.GRAY + " - " + EnumChatFormatting.GREEN + locationStr;
+ }
+
+ Utils.drawStringCentered(statusStr, fr, guiLeft + 63, guiTop + 160, true, 0);
+ }
+
+ if (entityPlayer == null) {
+ if (!loadingProfile || ((ThreadPoolExecutor) profileLoader).getActiveCount() == 0) {
+ loadingProfile = true;
+ UUID playerUUID = UUID.fromString(niceUuid(profile.getUuid()));
+
+ profileLoader.submit(() -> {
+ GameProfile fakeProfile = Minecraft
+ .getMinecraft()
+ .getSessionService()
+ .fillProfileProperties(new GameProfile(playerUUID, "CoolGuy123"), false);
+ entityPlayer =
+ new EntityOtherPlayerMP(Minecraft.getMinecraft().theWorld, fakeProfile) {
+ public ResourceLocation getLocationSkin() {
+ return playerLocationSkin == null
+ ? DefaultPlayerSkin.getDefaultSkin(this.getUniqueID())
+ : playerLocationSkin;
+ }
+
+ public ResourceLocation getLocationCape() {
+ return playerLocationCape;
+ }
+
+ public String getSkinType() {
+ return skinType == null ? DefaultPlayerSkin.getSkinType(this.getUniqueID()) : skinType;
+ }
+ };
+ entityPlayer.setAlwaysRenderNameTag(false);
+ entityPlayer.setCustomNameTag("");
+ });
+ }
+ } else {
+ entityPlayer.refreshDisplayName();
+ byte b = 0;
+ for (EnumPlayerModelParts part : EnumPlayerModelParts.values()) {
+ b |= part.getPartMask();
+ }
+ entityPlayer.getDataWatcher().updateObject(10, b);
+ }
+
+ JsonObject profileInfo = profile.getProfileInformation(profileId);
+ if (profileInfo == null) return;
+
+ Map<String, ProfileViewer.Level> skyblockInfo = profile.getSkyblockInfo(profileId);
+ JsonObject inventoryInfo = profile.getInventoryInfo(profileId);
+
+ if (entityPlayer != null) {
+ if (backgroundClickedX != -1 && Mouse.isButtonDown(1)) {
+ Arrays.fill(entityPlayer.inventory.armorInventory, null);
+ } else {
+ if (inventoryInfo != null && inventoryInfo.has("inv_armor")) {
+ JsonArray items = inventoryInfo.get("inv_armor").getAsJsonArray();
+ if (items != null && items.size() == 4) {
+ for (int i = 0; i < entityPlayer.inventory.armorInventory.length; i++) {
+ JsonElement itemElement = items.get(i);
+ if (itemElement != null && itemElement.isJsonObject()) {
+ entityPlayer.inventory.armorInventory[i] =
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(itemElement.getAsJsonObject(), false);
+ }
+ }
+ }
+ } else {
+ Arrays.fill(entityPlayer.inventory.armorInventory, null);
+ }
+ }
+ if (entityPlayer.getUniqueID().toString().equals("ae6193ab-494a-4719-b6e7-d50392c8f012")) {
+ entityPlayer.inventory.armorInventory[3] =
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("SMALL_BACKPACK")
+ );
+ }
+ }
+
+ if (entityPlayer != null && playerLocationSkin == null) {
+ try {
+ Minecraft
+ .getMinecraft()
+ .getSkinManager()
+ .loadProfileTextures(
+ entityPlayer.getGameProfile(),
+ (type, location1, profileTexture) -> {
+ switch (type) {
+ case SKIN:
+ playerLocationSkin = location1;
+ skinType = profileTexture.getMetadata("model");
+
+ if (skinType == null) {
+ skinType = "default";
+ }
+
+ break;
+ case CAPE:
+ playerLocationCape = location1;
+ }
+ },
+ false
+ );
+ } catch (Exception ignored) {
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ JsonObject petsInfo = profile.getPetsInfo(profileId);
+ if (petsInfo != null) {
+ JsonElement activePetElement = petsInfo.get("active_pet");
+ if (activePetElement != null && activePetElement.isJsonObject()) {
+ JsonObject activePet = activePetElement.getAsJsonObject();
+
+ String type = activePet.get("type").getAsString();
+
+ for (int i = 0; i < 4; i++) {
+ JsonObject item = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(type + ";" + i);
+ if (item != null) {
+ int x = guiLeft + 20;
+ float y =
+ guiTop +
+ 82 +
+ 15 *
+ (float) Math.sin(((getInstance().currentTime - getInstance().startTime) / 800f) % (2 * Math.PI));
+ GlStateManager.translate(x, y, 0);
+ ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false);
+
+ //Remove extra attributes so no CIT
+ NBTTagCompound stackTag = stack.getTagCompound() == null ? new NBTTagCompound() : stack.getTagCompound();
+ stackTag.removeTag("ExtraAttributes");
+ stack.setTagCompound(stackTag);
+
+ GlStateManager.scale(1.5f, 1.5f, 1);
+ GlStateManager.enableDepth();
+ Utils.drawItemStack(stack, 0, 0);
+ GlStateManager.scale(1 / 1.5f, 1 / 1.5f, 1);
+ GlStateManager.translate(-x, -y, 0);
+ break;
+ }
+ }
+ }
+ }
+ if (entityPlayer != null) {
+ drawEntityOnScreen(
+ guiLeft + 63,
+ guiTop + 128 + 7,
+ 36,
+ guiLeft + 63 - mouseX,
+ guiTop + 129 - mouseY,
+ entityPlayer
+ );
+ }
+
+ PlayerStats.Stats stats = profile.getStats(profileId);
+
+ if (stats != null) {
+ Splitter splitter = Splitter.on(" ").omitEmptyStrings().limit(2);
+ for (int i = 0; i < PlayerStats.defaultStatNames.length; i++) {
+ String statName = PlayerStats.defaultStatNames[i];
+ //if (statName.equals("mining_fortune") || statName.equals("mining_speed")) continue;
+ String statNamePretty = PlayerStats.defaultStatNamesPretty[i];
+
+ int val = Math.round(stats.get(statName));
+
+ GlStateManager.color(1, 1, 1, 1);
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(
+ GL11.GL_SRC_ALPHA,
+ GL11.GL_ONE_MINUS_SRC_ALPHA,
+ GL11.GL_ONE,
+ GL11.GL_ONE_MINUS_SRC_ALPHA
+ );
+ Utils.renderAlignedString(
+ statNamePretty,
+ EnumChatFormatting.WHITE.toString() + val,
+ guiLeft + 132,
+ guiTop + 21 + 11f * i,
+ 80
+ );
+
+ if (mouseX > guiLeft + 132 && mouseX < guiLeft + 212) {
+ if (mouseY > guiTop + 21 + 11f * i && mouseY < guiTop + 37 + 11f * i) {
+ List<String> split = splitter.splitToList(statNamePretty);
+ PlayerStats.Stats baseStats = PlayerStats.getBaseStats();
+ getInstance().tooltipToDisplay = new ArrayList<>();
+ getInstance().tooltipToDisplay.add(statNamePretty);
+ int base = Math.round(baseStats.get(statName));
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GRAY +
+ "Base " +
+ split.get(1) +
+ ": " +
+ EnumChatFormatting.GREEN +
+ base +
+ " " +
+ split.get(0)
+ );
+ int passive = Math.round(profile.getPassiveStats(profileId).get(statName) - baseStats.get(statName));
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GRAY +
+ "Passive " +
+ split.get(1) +
+ " Bonus: +" +
+ EnumChatFormatting.YELLOW +
+ passive +
+ " " +
+ split.get(0)
+ );
+ int itemBonus = Math.round(stats.get(statName) - profile.getPassiveStats(profileId).get(statName));
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GRAY +
+ "Item " +
+ split.get(1) +
+ " Bonus: +" +
+ EnumChatFormatting.DARK_PURPLE +
+ itemBonus +
+ " " +
+ split.get(0)
+ );
+ int finalStat = Math.round(stats.get(statName));
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GRAY +
+ "Final " +
+ split.get(1) +
+ ": +" +
+ EnumChatFormatting.RED +
+ finalStat +
+ " " +
+ split.get(0)
+ );
+ }
+ }
+ }
+ } else {
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "Skill/Inv/Coll",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 172,
+ guiTop + 101 - 10,
+ true,
+ 0
+ );
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "APIs not",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 172,
+ guiTop + 101,
+ true,
+ 0
+ );
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "enabled!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 172,
+ guiTop + 101 + 10,
+ true,
+ 0
+ );
+ }
+
+ if (skyblockInfo != null) {
+ int position = 0;
+ for (Map.Entry<String, ItemStack> entry : ProfileViewer.getSkillToSkillDisplayMap().entrySet()) {
+ if (entry.getValue() == null || entry.getKey() == null) {
+ position++;
+ continue;
+ }
+
+ int yPosition = position % 8;
+ int xPosition = position / 8;
+
+ String skillName = entry.getValue().getDisplayName();
+
+ float level = skyblockInfo.get(entry.getKey()).level;
+ int levelFloored = (int) Math.floor(level);
+
+ int x = guiLeft + 237 + 86 * xPosition;
+ int y = guiTop + 24 + 21 * yPosition;
+
+ Utils.renderAlignedString(skillName, EnumChatFormatting.WHITE.toString() + levelFloored, x + 14, y - 4, 60);
+
+ if (skyblockInfo.get(entry.getKey()).maxed) {
+ getInstance().renderGoldBar(x, y + 6, 80);
+ } else {
+ getInstance().renderBar(x, y + 6, 80, level % 1);
+ }
+
+ if (mouseX > x && mouseX < x + 80) {
+ if (mouseY > y - 4 && mouseY < y + 13) {
+ getInstance().tooltipToDisplay = new ArrayList<>();
+ getInstance().tooltipToDisplay.add(skillName);
+ if (skyblockInfo.get(entry.getKey()).maxed) {
+ getInstance().tooltipToDisplay.add(
+ EnumChatFormatting.GRAY + "Progress: " + EnumChatFormatting.GOLD + "MAXED!");
+ } else {
+ int maxXp = (int) skyblockInfo.get(entry.getKey()).maxXpForLevel;
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GRAY +
+ "Progress: " +
+ EnumChatFormatting.DARK_PURPLE +
+ StringUtils.shortNumberFormat(Math.round((level % 1) * maxXp)) +
+ "/" +
+ StringUtils.shortNumberFormat(maxXp)
+ );
+ }
+ String totalXpS = GuiProfileViewer.numberFormat.format((int) skyblockInfo.get(entry.getKey()).totalXp);
+ getInstance()
+ .tooltipToDisplay.add(EnumChatFormatting.GRAY + "Total XP: " + EnumChatFormatting.DARK_PURPLE + totalXpS);
+ }
+ }
+
+ GL11.glTranslatef((x), (y - 6f), 0);
+ GL11.glScalef(0.7f, 0.7f, 1);
+ Utils.drawItemStackLinear(entry.getValue(), 0, 0);
+ GL11.glScalef(1 / 0.7f, 1 / 0.7f, 1);
+ GL11.glTranslatef(-(x), -(y - 6f), 0);
+
+ position++;
+ }
+ } else {
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "Skills API not enabled!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 322,
+ guiTop + 101,
+ true,
+ 0
+ );
+ }
+
+ renderWeight(mouseX, mouseY, skyblockInfo, profileInfo);
+ }
+
+ @Override
+ public void resetCache() {
+ entityPlayer = null;
+ playerLocationSkin = null;
+ playerLocationCape = null;
+ skinType = null;
+ }
+
+ private String niceUuid(String uuidStr) {
+ if (uuidStr.length() != 32) return uuidStr;
+
+ return (
+ uuidStr.substring(0, 8) +
+ "-" +
+ uuidStr.substring(8, 12) +
+ "-" +
+ uuidStr.substring(12, 16) +
+ "-" +
+ uuidStr.substring(16, 20) +
+ "-" +
+ uuidStr.substring(20, 32)
+ );
+ }
+
+ private void renderWeight(
+ int mouseX,
+ int mouseY,
+ Map<String, ProfileViewer.Level> skyblockInfo,
+ JsonObject profileInfo
+ ) {
+ if (skyblockInfo == null) {
+ return;
+ }
+
+ if (Constants.WEIGHT == null || Utils.getElement(Constants.WEIGHT, "lily.skills.overall") == null ||
+ !Utils.getElement(Constants.WEIGHT, "lily.skills.overall").isJsonPrimitive()) {
+ Utils.showOutdatedRepoNotification();
+ return;
+ }
+
+ FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ SenitherWeight senitherWeight = new SenitherWeight(skyblockInfo);
+ LilyWeight lilyWeight = new LilyWeight(skyblockInfo, profileInfo);
+
+ Utils.drawStringCentered(
+ EnumChatFormatting.GREEN +
+ "Senither Weight: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw())),
+ fr,
+ guiLeft + 63,
+ guiTop + 18,
+ true,
+ 0
+ );
+
+ int textWidth = fr.getStringWidth(
+ "Senither Weight: " +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight.getTotalWeight().getRaw()))
+ );
+ if (mouseX > guiLeft + 63 - textWidth / 2 && mouseX < guiLeft + 63 + textWidth / 2) {
+ if (mouseY > guiTop + 12 && mouseY < guiTop + 12 + fr.FONT_HEIGHT) {
+ getInstance().tooltipToDisplay = new ArrayList<>();
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Skills: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight
+ .getSkillsWeight()
+ .getWeightStruct()
+ .getRaw()))
+ );
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Slayer: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(senitherWeight
+ .getSlayerWeight()
+ .getWeightStruct()
+ .getRaw()))
+ );
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Dungeons: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(
+ roundToNearestInt(senitherWeight.getDungeonsWeight().getWeightStruct().getRaw())
+ )
+ );
+ }
+ }
+
+ Utils.drawStringCentered(
+ EnumChatFormatting.GREEN +
+ "Lily Weight: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw())),
+ fr,
+ guiLeft + 63,
+ guiTop + 28,
+ true,
+ 0
+ );
+
+ int fontWidth = fr.getStringWidth(
+ "Lily Weight: " + GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight.getTotalWeight().getRaw()))
+ );
+ if (mouseX > guiLeft + 63 - fontWidth / 2 && mouseX < guiLeft + 63 + fontWidth / 2) {
+ if (mouseY > guiTop + 22 && mouseY < guiTop + 22 + fr.FONT_HEIGHT) {
+ getInstance().tooltipToDisplay = new ArrayList<>();
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Skills: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight
+ .getSkillsWeight()
+ .getWeightStruct()
+ .getRaw()))
+ );
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Slayer: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight
+ .getSlayerWeight()
+ .getWeightStruct()
+ .getRaw()))
+ );
+ getInstance()
+ .tooltipToDisplay.add(
+ EnumChatFormatting.GREEN +
+ "Dungeons: " +
+ EnumChatFormatting.GOLD +
+ GuiProfileViewer.numberFormat.format(roundToNearestInt(lilyWeight
+ .getDungeonsWeight()
+ .getWeightStruct()
+ .getRaw()))
+ );
+ }
+ }
+ }
+
+ private void drawEntityOnScreen(int posX, int posY, int scale, float mouseX, float mouseY, EntityLivingBase ent) {
+ GlStateManager.enableColorMaterial();
+ GlStateManager.pushMatrix();
+ GlStateManager.translate((float) posX, (float) posY, 50.0F);
+ GlStateManager.scale((float) (-scale), (float) scale, (float) scale);
+ GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F);
+ float renderYawOffset = ent.renderYawOffset;
+ float f1 = ent.rotationYaw;
+ float f2 = ent.rotationPitch;
+ float f3 = ent.prevRotationYawHead;
+ float f4 = ent.rotationYawHead;
+ GlStateManager.rotate(135.0F, 0.0F, 1.0F, 0.0F);
+ RenderHelper.enableStandardItemLighting();
+ GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F);
+ GlStateManager.rotate(25, 1.0F, 0.0F, 0.0F);
+ ent.renderYawOffset = (float) Math.atan(mouseX / 40.0F) * 20.0F;
+ ent.rotationYaw = (float) Math.atan(mouseX / 40.0F) * 40.0F;
+ ent.rotationPitch = -((float) Math.atan(mouseY / 40.0F)) * 20.0F;
+ ent.rotationYawHead = ent.rotationYaw;
+ ent.prevRotationYawHead = ent.rotationYaw;
+ RenderManager rendermanager = Minecraft.getMinecraft().getRenderManager();
+ rendermanager.setPlayerViewY(180.0F);
+ rendermanager.setRenderShadow(false);
+ rendermanager.renderEntityWithPosYaw(ent, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F);
+
+ ent.renderYawOffset = renderYawOffset;
+ ent.rotationYaw = f1;
+ ent.rotationPitch = f2;
+ ent.prevRotationYawHead = f3;
+ ent.rotationYawHead = f4;
+ GlStateManager.popMatrix();
+ RenderHelper.disableStandardItemLighting();
+ GlStateManager.disableRescaleNormal();
+ GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
+ GlStateManager.disableTexture2D();
+ GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BingoPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BingoPage.java
new file mode 100644
index 00000000..ab80afab
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/BingoPage.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BingoPage extends GuiProfileViewerPage {
+
+ private static final ResourceLocation BINGO_GUI_TEXTURE = new ResourceLocation("notenoughupdates:pv_bingo_tab.png");
+ private long lastResourceRequest;
+ private List<JsonObject> bingoGoals = null;
+ private int currentEventId;
+
+ public BingoPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ processBingoResources();
+ JsonObject bingoInfo = GuiProfileViewer.getProfile().getBingoInformation();
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+ //check if the player has created a bingo profile for the current event
+ if (bingoInfo == null) {
+ showMissingDataMessage(guiLeft, guiTop);
+ return;
+ }
+
+ JsonArray events = bingoInfo.get("events").getAsJsonArray();
+ JsonObject lastEvent = events.get(events.size() - 1).getAsJsonObject();
+ int lastParticipatedId = lastEvent.get("key").getAsInt();
+ if (currentEventId != lastParticipatedId) {
+ showMissingDataMessage(guiLeft, guiTop);
+ return;
+ }
+
+ List<String> completedGoals = jsonArrayToStringList(lastEvent.get("completed_goals").getAsJsonArray());
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BINGO_GUI_TEXTURE);
+ Utils.drawTexturedRect(guiLeft, guiTop, 431, 202, GL11.GL_NEAREST);
+
+ GlStateManager.color(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+
+ int row = 0;
+ int col = 0;
+ int initialY = guiTop + 46;
+ int initialX = guiLeft + 231;
+ int xAdjustment = 0;
+ int yAdjustment = 0;
+ for (JsonObject bingoGoal : bingoGoals) {
+ boolean dye = false;
+ boolean completed = false;
+ boolean communityGoal = false;
+ Item material;
+ if (bingoGoal.has("tiers")) {
+ if (isCommunityGoalFinished(bingoGoal)) {
+ material = Item.getItemFromBlock(Blocks.emerald_block);
+ } else {
+ material = Item.getItemFromBlock(Blocks.iron_block);
+ }
+ RenderHelper.enableGUIStandardItemLighting();
+ completed = true;
+ communityGoal = true;
+ yAdjustment = -1;
+ xAdjustment = -1;
+ } else {
+ if (completedGoals.contains(bingoGoal.get("id").getAsString())) {
+ material = Items.dye;
+ xAdjustment = -1;
+ dye = true;
+ completed = true;
+ } else {
+ material = Items.paper;
+ }
+ }
+
+ ItemStack itemStack = new ItemStack(material);
+ if (dye) {
+ itemStack.setItemDamage(10);
+ }
+ int x = col == 0 ? initialX + xAdjustment : initialX + (24 * col) + xAdjustment;
+ int y = row == 0 ? initialY + yAdjustment : initialY + (24 * row) + yAdjustment;
+
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, x, y);
+ y = communityGoal ? y - 1 : y;
+ if (mouseX >= x && mouseX < x + 24) {
+ if (mouseY >= y && mouseY <= y + 24) {
+ Utils.drawHoveringText(
+ getTooltip(bingoGoal, completed, communityGoal),
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+ col++;
+ if (col == 5) {
+ col = 0;
+ row++;
+ }
+ }
+
+ String totalPointsString =
+ EnumChatFormatting.AQUA + "Collected Points: " + EnumChatFormatting.WHITE + lastEvent.get("points").getAsInt();
+ int totalGoals = completedGoals.size();
+ String personalGoalsString;
+ if (totalGoals == 20) {
+ personalGoalsString = EnumChatFormatting.AQUA + "Personal Goals: " + EnumChatFormatting.GOLD + "20/20";
+ } else {
+ personalGoalsString =
+ EnumChatFormatting.AQUA +
+ "Personal Goals: " +
+ EnumChatFormatting.WHITE +
+ completedGoals.size() +
+ EnumChatFormatting.GOLD +
+ "/" +
+ EnumChatFormatting.WHITE +
+ 20;
+ }
+ Utils.drawStringF(totalPointsString, Minecraft.getMinecraft().fontRendererObj, guiLeft + 22, guiTop + 19, true, 0);
+ Utils.drawStringF(
+ personalGoalsString,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 22,
+ guiTop + 31,
+ true,
+ 0
+ );
+
+ GlStateManager.enableLighting();
+ }
+
+ private boolean isCommunityGoalFinished(JsonObject goal) {
+ JsonArray tiers = goal.get("tiers").getAsJsonArray();
+ int totalTiers = tiers.size();
+ long progress = goal.get("progress").getAsLong();
+ int finalTier = 0;
+ for (JsonElement tier : tiers) {
+ long currentTier = tier.getAsLong();
+ if (progress < currentTier) {
+ break;
+ }
+ finalTier++;
+ }
+ return finalTier == totalTiers;
+ }
+
+ private String generateProgressIndicator(double progress, double goal) {
+ int totalFields = 20;
+ int filled;
+ double percentage = progress / goal * 100;
+ if (percentage >= 100) {
+ filled = 20;
+ } else {
+ filled = (int) Math.round((percentage / 100) * 20);
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append(EnumChatFormatting.DARK_GREEN);
+ for (int i = 0; i < totalFields; i++) {
+ stringBuilder.append("-");
+ if (i > filled) {
+ stringBuilder.append(EnumChatFormatting.GRAY);
+ }
+ }
+
+ return stringBuilder.toString();
+ }
+
+ private List<String> getTooltip(JsonObject goal, boolean completed, boolean communityGoal) {
+ List<String> tooltip = new ArrayList<>();
+ if (communityGoal) {
+ //get current tier
+ JsonArray tiers = goal.get("tiers").getAsJsonArray();
+ int totalTiers = tiers.size();
+ double progress = goal.get("progress").getAsLong();
+ int finalTier = 0;
+ for (JsonElement tier : tiers) {
+ double currentTier = tier.getAsLong();
+ if (progress < currentTier) {
+ break;
+ }
+ finalTier++;
+ }
+ double nextTier = finalTier < totalTiers ? tiers.get(totalTiers - 1).getAsLong() : tiers
+ .get(finalTier - 1)
+ .getAsLong();
+ int progressToNextTier = (int) Math.round(progress / nextTier * 100);
+ if (progressToNextTier > 100) progressToNextTier = 100;
+ String progressBar = generateProgressIndicator(progress, nextTier);
+ String name = goal.get("name").getAsString();
+ int nextTierNum = finalTier < totalTiers ? finalTier + 1 : totalTiers;
+
+ String nextTierString = Utils.shortNumberFormat(nextTier, 0);
+ String progressString = Utils.shortNumberFormat(progress, 0);
+ tooltip.add(EnumChatFormatting.GREEN + name + " " + finalTier);
+ tooltip.add(EnumChatFormatting.DARK_GRAY + "Community Goal");
+ tooltip.add("");
+ tooltip.add(
+ EnumChatFormatting.GRAY +
+ "Progress to " +
+ name +
+ " " +
+ nextTierNum +
+ ": " +
+ EnumChatFormatting.YELLOW +
+ progressToNextTier +
+ EnumChatFormatting.GOLD +
+ "%"
+ );
+ tooltip.add(
+ progressBar +
+ EnumChatFormatting.YELLOW +
+ " " +
+ progressString +
+ EnumChatFormatting.GOLD +
+ "/" +
+ EnumChatFormatting.YELLOW +
+ nextTierString
+ );
+ tooltip.add("");
+ tooltip.add(EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "Community Goals are");
+ tooltip.add(
+ EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "collaborative - anyone with a");
+ tooltip.add(
+ EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "Bingo profile can help to reach");
+ tooltip.add(EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "the goal!");
+ tooltip.add("");
+ tooltip.add(EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "The more you contribute");
+ tooltip.add(
+ EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "towards the goal, the more you");
+ tooltip.add(EnumChatFormatting.DARK_GRAY.toString() + EnumChatFormatting.ITALIC + "will be rewarded");
+
+ if (finalTier == totalTiers) {
+ tooltip.add("");
+ tooltip.add(EnumChatFormatting.GREEN + "GOAL REACHED");
+ }
+ } else {
+ tooltip.add(EnumChatFormatting.GREEN + goal.get("name").getAsString());
+ tooltip.add(EnumChatFormatting.DARK_GRAY + "Personal Goal");
+ tooltip.add("");
+ tooltip.add(goal.get("lore").getAsString());
+ tooltip.add("");
+ tooltip.add(EnumChatFormatting.GRAY + "Reward");
+ tooltip.add(EnumChatFormatting.GOLD + "1 Bingo Point");
+ if (completed) {
+ tooltip.add("");
+ tooltip.add(EnumChatFormatting.GREEN + "GOAL REACHED");
+ } else {
+ tooltip.add("");
+ tooltip.add(EnumChatFormatting.RED + "You have not reached this goal!");
+ }
+ }
+ return tooltip;
+ }
+
+ private void showMissingDataMessage(int guiLeft, int guiTop) {
+ String message = EnumChatFormatting.RED + "No Bingo data for current event!";
+ Utils.drawStringCentered(
+ message,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 431 / 2f,
+ guiTop + 101,
+ true,
+ 0
+ );
+ }
+
+ private List<String> jsonArrayToStringList(JsonArray completedGoals) {
+ List<String> list = new ArrayList<>();
+ for (JsonElement completedGoal : completedGoals) {
+ list.add(completedGoal.getAsString());
+ }
+ return list;
+ }
+
+ private List<JsonObject> jsonArrayToJsonObjectList(JsonArray goals) {
+ List<JsonObject> list = new ArrayList<>();
+ for (JsonElement goal : goals) {
+ list.add(goal.getAsJsonObject());
+ }
+
+ return list;
+ }
+
+ private void processBingoResources() {
+ long currentTime = System.currentTimeMillis();
+
+ //renew every 2 minutes
+ if (currentTime - lastResourceRequest < 120 * 1000 && bingoGoals != null) return;
+ lastResourceRequest = currentTime;
+
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newAnonymousHypixelApiRequest("resources/skyblock/bingo")
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ if (jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ bingoGoals = jsonArrayToJsonObjectList(jsonObject.get("goals").getAsJsonArray());
+ currentEventId = jsonObject.get("id").getAsInt();
+ }
+ });
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java
new file mode 100644
index 00000000..554e204c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/CollectionsPage.java
@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.io.IOException;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+public class CollectionsPage extends GuiProfileViewerPage {
+
+ public static final ResourceLocation pv_cols = new ResourceLocation("notenoughupdates:pv_cols.png");
+ public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png");
+ private static final int COLLS_XCOUNT = 5;
+ private static final int COLLS_YCOUNT = 4;
+ private static final float COLLS_XPADDING = (190 - COLLS_XCOUNT * 20) / (float) (COLLS_XCOUNT + 1);
+ private static final float COLLS_YPADDING = (202 - COLLS_YCOUNT * 20) / (float) (COLLS_YCOUNT + 1);
+ private static final String[] romans = new String[] {
+ "I",
+ "II",
+ "III",
+ "IV",
+ "V",
+ "VI",
+ "VII",
+ "VIII",
+ "IX",
+ "X",
+ "XI",
+ "XII",
+ "XIII",
+ "XIV",
+ "XV",
+ "XVI",
+ "XVII",
+ "XIX",
+ "XX",
+ };
+ private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
+ private static List<String> tooltipToDisplay = null;
+ private static ItemStack selectedCollectionCategory = null;
+ private int page = 0;
+ private int maxPage = 0;
+
+ public CollectionsPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_cols);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+
+ JsonObject collectionInfo = GuiProfileViewer.getProfile().getCollectionInfo(GuiProfileViewer.getProfileId());
+ if (collectionInfo == null) {
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "Collection API not enabled!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 134,
+ guiTop + 101,
+ true,
+ 0
+ );
+ return;
+ }
+
+ JsonObject resourceCollectionInfo = ProfileViewer.getResourceCollectionInformation();
+ if (resourceCollectionInfo == null) return;
+
+ int collectionCatSize = ProfileViewer.getCollectionCatToCollectionMap().size();
+ int collectionCatYSize = (int) (162f / (collectionCatSize - 1 + 0.0000001f));
+ {
+ int yIndex = 0;
+ for (ItemStack stack : ProfileViewer.getCollectionCatToCollectionMap().keySet()) {
+ if (selectedCollectionCategory == null) selectedCollectionCategory = stack;
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ if (stack == selectedCollectionCategory) {
+ Utils.drawTexturedRect(
+ guiLeft + 7,
+ guiTop + 10 + collectionCatYSize * yIndex,
+ 20,
+ 20,
+ 20 / 256f,
+ 0,
+ 20 / 256f,
+ 0,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStackWithText(stack, guiLeft + 10, guiTop + 13 + collectionCatYSize * yIndex, "" + (yIndex + 1));
+ } else {
+ Utils.drawTexturedRect(
+ guiLeft + 7,
+ guiTop + 10 + collectionCatYSize * yIndex,
+ 20,
+ 20,
+ 0,
+ 20 / 256f,
+ 0,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStackWithText(stack, guiLeft + 9, guiTop + 12 + collectionCatYSize * yIndex, "" + (yIndex + 1));
+ }
+ yIndex++;
+ }
+ }
+
+ List<String> collections = ProfileViewer.getCollectionCatToCollectionMap().get(selectedCollectionCategory);
+ List<String> minions = ProfileViewer.getCollectionCatToMinionMap().get(selectedCollectionCategory);
+
+ maxPage = Math.max((collections != null ? collections.size() : 0) / 20, (minions != null ? minions.size() : 0) / 20);
+
+ if (maxPage != 0) {
+ boolean leftHovered = false;
+ boolean rightHovered = false;
+ if (Mouse.isButtonDown(0)) {
+ if (mouseY > guiTop + 6 && mouseY < guiTop + 22) {
+ if (mouseX > guiLeft + 100 - 20 - 12 && mouseX < guiLeft + 100 - 20) {
+ leftHovered = true;
+ } else if (mouseX > guiLeft + 100 + 20 + 250 && mouseX < guiLeft + 100 + 20 + 12 + 250) {
+ rightHovered = true;
+ }
+ }
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.resource_packs);
+
+ if (page > 0) {
+ Utils.drawTexturedRect(
+ guiLeft + 100 - 15 - 12,
+ guiTop + 6,
+ 12,
+ 16,
+ 29 / 256f,
+ 53 / 256f,
+ !leftHovered ? 0 : 32 / 256f,
+ !leftHovered ? 32 / 256f : 64 / 256f,
+ GL11.GL_NEAREST
+ );
+ }
+ if (page < 1) {
+ Utils.drawTexturedRect(
+ guiLeft + 100 + 15 + 250,
+ guiTop + 6,
+ 12,
+ 16,
+ 5 / 256f,
+ 29 / 256f,
+ !rightHovered ? 0 : 32 / 256f,
+ !rightHovered ? 32 / 256f : 64 / 256f,
+ GL11.GL_NEAREST
+ );
+ }
+ }
+
+ Utils.drawStringCentered(
+ selectedCollectionCategory.getDisplayName() + " Collections",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 134,
+ guiTop + 14,
+ true,
+ 4210752
+ );
+
+ JsonObject minionTiers = collectionInfo.get("minion_tiers").getAsJsonObject();
+ JsonObject collectionTiers = collectionInfo.get("collection_tiers").getAsJsonObject();
+ JsonObject maxAmounts = collectionInfo.get("max_amounts").getAsJsonObject();
+ JsonObject totalAmounts = collectionInfo.get("total_amounts").getAsJsonObject();
+ JsonObject personalAmounts = collectionInfo.get("personal_amounts").getAsJsonObject();
+
+ if (collections != null) {
+ for (int i = page * 20, j = 0; i < Math.min((page + 1) * 20, collections.size()); i++, j++) {
+ String collection = collections.get(i);
+ if (collection != null) {
+ ItemStack collectionItem = ProfileViewer.getCollectionToCollectionDisplayMap().get(collection);
+ if (collectionItem != null) {
+ int xIndex = j % COLLS_XCOUNT;
+ int yIndex = j / COLLS_XCOUNT;
+
+ float x = 39 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
+ float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
+
+ String tierString;
+ int tier = (int) Utils.getElementAsFloat(collectionTiers.get(collection), 0);
+ if (tier > 20 || tier < 0) {
+ tierString = String.valueOf(tier);
+ } else {
+ tierString = romans[tier];
+ }
+ float amount = Utils.getElementAsFloat(totalAmounts.get(collection), 0);
+ float maxAmount = Utils.getElementAsFloat(maxAmounts.get(collection), 0);
+ Color color = new Color(128, 128, 128, 255);
+ int tierStringColour = color.getRGB();
+ float completedness = 0;
+ if (maxAmount > 0) {
+ completedness = amount / maxAmount;
+ }
+ completedness = Math.min(1, completedness);
+ if (maxAmounts.has(collection) && completedness >= 1) {
+ tierStringColour = new Color(255, 215, 0).getRGB();
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y,
+ 20,
+ 20 * (1 - completedness),
+ 0,
+ 20 / 256f,
+ 0,
+ 20 * (1 - completedness) / 256f,
+ GL11.GL_NEAREST
+ );
+ GlStateManager.color(1, 185 / 255f, 0, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y + 20 * (1 - completedness),
+ 20,
+ 20 * (completedness),
+ 0,
+ 20 / 256f,
+ 20 * (1 - completedness) / 256f,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStack(collectionItem, guiLeft + (int) x + 2, guiTop + (int) y + 2);
+
+ if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
+ if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
+ tooltipToDisplay = new ArrayList<>();
+ tooltipToDisplay.add(
+ collectionItem.getDisplayName() +
+ " " +
+ (completedness >= 1 ? EnumChatFormatting.GOLD : EnumChatFormatting.GRAY) +
+ tierString
+ );
+ tooltipToDisplay.add(
+ "Collected: " + numberFormat.format(Utils.getElementAsFloat(personalAmounts.get(collection), 0))
+ );
+ tooltipToDisplay.add("Total Collected: " + numberFormat.format(amount));
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ if (tier >= 0) {
+ Utils.drawStringCentered(
+ tierString,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y - 4,
+ true,
+ tierStringColour
+ );
+ }
+
+ Utils.drawStringCentered(
+ StringUtils.shortNumberFormat(amount) + "",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y + 26,
+ true,
+ color.getRGB()
+ );
+ }
+ }
+ }
+ }
+
+ Utils.drawStringCentered(
+ selectedCollectionCategory.getDisplayName() + " Minions",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 326,
+ guiTop + 14,
+ true,
+ 4210752
+ );
+
+ if (minions != null) {
+ for (int i = page * 20, j = 0; i < Math.min((page + 1) * 20, minions.size()); i++, j++) {
+ String minion = minions.get(i);
+ if (minion != null) {
+ JsonObject misc = Constants.MISC;
+ float MAX_MINION_TIER = Utils.getElementAsFloat(Utils.getElement(misc, "minions." + minion + "_GENERATOR"), 11);
+
+ int tier = (int) Utils.getElementAsFloat(minionTiers.get(minion), 0);
+ JsonObject minionJson;
+ if (tier == 0) {
+ minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_1");
+ } else {
+ minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_" + tier);
+ }
+
+ if (minionJson != null) {
+ int xIndex = j % COLLS_XCOUNT;
+ int yIndex = j / COLLS_XCOUNT;
+
+ float x = 231 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
+ float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
+
+ String tierString;
+
+ if (tier - 1 >= romans.length || tier - 1 < 0) {
+ tierString = String.valueOf(tier);
+ } else {
+ tierString = romans[tier - 1];
+ }
+
+ Color color = new Color(128, 128, 128, 255);
+ int tierStringColour = color.getRGB();
+ float completedness = tier / MAX_MINION_TIER;
+
+ completedness = Math.min(1, completedness);
+ if (completedness >= 1) {
+ tierStringColour = new Color(255, 215, 0).getRGB();
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y,
+ 20,
+ 20 * (1 - completedness),
+ 0,
+ 20 / 256f,
+ 0,
+ 20 * (1 - completedness) / 256f,
+ GL11.GL_NEAREST
+ );
+ GlStateManager.color(1, 185 / 255f, 0, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y + 20 * (1 - completedness),
+ 20,
+ 20 * (completedness),
+ 0,
+ 20 / 256f,
+ 20 * (1 - completedness) / 256f,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+
+ Utils.drawItemStack(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson),
+ guiLeft + (int) x + 2,
+ guiTop + (int) y + 2
+ );
+
+ if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
+ if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
+ tooltipToDisplay =
+ NotEnoughUpdates.INSTANCE.manager
+ .jsonToStack(minionJson)
+ .getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ if (tier >= 0) {
+ Utils.drawStringCentered(
+ tierString,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y - 4,
+ true,
+ tierStringColour
+ );
+ }
+ }
+ }
+ }
+ }
+
+ if (tooltipToDisplay != null) {
+ List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size());
+ for (String line : tooltipToDisplay) {
+ grayTooltip.add(EnumChatFormatting.GRAY + line);
+ }
+ Utils.drawHoveringText(
+ grayTooltip,
+ mouseX,
+ mouseY,
+ getInstance().width,
+ getInstance().height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ tooltipToDisplay = null;
+ }
+ }
+
+ @Override
+ public void keyTyped(char typedChar, int keyCode) throws IOException {
+ ItemStack stack = null;
+ Iterator<ItemStack> items = ProfileViewer.getCollectionCatToCollectionMap().keySet().iterator();
+ switch (keyCode) {
+ case Keyboard.KEY_5:
+ case Keyboard.KEY_NUMPAD5:
+ stack = items.next();
+ case Keyboard.KEY_4:
+ case Keyboard.KEY_NUMPAD4:
+ stack = items.next();
+ case Keyboard.KEY_3:
+ case Keyboard.KEY_NUMPAD3:
+ stack = items.next();
+ case Keyboard.KEY_2:
+ case Keyboard.KEY_NUMPAD2:
+ stack = items.next();
+ case Keyboard.KEY_1:
+ case Keyboard.KEY_NUMPAD1:
+ stack = items.next();
+ }
+ if (stack != null) {
+ selectedCollectionCategory = stack;
+ page = 0;
+ }
+ Utils.playPressSound();
+ }
+
+ @Override
+ public void mouseReleased(int mouseX, int mouseY, int mouseButton) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ if (maxPage != 0) {
+ if (mouseY > guiTop + 6 && mouseY < guiTop + 22) {
+ if (mouseX > guiLeft + 100 - 15 - 12 && mouseX < guiLeft + 100 - 20) {
+ if (page > 0) {
+ page--;
+ return;
+ }
+ } else if (mouseX > guiLeft + 100 + 15 + 250 && mouseX < guiLeft + 100 + 20 + 12 + 250) {
+ if (page < 1) {
+ page++;
+ return;
+ }
+ }
+ }
+ }
+
+ int collectionCatSize = ProfileViewer.getCollectionCatToCollectionMap().size();
+ int collectionCatYSize = (int) (162f / (collectionCatSize - 1 + 0.0000001f));
+ int yIndex = 0;
+ for (ItemStack stack : ProfileViewer.getCollectionCatToCollectionMap().keySet()) {
+ if (mouseX > guiLeft + 7 && mouseX < guiLeft + 7 + 20) {
+ if (mouseY > guiTop + 10 + collectionCatYSize * yIndex && mouseY < guiTop + 10 + collectionCatYSize * yIndex + 20) {
+ selectedCollectionCategory = stack;
+ page = 0;
+ Utils.playPressSound();
+ return;
+ }
+ }
+ yIndex++;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
new file mode 100644
index 00000000..15a70ded
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/DungeonPage.java
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL14;
+
+import java.io.IOException;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.UUID;
+
+public class DungeonPage extends GuiProfileViewerPage {
+
+ private static final ResourceLocation pv_dung = new ResourceLocation("notenoughupdates:pv_dung.png");
+ private static final ItemStack DEADBUSH = new ItemStack(Item.getItemFromBlock(Blocks.deadbush));
+ private static final String[] dungSkillsName = { "Healer", "Mage", "Berserk", "Archer", "Tank" };
+ private static final ItemStack[] BOSS_HEADS = new ItemStack[7];
+ private static final ItemStack[] dungSkillsStack = {
+ new ItemStack(Items.potionitem, 1, 16389),
+ new ItemStack(Items.blaze_rod),
+ new ItemStack(Items.iron_sword),
+ new ItemStack(Items.bow),
+ new ItemStack(Items.leather_chestplate),
+ };
+ private static final String[] bossFloorArr = { "Bonzo", "Scarf", "Professor", "Thorn", "Livid", "Sadan", "Necron" };
+ private static final String[] bossFloorHeads = {
+ "12716ecbf5b8da00b05f316ec6af61e8bd02805b21eb8e440151468dc656549c",
+ "7de7bbbdf22bfe17980d4e20687e386f11d59ee1db6f8b4762391b79a5ac532d",
+ "9971cee8b833a62fc2a612f3503437fdf93cad692d216b8cf90bbb0538c47dd8",
+ "8b6a72138d69fbbd2fea3fa251cabd87152e4f1c97e5f986bf685571db3cc0",
+ "c1007c5b7114abec734206d4fc613da4f3a0e99f71ff949cedadc99079135a0b",
+ "fa06cb0c471c1c9bc169af270cd466ea701946776056e472ecdaeb49f0f4a4dc",
+ "a435164c05cea299a3f016bbbed05706ebb720dac912ce4351c2296626aecd9a",
+ };
+
+ private static final LinkedHashMap<String, ItemStack> dungeonsModeIcons = new LinkedHashMap<String, ItemStack>() {
+ {
+ put(
+ "catacombs",
+ Utils.editItemStackInfo(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("DUNGEON_STONE")
+ ),
+ EnumChatFormatting.GRAY + "Normal Mode",
+ true
+ )
+ );
+ put(
+ "master_catacombs",
+ Utils.editItemStackInfo(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("MASTER_SKULL_TIER_7")
+ ),
+ EnumChatFormatting.GRAY + "Master Mode",
+ true
+ )
+ );
+ }
+ };
+
+ private static int floorTime = 7;
+ private final HashMap<String, HashMap<String, ProfileViewer.Level>> levelObjClasseses = new HashMap<>();
+
+ private final HashMap<String, ProfileViewer.Level> levelObjCatas = new HashMap<>();
+ private final GuiElementTextField dungeonLevelTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT);
+ private int floorLevelTo = -1;
+ private long floorLevelToXP = -1;
+ private boolean onMasterMode = false;
+
+ public DungeonPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj;
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dung);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+
+ ProfileViewer.Profile profile = GuiProfileViewer.getProfile();
+ String profileId = GuiProfileViewer.getProfileId();
+ JsonObject hypixelInfo = profile.getHypixelProfile();
+ if (hypixelInfo == null) return;
+ JsonObject profileInfo = profile.getProfileInformation(profileId);
+ if (profileInfo == null) return;
+
+ JsonObject leveling = Constants.LEVELING;
+ if (leveling == null) return;
+
+ int sectionWidth = 110;
+
+ String dungeonString = onMasterMode ? "master_catacombs" : "catacombs";
+
+ Utils.renderShadowedString(
+ EnumChatFormatting.RED + (onMasterMode ? "Master Mode" : "Catacombs"),
+ (guiLeft + getInstance().sizeX / 2),
+ guiTop + 5,
+ sectionWidth
+ );
+
+ ProfileViewer.Level levelObjCata = levelObjCatas.get(profileId);
+ //Catacombs level thingy
+ {
+ if (levelObjCata == null) {
+ float cataXp = Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.experience"), 0);
+ levelObjCata =
+ ProfileViewer.getLevel(
+ Utils.getElementOrDefault(leveling, "catacombs", new JsonArray()).getAsJsonArray(),
+ cataXp,
+ 99,
+ false
+ );
+ levelObjCata.totalXp = cataXp;
+ levelObjCatas.put(profileId, levelObjCata);
+ }
+
+ String skillName = EnumChatFormatting.RED + "Catacombs";
+ float level = levelObjCata.level;
+ int levelFloored = (int) Math.floor(level);
+
+ if (floorLevelTo == -1 && levelFloored >= 0) {
+ dungeonLevelTextField.setText("" + (levelFloored + 1));
+ calculateFloorLevelXP();
+ }
+
+ int x = guiLeft + 23;
+ int y = guiTop + 25;
+
+ getInstance().renderXpBar(skillName, DEADBUSH, x, y, sectionWidth, levelObjCata, mouseX, mouseY);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Until Cata " + floorLevelTo + ": ",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat((double) floorLevelToXP),
+ x,
+ y + 16,
+ sectionWidth
+ );
+
+ if (mouseX > x && mouseX < x + sectionWidth && mouseY > y + 16 && mouseY < y + 24 && !onMasterMode) {
+ float F5 =
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + 5), 0)); //this can prob be done better
+ float F6 =
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + 6), 0));
+ float F7 =
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + 7), 0));
+ if (F5 > 150) {
+ F5 = 150;
+ }
+ if (F6 > 100) {
+ F6 = 100;
+ }
+ if (F7 > 50) {
+ F7 = 50;
+ }
+ float xpF5 = 2400 * (F5 / 100 + 1);
+ float xpF6 = 4880 * (F6 / 100 + 1);
+ float xpF7 = 28000 * (F7 / 100 + 1);
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+ xpF5 *= 1.1;
+ xpF6 *= 1.1;
+ xpF7 *= 1.1;
+ }
+
+ long runsF5 = (int) Math.ceil(floorLevelToXP / xpF5);
+ long runsF6 = (int) Math.ceil(floorLevelToXP / xpF6);
+ long runsF7 = (int) Math.ceil(floorLevelToXP / xpF7);
+
+ float timeF5 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.5"),
+ 0
+ );
+ float timeF6 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.6"),
+ 0
+ );
+ float timeF7 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.fastest_time_s_plus.7"),
+ 0
+ );
+
+ getInstance().tooltipToDisplay =
+ Lists.newArrayList(
+ String.format("# F5 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF5), runsF5),
+ String.format("# F6 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF6), runsF6),
+ String.format("# F7 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpF7), runsF7),
+ ""
+ );
+ boolean hasTime = false;
+ if (timeF5 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (F5) : %s", Utils.prettyTime(runsF5 * (long) (timeF5 * 1.2))));
+ hasTime = true;
+ }
+ if (timeF6 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (F6) : %s", Utils.prettyTime(runsF6 * (long) (timeF6 * 1.2))));
+ hasTime = true;
+ }
+ if (timeF7 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (F7) : %s", Utils.prettyTime(runsF7 * (long) (timeF7 * 1.2))));
+ hasTime = true;
+ }
+ if (hasTime) {
+ getInstance().tooltipToDisplay.add("");
+ }
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+ getInstance()
+ .tooltipToDisplay.add(
+ "[Hold " + EnumChatFormatting.YELLOW + "SHIFT" + EnumChatFormatting.GRAY + " to show without Expert Ring]"
+ );
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) {
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) getInstance().tooltipToDisplay.add("");
+ getInstance().tooltipToDisplay.add("Number of runs is calculated as [Remaining XP]/[XP per Run].");
+ getInstance().tooltipToDisplay.add("The [XP per Run] is the average xp gained from an S+ run");
+ getInstance()
+ .tooltipToDisplay.add(
+ "The " +
+ EnumChatFormatting.DARK_PURPLE +
+ "Catacombs Expert Ring" +
+ EnumChatFormatting.GRAY +
+ " is assumed to be used, unless " +
+ EnumChatFormatting.YELLOW +
+ "SHIFT" +
+ EnumChatFormatting.GRAY +
+ " is held."
+ );
+ getInstance().tooltipToDisplay.add("[Time per run] is calculated using Fastest S+ x 120%");
+ } else {
+ getInstance()
+ .tooltipToDisplay.add("[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
+ }
+ }
+
+ if (mouseX > x && mouseX < x + sectionWidth && mouseY > y + 16 && mouseY < y + 24 && onMasterMode) {
+ float M3 =
+ (
+ Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + 3),
+ 0
+ )
+ );
+ float M4 =
+ (
+ Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + 4),
+ 0
+ )
+ );
+ float M5 =
+ (
+ Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + 5),
+ 0
+ )
+ ); //this can prob be done better
+ float M6 =
+ (
+ Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + 6),
+ 0
+ )
+ );
+ float M7 =
+ (
+ Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + 7),
+ 0
+ )
+ );
+ if (M3 > 50) {
+ M3 = 50;
+ }
+ if (M4 > 50) {
+ M4 = 50;
+ }
+ if (M5 > 50) {
+ M5 = 50;
+ }
+ if (M6 > 50) {
+ M6 = 50;
+ }
+ if (M7 > 50) {
+ M7 = 50;
+ }
+ float xpM3 = 35000 * (M3 / 100 + 1);
+ float xpM4 = 55000 * (M4 / 100 + 1);
+ float xpM5 = 70000 * (M5 / 100 + 1);
+ float xpM6 = 100000 * (M6 / 100 + 1);
+ float xpM7 = 300000 * (M7 / 100 + 1);
+ //No clue if M3 or M4 xp values are right
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+ xpM3 *= 1.1;
+ xpM4 *= 1.1;
+ xpM5 *= 1.1;
+ xpM6 *= 1.1;
+ xpM7 *= 1.1;
+ }
+
+ long runsM3 = (int) Math.ceil(floorLevelToXP / xpM3);
+ long runsM4 = (int) Math.ceil(floorLevelToXP / xpM4);
+ long runsM5 = (int) Math.ceil(floorLevelToXP / xpM5);
+ long runsM6 = (int) Math.ceil(floorLevelToXP / xpM6);
+ long runsM7 = (int) Math.ceil(floorLevelToXP / xpM7);
+
+ float timeM3 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.3"),
+ 0
+ );
+ float timeM4 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.4"),
+ 0
+ );
+ float timeM5 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.5"),
+ 0
+ );
+ float timeM6 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.6"),
+ 0
+ );
+ float timeM7 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.7"),
+ 0
+ );
+
+ getInstance().tooltipToDisplay =
+ Lists.newArrayList(
+ String.format("# M3 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM3), runsM3),
+ String.format("# M4 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM4), runsM4),
+ String.format("# M5 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM5), runsM5),
+ String.format("# M6 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM6), runsM6),
+ String.format("# M7 Runs (%s xp) : %d", StringUtils.shortNumberFormat(xpM7), runsM7),
+ ""
+ );
+ boolean hasTime = false;
+ if (timeM3 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (M3) : %s", Utils.prettyTime(runsM3 * (long) (timeM3 * 1.2))));
+ hasTime = true;
+ }
+ if (timeM4 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (M4) : %s", Utils.prettyTime(runsM4 * (long) (timeM4 * 1.2))));
+ hasTime = true;
+ }
+ if (timeM5 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (M5) : %s", Utils.prettyTime(runsM5 * (long) (timeM5 * 1.2))));
+ hasTime = true;
+ }
+ if (timeM6 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (M6) : %s", Utils.prettyTime(runsM6 * (long) (timeM6 * 1.2))));
+ hasTime = true;
+ }
+ if (timeM7 > 1000) {
+ getInstance()
+ .tooltipToDisplay.add(String.format("Expected Time (M7) : %s", Utils.prettyTime(runsM7 * (long) (timeM7 * 1.2))));
+ hasTime = true;
+ }
+ if (hasTime) {
+ getInstance().tooltipToDisplay.add("");
+ }
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
+ getInstance()
+ .tooltipToDisplay.add(
+ "[Hold " + EnumChatFormatting.YELLOW + "SHIFT" + EnumChatFormatting.GRAY + " to show without Expert Ring]"
+ );
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) {
+ if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) getInstance().tooltipToDisplay.add("");
+ getInstance().tooltipToDisplay.add("Number of runs is calculated as [Remaining XP]/[XP per Run].");
+ getInstance().tooltipToDisplay.add("The [XP per Run] is the average xp gained from an S+ run");
+ getInstance()
+ .tooltipToDisplay.add(
+ "The " +
+ EnumChatFormatting.DARK_PURPLE +
+ "Catacombs Expert Ring" +
+ EnumChatFormatting.GRAY +
+ " is assumed to be used, unless " +
+ EnumChatFormatting.YELLOW +
+ "SHIFT" +
+ EnumChatFormatting.GRAY +
+ " is held."
+ );
+ getInstance().tooltipToDisplay.add("[Time per run] is calculated using Fastest S+ x 120%");
+ } else {
+ getInstance()
+ .tooltipToDisplay.add("[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
+ }
+ }
+
+ dungeonLevelTextField.setSize(20, 10);
+ dungeonLevelTextField.render(x + 22, y + 29);
+ int calcLen = fontRendererObj.getStringWidth("Calculate");
+ Utils.renderShadowedString(EnumChatFormatting.WHITE + "Calculate", x + sectionWidth - 17 - calcLen / 2f, y + 30, 100);
+
+ //Random stats
+
+ float secrets = Utils.getElementAsFloat(Utils.getElement(hypixelInfo, "achievements.skyblock_treasure_hunter"), 0);
+ float totalRunsF = 0;
+ float totalRunsF5 = 0;
+ for (int i = 1; i <= 7; i++) {
+ float runs = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.tier_completions." + i),
+ 0
+ );
+ totalRunsF += runs;
+ if (i >= 5) {
+ totalRunsF5 += runs;
+ }
+ }
+ float totalRunsM = 0;
+ float totalRunsM5 = 0;
+ for (int i = 1; i <= 7; i++) {
+ float runs = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.tier_completions." + i),
+ 0
+ );
+ totalRunsM += runs;
+ if (i >= 5) {
+ totalRunsM5 += runs;
+ }
+ }
+ float totalRuns = totalRunsF + totalRunsM;
+
+ float mobKills;
+ float mobKillsF = 0;
+ for (int i = 1; i <= 7; i++) {
+ float kills = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.mobs_killed." + i),
+ 0
+ );
+ mobKillsF += kills;
+ }
+ float mobKillsM = 0;
+ for (int i = 1; i <= 7; i++) {
+ float kills = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types.master_catacombs.mobs_killed." + i),
+ 0
+ );
+ mobKillsM += kills;
+ }
+ mobKills = mobKillsF + mobKillsM;
+
+ int miscTopY = y + 55;
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Total Runs " + (onMasterMode ? "M" : "F"),
+ EnumChatFormatting.WHITE.toString() + ((int) (onMasterMode ? totalRunsM : totalRunsF)),
+ x,
+ miscTopY,
+ sectionWidth
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Total Runs (" + (onMasterMode ? "M" : "F") + "5-7) ",
+ EnumChatFormatting.WHITE.toString() + ((int) (onMasterMode ? totalRunsM5 : totalRunsF5)),
+ x,
+ miscTopY + 10,
+ sectionWidth
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Secrets (Total) ",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(secrets),
+ x,
+ miscTopY + 20,
+ sectionWidth
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Secrets (/Run) ",
+ EnumChatFormatting.WHITE.toString() + (Math.round(secrets / Math.max(1, totalRuns) * 100) / 100f),
+ x,
+ miscTopY + 30,
+ sectionWidth
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Mob Kills (Total) ",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(mobKills),
+ x,
+ miscTopY + 40,
+ sectionWidth
+ );
+
+ int y3 = y + 117;
+
+ for (int i = 1; i <= 7; i++) {
+ int w = fontRendererObj.getStringWidth("" + i);
+
+ int bx = x + sectionWidth * i / 8 - w / 2;
+
+ boolean invert = i == floorTime;
+ float uMin = 20 / 256f;
+ float uMax = 29 / 256f;
+ float vMin = 0 / 256f;
+ float vMax = 11 / 256f;
+
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.pv_elements);
+ Utils.drawTexturedRect(
+ bx - 2,
+ y3 - 2,
+ 9,
+ 11,
+ invert ? uMax : uMin,
+ invert ? uMin : uMax,
+ invert ? vMax : vMin,
+ invert ? vMin : vMax,
+ GL11.GL_NEAREST
+ );
+
+ Utils.renderShadowedString(EnumChatFormatting.WHITE.toString() + i, bx + w / 2, y3, 10);
+ }
+
+ float timeNorm = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time." + floorTime),
+ 0
+ );
+ float timeS = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time_s." + floorTime),
+ 0
+ );
+ float timeSPLUS = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".fastest_time_s_plus." + floorTime),
+ 0
+ );
+ String timeNormStr = timeNorm <= 0 ? "N/A" : Utils.prettyTime((long) timeNorm);
+ String timeSStr = timeS <= 0 ? "N/A" : Utils.prettyTime((long) timeS);
+ String timeSPlusStr = timeSPLUS <= 0 ? "N/A" : Utils.prettyTime((long) timeSPLUS);
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Floor " + floorTime + " ",
+ EnumChatFormatting.WHITE + timeNormStr,
+ x,
+ y3 + 10,
+ sectionWidth
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Floor " + floorTime + " S",
+ EnumChatFormatting.WHITE + timeSStr,
+ x,
+ y3 + 20,
+ sectionWidth
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Floor " + floorTime + " S+",
+ EnumChatFormatting.WHITE + timeSPlusStr,
+ x,
+ y3 + 30,
+ sectionWidth
+ );
+ }
+
+ //Completions
+ {
+ int x = guiLeft + 161;
+ int y = guiTop + 27;
+
+ Utils.renderShadowedString(EnumChatFormatting.RED + "Boss Collections", x + sectionWidth / 2, y, sectionWidth);
+ for (int i = 1; i <= 7; i++) {
+ float compl = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.dungeon_types." + dungeonString + ".tier_completions." + i),
+ 0
+ );
+
+ if (BOSS_HEADS[i - 1] == null) {
+ String textureLink = bossFloorHeads[i - 1];
+
+ String b64Decoded = "{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + textureLink + "\"}}}";
+ String b64Encoded = new String(Base64.getEncoder().encode(b64Decoded.getBytes()));
+
+ ItemStack stack = new ItemStack(Items.skull, 1, 3);
+ NBTTagCompound nbt = new NBTTagCompound();
+ NBTTagCompound skullOwner = new NBTTagCompound();
+ NBTTagCompound properties = new NBTTagCompound();
+ NBTTagList textures = new NBTTagList();
+ NBTTagCompound textures_0 = new NBTTagCompound();
+
+ String uuid = UUID.nameUUIDFromBytes(b64Encoded.getBytes()).toString();
+ skullOwner.setString("Id", uuid);
+ skullOwner.setString("Name", uuid);
+
+ textures_0.setString("Value", b64Encoded);
+ textures.appendTag(textures_0);
+
+ properties.setTag("textures", textures);
+ skullOwner.setTag("Properties", properties);
+ nbt.setTag("SkullOwner", skullOwner);
+ stack.setTagCompound(nbt);
+
+ BOSS_HEADS[i - 1] = stack;
+ }
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(x - 4, y + 10 + 20 * (i - 1), 0);
+ GlStateManager.scale(1.3f, 1.3f, 1);
+ Utils.drawItemStack(BOSS_HEADS[i - 1], 0, 0);
+ GlStateManager.popMatrix();
+
+ Utils.renderAlignedString(
+ String.format(EnumChatFormatting.YELLOW + "%s (" + (onMasterMode ? "M" : "F") + "%d) ", bossFloorArr[i - 1], i),
+ EnumChatFormatting.WHITE.toString() + (int) compl,
+ x + 16,
+ y + 18 + 20 * (i - 1),
+ sectionWidth - 15
+ );
+ }
+ }
+
+ //Skills
+ {
+ int x = guiLeft + 298;
+ int y = guiTop + 27;
+
+ //Gui.drawRect(x, y, x+120, y+147, 0xffffffff);
+
+ Utils.renderShadowedString(EnumChatFormatting.DARK_PURPLE + "Class Levels", x + sectionWidth / 2, y, sectionWidth);
+
+ JsonElement activeClassElement = Utils.getElement(profileInfo, "dungeons.selected_dungeon_class");
+ String activeClass = null;
+ if (activeClassElement instanceof JsonPrimitive && ((JsonPrimitive) activeClassElement).isString()) {
+ activeClass = activeClassElement.getAsString();
+ }
+
+ for (int i = 0; i < dungSkillsName.length; i++) {
+ String skillName = dungSkillsName[i];
+
+ HashMap<String, ProfileViewer.Level> levelObjClasses = levelObjClasseses.computeIfAbsent(profileId, k -> new HashMap<>());
+ if (!levelObjClasses.containsKey(skillName)) {
+ float cataXp = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.player_classes." + skillName.toLowerCase() + ".experience"),
+ 0
+ );
+ ProfileViewer.Level levelObj = ProfileViewer.getLevel(
+ Utils.getElementOrDefault(leveling, "catacombs", new JsonArray()).getAsJsonArray(),
+ cataXp,
+ 50,
+ false
+ );
+ levelObjClasses.put(skillName, levelObj);
+ }
+
+ String colour = EnumChatFormatting.WHITE.toString();
+ if (skillName.toLowerCase().equals(activeClass)) {
+ colour = EnumChatFormatting.GREEN.toString();
+ }
+
+ ProfileViewer.Level levelObj = levelObjClasses.get(skillName);
+
+ getInstance()
+ .renderXpBar(colour + skillName, dungSkillsStack[i], x, y + 20 + 29 * i, sectionWidth, levelObj, mouseX, mouseY);
+ }
+ }
+
+ drawSideButtons();
+ }
+
+ @Override
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ FontRenderer fontRendererObj = Minecraft.getMinecraft().fontRendererObj;
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ if (mouseX >= guiLeft + 50 && mouseX <= guiLeft + 70 && mouseY >= guiTop + 54 && mouseY <= guiTop + 64) {
+ dungeonLevelTextField.mouseClicked(mouseX, mouseY, mouseButton);
+ } else {
+ dungeonLevelTextField.otherComponentClick();
+ }
+
+ int cW = fontRendererObj.getStringWidth("Calculate");
+ if (mouseX >= guiLeft + 23 + 110 - 17 - cW && mouseX <= guiLeft + 23 + 110 - 17 && mouseY >= guiTop + 55 && mouseY <= guiTop + 65) {
+ calculateFloorLevelXP();
+ }
+
+ int y = guiTop + 142;
+
+ if (mouseY >= y - 2 && mouseY <= y + 9) {
+ for (int i = 1; i <= 7; i++) {
+ int w = fontRendererObj.getStringWidth("" + i);
+
+ int x = guiLeft + 23 + 110 * i / 8 - w / 2;
+
+ if (mouseX >= x - 2 && mouseX <= x + 7) {
+ floorTime = i;
+ return false;
+ }
+ }
+ }
+ if (mouseX >= guiLeft - 29 && mouseX <= guiLeft) {
+ if (mouseY >= guiTop && mouseY <= guiTop + 28) {
+ onMasterMode = false;
+ } else if (mouseY + 28 >= guiTop && mouseY <= guiTop + 28 * 2) {
+ onMasterMode = true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void keyTyped(char typedChar, int keyCode) throws IOException {
+ dungeonLevelTextField.keyTyped(typedChar, keyCode);
+ }
+
+ private void drawSideButtons() {
+ GlStateManager.enableDepth();
+ GlStateManager.translate(0, 0, 5);
+ if (onMasterMode) {
+ drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), true);
+ } else {
+ drawSideButton(0, dungeonsModeIcons.get("catacombs"), true);
+ }
+ GlStateManager.translate(0, 0, -3);
+
+ GlStateManager.translate(0, 0, -2);
+ if (!onMasterMode) {
+ drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), false);
+ } else {
+ drawSideButton(0, dungeonsModeIcons.get("catacombs"), false);
+ }
+ GlStateManager.disableDepth();
+ }
+
+ private void drawSideButton(int yIndex, ItemStack itemStack, boolean pressed) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ GlStateManager.disableLighting();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ int x = guiLeft - 28;
+ int y = guiTop + yIndex * 28;
+
+ float uMin = 193 / 256f;
+ float uMax = 223 / 256f;
+ float vMin = 200 / 256f;
+ float vMax = 228 / 256f;
+ if (pressed) {
+ uMin = 224 / 256f;
+ uMax = 1f;
+
+ if (yIndex != 0) {
+ vMin = 228 / 256f;
+ vMax = 1f;
+ }
+
+ getInstance().renderBlurredBackground(getInstance().width, getInstance().height, x + 2, y + 2, 30, 28 - 4);
+ } else {
+ getInstance().renderBlurredBackground(getInstance().width, getInstance().height, x + 2, y + 2, 28 - 2, 28 - 4);
+ }
+
+ GlStateManager.disableLighting();
+ GlStateManager.enableBlend();
+ GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.enableAlpha();
+ GlStateManager.alphaFunc(516, 0.1F);
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.pv_elements);
+
+ Utils.drawTexturedRect(x, y, pressed ? 32 : 28, 28, uMin, uMax, vMin, vMax, GL11.GL_NEAREST);
+
+ GlStateManager.enableDepth();
+ Utils.drawItemStack(itemStack, x + 8, y + 7);
+ }
+
+ private void calculateFloorLevelXP() {
+ JsonObject leveling = Constants.LEVELING;
+ if (leveling == null) return;
+ ProfileViewer.Level levelObjCata = levelObjCatas.get(GuiProfileViewer.getProfileId());
+ if (levelObjCata == null) return;
+
+ try {
+ dungeonLevelTextField.setCustomBorderColour(0xffffffff);
+ floorLevelTo = Integer.parseInt(dungeonLevelTextField.getText());
+
+ JsonArray levelingArray = Utils.getElementOrDefault(leveling, "catacombs", new JsonArray()).getAsJsonArray();
+
+ float remaining = -((levelObjCata.level % 1) * levelObjCata.maxXpForLevel);
+
+ for (int level = 0; level < Math.min(floorLevelTo, levelingArray.size()); level++) {
+ if (level < Math.floor(levelObjCata.level)) {
+ continue;
+ }
+ remaining += levelingArray.get(level).getAsFloat();
+ }
+
+ if (remaining < 0) {
+ remaining = 0;
+ }
+ floorLevelToXP = (long) remaining;
+ } catch (Exception e) {
+ dungeonLevelTextField.setCustomBorderColour(0xffff0000);
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java
new file mode 100644
index 00000000..3b30b9b7
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ExtraPage.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.apache.commons.lang3.text.WordUtils;
+import org.lwjgl.opengl.GL11;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.TreeMap;
+
+public class ExtraPage extends GuiProfileViewerPage {
+
+ private static final ResourceLocation pv_extra = new ResourceLocation("notenoughupdates:pv_extra.png");
+ private TreeMap<Integer, Set<String>> topKills = null;
+ private TreeMap<Integer, Set<String>> topDeaths = null;
+
+ public ExtraPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_extra);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+
+ ProfileViewer.Profile profile = GuiProfileViewer.getProfile();
+ String profileId = GuiProfileViewer.getProfileId();
+ JsonObject profileInfo = profile.getProfileInformation(profileId);
+ if (profileInfo == null) return;
+ Map<String, ProfileViewer.Level> skyblockInfo = profile.getSkyblockInfo(profileId);
+
+ float xStart = 22;
+ float xOffset = 103;
+ float yStartTop = 27;
+ float yStartBottom = 105;
+ float yOffset = 10;
+
+ float bankBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "banking.balance"), 0);
+ float purseBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "coin_purse"), 0);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.GOLD + "Bank Balance",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(bankBalance),
+ guiLeft + xStart,
+ guiTop + yStartTop,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.GOLD + "Purse",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(purseBalance),
+ guiLeft + xStart,
+ guiTop + yStartTop + yOffset,
+ 76
+ );
+
+ {
+ String first_join = getTimeSinceString(profileInfo, "first_join");
+ if (first_join != null) {
+ Utils.renderAlignedString(
+ EnumChatFormatting.AQUA + "Joined",
+ EnumChatFormatting.WHITE + first_join,
+ guiLeft + xStart,
+ guiTop + yStartTop + yOffset * 2,
+ 76
+ );
+ }
+ }
+ JsonObject guildInfo = profile.getGuildInformation(null);
+ boolean shouldRenderGuild = guildInfo != null && guildInfo.has("name");
+ {
+ if (shouldRenderGuild) {
+ Utils.renderAlignedString(
+ EnumChatFormatting.AQUA + "Guild",
+ EnumChatFormatting.WHITE + guildInfo.get("name").getAsString(),
+ guiLeft + xStart,
+ guiTop + yStartTop + yOffset * 3,
+ 76
+ );
+ }
+ }
+ {
+ GuiProfileViewer.pronouns.peekValue().flatMap(it -> it).ifPresent(choice -> Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Pronouns",
+ EnumChatFormatting.WHITE + String.join(" / ", choice.render()),
+ guiLeft + xStart,
+ guiTop + yStartTop + yOffset * (shouldRenderGuild ? 4 : 3),
+ 76
+ ));
+ }
+
+ float fairySouls = Utils.getElementAsFloat(Utils.getElement(profileInfo, "fairy_souls_collected"), 0);
+
+ int fairySoulMax = 227;
+ if (Constants.FAIRYSOULS != null && Constants.FAIRYSOULS.has("Max Souls")) {
+ fairySoulMax = Constants.FAIRYSOULS.get("Max Souls").getAsInt();
+ }
+ Utils.renderAlignedString(
+ EnumChatFormatting.LIGHT_PURPLE + "Fairy Souls",
+ EnumChatFormatting.WHITE.toString() + (int) fairySouls + "/" + fairySoulMax,
+ guiLeft + xStart,
+ guiTop + yStartBottom,
+ 76
+ );
+
+ if (skyblockInfo != null) {
+ float totalSkillLVL = 0;
+ float totalTrueSkillLVL = 0;
+ float totalSlayerLVL = 0;
+ float totalSkillCount = 0;
+ float totalSlayerCount = 0;
+ float totalSlayerXP = 0;
+
+ List<String> skills = Arrays.asList(
+ "taming",
+ "mining",
+ "foraging",
+ "enchanting",
+ "farming",
+ "combat",
+ "fishing",
+ "alchemy",
+ "carpentry"
+ );
+ List<String> slayers = Arrays.asList("zombie", "spider", "wolf", "enderman", "blaze");
+
+ for (Map.Entry<String, ProfileViewer.Level> entry : skyblockInfo.entrySet()) {
+ if (skills.contains(entry.getKey())) {
+ totalSkillLVL += entry.getValue().level;
+ totalTrueSkillLVL += Math.floor(entry.getValue().level);
+ totalSkillCount++;
+ } else if (slayers.contains(entry.getKey())) {
+ totalSlayerLVL += entry.getValue().level;
+ totalSlayerCount++;
+ totalSlayerXP += entry.getValue().totalXp;
+ }
+ }
+
+ float avgSkillLVL = totalSkillLVL / totalSkillCount;
+ float avgTrueSkillLVL = totalTrueSkillLVL / totalSkillCount;
+ float avgSlayerLVL = totalSlayerLVL / totalSlayerCount;
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + "AVG Skill Level",
+ EnumChatFormatting.WHITE.toString() + Math.floor(avgSkillLVL * 10) / 10,
+ guiLeft + xStart,
+ guiTop + yStartBottom + yOffset,
+ 76
+ );
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + "True AVG Skill Level",
+ EnumChatFormatting.WHITE.toString() + Math.floor(avgTrueSkillLVL * 10) / 10,
+ guiLeft + xStart,
+ guiTop + yStartBottom + yOffset * 2,
+ 76
+ );
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + "AVG Slayer Level",
+ EnumChatFormatting.WHITE.toString() + Math.floor(avgSlayerLVL * 10) / 10,
+ guiLeft + xStart,
+ guiTop + yStartBottom + yOffset * 3,
+ 76
+ );
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + "Total Slayer XP",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(totalSlayerXP),
+ guiLeft + xStart,
+ guiTop + yStartBottom + yOffset * 4,
+ 76
+ );
+ }
+
+ float auctions_bids = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_bids"), 0);
+ float auctions_highest_bid = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "stats.auctions_highest_bid"),
+ 0
+ );
+ float auctions_won = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_won"), 0);
+ float auctions_created = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_created"), 0);
+ float auctions_gold_spent = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_gold_spent"), 0);
+ float auctions_gold_earned = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "stats.auctions_gold_earned"),
+ 0
+ );
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Auction Bids",
+ EnumChatFormatting.WHITE.toString() + (int) auctions_bids,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartTop,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Highest Bid",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(auctions_highest_bid),
+ guiLeft + xStart + xOffset,
+ guiTop + yStartTop + yOffset,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Auctions Won",
+ EnumChatFormatting.WHITE.toString() + (int) auctions_won,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartTop + yOffset * 2,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Auctions Created",
+ EnumChatFormatting.WHITE.toString() + (int) auctions_created,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartTop + yOffset * 3,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Gold Spent",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(auctions_gold_spent),
+ guiLeft + xStart + xOffset,
+ guiTop + yStartTop + yOffset * 4,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Gold Earned",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(auctions_gold_earned),
+ guiLeft + xStart + xOffset,
+ guiTop + yStartTop + yOffset * 5,
+ 76
+ );
+
+ //Slayer values
+ float zombie_boss_kills_tier_2 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_2"),
+ 0
+ );
+ float zombie_boss_kills_tier_3 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_3"),
+ 0
+ );
+ float zombie_boss_kills_tier_4 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_4"),
+ 0
+ );
+ float wolf_boss_kills_tier_2 = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "slayer_bosses.wolf.boss_kills_tier_2"
+ ), 0);
+ float wolf_boss_kills_tier_3 = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "slayer_bosses.wolf.boss_kills_tier_3"
+ ), 0);
+ float spider_boss_kills_tier_2 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.spider.boss_kills_tier_2"),
+ 0
+ );
+ float spider_boss_kills_tier_3 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.spider.boss_kills_tier_3"),
+ 0
+ );
+ float enderman_boss_kills_tier_2 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.enderman.boss_kills_tier_2"),
+ 0
+ );
+ float enderman_boss_kills_tier_3 = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "slayer_bosses.enderman.boss_kills_tier_3"),
+ 0
+ );
+ float blaze_boss_kills_tier_2 = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "slayer_bosses.blaze.boss_kills_tier_2"
+ ), 0);
+ float blaze_boss_kills_tier_3 = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "slayer_bosses.blaze.boss_kills_tier_3"
+ ), 0);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Revenant T3",
+ EnumChatFormatting.WHITE.toString() + (int) zombie_boss_kills_tier_2,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartBottom,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Revenant T4",
+ EnumChatFormatting.WHITE.toString() + (int) zombie_boss_kills_tier_3,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartBottom + yOffset,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Revenant T5",
+ EnumChatFormatting.WHITE.toString() + (int) zombie_boss_kills_tier_4,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartBottom + yOffset * 2,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Tarantula T3",
+ EnumChatFormatting.WHITE.toString() + (int) spider_boss_kills_tier_2,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartBottom + yOffset * 3,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Tarantula T4",
+ EnumChatFormatting.WHITE.toString() + (int) spider_boss_kills_tier_3,
+ guiLeft + xStart + xOffset,
+ guiTop + yStartBottom + yOffset * 4,
+ 76
+ );
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Sven T3",
+ EnumChatFormatting.WHITE.toString() + (int) wolf_boss_kills_tier_2,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartBottom + yOffset * 0,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Sven T4",
+ EnumChatFormatting.WHITE.toString() + (int) wolf_boss_kills_tier_3,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartBottom + yOffset * 1,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Voidgloom T3",
+ EnumChatFormatting.WHITE.toString() + (int) enderman_boss_kills_tier_2,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartBottom + yOffset * 2,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Voidgloom T4",
+ EnumChatFormatting.WHITE.toString() + (int) enderman_boss_kills_tier_3,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartBottom + yOffset * 3,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Inferno T3",
+ EnumChatFormatting.WHITE.toString() + (int) blaze_boss_kills_tier_2,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartBottom + yOffset * 4,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_AQUA + "Inferno T4",
+ EnumChatFormatting.WHITE.toString() + (int) blaze_boss_kills_tier_3,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartBottom + yOffset * 5,
+ 76
+ );
+
+ float pet_milestone_ores_mined = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "stats.pet_milestone_ores_mined"
+ ), 0);
+ float pet_milestone_sea_creatures_killed = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "stats.pet_milestone_sea_creatures_killed"),
+ 0
+ );
+
+ float items_fished = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished"), 0);
+ float items_fished_treasure = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "stats.items_fished_treasure"),
+ 0
+ );
+ float items_fished_large_treasure = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "stats.items_fished_large_treasure"
+ ), 0);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Ores Mined",
+ EnumChatFormatting.WHITE.toString() + (int) pet_milestone_ores_mined,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartTop,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Sea Creatures Killed",
+ EnumChatFormatting.WHITE.toString() + (int) pet_milestone_sea_creatures_killed,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartTop + yOffset,
+ 76
+ );
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Items Fished",
+ EnumChatFormatting.WHITE.toString() + (int) items_fished,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartTop + yOffset * 3,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Treasures Fished",
+ EnumChatFormatting.WHITE.toString() + (int) items_fished_treasure,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartTop + yOffset * 4,
+ 76
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Large Treasures",
+ EnumChatFormatting.WHITE.toString() + (int) items_fished_large_treasure,
+ guiLeft + xStart + xOffset * 2,
+ guiTop + yStartTop + yOffset * 5,
+ 76
+ );
+
+ if (topKills == null) {
+ topKills = new TreeMap<>();
+ JsonObject stats = profileInfo.get("stats").getAsJsonObject();
+ for (Map.Entry<String, JsonElement> entry : stats.entrySet()) {
+ if (entry.getKey().startsWith("kills_")) {
+ if (entry.getValue().isJsonPrimitive()) {
+ JsonPrimitive prim = (JsonPrimitive) entry.getValue();
+ if (prim.isNumber()) {
+ String name = WordUtils.capitalizeFully(entry.getKey().substring("kills_".length()).replace("_", " "));
+ Set<String> kills = topKills.computeIfAbsent(prim.getAsInt(), k -> new HashSet<>());
+ kills.add(name);
+ }
+ }
+ }
+ }
+ }
+ if (topDeaths == null) {
+ topDeaths = new TreeMap<>();
+ JsonObject stats = profileInfo.get("stats").getAsJsonObject();
+ for (Map.Entry<String, JsonElement> entry : stats.entrySet()) {
+ if (entry.getKey().startsWith("deaths_")) {
+ if (entry.getValue().isJsonPrimitive()) {
+ JsonPrimitive prim = (JsonPrimitive) entry.getValue();
+ if (prim.isNumber()) {
+ String name = WordUtils.capitalizeFully(entry.getKey().substring("deaths_".length()).replace("_", " "));
+ Set<String> deaths = topDeaths.computeIfAbsent(prim.getAsInt(), k -> new HashSet<>());
+ deaths.add(name);
+ }
+ }
+ }
+ }
+ }
+
+ int index = 0;
+ for (int killCount : topKills.descendingKeySet()) {
+ if (index >= 6) break;
+ Set<String> kills = topKills.get(killCount);
+ for (String killType : kills) {
+ if (index >= 6) break;
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + killType + " Kills",
+ EnumChatFormatting.WHITE.toString() + killCount,
+ guiLeft + xStart + xOffset * 3,
+ guiTop + yStartTop + yOffset * index,
+ 76
+ );
+ index++;
+ }
+ }
+ index = 0;
+ for (int deathCount : topDeaths.descendingKeySet()) {
+ if (index >= 6) break;
+ Set<String> deaths = topDeaths.get(deathCount);
+ for (String deathType : deaths) {
+ if (index >= 6) break;
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Deaths: " + deathType,
+ EnumChatFormatting.WHITE.toString() + deathCount,
+ guiLeft + xStart + xOffset * 3,
+ guiTop + yStartBottom + yOffset * index,
+ 76
+ );
+ index++;
+ }
+ }
+ }
+
+ private String getTimeSinceString(JsonObject profileInfo, String path) {
+ JsonElement lastSaveElement = Utils.getElement(profileInfo, path);
+
+ if (lastSaveElement != null && lastSaveElement.isJsonPrimitive()) {
+ Instant lastSave = Instant.ofEpochMilli(lastSaveElement.getAsLong());
+ LocalDateTime lastSaveTime = LocalDateTime.ofInstant(lastSave, TimeZone.getDefault().toZoneId());
+ long timeDiff = System.currentTimeMillis() - lastSave.toEpochMilli();
+ LocalDateTime sinceOnline = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeDiff), ZoneId.of("UTC"));
+ String renderText;
+
+ if (timeDiff < 60000L) {
+ renderText = sinceOnline.getSecond() + " seconds ago.";
+ } else if (timeDiff < 3600000L) {
+ renderText = sinceOnline.getMinute() + " minutes ago.";
+ } else if (timeDiff < 86400000L) {
+ renderText = sinceOnline.getHour() + " hours ago.";
+ } else if (timeDiff < 31556952000L) {
+ renderText = sinceOnline.getDayOfYear() + " days ago.";
+ } else {
+ renderText = lastSaveTime.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
+ }
+ return renderText;
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
index 44ea686d..98f186cb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewer.java
@@ -1,43 +1,55 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.profileviewer;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import com.mojang.authlib.GameProfile;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
import io.github.moulberry.notenoughupdates.cosmetics.ShaderManager;
import io.github.moulberry.notenoughupdates.itemeditor.GuiElementTextField;
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryPage;
+import io.github.moulberry.notenoughupdates.profileviewer.trophy.TrophyFishPage;
+import io.github.moulberry.notenoughupdates.util.AsyncDependencyLoader;
import io.github.moulberry.notenoughupdates.util.Constants;
-import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.PronounDB;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityOtherPlayerMP;
-import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
-import net.minecraft.client.renderer.RenderHelper;
-import net.minecraft.client.renderer.entity.RenderManager;
-import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.client.shader.Framebuffer;
import net.minecraft.client.shader.Shader;
-import net.minecraft.entity.EntityLivingBase;
-import net.minecraft.entity.player.EnumPlayerModelParts;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.*;
+import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.Matrix4f;
import net.minecraft.util.ResourceLocation;
-import org.apache.commons.lang3.text.WordUtils;
import org.lwjgl.input.Keyboard;
-import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL20;
@@ -47,29 +59,18 @@ import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.NumberFormat;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
-import java.util.*;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.function.Supplier;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
public class GuiProfileViewer extends GuiScreen {
- private static final ResourceLocation CHEST_GUI_TEXTURE =
- new ResourceLocation("textures/gui/container/generic_54.png");
- public static final ResourceLocation pv_basic = new ResourceLocation("notenoughupdates:pv_basic.png");
- public static final ResourceLocation pv_dung = new ResourceLocation("notenoughupdates:pv_dung.png");
- public static final ResourceLocation pv_extra = new ResourceLocation("notenoughupdates:pv_extra.png");
- public static final ResourceLocation pv_mining = new ResourceLocation("notenoughupdates:pv_mining.png");
- public static final ResourceLocation pv_invs = new ResourceLocation("notenoughupdates:pv_invs.png");
- public static final ResourceLocation pv_cols = new ResourceLocation("notenoughupdates:pv_cols.png");
- public static final ResourceLocation pv_pets = new ResourceLocation("notenoughupdates:pv_pets.png");
+
public static final ResourceLocation pv_dropdown = new ResourceLocation("notenoughupdates:pv_dropdown.png");
public static final ResourceLocation pv_bg = new ResourceLocation("notenoughupdates:pv_bg.png");
public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png");
@@ -80,64 +81,232 @@ public class GuiProfileViewer extends GuiScreen {
public static final ResourceLocation resource_packs =
new ResourceLocation("minecraft:textures/gui/resource_packs.png");
public static final ResourceLocation icons = new ResourceLocation("textures/gui/icons.png");
+ public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS =
+ new HashMap<String, HashMap<String, Float>>() {
+ {
+ put(
+ "PET_ITEM_BIG_TEETH_COMMON",
+ new HashMap<String, Float>() {
+ {
+ put("CRIT_CHANCE", 5f);
+ }
+ }
+ );
+ put(
+ "PET_ITEM_HARDENED_SCALES_UNCOMMON",
+ new HashMap<String, Float>() {
+ {
+ put("DEFENCE", 25f);
+ }
+ }
+ );
+ put(
+ "PET_ITEM_LUCKY_CLOVER",
+ new HashMap<String, Float>() {
+ {
+ put("MAGIC_FIND", 7f);
+ }
+ }
+ );
+ put(
+ "PET_ITEM_SHARPENED_CLAWS_UNCOMMON",
+ new HashMap<String, Float>() {
+ {
+ put("CRIT_DAMAGE", 15f);
+ }
+ }
+ );
+ }
+ };
+ public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS_MULT =
+ new HashMap<String, HashMap<String, Float>>() {
+ {
+ put(
+ "PET_ITEM_IRON_CLAWS_COMMON",
+ new HashMap<String, Float>() {
+ {
+ put("CRIT_DAMAGE", 1.4f);
+ put("CRIT_CHANCE", 1.4f);
+ }
+ }
+ );
+ put(
+ "PET_ITEM_TEXTBOOK",
+ new HashMap<String, Float>() {
+ {
+ put("INTELLIGENCE", 2f);
+ }
+ }
+ );
+ }
+ };
- private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
+ public static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
- private final ProfileViewer.Profile profile;
+ private static final char[] c = new char[]{'k', 'm', 'b', 't'};
public static ProfileViewerPage currentPage = ProfileViewerPage.BASIC;
- private int sizeX;
- private int sizeY;
- private int guiLeft;
- private int guiTop;
-
- private float backgroundRotation = 0;
-
- private long currentTime = 0;
- private long lastTime = 0;
- private long startTime = 0;
-
- private List<String> tooltipToDisplay = null;
-
- private String profileId = null;
+ public static HashMap<String, String> MINION_RARITY_TO_NUM = new HashMap<String, String>() {
+ {
+ put("COMMON", "0");
+ put("UNCOMMON", "1");
+ put("RARE", "2");
+ put("EPIC", "3");
+ put("LEGENDARY", "4");
+ put("MYTHIC", "5");
+ }
+ };
+ private static int guiLeft;
+ private static int guiTop;
+ private static ProfileViewer.Profile profile;
+ private static String profileId = null;
+ public static AsyncDependencyLoader<Optional<PronounDB.PronounChoice>> pronouns =
+ AsyncDependencyLoader.withEqualsInvocation(
+ () ->
+ NotEnoughUpdates.INSTANCE.config.profileViewer.showPronounsInPv
+ ? Optional.ofNullable(profile).map(it -> Utils.parseDashlessUUID(it.getUuid()))
+ : Optional.<UUID>empty(),
+ uuid -> uuid.isPresent()
+ ? PronounDB.getPronounsFor(uuid.get())
+ : CompletableFuture.completedFuture(Optional.empty())
+ );
+ public final GuiElementTextField playerNameTextField;
+ public final GuiElementTextField inventoryTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT);
+ private final Map<ProfileViewerPage, GuiProfileViewerPage> pages = new HashMap<>();
+ public int sizeX;
+ public int sizeY;
+ public float backgroundRotation = 0;
+ public long currentTime = 0;
+ public long lastTime = 0;
+ public long startTime = 0;
+ public List<String> tooltipToDisplay = null;
+ Shader blurShaderHorz = null;
+ Framebuffer blurOutputHorz = null;
+ Shader blurShaderVert = null;
+ Framebuffer blurOutputVert = null;
private boolean profileDropdownSelected = false;
- public enum ProfileViewerPage {
- LOADING(null),
- INVALID_NAME(null),
- NO_SKYBLOCK(null),
- BASIC(new ItemStack(Items.paper)),
- DUNG(new ItemStack(Item.getItemFromBlock(Blocks.deadbush))),
- EXTRA(new ItemStack(Items.book)),
- INVS(new ItemStack(Item.getItemFromBlock(Blocks.ender_chest))),
- COLS(new ItemStack(Items.painting)),
- PETS(new ItemStack(Items.bone)),
- MINING(new ItemStack(Items.iron_pickaxe));
-
- public final ItemStack stack;
-
- ProfileViewerPage(ItemStack stack) {
- this.stack = stack;
- }
- }
+ private double lastBgBlurFactor = -1;
+ private boolean showBingoPage;
public GuiProfileViewer(ProfileViewer.Profile profile) {
- this.profile = profile;
+ GuiProfileViewer.profile = profile;
+ GuiProfileViewer.profileId = profile.getLatestProfile();
String name = "";
- if (profile != null && profile.getHypixelProfile() != null) {
+ if (profile.getHypixelProfile() != null) {
name = profile.getHypixelProfile().get("displayname").getAsString();
}
- playerNameTextField = new GuiElementTextField(
- name,
- GuiElementTextField.SCALE_TEXT
- );
+ playerNameTextField = new GuiElementTextField(name, GuiElementTextField.SCALE_TEXT);
playerNameTextField.setSize(100, 20);
if (currentPage == ProfileViewerPage.LOADING) {
currentPage = ProfileViewerPage.BASIC;
}
+
+ pages.put(ProfileViewerPage.BASIC, new BasicPage(this));
+ pages.put(ProfileViewerPage.DUNGEON, new DungeonPage(this));
+ pages.put(ProfileViewerPage.EXTRA, new ExtraPage(this));
+ pages.put(ProfileViewerPage.INVENTORIES, new InventoriesPage(this));
+ pages.put(ProfileViewerPage.COLLECTIONS, new CollectionsPage(this));
+ pages.put(ProfileViewerPage.PETS, new PetsPage(this));
+ pages.put(ProfileViewerPage.MINING, new MiningPage(this));
+ pages.put(ProfileViewerPage.BINGO, new BingoPage(this));
+ pages.put(ProfileViewerPage.TROPHY_FISH, new TrophyFishPage(this));
+ pages.put(ProfileViewerPage.BESTIARY, new BestiaryPage(this));
+ }
+
+ private static float getMaxLevelXp(JsonArray levels, int offset, int maxLevel) {
+ float xpTotal = 0;
+
+ for (int i = offset; i < offset + maxLevel - 1; i++) {
+ xpTotal += levels.get(i).getAsFloat();
+ }
+
+ return xpTotal;
+ }
+
+ public static PetLevel getPetLevel(
+ String petType,
+ String rarity,
+ float exp
+ ) {
+ int offset = PetInfoOverlay.Rarity.valueOf(rarity).petOffset;
+ int maxLevel = 100;
+
+ JsonArray levels = new JsonArray();
+ levels.addAll(Constants.PETS.get("pet_levels").getAsJsonArray());
+ JsonElement customLevelingJson = Constants.PETS.get("custom_pet_leveling").getAsJsonObject().get(petType);
+ if (customLevelingJson != null) {
+ switch (Utils.getElementAsInt(Utils.getElement(customLevelingJson, "type"), 0)) {
+ case 1:
+ levels.addAll(customLevelingJson.getAsJsonObject().get("pet_levels").getAsJsonArray());
+ break;
+ case 2:
+ levels = customLevelingJson.getAsJsonObject().get("pet_levels").getAsJsonArray();
+ break;
+ }
+ maxLevel = Utils.getElementAsInt(Utils.getElement(customLevelingJson, "max_level"), 100);
+ }
+
+ float maxXP = getMaxLevelXp(levels, offset, maxLevel);
+ boolean isMaxed = exp >= maxXP;
+
+ int level = 1;
+ float currentLevelRequirement = 0;
+ float xpThisLevel = 0;
+ float pct = 0;
+
+ if (isMaxed) {
+ level = maxLevel;
+ currentLevelRequirement = levels.get(offset + level - 2).getAsFloat();
+ xpThisLevel = currentLevelRequirement;
+ pct = 1;
+ } else {
+ long totalExp = 0;
+ for (int i = offset; i < levels.size(); i++) {
+ currentLevelRequirement = levels.get(i).getAsLong();
+ totalExp += currentLevelRequirement;
+ if (totalExp >= exp) {
+ xpThisLevel = currentLevelRequirement - (totalExp - exp);
+ level = Math.min(i - offset + 1, maxLevel);
+ break;
+ }
+ }
+ pct = currentLevelRequirement != 0 ? xpThisLevel / currentLevelRequirement : 0;
+ level += pct;
+ }
+
+ GuiProfileViewer.PetLevel levelObj = new GuiProfileViewer.PetLevel();
+ levelObj.level = level;
+ levelObj.maxLevel = maxLevel;
+ levelObj.currentLevelRequirement = currentLevelRequirement;
+ levelObj.maxXP = maxXP;
+ levelObj.levelPercentage = pct;
+ levelObj.levelXp = xpThisLevel;
+ levelObj.totalXp = exp;
+ return levelObj;
}
- private final GuiElementTextField playerNameTextField;
+ @Deprecated
+ public static String shortNumberFormat(double n, int iteration) {
+ return StringUtils.shortNumberFormat(n, iteration
+ );
+ }
+
+ public static int getGuiLeft() {
+ return guiLeft;
+ }
+
+ public static int getGuiTop() {
+ return guiTop;
+ }
+
+ public static ProfileViewer.Profile getProfile() {
+ return profile;
+ }
+
+ public static String getProfileId() {
+ return profileId;
+ }
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
@@ -147,7 +316,7 @@ public class GuiProfileViewer extends GuiScreen {
ProfileViewerPage page = currentPage;
if (profile == null) {
page = ProfileViewerPage.INVALID_NAME;
- } else if (profile.getPlayerInformation(null) == null) {
+ } else if (profile.getSkyblockProfiles(null) == null) {
page = ProfileViewerPage.LOADING;
} else if (profile.getLatestProfile() == null) {
page = ProfileViewerPage.NO_SKYBLOCK;
@@ -159,14 +328,26 @@ public class GuiProfileViewer extends GuiScreen {
{
//this is just to cache the guild info
if (profile != null) {
- JsonObject guildinfo = profile.getGuildInfo(null);
+ profile.getGuildInformation(null);
}
}
this.sizeX = 431;
this.sizeY = 202;
- this.guiLeft = (this.width - this.sizeX) / 2;
- this.guiTop = (this.height - this.sizeY) / 2;
+ guiLeft = (this.width - this.sizeX) / 2;
+ guiTop = (this.height - this.sizeY) / 2;
+
+ JsonObject currProfileInfo = profile != null ? profile.getProfileInformation(profileId) : null;
+ if (NotEnoughUpdates.INSTANCE.config.profileViewer.alwaysShowBingoTab) {
+ showBingoPage = true;
+ } else {
+ showBingoPage =
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("bingo");
+ }
+
+ if (!showBingoPage && currentPage == ProfileViewerPage.BINGO) currentPage = ProfileViewerPage.BASIC;
super.drawScreen(mouseX, mouseY, partialTicks);
drawDefaultBackground();
@@ -199,42 +380,57 @@ public class GuiProfileViewer extends GuiScreen {
ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
if (profile != null) {
- JsonObject currProfileInfo = profile.getProfileInformation(profileId);
//Render Profile chooser button
renderBlurredBackground(width, height, guiLeft + 2, guiTop + sizeY + 3 + 2, 100 - 4, 20 - 4);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown);
- Utils.drawTexturedRect(guiLeft, guiTop + sizeY + 3, 100, 20,
- 0, 100 / 200f, 0, 20 / 185f, GL11.GL_NEAREST
- );
- Utils.drawStringCenteredScaledMaxWidth(profileId, Minecraft.getMinecraft().fontRendererObj, guiLeft + 50,
- guiTop + sizeY + 3 + 10, true, 90, new Color(63, 224, 208, 255).getRGB()
+ Utils.drawTexturedRect(guiLeft, guiTop + sizeY + 3, 100, 20, 0, 100 / 200f, 0, 20 / 185f, GL11.GL_NEAREST);
+ Utils.drawStringCenteredScaledMaxWidth(
+ profileId,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 50,
+ guiTop + sizeY + 3 + 10,
+ true,
+ 90,
+ new Color(63, 224, 208, 255).getRGB()
);
//ironman icon
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- currProfileInfo.get("game_mode").getAsString().equals("ironman")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("ironman")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_ironman);
Utils.drawTexturedRect(guiLeft - 16 - 5, guiTop + sizeY + 5, 16, 16, GL11.GL_NEAREST);
}
//bingo! icon
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- currProfileInfo.get("game_mode").getAsString().equals("bingo")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("bingo")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_bingo);
Utils.drawTexturedRect(guiLeft - 16 - 5, guiTop + sizeY + 5, 16, 16, GL11.GL_NEAREST);
}
//stranded icon
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- currProfileInfo.get("game_mode").getAsString().equals("island")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("island")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_stranded);
Utils.drawTexturedRect(guiLeft - 16 - 5, guiTop + sizeY + 5, 16, 16, GL11.GL_NEAREST);
}
//icon if game mode is unknown
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- !currProfileInfo.get("game_mode").getAsString().equals("island") &&
- !currProfileInfo.get("game_mode").getAsString().equals("bingo") &&
- !currProfileInfo.get("game_mode").getAsString().equals("ironman")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ !currProfileInfo.get("game_mode").getAsString().equals("island") &&
+ !currProfileInfo.get("game_mode").getAsString().equals("bingo") &&
+ !currProfileInfo.get("game_mode").getAsString().equals("ironman")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_unknown);
Utils.drawTexturedRect(guiLeft - 16 - 5, guiTop + sizeY + 5, 16, 16, GL11.GL_NEAREST);
@@ -242,8 +438,16 @@ public class GuiProfileViewer extends GuiScreen {
//Render Open In Skycrypt button
renderBlurredBackground(width, height, guiLeft + 100 + 6 + 2, guiTop + sizeY + 3 + 2, 100 - 4, 20 - 4);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown);
- Utils.drawTexturedRect(guiLeft + 100 + 6, guiTop + sizeY + 3, 100, 20,
- 0, 100 / 200f, 0, 20 / 185f, GL11.GL_NEAREST
+ Utils.drawTexturedRect(
+ guiLeft + 100 + 6,
+ guiTop + sizeY + 3,
+ 100,
+ 20,
+ 0,
+ 100 / 200f,
+ 0,
+ 20 / 185f,
+ GL11.GL_NEAREST
);
Utils.drawStringCenteredScaledMaxWidth(
"Open in Skycrypt",
@@ -255,25 +459,39 @@ public class GuiProfileViewer extends GuiScreen {
new Color(63, 224, 208, 255).getRGB()
);
- if (profileDropdownSelected && !profile.getProfileIds().isEmpty() && scaledResolution.getScaleFactor() != 4) {
+ if (profileDropdownSelected && !profile.getProfileNames().isEmpty() && scaledResolution.getScaleFactor() < 4) {
int dropdownOptionSize = scaledResolution.getScaleFactor() == 3 ? 10 : 20;
- int numProfiles = profile.getProfileIds().size();
+ int numProfiles = profile.getProfileNames().size();
int sizeYDropdown = numProfiles * dropdownOptionSize;
renderBlurredBackground(width, height, guiLeft + 2, guiTop + sizeY + 23, 100 - 4, sizeYDropdown - 2);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dropdown);
- Utils.drawTexturedRect(guiLeft, guiTop + sizeY + 23 - 3, 100, 3,
- 100 / 200f, 1, 0, 3 / 185f, GL11.GL_NEAREST
+ Utils.drawTexturedRect(guiLeft, guiTop + sizeY + 23 - 3, 100, 3, 100 / 200f, 1, 0, 3 / 185f, GL11.GL_NEAREST);
+ Utils.drawTexturedRect(
+ guiLeft,
+ guiTop + sizeY + 23 + sizeYDropdown - 4,
+ 100,
+ 4,
+ 100 / 200f,
+ 1,
+ 181 / 185f,
+ 1,
+ GL11.GL_NEAREST
);
- Utils.drawTexturedRect(guiLeft, guiTop + sizeY + 23 + sizeYDropdown - 4, 100, 4,
- 100 / 200f, 1, 181 / 185f, 1, GL11.GL_NEAREST
- );
- Utils.drawTexturedRect(guiLeft, guiTop + sizeY + 23, 100, sizeYDropdown - 4,
- 100 / 200f, 1, (181 - sizeYDropdown) / 185f, 181 / 185f, GL11.GL_NEAREST
+ Utils.drawTexturedRect(
+ guiLeft,
+ guiTop + sizeY + 23,
+ 100,
+ sizeYDropdown - 4,
+ 100 / 200f,
+ 1,
+ (181 - sizeYDropdown) / 185f,
+ 181 / 185f,
+ GL11.GL_NEAREST
);
- for (int yIndex = 0; yIndex < profile.getProfileIds().size(); yIndex++) {
- String otherProfileId = profile.getProfileIds().get(yIndex);
+ for (int yIndex = 0; yIndex < profile.getProfileNames().size(); yIndex++) {
+ String otherProfileId = profile.getProfileNames().get(yIndex);
Utils.drawStringCenteredScaledMaxWidth(
otherProfileId,
Minecraft.getMinecraft().fontRendererObj,
@@ -284,8 +502,11 @@ public class GuiProfileViewer extends GuiScreen {
new Color(33, 112, 104, 255).getRGB()
);
currProfileInfo = profile.getProfileInformation(otherProfileId);
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- currProfileInfo.get("game_mode").getAsString().equals("ironman")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("ironman")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_ironman);
Utils.drawTexturedRect(
@@ -296,8 +517,11 @@ public class GuiProfileViewer extends GuiScreen {
GL11.GL_NEAREST
);
}
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- currProfileInfo.get("game_mode").getAsString().equals("bingo")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("bingo")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_bingo);
Utils.drawTexturedRect(
@@ -308,8 +532,11 @@ public class GuiProfileViewer extends GuiScreen {
GL11.GL_NEAREST
);
}
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- currProfileInfo.get("game_mode").getAsString().equals("island")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ currProfileInfo.get("game_mode").getAsString().equals("island")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_stranded);
Utils.drawTexturedRect(
@@ -320,10 +547,13 @@ public class GuiProfileViewer extends GuiScreen {
GL11.GL_NEAREST
);
}
- if (currProfileInfo != null && currProfileInfo.has("game_mode") &&
- !currProfileInfo.get("game_mode").getAsString().equals("island") &&
- !currProfileInfo.get("game_mode").getAsString().equals("bingo") &&
- !currProfileInfo.get("game_mode").getAsString().equals("ironman")) {
+ if (
+ currProfileInfo != null &&
+ currProfileInfo.has("game_mode") &&
+ !currProfileInfo.get("game_mode").getAsString().equals("island") &&
+ !currProfileInfo.get("game_mode").getAsString().equals("bingo") &&
+ !currProfileInfo.get("game_mode").getAsString().equals("ironman")
+ ) {
GlStateManager.color(1, 1, 1, 1);
Minecraft.getMinecraft().getTextureManager().bindTexture(pv_unknown);
Utils.drawTexturedRect(
@@ -335,163 +565,156 @@ public class GuiProfileViewer extends GuiScreen {
);
}
}
-
}
}
}
GlStateManager.color(1, 1, 1, 1);
- switch (page) {
- case BASIC:
- drawBasicPage(mouseX, mouseY, partialTicks);
- break;
- case DUNG:
- drawDungPage(mouseX, mouseY, partialTicks);
- break;
- case EXTRA:
- drawExtraPage(mouseX, mouseY, partialTicks);
- break;
- case INVS:
- drawInvsPage(mouseX, mouseY, partialTicks);
- break;
- case COLS:
- drawColsPage(mouseX, mouseY, partialTicks);
- break;
- case PETS:
- drawPetsPage(mouseX, mouseY, partialTicks);
- break;
- case MINING:
- drawMiningPage(mouseX, mouseY, partialTicks);
- break;
- case LOADING:
- String str = EnumChatFormatting.YELLOW + "Loading player profiles.";
- long currentTimeMod = System.currentTimeMillis() % 1000;
- if (currentTimeMod > 333) {
- if (currentTimeMod < 666) {
- str += ".";
- } else {
- str += "..";
- }
- }
-
- Utils.drawStringCentered(str, Minecraft.getMinecraft().fontRendererObj,
- guiLeft + sizeX / 2f, guiTop + 101, true, 0
- );
- //This is just here to inform the player what to do
- //like typing /api new or telling them to go find a psychotherapist
- long timeDiff = System.currentTimeMillis() - startTime;
+ if (pages.containsKey(page)) {
+ pages.get(page).drawPage(mouseX, mouseY, partialTicks);
+ } else {
+ switch (page) {
+ case LOADING:
+ String str = EnumChatFormatting.YELLOW + "Loading player profiles.";
+ long currentTimeMod = System.currentTimeMillis() % 1000;
+ if (currentTimeMod > 333) {
+ if (currentTimeMod < 666) {
+ str += ".";
+ } else {
+ str += "..";
+ }
+ }
- if (timeDiff > 20000) {
- Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + "Its taking a while...",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + sizeX / 2f,
- guiTop + 111,
- true,
- 0
- );
Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + "Try \"/api new\".",
+ str,
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 121,
+ guiTop + 101,
true,
0
);
- if (timeDiff > 60000) {
+
+ //This is just here to inform the player what to do
+ //like typing /api new or telling them to go find a psychotherapist
+ long timeDiff = System.currentTimeMillis() - startTime;
+
+ if (timeDiff > 20000) {
Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + "Might be hypixel's fault.",
+ EnumChatFormatting.YELLOW + "Its taking a while...",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 131,
+ guiTop + 111,
true,
0
);
- if (timeDiff > 180000) {
+ Utils.drawStringCentered(
+ EnumChatFormatting.YELLOW + "Try \"/api new\".",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + sizeX / 2f,
+ guiTop + 121,
+ true,
+ 0
+ );
+ if (timeDiff > 60000) {
Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + "Wow you're still here?",
+ EnumChatFormatting.YELLOW + "Might be hypixel's fault.",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 141,
+ guiTop + 131,
true,
0
);
- if (timeDiff > 360000) {
- long second = (timeDiff / 1000) % 60;
- long minute = (timeDiff / (1000 * 60)) % 60;
- long hour = (timeDiff / (1000 * 60 * 60)) % 24;
-
- String time = String.format("%02d:%02d:%02d", hour, minute, second);
- Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + "You've wasted your time here for: " + time,
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + sizeX / 2f,
- guiTop + 151,
- true,
- 0
- );
+ if (timeDiff > 180000) {
Utils.drawStringCentered(
- EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "What are you doing with your life?",
+ EnumChatFormatting.YELLOW + "Wow you're still here?",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 161,
+ guiTop + 141,
true,
0
);
- if (timeDiff > 600000) {
+ if (timeDiff > 360000) {
+ long second = (timeDiff / 1000) % 60;
+ long minute = (timeDiff / (1000 * 60)) % 60;
+ long hour = (timeDiff / (1000 * 60 * 60)) % 24;
+
+ String time = String.format("%02d:%02d:%02d", hour, minute, second);
Utils.drawStringCentered(
- EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD + "Maniac",
+ EnumChatFormatting.YELLOW + "You've wasted your time here for: " + time,
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 171,
+ guiTop + 151,
true,
0
);
- if (timeDiff > 1200000) {
+ Utils.drawStringCentered(
+ EnumChatFormatting.YELLOW + "" + EnumChatFormatting.BOLD + "What are you doing with your life?",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + sizeX / 2f,
+ guiTop + 161,
+ true,
+ 0
+ );
+ if (timeDiff > 600000) {
Utils.drawStringCentered(
- EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD + "You're a menace to society",
+ EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD + "Maniac",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 181,
+ guiTop + 171,
true,
0
);
- if (timeDiff > 1800000) {
+ if (timeDiff > 1200000) {
Utils.drawStringCentered(
- EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD +
- "You don't know what's gonna happen to you",
+ EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD + "You're a menace to society",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 191,
+ guiTop + 181,
true,
0
);
- if (timeDiff > 3000000) {
+ if (timeDiff > 1800000) {
Utils.drawStringCentered(
- EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD + "You really want this?",
+ EnumChatFormatting.RED +
+ "" +
+ EnumChatFormatting.BOLD +
+ "You don't know what's gonna happen to you",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 91,
+ guiTop + 191,
true,
0
);
- if (timeDiff > 3300000) {
+ if (timeDiff > 3000000) {
Utils.drawStringCentered(
- EnumChatFormatting.DARK_RED + "" + EnumChatFormatting.BOLD + "OW LORD FORGIVE ME FOR THIS",
+ EnumChatFormatting.RED + "" + EnumChatFormatting.BOLD + "You really want this?",
Minecraft.getMinecraft().fontRendererObj,
guiLeft + sizeX / 2f,
- guiTop + 71,
+ guiTop + 91,
true,
0
);
- if (timeDiff > 3600000) {
- throw new Error("Go do something productive") {
- @Override
- public void printStackTrace() {
- throw new Error("Go do something productive");
- }
- };
+ if (timeDiff > 3300000) {
+ Utils.drawStringCentered(
+ EnumChatFormatting.DARK_RED +
+ "" +
+ EnumChatFormatting.BOLD +
+ "OW LORD FORGIVE ME FOR THIS",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + sizeX / 2f,
+ guiTop + 71,
+ true,
+ 0
+ );
+ if (timeDiff > 3600000) {
+ throw new Error("Go do something productive") {
+ @Override
+ public void printStackTrace() {
+ throw new Error("Go do something productive");
+ }
+ };
+ }
}
}
}
@@ -501,33 +724,61 @@ public class GuiProfileViewer extends GuiScreen {
}
}
}
- }
- break;
- case INVALID_NAME:
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "Invalid name or API is down!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + sizeX / 2f,
- guiTop + 101,
- true,
- 0
- );
- break;
- case NO_SKYBLOCK:
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "No skyblock data found!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + sizeX / 2f,
- guiTop + 101,
- true,
- 0
- );
- break;
+ break;
+ case INVALID_NAME:
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "Invalid name or API is down!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + sizeX / 2f,
+ guiTop + 101,
+ true,
+ 0
+ );
+ break;
+ case NO_SKYBLOCK:
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "No skyblock data found!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + sizeX / 2f,
+ guiTop + 101,
+ true,
+ 0
+ );
+ break;
+ }
}
lastTime = currentTime;
+ if (currentPage != ProfileViewerPage.LOADING && currentPage != ProfileViewerPage.INVALID_NAME) {
+ int ignoredTabs = 0;
+ List<Integer> configList = NotEnoughUpdates.INSTANCE.config.profileViewer.pageLayout;
+ for (int i = 0; i < configList.size(); i++) {
+ ProfileViewerPage iPage = ProfileViewerPage.getById(configList.get(i));
+ if (iPage == null) continue;
+ if (iPage.stack == null || (iPage == ProfileViewerPage.BINGO && !showBingoPage)) {
+ ignoredTabs++;
+ continue;
+ }
+ int i2 = i - ignoredTabs;
+ int x = guiLeft + i2 * 28;
+ int y = guiTop - 28;
+
+ if (mouseX > x && mouseX < x + 28) {
+ if (mouseY > y && mouseY < y + 32) {
+ if (!iPage.stack
+ .getTooltip(Minecraft.getMinecraft().thePlayer, false)
+ .isEmpty()) {
+ tooltipToDisplay = Collections.singletonList(iPage.stack
+ .getTooltip(Minecraft.getMinecraft().thePlayer, false)
+ .get(0));
+ }
+ }
+ }
+ }
+ }
+
if (tooltipToDisplay != null) {
List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size());
for (String line : tooltipToDisplay) {
@@ -540,9 +791,11 @@ public class GuiProfileViewer extends GuiScreen {
private void renderTabs(boolean renderPressed) {
int ignoredTabs = 0;
- for (int i = 0; i < ProfileViewerPage.values().length; i++) {
- ProfileViewerPage page = ProfileViewerPage.values()[i];
- if (page.stack == null) {
+ List<Integer> configList = NotEnoughUpdates.INSTANCE.config.profileViewer.pageLayout;
+ for (int i = 0; i < configList.size(); i++) {
+ ProfileViewerPage page = ProfileViewerPage.getById(configList.get(i));
+ if (page == null) continue;
+ if (page.stack == null || (page == ProfileViewerPage.BINGO && !showBingoPage)) {
ignoredTabs++;
continue;
}
@@ -598,9 +851,11 @@ public class GuiProfileViewer extends GuiScreen {
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
if (currentPage != ProfileViewerPage.LOADING && currentPage != ProfileViewerPage.INVALID_NAME) {
int ignoredTabs = 0;
- for (int i = 0; i < ProfileViewerPage.values().length; i++) {
- ProfileViewerPage page = ProfileViewerPage.values()[i];
- if (page.stack == null) {
+ List<Integer> configList = NotEnoughUpdates.INSTANCE.config.profileViewer.pageLayout;
+ for (int i = 0; i < configList.size(); i++) {
+ ProfileViewerPage page = ProfileViewerPage.getById(configList.get(i));
+ if (page == null) continue;
+ if (page.stack == null || (page == ProfileViewerPage.BINGO && !showBingoPage)) {
ignoredTabs++;
continue;
}
@@ -619,38 +874,13 @@ public class GuiProfileViewer extends GuiScreen {
}
}
}
- switch (currentPage) {
- case DUNG:
- mouseClickedDung(mouseX, mouseY, mouseButton);
- break;
- case INVS:
- inventoryTextField.setSize(88, 20);
- if (mouseX > guiLeft + 19 && mouseX < guiLeft + 19 + 88) {
- if (mouseY > guiTop + sizeY - 26 - 20 && mouseY < guiTop + sizeY - 26) {
- inventoryTextField.mouseClicked(mouseX, mouseY, mouseButton);
- playerNameTextField.otherComponentClick();
- return;
- }
- }
- break;
- case PETS:
- if (sortedPets == null) break;
- for (int i = petsPage * 20; i < Math.min(petsPage * 20 + 20, sortedPets.size()); i++) {
- int xIndex = (i % 20) % COLLS_XCOUNT;
- int yIndex = (i % 20) / COLLS_XCOUNT;
- float x = 5 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
- float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
-
- if (mouseX > guiLeft + x && mouseX < guiLeft + x + 20) {
- if (mouseY > guiTop + y && mouseY < guiTop + y + 20) {
- selectedPet = i;
- return;
- }
- }
- }
- break;
+ if (pages.containsKey(currentPage)) {
+ if (pages.get(currentPage).mouseClicked(mouseX, mouseY, mouseButton)) {
+ return;
+ }
}
+
if (mouseX > guiLeft + sizeX - 100 && mouseX < guiLeft + sizeX) {
if (mouseY > guiTop + sizeY + 5 && mouseY < guiTop + sizeY + 25) {
playerNameTextField.mouseClicked(mouseX, mouseY, mouseButton);
@@ -658,14 +888,22 @@ public class GuiProfileViewer extends GuiScreen {
return;
}
}
- if (mouseX > guiLeft + 106 && mouseX < guiLeft + 106 + 100 && profile != null &&
- !profile.getProfileIds().isEmpty() && profileId != null) {
+ if (
+ mouseX > guiLeft + 106 &&
+ mouseX < guiLeft + 106 + 100 &&
+ profile != null &&
+ !profile.getProfileNames().isEmpty() &&
+ profileId != null
+ ) {
if (mouseY > guiTop + sizeY + 3 && mouseY < guiTop + sizeY + 23) {
try {
Desktop desk = Desktop.getDesktop();
- desk.browse(new URI(
- "https://sky.shiiyu.moe/stats/" + profile.getHypixelProfile().get("displayname").getAsString() + "/" +
- profileId));
+ desk.browse(
+ new URI(
+ "https://sky.shiiyu.moe/stats/" + profile.getHypixelProfile().get("displayname").getAsString() + "/" +
+ profileId
+ )
+ );
Utils.playPressSound();
return;
} catch (UnsupportedOperationException | IOException | URISyntaxException ignored) {
@@ -676,14 +914,14 @@ public class GuiProfileViewer extends GuiScreen {
}
}
- if (mouseX > guiLeft && mouseX < guiLeft + 100 && profile != null && !profile.getProfileIds().isEmpty()) {
+ if (mouseX > guiLeft && mouseX < guiLeft + 100 && profile != null && !profile.getProfileNames().isEmpty()) {
ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
if (mouseY > guiTop + sizeY + 3 && mouseY < guiTop + sizeY + 23) {
- if (scaledResolution.getScaleFactor() == 4) {
+ if (scaledResolution.getScaleFactor() >= 4) {
profileDropdownSelected = false;
int profileNum = 0;
- for (int index = 0; index < profile.getProfileIds().size(); index++) {
- if (profile.getProfileIds().get(index).equals(profileId)) {
+ for (int index = 0; index < profile.getProfileNames().size(); index++) {
+ if (profile.getProfileNames().get(index).equals(profileId)) {
profileNum = index;
break;
}
@@ -693,10 +931,10 @@ public class GuiProfileViewer extends GuiScreen {
} else {
profileNum--;
}
- if (profileNum >= profile.getProfileIds().size()) profileNum = 0;
- if (profileNum < 0) profileNum = profile.getProfileIds().size() - 1;
+ if (profileNum >= profile.getProfileNames().size()) profileNum = 0;
+ if (profileNum < 0) profileNum = profile.getProfileNames().size() - 1;
- String newProfileId = profile.getProfileIds().get(profileNum);
+ String newProfileId = profile.getProfileNames().get(profileNum);
if (profileId != null && !profileId.equals(newProfileId)) {
resetCache();
}
@@ -704,12 +942,12 @@ public class GuiProfileViewer extends GuiScreen {
} else {
profileDropdownSelected = !profileDropdownSelected;
}
- } else if (scaledResolution.getScaleFactor() != 4 && profileDropdownSelected) {
+ } else if (scaledResolution.getScaleFactor() < 4 && profileDropdownSelected) {
int dropdownOptionSize = scaledResolution.getScaleFactor() == 3 ? 10 : 20;
int extraY = mouseY - (guiTop + sizeY + 23);
int index = extraY / dropdownOptionSize;
- if (index >= 0 && index < profile.getProfileIds().size()) {
- String newProfileId = profile.getProfileIds().get(index);
+ if (index >= 0 && index < profile.getProfileNames().size()) {
+ String newProfileId = profile.getProfileNames().get(index);
if (profileId != null && !profileId.equals(newProfileId)) {
resetCache();
}
@@ -728,25 +966,21 @@ public class GuiProfileViewer extends GuiScreen {
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
super.keyTyped(typedChar, keyCode);
- switch (currentPage) {
- case INVS:
- keyTypedInvs(typedChar, keyCode);
- inventoryTextField.keyTyped(typedChar, keyCode);
- break;
- case COLS:
- keyTypedCols(typedChar, keyCode);
- break;
- case DUNG:
- keyTypedDung(typedChar, keyCode);
- break;
+
+ if (pages.containsKey(currentPage)) {
+ pages.get(currentPage).keyTyped(typedChar, keyCode);
}
- if (playerNameTextField.getFocus() && !(currentPage == ProfileViewerPage.LOADING)) {
+
+ if (playerNameTextField.getFocus()) {
if (keyCode == Keyboard.KEY_RETURN) {
currentPage = ProfileViewerPage.LOADING;
- NotEnoughUpdates.profileViewer.getProfileByName(playerNameTextField.getText(), profile -> { //todo: invalid name
- if (profile != null) profile.resetCache();
- Minecraft.getMinecraft().displayGuiScreen(new GuiProfileViewer(profile));
- });
+ NotEnoughUpdates.profileViewer.getProfileByName(
+ playerNameTextField.getText(),
+ profile -> { //todo: invalid name
+ if (profile != null) profile.resetCache();
+ Minecraft.getMinecraft().displayGuiScreen(new GuiProfileViewer(profile));
+ }
+ );
}
playerNameTextField.keyTyped(typedChar, keyCode);
}
@@ -756,887 +990,12 @@ public class GuiProfileViewer extends GuiScreen {
protected void mouseReleased(int mouseX, int mouseY, int mouseButton) {
super.mouseReleased(mouseX, mouseY, mouseButton);
- switch (currentPage) {
- case INVS:
- mouseReleasedInvs(mouseX, mouseY, mouseButton);
- break;
- case COLS:
- mouseReleasedCols(mouseX, mouseY, mouseButton);
- break;
- case PETS:
- mouseReleasedPets(mouseX, mouseY, mouseButton);
- }
- }
-
- protected void mouseClickedDung(int mouseX, int mouseY, int mouseButton) {
- if (mouseX >= guiLeft + 50 && mouseX <= guiLeft + 70 &&
- mouseY >= guiTop + 54 && mouseY <= guiTop + 64) {
- dungeonLevelTextField.mouseClicked(mouseX, mouseY, mouseButton);
- } else {
- dungeonLevelTextField.otherComponentClick();
- }
-
- int cW = fontRendererObj.getStringWidth("Calculate");
- if (mouseX >= guiLeft + 23 + 110 - 17 - cW && mouseX <= guiLeft + 23 + 110 - 17 &&
- mouseY >= guiTop + 55 && mouseY <= guiTop + 65) {
- calculateFloorLevelXP();
- }
-
- int y = guiTop + 142;
-
- if (mouseY >= y - 2 && mouseY <= y + 9) {
- for (int i = 1; i <= 7; i++) {
- int w = fontRendererObj.getStringWidth("" + i);
-
- int x = guiLeft + 23 + 110 * i / 8 - w / 2;
-
- if (mouseX >= x - 2 && mouseX <= x + 7) {
- floorTime = i;
- return;
- }
- }
- }
- if (mouseX >= guiLeft - 29 && mouseX <= guiLeft) {
- if (mouseY >= guiTop && mouseY <= guiTop + 28) {
- onMasterMode = false;
- return;
- } else if (mouseY + 28 >= guiTop && mouseY <= guiTop + 28 * 2) {
- onMasterMode = true;
- return;
- }
- }
- }
-
- protected void keyTypedDung(char typedChar, int keyCode) {
- dungeonLevelTextField.keyTyped(typedChar, keyCode);
- }
-
- protected void keyTypedInvs(char typedChar, int keyCode) throws IOException {
- switch (keyCode) {
- case Keyboard.KEY_1:
- case Keyboard.KEY_NUMPAD1:
- selectedInventory = "inv_contents";
- break;
- case Keyboard.KEY_2:
- case Keyboard.KEY_NUMPAD2:
- selectedInventory = "ender_chest_contents";
- break;
- case Keyboard.KEY_3:
- case Keyboard.KEY_NUMPAD3:
- selectedInventory = "backpack_contents";
- break;
- case Keyboard.KEY_4:
- case Keyboard.KEY_NUMPAD4:
- selectedInventory = "personal_vault_contents";
- break;
- case Keyboard.KEY_5:
- case Keyboard.KEY_NUMPAD5:
- selectedInventory = "talisman_bag";
- break;
- case Keyboard.KEY_6:
- case Keyboard.KEY_NUMPAD6:
- selectedInventory = "wardrobe_contents";
- break;
- case Keyboard.KEY_7:
- case Keyboard.KEY_NUMPAD7:
- selectedInventory = "fishing_bag";
- break;
- case Keyboard.KEY_8:
- case Keyboard.KEY_NUMPAD8:
- selectedInventory = "potion_bag";
- break;
-
- }
- Utils.playPressSound();
- }
-
- protected void keyTypedCols(char typedChar, int keyCode) throws IOException {
- ItemStack stack = null;
- Iterator<ItemStack> items = ProfileViewer.getCollectionCatToCollectionMap().keySet().iterator();
- switch (keyCode) {
- case Keyboard.KEY_5:
- case Keyboard.KEY_NUMPAD5:
- stack = items.next();
- case Keyboard.KEY_4:
- case Keyboard.KEY_NUMPAD4:
- stack = items.next();
- case Keyboard.KEY_3:
- case Keyboard.KEY_NUMPAD3:
- stack = items.next();
- case Keyboard.KEY_2:
- case Keyboard.KEY_NUMPAD2:
- stack = items.next();
- case Keyboard.KEY_1:
- case Keyboard.KEY_NUMPAD1:
- stack = items.next();
- }
- if (stack != null) {
- selectedCollectionCategory = stack;
- }
- Utils.playPressSound();
- }
-
- private void mouseReleasedPets(int mouseX, int mouseY, int mouseButton) {
- if (mouseY > guiTop + 6 && mouseY < guiTop + 22) {
- if (mouseX > guiLeft + 100 - 15 - 12 && mouseX < guiLeft + 100 - 20) {
- if (petsPage > 0) {
- petsPage--;
- }
- return;
- } else if (mouseX > guiLeft + 100 + 15 && mouseX < guiLeft + 100 + 20 + 12) {
- if (sortedPets != null && petsPage < Math.ceil(sortedPets.size() / 20f) - 1) {
- petsPage++;
- }
- return;
- }
- }
- }
-
- private void mouseReleasedInvs(int mouseX, int mouseY, int mouseButton) {
- if (mouseButton == 0) {
- int i = 0;
- for (Map.Entry<String, ItemStack> entry : invNameToDisplayMap.entrySet()) {
- int xIndex = i % 3;
- int yIndex = i / 3;
-
- int x = guiLeft + 19 + 34 * xIndex;
- int y = guiTop + 26 + 34 * yIndex;
-
- if (mouseX >= x && mouseX <= x + 16) {
- if (mouseY >= y && mouseY <= y + 16) {
- if (selectedInventory != entry.getKey()) Utils.playPressSound();
- selectedInventory = entry.getKey();
- return;
- }
- }
-
- i++;
- }
-
- JsonObject inventoryInfo = profile.getInventoryInfo(profileId);
- if (inventoryInfo == null) return;
-
- ItemStack[][][] inventories = getItemsForInventory(inventoryInfo, selectedInventory);
- if (currentInventoryIndex >= inventories.length) currentInventoryIndex = inventories.length - 1;
- if (currentInventoryIndex < 0) currentInventoryIndex = 0;
-
- ItemStack[][] inventory = inventories[currentInventoryIndex];
- if (inventory == null) return;
-
- int inventoryRows = inventory.length;
- int invSizeY = inventoryRows * 18 + 17 + 7;
-
- int y = guiTop + 101 - invSizeY / 2;
- int staticSelectorHeight = guiTop + 177;
-
- if (mouseY > staticSelectorHeight && mouseY < staticSelectorHeight + 16) {
- if (mouseX > guiLeft + 320 - 12 && mouseX < guiLeft + 320 + 12) {
- if (mouseX < guiLeft + 320) {
- currentInventoryIndex--;
- } else {
- currentInventoryIndex++;
- }
- }
- }
- }
- }
-
- private ItemStack selectedCollectionCategory = null;
-
- private void mouseReleasedCols(int mouseX, int mouseY, int mouseButton) {
- int collectionCatSize = ProfileViewer.getCollectionCatToCollectionMap().size();
- int collectionCatYSize = (int) (162f / (collectionCatSize - 1 + 0.0000001f));
- int yIndex = 0;
- for (ItemStack stack : ProfileViewer.getCollectionCatToCollectionMap().keySet()) {
- if (mouseX > guiLeft + 7 && mouseX < guiLeft + 7 + 20) {
- if (mouseY > guiTop + 10 + collectionCatYSize * yIndex &&
- mouseY < guiTop + 10 + collectionCatYSize * yIndex + 20) {
- selectedCollectionCategory = stack;
- Utils.playPressSound();
- return;
- }
- }
- yIndex++;
- }
- }
-
- private static final ItemStack DEADBUSH = new ItemStack(Item.getItemFromBlock(Blocks.deadbush));
- private static final ItemStack iron_pick = new ItemStack(Items.iron_pickaxe);
- private static final ItemStack[] BOSS_HEADS = new ItemStack[7];
-
- private final HashMap<String, ProfileViewer.Level> levelObjCatas = new HashMap<>();
- private final HashMap<String, ProfileViewer.Level> levelObjhotms = new HashMap<>();
- private final HashMap<String, HashMap<String, ProfileViewer.Level>> levelObjClasseses = new HashMap<>();
-
- private final GuiElementTextField dungeonLevelTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT);
-
- private static final String[] dungSkillsName = {"Healer", "Mage", "Berserk", "Archer", "Tank"};
- private static final ItemStack[] dungSkillsStack = {
- new ItemStack(Items.potionitem, 1, 16389),
- new ItemStack(Items.blaze_rod),
- new ItemStack(Items.iron_sword),
- new ItemStack(Items.bow),
- new ItemStack(Items.leather_chestplate)
- };
- private static final String[] bossFloorArr = {"Bonzo", "Scarf", "Professor", "Thorn", "Livid", "Sadan", "Necron"};
- private static final String[] bossFloorHeads = {
- "12716ecbf5b8da00b05f316ec6af61e8bd02805b21eb8e440151468dc656549c",
- "7de7bbbdf22bfe17980d4e20687e386f11d59ee1db6f8b4762391b79a5ac532d",
- "9971cee8b833a62fc2a612f3503437fdf93cad692d216b8cf90bbb0538c47dd8",
- "8b6a72138d69fbbd2fea3fa251cabd87152e4f1c97e5f986bf685571db3cc0",
- "c1007c5b7114abec734206d4fc613da4f3a0e99f71ff949cedadc99079135a0b",
- "fa06cb0c471c1c9bc169af270cd466ea701946776056e472ecdaeb49f0f4a4dc",
- "a435164c05cea299a3f016bbbed05706ebb720dac912ce4351c2296626aecd9a"
- };
- private static int floorTime = 7;
- private int floorLevelTo = -1;
- private int floorLevelToXP = -1;
-
- private void calculateFloorLevelXP() {
- JsonObject leveling = Constants.LEVELING;
- if (leveling == null) return;
- ProfileViewer.Level levelObjCata = levelObjCatas.get(profileId);
- if (levelObjCata == null) return;
-
- try {
- dungeonLevelTextField.setCustomBorderColour(0xffffffff);
- floorLevelTo = Integer.parseInt(dungeonLevelTextField.getText());
-
- JsonArray levelingArray = Utils.getElement(leveling, "catacombs").getAsJsonArray();
-
- float remaining = -((levelObjCata.level % 1) * levelObjCata.maxXpForLevel);
-
- for (int level = 0; level < Math.min(floorLevelTo, levelingArray.size()); level++) {
- if (level < Math.floor(levelObjCata.level)) {
- continue;
- }
- remaining += levelingArray.get(level).getAsFloat();
- }
-
- if (remaining < 0) {
- remaining = 0;
- }
- floorLevelToXP = (int) remaining;
- } catch (Exception e) {
- dungeonLevelTextField.setCustomBorderColour(0xffff0000);
- }
- }
-
- private static final LinkedHashMap<String, ItemStack> dungeonsModeIcons = new LinkedHashMap<String, ItemStack>() {{
- put(
- "catacombs",
- Utils.editItemStackInfo(NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get("DUNGEON_STONE")), EnumChatFormatting.GRAY + "Normal Mode", true)
- );
- put(
- "master_catacombs",
- Utils.editItemStackInfo(NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get("MASTER_SKULL_TIER_7")), EnumChatFormatting.GRAY + "Master Mode", true)
- );
- }};
-
- private void drawDungPage(int mouseX, int mouseY, float partialTicks) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_dung);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- JsonObject hypixelInfo = profile.getHypixelProfile();
- if (hypixelInfo == null) return;
- JsonObject profileInfo = profile.getProfileInformation(profileId);
- if (profileInfo == null) return;
-
- JsonObject leveling = Constants.LEVELING;
- if (leveling == null) return;
-
- int sectionWidth = 110;
-
- String dungeonString = onMasterMode ? "master_catacombs" : "catacombs";
-
- //Utils.drawStringCentered((onMasterMode?"Master Mode":"Catacombs"),fontRendererObj,(guiLeft+sizeX/2), guiTop+10, true, 0xffff0000);
- Utils.renderShadowedString(EnumChatFormatting.RED + (onMasterMode ? "Master Mode" : "Catacombs"),
- (guiLeft + sizeX / 2), guiTop + 5, sectionWidth
- );
-
- ProfileViewer.Level levelObjCata = levelObjCatas.get(profileId);
- //Catacombs level thingy
- {
- if (levelObjCata == null) {
- float cataXp = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.experience"
- ), 0);
- levelObjCata = ProfileViewer.getLevel(Utils.getElement(leveling, "catacombs").getAsJsonArray(),
- cataXp, 50, false
- );
- levelObjCata.totalXp = cataXp;
- levelObjCatas.put(profileId, levelObjCata);
- }
-
- String skillName = EnumChatFormatting.RED + "Catacombs";
- float level = levelObjCata.level;
- int levelFloored = (int) Math.floor(level);
-
- if (floorLevelTo == -1 && levelFloored >= 0) {
- dungeonLevelTextField.setText("" + (levelFloored + 1));
- calculateFloorLevelXP();
- }
-
- int x = guiLeft + 23;
- int y = guiTop + 25;
-
- renderXpBar(skillName, DEADBUSH, x, y, sectionWidth, levelObjCata, mouseX, mouseY);
-
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Until Cata " + floorLevelTo + ": ",
- EnumChatFormatting.WHITE + shortNumberFormat(floorLevelToXP, 0), x, y + 16, sectionWidth
- );
-
- if (mouseX > x && mouseX < x + sectionWidth && mouseY > y + 16 && mouseY < y + 24 && !onMasterMode) {
- float F5 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.tier_completions." + 5
- ), 0)); //this can prob be done better
- float F6 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.tier_completions." + 6
- ), 0));
- float F7 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.tier_completions." + 7
- ), 0));
- if (F5 > 150) {
- F5 = 150;
- }
- if (F6 > 100) {
- F6 = 100;
- }
- if (F7 > 50) {
- F7 = 50;
- }
- float xpF5 = 2000 * (F5 / 100 + 1);
- float xpF6 = 4000 * (F6 / 100 + 1);
- float xpF7 = 20000 * (F7 / 100 + 1);
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
- xpF5 *= 1.1;
- xpF6 *= 1.1;
- xpF7 *= 1.1;
- }
-
- long runsF5 = (int) Math.ceil(floorLevelToXP / xpF5);
- long runsF6 = (int) Math.ceil(floorLevelToXP / xpF6);
- long runsF7 = (int) Math.ceil(floorLevelToXP / xpF7);
-
- float timeF5 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.fastest_time_s_plus.5"
- ), 0);
- float timeF6 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.fastest_time_s_plus.6"
- ), 0);
- float timeF7 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.fastest_time_s_plus.7"
- ), 0);
-
- tooltipToDisplay = Lists.newArrayList(
- String.format("# F5 Runs (%s xp) : %d", shortNumberFormat(xpF5, 0), runsF5),
- String.format("# F6 Runs (%s xp) : %d", shortNumberFormat(xpF6, 0), runsF6),
- String.format("# F7 Runs (%s xp) : %d", shortNumberFormat(xpF7, 0), runsF7),
- ""
- );
- boolean hasTime = false;
- if (timeF5 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (F5) : %s",
- Utils.prettyTime(runsF5 * (long) (timeF5 * 1.2))
- ));
- hasTime = true;
- }
- if (timeF6 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (F6) : %s",
- Utils.prettyTime(runsF6 * (long) (timeF6 * 1.2))
- ));
- hasTime = true;
- }
- if (timeF7 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (F7) : %s",
- Utils.prettyTime(runsF7 * (long) (timeF7 * 1.2))
- ));
- hasTime = true;
- }
- if (hasTime) {
- tooltipToDisplay.add("");
- }
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
- tooltipToDisplay.add(
- "[Hold " + EnumChatFormatting.YELLOW + "SHIFT" + EnumChatFormatting.GRAY + " to show without Expert Ring]");
- }
- if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) {
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) tooltipToDisplay.add("");
- tooltipToDisplay.add("Number of runs is calculated as [Remaining XP]/[XP per Run].");
- tooltipToDisplay.add("The [XP per Run] is the average xp gained from an S+ run");
- tooltipToDisplay.add(
- "The " + EnumChatFormatting.DARK_PURPLE + "Catacombs Expert Ring" + EnumChatFormatting.GRAY +
- " is assumed to be used, unless " + EnumChatFormatting.YELLOW + "SHIFT" + EnumChatFormatting.GRAY +
- " is held.");
- tooltipToDisplay.add("[Time per run] is calculated using Fastest S+ x 120%");
- } else {
- tooltipToDisplay.add(
- "[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
- }
- }
-
- if (mouseX > x && mouseX < x + sectionWidth && mouseY > y + 16 && mouseY < y + 24 && onMasterMode) {
- float M3 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.tier_completions." + 3
- ), 0));
- float M4 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.tier_completions." + 4
- ), 0));
- float M5 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.tier_completions." + 5
- ), 0)); //this can prob be done better
- float M6 = (Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.tier_completions." + 6
- ), 0));
- if (M3 > 50) {
- M3 = 50;
- }
- if (M4 > 50) {
- M4 = 50;
- }
- if (M5 > 50) {
- M5 = 50;
- }
- if (M6 > 50) {
- M6 = 50;
- }
- float xpM3 = 36500 * (M3 / 100 + 1);
- float xpM4 = 48500 * (M4 / 100 + 1);
- float xpM5 = 70000 * (M5 / 100 + 1);
- float xpM6 = 100000 * (M6 / 100 + 1);
- //No clue if M3 or M4 xp values are right
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
- xpM3 *= 1.1;
- xpM4 *= 1.1;
- xpM5 *= 1.1;
- xpM6 *= 1.1;
- }
-
- long runsM3 = (int) Math.ceil(floorLevelToXP / xpM3);
- long runsM4 = (int) Math.ceil(floorLevelToXP / xpM4);
- long runsM5 = (int) Math.ceil(floorLevelToXP / xpM5);
- long runsM6 = (int) Math.ceil(floorLevelToXP / xpM6);
-
- float timeM3 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.3"
- ), 0);
- float timeM4 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.4"
- ), 0);
- float timeM5 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.5"
- ), 0);
- float timeM6 = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.fastest_time_s_plus.6"
- ), 0);
-
- tooltipToDisplay = Lists.newArrayList(
- String.format("# M3 Runs (%s xp) : %d", shortNumberFormat(xpM3, 0), runsM3),
- String.format("# M4 Runs (%s xp) : %d", shortNumberFormat(xpM4, 0), runsM4),
- String.format("# M5 Runs (%s xp) : %d", shortNumberFormat(xpM5, 0), runsM5),
- String.format("# M6 Runs (%s xp) : %d", shortNumberFormat(xpM6, 0), runsM6),
- ""
- );
- boolean hasTime = false;
- if (timeM3 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (M3) : %s",
- Utils.prettyTime(runsM3 * (long) (timeM3 * 1.2))
- ));
- hasTime = true;
- }
- if (timeM4 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (M4) : %s",
- Utils.prettyTime(runsM4 * (long) (timeM4 * 1.2))
- ));
- hasTime = true;
- }
- if (timeM5 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (M5) : %s",
- Utils.prettyTime(runsM5 * (long) (timeM5 * 1.2))
- ));
- hasTime = true;
- }
- if (timeM6 > 1000) {
- tooltipToDisplay.add(String.format(
- "Expected Time (M6) : %s",
- Utils.prettyTime(runsM6 * (long) (timeM6 * 1.2))
- ));
- hasTime = true;
- }
- if (hasTime) {
- tooltipToDisplay.add("");
- }
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
- tooltipToDisplay.add(
- "[Hold " + EnumChatFormatting.YELLOW + "SHIFT" + EnumChatFormatting.GRAY + " to show without Expert Ring]");
- }
- if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) {
- if (!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) tooltipToDisplay.add("");
- tooltipToDisplay.add("Number of runs is calculated as [Remaining XP]/[XP per Run].");
- tooltipToDisplay.add("The [XP per Run] is the average xp gained from an S+ run");
- tooltipToDisplay.add(
- "The " + EnumChatFormatting.DARK_PURPLE + "Catacombs Expert Ring" + EnumChatFormatting.GRAY +
- " is assumed to be used, unless " + EnumChatFormatting.YELLOW + "SHIFT" + EnumChatFormatting.GRAY +
- " is held.");
- tooltipToDisplay.add("[Time per run] is calculated using Fastest S+ x 120%");
- } else {
- tooltipToDisplay.add(
- "[Hold " + EnumChatFormatting.YELLOW + "CTRL" + EnumChatFormatting.GRAY + " to see details]");
- }
- }
-
- dungeonLevelTextField.setSize(20, 10);
- dungeonLevelTextField.render(x + 22, y + 29);
- int calcLen = fontRendererObj.getStringWidth("Calculate");
- Utils.renderShadowedString(EnumChatFormatting.WHITE + "Calculate", x + sectionWidth - 17 - calcLen / 2f,
- y + 30, 100
- );
-
- //Random stats
-
- float secrets = Utils.getElementAsFloat(Utils.getElement(
- hypixelInfo,
- "achievements.skyblock_treasure_hunter"
- ), 0);
- float totalRuns = 0;
- float totalRunsF = 0;
- float totalRunsF5 = 0;
- for (int i = 1; i <= 7; i++) {
- float runs = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.tier_completions." + i
- ), 0);
- totalRunsF += runs;
- if (i >= 5) {
- totalRunsF5 += runs;
- }
- }
- float totalRunsM = 0;
- float totalRunsM5 = 0;
- for (int i = 1; i <= 7; i++) {
- float runs = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.tier_completions." + i
- ), 0);
- totalRunsM += runs;
- if (i >= 5) {
- totalRunsM5 += runs;
- }
- }
- totalRuns = totalRunsF + totalRunsM;
-
- float mobKills = 0;
- float mobKillsF = 0;
- float mobKillsF5 = 0;
- for (int i = 1; i <= 7; i++) {
- float kills = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.catacombs.mobs_killed." + i
- ), 0);
- mobKillsF += kills;
- if (i >= 5) {
- mobKillsF5 += kills;
- }
- }
- float mobKillsM = 0;
- float mobKillsM5 = 0;
- for (int i = 1; i <= 7; i++) {
- float kills = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types.master_catacombs.mobs_killed." + i
- ), 0);
- mobKillsM += kills;
- if (i >= 5) {
- mobKillsM5 += kills;
- }
- }
- mobKills = mobKillsF + mobKillsM;
-
- int miscTopY = y + 55;
-
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Total Runs " + (onMasterMode ? "M" : "F"),
- EnumChatFormatting.WHITE.toString() + ((int) (onMasterMode ? totalRunsM : totalRunsF)),
- x,
- miscTopY,
- sectionWidth
- );
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Total Runs (" + (onMasterMode ? "M" : "F") + "5-7) ",
- EnumChatFormatting.WHITE.toString() + ((int) (onMasterMode ? totalRunsM5 : totalRunsF5)),
- x,
- miscTopY + 10,
- sectionWidth
- );
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Secrets (Total) ",
- EnumChatFormatting.WHITE + shortNumberFormat(secrets, 0), x, miscTopY + 20, sectionWidth
- );
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Secrets (/Run) ",
- EnumChatFormatting.WHITE.toString() + (Math.round(secrets / Math.max(1, totalRuns) * 100) / 100f),
- x,
- miscTopY + 30,
- sectionWidth
- );
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Mob Kills (Total) ",
- EnumChatFormatting.WHITE + shortNumberFormat(mobKills, 0), x, miscTopY + 40, sectionWidth
- );
-
- int y3 = y + 117;
-
- for (int i = 1; i <= 7; i++) {
- int w = fontRendererObj.getStringWidth("" + i);
-
- int bx = x + sectionWidth * i / 8 - w / 2;
-
- boolean invert = i == floorTime;
- float uMin = 20 / 256f;
- float uMax = 29 / 256f;
- float vMin = 0 / 256f;
- float vMax = 11 / 256f;
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(bx - 2, y3 - 2, 9, 11,
- invert ? uMax : uMin, invert ? uMin : uMax,
- invert ? vMax : vMin, invert ? vMin : vMax, GL11.GL_NEAREST
- );
-
- Utils.renderShadowedString(EnumChatFormatting.WHITE.toString() + i, bx + w / 2, y3, 10);
- }
-
- float timeNorm = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types." + dungeonString + ".fastest_time." + floorTime
- ), 0);
- float timeS = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types." + dungeonString + ".fastest_time_s." + floorTime
- ), 0);
- float timeSPLUS = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types." + dungeonString + ".fastest_time_s_plus." + floorTime
- ), 0);
- String timeNormStr = timeNorm <= 0 ? "N/A" : Utils.prettyTime((long) timeNorm);
- String timeSStr = timeS <= 0 ? "N/A" : Utils.prettyTime((long) timeS);
- String timeSPlusStr = timeSPLUS <= 0 ? "N/A" : Utils.prettyTime((long) timeSPLUS);
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Floor " + floorTime + " ",
- EnumChatFormatting.WHITE + timeNormStr, x, y3 + 10, sectionWidth
- );
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Floor " + floorTime + " S",
- EnumChatFormatting.WHITE + timeSStr, x, y3 + 20, sectionWidth
- );
- Utils.renderAlignedString(EnumChatFormatting.YELLOW + "Floor " + floorTime + " S+",
- EnumChatFormatting.WHITE + timeSPlusStr, x, y3 + 30, sectionWidth
- );
- }
-
- //Completions
- {
- int x = guiLeft + 161;
- int y = guiTop + 27;
-
- Utils.renderShadowedString(EnumChatFormatting.RED + "Boss Collections",
- x + sectionWidth / 2, y, sectionWidth
- );
- for (int i = 1; i <= 7; i++) {
- float compl = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.dungeon_types." + dungeonString + ".tier_completions." + i
- ), 0);
-
- if (BOSS_HEADS[i - 1] == null) {
- String textureLink = bossFloorHeads[i - 1];
-
- String b64Decoded =
- "{\"textures\":{\"SKIN\":{\"url\":\"http://textures.minecraft.net/texture/" + textureLink + "\"}}}";
- String b64Encoded = new String(Base64.getEncoder().encode(b64Decoded.getBytes()));
-
- ItemStack stack = new ItemStack(Items.skull, 1, 3);
- NBTTagCompound nbt = new NBTTagCompound();
- NBTTagCompound skullOwner = new NBTTagCompound();
- NBTTagCompound properties = new NBTTagCompound();
- NBTTagList textures = new NBTTagList();
- NBTTagCompound textures_0 = new NBTTagCompound();
-
- String uuid = UUID.nameUUIDFromBytes(b64Encoded.getBytes()).toString();
- skullOwner.setString("Id", uuid);
- skullOwner.setString("Name", uuid);
-
- textures_0.setString("Value", b64Encoded);
- textures.appendTag(textures_0);
-
- properties.setTag("textures", textures);
- skullOwner.setTag("Properties", properties);
- nbt.setTag("SkullOwner", skullOwner);
- stack.setTagCompound(nbt);
-
- BOSS_HEADS[i - 1] = stack;
- }
-
- GlStateManager.pushMatrix();
- GlStateManager.translate(x - 4, y + 10 + 20 * (i - 1), 0);
- GlStateManager.scale(1.3f, 1.3f, 1);
- Utils.drawItemStack(BOSS_HEADS[i - 1], 0, 0);
- GlStateManager.popMatrix();
-
- Utils.renderAlignedString(String.format(
- EnumChatFormatting.YELLOW + "%s (" + (onMasterMode ? "M" : "F") + "%d) ",
- bossFloorArr[i - 1],
- i
- ),
- EnumChatFormatting.WHITE.toString() + (int) compl,
- x + 16, y + 18 + 20 * (i - 1), sectionWidth - 15
- );
-
- }
- }
-
- //Skills
- {
- int x = guiLeft + 298;
- int y = guiTop + 27;
-
- //Gui.drawRect(x, y, x+120, y+147, 0xffffffff);
-
- Utils.renderShadowedString(EnumChatFormatting.DARK_PURPLE + "Class Levels",
- x + sectionWidth / 2, y, sectionWidth
- );
-
- JsonElement activeClassElement = Utils.getElement(profileInfo, "dungeons.selected_dungeon_class");
- String activeClass = null;
- if (activeClassElement instanceof JsonPrimitive && ((JsonPrimitive) activeClassElement).isString()) {
- activeClass = activeClassElement.getAsString();
- }
-
- for (int i = 0; i < dungSkillsName.length; i++) {
- String skillName = dungSkillsName[i];
-
- HashMap<String, ProfileViewer.Level> levelObjClasses =
- levelObjClasseses.computeIfAbsent(profileId, k -> new HashMap<>());
- if (!levelObjClasses.containsKey(skillName)) {
- float cataXp = Utils.getElementAsFloat(Utils.getElement(
- profileInfo,
- "dungeons.player_classes." + skillName.toLowerCase() + ".experience"
- ), 0);
- ProfileViewer.Level levelObj =
- ProfileViewer.getLevel(Utils.getElement(leveling, "catacombs").getAsJsonArray(),
- cataXp, 50, false
- );
- levelObjClasses.put(skillName, levelObj);
- }
-
- String colour = EnumChatFormatting.WHITE.toString();
- if (skillName.toLowerCase().equals(activeClass)) {
- colour = EnumChatFormatting.GREEN.toString();
- }
-
- ProfileViewer.Level levelObj = levelObjClasses.get(skillName);
-
- renderXpBar(colour + skillName, dungSkillsStack[i], x, y + 20 + 29 * i, sectionWidth, levelObj, mouseX, mouseY);
- }
+ if (pages.containsKey(currentPage)) {
+ pages.get(currentPage).mouseReleased(mouseX, mouseY, mouseButton);
}
-
- drawSideButtons();
-
- //drawSideButton(0, dungeonsModeIcons.get("catacombs"), true);
- //drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), true);
- //drawSideButton(1, dungeonsModeIcons.get("catacombs"), true);
- //drawSideButton(2, dungeonsModeIcons.get("catacombs"), false);
}
- private boolean onMasterMode = false;
-
- //TODO: improve this shit
- private void drawSideButtons() {
- // GlStateManager.pushMatrix();
- GlStateManager.enableDepth();
- GlStateManager.translate(0, 0, 5);
- if (onMasterMode) {
- drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), true);
- } else {
- drawSideButton(0, dungeonsModeIcons.get("catacombs"), true);
- }
- GlStateManager.translate(0, 0, -3);
-
- GlStateManager.translate(0, 0, -2);
- if (!onMasterMode) {
- drawSideButton(1, dungeonsModeIcons.get("master_catacombs"), false);
- } else {
- drawSideButton(0, dungeonsModeIcons.get("catacombs"), false);
- }
- GlStateManager.disableDepth();
- //GlStateManager.popMatrix();
- }
-
- private void drawSideButton(int yIndex, ItemStack itemStack, boolean pressed) {
- GlStateManager.disableLighting();
- GlStateManager.enableBlend();
- GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
- GlStateManager.enableAlpha();
- GlStateManager.alphaFunc(516, 0.1F);
-
- int x = guiLeft - 28;
- int y = guiTop + yIndex * 28;
-
- float uMin = 193 / 256f;
- float uMax = 223 / 256f;
- float vMin = 200 / 256f;
- float vMax = 228 / 256f;
- if (pressed) {
- uMin = 224 / 256f;
- uMax = 1f;
-
- if (yIndex != 0) {
- vMin = 228 / 256f;
- vMax = 1f;
- }
-
- renderBlurredBackground(width, height, x + 2, y + 2, 30, 28 - 4);
- } else {
- renderBlurredBackground(width, height, x + 2, y + 2, 28 - 2, 28 - 4);
- }
-
- GlStateManager.disableLighting();
- GlStateManager.enableBlend();
- GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
- GlStateManager.enableAlpha();
- GlStateManager.alphaFunc(516, 0.1F);
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
-
- Utils.drawTexturedRect(x, y, pressed ? 32 : 28, 28, uMin, uMax, vMin, vMax, GL11.GL_NEAREST);
-
- GlStateManager.enableDepth();
- Utils.drawItemStack(itemStack, x + 8, y + 7);
- }
-
- private void renderXpBar(
+ public void renderXpBar(
String skillName,
ItemStack stack,
int x,
@@ -1654,24 +1013,29 @@ public class GuiProfileViewer extends GuiScreen {
if (levelObj.maxed) {
renderGoldBar(x, y + 6, xSize);
} else {
- renderBar(x, y + 6, xSize, level % 1);
+ if (skillName.contains("Catacombs") && levelObj.level >= 50) {
+ renderGoldBar(x, y + 6, xSize);
+ } else {
+ renderBar(x, y + 6, xSize, level % 1);
+ }
}
if (mouseX > x && mouseX < x + 120) {
if (mouseY > y - 4 && mouseY < y + 13) {
String levelStr;
String totalXpStr = null;
+ if (skillName.contains("Catacombs")) totalXpStr =
+ EnumChatFormatting.GRAY + "Total XP: " + EnumChatFormatting.DARK_PURPLE +
+ numberFormat.format(levelObj.totalXp);
if (levelObj.maxed) {
levelStr = EnumChatFormatting.GOLD + "MAXED!";
- if (skillName.contains("Catacombs"))
- totalXpStr = EnumChatFormatting.GRAY + "Total XP: " + EnumChatFormatting.DARK_PURPLE +
- Utils.formatNumberWithDots((long) levelObj.totalXp);
} else {
int maxXp = (int) levelObj.maxXpForLevel;
- levelStr = EnumChatFormatting.DARK_PURPLE + shortNumberFormat(
- Math.round((level % 1) * maxXp),
- 0
- ) + "/" + shortNumberFormat(maxXp, 0);
+ levelStr =
+ EnumChatFormatting.DARK_PURPLE +
+ StringUtils.shortNumberFormat(Math.round((level % 1) * maxXp)) +
+ "/" +
+ StringUtils.shortNumberFormat(maxXp);
}
if (totalXpStr != null) {
tooltipToDisplay = Utils.createList(levelStr, totalXpStr);
@@ -1681,6 +1045,12 @@ public class GuiProfileViewer extends GuiScreen {
}
}
+ NBTTagCompound nbt = new NBTTagCompound(); //Adding NBT Data for Custom Resource Packs
+ NBTTagCompound display = new NBTTagCompound();
+ display.setString("Name", skillName);
+ nbt.setTag("display", display);
+ stack.setTagCompound(nbt);
+
GL11.glTranslatef((x), (y - 6f), 0);
GL11.glScalef(0.7f, 0.7f, 1);
Utils.drawItemStackLinear(stack, 0, 0);
@@ -1688,3146 +1058,11 @@ public class GuiProfileViewer extends GuiScreen {
GL11.glTranslatef(-(x), -(y - 6f), 0);
}
- public static class PetLevel {
- public float level;
- public float currentLevelRequirement;
- public float maxXP;
- public float levelPercentage;
- public float levelXp;
- public float totalXp;
- }
-
- private static JsonObject getPetInfo(String pet_name, String rarity) {
- JsonObject petInfo = new JsonObject();
- //System.out.println(pet_name);
- //System.out.println(rarity);
-
- if (Constants.PETS.has("custom_pet_leveling") &&
- Constants.PETS.getAsJsonObject("custom_pet_leveling").has(pet_name)) {
- JsonObject pet = Constants.PETS.getAsJsonObject("custom_pet_leveling").getAsJsonObject(pet_name);
- if (pet.has("type") && pet.has("pet_levels")) {
- int type = pet.get("type").getAsInt();
- switch (type) {
- case 1:
- JsonArray defaultLevels = Constants.PETS.getAsJsonArray("pet_levels");
- defaultLevels.addAll(pet.getAsJsonArray("pet_levels"));
- petInfo.add("pet_levels", Constants.PETS.getAsJsonArray("pet_levels"));
- break;
- case 2:
- petInfo.add("pet_levels", pet.getAsJsonArray("pet_levels"));
- break;
- default:
- petInfo.add("pet_levels", Constants.PETS.getAsJsonArray("pet_levels"));
- break;
- }
- } else {
- petInfo.add("pet_levels", Constants.PETS.getAsJsonArray("pet_levels"));
- }
- if (pet.has("max_level")) {
- petInfo.add("max_level", pet.get("max_level"));
- } else {
- petInfo.add("max_level", new JsonPrimitive(100));
- }
-
- if (pet.has("pet_rarity_offset")) {
- petInfo.add("offset", pet.get("pet_rarity_offset"));
- } else {
- petInfo.add("offset", Constants.PETS.getAsJsonObject("pet_rarity_offset").get(rarity));
- }
-
- } else {
- //System.out.println("Default Path");
- petInfo.add("offset", Constants.PETS.getAsJsonObject("pet_rarity_offset").get(rarity));
- petInfo.add("max_level", new JsonPrimitive(100));
- petInfo.add("pet_levels", Constants.PETS.getAsJsonArray("pet_levels"));
- }
-
- return petInfo;
-
- }
-
- public static PetLevel getPetLevel(String pet_name, String rarity, float exp) {
- JsonObject petInfo = getPetInfo(pet_name, rarity);
- int offset = petInfo.get("offset").getAsInt();
- int maxPetLevel = petInfo.get("max_level").getAsInt();
- JsonArray levels = petInfo.getAsJsonArray("pet_levels");
-
- float xpTotal = 0;
- float level = 1;
- float currentLevelRequirement = 0;
- float currentLevelProgress = 0;
-
- boolean addLevel = true;
-
- for (int i = offset; i < offset + maxPetLevel - 1; i++) {
- if (addLevel) {
- currentLevelRequirement = levels.get(i).getAsFloat();
- xpTotal += currentLevelRequirement;
- if (xpTotal > exp) {
- currentLevelProgress = (exp - (xpTotal - currentLevelRequirement));
- addLevel = false;
- } else {
- level += 1;
- }
- } else {
-
- xpTotal += levels.get(i).getAsFloat();
-
- }
- }
-
- level += currentLevelProgress / currentLevelRequirement;
- if (level <= 0) {
- level = 1;
- } else if (level > maxPetLevel) {
- level = maxPetLevel;
- }
- PetLevel levelObj = new PetLevel();
- levelObj.level = level;
- levelObj.currentLevelRequirement = currentLevelRequirement;
- levelObj.maxXP = xpTotal;
- levelObj.levelPercentage = currentLevelProgress / currentLevelRequirement;
- levelObj.levelXp = currentLevelProgress;
- levelObj.totalXp = exp;
- return levelObj;
- }
-
- public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS =
- new HashMap<String, HashMap<String, Float>>() {{
- put("PET_ITEM_BIG_TEETH_COMMON", new HashMap<String, Float>() {{
- put("CRIT_CHANCE", 5f);
- }});
- put("PET_ITEM_HARDENED_SCALES_UNCOMMON", new HashMap<String, Float>() {{
- put("DEFENCE", 25f);
- }});
- put("PET_ITEM_LUCKY_CLOVER", new HashMap<String, Float>() {{
- put("MAGIC_FIND", 7f);
- }});
- put("PET_ITEM_SHARPENED_CLAWS_UNCOMMON", new HashMap<String, Float>() {{
- put("CRIT_DAMAGE", 15f);
- }});
- }};
-
- public static final HashMap<String, HashMap<String, Float>> PET_STAT_BOOSTS_MULT =
- new HashMap<String, HashMap<String, Float>>() {{
- put("PET_ITEM_IRON_CLAWS_COMMON", new HashMap<String, Float>() {{
- put("CRIT_DAMAGE", 1.4f);
- put("CRIT_CHANCE", 1.4f);
- }});
- put("PET_ITEM_TEXTBOOK", new HashMap<String, Float>() {{
- put("INTELLIGENCE", 2f);
- }});
- }};
-
- private int selectedPet = -1;
- private int petsPage = 0;
- private List<JsonObject> sortedPets = null;
- private List<ItemStack> sortedPetsStack = null;
- public static HashMap<String, String> MINION_RARITY_TO_NUM = new HashMap<String, String>() {{
- put("COMMON", "0");
- put("UNCOMMON", "1");
- put("RARE", "2");
- put("EPIC", "3");
- put("LEGENDARY", "4");
- put("MYTHIC", "5");
- }};
-
- private void drawPetsPage(int mouseX, int mouseY, float partialTicks) {
- JsonObject petsInfo = profile.getPetsInfo(profileId);
- if (petsInfo == null) return;
- JsonObject petsJson = Constants.PETS;
- if (petsJson == null) return;
-
- String location = null;
- JsonObject status = profile.getPlayerStatus();
- if (status != null && status.has("mode")) {
- location = status.get("mode").getAsString();
- }
-
- backgroundRotation += (currentTime - lastTime) / 400f;
- backgroundRotation %= 360;
-
- String panoramaIdentifier = "day";
- if (SBInfo.getInstance().currentTimeDate != null) {
- if (SBInfo.getInstance().currentTimeDate.getHours() <= 6 ||
- SBInfo.getInstance().currentTimeDate.getHours() >= 20) {
- panoramaIdentifier = "night";
- }
- }
-
- JsonArray pets = petsInfo.get("pets").getAsJsonArray();
- if (sortedPets == null) {
- sortedPets = new ArrayList<>();
- sortedPetsStack = new ArrayList<>();
- for (int i = 0; i < pets.size(); i++) {
- sortedPets.add(pets.get(i).getAsJsonObject());
- }
- sortedPets.sort((pet1, pet2) -> {
- String tier1 = pet1.get("tier").getAsString();
- String tierNum1 = MINION_RARITY_TO_NUM.get(tier1);
- if (tierNum1 == null) return 1;
- int tierNum1I = Integer.parseInt(tierNum1);
- float exp1 = pet1.get("exp").getAsFloat();
-
- String tier2 = pet2.get("tier").getAsString();
- String tierNum2 = MINION_RARITY_TO_NUM.get(tier2);
- if (tierNum2 == null) return -1;
- int tierNum2I = Integer.parseInt(tierNum2);
- float exp2 = pet2.get("exp").getAsFloat();
-
- if (tierNum1I != tierNum2I) {
- return tierNum2I - tierNum1I;
- } else {
- return (int) (exp2 - exp1);
- }
- });
- for (JsonObject pet : sortedPets) {
- String petname = pet.get("type").getAsString();
- String tier = pet.get("tier").getAsString();
- String heldItem = Utils.getElementAsString(pet.get("heldItem"), null);
- String skin = Utils.getElementAsString(pet.get("skin"), null);
- int candy = pet.get("candyUsed").getAsInt();
- JsonObject heldItemJson =
- heldItem == null ? null : NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(heldItem);
- String tierNum = MINION_RARITY_TO_NUM.get(tier);
- float exp = pet.get("exp").getAsFloat();
- if (tierNum == null) continue;
-
- if (pet.has("heldItem") && !pet.get("heldItem").isJsonNull() &&
- pet.get("heldItem").getAsString().equals("PET_ITEM_TIER_BOOST")) {
- tierNum = "" + (Integer.parseInt(tierNum) + 1);
- }
-
- PetLevel levelObj = GuiProfileViewer.getPetLevel(petname, tier, exp);
-
- float level = levelObj.level;
- float currentLevelRequirement = levelObj.currentLevelRequirement;
- float maxXP = levelObj.maxXP;
- pet.addProperty("level", level);
- pet.addProperty("currentLevelRequirement", currentLevelRequirement);
- pet.addProperty("maxXP", maxXP);
-
- JsonObject petItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(petname + ";" + tierNum);
- if (petItem == null) continue;
-
- ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(petItem, false, false);
- HashMap<String, String> replacements =
- NotEnoughUpdates.INSTANCE.manager.getLoreReplacements(petname, tier, (int) Math.floor(level));
-
- if (heldItem != null) {
- HashMap<String, Float> petStatBoots = PET_STAT_BOOSTS.get(heldItem);
- HashMap<String, Float> petStatBootsMult = PET_STAT_BOOSTS_MULT.get(heldItem);
- if (petStatBoots != null) {
- for (Map.Entry<String, Float> entryBoost : petStatBoots.entrySet()) {
- try {
- float value = Float.parseFloat(replacements.get(entryBoost.getKey()));
- replacements.put(entryBoost.getKey(), String.valueOf((int) Math.floor(value + entryBoost.getValue())));
- } catch (Exception ignored) {
- }
- }
-
- }
- if (petStatBootsMult != null) {
- for (Map.Entry<String, Float> entryBoost : petStatBootsMult.entrySet()) {
- try {
- float value = Float.parseFloat(replacements.get(entryBoost.getKey()));
- replacements.put(entryBoost.getKey(), String.valueOf((int) Math.floor(value * entryBoost.getValue())));
- } catch (Exception ignored) {
- }
- }
- }
- }
-
- NBTTagCompound tag = stack.getTagCompound() == null ? new NBTTagCompound() : stack.getTagCompound();
- if (tag.hasKey("display", 10)) {
- NBTTagCompound display = tag.getCompoundTag("display");
- if (display.hasKey("Lore", 9)) {
- NBTTagList newLore = new NBTTagList();
- NBTTagList lore = display.getTagList("Lore", 8);
- HashMap<Integer, Integer> blankLocations = new HashMap<>();
- for (int j = 0; j < lore.tagCount(); j++) {
- String line = lore.getStringTagAt(j);
- if (line.trim().isEmpty()) {
- blankLocations.put(blankLocations.size(), j);
- }
- for (Map.Entry<String, String> replacement : replacements.entrySet()) {
- line = line.replace("{" + replacement.getKey() + "}", replacement.getValue());
- }
- newLore.appendTag(new NBTTagString(line));
- }
- Integer secondLastBlank = blankLocations.get(blankLocations.size() - 2);
- if (skin != null) {
- JsonObject petSkin = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("PET_SKIN_" + skin);
- if (petSkin != null) {
- try {
- NBTTagCompound nbt = JsonToNBT.getTagFromJson(petSkin.get("nbttag").getAsString());
- tag.setTag("SkullOwner", nbt.getTag("SkullOwner"));
- String name = petSkin.get("displayname").getAsString();
- if (name != null) {
- name = Utils.cleanColour(name);
- newLore.set(0, new NBTTagString(newLore.get(0).toString().replace("\"", "") + ", " + name));
- }
- } catch (NBTException e) {
- e.printStackTrace();
- }
- }
- }
- for (int i = 0; i < newLore.tagCount(); i++) {
- String cleaned = Utils.cleanColour(newLore.get(i).toString());
- if (cleaned.equals("\"Right-click to add this pet to\"")) {
- newLore.removeTag(i + 1);
- newLore.removeTag(i);
- secondLastBlank = i - 1;
- break;
- }
- }
- NBTTagList temp = new NBTTagList();
- for (int i = 0; i < newLore.tagCount(); i++) {
- temp.appendTag(newLore.get(i));
- if (secondLastBlank != null && i == secondLastBlank) {
- if (heldItem != null) {
- temp.appendTag(new NBTTagString(
- EnumChatFormatting.GOLD + "Held Item: " + heldItemJson.get("displayname").getAsString()));
- int blanks = 0;
- JsonArray heldItemLore = heldItemJson.get("lore").getAsJsonArray();
- for (int k = 0; k < heldItemLore.size(); k++) {
- String heldItemLine = heldItemLore.get(k).getAsString();
- if (heldItemLine.trim().isEmpty()) {
- blanks++;
- } else if (blanks == 2) {
- temp.appendTag(new NBTTagString(heldItemLine));
- } else if (blanks > 2) {
- break;
- }
- }
- temp.appendTag(new NBTTagString());
- }
- if (candy != 0) {
- temp.appendTag(new NBTTagString(EnumChatFormatting.GREEN + "(" + candy + "/10) Pet Candy Used"));
- temp.appendTag(new NBTTagString());
- }
- temp.removeTag(temp.tagCount() - 1);
- }
- }
- newLore = temp;
- display.setTag("Lore", newLore);
- }
- if (display.hasKey("Name", 8)) {
- String displayName = display.getString("Name");
- for (Map.Entry<String, String> replacement : replacements.entrySet()) {
- displayName = displayName.replace("{" + replacement.getKey() + "}", replacement.getValue());
- }
- display.setTag("Name", new NBTTagString(displayName));
- }
- tag.setTag("display", display);
- }
- stack.setTagCompound(tag);
-
- sortedPetsStack.add(stack);
- }
- }
-
- Panorama.drawPanorama(-backgroundRotation, guiLeft + 212, guiTop + 44, 81, 108, -0.37f, 0.6f,
- getPanoramasForLocation(location == null ? "dynamic" : location, panoramaIdentifier)
- );
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_pets);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- Utils.drawStringCentered(EnumChatFormatting.DARK_PURPLE + "Pets", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 100, guiTop + 14, true, 4210752
- );
- GlStateManager.color(1, 1, 1, 1);
-
- JsonElement activePetElement = petsInfo.get("active_pet");
- if (selectedPet == -1 && activePetElement != null && activePetElement.isJsonObject()) {
- JsonObject active = activePetElement.getAsJsonObject();
- for (int i = 0; i < sortedPets.size(); i++) {
- if (sortedPets.get(i) == active) {
- selectedPet = i;
- break;
- }
- }
- }
-
- boolean leftHovered = false;
- boolean rightHovered = false;
- if (Mouse.isButtonDown(0)) {
- if (mouseY > guiTop + 6 && mouseY < guiTop + 22) {
- if (mouseX > guiLeft + 100 - 20 - 12 && mouseX < guiLeft + 100 - 20) {
- leftHovered = true;
- } else if (mouseX > guiLeft + 100 + 20 && mouseX < guiLeft + 100 + 20 + 12) {
- rightHovered = true;
- }
- }
- }
- Minecraft.getMinecraft().getTextureManager().bindTexture(resource_packs);
-
- if (petsPage > 0) {
- Utils.drawTexturedRect(guiLeft + 100 - 15 - 12, guiTop + 6, 12, 16,
- 29 / 256f, 53 / 256f, !leftHovered ? 0 : 32 / 256f, !leftHovered ? 32 / 256f : 64 / 256f, GL11.GL_NEAREST
- );
- }
- if (petsPage < Math.ceil(pets.size() / 20f) - 1) {
- Utils.drawTexturedRect(guiLeft + 100 + 15, guiTop + 6, 12, 16,
- 5 / 256f, 29 / 256f, !rightHovered ? 0 : 32 / 256f, !rightHovered ? 32 / 256f : 64 / 256f, GL11.GL_NEAREST
- );
- }
-
- for (
- int i = petsPage * 20;
- i < Math.min(petsPage * 20 + 20, Math.min(sortedPetsStack.size(), sortedPets.size()));
- i++
- ) {
- JsonObject pet = sortedPets.get(i);
- ItemStack stack = sortedPetsStack.get(i);
-
- if (pet != null) {
- {
- NBTTagCompound tag = stack.getTagCompound();
- tag.setBoolean("DisablePetExp", true);
- stack.setTagCompound(tag);
- }
- int xIndex = (i % 20) % COLLS_XCOUNT;
- int yIndex = (i % 20) / COLLS_XCOUNT;
-
- float x = 5 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
- float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- if (i == selectedPet) {
- GlStateManager.color(1, 185 / 255f, 0, 1);
- } else {
- GlStateManager.color(1, 1, 1, 1);
- }
- Utils.drawTexturedRect(guiLeft + x, guiTop + y, 20, 20, 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST);
-
- Utils.drawItemStack(stack, guiLeft + (int) x + 2, guiTop + (int) y + 2);
-
- if (mouseX > guiLeft + x && mouseX < guiLeft + x + 20) {
- if (mouseY > guiTop + y && mouseY < guiTop + y + 20) {
- tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- }
- }
- }
- }
-
- if (selectedPet >= 0) {
- ItemStack petStack = sortedPetsStack.get(selectedPet);
- String display = petStack.getDisplayName();
- JsonObject pet = sortedPets.get(selectedPet);
-
- int x = guiLeft + 280;
- float y = guiTop + 67 + 15 * (float) Math.sin(((currentTime - startTime) / 800f) % (2 * Math.PI));
-
- int displayLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(display);
- int halfDisplayLen = displayLen / 2;
-
- GlStateManager.pushMatrix();
- GlStateManager.translate(x, y, 0);
-
- drawRect(-halfDisplayLen - 1 - 28, -1, halfDisplayLen + 1 - 28, 8, new Color(0, 0, 0, 100).getRGB());
-
- Minecraft.getMinecraft().fontRendererObj.drawString(display, -halfDisplayLen - 28, 0, 0, true);
-
- GlStateManager.enableDepth();
- GlStateManager.translate(-55, 0, 0);
- GlStateManager.scale(3.5f, 3.5f, 1);
- Utils.drawItemStack(petStack, 0, 0);
- GlStateManager.popMatrix();
-
- float level = pet.get("level").getAsFloat();
- float currentLevelRequirement = pet.get("currentLevelRequirement").getAsFloat();
- float exp = pet.get("exp").getAsFloat();
- float maxXP = pet.get("maxXP").getAsFloat();
-
- String[] split = display.split("] ");
- String colouredName = split[split.length - 1];
-
- Utils.renderAlignedString(
- colouredName,
- EnumChatFormatting.WHITE + "Level " + (int) Math.floor(level),
- guiLeft + 319,
- guiTop + 28,
- 98
- );
-
- //Utils.drawStringCenteredScaledMaxWidth(, Minecraft.getMinecraft().fontRendererObj, guiLeft+368, guiTop+28+4, true, 98, 0);
- //renderAlignedString(display, EnumChatFormatting.YELLOW+"[LVL "+Math.floor(level)+"]", guiLeft+319, guiTop+28, 98);
- renderBar(guiLeft + 319, guiTop + 38, 98, (float) Math.floor(level) / 100f);
-
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "To Next LVL",
- EnumChatFormatting.WHITE.toString() + (int) (level % 1 * 100) + "%",
- guiLeft + 319,
- guiTop + 46,
- 98
- );
- renderBar(guiLeft + 319, guiTop + 56, 98, level % 1);
-
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "To Max LVL",
- EnumChatFormatting.WHITE.toString() + Math.min(100, (int) (exp / maxXP * 100)) + "%",
- guiLeft + 319,
- guiTop + 64,
- 98
- );
- renderBar(guiLeft + 319, guiTop + 74, 98, exp / maxXP);
-
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Total XP",
- EnumChatFormatting.WHITE + shortNumberFormat(exp, 0),
- guiLeft + 319,
- guiTop + 125,
- 98
- );
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Current LVL XP",
- EnumChatFormatting.WHITE + shortNumberFormat((level % 1) * currentLevelRequirement, 0),
- guiLeft + 319,
- guiTop + 143,
- 98
- );
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Required LVL XP",
- EnumChatFormatting.WHITE + shortNumberFormat(currentLevelRequirement, 0),
- guiLeft + 319,
- guiTop + 161,
- 98
- );
- }
- }
-
- private final String[] romans = new String[]{
- "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI",
- "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XIX", "XX"
- };
-
- private final int COLLS_XCOUNT = 5;
- private final int COLLS_YCOUNT = 4;
- private final float COLLS_XPADDING = (190 - COLLS_XCOUNT * 20) / (float) (COLLS_XCOUNT + 1);
- private final float COLLS_YPADDING = (202 - COLLS_YCOUNT * 20) / (float) (COLLS_YCOUNT + 1);
-
- private void drawColsPage(int mouseX, int mouseY, float partialTicks) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_cols);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- JsonObject collectionInfo = profile.getCollectionInfo(profileId);
- if (collectionInfo == null) {
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "Collection API not enabled!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 134,
- guiTop + 101,
- true,
- 0
- );
- return;
- }
- JsonObject resourceCollectionInfo = ProfileViewer.getResourceCollectionInformation();
- if (resourceCollectionInfo == null) return;
-
- int collectionCatSize = ProfileViewer.getCollectionCatToCollectionMap().size();
- int collectionCatYSize = (int) (162f / (collectionCatSize - 1 + 0.0000001f));
- {
- int yIndex = 0;
- for (ItemStack stack : ProfileViewer.getCollectionCatToCollectionMap().keySet()) {
- if (selectedCollectionCategory == null) selectedCollectionCategory = stack;
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- if (stack == selectedCollectionCategory) {
- Utils.drawTexturedRect(guiLeft + 7, guiTop + 10 + collectionCatYSize * yIndex, 20, 20,
- 20 / 256f, 0, 20 / 256f, 0, GL11.GL_NEAREST
- );
- Utils.drawItemStackWithText(
- stack,
- guiLeft + 10,
- guiTop + 13 + collectionCatYSize * yIndex,
- "" + (yIndex + 1)
- );
- } else {
- Utils.drawTexturedRect(guiLeft + 7, guiTop + 10 + collectionCatYSize * yIndex, 20, 20,
- 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST
- );
- Utils.drawItemStackWithText(stack, guiLeft + 9, guiTop + 12 + collectionCatYSize * yIndex, "" + (yIndex + 1));
- }
- yIndex++;
- }
- }
-
- Utils.drawStringCentered(
- selectedCollectionCategory.getDisplayName() + " Collections",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 134,
- guiTop + 14,
- true,
- 4210752
- );
-
- JsonObject minionTiers = collectionInfo.get("minion_tiers").getAsJsonObject();
- JsonObject collectionTiers = collectionInfo.get("collection_tiers").getAsJsonObject();
- JsonObject maxAmounts = collectionInfo.get("max_amounts").getAsJsonObject();
- JsonObject totalAmounts = collectionInfo.get("total_amounts").getAsJsonObject();
- JsonObject personalAmounts = collectionInfo.get("personal_amounts").getAsJsonObject();
-
- List<String> collections = ProfileViewer.getCollectionCatToCollectionMap().get(selectedCollectionCategory);
- if (collections != null) {
- for (int i = 0; i < collections.size(); i++) {
- String collection = collections.get(i);
- if (collection != null) {
- ItemStack collectionItem = ProfileViewer.getCollectionToCollectionDisplayMap().get(collection);
- if (collectionItem != null) {
- int xIndex = i % COLLS_XCOUNT;
- int yIndex = i / COLLS_XCOUNT;
-
- float x = 39 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
- float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
-
- String tierString;
- int tier = (int) Utils.getElementAsFloat(collectionTiers.get(collection), 0);
- if (tier > 20 || tier < 0) {
- tierString = String.valueOf(tier);
- } else {
- tierString = romans[tier];
- }
- float amount = Utils.getElementAsFloat(totalAmounts.get(collection), 0);
- float maxAmount = Utils.getElementAsFloat(maxAmounts.get(collection), 0);
- Color color = new Color(128, 128, 128, 255);
- int tierStringColour = color.getRGB();
- float completedness = 0;
- if (maxAmount > 0) {
- completedness = amount / maxAmount;
- }
- completedness = Math.min(1, completedness);
- if (maxAmounts.has(collection) && completedness >= 1) {
- tierStringColour = new Color(255, 215, 0).getRGB();
- }
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(guiLeft + x, guiTop + y, 20, 20 * (1 - completedness),
- 0, 20 / 256f, 0, 20 * (1 - completedness) / 256f, GL11.GL_NEAREST
- );
- GlStateManager.color(1, 185 / 255f, 0, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(guiLeft + x, guiTop + y + 20 * (1 - completedness), 20, 20 * (completedness),
- 0, 20 / 256f, 20 * (1 - completedness) / 256f, 20 / 256f, GL11.GL_NEAREST
- );
- Utils.drawItemStack(collectionItem, guiLeft + (int) x + 2, guiTop + (int) y + 2);
-
- if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
- if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
- tooltipToDisplay = new ArrayList<>();
- tooltipToDisplay.add(collectionItem.getDisplayName() + " " +
- (completedness >= 1 ? EnumChatFormatting.GOLD : EnumChatFormatting.GRAY) + tierString);
- tooltipToDisplay.add(
- "Collected: " + numberFormat.format(Utils.getElementAsFloat(personalAmounts.get(collection), 0)));
- tooltipToDisplay.add("Total Collected: " + numberFormat.format(amount));
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- if (tier >= 0) {
- Utils.drawStringCentered(tierString, fontRendererObj,
- guiLeft + x + 10, guiTop + y - 4, true,
- tierStringColour
- );
- }
-
- Utils.drawStringCentered(shortNumberFormat(amount, 0) + "", fontRendererObj,
- guiLeft + x + 10, guiTop + y + 26, true,
- color.getRGB()
- );
- }
- }
- }
- }
-
- Utils.drawStringCentered(
- selectedCollectionCategory.getDisplayName() + " Minions",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 326,
- guiTop + 14,
- true,
- 4210752
- );
-
- List<String> minions = ProfileViewer.getCollectionCatToMinionMap().get(selectedCollectionCategory);
- if (minions != null) {
- for (int i = 0; i < minions.size(); i++) {
- String minion = minions.get(i);
- if (minion != null) {
- JsonObject misc = Constants.MISC;
- float MAX_MINION_TIER =
- Utils.getElementAsFloat(Utils.getElement(misc, "minions." + minion + "_GENERATOR"), 11);
-
- int tier = (int) Utils.getElementAsFloat(minionTiers.get(minion), 0);
- JsonObject minionJson;
- if (tier == 0) {
- minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_1");
- } else {
- minionJson = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(minion + "_GENERATOR_" + tier);
- }
-
- if (minionJson != null) {
- int xIndex = i % COLLS_XCOUNT;
- int yIndex = i / COLLS_XCOUNT;
-
- float x = 231 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
- float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
-
- String tierString;
-
- if (tier - 1 >= romans.length || tier - 1 < 0) {
- tierString = String.valueOf(tier);
- } else {
- tierString = romans[tier - 1];
- }
-
- Color color = new Color(128, 128, 128, 255);
- int tierStringColour = color.getRGB();
- float completedness = tier / MAX_MINION_TIER;
-
- completedness = Math.min(1, completedness);
- if (completedness >= 1) {
- tierStringColour = new Color(255, 215, 0).getRGB();
- }
-
- GlStateManager.color(1, 1, 1, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(guiLeft + x, guiTop + y, 20, 20 * (1 - completedness),
- 0, 20 / 256f, 0, 20 * (1 - completedness) / 256f, GL11.GL_NEAREST
- );
- GlStateManager.color(1, 185 / 255f, 0, 1);
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- Utils.drawTexturedRect(guiLeft + x, guiTop + y + 20 * (1 - completedness), 20, 20 * (completedness),
- 0, 20 / 256f, 20 * (1 - completedness) / 256f, 20 / 256f, GL11.GL_NEAREST
- );
-
- Utils.drawItemStack(
- NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson),
- guiLeft + (int) x + 2,
- guiTop + (int) y + 2
- );
-
- if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
- if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
- tooltipToDisplay = NotEnoughUpdates.INSTANCE.manager.jsonToStack(minionJson)
- .getTooltip(
- Minecraft.getMinecraft().thePlayer,
- false
- );
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- if (tier >= 0) {
- Utils.drawStringCentered(tierString, fontRendererObj,
- guiLeft + x + 10, guiTop + y - 4, true,
- tierStringColour
- );
- }
- }
- }
- }
- }
-
- //190
- }
-
- private static final LinkedHashMap<String, ItemStack> invNameToDisplayMap = new LinkedHashMap<String, ItemStack>() {{
- put(
- "inv_contents",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.chest), EnumChatFormatting.GRAY + "Inventory")
- );
- put(
- "ender_chest_contents",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.ender_chest), EnumChatFormatting.GRAY + "Ender Chest")
- );
- // put("backpack_contents", Utils.createItemStack(Item.getItemFromBlock(Blocks.dropper), EnumChatFormatting.GRAY+"Backpacks"));
- put(
- "backpack_contents",
- Utils.editItemStackInfo(NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get("JUMBO_BACKPACK")), EnumChatFormatting.GRAY + "Backpacks", true)
- );
- put(
- "personal_vault_contents",
- Utils.editItemStackInfo(NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
- .getItemInformation()
- .get("IRON_CHEST")), EnumChatFormatting.GRAY + "Personal vault", true)
- );
- put("talisman_bag", Utils.createItemStack(Items.golden_apple, EnumChatFormatting.GRAY + "Accessory Bag"));
- put("wardrobe_contents", Utils.createItemStack(Items.leather_chestplate, EnumChatFormatting.GRAY + "Wardrobe"));
- put("fishing_bag", Utils.createItemStack(Items.fish, EnumChatFormatting.GRAY + "Fishing Bag"));
- put("potion_bag", Utils.createItemStack(Items.potionitem, EnumChatFormatting.GRAY + "Potion Bag"));
- }};
-
- public int countItemsInInventory(
- String internalname,
- JsonObject inventoryInfo,
- boolean specific,
- String... invsToSearch
- ) {
- int count = 0;
- for (String inv : invsToSearch) {
- JsonArray invItems = inventoryInfo.get(inv).getAsJsonArray();
- for (int i = 0; i < invItems.size(); i++) {
- if (invItems.get(i) == null || !invItems.get(i).isJsonObject()) continue;
- JsonObject item = invItems.get(i).getAsJsonObject();
- if ((specific && item.get("internalname").getAsString().equals(internalname)) ||
- (!specific && item.get("internalname").getAsString().contains(internalname))) {
- if (item.has("count")) {
- count += item.get("count").getAsInt();
- } else {
- count += 1;
- }
- }
- }
- }
- return count;
- }
-
- private static final Pattern DAMAGE_PATTERN = Pattern.compile("^Damage: \\+([0-9]+)");
- private static final Pattern STRENGTH_PATTERN = Pattern.compile("^Strength: \\+([0-9]+)");
- private static final Pattern FISHSPEED_PATTERN = Pattern.compile("^Increases fishing speed by \\+([0-9]+)");
-
- private ItemStack[] findBestItems(
- JsonObject inventoryInfo,
- int numItems,
- String[] invsToSearch,
- String[] typeMatches,
- Pattern... importantPatterns
- ) {
- ItemStack[] bestItems = new ItemStack[numItems];
- TreeMap<Integer, Set<ItemStack>> map = new TreeMap<>();
- for (String inv : invsToSearch) {
- JsonArray invItems = inventoryInfo.get(inv).getAsJsonArray();
- for (int i = 0; i < invItems.size(); i++) {
- if (invItems.get(i) == null || !invItems.get(i).isJsonObject()) continue;
- JsonObject item = invItems.get(i).getAsJsonObject();
- JsonArray lore = item.get("lore").getAsJsonArray();
- if (Utils.checkItemType(lore, true, typeMatches) >= 0) {
- int importance = 0;
- for (int j = 0; j < lore.size(); j++) {
- String line = lore.get(j).getAsString();
- for (Pattern pattern : importantPatterns) {
- Matcher matcher = pattern.matcher(Utils.cleanColour(line));
- if (matcher.find()) {
- importance += Integer.parseInt(matcher.group(1));
- }
- }
- }
- map.computeIfAbsent(importance, k -> new HashSet<>()).add(
- NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false));
- }
- }
- }
- int i = 0;
- outer:
- for (int key : map.descendingKeySet()) {
- Set<ItemStack> items = map.get(key);
- for (ItemStack item : items) {
- bestItems[i] = item;
- if (++i >= bestItems.length) break outer;
- }
- }
-
- return bestItems;
- }
-
- private int getRowsForInventory(String invName) {
- switch (invName) {
- case "wardrobe_contents":
- return 4;
- case "backpack_contents":
- return 5;
- case "ender_chest_contents":
- return 5;
- }
- return 6;
- }
-
- private boolean useActualMax(String invName) {
- switch (invName) {
- case "talisman_bag":
- case "fishing_bag":
- case "potion_bag":
- case "personal_vault_contents":
- return true;
- }
- return false;
- }
-
- private int getIgnoredRowsForInventory(String invName) {
- switch (invName) {
- case "talisman_bag":
- case "fishing_bag":
- case "potion_bag":
- return 1;
- }
- return 0;
- }
-
- private final ItemStack fillerStack = new ItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), 1, 15);
-
- public ItemStack[][][] getItemsForInventory(JsonObject inventoryInfo, String invName) {
- if (inventoryItems.containsKey(invName)) return inventoryItems.get(invName);
-
- JsonArray jsonInv = Utils.getElement(inventoryInfo, invName).getAsJsonArray();
-
- if (jsonInv.size() == 0) return new ItemStack[1][][];
-
- int jsonInvSize;
- if (useActualMax(invName)) {
- jsonInvSize = (int) Math.ceil(jsonInv.size() / 9f) * 9;
- } else {
- jsonInvSize = 9 * 4;
- float divideBy = 9f;
- if (invName.equals("wardrobe_contents")) {
- divideBy = 36f;
- }
- for (int i = 9 * 4; i < jsonInv.size(); i++) {
- JsonElement item = jsonInv.get(i);
- if (item != null && item.isJsonObject()) {
- jsonInvSize = (int) (Math.ceil((i + 1) / divideBy) * (int) divideBy);
- }
- }
- }
-
- int rowSize = 9;
- int rows = jsonInvSize / rowSize;
- int maxRowsPerPage = getRowsForInventory(invName);
- int maxInvSize = rowSize * maxRowsPerPage;
-
- int numInventories = (jsonInvSize - 1) / maxInvSize + 1;
- JsonArray backPackSizes = (JsonArray) inventoryInfo.get("backpack_sizes");
- if (invName.equals("backpack_contents")) {
- numInventories = backPackSizes.size();
- }
-
- ItemStack[][][] inventories = new ItemStack[numInventories][][];
-
- //int availableSlots = getAvailableSlotsForInventory(inventoryInfo, collectionInfo, invName);
- int startNumberJ = 0;
-
- for (int i = 0; i < numInventories; i++) {
- int thisRows = Math.min(maxRowsPerPage, rows - maxRowsPerPage * i);
- int invSize = 0;
-
- if (invName.equals("backpack_contents")) {
- thisRows = backPackSizes.get(i).getAsInt() / 9;
- invSize = startNumberJ + (thisRows * 9);
- maxInvSize = thisRows * 9;
- } else {
- startNumberJ = maxInvSize * i;
- invSize = Math.min(jsonInvSize, maxInvSize + maxInvSize * i);
- }
- if (thisRows <= 0) break;
-
- ItemStack[][] items = new ItemStack[thisRows][rowSize];
-
- for (int j = startNumberJ; j < invSize; j++) {
-
- int xIndex = (j % maxInvSize) % rowSize;
- int yIndex = (j % maxInvSize) / rowSize;
- if (invName.equals("inv_contents")) {
- yIndex--;
- if (yIndex < 0) yIndex = rows - 1;
- }
- if (yIndex >= thisRows) {
- break;
- }
-
- if (j >= jsonInv.size()) {
- items[yIndex][xIndex] = fillerStack;
- continue;
- }
- if (jsonInv.get(j) == null || !jsonInv.get(j).isJsonObject()) {
- continue;
- }
-
- JsonObject item = jsonInv.get(j).getAsJsonObject();
- ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false);
- if (item.has("item_contents")) {
- JsonArray bytesArr = item.get("item_contents").getAsJsonArray();
- byte[] bytes = new byte[bytesArr.size()];
- for (int bytesArrI = 0; bytesArrI < bytesArr.size(); bytesArrI++) {
- bytes[bytesArrI] = bytesArr.get(bytesArrI).getAsByte();
- }
- //byte[] bytes2 = null;
- NBTTagCompound tag = stack.getTagCompound();
- if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
- NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
- for (String key : ea.getKeySet()) {
- if (key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) {
- ea.setTag(key, new NBTTagByteArray(bytes));
- break;
- }
- }
- tag.setTag("ExtraAttributes", ea);
- stack.setTagCompound(tag);
- }
- }
-
- items[yIndex][xIndex] = stack;
- }
- inventories[i] = items;
- if (invName.equals("backpack_contents")) {
- startNumberJ = startNumberJ + backPackSizes.get(i).getAsInt();
- }
- }
-
- inventoryItems.put(invName, inventories);
- return inventories;
- }
-
- private ItemStack[] bestWeapons = null;
- private ItemStack[] bestRods = null;
- private ItemStack[] armorItems = null;
- private HashMap<String, ItemStack[][][]> inventoryItems = new HashMap<>();
- private String selectedInventory = "inv_contents";
- private int currentInventoryIndex = 0;
- private int arrowCount = -1;
- private int greenCandyCount = -1;
- private int purpleCandyCount = -1;
- private final GuiElementTextField inventoryTextField = new GuiElementTextField("", GuiElementTextField.SCALE_TEXT);
- private ItemStack lastBackpack;
- private int lastBackpackX;
- private int lastBackpackY;
-
- private void drawInvsPage(int mouseX, int mouseY, float partialTicks) {
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_invs);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
- inventoryTextField.setSize(88, 20);
-
- JsonObject inventoryInfo = profile.getInventoryInfo(profileId);
- if (inventoryInfo == null) return;
-
- int invNameIndex = 0;
- for (Map.Entry<String, ItemStack> entry : invNameToDisplayMap.entrySet()) {
- int xIndex = invNameIndex % 3;
- int yIndex = invNameIndex / 3;
-
- int x = 19 + 34 * xIndex;
- int y = 26 + 34 * yIndex;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
- if (entry.getKey().equals(selectedInventory)) {
- Utils.drawTexturedRect(guiLeft + x - 2, guiTop + y - 2, 20, 20, 20 / 256f, 0,
- 20 / 256f, 0, GL11.GL_NEAREST
- );
- x++;
- y++;
- } else {
- Utils.drawTexturedRect(guiLeft + x - 2, guiTop + y - 2, 20, 20, 0, 20 / 256f,
- 0, 20 / 256f, GL11.GL_NEAREST
- );
- }
-
- Utils.drawItemStackWithText(entry.getValue(), guiLeft + x, guiTop + y, "" + (invNameIndex + 1));
-
- if (mouseX >= guiLeft + x && mouseX <= guiLeft + x + 16) {
- if (mouseY >= guiTop + y && mouseY <= guiTop + y + 16) {
- tooltipToDisplay = entry.getValue().getTooltip(Minecraft.getMinecraft().thePlayer, false);
- }
- }
-
- invNameIndex++;
- }
-
- inventoryTextField.render(guiLeft + 19, guiTop + sizeY - 26 - 20);
-
- if (armorItems == null) {
- armorItems = new ItemStack[4];
- JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
- for (int i = 0; i < armor.size(); i++) {
- if (armor.get(i) == null || !armor.get(i).isJsonObject()) continue;
- armorItems[i] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(armor.get(i).getAsJsonObject(), false);
- }
- }
-
- for (int i = 0; i < armorItems.length; i++) {
- ItemStack stack = armorItems[i];
- if (stack != null) {
- Utils.drawItemStack(stack, guiLeft + 173, guiTop + 67 - 18 * i);
- if (stack != fillerStack) {
- if (mouseX >= guiLeft + 173 - 1 && mouseX <= guiLeft + 173 + 16 + 1) {
- if (mouseY >= guiTop + 67 - 18 * i - 1 && mouseY <= guiTop + 67 - 18 * i + 16 + 1) {
- tooltipToDisplay = stack.getTooltip(
- Minecraft.getMinecraft().thePlayer,
- Minecraft.getMinecraft().gameSettings.advancedItemTooltips
- );
- }
- }
- }
- }
- }
-
- ItemStack[][][] inventories = getItemsForInventory(inventoryInfo, selectedInventory);
- if (currentInventoryIndex >= inventories.length) currentInventoryIndex = inventories.length - 1;
- if (currentInventoryIndex < 0) currentInventoryIndex = 0;
-
- ItemStack[][] inventory = inventories[currentInventoryIndex];
- if (inventory == null) {
- if (selectedInventory.equalsIgnoreCase("personal_vault_contents")) {
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "Personal Vault API not enabled!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 317,
- guiTop + 101,
- true,
- 0
- );
- } else {
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "Inventory API not enabled!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 317,
- guiTop + 101,
- true,
- 0
- );
- }
- return;
- }
-
- if (bestWeapons == null) {
- bestWeapons = findBestItems(inventoryInfo, 6, new String[]{"inv_contents", "ender_chest_contents"},
- new String[]{"SWORD", "BOW"}, DAMAGE_PATTERN, STRENGTH_PATTERN
- );
- }
- if (bestRods == null) {
- bestRods = findBestItems(inventoryInfo, 3, new String[]{"inv_contents", "ender_chest_contents"},
- new String[]{"FISHING ROD"}, FISHSPEED_PATTERN
- );
- }
-
- for (int i = 0; i < bestWeapons.length; i++) {
- if (bestWeapons[i] == null) continue;
- ItemStack stack = bestWeapons[i];
- Utils.drawItemStack(stack, guiLeft + 143, guiTop + 13 + 18 * i);
- if (mouseX >= guiLeft + 143 - 1 && mouseX <= guiLeft + 143 + 16 + 1) {
- if (mouseY >= guiTop + 13 + 18 * i - 1 && mouseY <= guiTop + 13 + 18 * i + 16 + 1) {
- tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- }
- }
- }
-
- for (int i = 0; i < bestRods.length; i++) {
- if (bestRods[i] == null) continue;
- ItemStack stack = bestRods[i];
- Utils.drawItemStack(stack, guiLeft + 143, guiTop + 137 + 18 * i);
- if (mouseX >= guiLeft + 143 - 1 && mouseX <= guiLeft + 143 + 16 + 1) {
- if (mouseY >= guiTop + 137 + 18 * i - 1 && mouseY <= guiTop + 137 + 18 * i + 16 + 1) {
- tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- }
- }
- }
-
- if (arrowCount == -1) {
- arrowCount = countItemsInInventory("ARROW", inventoryInfo, false, "quiver");
- }
- if (greenCandyCount == -1) {
- greenCandyCount = countItemsInInventory("GREEN_CANDY", inventoryInfo, true, "candy_inventory_contents");
- }
- if (purpleCandyCount == -1) {
- purpleCandyCount = countItemsInInventory("PURPLE_CANDY", inventoryInfo, true, "candy_inventory_contents");
- }
-
- Utils.drawItemStackWithText(NotEnoughUpdates.INSTANCE.manager.jsonToStack(
- NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("ARROW")), guiLeft + 173, guiTop + 101,
- "" + (arrowCount > 999 ? shortNumberFormat(arrowCount, 0) : arrowCount)
- );
- Utils.drawItemStackWithText(
- NotEnoughUpdates.INSTANCE.manager.jsonToStack(
- NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("GREEN_CANDY")),
- guiLeft + 173,
- guiTop + 119,
- "" + greenCandyCount
- );
- Utils.drawItemStackWithText(
- NotEnoughUpdates.INSTANCE.manager.jsonToStack(
- NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("PURPLE_CANDY")),
- guiLeft + 173,
- guiTop + 137,
- "" + purpleCandyCount
- );
- if (mouseX > guiLeft + 173 && mouseX < guiLeft + 173 + 16) {
- if (mouseY > guiTop + 101 && mouseY < guiTop + 137 + 16) {
- if (mouseY < guiTop + 101 + 17) {
- tooltipToDisplay =
- Utils.createList(EnumChatFormatting.WHITE + "Arrow " + EnumChatFormatting.GRAY + "x" + arrowCount);
- } else if (mouseY < guiTop + 119 + 17) {
- tooltipToDisplay = Utils.createList(
- EnumChatFormatting.GREEN + "Green Candy " + EnumChatFormatting.GRAY + "x" + greenCandyCount);
- } else {
- tooltipToDisplay = Utils.createList(
- EnumChatFormatting.DARK_PURPLE + "Purple Candy " + EnumChatFormatting.GRAY + "x" + purpleCandyCount);
- }
- }
- }
-
- int inventoryRows = inventory.length;
-
- GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
- Minecraft.getMinecraft().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
-
- int invSizeY = inventoryRows * 18 + 17 + 7;
-
- int x = guiLeft + 320 - 176 / 2;
- int y = guiTop + 101 - invSizeY / 2;
- int staticSelectorHeight = guiTop + 177;
-
- this.drawTexturedModalRect(x, y, 0, 0, 176, inventoryRows * 18 + 17);
- this.drawTexturedModalRect(x, y + inventoryRows * 18 + 17, 0, 215, 176, 7);
-
- boolean leftHovered = false;
- boolean rightHovered = false;
- if (Mouse.isButtonDown(0)) {
- if (mouseY > staticSelectorHeight && mouseY < staticSelectorHeight + 16) {
- if (mouseX > guiLeft + 320 - 12 && mouseX < guiLeft + 320 + 12) {
- if (mouseX < guiLeft + 320) {
- leftHovered = true;
- } else {
- rightHovered = true;
- }
- }
- }
- }
- Minecraft.getMinecraft().getTextureManager().bindTexture(resource_packs);
-
- if (currentInventoryIndex > 0) {
- Utils.drawTexturedRect(guiLeft + 320 - 12, staticSelectorHeight, 12, 16,
- 29 / 256f, 53 / 256f, !leftHovered ? 0 : 32 / 256f, !leftHovered ? 32 / 256f : 64 / 256f, GL11.GL_NEAREST
- );
- }
- if (currentInventoryIndex < inventories.length - 1) {
- Utils.drawTexturedRect(guiLeft + 320, staticSelectorHeight, 12, 16,
- 5 / 256f, 29 / 256f, !rightHovered ? 0 : 32 / 256f, !rightHovered ? 32 / 256f : 64 / 256f, GL11.GL_NEAREST
- );
- }
-
- fontRendererObj.drawString(
- Utils.cleanColour(invNameToDisplayMap.get(selectedInventory).getDisplayName()),
- x + 8,
- y + 6,
- 4210752
- );
-
- ItemStack stackToRender = null;
- int overlay = new Color(0, 0, 0, 100).getRGB();
- for (int yIndex = 0; yIndex < inventory.length; yIndex++) {
- if (inventory[yIndex] == null) continue;
-
- for (int xIndex = 0; xIndex < inventory[yIndex].length; xIndex++) {
- ItemStack stack = inventory[yIndex][xIndex];
-
- if (stack != null) Utils.drawItemStack(stack, x + 8 + xIndex * 18, y + 18 + yIndex * 18);
-
- if (inventoryTextField.getText() != null && !inventoryTextField.getText().isEmpty() &&
- (stack == null ||
- !NotEnoughUpdates.INSTANCE.manager.doesStackMatchSearch(stack, inventoryTextField.getText()))) {
- GlStateManager.translate(0, 0, 50);
- drawRect(
- x + 8 + xIndex * 18,
- y + 18 + yIndex * 18,
- x + 8 + xIndex * 18 + 16,
- y + 18 + yIndex * 18 + 16,
- overlay
- );
- GlStateManager.translate(0, 0, -50);
- }
-
- if (stack == null || stack == fillerStack) continue;
-
- if (mouseX >= x + 8 + xIndex * 18 && mouseX <= x + 8 + xIndex * 18 + 16) {
- if (mouseY >= y + 18 + yIndex * 18 && mouseY <= y + 18 + yIndex * 18 + 16) {
- stackToRender = stack;
- }
- }
- }
- }
- if (stackToRender != null) {
- tooltipToDisplay = stackToRender.getTooltip(Minecraft.getMinecraft().thePlayer, false);
- }
-
- }
-
- private String niceUuid(String uuidStr) {
- if (uuidStr.length() != 32) return uuidStr;
-
- StringBuilder niceAucId = new StringBuilder();
- niceAucId.append(uuidStr, 0, 8);
- niceAucId.append("-");
- niceAucId.append(uuidStr, 8, 12);
- niceAucId.append("-");
- niceAucId.append(uuidStr, 12, 16);
- niceAucId.append("-");
- niceAucId.append(uuidStr, 16, 20);
- niceAucId.append("-");
- niceAucId.append(uuidStr, 20, 32);
- return niceAucId.toString();
- }
-
public EntityOtherPlayerMP getEntityPlayer() {
- return entityPlayer;
- }
-
- private EntityOtherPlayerMP entityPlayer = null;
- private ResourceLocation playerLocationSkin = null;
- private ResourceLocation playerLocationCape = null;
- private String skinType = null;
-
- private final HashMap<String, ResourceLocation[]> panoramasMap = new HashMap<>();
-
- public ResourceLocation[] getPanoramasForLocation(String location, String identifier) {
- if (panoramasMap.containsKey(location + identifier)) return panoramasMap.get(location + identifier);
- try {
- ResourceLocation[] panoramasArray = new ResourceLocation[6];
- for (int i = 0; i < 6; i++) {
- panoramasArray[i] =
- new ResourceLocation("notenoughupdates:panoramas/" + location + "_" + identifier + "/panorama_" + i + ".jpg");
- Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
- }
- panoramasMap.put(location + identifier, panoramasArray);
- return panoramasArray;
- } catch (IOException e) {
- try {
- ResourceLocation[] panoramasArray = new ResourceLocation[6];
- for (int i = 0; i < 6; i++) {
- panoramasArray[i] =
- new ResourceLocation("notenoughupdates:panoramas/" + location + "/panorama_" + i + ".jpg");
- Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
- }
- panoramasMap.put(location + identifier, panoramasArray);
- return panoramasArray;
- } catch (IOException e2) {
- ResourceLocation[] panoramasArray = new ResourceLocation[6];
- for (int i = 0; i < 6; i++) {
- panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/unknown/panorama_" + i + ".jpg");
- }
- panoramasMap.put(location + identifier, panoramasArray);
- return panoramasArray;
- }
- }
- }
-
- private TreeMap<Integer, Set<String>> topKills = null;
- private TreeMap<Integer, Set<String>> topDeaths = null;
-
- private void drawExtraPage(int mouseX, int mouseY, float partialTicks) {
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_extra);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- JsonObject profileInfo = profile.getProfileInformation(profileId);
- if (profileInfo == null) return;
- JsonObject skillInfo = profile.getSkillInfo(profileId);
-
- float xStart = 22;
- float xOffset = 103;
- float yStartTop = 27;
- float yStartBottom = 105;
- float yOffset = 10;
-
- float bankBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "banking.balance"), 0);
- float purseBalance = Utils.getElementAsFloat(Utils.getElement(profileInfo, "coin_purse"), 0);
-
- Utils.renderAlignedString(
- EnumChatFormatting.GOLD + "Bank Balance",
- EnumChatFormatting.WHITE + shortNumberFormat(bankBalance, 0),
- guiLeft + xStart,
- guiTop + yStartTop,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.GOLD + "Purse",
- EnumChatFormatting.WHITE + shortNumberFormat(purseBalance, 0),
- guiLeft + xStart,
- guiTop + yStartTop + yOffset,
- 76
- );
-
- {
- String lastSaveText = this.getTimeSinceString(profileInfo, "last_save");
- if (lastSaveText != null) {
- Utils.renderAlignedString(EnumChatFormatting.AQUA + "Last Seen", EnumChatFormatting.WHITE + lastSaveText,
- guiLeft + xStart, guiTop + yStartTop + yOffset * 2, 76
- );
- }
-
- }
- {
- String first_join = this.getTimeSinceString(profileInfo, "first_join");
- if (first_join != null) {
- Utils.renderAlignedString(EnumChatFormatting.AQUA + "Joined", EnumChatFormatting.WHITE + first_join,
- guiLeft + xStart, guiTop + yStartTop + yOffset * 3, 76
- );
- }
-
- }
- {
- JsonObject guildInfo = profile.getGuildInfo(null);
- if (guildInfo != null && guildInfo.has("name")) {
- Utils.renderAlignedString(
- EnumChatFormatting.AQUA + "Guild",
- EnumChatFormatting.WHITE + guildInfo.get("name").getAsString(),
- guiLeft + xStart,
- guiTop + yStartTop + yOffset * 4,
- 76
- );
- }
- }
-
- float fairySouls = Utils.getElementAsFloat(Utils.getElement(profileInfo, "fairy_souls_collected"), 0);
-
- int fairySoulMax = 227;
- if (Constants.FAIRYSOULS != null && Constants.FAIRYSOULS.has("Max Souls")) {
- fairySoulMax = Constants.FAIRYSOULS.get("Max Souls").getAsInt();
- }
- Utils.renderAlignedString(
- EnumChatFormatting.LIGHT_PURPLE + "Fairy Souls",
- EnumChatFormatting.WHITE.toString() + (int) fairySouls + "/" + fairySoulMax,
- guiLeft + xStart,
- guiTop + yStartBottom,
- 76
- );
- if (skillInfo != null) {
- float totalSkillLVL = 0;
- float totalTrueSkillLVL = 0;
- float totalSlayerLVL = 0;
- float totalSkillCount = 0;
- float totalSlayerCount = 0;
- float totalSlayerXP = 0;
-
- for (Map.Entry<String, JsonElement> entry : skillInfo.entrySet()) {
- if (entry.getKey().startsWith("level_skill")) {
- if (entry.getKey().contains("runecrafting")) continue;
- if (entry.getKey().contains("carpentry")) continue;
- if (entry.getKey().contains("catacombs")) continue;
-
- totalSkillLVL += entry.getValue().getAsFloat();
- totalTrueSkillLVL += Math.floor(entry.getValue().getAsFloat());
- totalSkillCount++;
- } else if (entry.getKey().startsWith("level_slayer")) {
- totalSlayerLVL += entry.getValue().getAsFloat();
- totalSlayerCount++;
- } else if (entry.getKey().startsWith("experience_slayer")) {
- totalSlayerXP += entry.getValue().getAsFloat();
- }
- }
-
- float avgSkillLVL = totalSkillLVL / totalSkillCount;
- float avgTrueSkillLVL = totalTrueSkillLVL / totalSkillCount;
- float avgSlayerLVL = totalSlayerLVL / totalSlayerCount;
-
- Utils.renderAlignedString(
- EnumChatFormatting.RED + "AVG Skill Level",
- EnumChatFormatting.WHITE.toString() + Math.floor(avgSkillLVL * 10) / 10,
- guiLeft + xStart,
- guiTop + yStartBottom + yOffset,
- 76
- );
-
- Utils.renderAlignedString(
- EnumChatFormatting.RED + "True AVG Skill Level",
- EnumChatFormatting.WHITE.toString() + Math.floor(avgTrueSkillLVL * 10) / 10,
- guiLeft + xStart,
- guiTop + yStartBottom + yOffset * 2,
- 76
- );
-
- Utils.renderAlignedString(
- EnumChatFormatting.RED + "AVG Slayer Level",
- EnumChatFormatting.WHITE.toString() + Math.floor(avgSlayerLVL * 10) / 10,
- guiLeft + xStart,
- guiTop + yStartBottom + yOffset * 3,
- 76
- );
-
- Utils.renderAlignedString(
- EnumChatFormatting.RED + "Total Slayer XP",
- EnumChatFormatting.WHITE + shortNumberFormat(totalSlayerXP, 0),
- guiLeft + xStart,
- guiTop + yStartBottom + yOffset * 4,
- 76
- );
- }
-
- float auctions_bids = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_bids"), 0);
- float auctions_highest_bid =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_highest_bid"), 0);
- float auctions_won = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_won"), 0);
- float auctions_created = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_created"), 0);
- float auctions_gold_spent = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_gold_spent"), 0);
- float auctions_gold_earned =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.auctions_gold_earned"), 0);
-
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Auction Bids",
- EnumChatFormatting.WHITE.toString() + (int) auctions_bids,
- guiLeft + xStart + xOffset,
- guiTop + yStartTop,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Highest Bid",
- EnumChatFormatting.WHITE + shortNumberFormat(auctions_highest_bid, 0),
- guiLeft + xStart + xOffset,
- guiTop + yStartTop + yOffset,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Auctions Won",
- EnumChatFormatting.WHITE.toString() + (int) auctions_won,
- guiLeft + xStart + xOffset,
- guiTop + yStartTop + yOffset * 2,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Auctions Created",
- EnumChatFormatting.WHITE.toString() + (int) auctions_created,
- guiLeft + xStart + xOffset,
- guiTop + yStartTop + yOffset * 3,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Gold Spent",
- EnumChatFormatting.WHITE + shortNumberFormat(auctions_gold_spent, 0),
- guiLeft + xStart + xOffset,
- guiTop + yStartTop + yOffset * 4,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Gold Earned",
- EnumChatFormatting.WHITE + shortNumberFormat(auctions_gold_earned, 0),
- guiLeft + xStart + xOffset,
- guiTop + yStartTop + yOffset * 5,
- 76
- );
-
- //Slayer values
- float zombie_boss_kills_tier_2 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_2"), 0);
- float zombie_boss_kills_tier_3 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_3"), 0);
- float zombie_boss_kills_tier_4 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.boss_kills_tier_4"), 0);
- float wolf_boss_kills_tier_2 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.wolf.boss_kills_tier_2"), 0);
- float wolf_boss_kills_tier_3 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.wolf.boss_kills_tier_3"), 0);
- float spider_boss_kills_tier_2 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.boss_kills_tier_2"), 0);
- float spider_boss_kills_tier_3 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.boss_kills_tier_3"), 0);
- float enderman_boss_kills_tier_2 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.enderman.boss_kills_tier_2"), 0);
- float enderman_boss_kills_tier_3 =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.enderman.boss_kills_tier_3"), 0);
-
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Revenant T3",
- EnumChatFormatting.WHITE.toString() + (int) zombie_boss_kills_tier_2,
- guiLeft + xStart + xOffset,
- guiTop + yStartBottom,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Revenant T4",
- EnumChatFormatting.WHITE.toString() + (int) zombie_boss_kills_tier_3,
- guiLeft + xStart + xOffset,
- guiTop + yStartBottom + yOffset,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Revenant T5",
- EnumChatFormatting.WHITE.toString() + (int) zombie_boss_kills_tier_4,
- guiLeft + xStart + xOffset,
- guiTop + yStartBottom + yOffset * 2,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Tarantula T3",
- EnumChatFormatting.WHITE.toString() + (int) spider_boss_kills_tier_2,
- guiLeft + xStart + xOffset,
- guiTop + yStartBottom + yOffset * 3,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Tarantula T4",
- EnumChatFormatting.WHITE.toString() + (int) spider_boss_kills_tier_3,
- guiLeft + xStart + xOffset,
- guiTop + yStartBottom + yOffset * 4,
- 76
- );
-
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Sven T3",
- EnumChatFormatting.WHITE.toString() + (int) wolf_boss_kills_tier_2,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartBottom + yOffset * 0,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Sven T4",
- EnumChatFormatting.WHITE.toString() + (int) wolf_boss_kills_tier_3,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartBottom + yOffset * 1,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Voidgloom T3",
- EnumChatFormatting.WHITE.toString() + (int) enderman_boss_kills_tier_2,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartBottom + yOffset * 2,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_AQUA + "Voidgloom T4",
- EnumChatFormatting.WHITE.toString() + (int) enderman_boss_kills_tier_3,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartBottom + yOffset * 3,
- 76
- );
-
- float pet_milestone_ores_mined =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.pet_milestone_ores_mined"), 0);
- float pet_milestone_sea_creatures_killed =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.pet_milestone_sea_creatures_killed"), 0);
-
- float items_fished = Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished"), 0);
- float items_fished_treasure =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished_treasure"), 0);
- float items_fished_large_treasure =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "stats.items_fished_large_treasure"), 0);
-
- Utils.renderAlignedString(
- EnumChatFormatting.GREEN + "Ores Mined",
- EnumChatFormatting.WHITE.toString() + (int) pet_milestone_ores_mined,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartTop,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.GREEN + "Sea Creatures Killed",
- EnumChatFormatting.WHITE.toString() + (int) pet_milestone_sea_creatures_killed,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartTop + yOffset,
- 76
- );
-
- Utils.renderAlignedString(
- EnumChatFormatting.GREEN + "Items Fished",
- EnumChatFormatting.WHITE.toString() + (int) items_fished,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartTop + yOffset * 3,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.GREEN + "Treasures Fished",
- EnumChatFormatting.WHITE.toString() + (int) items_fished_treasure,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartTop + yOffset * 4,
- 76
- );
- Utils.renderAlignedString(
- EnumChatFormatting.GREEN + "Large Treasures",
- EnumChatFormatting.WHITE.toString() + (int) items_fished_large_treasure,
- guiLeft + xStart + xOffset * 2,
- guiTop + yStartTop + yOffset * 5,
- 76
- );
-
- if (topKills == null) {
- topKills = new TreeMap<>();
- JsonObject stats = profileInfo.get("stats").getAsJsonObject();
- for (Map.Entry<String, JsonElement> entry : stats.entrySet()) {
- if (entry.getKey().startsWith("kills_")) {
- if (entry.getValue().isJsonPrimitive()) {
- JsonPrimitive prim = (JsonPrimitive) entry.getValue();
- if (prim.isNumber()) {
- String name = WordUtils.capitalizeFully(entry.getKey().substring("kills_".length()).replace("_", " "));
- Set<String> kills = topKills.computeIfAbsent(prim.getAsInt(), k -> new HashSet<>());
- kills.add(name);
- }
- }
- }
- }
- }
- if (topDeaths == null) {
- topDeaths = new TreeMap<>();
- JsonObject stats = profileInfo.get("stats").getAsJsonObject();
- for (Map.Entry<String, JsonElement> entry : stats.entrySet()) {
- if (entry.getKey().startsWith("deaths_")) {
- if (entry.getValue().isJsonPrimitive()) {
- JsonPrimitive prim = (JsonPrimitive) entry.getValue();
- if (prim.isNumber()) {
- String name = WordUtils.capitalizeFully(entry.getKey().substring("deaths_".length()).replace("_", " "));
- Set<String> deaths = topDeaths.computeIfAbsent(prim.getAsInt(), k -> new HashSet<>());
- deaths.add(name);
- }
- }
- }
- }
- }
-
- int index = 0;
- for (int killCount : topKills.descendingKeySet()) {
- if (index >= 6) break;
- Set<String> kills = topKills.get(killCount);
- for (String killType : kills) {
- if (index >= 6) break;
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + killType + " Kills",
- EnumChatFormatting.WHITE.toString() + killCount,
- guiLeft + xStart + xOffset * 3,
- guiTop + yStartTop + yOffset * index,
- 76
- );
- index++;
- }
- }
- index = 0;
- for (int deathCount : topDeaths.descendingKeySet()) {
- if (index >= 6) break;
- Set<String> deaths = topDeaths.get(deathCount);
- for (String deathType : deaths) {
- if (index >= 6) break;
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Deaths: " + deathType,
- EnumChatFormatting.WHITE.toString() + deathCount,
- guiLeft + xStart + xOffset * 3,
- guiTop + yStartBottom + yOffset * index,
- 76
- );
- index++;
- }
- }
- }
-
- private void drawMiningPage(int mouseX, int mouseY, float partialTicks) {
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_mining);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- JsonObject profileInfo = profile.getProfileInformation(profileId);
- if (profileInfo == null) return;
- JsonObject skillInfo = profile.getSkillInfo(profileId);
-
- float xStart = 22;
- float xOffset = 103;
- float yStartTop = 27;
- float yStartBottom = 105;
- float yOffset = 10;
-
- int x = guiLeft + 23;
- int y = guiTop + 25;
- int sectionWidth = 110;
- JsonObject leveling = Constants.LEVELING;
- ProfileViewer.Level levelObjhotm = levelObjhotms.get(profileId);
- if (levelObjhotm == null) {
- float hotmXp = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.experience"), 0);
- levelObjhotm = ProfileViewer.getLevel(Utils.getElement(leveling, "HOTM").getAsJsonArray(),
- hotmXp, 7, false
- );
- levelObjhotms.put(profileId, levelObjhotm);
- }
-
- String skillName = EnumChatFormatting.RED + "HOTM";
- //The stats that show
- float mithrilPowder = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.powder_mithril"), 0);
- float gemstonePowder = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.powder_gemstone"), 0);
- float mithrilPowderTotal =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.powder_spent_mithril"), 0);
- float gemstonePowderTotal =
- (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.powder_spent_gemstone"), 0));
- String jadeCrystal =
- (Utils.getElementAsString(Utils.getElement(profileInfo, "mining_core.crystals.jade_crystal.state"), "Not Found"));
- float crystalPlacedAmount =
- (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.crystals.jade_crystal.total_placed"), 0));
- String jadeCrystalString = "§c✖";
- String amethystCrystal = (Utils.getElementAsString(
- Utils.getElement(profileInfo, "mining_core.crystals.amethyst_crystal.state"),
- "Not Found"
- ));
- String amethystCrystalString = "§c✖";
- String amberCrystal = (Utils.getElementAsString(
- Utils.getElement(profileInfo, "mining_core.crystals.amber_crystal.state"),
- "Not Found"
- ));
- String amberCrystalString = "§c✖";
- String sapphireCrystal = (Utils.getElementAsString(
- Utils.getElement(profileInfo, "mining_core.crystals.sapphire_crystal.state"),
- "Not Found"
- ));
- String sapphireCrystalString = "§c✖";
- String topazCrystal = (Utils.getElementAsString(
- Utils.getElement(profileInfo, "mining_core.crystals.topaz_crystal.state"),
- "Not Found"
- ));
- String topazCrystalString = "§c✖";
- String jasperCrystal = (Utils.getElementAsString(
- Utils.getElement(profileInfo, "mining_core.crystals.jasper_crystal.state"),
- "Not Found"
- ));
- String jasperCrystalString = "§c✖";
- String rubyCrystal =
- (Utils.getElementAsString(Utils.getElement(profileInfo, "mining_core.crystals.ruby_crystal.state"), "Not Found"));
- String rubyCrystalString = "§c✖";
- int miningFortune = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune"), 0)));
- int miningFortuneStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune"), 0)) * 5);
- int miningSpeed = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed"), 0)));
- int miningSpeedStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed"), 0)) * 20);
- int dailyPowder = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.daily_powder"), 0)));
- int dailyPowderStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.daily_powder"), 0)) * 36 + 364);
- int effMiner = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.efficient_miner"), 0)));
- float effMinerStat =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.efficient_miner"), 0)) * 0.4 +
- 10.4);
- float effMinerStat2 =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.efficient_miner"), 0)) * .06 +
- 0.31);
- int tittyInsane =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.titanium_insanium"), 0)));
- float tittyInsaneStat =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.titanium_insanium"), 0)) * .1 +
- 2);
- int luckofcave = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.random_event"), 0)));
- int luckofcaveStat = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.random_event"), 0)));
- int madMining = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_madness"), 0)));
- int skyMall = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.daily_effect"), 0)));
- int goblinKiller = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.goblin_killer"), 0)));
- int seasonMine = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_experience"), 0)));
- float seasonMineStat = (float) (
- (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.mining_experience"), 0)) * 0.1 + 5);
- int quickForge = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.forge_time"), 0)));
- float quickForgeStat =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.forge_time"), 0)) * .5 + 10);
- int frontLoad = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.front_loaded"), 0)));
- int orbit = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.experience_orbs"), 0)));
- float orbitStat =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.experience_orbs"), 0)) * .01 +
- 0.2);
- int crystallized =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.fallen_star_bonus"), 0)));
- int crystallizedStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.fallen_star_bonus"), 0)) * 6 + 14);
- int professional = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.professional"), 0)));
- int professionalStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.professional"), 0)) * 5 + 50);
- int greatExplorer = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.great_explorer"), 0)));
- int greatExplorerStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.great_explorer"), 0)) * 4 + 16);
- int fortunate = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.fortunate"), 0)));
- int fortunateStat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.fortunate"), 0)) * 4 + 20);
- int lonesomeMiner = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.lonesome_miner"), 0)));
- float lonesomeMinerStat =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.lonesome_miner"), 0)) * .5 +
- 5);
- int miningFortune2 =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune_2"), 0)));
- int miningFortune2Stat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune_2"), 0)) * 5);
- int miningSpeed2 = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed_2"), 0)));
- int miningSpeed2Stat =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed_2"), 0)) * 40);
- int miningSpeedBoost =
- ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed_boost"), 0)));
- int veinSeeker = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.vein_seeker"), 0)));
- int powderBuff = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.powder_buff"), 0)));
- int potm = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.special_0"), 0)));
- int fortnite = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.precision_mining"), 0)));
- int starPowder = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.star_powder"), 0)));
- int pickoblus = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.pickaxe_toss"), 0)));
- int maniacMiner = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.maniac_miner"), 0)));
-
- if (effMinerStat2 < 1) {
- effMinerStat2 = 1;
- }
- int mole = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mole"), 0)));
- float moleStat =
- (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.mole"), 0)) * 0.051);
- double moleperkstat = (double) mole / 20 - 0.55 + 50;
- double moleperkstat2 = (double) Math.round(moleperkstat * 100) / 100;
-
- float output = Math.round((float) (moleperkstat2 % 1) * 100);
- if (output == 0) {
- output = 100;
- }
-
- //The logic for some of the stats
- if (Objects.equals(jadeCrystal, "NOT_FOUND")) {
- jadeCrystalString = "§c✖";
- } else if (Objects.equals(jadeCrystal, "FOUND")) {
- jadeCrystalString = "§a✔";
- }
- if (Objects.equals(amethystCrystal, "NOT_FOUND")) {
- amethystCrystalString = "§c✖";
- } else if (Objects.equals(amethystCrystal, "FOUND")) {
- amethystCrystalString = "§a✔";
- }
- if (Objects.equals(amberCrystal, "NOT_FOUND")) {
- amberCrystalString = "§c✖";
- } else if (Objects.equals(amberCrystal, "FOUND")) {
- amberCrystalString = "§a✔";
- }
- if (Objects.equals(sapphireCrystal, "NOT_FOUND")) {
- sapphireCrystalString = "§c✖";
- } else if (Objects.equals(sapphireCrystal, "FOUND")) {
- sapphireCrystalString = "§a✔";
- }
- if (Objects.equals(topazCrystal, "NOT_FOUND")) {
- topazCrystalString = "§c✖";
- } else if (Objects.equals(topazCrystal, "FOUND")) {
- topazCrystalString = "§a✔";
- }
- if (Objects.equals(jasperCrystal, "NOT_FOUND")) {
- jasperCrystalString = "§c✖";
- } else if (Objects.equals(jasperCrystal, "FOUND")) {
- jasperCrystalString = "§a✔";
- }
- if (Objects.equals(rubyCrystal, "NOT_FOUND")) {
- rubyCrystalString = "§c✖";
- } else if (Objects.equals(rubyCrystal, "FOUND")) {
- rubyCrystalString = "§a✔";
- }
-
- //The rendering of the stats
- //hotm level
- renderXpBar(skillName, iron_pick, x, y, sectionWidth, levelObjhotm, mouseX, mouseY);
- //Powder
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_GREEN + "Mithril Powder",
- EnumChatFormatting.WHITE + shortNumberFormat(mithrilPowder, 0),
- guiLeft + xStart,
- guiTop + yStartTop + 24,
- 115
- );
- Utils.renderAlignedString(
- EnumChatFormatting.LIGHT_PURPLE + "Gemstone Powder",
- EnumChatFormatting.WHITE + shortNumberFormat(gemstonePowder, 0),
- guiLeft + xStart,
- guiTop + yStartTop + 44,
- 115
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_GREEN + "Total Mithril Powder",
- EnumChatFormatting.WHITE + shortNumberFormat(mithrilPowderTotal + mithrilPowder, 0),
- guiLeft + xStart,
- guiTop + yStartTop + 34,
- 115
- );
- Utils.renderAlignedString(
- EnumChatFormatting.LIGHT_PURPLE + "Total Gemstone Powder",
- EnumChatFormatting.WHITE + shortNumberFormat(gemstonePowderTotal + gemstonePowder, 0),
- guiLeft + xStart,
- guiTop + yStartTop + 54,
- 115
- );
- //Crystals
- Utils.renderAlignedString(EnumChatFormatting.GREEN + "Jade Crystal:", EnumChatFormatting.WHITE + jadeCrystalString,
- guiLeft + xStart, guiTop + yStartTop + 74, 110
- );
- Utils.renderAlignedString(EnumChatFormatting.GOLD + "Amber Crystal:", EnumChatFormatting.WHITE + amberCrystalString,
- guiLeft + xStart, guiTop + yStartTop + 84, 110
- );
- Utils.renderAlignedString(
- EnumChatFormatting.DARK_PURPLE + "Amethyst Crystal:",
- EnumChatFormatting.WHITE + amethystCrystalString,
- guiLeft + xStart,
- guiTop + yStartTop + 94,
- 110
- );
- Utils.renderAlignedString(
- EnumChatFormatting.AQUA + "Sapphire Crystal:",
- EnumChatFormatting.WHITE + sapphireCrystalString,
- guiLeft + xStart,
- guiTop + yStartTop + 104,
- 110
- );
- Utils.renderAlignedString(
- EnumChatFormatting.YELLOW + "Topaz Crystal:",
- EnumChatFormatting.WHITE + topazCrystalString,
- guiLeft + xStart,
- guiTop + yStartTop + 114,
- 110
- );
- Utils.renderAlignedString(
- EnumChatFormatting.LIGHT_PURPLE + "Jasper Crystal:",
- EnumChatFormatting.WHITE + jasperCrystalString,
- guiLeft + xStart,
- guiTop + yStartTop + 124,
- 110
- );
- Utils.renderAlignedString(EnumChatFormatting.RED + "Ruby Crystal:", EnumChatFormatting.WHITE + rubyCrystalString,
- guiLeft + xStart, guiTop + yStartTop + 134, 110
- );
- Utils.renderAlignedString(
- EnumChatFormatting.BLUE + "Total Placed Crystals:",
- EnumChatFormatting.WHITE + shortNumberFormat(crystalPlacedAmount, 0),
- guiLeft + xStart,
- guiTop + yStartTop + 149,
- 110
- );
-
- //hotm render
- //Pain
-
- renderHotmPerk(
- miningSpeed,
- (int) (guiLeft + xStart + 255),
- (int) (guiTop + yStartTop + 138),
- mouseX,
- mouseY,
- () -> Lists.newArrayList(
- "Mining Speed",
- EnumChatFormatting.GRAY + "Level " + miningSpeed + EnumChatFormatting.DARK_GRAY + "/50",
- "",
- EnumChatFormatting.GRAY + "Grants " + EnumChatFormatting.GREEN + "+" + miningSpeedStat +
- EnumChatFormatting.GOLD + " ⸕ Mining",
- EnumChatFormatting.GOLD + "Speed" + EnumChatFormatting.GRAY + "."
- ),
- 50
- );
-
- renderHotmPerk(
- miningFortune,
- (int) (guiLeft + xStart + 255), (int) (guiTop + yStartTop + 114),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Mining Fortune",
- EnumChatFormatting.GRAY + "Level " + miningFortune + EnumChatFormatting.DARK_GRAY + "/50",
- "",
- EnumChatFormatting.GRAY + "Grants " + EnumChatFormatting.GREEN + "+" + miningFortuneStat +
- EnumChatFormatting.GOLD + " ☘ Mining",
- EnumChatFormatting.GOLD + "Fortune" + EnumChatFormatting.GRAY + "."
- ),
- 50
- );
-
- renderHotmPerk(
- tittyInsane,
- (int) (guiLeft + xStart + 231), (int) (guiTop + yStartTop + 114),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Titanium Insanium",
- EnumChatFormatting.GRAY + "Level " + tittyInsane + EnumChatFormatting.DARK_GRAY + "/50",
- "",
- EnumChatFormatting.GRAY + "When mining Mithril Ore, you",
- EnumChatFormatting.GRAY + "have a " + EnumChatFormatting.GREEN + tittyInsaneStat + "% " +
- EnumChatFormatting.GRAY + "chance to",
- EnumChatFormatting.GRAY + "convert the block into Titanium",
- EnumChatFormatting.GRAY + "Ore."
- ),
- 50
- );
-
- renderPickaxeAbility(
- miningSpeedBoost,
- (int) (guiLeft + xStart + 207), (int) (guiTop + yStartTop + 114),
- mouseX, mouseY,
- () -> potm == 0 ? Lists.newArrayList( // Peak of the mountain == 0
- "Mining Speed Boost",
- "",
- EnumChatFormatting.GRAY + "Pickaxe Ability: Mining Speed Boost",
- EnumChatFormatting.GRAY + "Grants " + EnumChatFormatting.GREEN + "200% " + EnumChatFormatting.GOLD + "⸕ Mining",
- EnumChatFormatting.GOLD + "Speed " + EnumChatFormatting.GRAY + "for " + EnumChatFormatting.GREEN + "15s" +
- EnumChatFormatting.GRAY,
- EnumChatFormatting.DARK_GRAY + "Cooldown: " + EnumChatFormatting.GREEN + "120s"
- ) : Lists.newArrayList( // Peak of the mountain > 0
- "Mining Speed Boost",
- "",
- EnumChatFormatting.GRAY + "Pickaxe Ability: Mining Speed Boost",
- EnumChatFormatting.GRAY + "Grants " + EnumChatFormatting.GREEN + "300% " + EnumChatFormatting.GOLD + "⸕ Mining",
- EnumChatFormatting.GOLD + "Speed " + EnumChatFormatting.GRAY + "for " + EnumChatFormatting.GREEN + "20s" +
- EnumChatFormatting.GRAY,
- EnumChatFormatting.DARK_GRAY + "Cooldown: " + EnumChatFormatting.GREEN + "120s"
- )
- );
-
- renderPickaxeAbility(
- veinSeeker,
- (int) (guiLeft + xStart + 183), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Vein Seeker",
- "",
- "§6Pickaxe Ability: Vein Seeker",
- "§7Points in the direction of the",
- "§7nearest vein and grants §a+§a3§7",
- "§7§6Mining Spread §7for §a14s§7§7.",
- "§8Cooldown: §a60s"
- )
- );
-
- renderHotmPerk(
- luckofcave,
- (int) (guiLeft + xStart + 207), (int) (guiTop + yStartTop + 90),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Luck of the Cave",
- "§7Level " + luckofcave + EnumChatFormatting.DARK_GRAY + "/45",
- "",
- "§7Increases the chance for you to",
- "§7trigger rare occurrences im",
- "§2Dwarven Mines " + EnumChatFormatting.GRAY + "by " + EnumChatFormatting.GREEN + luckofcaveStat + "%§7."
- ),
- 45
- );
-
- renderHotmPerk(
- dailyPowder,
- (int) (guiLeft + xStart + 255), (int) (guiTop + yStartTop + 90),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Daily Powder",
- EnumChatFormatting.GRAY + "Level " + dailyPowder + EnumChatFormatting.DARK_GRAY + "/100",
- "",
- EnumChatFormatting.GRAY + "Gains " + EnumChatFormatting.GREEN + dailyPowderStat + " Powder" +
- EnumChatFormatting.GRAY + " from the",
- EnumChatFormatting.GRAY + "first ore you mine every day.",
- EnumChatFormatting.GRAY + "Works for all Powder types."
- ),
- 100
- );
-
- float finalEffMinerStat2 = effMinerStat2;
- renderHotmPerk(
- effMiner,
- (int) (guiLeft + xStart + 255), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Efficient Miner",
- EnumChatFormatting.GRAY + "Level " + effMiner + EnumChatFormatting.DARK_GRAY + "/100",
- "",
- EnumChatFormatting.GRAY + "When mining ores, you have a",
- EnumChatFormatting.GREEN + "" + effMinerStat + "%" + EnumChatFormatting.GRAY + " chance to mine " +
- EnumChatFormatting.GREEN + Math.round(finalEffMinerStat2),
- EnumChatFormatting.GRAY + "adjacent ores."
- ),
- 100
- );
-
- renderHotmPerk(
- potm,
- (int) (guiLeft + xStart + 255), (int) (guiTop + yStartTop + 42),
- mouseX, mouseY,
- () -> {
- switch (potm) {
- case 0:
- return Lists.newArrayList(
- EnumChatFormatting.RED + "Peak of the Mountain",
- EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/5"
- );
- case 1:
- return Lists.newArrayList(
- EnumChatFormatting.YELLOW + "Peak of the Mountain",
- EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/5",
- "",
- "§7§8+§c1 Pickaxe Ability Level",
- "§7§8+§51 Token of the Mountain"
- );
- case 2:
- return Lists.newArrayList(
- EnumChatFormatting.YELLOW + "Peak of the Mountain",
- EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/5",
- "",
- "§7§8+§c1 Pickaxe Ability Level",
- "§7§8+§51 Token of the Mountain",
- "§7§8+§a1 Forge Slot"
- );
- case 3:
- return Lists.newArrayList(
- EnumChatFormatting.YELLOW + "Peak of the Mountain",
- EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/5",
- "",
- "§7§8+§c1 Pickaxe Ability Level",
- "§7§8+§51 Token of the Mountain",
- "§7§8+§a1 Forge Slot",
- "§7§8+§a1 Commission Slot"
- );
- case 4:
- return Lists.newArrayList(
- EnumChatFormatting.YELLOW + "Peak of the Mountain",
- EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/5",
- "",
- "§7§8+§c1 Pickaxe Ability Level",
- "§7§8+§51 Token of the Mountain",
- "§7§8+§a1 Forge Slot",
- "§7§8+§a1 Commission Slot",
- "§7§8+§21 Mithril Powder §7when",
- "§7mining §fMithril"
- );
- case 5:
- return Lists.newArrayList(
- EnumChatFormatting.GREEN + "Peak of the Mountain",
- EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/5",
- "",
- "§7§8+§c1 Pickaxe Ability Level",
- "§7§8+§51 Token of the Mountain",
- "§7§8+§a1 Forge Slot",
- "§7§8+§a1 Commission Slot",
- "§7§8+§21 Mithril Powder §7when",
- "§7mining §fMithril",
- "§7§8+§51 Token of the Mountain"
- );
- }
- return null;
- },
- potm > 0 ? new ItemStack(Blocks.redstone_block) : new ItemStack(Blocks.bedrock),
- true // A redstone block or bedrock is being rendered, so standard GUI item lighting needs to be enabled.
- );
-
- float finalOutput = output;
- renderHotmPerk(
- mole,
- (int) (guiLeft + xStart + 255), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Mole",
- EnumChatFormatting.GRAY + "Level " + mole + EnumChatFormatting.DARK_GRAY + "/190",
- "",
- EnumChatFormatting.GRAY + "When mining hard stone, you have",
- EnumChatFormatting.GRAY + "a " + EnumChatFormatting.GREEN + finalOutput + "% " + EnumChatFormatting.GRAY +
- "chance to mine " + EnumChatFormatting.GREEN,
- EnumChatFormatting.GREEN + "" + Math.round(moleStat) + EnumChatFormatting.GRAY + " adjacent hard stone block" +
- (moleStat == 1.0 ? "." : "s.")
- ),
- 190
- );
-
- renderHotmPerk(
- powderBuff,
- (int) (guiLeft + xStart + 255), (int) (guiTop + yStartTop - 6),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Powder Buff",
- EnumChatFormatting.GRAY + "Level " + powderBuff + EnumChatFormatting.DARK_GRAY + "/50",
- "",
- EnumChatFormatting.GRAY + "Gain " + EnumChatFormatting.GREEN + powderBuff + "% " + EnumChatFormatting.GRAY +
- "more Mithril",
- EnumChatFormatting.GRAY + "Powder and Gemstone Powder§7."
- ),
- 50
- );
-
- renderHotmPerk(
- skyMall,
- (int) (guiLeft + xStart + 183), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Sky Mall",
- "§7Every SkyBlock day, you receive",
- "§7a random buff in the §2Dwarven",
- "§2Mines§7.",
- "",
- "§7Possible Buffs",
- "§8 ■ §7Gain §a+100 §6⸕ Mining Speed.",
- "§8 ■ §7Gain §a+50 §6☘ Mining Fortune.",
- "§8 ■ §7Gain §a+15% §7chance to gain",
- " §7extra Powder while mining.",
- "§8 ■ §7Reduce Pickaxe Ability cooldown",
- " §7by §a20%", "§8 ■ §7§a10x §7chance to find Goblins",
- " §7while mining.",
- "§8 ■ §7Gain §a5x §9Titanium §7drops."
- ),
- new ItemStack(skyMall > 0 ? Items.diamond : Items.coal)
- );
-
- renderHotmPerk(
- goblinKiller,
- (int) (guiLeft + xStart + 207), (int) (guiTop + yStartTop + 42),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Goblin Killer",
- "§7Killing a §6Golden Goblin",
- "§6§7gives §2200 §7extra §2Mithril",
- "§2Powder§7, while killing other",
- "§7Goblins gives some based on",
- "§7their wits."
- ),
- new ItemStack(goblinKiller > 0 ? Items.diamond : Items.coal)
- );
-
- renderHotmPerk(
- seasonMine,
- (int) (guiLeft + xStart + 231), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Seasoned Mineman",
- "§7Level " + seasonMine + "§8/100",
- "",
- "§7Increases your Mining",
- "§7experience gain by " + EnumChatFormatting.GREEN + seasonMineStat + "%§7."
- ),
- 100
- );
-
- renderHotmPerk(
- madMining,
- (int) (guiLeft + xStart + 207), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Mining Madness",
- "§7Grants §a+50 §6⸕ Mining Speed",
- "§7and §6☘ Mining Fortune§7."
- ),
- new ItemStack(madMining > 0 ? Items.diamond : Items.coal)
- );
-
- renderHotmPerk(
- lonesomeMiner,
- (int) (guiLeft + xStart + 207), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Lonesome Miner",
- "§7Level " + lonesomeMiner + EnumChatFormatting.DARK_GRAY + "/45",
- "",
- "§7Increases §c❁ Strength, §9☣ Crit",
- "§9Chance, §9☠ Crit Damage, §a❈",
- "§aDefense, and §c❤ Health",
- "§c§7statistics gain by " + EnumChatFormatting.GREEN + lonesomeMinerStat + "%§7",
- "§7while in the Crystal Hollows."
- ),
- 45
- );
-
- renderHotmPerk(
- professional,
- (int) (guiLeft + xStart + 231), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Professional",
- "§7Level " + professional + EnumChatFormatting.DARK_GRAY + "/140",
- "",
- "§7Gain §a+" + professionalStat + "§6 ⸕ Mining",
- "§6Speed§7 when mining Gemstones."
- ),
- 140
- );
-
- renderHotmPerk(
- miningSpeed2,
- (int) (guiLeft + xStart + 207), (int) (guiTop + yStartTop - 6),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Mining Speed 2",
- "§7Level " + miningSpeed2 + EnumChatFormatting.DARK_GRAY + "/50",
- "",
- "§7Grants " + EnumChatFormatting.GREEN + "+" + miningSpeed2Stat + EnumChatFormatting.GOLD + " ⸕ Mining",
- "§6Speed§7."
- ),
- 50
- );
-
- renderHotmPerk(
- quickForge,
- (int) (guiLeft + xStart + 279), (int) (guiTop + yStartTop + 114),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Quick Forge",
- "§7Level " + quickForge + EnumChatFormatting.DARK_GRAY + "/20",
- "",
- "§7Decreases the time it takes to",
- "§7forge by §a" + (quickForgeStat < 20 ? quickForgeStat : 30) + "%§7."
- ),
- 20
- );
-
- renderHotmPerk(
- fortunate,
- (int) (guiLeft + xStart + 279), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Fortunate",
- "§7Level " + fortunate + EnumChatFormatting.DARK_GRAY + "/20",
- "",
- "§7Gain " + EnumChatFormatting.GREEN + "+" + fortunateStat + " §6☘ Mining",
- "§6Fortune§7 when mining Gemstone."
- ),
- 20
- );
-
- renderHotmPerk(
- greatExplorer,
- (int) (guiLeft + xStart + 303), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Great Explorer",
- "§7Level " + greatExplorer + EnumChatFormatting.DARK_GRAY + "/20",
- "",
- "§7Grants " + EnumChatFormatting.GREEN + "+" + greatExplorerStat + "% " + EnumChatFormatting.GRAY + "chance to",
- "§7find treasure."
- ),
- 20
- );
-
- renderHotmPerk(
- miningFortune2,
- (int) (guiLeft + xStart + 303), (int) (guiTop + yStartTop - 6),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Mining Fortune 2",
- "§7Level " + miningFortune2 + EnumChatFormatting.DARK_GRAY + "/50",
- "",
- "§7Grants §a+§a" + miningFortune2Stat + "§7 §6☘ Mining", "§6Fortune§7."
- ),
- 50
- );
-
- renderHotmPerk(
- orbit,
- (int) (guiLeft + xStart + 279), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Orbiter",
- "§7Level " + orbit + EnumChatFormatting.DARK_GRAY + "/80",
- "",
- "§7When mining ores, you have a",
- EnumChatFormatting.GREEN + "" + orbitStat + "%" + EnumChatFormatting.GRAY + " chance to get a random",
- "§7amount of experience orbs."
- ),
- 80
- );
-
- renderHotmPerk(
- frontLoad,
- (int) (guiLeft + xStart + 303), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Front Loaded",
- "§7Grants §a+100 §6⸕ Mining Speed",
- "§7and §6☘ Mining Fortune §7for",
- "§7the first §e2,500 §7ores you",
- "§7mine in a day."
- ),
- new ItemStack(frontLoad > 0 ? Items.diamond : Items.coal)
- );
-
- renderHotmPerk(
- starPowder,
- (int) (guiLeft + xStart + 303), (int) (guiTop + yStartTop + 42),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Star Powder",
- "§7Mining Mithril Ore near §5Fallen",
- "§5Crystals §7gives §a+3 §7extra",
- "§7Mithril Powder§7."
- ),
- new ItemStack(starPowder > 0 ? Items.diamond : Items.coal)
- );
-
- renderHotmPerk(
- fortnite,
- (int) (guiLeft + xStart + 327), (int) (guiTop + yStartTop + 66),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Precision Mining",
- "§7When mining ore, a particle",
- "§7target appears on the block that",
- "§7increases your §6⸕ Mining Speed",
- "§7by §a30% §7when aiming at it."
- ),
- new ItemStack(fortnite > 0 ? Items.diamond : Items.coal)
- );
-
- renderHotmPerk(
- crystallized,
- (int) (guiLeft + xStart + 303), (int) (guiTop + yStartTop + 90),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Crystallized",
- "§7Level " + crystallized + EnumChatFormatting.DARK_GRAY + "/30",
- "",
- "§7Grants §a+§a" + crystallizedStat + "§7 §6⸕ Mining",
- "§6Speed §7and a §a" + crystallizedStat + "%§7 §7chance",
- "§7to deal §a+1 §7extra damage near",
- "§7§5Fallen Stars§7."
- ),
- 30
- );
-
- renderPickaxeAbility(
- pickoblus,
- (int) (guiLeft + xStart + 303), (int) (guiTop + yStartTop + 114),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- "Pickobulus",
- "",
- "§6Pickaxe Ability: Pickobulus",
- "§7Throw your pickaxe to create an",
- "§7explosion on impact, mining all",
- "§7ores within a §a2§7 block",
- "§7radius.",
- "§8Cooldown: §a" + (potm == 0 ? "120s" : "110s")
- )
- );
-
- renderPickaxeAbility(
- maniacMiner,
- (int) (guiLeft + xStart + 327), (int) (guiTop + yStartTop + 18),
- mouseX, mouseY,
- () -> Lists.newArrayList(
- EnumChatFormatting.RED + "Maniac Miner",
- "",
- "§6Pickaxe Ability: Maniac Miner",
- "§7Spends all your Mana and grants",
- "§7§a+1 §6⸕ Mining Speed §7for",
- "§7every 10 Mana spent, for",
- "§7§a§a15s§7§7.",
- "§8Cooldown: §a59s"
- )
- );
- }
-
- /**
- * Renders a standard HOTM perk that can be levelled.
- */
- private void renderHotmPerk(
- int perkLevel,
- int xPosition,
- int yPosition,
- int mouseX,
- int mouseY,
- Supplier<ArrayList<String>> tooltipSupplier,
- int maxLevel
- ) {
- renderHotmPerk(perkLevel, xPosition, yPosition, mouseX, mouseY, tooltipSupplier, false, maxLevel);
- }
-
- /**
- * Renders a pickaxe ability that can be unlocked once and not levelled.
- */
- private void renderPickaxeAbility(
- int perkLevel,
- int xPosition,
- int yPosition,
- int mouseX,
- int mouseY,
- Supplier<ArrayList<String>> tooltipSupplier
- ) {
- renderHotmPerk(perkLevel, xPosition, yPosition, mouseX, mouseY, tooltipSupplier, true, -1);
- }
-
- /**
- * Renders a HOTM perk. This method is only called from its overloads above.
- */
- private void renderHotmPerk(
- int perkLevel,
- int xPosition,
- int yPosition,
- int mouseX,
- int mouseY,
- Supplier<ArrayList<String>> tooltipSupplier,
- boolean isPickaxeAbility,
- int maxLevel
- ) {
- boolean unlocked = perkLevel > 0;
- GlStateManager.color(1, 1, 1, 1);
- GlStateManager.disableLighting();
-
- ItemStack itemStack;
- if (isPickaxeAbility) {
- RenderHelper.enableGUIStandardItemLighting(); // GUI standard item lighting must be enabled for items that are rendered as blocks, like emerald blocks.
- itemStack =
- new ItemStack(unlocked ? Blocks.emerald_block : Blocks.coal_block); // Pickaxe abilities are rendered as blocks
- } else { // Non-pickaxe abilities are rendered as items
- itemStack = new ItemStack(unlocked ? (perkLevel >= maxLevel ? Items.diamond : Items.emerald) : Items.coal);
- }
-
- ArrayList<String> tooltip = tooltipSupplier.get();
- // Prepend the green, yellow, or red color on the first line of each tooltip depending on if the perk is unlocked
- tooltip.set(
- 0,
- (unlocked
- ? (perkLevel >= maxLevel ? EnumChatFormatting.GREEN : EnumChatFormatting.YELLOW)
- : EnumChatFormatting.RED) + tooltip.get(0)
- );
-
- NBTTagCompound nbt = new NBTTagCompound(); //Adding NBT Data for Custom Resource Packs
- NBTTagCompound display = new NBTTagCompound();
- display.setString("Name", tooltip.get(0));
- nbt.setTag("display", display);
- itemStack.setTagCompound(nbt);
-
- Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, xPosition, yPosition);
- GlStateManager.enableLighting();
- if (mouseX >= xPosition && mouseX < xPosition + 16) {
- if (mouseY >= yPosition && mouseY <= yPosition + 16) {
- Utils.drawHoveringText(tooltip, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
- }
- }
- }
-
- /**
- * A separate method similar to the one above, but allowing the caller to specify an ItemStack to render.
- * Used for rendering Peak of the Mountain and perks that are unlocked once and not upgraded.
- */
- private void renderHotmPerk(
- int perkLevel,
- int xPosition,
- int yPosition,
- int mouseX,
- int mouseY,
- Supplier<ArrayList<String>> tooltipSupplier,
- ItemStack itemStack
- ) {
- renderHotmPerk(perkLevel, xPosition, yPosition, mouseX, mouseY, tooltipSupplier, itemStack, false);
- }
-
- /**
- * This method renders a HOTM perk using the provided ItemStack.
- * It is overloaded by the method above, and is only called directly to render Peak of the Mountain.
- */
- private void renderHotmPerk(
- int perkLevel,
- int xPosition,
- int yPosition,
- int mouseX,
- int mouseY,
- Supplier<ArrayList<String>> tooltipSupplier,
- ItemStack itemStack,
- boolean isRenderingBlock
- ) {
- boolean unlocked = perkLevel > 0;
- GlStateManager.color(1, 1, 1, 1);
- GlStateManager.disableLighting();
- if (isRenderingBlock) RenderHelper.enableGUIStandardItemLighting();
-
- ArrayList<String> tooltip = tooltipSupplier.get();
- // Prepend the green or red color on the first line of each tooltip depending on if the perk is unlocked
- if (!tooltip.get(0).contains("Peak of the Mountain")) tooltip.set(
- 0,
- (unlocked ? EnumChatFormatting.GREEN : EnumChatFormatting.RED) + tooltip.get(0)
- ); //Peak of the Moutain has three color options, and is set already
-
- NBTTagCompound nbt = new NBTTagCompound(); //Adding NBT Data for Resource Packs
- NBTTagCompound display = new NBTTagCompound();
- display.setString("Name", tooltip.get(0));
- if (tooltip.get(0).contains("Peak of the Mountain")) display.setString("Lore", tooltip.get(1)); //Set Lore to Level
- nbt.setTag("display", display);
- itemStack.setTagCompound(nbt);
-
- Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, xPosition, yPosition);
- GlStateManager.enableLighting();
- if (mouseX >= xPosition && mouseX < xPosition + 16) {
- if (mouseY >= yPosition && mouseY <= yPosition + 16) {
- Utils.drawHoveringText(tooltip, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
- }
- }
- }
-
- private String getTimeSinceString(JsonObject profileInfo, String path) {
- JsonElement lastSaveElement = Utils.getElement(profileInfo, path);
-
- if (lastSaveElement != null && lastSaveElement.isJsonPrimitive()) {
-
- Instant lastSave = Instant.ofEpochMilli(lastSaveElement.getAsLong());
- LocalDateTime lastSaveTime = LocalDateTime.ofInstant(lastSave, TimeZone.getDefault().toZoneId());
- long timeDiff = System.currentTimeMillis() - lastSave.toEpochMilli();
- LocalDateTime sinceOnline = LocalDateTime.ofInstant(Instant.ofEpochMilli(timeDiff), ZoneId.of("UTC"));
- String renderText;
-
- if (timeDiff < 60000L) {
- renderText = sinceOnline.getSecond() + " seconds ago.";
- } else if (timeDiff < 3600000L) {
- renderText = sinceOnline.getMinute() + " minutes ago.";
- } else if (timeDiff < 86400000L) {
- renderText = sinceOnline.getHour() + " hours ago.";
- } else if (timeDiff < 31556952000L) {
- renderText = sinceOnline.getDayOfYear() + " days ago.";
- } else {
- renderText = lastSaveTime.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
- }
- return renderText;
- }
- return null;
- }
-
- private int backgroundClickedX = -1;
-
- private static final char[] c = new char[]{'k', 'm', 'b', 't'};
-
- public static String shortNumberFormat(double n, int iteration) {
- if (n < 1000) {
- if (n % 1 == 0) {
- return Integer.toString((int) n);
- } else {
- return String.format("%.2f", n);
- }
- }
-
- double d = ((long) n / 100) / 10.0;
- boolean isRound = (d * 10) % 10 == 0;
- return (d < 1000 ?
- ((d > 99.9 || isRound || (!isRound && d > 9.99) ?
- (int) d * 10 / 10 : d + ""
- ) + "" + c[iteration])
- : shortNumberFormat(d, iteration + 1));
- }
-
- private boolean loadingProfile = false;
- private static final ExecutorService profileLoader = Executors.newFixedThreadPool(1);
-
- private void drawBasicPage(int mouseX, int mouseY, float partialTicks) {
- FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
-
- String location = null;
- JsonObject status = profile.getPlayerStatus();
- if (status != null && status.has("mode")) {
- location = status.get("mode").getAsString();
- }
-
- int extraRotation = 0;
- if (Mouse.isButtonDown(0) || Mouse.isButtonDown(1)) {
- if (backgroundClickedX == -1) {
- if (mouseX > guiLeft + 23 && mouseX < guiLeft + 23 + 81) {
- if (mouseY > guiTop + 44 && mouseY < guiTop + 44 + 108) {
- backgroundClickedX = mouseX;
- }
- }
- }
- } else {
- if (backgroundClickedX != -1) {
- backgroundRotation += mouseX - backgroundClickedX;
- backgroundClickedX = -1;
- }
- }
- if (backgroundClickedX == -1) {
- backgroundRotation += (currentTime - lastTime) / 400f;
- } else {
- extraRotation = mouseX - backgroundClickedX;
- }
- backgroundRotation %= 360;
-
- String panoramaIdentifier = "day";
- if (SBInfo.getInstance().currentTimeDate != null) {
- if (SBInfo.getInstance().currentTimeDate.getHours() <= 6 ||
- SBInfo.getInstance().currentTimeDate.getHours() >= 20) {
- panoramaIdentifier = "night";
- }
- }
-
- Panorama.drawPanorama(-backgroundRotation - extraRotation, guiLeft + 23, guiTop + 44, 81, 108, 0.37f, 0.8f,
- getPanoramasForLocation(location == null ? "unknown" : location, panoramaIdentifier)
- );
-
- Minecraft.getMinecraft().getTextureManager().bindTexture(pv_basic);
- Utils.drawTexturedRect(guiLeft, guiTop, sizeX, sizeY, GL11.GL_NEAREST);
-
- if (entityPlayer != null && profile.getHypixelProfile() != null) {
- String playerName = null;
- if (profile.getHypixelProfile().has("prefix")) {
- playerName =
- Utils.getElementAsString(profile.getHypixelProfile().get("prefix"), "") + " " + entityPlayer.getName();
- } else {
- String rank = Utils.getElementAsString(
- profile.getHypixelProfile().get("rank"),
- Utils.getElementAsString(profile.getHypixelProfile().get("newPackageRank"), "NONE")
- );
- String monthlyPackageRank =
- Utils.getElementAsString(profile.getHypixelProfile().get("monthlyPackageRank"), "NONE");
- if (!rank.equals("YOUTUBER") && !monthlyPackageRank.equals("NONE")) {
- rank = monthlyPackageRank;
- }
- EnumChatFormatting rankPlusColorECF = EnumChatFormatting.getValueByName(Utils.getElementAsString(
- profile.getHypixelProfile().get("rankPlusColor"),
- "GOLD"
- ));
- String rankPlusColor = EnumChatFormatting.GOLD.toString();
- if (rankPlusColorECF != null) {
- rankPlusColor = rankPlusColorECF.toString();
- }
-
- JsonObject misc = Constants.MISC;
- if (misc != null) {
- if (misc.has("ranks")) {
- String rankName = Utils.getElementAsString(Utils.getElement(misc, "ranks." + rank + ".tag"), null);
- String rankColor = Utils.getElementAsString(Utils.getElement(misc, "ranks." + rank + ".color"), "7");
- String rankPlus = Utils.getElementAsString(Utils.getElement(misc, "ranks." + rank + ".plus"), "");
-
- String name = entityPlayer.getName();
-
- if (misc.has("special_bois")) {
- JsonArray special_bois = misc.get("special_bois").getAsJsonArray();
- for (int i = 0; i < special_bois.size(); i++) {
- if (special_bois.get(i).getAsString().equals(profile.getUuid())) {
- name = Utils.chromaString(name);
- break;
- }
- }
- }
-
- playerName = EnumChatFormatting.GRAY + name;
- if (rankName != null) {
- StringBuilder sb = new StringBuilder();
- sb.append("\u00A7" + rankColor);
- sb.append("[");
- sb.append(rankName);
- sb.append(rankPlusColor);
- sb.append(rankPlus);
- sb.append("\u00A7" + rankColor);
- sb.append("] ");
- sb.append(name);
- playerName = sb.toString();
- }
- }
- }
-
- }
- if (playerName != null) {
- int rankPrefixLen = fr.getStringWidth(playerName);
- int halfRankPrefixLen = rankPrefixLen / 2;
-
- int x = guiLeft + 63;
- int y = guiTop + 54;
-
- drawRect(x - halfRankPrefixLen - 1, y - 1, x + halfRankPrefixLen + 1, y + 8, new Color(0, 0, 0, 64).getRGB());
-
- fr.drawString(playerName, x - halfRankPrefixLen, y, 0, true);
- }
- }
-
- long networth = profile.getNetWorth(profileId);
- if (networth > 0) {
- Utils.drawStringCentered(
- EnumChatFormatting.GREEN + "Net Worth: " + EnumChatFormatting.GOLD + numberFormat.format(networth),
- fr,
- guiLeft + 63,
- guiTop + 38,
- true,
- 0
- );
- try {
- double networthInCookies = (networth / NotEnoughUpdates.INSTANCE.manager.auctionManager
- .getBazaarInfo("BOOSTER_COOKIE")
- .get("avg_buy")
- .getAsDouble());
- String networthIRLMoney = Long.toString(Math.round(((networthInCookies * 325) / 675) * 4.99));
-
- if (mouseX > guiLeft + 8 &&
- mouseX < guiLeft + 8 + fontRendererObj.getStringWidth("Net Worth: " + numberFormat.format(networth))) {
- if (mouseY > guiTop + 32 && mouseY < guiTop + 32 + fontRendererObj.FONT_HEIGHT) {
- tooltipToDisplay = new ArrayList<>();
- tooltipToDisplay.add(
- EnumChatFormatting.GREEN + "Net worth in IRL money: " + EnumChatFormatting.DARK_GREEN + "$" +
- EnumChatFormatting.GOLD + networthIRLMoney);
- tooltipToDisplay.add("");
- if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)) {
- tooltipToDisplay.add(EnumChatFormatting.RED + "This is calculated using the current");
- tooltipToDisplay.add(EnumChatFormatting.RED + "price of booster cookies on bazaar and the price");
- tooltipToDisplay.add(EnumChatFormatting.RED + "for cookies using gems, then the price of gems");
- tooltipToDisplay.add(EnumChatFormatting.RED + "is where we get the amount of IRL money you");
- tooltipToDisplay.add(EnumChatFormatting.RED + "theoretically have on skyblock in net worth.");
- } else {
- tooltipToDisplay.add(EnumChatFormatting.GRAY + "[SHIFT for Info]");
- }
- if (!NotEnoughUpdates.INSTANCE.config.hidden.dev) {
- tooltipToDisplay.add("");
- tooltipToDisplay.add(EnumChatFormatting.RED + "THIS IS IN NO WAY ENDORSING IRL TRADING!");
- }
- }
- }
- } catch (Exception ignored) {
- }
- }
-
- if (status != null) {
- JsonElement onlineElement = Utils.getElement(status, "online");
- boolean online = onlineElement != null && onlineElement.isJsonPrimitive() && onlineElement.getAsBoolean();
- String statusStr = online ? EnumChatFormatting.GREEN + "ONLINE" : EnumChatFormatting.RED + "OFFLINE";
- String locationStr = null;
- if (profile.getUuid().equals("20934ef9488c465180a78f861586b4cf")) {
- locationStr = "Ignoring DMs";
- } else {
- if (location != null) {
- JsonObject misc = Constants.MISC;
- if (misc != null) {
- locationStr = Utils.getElementAsString(Utils.getElement(misc, "area_names." + location), "Unknown");
- }
- }
- }
- if (locationStr != null) {
- statusStr += EnumChatFormatting.GRAY + " - " + EnumChatFormatting.GREEN + locationStr;
- }
-
- Utils.drawStringCentered(statusStr, fr, guiLeft + 63, guiTop + 160, true, 0);
- }
-
- if (entityPlayer == null) {
- if (!loadingProfile || ((ThreadPoolExecutor) profileLoader).getActiveCount() == 0) {
- loadingProfile = true;
- UUID playerUUID = UUID.fromString(niceUuid(profile.getUuid()));
-
- profileLoader.submit(() -> {
- GameProfile fakeProfile = Minecraft
- .getMinecraft()
- .getSessionService()
- .fillProfileProperties(new GameProfile(playerUUID, "CoolGuy123"), false);
- entityPlayer = new EntityOtherPlayerMP(Minecraft.getMinecraft().theWorld, fakeProfile) {
- public ResourceLocation getLocationSkin() {
- return playerLocationSkin == null
- ? DefaultPlayerSkin.getDefaultSkin(this.getUniqueID())
- : playerLocationSkin;
- }
-
- public ResourceLocation getLocationCape() {
- return playerLocationCape;
- }
-
- public String getSkinType() {
- return skinType == null ? DefaultPlayerSkin.getSkinType(this.getUniqueID()) : skinType;
- }
- };
- entityPlayer.setAlwaysRenderNameTag(false);
- entityPlayer.setCustomNameTag("");
- });
- }
- } else {
- entityPlayer.refreshDisplayName();
- byte b = 0;
- for (EnumPlayerModelParts part : EnumPlayerModelParts.values()) {
- b |= part.getPartMask();
- }
- entityPlayer.getDataWatcher().updateObject(10, b);
- }
-
- JsonObject profileInfo = profile.getProfileInformation(profileId);
- if (profileInfo == null) return;
-
- JsonObject skillInfo = profile.getSkillInfo(profileId);
- JsonObject inventoryInfo = profile.getInventoryInfo(profileId);
-
- if (entityPlayer != null) {
- if (backgroundClickedX != -1 && Mouse.isButtonDown(1)) {
- Arrays.fill(entityPlayer.inventory.armorInventory, null);
- } else {
- if (inventoryInfo != null && inventoryInfo.has("inv_armor")) {
- JsonArray items = inventoryInfo.get("inv_armor").getAsJsonArray();
- if (items != null && items.size() == 4) {
- for (int i = 0; i < entityPlayer.inventory.armorInventory.length; i++) {
- JsonElement itemElement = items.get(i);
- if (itemElement != null && itemElement.isJsonObject()) {
- entityPlayer.inventory.armorInventory[i] =
- NotEnoughUpdates.INSTANCE.manager.jsonToStack(itemElement.getAsJsonObject(), false);
- }
- }
- }
- } else {
- Arrays.fill(entityPlayer.inventory.armorInventory, null);
- }
- }
- if (entityPlayer.getUniqueID().toString().equals("ae6193ab-494a-4719-b6e7-d50392c8f012")) {
- entityPlayer.inventory.armorInventory[3] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
- NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("SMALL_BACKPACK"));
- }
- }
-
- if (entityPlayer != null && playerLocationSkin == null) {
- try {
- Minecraft
- .getMinecraft()
- .getSkinManager()
- .loadProfileTextures(entityPlayer.getGameProfile(), (type, location1, profileTexture) -> {
- switch (type) {
- case SKIN:
- playerLocationSkin = location1;
- skinType = profileTexture.getMetadata("model");
-
- if (skinType == null) {
- skinType = "default";
- }
-
- break;
- case CAPE:
- playerLocationCape = location1;
- }
- }, false);
- } catch (Exception ignored) {
- }
- }
-
- GlStateManager.color(1, 1, 1, 1);
- JsonObject petsInfo = profile.getPetsInfo(profileId);
- if (petsInfo != null) {
- JsonElement activePetElement = petsInfo.get("active_pet");
- if (activePetElement != null && activePetElement.isJsonObject()) {
- JsonObject activePet = activePetElement.getAsJsonObject();
-
- String type = activePet.get("type").getAsString();
-
- for (int i = 0; i < 4; i++) {
- JsonObject item = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(type + ";" + i);
- if (item != null) {
- int x = guiLeft + 20;
- float y = guiTop + 82 + 15 * (float) Math.sin(((currentTime - startTime) / 800f) % (2 * Math.PI));
- GlStateManager.translate(x, y, 0);
- ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false);
-
- //Remove extra attributes so no CIT
- NBTTagCompound stackTag = stack.getTagCompound() == null ? new NBTTagCompound() : stack.getTagCompound();
- stackTag.removeTag("ExtraAttributes");
- stack.setTagCompound(stackTag);
-
- GlStateManager.scale(1.5f, 1.5f, 1);
- GlStateManager.enableDepth();
- Utils.drawItemStack(stack, 0, 0);
- GlStateManager.scale(1 / 1.5f, 1 / 1.5f, 1);
- GlStateManager.translate(-x, -y, 0);
- break;
- }
- }
- }
- }
- if (entityPlayer != null) {
- drawEntityOnScreen(
- guiLeft + 63,
- guiTop + 128 + 7,
- 36,
- guiLeft + 63 - mouseX,
- guiTop + 129 - mouseY,
- entityPlayer
- );
- }
-
- PlayerStats.Stats stats = profile.getStats(profileId);
-
- if (stats != null) {
- Splitter splitter = Splitter.on(" ").omitEmptyStrings().limit(2);
- for (int i = 0; i < PlayerStats.defaultStatNames.length; i++) {
- String statName = PlayerStats.defaultStatNames[i];
- if (statName.equals("mining_fortune") || statName.equals("mining_speed")) continue;
- String statNamePretty = PlayerStats.defaultStatNamesPretty[i];
-
- int val = Math.round(stats.get(statName));
-
- GlStateManager.color(1, 1, 1, 1);
- GlStateManager.enableBlend();
- GL14.glBlendFuncSeparate(
- GL11.GL_SRC_ALPHA,
- GL11.GL_ONE_MINUS_SRC_ALPHA,
- GL11.GL_ONE,
- GL11.GL_ONE_MINUS_SRC_ALPHA
- );
- Utils.renderAlignedString(
- statNamePretty,
- EnumChatFormatting.WHITE.toString() + val,
- guiLeft + 132,
- guiTop + 27 + 11f * i,
- 80
- );
-
- if (mouseX > guiLeft + 132 && mouseX < guiLeft + 212) {
- if (mouseY > guiTop + 27 + 11f * i && mouseY < guiTop + 37 + 11f * i) {
- List<String> split = splitter.splitToList(statNamePretty);
- PlayerStats.Stats baseStats = PlayerStats.getBaseStats();
- tooltipToDisplay = new ArrayList<>();
- tooltipToDisplay.add(statNamePretty);
- int base = Math.round(baseStats.get(statName));
- tooltipToDisplay.add(
- EnumChatFormatting.GRAY + "Base " + split.get(1) + ": " + EnumChatFormatting.GREEN + base + " " +
- split.get(0));
- int passive = Math.round(profile.getPassiveStats(profileId).get(statName) - baseStats.get(statName));
- tooltipToDisplay.add(
- EnumChatFormatting.GRAY + "Passive " + split.get(1) + " Bonus: +" + EnumChatFormatting.YELLOW + passive +
- " " + split.get(0));
- int itemBonus = Math.round(stats.get(statName) - profile.getPassiveStats(profileId).get(statName));
- tooltipToDisplay.add(
- EnumChatFormatting.GRAY + "Item " + split.get(1) + " Bonus: +" + EnumChatFormatting.DARK_PURPLE +
- itemBonus + " " + split.get(0));
- int finalStat = Math.round(stats.get(statName));
- tooltipToDisplay.add(
- EnumChatFormatting.GRAY + "Final " + split.get(1) + ": +" + EnumChatFormatting.RED + finalStat + " " +
- split.get(0));
- }
- }
- }
- } else {
- Utils.drawStringCentered(EnumChatFormatting.RED + "Skill/Inv/Coll", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 172, guiTop + 101 - 10, true, 0
- );
- Utils.drawStringCentered(EnumChatFormatting.RED + "APIs not", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 172, guiTop + 101, true, 0
- );
- Utils.drawStringCentered(EnumChatFormatting.RED + "enabled!", Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 172, guiTop + 101 + 10, true, 0
- );
- }
-
- if (skillInfo != null) {
- int position = 0;
- for (Map.Entry<String, ItemStack> entry : ProfileViewer.getSkillToSkillDisplayMap().entrySet()) {
- if (entry.getValue() == null || entry.getKey() == null) {
- position++;
- continue;
- }
-
- int yPosition = position % 7;
- int xPosition = position / 7;
-
- String skillName = entry.getValue().getDisplayName();
-
- float level = Utils.getElementAsFloat(skillInfo.get("level_" + entry.getKey()), 0);
- int levelFloored = (int) Math.floor(level);
-
- int x = guiLeft + 237 + 86 * xPosition;
- int y = guiTop + 31 + 21 * yPosition;
-
- Utils.renderAlignedString(skillName, EnumChatFormatting.WHITE.toString() + levelFloored, x + 14, y - 4, 60);
-
- if (skillInfo.get("maxed_" + entry.getKey()).getAsBoolean()) {
- renderGoldBar(x, y + 6, 80);
- } else {
- renderBar(x, y + 6, 80, level % 1);
- }
-
- if (mouseX > x && mouseX < x + 80) {
- if (mouseY > y - 4 && mouseY < y + 13) {
- tooltipToDisplay = new ArrayList<>();
- tooltipToDisplay.add(skillName);
- if (skillInfo.get("maxed_" + entry.getKey()).getAsBoolean()) {
- tooltipToDisplay.add(EnumChatFormatting.GRAY + "Progress: " + EnumChatFormatting.GOLD + "MAXED!");
- } else {
- int maxXp = (int) skillInfo.get("maxxp_" + entry.getKey()).getAsFloat();
- tooltipToDisplay.add(EnumChatFormatting.GRAY + "Progress: " + EnumChatFormatting.DARK_PURPLE +
- shortNumberFormat(Math.round((level % 1) * maxXp), 0) + "/" + shortNumberFormat(maxXp, 0));
- }
- String totalXpS = NumberFormat
- .getIntegerInstance()
- .format((int) skillInfo.get("experience_" + entry.getKey()).getAsFloat());
- tooltipToDisplay.add(EnumChatFormatting.GRAY + "Total XP: " +
- EnumChatFormatting.DARK_PURPLE + totalXpS);
- }
- }
-
- GL11.glTranslatef((x), (y - 6f), 0);
- GL11.glScalef(0.7f, 0.7f, 1);
- Utils.drawItemStackLinear(entry.getValue(), 0, 0);
- GL11.glScalef(1 / 0.7f, 1 / 0.7f, 1);
- GL11.glTranslatef(-(x), -(y - 6f), 0);
-
- position++;
- }
- } else {
- Utils.drawStringCentered(
- EnumChatFormatting.RED + "Skills API not enabled!",
- Minecraft.getMinecraft().fontRendererObj,
- guiLeft + 322,
- guiTop + 101,
- true,
- 0
- );
- }
+ return ((BasicPage) pages.get(ProfileViewerPage.BASIC)).entityPlayer;
}
- private void renderGoldBar(float x, float y, float xSize) {
+ public void renderGoldBar(float x, float y, float xSize) {
if (!OpenGlHelper.areShadersSupported()) {
renderBar(x, y, xSize, 1);
return;
@@ -4854,19 +1089,15 @@ public class GuiProfileViewer extends GuiScreen {
GL20.glUseProgram(0);
}
- private void renderBar(float x, float y, float xSize, float completed) {
+ public void renderBar(float x, float y, float xSize, float completed) {
Minecraft.getMinecraft().getTextureManager().bindTexture(icons);
completed = Math.round(completed / 0.05f) * 0.05f;
-
- float notcompleted = 1 - completed;
-
- int displayNum = 0;//tl.x%5;
-
+ float notCompleted = 1 - completed;
GlStateManager.color(1, 1, 1, 1);
- float width = 0;
+ float width;
- if (completed < 0.5f && (displayNum == 1 || displayNum == 0)) {
+ if (completed < 0.5f) {
width = (0.5f - completed) * xSize;
Utils.drawTexturedRect(
x + xSize * completed,
@@ -4880,8 +1111,8 @@ public class GuiProfileViewer extends GuiScreen {
GL11.GL_NEAREST
);
}
- if (completed < 1f && (displayNum == 2 || displayNum == 0)) {
- width = Math.min(xSize * notcompleted, xSize / 2f);
+ if (completed < 1f) {
+ width = Math.min(xSize * notCompleted, xSize / 2f);
Utils.drawTexturedRect(
x + (xSize / 2f) + Math.max(xSize * (completed - 0.5f), 0),
y,
@@ -4895,127 +1126,30 @@ public class GuiProfileViewer extends GuiScreen {
);
}
- if (completed > 0f && (displayNum == 3 || displayNum == 0)) {
+ if (completed > 0f) {
width = Math.min(xSize * completed, xSize / 2f);
- Utils.drawTexturedRect(x, y, width, 5,
- 0 / 256f, width / 256f, 79 / 256f, 84 / 256f, GL11.GL_NEAREST
- );
+ Utils.drawTexturedRect(x, y, width, 5, 0 / 256f, width / 256f, 79 / 256f, 84 / 256f, GL11.GL_NEAREST);
}
- if (completed > 0.5f && (displayNum == 4 || displayNum == 0)) {
+ if (completed > 0.5f) {
width = Math.min(xSize * (completed - 0.5f), xSize / 2f);
- Utils.drawTexturedRect(x + (xSize / 2f), y, width, 5,
- (182 - (xSize / 2f)) / 256f, (182 - (xSize / 2f) + width) / 256f, 79 / 256f, 84 / 256f, GL11.GL_NEAREST
+ Utils.drawTexturedRect(
+ x + (xSize / 2f),
+ y,
+ width,
+ 5,
+ (182 - (xSize / 2f)) / 256f,
+ (182 - (xSize / 2f) + width) / 256f,
+ 79 / 256f,
+ 84 / 256f,
+ GL11.GL_NEAREST
);
}
}
- private static final ResourceLocation shadowTextures = new ResourceLocation("textures/misc/shadow.png");
-
- public static void drawEntityOnScreen(
- int posX,
- int posY,
- int scale,
- float mouseX,
- float mouseY,
- EntityLivingBase ent
- ) {
- GlStateManager.enableColorMaterial();
- GlStateManager.pushMatrix();
- GlStateManager.translate((float) posX, (float) posY, 50.0F);
- GlStateManager.scale((float) (-scale), (float) scale, (float) scale);
- GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F);
- float renderYawOffset = ent.renderYawOffset;
- float f1 = ent.rotationYaw;
- float f2 = ent.rotationPitch;
- float f3 = ent.prevRotationYawHead;
- float f4 = ent.rotationYawHead;
- GlStateManager.rotate(135.0F, 0.0F, 1.0F, 0.0F);
- RenderHelper.enableStandardItemLighting();
- GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F);
- GlStateManager.rotate(25, 1.0F, 0.0F, 0.0F);
- ent.renderYawOffset = (float) Math.atan(mouseX / 40.0F) * 20.0F;
- ent.rotationYaw = (float) Math.atan(mouseX / 40.0F) * 40.0F;
- ent.rotationPitch = -((float) Math.atan(mouseY / 40.0F)) * 20.0F;
- ent.rotationYawHead = ent.rotationYaw;
- ent.prevRotationYawHead = ent.rotationYaw;
- RenderManager rendermanager = Minecraft.getMinecraft().getRenderManager();
- rendermanager.setPlayerViewY(180.0F);
- rendermanager.setRenderShadow(false);
- rendermanager.renderEntityWithPosYaw(ent, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F);
-
- /*{
- GlStateManager.enableBlend();
- GlStateManager.blendFunc(770, 771);
- rendermanager.renderEngine.bindTexture(shadowTextures);
- GlStateManager.depthMask(false);
- float f = 0.5f;
-
- if (ent instanceof EntityLiving) {
- EntityLiving entityliving = (EntityLiving)ent;
- f *= entityliving.getRenderSizeModifier();
-
- if (entityliving.isChild())
- {
- f *= 0.5F;
- }
- }
-
- /*Tessellator tessellator = Tessellator.getInstance();
- WorldRenderer worldrenderer = tessellator.getWorldRenderer();
- worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX_COLOR);
-
- GlStateManager.color(1, 1, 1, 0.5f);
- Utils.drawTexturedRect(-0.5f*tl.x, -0.5f*tl.x, 1*tl.x, 1*tl.x);
-
- /*for (BlockPos blockpos : BlockPos.getAllInBoxMutable(new BlockPos(i, k, i1), new BlockPos(j, l, j1))) {
- Block block = world.getBlockState(blockpos.down()).getBlock();
-
- if (block.getRenderType() != -1 && world.getLightFromNeighbors(blockpos) > 3) {
- this.func_180549_a(block, x, y, z, blockpos, shadowAlpha, f, d2, d3, d4);
- }
- }
-
- GlStateManager.disableBlend();
- GlStateManager.depthMask(true);
- }*/
-
- ent.renderYawOffset = renderYawOffset;
- ent.rotationYaw = f1;
- ent.rotationPitch = f2;
- ent.prevRotationYawHead = f3;
- ent.rotationYawHead = f4;
- GlStateManager.popMatrix();
- RenderHelper.disableStandardItemLighting();
- GlStateManager.disableRescaleNormal();
- GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
- GlStateManager.disableTexture2D();
- GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
- }
-
public void resetCache() {
- bestWeapons = null;
- bestRods = null;
- armorItems = null;
- inventoryItems = new HashMap<>();
- currentInventoryIndex = 0;
- arrowCount = -1;
- greenCandyCount = -1;
- purpleCandyCount = -1;
- entityPlayer = null;
- playerLocationSkin = null;
- playerLocationCape = null;
- skinType = null;
- petsPage = 0;
- sortedPets = null;
- sortedPetsStack = null;
- selectedPet = -1;
+ pages.values().forEach(GuiProfileViewerPage::resetCache);
}
- Shader blurShaderHorz = null;
- Framebuffer blurOutputHorz = null;
- Shader blurShaderVert = null;
- Framebuffer blurOutputVert = null;
-
/**
* Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate
* space [-1 -> 1; 1 -> -1] (Note: flipped y-axis).
@@ -5036,14 +1170,6 @@ public class GuiProfileViewer extends GuiScreen {
return projMatrix;
}
- /**
- * Renders whatever is currently in the Minecraft framebuffer to our two framebuffers, applying a horizontal
- * and vertical blur separately in order to significantly save computation time.
- * This is only possible if framebuffers are supported by the system, so this method will exit prematurely
- * if framebuffers are not available. (Apple machines, for example, have poor framebuffer support).
- */
- private double lastBgBlurFactor = -1;
-
private void blurBackground() {
if (!OpenGlHelper.isFramebufferEnabled()) return;
@@ -5071,9 +1197,13 @@ public class GuiProfileViewer extends GuiScreen {
if (blurShaderHorz == null) {
try {
- blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
- Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz
- );
+ blurShaderHorz =
+ new Shader(
+ Minecraft.getMinecraft().getResourceManager(),
+ "blur",
+ Minecraft.getMinecraft().getFramebuffer(),
+ blurOutputHorz
+ );
blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0);
blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height));
} catch (Exception ignored) {
@@ -5081,8 +1211,11 @@ public class GuiProfileViewer extends GuiScreen {
}
if (blurShaderVert == null) {
try {
- blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur",
- blurOutputHorz, blurOutputVert
+ blurShaderVert = new Shader(
+ Minecraft.getMinecraft().getResourceManager(),
+ "blur",
+ blurOutputHorz,
+ blurOutputVert
);
blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1);
blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height));
@@ -5124,4 +1257,65 @@ public class GuiProfileViewer extends GuiScreen {
//Utils.setScreen(width, height, f);
blurOutputVert.unbindFramebufferTexture();
}
+
+ public enum ProfileViewerPage {
+ LOADING(),
+ INVALID_NAME(),
+ NO_SKYBLOCK(),
+ BASIC(0, Items.paper, "§9Your Skills"),
+ DUNGEON(1, Item.getItemFromBlock(Blocks.deadbush), "§eDungeoneering"),
+ EXTRA(2, Items.book, "§7Profile Stats"),
+ INVENTORIES(3, Item.getItemFromBlock(Blocks.ender_chest), "§bStorage"),
+ COLLECTIONS(4, Items.painting, "§6Collections"),
+ PETS(5, Items.bone, "§aPets"),
+ MINING(6, Items.iron_pickaxe, "§5Heart of the Mountain"),
+ BINGO(7, Items.filled_map, "§zBingo"),
+ TROPHY_FISH(8, Items.fishing_rod, "§3Trophy Fish"),
+ BESTIARY(9, Items.iron_sword, "§cBestiary");
+
+ public final ItemStack stack;
+ public final int id;
+
+ ProfileViewerPage() {
+ this(-1, null, null);
+ }
+
+ ProfileViewerPage(int id, Item item, String name) {
+ this.id = id;
+ if (item == null) {
+ stack = null;
+ } else {
+ stack = new ItemStack(item);
+ NBTTagCompound nbt = new NBTTagCompound(); //Adding NBT Data for Custom Resource Packs
+ NBTTagCompound display = new NBTTagCompound();
+ display.setString("Name", name);
+ nbt.setTag("display", display);
+ stack.setTagCompound(nbt);
+ }
+ }
+
+ public static ProfileViewerPage getById(int id) {
+ for (ProfileViewerPage page : values()) {
+ if (page.id == id) {
+ return page;
+ }
+ }
+ return null;
+ }
+
+ public Optional<ItemStack> getItem() {
+ return Optional.ofNullable(stack);
+ }
+ }
+
+ public static class PetLevel {
+
+ public float level;
+ public float maxLevel;
+ public float currentLevelRequirement;
+ public float maxXP;
+ public float levelPercentage;
+ public float levelXp;
+ public float totalXp;
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewerPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewerPage.java
new file mode 100644
index 00000000..2c7fd9f4
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/GuiProfileViewerPage.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import java.io.IOException;
+
+public abstract class GuiProfileViewerPage {
+
+ private final GuiProfileViewer instance;
+
+ public GuiProfileViewerPage(GuiProfileViewer instance) {
+ this.instance = instance;
+ }
+
+ /**
+ * @return Instance of the current {@link GuiProfileViewer}
+ */
+ public GuiProfileViewer getInstance() {
+ return instance;
+ }
+
+ public abstract void drawPage(int mouseX, int mouseY, float partialTicks);
+
+ /**
+ * @return Whether to return in calling method
+ */
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ return false;
+ }
+
+ public void mouseReleased(int mouseX, int mouseY, int mouseButton) {}
+
+ public void keyTyped(char typedChar, int keyCode) throws IOException {}
+
+ public void resetCache() {}
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java
new file mode 100644
index 00000000..b4f1da30
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/InventoriesPage.java
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.profileviewer.info.QuiverInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagByteArray;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer.pv_elements;
+
+public class InventoriesPage extends GuiProfileViewerPage {
+
+ public static final ResourceLocation pv_invs = new ResourceLocation("notenoughupdates:pv_invs.png");
+ private static final ResourceLocation CHEST_GUI_TEXTURE =
+ new ResourceLocation("textures/gui/container/generic_54.png");
+ private static final Pattern FISHING_SPEED_PATTERN = Pattern.compile("^Fishing Speed: \\+(\\d+)");
+ private static final LinkedHashMap<String, ItemStack> invNameToDisplayMap = new LinkedHashMap<String, ItemStack>() {
+ {
+ put(
+ "inv_contents",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.chest), EnumChatFormatting.GRAY + "Inventory")
+ );
+ put(
+ "ender_chest_contents",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.ender_chest), EnumChatFormatting.GRAY + "Ender Chest")
+ );
+ // put("backpack_contents", Utils.createItemStack(Item.getItemFromBlock(Blocks.dropper), EnumChatFormatting.GRAY+"Backpacks"));
+ put(
+ "backpack_contents",
+ Utils.editItemStackInfo(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("JUMBO_BACKPACK")
+ ),
+ EnumChatFormatting.GRAY + "Backpacks",
+ true
+ )
+ );
+ put(
+ "personal_vault_contents",
+ Utils.editItemStackInfo(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .get("IRON_CHEST")),
+ EnumChatFormatting.GRAY + "Personal Vault",
+ true
+ )
+ );
+ put("talisman_bag", Utils.createItemStack(Items.golden_apple, EnumChatFormatting.GRAY + "Accessory Bag"));
+ put("wardrobe_contents", Utils.createItemStack(Items.leather_chestplate, EnumChatFormatting.GRAY + "Wardrobe"));
+ put("fishing_bag", Utils.createItemStack(Items.fish, EnumChatFormatting.GRAY + "Fishing Bag"));
+ put("potion_bag", Utils.createItemStack(Items.potionitem, EnumChatFormatting.GRAY + "Potion Bag"));
+ }
+ };
+ private final ItemStack fillerStack = new ItemStack(Item.getItemFromBlock(Blocks.stained_glass_pane), 1, 15);
+ private HashMap<String, ItemStack[][][]> inventoryItems = new HashMap<>();
+
+ private ItemStack[] bestWeapons = null;
+ private ItemStack[] bestRods = null;
+ private ItemStack[] armorItems = null;
+ private ItemStack[] equipmentItems = null;
+ private String selectedInventory = "inv_contents";
+ private int currentInventoryIndex = 0;
+ private int arrowCount = -1;
+ private int greenCandyCount = -1;
+ private int purpleCandyCount = -1;
+
+ public InventoriesPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_invs);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+ getInstance().inventoryTextField.setSize(88, 20);
+
+ ProfileViewer.Profile profile = GuiProfileViewer.getProfile();
+ String profileId = GuiProfileViewer.getProfileId();
+ JsonObject inventoryInfo = profile.getInventoryInfo(profileId);
+ if (inventoryInfo == null) return;
+
+ int invNameIndex = 0;
+ for (Map.Entry<String, ItemStack> entry : invNameToDisplayMap.entrySet()) {
+ int xIndex = invNameIndex % 3;
+ int yIndex = invNameIndex / 3;
+
+ int x = 19 + 34 * xIndex;
+ int y = 26 + 34 * yIndex;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ if (entry.getKey().equals(selectedInventory)) {
+ Utils.drawTexturedRect(guiLeft + x - 2, guiTop + y - 2, 20, 20, 20 / 256f, 0, 20 / 256f, 0, GL11.GL_NEAREST);
+ x++;
+ y++;
+ } else {
+ Utils.drawTexturedRect(guiLeft + x - 2, guiTop + y - 2, 20, 20, 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST);
+ }
+
+ Utils.drawItemStackWithText(entry.getValue(), guiLeft + x, guiTop + y, "" + (invNameIndex + 1), true);
+
+ if (mouseX >= guiLeft + x && mouseX <= guiLeft + x + 16) {
+ if (mouseY >= guiTop + y && mouseY <= guiTop + y + 16) {
+ getInstance().tooltipToDisplay = entry.getValue().getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ if (Objects.equals(entry.getKey(), "talisman_bag")) {
+ StringBuilder magicalPowerString = new StringBuilder(EnumChatFormatting.DARK_GRAY + "Magical Power: ");
+ int magicalPower = PlayerStats.getMagicalPower(inventoryInfo);
+ getInstance()
+ .tooltipToDisplay.add(
+ magicalPower == -1
+ ? magicalPowerString.append(EnumChatFormatting.RED).append("Error while calculating!").toString()
+ : magicalPowerString
+ .append(EnumChatFormatting.GOLD)
+ .append(GuiProfileViewer.numberFormat.format(magicalPower))
+ .toString()
+ );
+
+ StringBuilder selectedPowerString = new StringBuilder(EnumChatFormatting.DARK_GRAY + "Selected Power: ");
+ String selectedPower = PlayerStats.getSelectedMagicalPower(profile.getProfileInformation(profileId));
+ getInstance()
+ .tooltipToDisplay.add(
+ selectedPower == null
+ ? selectedPowerString.append(EnumChatFormatting.RED).append("None!").toString()
+ : selectedPowerString.append(EnumChatFormatting.GREEN).append(selectedPower).toString()
+ );
+ }
+ }
+ }
+
+ invNameIndex++;
+ }
+
+ getInstance().inventoryTextField.render(guiLeft + 19, guiTop + getInstance().sizeY - 26 - 20);
+
+ if (armorItems == null) {
+ armorItems = new ItemStack[4];
+ JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
+ for (int i = 0; i < armor.size(); i++) {
+ if (armor.get(i) == null || !armor.get(i).isJsonObject()) continue;
+ armorItems[i] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(armor.get(i).getAsJsonObject(), false);
+ }
+ }
+
+ for (int i = 0; i < armorItems.length; i++) {
+ ItemStack stack = armorItems[i];
+ if (stack != null) {
+ Utils.drawItemStack(stack, guiLeft + 173, guiTop + 67 - 18 * i, true);
+ if (stack != fillerStack) {
+ if (mouseX >= guiLeft + 173 - 1 && mouseX <= guiLeft + 173 + 16 + 1) {
+ if (mouseY >= guiTop + 67 - 18 * i - 1 && mouseY <= guiTop + 67 - 18 * i + 16 + 1) {
+ getInstance().tooltipToDisplay =
+ stack.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+ }
+ }
+
+ if (equipmentItems == null) {
+ equipmentItems = new ItemStack[4];
+ JsonArray equippment = Utils.getElement(inventoryInfo, "equippment_contents").getAsJsonArray();
+ for (int i = 0; i < equippment.size(); i++) {
+ if (equippment.get(i) == null || !equippment.get(i).isJsonObject()) continue;
+ equipmentItems[i] = NotEnoughUpdates.INSTANCE.manager.jsonToStack(equippment.get(i).getAsJsonObject(), false);
+ }
+ }
+
+ for (int i = 0; i < equipmentItems.length; i++) {
+ ItemStack stack = equipmentItems[i];
+ if (stack != null) {
+ Utils.drawItemStack(stack, guiLeft + 192, guiTop + 13 + 18 * i, true);
+ if (stack != fillerStack) {
+ if (mouseX >= guiLeft + 192 - 1 && mouseX <= guiLeft + 192 + 16 + 1) {
+ if (mouseY >= guiTop + 13 + 18 * i - 1 && mouseY <= guiTop + 13 + 18 * i + 16 + 1) {
+ getInstance().tooltipToDisplay =
+ stack.getTooltip(
+ Minecraft.getMinecraft().thePlayer,
+ Minecraft.getMinecraft().gameSettings.advancedItemTooltips
+ );
+ }
+ }
+ }
+ }
+ }
+
+ ItemStack[][][] inventories = getItemsForInventory(inventoryInfo, selectedInventory);
+ if (currentInventoryIndex >= inventories.length) currentInventoryIndex = inventories.length - 1;
+ if (currentInventoryIndex < 0) currentInventoryIndex = 0;
+
+ ItemStack[][] inventory = inventories[currentInventoryIndex];
+
+ if (bestWeapons == null) {
+ bestWeapons =
+ findBestItems(
+ inventoryInfo,
+ 6,
+ new String[]{"inv_contents", "ender_chest_contents"},
+ new String[]{"SWORD", "BOW"}
+ );
+ }
+ if (bestRods == null) {
+ bestRods = findBestItems(
+ inventoryInfo,
+ 3,
+ new String[]{"inv_contents", "ender_chest_contents"},
+ new String[]{"FISHING ROD", "FISHING WEAPON"},
+ FISHING_SPEED_PATTERN
+ );
+ }
+
+ for (int i = 0; i < bestWeapons.length; i++) {
+ if (bestWeapons[i] == null) continue;
+ ItemStack stack = bestWeapons[i];
+ Utils.drawItemStack(stack, guiLeft + 143, guiTop + 13 + 18 * i, true);
+ if (mouseX >= guiLeft + 143 - 1 && mouseX <= guiLeft + 143 + 16 + 1) {
+ if (mouseY >= guiTop + 13 + 18 * i - 1 && mouseY <= guiTop + 13 + 18 * i + 16 + 1) {
+ getInstance().tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+ }
+ }
+
+ for (int i = 0; i < bestRods.length; i++) {
+ if (bestRods[i] == null) continue;
+ ItemStack stack = bestRods[i];
+ Utils.drawItemStack(stack, guiLeft + 143, guiTop + 137 + 18 * i, true);
+ if (mouseX >= guiLeft + 143 - 1 && mouseX <= guiLeft + 143 + 16 + 1) {
+ if (mouseY >= guiTop + 137 + 18 * i - 1 && mouseY <= guiTop + 137 + 18 * i + 16 + 1) {
+ getInstance().tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+ }
+ }
+
+ if (arrowCount == -1) {
+ arrowCount = countItemsInInventory("ARROW", inventoryInfo, false, "quiver");
+ }
+ if (greenCandyCount == -1) {
+ greenCandyCount = countItemsInInventory("GREEN_CANDY", inventoryInfo, true, "candy_inventory_contents");
+ }
+ if (purpleCandyCount == -1) {
+ purpleCandyCount = countItemsInInventory("PURPLE_CANDY", inventoryInfo, true, "candy_inventory_contents");
+ }
+
+ Utils.drawItemStackWithText(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .get("ARROW")),
+ guiLeft + 173,
+ guiTop + 101,
+ "" + (arrowCount > 999 ? StringUtils.shortNumberFormat(arrowCount) : arrowCount),
+ true
+ );
+ Utils.drawItemStackWithText(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .get("GREEN_CANDY")),
+ guiLeft + 173,
+ guiTop + 119,
+ "" + greenCandyCount,
+ true
+ );
+ Utils.drawItemStackWithText(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .get("PURPLE_CANDY")),
+ guiLeft + 173,
+ guiTop + 137,
+ "" + purpleCandyCount,
+ true
+ );
+ if (mouseX > guiLeft + 173 && mouseX < guiLeft + 173 + 16) {
+ if (mouseY > guiTop + 101 && mouseY < guiTop + 137 + 16) {
+ if (mouseY < guiTop + 101 + 17) {
+ QuiverInfo quiverInfo = PlayerStats.getQuiverInfo(inventoryInfo, profile.getProfileInformation(profileId));
+ if (quiverInfo == null) {
+ getInstance().tooltipToDisplay = Utils.createList(EnumChatFormatting.RED + "Error checking Quiver");
+ } else {
+ getInstance().tooltipToDisplay = quiverInfo.generateProfileViewerTooltip();
+ }
+ } else if (mouseY < guiTop + 119 + 17) {
+ getInstance().tooltipToDisplay =
+ Utils.createList(
+ EnumChatFormatting.GREEN + "Green Candy " + EnumChatFormatting.GRAY + "x" + greenCandyCount);
+ } else {
+ getInstance().tooltipToDisplay =
+ Utils.createList(
+ EnumChatFormatting.DARK_PURPLE + "Purple Candy " + EnumChatFormatting.GRAY + "x" + purpleCandyCount
+ );
+ }
+ }
+ }
+
+ if (inventory == null) {
+ String strToRender = "Inventory API not enabled!";
+ if (selectedInventory.equalsIgnoreCase("personal_vault_contents")) {
+ strToRender = "Personal Vault API not enabled!";
+ } else if (selectedInventory.equalsIgnoreCase("backpack_contents")) {
+ strToRender = "Inventory API not enabled";
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "Or has no backpacks!",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 317,
+ guiTop + 112,
+ true,
+ 0
+ );
+ }
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + strToRender,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 317,
+ guiTop + 101,
+ true,
+ 0
+ );
+ return;
+ }
+
+ int inventoryRows = inventory.length;
+
+ GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
+
+ int invSizeY = inventoryRows * 18 + 17 + 7;
+
+ int x = guiLeft + 320 - 176 / 2;
+ int y = guiTop + 101 - invSizeY / 2;
+ int staticSelectorHeight = guiTop + 177;
+
+ getInstance().drawTexturedModalRect(x, y, 0, 0, 176, inventoryRows * 18 + 17);
+ getInstance().drawTexturedModalRect(x, y + inventoryRows * 18 + 17, 0, 215, 176, 7);
+
+ boolean leftHovered = false;
+ boolean rightHovered = false;
+ if (Mouse.isButtonDown(0)) {
+ if (mouseY > staticSelectorHeight && mouseY < staticSelectorHeight + 16) {
+ if (mouseX > guiLeft + 320 - 12 && mouseX < guiLeft + 320 + 12) {
+ if (mouseX < guiLeft + 320) {
+ leftHovered = true;
+ } else {
+ rightHovered = true;
+ }
+ }
+ }
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.resource_packs);
+
+ if (currentInventoryIndex > 0) {
+ Utils.drawTexturedRect(
+ guiLeft + 320 - 12,
+ staticSelectorHeight,
+ 12,
+ 16,
+ 29 / 256f,
+ 53 / 256f,
+ !leftHovered ? 0 : 32 / 256f,
+ !leftHovered ? 32 / 256f : 64 / 256f,
+ GL11.GL_NEAREST
+ );
+ }
+ if (currentInventoryIndex < inventories.length - 1) {
+ Utils.drawTexturedRect(
+ guiLeft + 320,
+ staticSelectorHeight,
+ 12,
+ 16,
+ 5 / 256f,
+ 29 / 256f,
+ !rightHovered ? 0 : 32 / 256f,
+ !rightHovered ? 32 / 256f : 64 / 256f,
+ GL11.GL_NEAREST
+ );
+ }
+
+ Minecraft
+ .getMinecraft()
+ .fontRendererObj.drawString(
+ Utils.cleanColour(invNameToDisplayMap.get(selectedInventory).getDisplayName()),
+ x + 8,
+ y + 6,
+ 4210752
+ );
+
+ ItemStack stackToRender = null;
+ int overlay = new Color(0, 0, 0, 100).getRGB();
+ for (int yIndex = 0; yIndex < inventory.length; yIndex++) {
+ if (inventory[yIndex] == null) continue;
+
+ for (int xIndex = 0; xIndex < inventory[yIndex].length; xIndex++) {
+ ItemStack stack = inventory[yIndex][xIndex];
+
+ if (stack != null) Utils.drawItemStack(stack, x + 8 + xIndex * 18, y + 18 + yIndex * 18, true);
+
+ if (
+ getInstance().inventoryTextField.getText() != null &&
+ !getInstance().inventoryTextField.getText().isEmpty() &&
+ (
+ stack == null ||
+ !NotEnoughUpdates.INSTANCE.manager.doesStackMatchSearch(
+ stack,
+ getInstance().inventoryTextField.getText()
+ )
+ )
+ ) {
+ GlStateManager.translate(0, 0, 50);
+ GuiScreen.drawRect(
+ x + 8 + xIndex * 18,
+ y + 18 + yIndex * 18,
+ x + 8 + xIndex * 18 + 16,
+ y + 18 + yIndex * 18 + 16,
+ overlay
+ );
+ GlStateManager.translate(0, 0, -50);
+ }
+
+ if (stack == null || stack == fillerStack) continue;
+
+ if (mouseX >= x + 8 + xIndex * 18 && mouseX <= x + 8 + xIndex * 18 + 16) {
+ if (mouseY >= y + 18 + yIndex * 18 && mouseY <= y + 18 + yIndex * 18 + 16) {
+ stackToRender = stack;
+ }
+ }
+ }
+ }
+ if (stackToRender != null) {
+ getInstance().tooltipToDisplay = stackToRender.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+ }
+
+ @Override
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ getInstance().inventoryTextField.setSize(88, 20);
+ if (mouseX > guiLeft + 19 && mouseX < guiLeft + 19 + 88) {
+ if (mouseY > guiTop + getInstance().sizeY - 26 - 20 && mouseY < guiTop + getInstance().sizeY - 26) {
+ getInstance().inventoryTextField.mouseClicked(mouseX, mouseY, mouseButton);
+ getInstance().playerNameTextField.otherComponentClick();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void mouseReleased(int mouseX, int mouseY, int mouseButton) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ if (mouseButton == 0) {
+ int i = 0;
+ for (Map.Entry<String, ItemStack> entry : invNameToDisplayMap.entrySet()) {
+ int xIndex = i % 3;
+ int yIndex = i / 3;
+
+ int x = guiLeft + 19 + 34 * xIndex;
+ int y = guiTop + 26 + 34 * yIndex;
+
+ if (mouseX >= x && mouseX <= x + 16) {
+ if (mouseY >= y && mouseY <= y + 16) {
+ if (!selectedInventory.equals(entry.getKey())) Utils.playPressSound();
+ selectedInventory = entry.getKey();
+ return;
+ }
+ }
+
+ i++;
+ }
+
+ JsonObject inventoryInfo = GuiProfileViewer.getProfile().getInventoryInfo(GuiProfileViewer.getProfileId());
+ if (inventoryInfo == null) return;
+
+ ItemStack[][][] inventories = getItemsForInventory(inventoryInfo, selectedInventory);
+ if (currentInventoryIndex >= inventories.length) currentInventoryIndex = inventories.length - 1;
+ if (currentInventoryIndex < 0) currentInventoryIndex = 0;
+
+ ItemStack[][] inventory = inventories[currentInventoryIndex];
+ if (inventory == null) return;
+
+ int inventoryRows = inventory.length;
+
+ int staticSelectorHeight = guiTop + 177;
+
+ if (mouseY > staticSelectorHeight && mouseY < staticSelectorHeight + 16) {
+ if (mouseX > guiLeft + 320 - 12 && mouseX < guiLeft + 320 + 12) {
+ if (mouseX < guiLeft + 320) {
+ currentInventoryIndex--;
+ } else {
+ currentInventoryIndex++;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void keyTyped(char typedChar, int keyCode) throws IOException {
+ switch (keyCode) {
+ case Keyboard.KEY_1:
+ case Keyboard.KEY_NUMPAD1:
+ selectedInventory = "inv_contents";
+ break;
+ case Keyboard.KEY_2:
+ case Keyboard.KEY_NUMPAD2:
+ selectedInventory = "ender_chest_contents";
+ break;
+ case Keyboard.KEY_3:
+ case Keyboard.KEY_NUMPAD3:
+ selectedInventory = "backpack_contents";
+ break;
+ case Keyboard.KEY_4:
+ case Keyboard.KEY_NUMPAD4:
+ selectedInventory = "personal_vault_contents";
+ break;
+ case Keyboard.KEY_5:
+ case Keyboard.KEY_NUMPAD5:
+ selectedInventory = "talisman_bag";
+ break;
+ case Keyboard.KEY_6:
+ case Keyboard.KEY_NUMPAD6:
+ selectedInventory = "wardrobe_contents";
+ break;
+ case Keyboard.KEY_7:
+ case Keyboard.KEY_NUMPAD7:
+ selectedInventory = "fishing_bag";
+ break;
+ case Keyboard.KEY_8:
+ case Keyboard.KEY_NUMPAD8:
+ selectedInventory = "potion_bag";
+ break;
+ default:
+ getInstance().inventoryTextField.keyTyped(typedChar, keyCode);
+ return;
+ }
+ Utils.playPressSound();
+ getInstance().inventoryTextField.keyTyped(typedChar, keyCode);
+ }
+
+ @Override
+ public void resetCache() {
+ inventoryItems = new HashMap<>();
+ bestWeapons = null;
+ bestRods = null;
+ armorItems = null;
+ equipmentItems = null;
+ currentInventoryIndex = 0;
+ arrowCount = -1;
+ greenCandyCount = -1;
+ purpleCandyCount = -1;
+ }
+
+ private int countItemsInInventory(
+ String internalname,
+ JsonObject inventoryInfo,
+ boolean specific,
+ String... invsToSearch
+ ) {
+ int count = 0;
+ for (String inv : invsToSearch) {
+ JsonArray invItems = inventoryInfo.get(inv).getAsJsonArray();
+ for (int i = 0; i < invItems.size(); i++) {
+ if (invItems.get(i) == null || !invItems.get(i).isJsonObject()) continue;
+ JsonObject item = invItems.get(i).getAsJsonObject();
+ if (
+ (specific && item.get("internalname").getAsString().equals(internalname)) ||
+ (!specific && item.get("internalname").getAsString().contains(internalname))
+ ) {
+ if (item.has("count")) {
+ count += item.get("count").getAsInt();
+ } else {
+ count += 1;
+ }
+ }
+ }
+ }
+ return count;
+ }
+
+ private ItemStack[] findBestItems(
+ JsonObject inventoryInfo,
+ int numItems,
+ String[] invsToSearch,
+ String[] typeMatches,
+ Pattern... importantPatterns
+ ) {
+ ItemStack[] bestItems = new ItemStack[numItems];
+ TreeMap<Long, Set<ItemStack>> map = new TreeMap<>();
+ for (String inv : invsToSearch) {
+ JsonArray invItems = inventoryInfo.get(inv).getAsJsonArray();
+ for (int i = 0; i < invItems.size(); i++) {
+ if (invItems.get(i) == null || !invItems.get(i).isJsonObject()) continue;
+ JsonObject item = invItems.get(i).getAsJsonObject();
+ JsonArray lore = item.get("lore").getAsJsonArray();
+ if (Utils.checkItemType(lore, true, typeMatches) >= 0) {
+ long importance = 0;
+ int id = 0;
+ if (importantPatterns.length == 0) {
+ String internalName = item.get("internalname").getAsString();
+ importance += NotEnoughUpdates.INSTANCE.manager.auctionManager.getLowestBin(internalName);
+ importance += ++id;
+ } else {
+ for (int j = 0; j < lore.size(); j++) {
+ String line = lore.get(j).getAsString();
+ for (Pattern pattern : importantPatterns) {
+ Matcher matcher = pattern.matcher(Utils.cleanColour(line));
+ if (matcher.find()) {
+ importance += Integer.parseInt(matcher.group(1));
+ }
+ }
+ }
+ }
+ map.computeIfAbsent(importance, k -> new HashSet<>()).add(NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ item,
+ false
+ ));
+ }
+ }
+ }
+ int i = 0;
+ outer:
+ for (long key : map.descendingKeySet()) {
+ Set<ItemStack> items = map.get(key);
+ for (ItemStack item : items) {
+ bestItems[i] = item;
+ if (++i >= bestItems.length) break outer;
+ }
+ }
+
+ return bestItems;
+ }
+
+ private ItemStack[][][] getItemsForInventory(JsonObject inventoryInfo, String invName) {
+ if (inventoryItems.containsKey(invName)) return inventoryItems.get(invName);
+
+ JsonArray jsonInv = Utils.getElement(inventoryInfo, invName).getAsJsonArray();
+
+ if (jsonInv.size() == 0) return new ItemStack[1][][];
+
+ int jsonInvSize;
+ if (useActualMax(invName)) {
+ jsonInvSize = (int) Math.ceil(jsonInv.size() / 9f) * 9;
+ } else {
+ jsonInvSize = 9 * 4;
+ float divideBy = 9f;
+ if (invName.equals("wardrobe_contents")) {
+ divideBy = 36f;
+ }
+ for (int i = 9 * 4; i < jsonInv.size(); i++) {
+ JsonElement item = jsonInv.get(i);
+ if (item != null && item.isJsonObject()) {
+ jsonInvSize = (int) (Math.ceil((i + 1) / divideBy) * (int) divideBy);
+ }
+ }
+ }
+
+ int rowSize = 9;
+ int rows = jsonInvSize / rowSize;
+ int maxRowsPerPage = getRowsForInventory(invName);
+ int maxInvSize = rowSize * maxRowsPerPage;
+
+ int numInventories = (jsonInvSize - 1) / maxInvSize + 1;
+ JsonArray backPackSizes = (JsonArray) inventoryInfo.get("backpack_sizes");
+ if (invName.equals("backpack_contents")) {
+ numInventories = backPackSizes.size();
+ }
+
+ ItemStack[][][] inventories = new ItemStack[numInventories][][];
+
+ //int availableSlots = getAvailableSlotsForInventory(inventoryInfo, collectionInfo, invName);
+ int startNumberJ = 0;
+
+ for (int i = 0; i < numInventories; i++) {
+ int thisRows = Math.min(maxRowsPerPage, rows - maxRowsPerPage * i);
+ int invSize;
+
+ if (invName.equals("backpack_contents")) {
+ thisRows = backPackSizes.get(i).getAsInt() / 9;
+ invSize = startNumberJ + (thisRows * 9);
+ maxInvSize = thisRows * 9;
+ } else {
+ startNumberJ = maxInvSize * i;
+ invSize = Math.min(jsonInvSize, maxInvSize + maxInvSize * i);
+ }
+ if (thisRows <= 0) break;
+
+ ItemStack[][] items = new ItemStack[thisRows][rowSize];
+
+ for (int j = startNumberJ; j < invSize; j++) {
+ int xIndex = (j % maxInvSize) % rowSize;
+ int yIndex = (j % maxInvSize) / rowSize;
+ if (invName.equals("inv_contents")) {
+ yIndex--;
+ if (yIndex < 0) yIndex = rows - 1;
+ }
+ if (yIndex >= thisRows) {
+ break;
+ }
+
+ if (j >= jsonInv.size()) {
+ items[yIndex][xIndex] = fillerStack;
+ continue;
+ }
+ if (jsonInv.get(j) == null || !jsonInv.get(j).isJsonObject()) {
+ continue;
+ }
+
+ JsonObject item = jsonInv.get(j).getAsJsonObject();
+ ItemStack stack = NotEnoughUpdates.INSTANCE.manager.jsonToStack(item, false);
+ if (item.has("item_contents")) {
+ JsonArray bytesArr = item.get("item_contents").getAsJsonArray();
+ byte[] bytes = new byte[bytesArr.size()];
+ for (int bytesArrI = 0; bytesArrI < bytesArr.size(); bytesArrI++) {
+ bytes[bytesArrI] = bytesArr.get(bytesArrI).getAsByte();
+ }
+ //byte[] bytes2 = null;
+ NBTTagCompound tag = stack.getTagCompound();
+ if (tag != null && tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ for (String key : ea.getKeySet()) {
+ if (key.endsWith("backpack_data") || key.equals("new_year_cake_bag_data")) {
+ ea.setTag(key, new NBTTagByteArray(bytes));
+ break;
+ }
+ }
+ tag.setTag("ExtraAttributes", ea);
+ stack.setTagCompound(tag);
+ }
+ }
+
+ items[yIndex][xIndex] = stack;
+ }
+ inventories[i] = items;
+ if (invName.equals("backpack_contents")) {
+ startNumberJ = startNumberJ + backPackSizes.get(i).getAsInt();
+ }
+ }
+
+ inventoryItems.put(invName, inventories);
+ return inventories;
+ }
+
+ private boolean useActualMax(String invName) {
+ switch (invName) {
+ case "talisman_bag":
+ case "fishing_bag":
+ case "potion_bag":
+ case "personal_vault_contents":
+ return true;
+ }
+ return false;
+ }
+
+ private int getRowsForInventory(String invName) {
+ switch (invName) {
+ case "wardrobe_contents":
+ return 4;
+ case "backpack_contents":
+ case "ender_chest_contents":
+ return 5;
+ default:
+ return 6;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MiningPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MiningPage.java
new file mode 100644
index 00000000..d3b43e20
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/MiningPage.java
@@ -0,0 +1,1534 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.common.collect.Lists;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.function.Supplier;
+
+public class MiningPage extends GuiProfileViewerPage {
+
+ public static final ResourceLocation pv_mining = new ResourceLocation("notenoughupdates:pv_mining.png");
+ private static final ItemStack iron_pick = new ItemStack(Items.iron_pickaxe);
+ private final HashMap<String, ProfileViewer.Level> levelObjhotms = new HashMap<>();
+
+ public MiningPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_mining);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+
+ ProfileViewer.Profile profile = GuiProfileViewer.getProfile();
+ String profileId = GuiProfileViewer.getProfileId();
+ JsonObject profileInfo = profile.getProfileInformation(profileId);
+ if (profileInfo == null) return;
+
+ float xStart = 22;
+ float yStartTop = 27;
+
+ int x = guiLeft + 23;
+ int y = guiTop + 25;
+ int sectionWidth = 110;
+ JsonObject leveling = Constants.LEVELING;
+ ProfileViewer.Level levelObjhotm = levelObjhotms.get(profileId);
+ if (levelObjhotm == null) {
+ float hotmXp = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.experience"), 0);
+ levelObjhotm =
+ ProfileViewer.getLevel(
+ Utils.getElementOrDefault(leveling, "HOTM", new JsonArray()).getAsJsonArray(),
+ hotmXp,
+ 7,
+ false
+ );
+ levelObjhotms.put(profileId, levelObjhotm);
+ }
+
+ String skillName = EnumChatFormatting.RED + "HOTM";
+ //The stats that show
+ float mithrilPowder = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.powder_mithril"), 0);
+ float gemstonePowder = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.powder_gemstone"), 0);
+ float mithrilPowderTotal = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "mining_core.powder_spent_mithril"
+ ), 0);
+ float gemstonePowderTotal = (Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "mining_core.powder_spent_gemstone"
+ ), 0));
+ String jadeCrystal =
+ (Utils.getElementAsString(Utils.getElement(profileInfo, "mining_core.crystals.jade_crystal.state"), "Not Found"));
+ float crystalPlacedAmount =
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.crystals.jade_crystal.total_placed"), 0));
+ String jadeCrystalString = "§c✖";
+ String amethystCrystal =
+ (Utils.getElementAsString(
+ Utils.getElement(profileInfo, "mining_core.crystals.amethyst_crystal.state"),
+ "Not Found"
+ ));
+ String amethystCrystalString = "§c✖";
+ String amberCrystal =
+ (Utils.getElementAsString(
+ Utils.getElement(profileInfo, "mining_core.crystals.amber_crystal.state"),
+ "Not Found"
+ ));
+ String amberCrystalString = "§c✖";
+ String sapphireCrystal =
+ (Utils.getElementAsString(
+ Utils.getElement(profileInfo, "mining_core.crystals.sapphire_crystal.state"),
+ "Not Found"
+ ));
+ String sapphireCrystalString = "§c✖";
+ String topazCrystal =
+ (Utils.getElementAsString(
+ Utils.getElement(profileInfo, "mining_core.crystals.topaz_crystal.state"),
+ "Not Found"
+ ));
+ String topazCrystalString = "§c✖";
+ String jasperCrystal =
+ (Utils.getElementAsString(
+ Utils.getElement(profileInfo, "mining_core.crystals.jasper_crystal.state"),
+ "Not Found"
+ ));
+ String jasperCrystalString = "§c✖";
+ String rubyCrystal =
+ (Utils.getElementAsString(Utils.getElement(profileInfo, "mining_core.crystals.ruby_crystal.state"), "Not Found"));
+ String rubyCrystalString = "§c✖";
+ int miningFortune = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune"), 0)));
+ int miningFortuneStat = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune"),
+ 0
+ )) * 5);
+ int miningSpeed = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed"), 0)));
+ int miningSpeedStat = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed"), 0)) *
+ 20);
+ int dailyPowder = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.daily_powder"), 0)));
+ int dailyPowderStat = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.daily_powder"), 0)) *
+ 36 + 364);
+ int effMiner = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.efficient_miner"), 0)));
+ float effMinerStat = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.efficient_miner"), 0)) * 0.4 + 10.4
+ );
+ float effMinerStat2 = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.efficient_miner"), 0)) * .06 + 0.31
+ );
+ int tittyInsane = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.titanium_insanium"),
+ 0
+ )));
+ float tittyInsaneStat = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.titanium_insanium"), 0)) * .1 + 2
+ );
+ int luckofcave = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.random_event"), 0)));
+ int luckofcaveStat = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.random_event"), 0)));
+ int madMining = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_madness"), 0)));
+ int skyMall = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.daily_effect"), 0)));
+ int goblinKiller = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.goblin_killer"), 0)));
+ int seasonMine = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_experience"), 0)));
+ float seasonMineStat = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.mining_experience"), 0)) * 0.1 + 5
+ );
+ int quickForge = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.forge_time"), 0)));
+ float quickForgeStat = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.forge_time"), 0)) * .5 + 10
+ );
+ int frontLoad = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.front_loaded"), 0)));
+ int orbit = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.experience_orbs"), 0)));
+ float orbitStat = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.experience_orbs"), 0)) * .01 + 0.2
+ );
+ int crystallized = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.fallen_star_bonus"),
+ 0
+ )));
+ int crystallizedStat = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.fallen_star_bonus"),
+ 0
+ )) * 6 + 14);
+ int professional = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.professional"), 0)));
+ int professionalStat = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.professional"),
+ 0
+ )) * 5 + 50);
+ int greatExplorer = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.great_explorer"), 0)));
+ int greatExplorerStat = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.great_explorer"),
+ 0
+ )) * 4 + 16);
+ int fortunate = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.fortunate"), 0)));
+ int fortunateStat = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.fortunate"), 0)) * 4 +
+ 20);
+ int lonesomeMiner = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.lonesome_miner"), 0)));
+ float lonesomeMinerStat = (float) (
+ (Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.lonesome_miner"), 0)) * .5 + 5
+ );
+ int miningFortune2 = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.mining_fortune_2"),
+ 0
+ )));
+ int miningFortune2Stat = ((Utils.getElementAsInt(Utils.getElement(
+ profileInfo,
+ "mining_core.nodes.mining_fortune_2"
+ ), 0)) * 5);
+ int miningSpeed2 = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mining_speed_2"), 0)));
+ int miningSpeed2Stat = ((Utils.getElementAsInt(
+ Utils.getElement(profileInfo, "mining_core.nodes.mining_speed_2"),
+ 0
+ )) * 40);
+ int miningSpeedBoost = ((Utils.getElementAsInt(Utils.getElement(
+ profileInfo,
+ "mining_core.nodes.mining_speed_boost"
+ ), 0)));
+ int veinSeeker = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.vein_seeker"), 0)));
+ int powderBuff = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.powder_buff"), 0)));
+ int potm = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.special_0"), 0)));
+ int fortnite = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.precision_mining"), 0)));
+ int starPowder = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.star_powder"), 0)));
+ int pickoblus = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.pickaxe_toss"), 0)));
+ int maniacMiner = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.maniac_miner"), 0)));
+
+ if (effMinerStat2 < 1) {
+ effMinerStat2 = 1;
+ }
+ int mole = ((Utils.getElementAsInt(Utils.getElement(profileInfo, "mining_core.nodes.mole"), 0)));
+ float moleStat = (float) ((Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.nodes.mole"), 0)) *
+ 0.051);
+ double moleperkstat = (double) mole / 20 - 0.55 + 50;
+ double moleperkstat2 = (double) Math.round(moleperkstat * 100) / 100;
+
+ float output = Math.round((float) (moleperkstat2 % 1) * 100);
+ if (output == 0) {
+ output = 100;
+ }
+
+ //The logic for some of the stats
+ if (Objects.equals(jadeCrystal, "NOT_FOUND")) {
+ jadeCrystalString = "§c✖";
+ } else if (Objects.equals(jadeCrystal, "FOUND")) {
+ jadeCrystalString = "§a✔";
+ }
+ if (Objects.equals(amethystCrystal, "NOT_FOUND")) {
+ amethystCrystalString = "§c✖";
+ } else if (Objects.equals(amethystCrystal, "FOUND")) {
+ amethystCrystalString = "§a✔";
+ }
+ if (Objects.equals(amberCrystal, "NOT_FOUND")) {
+ amberCrystalString = "§c✖";
+ } else if (Objects.equals(amberCrystal, "FOUND")) {
+ amberCrystalString = "§a✔";
+ }
+ if (Objects.equals(sapphireCrystal, "NOT_FOUND")) {
+ sapphireCrystalString = "§c✖";
+ } else if (Objects.equals(sapphireCrystal, "FOUND")) {
+ sapphireCrystalString = "§a✔";
+ }
+ if (Objects.equals(topazCrystal, "NOT_FOUND")) {
+ topazCrystalString = "§c✖";
+ } else if (Objects.equals(topazCrystal, "FOUND")) {
+ topazCrystalString = "§a✔";
+ }
+ if (Objects.equals(jasperCrystal, "NOT_FOUND")) {
+ jasperCrystalString = "§c✖";
+ } else if (Objects.equals(jasperCrystal, "FOUND")) {
+ jasperCrystalString = "§a✔";
+ }
+ if (Objects.equals(rubyCrystal, "NOT_FOUND")) {
+ rubyCrystalString = "§c✖";
+ } else if (Objects.equals(rubyCrystal, "FOUND")) {
+ rubyCrystalString = "§a✔";
+ }
+
+ //The rendering of the stats
+ //hotm level
+ getInstance().renderXpBar(skillName, iron_pick, x, y, sectionWidth, levelObjhotm, mouseX, mouseY);
+ //Powder
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_GREEN + "Mithril Powder",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(mithrilPowder),
+ guiLeft + xStart,
+ guiTop + yStartTop + 24,
+ 115
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.LIGHT_PURPLE + "Gemstone Powder",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(gemstonePowder),
+ guiLeft + xStart,
+ guiTop + yStartTop + 44,
+ 115
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_GREEN + "Total Mithril Powder",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(mithrilPowderTotal + mithrilPowder),
+ guiLeft + xStart,
+ guiTop + yStartTop + 34,
+ 115
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.LIGHT_PURPLE + "Total Gemstone Powder",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(gemstonePowderTotal + gemstonePowder),
+ guiLeft + xStart,
+ guiTop + yStartTop + 54,
+ 115
+ );
+ //Crystals
+ Utils.renderAlignedString(
+ EnumChatFormatting.GREEN + "Jade Crystal:",
+ EnumChatFormatting.WHITE + jadeCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 74,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.GOLD + "Amber Crystal:",
+ EnumChatFormatting.WHITE + amberCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 84,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.DARK_PURPLE + "Amethyst Crystal:",
+ EnumChatFormatting.WHITE + amethystCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 94,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.AQUA + "Sapphire Crystal:",
+ EnumChatFormatting.WHITE + sapphireCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 104,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Topaz Crystal:",
+ EnumChatFormatting.WHITE + topazCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 114,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.LIGHT_PURPLE + "Jasper Crystal:",
+ EnumChatFormatting.WHITE + jasperCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 124,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + "Ruby Crystal:",
+ EnumChatFormatting.WHITE + rubyCrystalString,
+ guiLeft + xStart,
+ guiTop + yStartTop + 134,
+ 110
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.BLUE + "Total Placed Crystals:",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(crystalPlacedAmount),
+ guiLeft + xStart,
+ guiTop + yStartTop + 149,
+ 110
+ );
+
+ //hotm render
+ //Pain
+
+ renderHotmPerk(
+ miningSpeed,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop + 138),
+ mouseX,
+ mouseY,
+ () ->
+ miningSpeed != 50 && miningSpeed != 0
+ ? Lists.newArrayList(
+ "Mining Speed",
+ EnumChatFormatting.GRAY + "Level " + miningSpeed + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY +
+ "Grants " +
+ EnumChatFormatting.GREEN +
+ "+" +
+ miningSpeedStat +
+ EnumChatFormatting.GOLD +
+ " ⸕ Mining",
+ EnumChatFormatting.GOLD + "Speed" + EnumChatFormatting.GRAY + ".",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format(Math.pow(miningSpeed + 2, 3)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Mining Speed",
+ EnumChatFormatting.GRAY + "Level " + miningSpeed + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY +
+ "Grants " +
+ EnumChatFormatting.GREEN +
+ "+" +
+ miningSpeedStat +
+ EnumChatFormatting.GOLD +
+ " ⸕ Mining",
+ EnumChatFormatting.GOLD + "Speed" + EnumChatFormatting.GRAY + "."
+ ),
+ 50
+ );
+
+ renderHotmPerk(
+ miningFortune,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop + 114),
+ mouseX,
+ mouseY,
+ () ->
+ miningFortune != 0 && miningFortune != 50
+ ? Lists.newArrayList(
+ "Mining Fortune",
+ EnumChatFormatting.GRAY + "Level " + miningFortune + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY +
+ "Grants " +
+ EnumChatFormatting.GREEN +
+ "+" +
+ miningFortuneStat +
+ EnumChatFormatting.GOLD +
+ " ☘ Mining",
+ EnumChatFormatting.GOLD + "Fortune" + EnumChatFormatting.GRAY + ".",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format(Math.pow(miningFortune + 2, 3)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Mining Fortune",
+ EnumChatFormatting.GRAY + "Level " + miningFortune + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY +
+ "Grants " +
+ EnumChatFormatting.GREEN +
+ "+" +
+ miningFortuneStat +
+ EnumChatFormatting.GOLD +
+ " ☘ Mining",
+ EnumChatFormatting.GOLD + "Fortune" + EnumChatFormatting.GRAY + "."
+ ),
+ 50
+ );
+
+ renderHotmPerk(
+ tittyInsane,
+ (int) (guiLeft + xStart + 231),
+ (int) (guiTop + yStartTop + 114),
+ mouseX,
+ mouseY,
+ () ->
+ tittyInsane != 0 && tittyInsane != 50
+ ? Lists.newArrayList(
+ "Titanium Insanium",
+ EnumChatFormatting.GRAY + "Level " + tittyInsane + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY + "When mining Mithril Ore, you",
+ EnumChatFormatting.GRAY +
+ "have a " +
+ EnumChatFormatting.GREEN +
+ tittyInsaneStat +
+ "% " +
+ EnumChatFormatting.GRAY +
+ "chance to",
+ EnumChatFormatting.GRAY + "convert the block into Titanium",
+ EnumChatFormatting.GRAY + "Ore.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(tittyInsane + 2, 3)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Titanium Insanium",
+ EnumChatFormatting.GRAY + "Level " + tittyInsane + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY + "When mining Mithril Ore, you",
+ EnumChatFormatting.GRAY +
+ "have a " +
+ EnumChatFormatting.GREEN +
+ tittyInsaneStat +
+ "% " +
+ EnumChatFormatting.GRAY +
+ "chance to",
+ EnumChatFormatting.GRAY + "convert the block into Titanium",
+ EnumChatFormatting.GRAY + "Ore."
+ ),
+ 50
+ );
+
+ renderPickaxeAbility(
+ miningSpeedBoost,
+ (int) (guiLeft + xStart + 207),
+ (int) (guiTop + yStartTop + 114),
+ mouseX,
+ mouseY,
+ () ->
+ potm == 0
+ ? Lists.newArrayList( // Peak of the mountain == 0
+ "Mining Speed Boost",
+ "",
+ EnumChatFormatting.GRAY + "Pickaxe Ability: Mining Speed Boost",
+ EnumChatFormatting.GRAY + "Grants " + EnumChatFormatting.GREEN + "200% " + EnumChatFormatting.GOLD +
+ "⸕ Mining",
+ EnumChatFormatting.GOLD +
+ "Speed " +
+ EnumChatFormatting.GRAY +
+ "for " +
+ EnumChatFormatting.GREEN +
+ "15s" +
+ EnumChatFormatting.GRAY,
+ EnumChatFormatting.DARK_GRAY + "Cooldown: " + EnumChatFormatting.GREEN + "120s"
+ )
+ : Lists.newArrayList( // Peak of the mountain > 0
+ "Mining Speed Boost",
+ "",
+ EnumChatFormatting.GRAY + "Pickaxe Ability: Mining Speed Boost",
+ EnumChatFormatting.GRAY + "Grants " + EnumChatFormatting.GREEN + "300% " + EnumChatFormatting.GOLD +
+ "⸕ Mining",
+ EnumChatFormatting.GOLD +
+ "Speed " +
+ EnumChatFormatting.GRAY +
+ "for " +
+ EnumChatFormatting.GREEN +
+ "20s" +
+ EnumChatFormatting.GRAY,
+ EnumChatFormatting.DARK_GRAY + "Cooldown: " + EnumChatFormatting.GREEN + "120s"
+ )
+ );
+
+ renderPickaxeAbility(
+ veinSeeker,
+ (int) (guiLeft + xStart + 183),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Vein Seeker",
+ "",
+ "§6Pickaxe Ability: Vein Seeker",
+ "§7Points in the direction of the",
+ "§7nearest vein and grants §a+§a3§7",
+ "§7§6Mining Spread §7for §a14s§7§7.",
+ "§8Cooldown: §a60s"
+ )
+ );
+
+ renderHotmPerk(
+ luckofcave,
+ (int) (guiLeft + xStart + 207),
+ (int) (guiTop + yStartTop + 90),
+ mouseX,
+ mouseY,
+ () ->
+ luckofcave != 0 && luckofcave != 45
+ ? Lists.newArrayList(
+ "Luck of the Cave",
+ "§7Level " + luckofcave + EnumChatFormatting.DARK_GRAY + "/45",
+ "",
+ "§7Increases the chance for you to",
+ "§7trigger rare occurrences im",
+ "§2Dwarven Mines " + EnumChatFormatting.GRAY + "by " + EnumChatFormatting.GREEN + luckofcaveStat + "%§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(luckofcave + 2, 3.07)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Luck of the Cave",
+ "§7Level " + luckofcave + EnumChatFormatting.DARK_GRAY + "/45",
+ "",
+ "§7Increases the chance for you to",
+ "§7trigger rare occurrences im",
+ "§2Dwarven Mines " + EnumChatFormatting.GRAY + "by " + EnumChatFormatting.GREEN + luckofcaveStat + "%§7."
+ ),
+ 45
+ );
+
+ renderHotmPerk(
+ dailyPowder,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop + 90),
+ mouseX,
+ mouseY,
+ () ->
+ dailyPowder != 0 && dailyPowder != 100
+ ? Lists.newArrayList(
+ "Daily Powder",
+ EnumChatFormatting.GRAY + "Level " + dailyPowder + EnumChatFormatting.DARK_GRAY + "/100",
+ "",
+ EnumChatFormatting.GRAY +
+ "Gains " +
+ EnumChatFormatting.GREEN +
+ dailyPowderStat +
+ " Powder" +
+ EnumChatFormatting.GRAY +
+ " from the",
+ EnumChatFormatting.GRAY + "first ore you mine every day.",
+ EnumChatFormatting.GRAY + "Works for all Powder types.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "" + (200 + ((dailyPowder) * 18)) + " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Daily Powder",
+ EnumChatFormatting.GRAY + "Level " + dailyPowder + EnumChatFormatting.DARK_GRAY + "/100",
+ "",
+ EnumChatFormatting.GRAY +
+ "Gains " +
+ EnumChatFormatting.GREEN +
+ dailyPowderStat +
+ " Powder" +
+ EnumChatFormatting.GRAY +
+ " from the",
+ EnumChatFormatting.GRAY + "first ore you mine every day.",
+ EnumChatFormatting.GRAY + "Works for all Powder types."
+ ),
+ 100
+ );
+
+ float finalEffMinerStat2 = effMinerStat2;
+ renderHotmPerk(
+ effMiner,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () ->
+ effMiner != 0 && effMiner != 100
+ ? Lists.newArrayList(
+ "Efficient Miner",
+ EnumChatFormatting.GRAY + "Level " + effMiner + EnumChatFormatting.DARK_GRAY + "/100",
+ "",
+ EnumChatFormatting.GRAY + "When mining ores, you have a",
+ EnumChatFormatting.GREEN +
+ "" +
+ effMinerStat +
+ "%" +
+ EnumChatFormatting.GRAY +
+ " chance to mine " +
+ EnumChatFormatting.GREEN +
+ Math.round(finalEffMinerStat2),
+ EnumChatFormatting.GRAY + "adjacent ores.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(effMiner + 2, 2.6)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Efficient Miner",
+ EnumChatFormatting.GRAY + "Level " + effMiner + EnumChatFormatting.DARK_GRAY + "/100",
+ "",
+ EnumChatFormatting.GRAY + "When mining ores, you have a",
+ EnumChatFormatting.GREEN +
+ "" +
+ effMinerStat +
+ "%" +
+ EnumChatFormatting.GRAY +
+ " chance to mine " +
+ EnumChatFormatting.GREEN +
+ Math.round(finalEffMinerStat2),
+ EnumChatFormatting.GRAY + "adjacent ores."
+ ),
+ 100
+ );
+
+ renderHotmPerk(
+ potm,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop + 42),
+ mouseX,
+ mouseY,
+ () -> {
+ switch (potm) {
+ case 0:
+ return Lists.newArrayList(
+ EnumChatFormatting.RED + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "50,000 Mithril Powder"
+ );
+ case 1:
+ return Lists.newArrayList(
+ EnumChatFormatting.YELLOW + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "50,000 Mithril Powder"
+ );
+ case 2:
+ return Lists.newArrayList(
+ EnumChatFormatting.YELLOW + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§a1 Forge Slot",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "75,000 Mithril Powder"
+ );
+ case 3:
+ return Lists.newArrayList(
+ EnumChatFormatting.YELLOW + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§a1 Forge Slot",
+ "§7§8+§a1 Commission Slot",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "100,000 Mithril Powder"
+ );
+ case 4:
+ return Lists.newArrayList(
+ EnumChatFormatting.YELLOW + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§a1 Forge Slot",
+ "§7§8+§a1 Commission Slot",
+ "§7§8+§21 Mithril Powder §7when",
+ "§7mining §fMithril",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "125,000 Mithril Powder"
+ );
+ case 5:
+ return Lists.newArrayList(
+ EnumChatFormatting.GREEN + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§a1 Forge Slot",
+ "§7§8+§a1 Commission Slot",
+ "§7§8+§21 Mithril Powder §7when",
+ "§7mining §fMithril",
+ "§7§8+§51 Token of the Mountain",
+ "",
+ "§7Cost",
+ "§d500,000 Gemstone Powder"
+ );
+ case 6:
+ return Lists.newArrayList(
+ EnumChatFormatting.GREEN + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§a1 Forge Slot",
+ "§7§8+§a1 Commission Slot",
+ "§7§8+§21 Mithril Powder §7when",
+ "§7mining §fMithril",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§d2 Gemstone Powder §7when",
+ "§7mining §dGemstones",
+ "",
+ "§7Cost",
+ "§d750,000 Gemstone Powder"
+ );
+ case 7:
+ return Lists.newArrayList(
+ EnumChatFormatting.GREEN + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/7",
+ "",
+ "§7§8+§c1 Pickaxe Ability Level",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§a1 Forge Slot",
+ "§7§8+§a1 Commission Slot",
+ "§7§8+§21 Mithril Powder §7when",
+ "§7mining §fMithril",
+ "§7§8+§51 Token of the Mountain",
+ "§7§8+§d2 Gemstone Powder §7when",
+ "§7mining §dGemstones",
+ "§7§8+§51 Token of the Mountain"
+ );
+ }
+ return Lists.newArrayList(
+ EnumChatFormatting.GREEN + "Peak of the Mountain",
+ EnumChatFormatting.GRAY + "Level " + potm + EnumChatFormatting.DARK_GRAY + "/???",
+ EnumChatFormatting.RED + "It looks like your NEU doesn't understand your peak of the mountain perks.",
+ EnumChatFormatting.RED + "Please patiently await an update to your NEU installation."
+ );
+ },
+ potm > 0 ? new ItemStack(Blocks.redstone_block) : new ItemStack(Blocks.bedrock),
+ true // A redstone block or bedrock is being rendered, so standard GUI item lighting needs to be enabled.
+ );
+
+ float finalOutput = output;
+ renderHotmPerk(
+ mole,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ mole != 0 && mole != 190
+ ? Lists.newArrayList(
+ "Mole",
+ EnumChatFormatting.GRAY + "Level " + mole + EnumChatFormatting.DARK_GRAY + "/190",
+ "",
+ EnumChatFormatting.GRAY + "When mining hard stone, you have",
+ EnumChatFormatting.GRAY +
+ "a " +
+ EnumChatFormatting.GREEN +
+ finalOutput +
+ "% " +
+ EnumChatFormatting.GRAY +
+ "chance to mine " +
+ EnumChatFormatting.GREEN,
+ EnumChatFormatting.GREEN +
+ "" +
+ Math.round(moleStat) +
+ EnumChatFormatting.GRAY +
+ " adjacent hard stone block" +
+ (moleStat == 1.0 ? "." : "s."),
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(mole + 2, 2.2)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Mole",
+ EnumChatFormatting.GRAY + "Level " + mole + EnumChatFormatting.DARK_GRAY + "/190",
+ "",
+ EnumChatFormatting.GRAY + "When mining hard stone, you have",
+ EnumChatFormatting.GRAY +
+ "a " +
+ EnumChatFormatting.GREEN +
+ finalOutput +
+ "% " +
+ EnumChatFormatting.GRAY +
+ "chance to mine " +
+ EnumChatFormatting.GREEN,
+ EnumChatFormatting.GREEN +
+ "" +
+ Math.round(moleStat) +
+ EnumChatFormatting.GRAY +
+ " adjacent hard stone block" +
+ (moleStat == 1.0 ? "." : "s.")
+ ),
+ 190
+ );
+
+ renderHotmPerk(
+ powderBuff,
+ (int) (guiLeft + xStart + 255),
+ (int) (guiTop + yStartTop - 6),
+ mouseX,
+ mouseY,
+ () ->
+ powderBuff != 0 && powderBuff != 50
+ ? Lists.newArrayList(
+ "Powder Buff",
+ EnumChatFormatting.GRAY + "Level " + powderBuff + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY +
+ "Gain " +
+ EnumChatFormatting.GREEN +
+ powderBuff +
+ "% " +
+ EnumChatFormatting.GRAY +
+ "more Mithril",
+ EnumChatFormatting.GRAY + "Powder and Gemstone Powder§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(powderBuff + 2, 3.2)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Powder Buff",
+ EnumChatFormatting.GRAY + "Level " + powderBuff + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ EnumChatFormatting.GRAY +
+ "Gain " +
+ EnumChatFormatting.GREEN +
+ powderBuff +
+ "% " +
+ EnumChatFormatting.GRAY +
+ "more Mithril",
+ EnumChatFormatting.GRAY + "Powder and Gemstone Powder§7."
+ ),
+ 50
+ );
+
+ renderHotmPerk(
+ skyMall,
+ (int) (guiLeft + xStart + 183),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Sky Mall",
+ "§7Every SkyBlock day, you receive",
+ "§7a random buff in the §2Dwarven",
+ "§2Mines§7.",
+ "",
+ "§7Possible Buffs",
+ "§8 ■ §7Gain §a+100 §6⸕ Mining Speed.",
+ "§8 ■ §7Gain §a+50 §6☘ Mining Fortune.",
+ "§8 ■ §7Gain §a+15% §7chance to gain",
+ " §7extra Powder while mining.",
+ "§8 ■ §7Reduce Pickaxe Ability cooldown",
+ " §7by §a20%",
+ "§8 ■ §7§a10x §7chance to find Goblins",
+ " §7while mining.",
+ "§8 ■ §7Gain §a5x §9Titanium §7drops."
+ ),
+ new ItemStack(skyMall > 0 ? Items.diamond : Items.coal)
+ );
+
+ renderHotmPerk(
+ goblinKiller,
+ (int) (guiLeft + xStart + 207),
+ (int) (guiTop + yStartTop + 42),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Goblin Killer",
+ "§7Killing a §6Golden Goblin",
+ "§6§7gives §2200 §7extra §2Mithril",
+ "§2Powder§7, while killing other",
+ "§7Goblins gives some based on",
+ "§7their wits."
+ ),
+ new ItemStack(goblinKiller > 0 ? Items.diamond : Items.coal)
+ );
+
+ renderHotmPerk(
+ seasonMine,
+ (int) (guiLeft + xStart + 231),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () ->
+ seasonMine != 0 && seasonMine != 100
+ ? Lists.newArrayList(
+ "Seasoned Mineman",
+ "§7Level " + seasonMine + "§8/100",
+ "",
+ "§7Grants §3+" + EnumChatFormatting.DARK_AQUA + seasonMineStat + "☯ Mining Wisdom§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(seasonMine + 2, 2.3)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Seasoned Mineman",
+ "§7Level " + seasonMine + "§8/100",
+ "",
+ "§7Grants §3+" + EnumChatFormatting.DARK_AQUA + seasonMineStat + "☯ Mining Wisdom§7."
+ ),
+ 100
+ );
+
+ renderHotmPerk(
+ madMining,
+ (int) (guiLeft + xStart + 207),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () -> Lists.newArrayList("Mining Madness", "§7Grants §a+50 §6⸕ Mining Speed", "§7and §6☘ Mining Fortune§7."),
+ new ItemStack(madMining > 0 ? Items.diamond : Items.coal)
+ );
+
+ renderHotmPerk(
+ lonesomeMiner,
+ (int) (guiLeft + xStart + 207),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ lonesomeMiner != 0 && lonesomeMiner != 45
+ ? Lists.newArrayList(
+ "Lonesome Miner",
+ "§7Level " + lonesomeMiner + EnumChatFormatting.DARK_GRAY + "/45",
+ "",
+ "§7Increases §c❁ Strength, §9☣ Crit",
+ "§9Chance, §9☠ Crit Damage, §a❈",
+ "§aDefense, and §c❤ Health",
+ "§c§7statistics gain by " + EnumChatFormatting.GREEN + lonesomeMinerStat + "%§7",
+ "§7while in the Crystal Hollows.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(lonesomeMiner + 2, 3.07)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Lonesome Miner",
+ "§7Level " + lonesomeMiner + EnumChatFormatting.DARK_GRAY + "/45",
+ "",
+ "§7Increases §c❁ Strength, §9☣ Crit",
+ "§9Chance, §9☠ Crit Damage, §a❈",
+ "§aDefense, and §c❤ Health",
+ "§c§7statistics gain by " + EnumChatFormatting.GREEN + lonesomeMinerStat + "%§7"
+ ),
+ 45
+ );
+
+ renderHotmPerk(
+ professional,
+ (int) (guiLeft + xStart + 231),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ professional != 0 && professional != 140
+ ? Lists.newArrayList(
+ "Professional",
+ "§7Level " + professional + EnumChatFormatting.DARK_GRAY + "/140",
+ "",
+ "§7Gain §a+" + professionalStat + "§6 ⸕ Mining",
+ "§6Speed§7 when mining Gemstones.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(professional + 2, 2.3)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Professional",
+ "§7Level " + professional + EnumChatFormatting.DARK_GRAY + "/140",
+ "",
+ "§7Gain §a+" + professionalStat + "§6 ⸕ Mining",
+ "§6Speed§7 when mining Gemstones."
+ ),
+ 140
+ );
+
+ renderHotmPerk(
+ miningSpeed2,
+ (int) (guiLeft + xStart + 207),
+ (int) (guiTop + yStartTop - 6),
+ mouseX,
+ mouseY,
+ () ->
+ miningSpeed2 != 0 && miningSpeed2 != 50
+ ? Lists.newArrayList(
+ "Mining Speed 2",
+ "§7Level " + miningSpeed2 + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ "§7Grants " + EnumChatFormatting.GREEN + "+" + miningSpeed2Stat + EnumChatFormatting.GOLD + " ⸕ Mining",
+ "§6Speed§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format(Math.pow(miningSpeed2 + 2, 3)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Mining Speed 2",
+ "§7Level " + miningSpeed2 + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ "§7Grants " + EnumChatFormatting.GREEN + "+" + miningSpeed2Stat + EnumChatFormatting.GOLD + " ⸕ Mining",
+ "§6Speed§7."
+ ),
+ 50
+ );
+
+ renderHotmPerk(
+ quickForge,
+ (int) (guiLeft + xStart + 279),
+ (int) (guiTop + yStartTop + 114),
+ mouseX,
+ mouseY,
+ () ->
+ quickForge != 0 && quickForge != 20
+ ? Lists.newArrayList(
+ "Quick Forge",
+ "§7Level " + quickForge + EnumChatFormatting.DARK_GRAY + "/20",
+ "",
+ "§7Decreases the time it takes to",
+ "§7forge by §a" + (quickForgeStat < 20 ? quickForgeStat : 30) + "%§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(quickForge + 2, 4)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Quick Forge",
+ "§7Level " + quickForge + EnumChatFormatting.DARK_GRAY + "/20",
+ "",
+ "§7Decreases the time it takes to",
+ "§7forge by §a" + (quickForgeStat < 20 ? quickForgeStat : 30) + "%§7."
+ ),
+ 20
+ );
+
+ renderHotmPerk(
+ fortunate,
+ (int) (guiLeft + xStart + 279),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ fortunate != 0 && fortunate != 20
+ ? Lists.newArrayList(
+ "Fortunate",
+ "§7Level " + fortunate + EnumChatFormatting.DARK_GRAY + "/20",
+ "",
+ "§7Gain " + EnumChatFormatting.GREEN + "+" + fortunateStat + " §6☘ Mining",
+ "§6Fortune§7 when mining Gemstone.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(fortunate + 2, 3.05)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Fortunate",
+ "§7Level " + fortunate + EnumChatFormatting.DARK_GRAY + "/20",
+ "",
+ "§7Gain " + EnumChatFormatting.GREEN + "+" + fortunateStat + " §6☘ Mining",
+ "§6Fortune§7 when mining Gemstone."
+ ),
+ 20
+ );
+
+ renderHotmPerk(
+ greatExplorer,
+ (int) (guiLeft + xStart + 303),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ greatExplorer != 0 && greatExplorer != 20
+ ? Lists.newArrayList(
+ "Great Explorer",
+ "§7Level " + greatExplorer + EnumChatFormatting.DARK_GRAY + "/20",
+ "",
+ "§7Grants " + EnumChatFormatting.GREEN + "+" + greatExplorerStat + "% " + EnumChatFormatting.GRAY +
+ "chance to",
+ "§7find treasure.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(greatExplorer + 2, 4)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Great Explorer",
+ "§7Level " + greatExplorer + EnumChatFormatting.DARK_GRAY + "/20",
+ "",
+ "§7Grants " + EnumChatFormatting.GREEN + "+" + greatExplorerStat + "% " + EnumChatFormatting.GRAY +
+ "chance to",
+ "§7find treasure."
+ ),
+ 20
+ );
+
+ renderHotmPerk(
+ miningFortune2,
+ (int) (guiLeft + xStart + 303),
+ (int) (guiTop + yStartTop - 6),
+ mouseX,
+ mouseY,
+ () ->
+ miningFortune2 != 0 && miningFortune2 != 50
+ ? Lists.newArrayList(
+ "Mining Fortune 2",
+ "§7Level " + miningFortune2 + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ "§7Grants §a+§a" + miningFortune2Stat + "§7 §6☘ Mining",
+ "§6Fortune§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.LIGHT_PURPLE +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(miningFortune2 + 2, 3.2)) +
+ " Gemstone Powder"
+ )
+ : Lists.newArrayList(
+ "Mining Fortune 2",
+ "§7Level " + miningFortune2 + EnumChatFormatting.DARK_GRAY + "/50",
+ "",
+ "§7Grants §a+§a" + miningFortune2Stat + "§7 §6☘ Mining",
+ "§6Fortune§7."
+ ),
+ 50
+ );
+
+ renderHotmPerk(
+ orbit,
+ (int) (guiLeft + xStart + 279),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () ->
+ orbit != 0 && orbit != 80
+ ? Lists.newArrayList(
+ "Orbiter",
+ "§7Level " + orbit + EnumChatFormatting.DARK_GRAY + "/80",
+ "",
+ "§7When mining ores, you have a",
+ EnumChatFormatting.GREEN + "" + orbitStat + "%" + EnumChatFormatting.GRAY + " chance to get a random",
+ "§7amount of experience orbs.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN + "" + ((orbit + 1) * 70) + " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Orbiter",
+ "§7Level " + orbit + EnumChatFormatting.DARK_GRAY + "/80",
+ "",
+ "§7When mining ores, you have a",
+ EnumChatFormatting.GREEN + "" + orbitStat + "%" + EnumChatFormatting.GRAY + " chance to get a random",
+ "§7amount of experience orbs."
+ ),
+ 80
+ );
+
+ renderHotmPerk(
+ frontLoad,
+ (int) (guiLeft + xStart + 303),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Front Loaded",
+ "§7Grants §a+100 §6⸕ Mining Speed",
+ "§7and §6☘ Mining Fortune §7for",
+ "§7the first §e2,500 §7ores you",
+ "§7mine in a day."
+ ),
+ new ItemStack(frontLoad > 0 ? Items.diamond : Items.coal)
+ );
+
+ renderHotmPerk(
+ starPowder,
+ (int) (guiLeft + xStart + 303),
+ (int) (guiTop + yStartTop + 42),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Star Powder",
+ "§7Mining Mithril Ore near §5Fallen",
+ "§5Crystals §7gives §a+3 §7extra",
+ "§7Mithril Powder§7."
+ ),
+ new ItemStack(starPowder > 0 ? Items.diamond : Items.coal)
+ );
+
+ renderHotmPerk(
+ fortnite,
+ (int) (guiLeft + xStart + 327),
+ (int) (guiTop + yStartTop + 66),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Precision Mining",
+ "§7When mining ore, a particle",
+ "§7target appears on the block that",
+ "§7increases your §6⸕ Mining Speed",
+ "§7by §a30% §7when aiming at it."
+ ),
+ new ItemStack(fortnite > 0 ? Items.diamond : Items.coal)
+ );
+
+ renderHotmPerk(
+ crystallized,
+ (int) (guiLeft + xStart + 303),
+ (int) (guiTop + yStartTop + 90),
+ mouseX,
+ mouseY,
+ () ->
+ crystallized != 0 && crystallized != 30
+ ? Lists.newArrayList(
+ "Crystallized",
+ "§7Level " + crystallized + EnumChatFormatting.DARK_GRAY + "/30",
+ "",
+ "§7Grants §a+§a" + crystallizedStat + "§7 §6⸕ Mining",
+ "§6Speed §7and a §a" + crystallizedStat + "%§7 §7chance",
+ "§7to deal §a+1 §7extra damage near",
+ "§7§5Fallen Stars§7.",
+ "",
+ EnumChatFormatting.GRAY + "Cost",
+ EnumChatFormatting.DARK_GREEN +
+ "" +
+ GuiProfileViewer.numberFormat.format((int) Math.pow(crystallized + 2, 2.4)) +
+ " Mithril Powder"
+ )
+ : Lists.newArrayList(
+ "Crystallized",
+ "§7Level " + crystallized + EnumChatFormatting.DARK_GRAY + "/30",
+ "",
+ "§7Grants §a+§a" + crystallizedStat + "§7 §6⸕ Mining",
+ "§6Speed §7and a §a" + crystallizedStat + "%§7 §7chance",
+ "§7to deal §a+1 §7extra damage near",
+ "§7§5Fallen Stars§7."
+ ),
+ 30
+ );
+
+ renderPickaxeAbility(
+ pickoblus,
+ (int) (guiLeft + xStart + 303),
+ (int) (guiTop + yStartTop + 114),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ "Pickobulus",
+ "",
+ "§6Pickaxe Ability: Pickobulus",
+ "§7Throw your pickaxe to create an",
+ "§7explosion on impact, mining all",
+ "§7ores within a §a2§7 block",
+ "§7radius.",
+ "§8Cooldown: §a" + (potm == 0 ? "120s" : "110s")
+ )
+ );
+
+ renderPickaxeAbility(
+ maniacMiner,
+ (int) (guiLeft + xStart + 327),
+ (int) (guiTop + yStartTop + 18),
+ mouseX,
+ mouseY,
+ () ->
+ Lists.newArrayList(
+ EnumChatFormatting.RED + "Maniac Miner",
+ "",
+ "§6Pickaxe Ability: Maniac Miner",
+ "§7Spends all your Mana and grants",
+ "§7§a+1 §6⸕ Mining Speed §7for",
+ "§7every 10 Mana spent, for",
+ "§7§a§a15s§7§7.",
+ "§8Cooldown: §a59s"
+ )
+ );
+ }
+
+ /**
+ * Renders a standard HOTM perk that can be levelled.
+ */
+ private void renderHotmPerk(
+ int perkLevel,
+ int xPosition,
+ int yPosition,
+ int mouseX,
+ int mouseY,
+ Supplier<ArrayList<String>> tooltipSupplier,
+ int maxLevel
+ ) {
+ renderHotmPerk(perkLevel, xPosition, yPosition, mouseX, mouseY, tooltipSupplier, false, maxLevel);
+ }
+
+ /**
+ * Renders a pickaxe ability that can be unlocked once and not levelled.
+ */
+ private void renderPickaxeAbility(
+ int perkLevel,
+ int xPosition,
+ int yPosition,
+ int mouseX,
+ int mouseY,
+ Supplier<ArrayList<String>> tooltipSupplier
+ ) {
+ renderHotmPerk(perkLevel, xPosition, yPosition, mouseX, mouseY, tooltipSupplier, true, -1);
+ }
+
+ /**
+ * Renders a HOTM perk. This method is only called from its overloads above.
+ */
+ private void renderHotmPerk(
+ int perkLevel,
+ int xPosition,
+ int yPosition,
+ int mouseX,
+ int mouseY,
+ Supplier<ArrayList<String>> tooltipSupplier,
+ boolean isPickaxeAbility,
+ int maxLevel
+ ) {
+ boolean unlocked = perkLevel > 0;
+ GlStateManager.color(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+
+ ItemStack itemStack;
+ if (isPickaxeAbility) {
+ RenderHelper.enableGUIStandardItemLighting(); // GUI standard item lighting must be enabled for items that are rendered as blocks, like emerald blocks.
+ itemStack = new ItemStack(unlocked
+ ? Blocks.emerald_block
+ : Blocks.coal_block); // Pickaxe abilities are rendered as blocks
+ } else { // Non-pickaxe abilities are rendered as items
+ itemStack = new ItemStack(unlocked ? (perkLevel >= maxLevel ? Items.diamond : Items.emerald) : Items.coal);
+ }
+
+ ArrayList<String> tooltip = tooltipSupplier.get();
+ // Prepend the green, yellow, or red color on the first line of each tooltip depending on if the perk is unlocked
+ tooltip.set(
+ 0,
+ (unlocked
+ ? (perkLevel >= maxLevel ? EnumChatFormatting.GREEN : EnumChatFormatting.YELLOW)
+ : EnumChatFormatting.RED) +
+ tooltip.get(0)
+ );
+
+ NBTTagCompound nbt = new NBTTagCompound(); //Adding NBT Data for Custom Resource Packs
+ NBTTagCompound display = new NBTTagCompound();
+ display.setString("Name", tooltip.get(0));
+ nbt.setTag("display", display);
+ itemStack.setTagCompound(nbt);
+
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, xPosition, yPosition);
+ GlStateManager.enableLighting();
+ if (mouseX >= xPosition && mouseX < xPosition + 16) {
+ if (mouseY >= yPosition && mouseY <= yPosition + 16) {
+ Utils.drawHoveringText(
+ tooltip,
+ mouseX,
+ mouseY,
+ getInstance().width,
+ getInstance().height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+ }
+
+ /**
+ * A separate method similar to the one above, but allowing the caller to specify an ItemStack to render.
+ * Used for rendering Peak of the Mountain and perks that are unlocked once and not upgraded.
+ */
+ private void renderHotmPerk(
+ int perkLevel,
+ int xPosition,
+ int yPosition,
+ int mouseX,
+ int mouseY,
+ Supplier<ArrayList<String>> tooltipSupplier,
+ ItemStack itemStack
+ ) {
+ renderHotmPerk(perkLevel, xPosition, yPosition, mouseX, mouseY, tooltipSupplier, itemStack, false);
+ }
+
+ /**
+ * This method renders a HOTM perk using the provided ItemStack.
+ * It is overloaded by the method above, and is only called directly to render Peak of the Mountain.
+ */
+ private void renderHotmPerk(
+ int perkLevel,
+ int xPosition,
+ int yPosition,
+ int mouseX,
+ int mouseY,
+ Supplier<ArrayList<String>> tooltipSupplier,
+ ItemStack itemStack,
+ boolean isRenderingBlock
+ ) {
+ boolean unlocked = perkLevel > 0;
+ GlStateManager.color(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+ if (isRenderingBlock) RenderHelper.enableGUIStandardItemLighting();
+
+ ArrayList<String> tooltip = tooltipSupplier.get();
+ // Prepend the green or red color on the first line of each tooltip depending on if the perk is unlocked
+ if (!tooltip.get(0).contains("Peak of the Mountain")) tooltip.set(
+ 0,
+ (unlocked ? EnumChatFormatting.GREEN : EnumChatFormatting.RED) + tooltip.get(0)
+ ); //Peak of the Moutain has three color options, and is set already
+
+ NBTTagCompound nbt = new NBTTagCompound(); //Adding NBT Data for Resource Packs
+ NBTTagCompound display = new NBTTagCompound();
+ display.setString("Name", tooltip.get(0));
+ if (tooltip.get(0).contains("Peak of the Mountain")) display.setString("Lore", tooltip.get(1)); //Set Lore to Level
+ nbt.setTag("display", display);
+ itemStack.setTagCompound(nbt);
+
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, xPosition, yPosition);
+ GlStateManager.enableLighting();
+ if (mouseX >= xPosition && mouseX < xPosition + 16) {
+ if (mouseY >= yPosition && mouseY <= yPosition + 16) {
+ Utils.drawHoveringText(
+ tooltip,
+ mouseX,
+ mouseY,
+ getInstance().width,
+ getInstance().height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java
index ac117bc2..41217201 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/Panorama.java
@@ -1,7 +1,28 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.profileviewer;
import io.github.moulberry.notenoughupdates.util.TexLoc;
import io.github.moulberry.notenoughupdates.util.Utils;
+import java.io.IOException;
+import java.util.HashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
@@ -16,14 +37,45 @@ import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.Project;
public class Panorama {
+
private static final TexLoc tl = new TexLoc(97, 19, Keyboard.KEY_P);
private static final TexLoc tl2 = new TexLoc(37, 80, Keyboard.KEY_L);
-
+ private static final HashMap<String, ResourceLocation[]> panoramasMap = new HashMap<>();
private static ResourceLocation backgroundTexture = null;
-
private static int lastWidth = 0;
private static int lastHeight = 0;
+ public static synchronized ResourceLocation[] getPanoramasForLocation(String location, String identifier) {
+ if (panoramasMap.containsKey(location + identifier)) return panoramasMap.get(location + identifier);
+ try {
+ ResourceLocation[] panoramasArray = new ResourceLocation[6];
+ for (int i = 0; i < 6; i++) {
+ panoramasArray[i] =
+ new ResourceLocation("notenoughupdates:panoramas/" + location + "_" + identifier + "/panorama_" + i + ".jpg");
+ Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
+ }
+ panoramasMap.put(location + identifier, panoramasArray);
+ return panoramasArray;
+ } catch (IOException e) {
+ try {
+ ResourceLocation[] panoramasArray = new ResourceLocation[6];
+ for (int i = 0; i < 6; i++) {
+ panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/" + location + "/panorama_" + i + ".jpg");
+ Minecraft.getMinecraft().getResourceManager().getResource(panoramasArray[i]);
+ }
+ panoramasMap.put(location + identifier, panoramasArray);
+ return panoramasArray;
+ } catch (IOException e2) {
+ ResourceLocation[] panoramasArray = new ResourceLocation[6];
+ for (int i = 0; i < 6; i++) {
+ panoramasArray[i] = new ResourceLocation("notenoughupdates:panoramas/unknown/panorama_" + i + ".jpg");
+ }
+ panoramasMap.put(location + identifier, panoramasArray);
+ return panoramasArray;
+ }
+ }
+ }
+
public static void drawPanorama(
float angle,
int x,
@@ -116,7 +168,6 @@ public class Panorama {
float scale = (float) Math.sqrt(3 / distSq);
worldrenderer.pos(xr * scale, yr * scale, scale).tex(x2, y2).color(255, 255, 255, 255).endVertex();
-
}
tessellator.draw();
@@ -140,12 +191,16 @@ public class Panorama {
GlStateManager.enableDepth();
}
- if (backgroundTexture == null || lastWidth != width * scaledresolution.getScaleFactor() ||
- lastHeight != height * scaledresolution.getScaleFactor()) {
- DynamicTexture viewportTexture =
- new DynamicTexture(width * scaledresolution.getScaleFactor(), height * scaledresolution.getScaleFactor());
- backgroundTexture =
- Minecraft.getMinecraft().getTextureManager().getDynamicTextureLocation("background", viewportTexture);
+ if (
+ backgroundTexture == null ||
+ lastWidth != width * scaledresolution.getScaleFactor() ||
+ lastHeight != height * scaledresolution.getScaleFactor()
+ ) {
+ DynamicTexture viewportTexture = new DynamicTexture(
+ width * scaledresolution.getScaleFactor(),
+ height * scaledresolution.getScaleFactor()
+ );
+ backgroundTexture = Minecraft.getMinecraft().getTextureManager().getDynamicTextureLocation("background", viewportTexture);
lastWidth = width * scaledresolution.getScaleFactor();
lastHeight = height * scaledresolution.getScaleFactor();
}
@@ -168,14 +223,10 @@ public class Panorama {
Tessellator tessellator = Tessellator.getInstance();
WorldRenderer worldrenderer = tessellator.getWorldRenderer();
worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX);
- worldrenderer.pos(x, y + height, 0)
- .tex(0, 1).endVertex();
- worldrenderer.pos(x + width, y + height, 0)
- .tex(0, 0).endVertex();
- worldrenderer.pos(x + width, y, 0)
- .tex(1, 0).endVertex();
- worldrenderer.pos(x, y, 0)
- .tex(1, 1).endVertex();
+ worldrenderer.pos(x, y + height, 0).tex(0, 1).endVertex();
+ worldrenderer.pos(x + width, y + height, 0).tex(0, 0).endVertex();
+ worldrenderer.pos(x + width, y, 0).tex(1, 0).endVertex();
+ worldrenderer.pos(x, y, 0).tex(1, 1).endVertex();
tessellator.draw();
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PetsPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PetsPage.java
new file mode 100644
index 00000000..cb85bf79
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PetsPage.java
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.SBInfo;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PetsPage extends GuiProfileViewerPage {
+
+ public static final ResourceLocation pv_pets = new ResourceLocation("notenoughupdates:pv_pets.png");
+ private static final int COLLS_XCOUNT = 5;
+ private static final int COLLS_YCOUNT = 4;
+ private static final float COLLS_XPADDING = (190 - COLLS_XCOUNT * 20) / (float) (COLLS_XCOUNT + 1);
+ private static final float COLLS_YPADDING = (202 - COLLS_YCOUNT * 20) / (float) (COLLS_YCOUNT + 1);
+ private List<JsonObject> sortedPets = null;
+ private List<ItemStack> sortedPetsStack = null;
+ private int selectedPet = -1;
+ private int petsPage = 0;
+
+ public PetsPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ ProfileViewer.Profile profile = GuiProfileViewer.getProfile();
+ String profileId = GuiProfileViewer.getProfileId();
+ JsonObject petsInfo = profile.getPetsInfo(profileId);
+ if (petsInfo == null) return;
+ JsonObject petsJson = Constants.PETS;
+ if (petsJson == null) return;
+
+ String location = null;
+ JsonObject status = profile.getPlayerStatus();
+ if (status != null && status.has("mode")) {
+ location = status.get("mode").getAsString();
+ }
+
+ getInstance().backgroundRotation += (getInstance().currentTime - getInstance().lastTime) / 400f;
+ getInstance().backgroundRotation %= 360;
+
+ String panoramaIdentifier = "day";
+ if (SBInfo.getInstance().currentTimeDate != null) {
+ if (SBInfo.getInstance().currentTimeDate.getHours() <= 6 ||
+ SBInfo.getInstance().currentTimeDate.getHours() >= 20) {
+ panoramaIdentifier = "night";
+ }
+ }
+
+ JsonArray pets = petsInfo.get("pets").getAsJsonArray();
+ if (sortedPets == null) {
+ sortedPets = new ArrayList<>();
+ sortedPetsStack = new ArrayList<>();
+ for (int i = 0; i < pets.size(); i++) {
+ sortedPets.add(pets.get(i).getAsJsonObject());
+ }
+ sortedPets.sort((pet1, pet2) -> {
+ String tier1 = pet1.get("tier").getAsString();
+ String tierNum1 = GuiProfileViewer.MINION_RARITY_TO_NUM.get(tier1);
+ if (tierNum1 == null) return 1;
+ int tierNum1I = Integer.parseInt(tierNum1);
+ float exp1 = pet1.get("exp").getAsFloat();
+
+ String tier2 = pet2.get("tier").getAsString();
+ String tierNum2 = GuiProfileViewer.MINION_RARITY_TO_NUM.get(tier2);
+ if (tierNum2 == null) return -1;
+ int tierNum2I = Integer.parseInt(tierNum2);
+ float exp2 = pet2.get("exp").getAsFloat();
+
+ if (tierNum1I != tierNum2I) {
+ return tierNum2I - tierNum1I;
+ } else {
+ return (int) (exp2 - exp1);
+ }
+ });
+ for (JsonObject pet : sortedPets) {
+ PetInfoOverlay.Pet parsedPet = new PetInfoOverlay.Pet();
+ parsedPet.petType = pet.get("type").getAsString();
+ parsedPet.rarity = PetInfoOverlay.Rarity.valueOf(pet.get("tier").getAsString());
+ parsedPet.petLevel = GuiProfileViewer.getPetLevel(
+ parsedPet.petType,
+ parsedPet.rarity.name(),
+ pet.get("exp").getAsFloat()
+ );
+ parsedPet.petXpType = "unknown";
+ parsedPet.petItem = Utils.getElementAsString(pet.get("heldItem"), null);
+ parsedPet.skin = Utils.getElementAsString(pet.get("skin"), null);
+ parsedPet.candyUsed = pet.get("candyUsed").getAsInt();
+ sortedPetsStack.add(ItemUtils.createPetItemstackFromPetInfo(parsedPet));
+ pet.addProperty("level", parsedPet.petLevel.level);
+ pet.addProperty("currentLevelRequirement", parsedPet.petLevel.currentLevelRequirement);
+ pet.addProperty("maxXP", parsedPet.petLevel.maxXP);
+ }
+ }
+
+ Panorama.drawPanorama(
+ -getInstance().backgroundRotation,
+ guiLeft + 212,
+ guiTop + 44,
+ 81,
+ 108,
+ -0.37f,
+ 0.6f,
+ Panorama.getPanoramasForLocation(location == null ? "dynamic" : location, panoramaIdentifier)
+ );
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_pets);
+ Utils.drawTexturedRect(guiLeft, guiTop, getInstance().sizeX, getInstance().sizeY, GL11.GL_NEAREST);
+
+ Utils.drawStringCentered(
+ EnumChatFormatting.DARK_PURPLE + "Pets",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 100,
+ guiTop + 14,
+ true,
+ 4210752
+ );
+ GlStateManager.color(1, 1, 1, 1);
+
+ JsonElement activePetElement = petsInfo.get("active_pet");
+ if (selectedPet == -1 && activePetElement != null && activePetElement.isJsonObject()) {
+ JsonObject active = activePetElement.getAsJsonObject();
+ for (int i = 0; i < sortedPets.size(); i++) {
+ if (sortedPets.get(i) == active) {
+ selectedPet = i;
+ break;
+ }
+ }
+ }
+
+ boolean leftHovered = false;
+ boolean rightHovered = false;
+ if (Mouse.isButtonDown(0)) {
+ if (mouseY > guiTop + 6 && mouseY < guiTop + 22) {
+ if (mouseX > guiLeft + 100 - 20 - 12 && mouseX < guiLeft + 100 - 20) {
+ leftHovered = true;
+ } else if (mouseX > guiLeft + 100 + 20 && mouseX < guiLeft + 100 + 20 + 12) {
+ rightHovered = true;
+ }
+ }
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.resource_packs);
+
+ if (petsPage > 0) {
+ Utils.drawTexturedRect(
+ guiLeft + 100 - 15 - 12,
+ guiTop + 6,
+ 12,
+ 16,
+ 29 / 256f,
+ 53 / 256f,
+ !leftHovered ? 0 : 32 / 256f,
+ !leftHovered ? 32 / 256f : 64 / 256f,
+ GL11.GL_NEAREST
+ );
+ }
+ if (petsPage < Math.ceil(pets.size() / 20f) - 1) {
+ Utils.drawTexturedRect(
+ guiLeft + 100 + 15,
+ guiTop + 6,
+ 12,
+ 16,
+ 5 / 256f,
+ 29 / 256f,
+ !rightHovered ? 0 : 32 / 256f,
+ !rightHovered ? 32 / 256f : 64 / 256f,
+ GL11.GL_NEAREST
+ );
+ }
+
+ for (
+ int i = petsPage * 20;
+ i < Math.min(petsPage * 20 + 20, Math.min(sortedPetsStack.size(), sortedPets.size()));
+ i++
+ ) {
+ JsonObject pet = sortedPets.get(i);
+ ItemStack stack = sortedPetsStack.get(i);
+
+ if (pet != null) {
+ {
+ NBTTagCompound tag = stack.getTagCompound();
+ tag.setBoolean("DisablePetExp", true);
+ stack.setTagCompound(tag);
+ }
+ int xIndex = (i % 20) % COLLS_XCOUNT;
+ int yIndex = (i % 20) / COLLS_XCOUNT;
+
+ float x = 5 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
+ float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiProfileViewer.pv_elements);
+ if (i == selectedPet) {
+ GlStateManager.color(1, 185 / 255f, 0, 1);
+ } else {
+ GlStateManager.color(1, 1, 1, 1);
+ }
+ Utils.drawTexturedRect(guiLeft + x, guiTop + y, 20, 20, 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST);
+
+ Utils.drawItemStack(stack, guiLeft + (int) x + 2, guiTop + (int) y + 2, true);
+
+ if (mouseX > guiLeft + x && mouseX < guiLeft + x + 20) {
+ if (mouseY > guiTop + y && mouseY < guiTop + y + 20) {
+ getInstance().tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+ }
+ }
+ }
+
+ if (selectedPet >= 0) {
+ ItemStack petStack;
+ if (sortedPetsStack.size() <= selectedPet) {
+ petStack = ItemUtils.createQuestionMarkSkull("§cInvalid pet selection");
+ } else {
+ petStack = sortedPetsStack.get(selectedPet);
+ }
+ String display = petStack.getDisplayName();
+ JsonObject pet = sortedPets.get(selectedPet);
+
+ int x = guiLeft + 280;
+ float y = guiTop + 67 + 15 * (float) Math.sin(
+ ((getInstance().currentTime - getInstance().startTime) / 800f) % (2 * Math.PI));
+
+ int displayLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(display);
+ int halfDisplayLen = displayLen / 2;
+
+ GlStateManager.pushMatrix();
+ GlStateManager.translate(x, y, 0);
+
+ GuiScreen.drawRect(-halfDisplayLen - 1 - 28, -1, halfDisplayLen + 1 - 28, 8, new Color(0, 0, 0, 100).getRGB());
+
+ Minecraft.getMinecraft().fontRendererObj.drawString(display, -halfDisplayLen - 28, 0, 0, true);
+
+ GlStateManager.enableDepth();
+ GlStateManager.translate(-55, 0, 0);
+ GlStateManager.scale(3.5f, 3.5f, 1);
+ Utils.drawItemStack(petStack, 0, 0);
+ GlStateManager.popMatrix();
+
+ float level = pet.get("level").getAsFloat();
+ float currentLevelRequirement = pet.get("currentLevelRequirement").getAsFloat();
+ float exp = pet.get("exp").getAsFloat();
+ float maxXP = pet.get("maxXP").getAsFloat();
+
+ String[] split = display.split("] ");
+ String colouredName = split[split.length - 1];
+
+ Utils.renderAlignedString(
+ colouredName,
+ EnumChatFormatting.WHITE + "Level " + (int) Math.floor(level),
+ guiLeft + 319,
+ guiTop + 28,
+ 98
+ );
+
+ //Utils.drawStringCenteredScaledMaxWidth(, Minecraft.getMinecraft().fontRendererObj, guiLeft+368, guiTop+28+4, true, 98, 0);
+ //renderAlignedString(display, EnumChatFormatting.YELLOW+"[LVL "+Math.floor(level)+"]", guiLeft+319, guiTop+28, 98);
+ getInstance().renderBar(guiLeft + 319, guiTop + 38, 98, (float) Math.floor(level) / 100f);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "To Next LVL",
+ EnumChatFormatting.WHITE.toString() + (int) (level % 1 * 100) + "%",
+ guiLeft + 319,
+ guiTop + 46,
+ 98
+ );
+ getInstance().renderBar(guiLeft + 319, guiTop + 56, 98, level % 1);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "To Max LVL",
+ EnumChatFormatting.WHITE.toString() + Math.min(100, (int) (exp / maxXP * 100)) + "%",
+ guiLeft + 319,
+ guiTop + 64,
+ 98
+ );
+ getInstance().renderBar(guiLeft + 319, guiTop + 74, 98, exp / maxXP);
+
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Total XP",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(exp),
+ guiLeft + 319,
+ guiTop + 125,
+ 98
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Current LVL XP",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat((level % 1) * currentLevelRequirement),
+ guiLeft + 319,
+ guiTop + 143,
+ 98
+ );
+ Utils.renderAlignedString(
+ EnumChatFormatting.YELLOW + "Required LVL XP",
+ EnumChatFormatting.WHITE + StringUtils.shortNumberFormat(currentLevelRequirement),
+ guiLeft + 319,
+ guiTop + 161,
+ 98
+ );
+ }
+ }
+
+ @Override
+ public boolean mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
+ if (sortedPets == null) return false;
+ for (int i = petsPage * 20; i < Math.min(petsPage * 20 + 20, sortedPets.size()); i++) {
+ int xIndex = (i % 20) % COLLS_XCOUNT;
+ int yIndex = (i % 20) / COLLS_XCOUNT;
+
+ float x = 5 + COLLS_XPADDING + (COLLS_XPADDING + 20) * xIndex;
+ float y = 7 + COLLS_YPADDING + (COLLS_YPADDING + 20) * yIndex;
+
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+ if (mouseX > guiLeft + x && mouseX < guiLeft + x + 20) {
+ if (mouseY > guiTop + y && mouseY < guiTop + y + 20) {
+ selectedPet = i;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void mouseReleased(int mouseX, int mouseY, int mouseButton) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ if (mouseY > guiTop + 6 && mouseY < guiTop + 22) {
+ if (mouseX > guiLeft + 100 - 15 - 12 && mouseX < guiLeft + 100 - 20) {
+ if (petsPage > 0) {
+ petsPage--;
+ }
+ } else if (mouseX > guiLeft + 100 + 15 && mouseX < guiLeft + 100 + 20 + 12) {
+ if (sortedPets != null && petsPage < Math.ceil(sortedPets.size() / 20f) - 1) {
+ petsPage++;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void resetCache() {
+ petsPage = 0;
+ sortedPets = null;
+ sortedPetsStack = null;
+ selectedPet = -1;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
index 4a915111..b0cc930a 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/PlayerStats.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.profileviewer;
import com.google.gson.JsonArray;
@@ -5,23 +24,34 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.profileviewer.info.QuiverInfo;
import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.JsonUtils;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.nbt.CompressedStreamTools;
+import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumChatFormatting;
import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class PlayerStats {
+
public static final String HEALTH = "health";
public static final String DEFENCE = "defence";
public static final String STRENGTH = "strength";
@@ -33,8 +63,10 @@ public class PlayerStats {
public static final String SEA_CREATURE_CHANCE = "sea_creature_chance";
public static final String MAGIC_FIND = "magic_find";
public static final String PET_LUCK = "pet_luck";
+ public static final String MINING_FORTUNE = "mining_fortune";
+ public static final String MINING_SPEED = "mining_speed";
- public static final String[] defaultStatNames = new String[]{
+ public static final String[] defaultStatNames = new String[] {
"health",
"defence",
"strength",
@@ -49,9 +81,9 @@ public class PlayerStats {
"ferocity",
"ability_damage",
"mining_fortune",
- "mining_speed"
+ "mining_speed",
};
- public static final String[] defaultStatNamesPretty = new String[]{
+ public static final String[] defaultStatNamesPretty = new String[] {
EnumChatFormatting.RED + "\u2764 Health",
EnumChatFormatting.GREEN + "\u2748 Defence",
EnumChatFormatting.RED + "\u2741 Strength",
@@ -66,83 +98,23 @@ public class PlayerStats {
EnumChatFormatting.RED + "\u2AFD Ferocity",
EnumChatFormatting.RED + "\u2739 Ability Damage",
EnumChatFormatting.GOLD + "\u2618 Mining Fortune",
- EnumChatFormatting.GOLD + "\u2E15 Mining Speed"
+ EnumChatFormatting.GOLD + "\u2E15 Mining Speed",
};
-
- public static class Stats {
- JsonObject statsJson = new JsonObject();
-
- /*public float health;
- public float defence;
- public float strength;
- public float speed;
- public float crit_chance;
- public float crit_damage;
- public float bonus_attack_speed;
- public float intelligence;
- public float sea_creature_chance;
- public float magic_find;
- public float pet_luck;*/
-
- public Stats(Stats... statses) {
- for (Stats stats : statses) {
- add(stats);
- }
- }
-
- /*@Override
- public String toString() {
- return String.format("{health=%s,defence=%s,strength=%s,speed=%s,crit_chance=%s,crit_damage=%s," +
- "bonus_attack_speed=%s,intelligence=%s,sea_creature_chance=%s,magic_find=%s,pet_luck=%s}",
- stats.get("health"), defence, strength, speed, crit_chance, crit_damage, bonus_attack_speed, intelligence,
- sea_creature_chance, magic_find, pet_luck
- );
- }*/
-
- public float get(String statName) {
- if (statsJson.has(statName)) {
- return statsJson.get(statName).getAsFloat();
- } else {
- return 0;
- }
- }
-
- public Stats add(Stats stats) {
- for (Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) {
- if (statEntry.getValue().isJsonPrimitive() && ((JsonPrimitive) statEntry.getValue()).isNumber()) {
- if (!statsJson.has(statEntry.getKey())) {
- statsJson.add(statEntry.getKey(), statEntry.getValue());
- } else {
- JsonPrimitive e = statsJson.get(statEntry.getKey()).getAsJsonPrimitive();
- float statNum = e.getAsFloat() + statEntry.getValue().getAsFloat();
- statsJson.add(statEntry.getKey(), new JsonPrimitive(statNum));
- }
- }
- }
- return this;
- }
-
- public void scale(String statName, float scale) {
- if (statsJson.has(statName)) {
- statsJson.add(statName, new JsonPrimitive(statsJson.get(statName).getAsFloat() * scale));
- }
- }
-
- public void scaleAll(float scale) {
- for (Map.Entry<String, JsonElement> statEntry : statsJson.entrySet()) {
- statsJson.add(statEntry.getKey(), new JsonPrimitive(statEntry.getValue().getAsFloat() * scale));
- }
+ private static final HashMap<String, Pattern> STAT_PATTERN_MAP = new HashMap<String, Pattern>() {
+ {
+ put(HEALTH, Pattern.compile("^Health: ((?:\\+|-)[0-9]+)"));
+ put(DEFENCE, Pattern.compile("^Defense: ((?:\\+|-)[0-9]+)"));
+ put(STRENGTH, Pattern.compile("^Strength: ((?:\\+|-)[0-9]+)"));
+ put(SPEED, Pattern.compile("^Speed: ((?:\\+|-)[0-9]+)"));
+ put(CRIT_CHANCE, Pattern.compile("^Crit Chance: ((?:\\+|-)[0-9]+)"));
+ put(CRIT_DAMAGE, Pattern.compile("^Crit Damage: ((?:\\+|-)[0-9]+)"));
+ put(BONUS_ATTACK_SPEED, Pattern.compile("^Bonus Attack Speed: ((?:\\+|-)[0-9]+)"));
+ put(INTELLIGENCE, Pattern.compile("^Intelligence: ((?:\\+|-)[0-9]+)"));
+ put(SEA_CREATURE_CHANCE, Pattern.compile("^Sea Creature Chance: ((?:\\+|-)[0-9]+)"));
+ put("ferocity", Pattern.compile("^Ferocity: ((?:\\+|-)[0-9]+)"));
+ put("ability_damage", Pattern.compile("^Ability Damage: ((?:\\+|-)[0-9]+)"));
}
-
- public void addStat(String statName, float amount) {
- if (!statsJson.has(statName)) {
- statsJson.add(statName, new JsonPrimitive(amount));
- } else {
- JsonPrimitive e = statsJson.get(statName).getAsJsonPrimitive();
- statsJson.add(statName, new JsonPrimitive(e.getAsFloat() + amount));
- }
- }
- }
+ };
public static Stats getBaseStats() {
JsonObject misc = Constants.MISC;
@@ -169,29 +141,26 @@ public class PlayerStats {
return bonus;
}
- private static Stats getSkillBonus(JsonObject skillInfo) {
+ private static Stats getSkillBonus(Map<String, ProfileViewer.Level> skyblockInfo) {
JsonObject bonuses = Constants.BONUSES;
if (bonuses == null) return null;
Stats skillBonus = new Stats();
- for (Map.Entry<String, JsonElement> entry : skillInfo.entrySet()) {
- if (entry.getKey().startsWith("level_")) {
- String skill = entry.getKey().substring("level_".length());
- JsonElement element = Utils.getElement(bonuses, "bonus_stats." + skill);
- if (element != null && element.isJsonObject()) {
- JsonObject skillStatMap = element.getAsJsonObject();
-
- Stats currentBonus = new Stats();
- for (int i = 1; i <= entry.getValue().getAsFloat(); i++) {
- if (skillStatMap.has("" + i)) {
- currentBonus = new Stats();
- for (Map.Entry<String, JsonElement> entry2 : skillStatMap.get("" + i).getAsJsonObject().entrySet()) {
- currentBonus.addStat(entry2.getKey(), entry2.getValue().getAsFloat());
- }
+ for (Map.Entry<String, ProfileViewer.Level> entry : skyblockInfo.entrySet()) {
+ JsonElement element = Utils.getElement(bonuses, "bonus_stats." + entry.getKey());
+ if (element != null && element.isJsonObject()) {
+ JsonObject skillStatMap = element.getAsJsonObject();
+
+ Stats currentBonus = new Stats();
+ for (int i = 1; i <= entry.getValue().level; i++) {
+ if (skillStatMap.has("" + i)) {
+ currentBonus = new Stats();
+ for (Map.Entry<String, JsonElement> entry2 : skillStatMap.get("" + i).getAsJsonObject().entrySet()) {
+ currentBonus.addStat(entry2.getKey(), entry2.getValue().getAsFloat());
}
- skillBonus.add(currentBonus);
}
+ skillBonus.add(currentBonus);
}
}
}
@@ -237,8 +206,7 @@ public class PlayerStats {
}
private static float harpBonus(JsonObject profile) {
- String talk_to_melody =
- Utils.getElementAsString(Utils.getElement(profile, "objectives.talk_to_melody.status"), "INCOMPLETE");
+ String talk_to_melody = Utils.getElementAsString(Utils.getElement(profile, "objectives.talk_to_melody.status"), "INCOMPLETE");
if (talk_to_melody.equalsIgnoreCase("COMPLETE")) {
return 26;
} else {
@@ -246,11 +214,24 @@ public class PlayerStats {
}
}
- public static Stats getPassiveBonuses(JsonObject skillInfo, JsonObject profile) {
+ private static float hotmFortune(JsonObject profile, Map<String, ProfileViewer.Level> skyblockInfo) {
+ int miningLevelFortune = (int) (4 * (float) Math.floor(skyblockInfo.get("mining").level));
+ int miningFortuneStat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_fortune"), 0)) * 5);
+ int miningFortune2Stat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_fortune_2"), 0)) * 5);
+ return miningFortuneStat + miningFortune2Stat + miningLevelFortune;
+ }
+
+ private static float hotmSpeed(JsonObject profile) {
+ int miningSpeedStat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_speed"), 0)) * 20);
+ int miningSpeed2Stat = ((Utils.getElementAsInt(Utils.getElement(profile, "mining_core.nodes.mining_speed_2"), 0)) * 40);
+ return miningSpeedStat + miningSpeed2Stat;
+ }
+
+ public static Stats getPassiveBonuses(Map<String, ProfileViewer.Level> skyblockInfo, JsonObject profile) {
Stats passiveBonuses = new Stats();
Stats fairyBonus = getFairyBonus((int) Utils.getElementAsFloat(Utils.getElement(profile, "fairy_exchanges"), 0));
- Stats skillBonus = getSkillBonus(skillInfo);
+ Stats skillBonus = getSkillBonus(skyblockInfo);
Stats petBonus = getTamingBonus(profile);
if (skillBonus == null || petBonus == null) {
@@ -265,6 +246,15 @@ public class PlayerStats {
return passiveBonuses;
}
+ public static Stats getHOTMBonuses(Map<String, ProfileViewer.Level> skyblockInfo, JsonObject profile) {
+ Stats hotmBonuses = new Stats();
+
+ hotmBonuses.addStat(MINING_FORTUNE, hotmFortune(profile, skyblockInfo));
+ hotmBonuses.addStat(MINING_SPEED, hotmSpeed(profile));
+
+ return hotmBonuses;
+ }
+
private static String getFullset(JsonArray armor, int ignore) {
String fullset = null;
for (int i = 0; i < armor.size(); i++) {
@@ -296,7 +286,7 @@ public class PlayerStats {
Stats stats,
JsonObject inventoryInfo,
JsonObject collectionInfo,
- JsonObject skillInfo,
+ Map<String, ProfileViewer.Level> skyblockInfo,
JsonObject profile
) {
JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
@@ -310,7 +300,8 @@ public class PlayerStats {
case "LAPIS_ARMOR_":
bonuses.addStat(HEALTH, 60);
break;
- case "EMERALD_ARMOR_": {
+ case "EMERALD_ARMOR_":
+ {
int bonus = (int) Math.floor(Utils.getElementAsFloat(Utils.getElement(collectionInfo, "EMERALD"), 0) / 3000);
bonuses.addStat(HEALTH, bonus);
bonuses.addStat(DEFENCE, bonus);
@@ -329,10 +320,7 @@ public class PlayerStats {
bonuses.addStat(HEALTH, 50 * Math.round(stats.get(CRIT_DAMAGE)));
break;
case "ANGLER_":
- bonuses.addStat(
- HEALTH,
- 10 * (float) Math.floor(Utils.getElementAsFloat(Utils.getElement(skillInfo, "level_skill_fishing"), 0))
- );
+ bonuses.addStat(HEALTH, 10 * (float) Math.floor(skyblockInfo.get("fishing").level));
bonuses.addStat(SEA_CREATURE_CHANCE, 4);
break;
case "ARMOR_OF_MAGMA_":
@@ -373,20 +361,6 @@ public class PlayerStats {
return bonuses;
}
- private static final HashMap<String, Pattern> STAT_PATTERN_MAP = new HashMap<String, Pattern>() {{
- put(HEALTH, Pattern.compile("^Health: ((?:\\+|-)[0-9]+)"));
- put(DEFENCE, Pattern.compile("^Defense: ((?:\\+|-)[0-9]+)"));
- put(STRENGTH, Pattern.compile("^Strength: ((?:\\+|-)[0-9]+)"));
- put(SPEED, Pattern.compile("^Speed: ((?:\\+|-)[0-9]+)"));
- put(CRIT_CHANCE, Pattern.compile("^Crit Chance: ((?:\\+|-)[0-9]+)"));
- put(CRIT_DAMAGE, Pattern.compile("^Crit Damage: ((?:\\+|-)[0-9]+)"));
- put(BONUS_ATTACK_SPEED, Pattern.compile("^Bonus Attack Speed: ((?:\\+|-)[0-9]+)"));
- put(INTELLIGENCE, Pattern.compile("^Intelligence: ((?:\\+|-)[0-9]+)"));
- put(SEA_CREATURE_CHANCE, Pattern.compile("^Sea Creature Chance: ((?:\\+|-)[0-9]+)"));
- put("ferocity", Pattern.compile("^Ferocity: ((?:\\+|-)[0-9]+)"));
- put("ability_damage", Pattern.compile("^Ability Damage: ((?:\\+|-)[0-9]+)"));
- }};
-
private static Stats getStatForItem(String internalname, JsonObject item, JsonArray lore) {
Stats stats = new Stats();
for (int i = 0; i < lore.size(); i++) {
@@ -450,8 +424,7 @@ public class PlayerStats {
if (itemBonuses.containsKey(internalname)) {
continue;
}
- if (!talismanOnly ||
- Utils.checkItemType(item.get("lore").getAsJsonArray(), true, "ACCESSORY", "HATCCESSORY") >= 0) {
+ if (!talismanOnly || Utils.checkItemType(item.get("lore").getAsJsonArray(), true, "ACCESSORY", "HATCCESSORY") >= 0) {
Stats itemBonus = getStatForItem(internalname, item, item.get("lore").getAsJsonArray());
itemBonuses.put(internalname, itemBonus);
@@ -483,13 +456,21 @@ public class PlayerStats {
JsonObject petnums = Constants.PETNUMS;
if (petsJson == null || petnums == null) return new Stats();
- if (petsInfo != null && petsInfo.has("active_pet") && petsInfo.get("active_pet") != null &&
- petsInfo.get("active_pet").isJsonObject()) {
+ if (
+ petsInfo != null &&
+ petsInfo.has("active_pet") &&
+ petsInfo.get("active_pet") != null &&
+ petsInfo.get("active_pet").isJsonObject()
+ ) {
JsonObject pet = petsInfo.get("active_pet").getAsJsonObject();
- if (pet.has("type") && pet.get("type") != null &&
- pet.has("tier") && pet.get("tier") != null &&
- pet.has("exp") && pet.get("exp") != null) {
-
+ if (
+ pet.has("type") &&
+ pet.get("type") != null &&
+ pet.has("tier") &&
+ pet.get("tier") != null &&
+ pet.has("exp") &&
+ pet.get("exp") != null
+ ) {
String petname = pet.get("type").getAsString();
String tier = pet.get("tier").getAsString();
String heldItem = Utils.getElementAsString(pet.get("heldItem"), null);
@@ -502,13 +483,16 @@ public class PlayerStats {
float exp = pet.get("exp").getAsFloat();
if (tierNum == null) return new Stats();
- if (pet.has("heldItem") && !pet.get("heldItem").isJsonNull() &&
- pet.get("heldItem").getAsString().equals("PET_ITEM_TIER_BOOST")) {
+ if (
+ pet.has("heldItem") &&
+ !pet.get("heldItem").isJsonNull() &&
+ pet.get("heldItem").getAsString().equals("PET_ITEM_TIER_BOOST")
+ ) {
tierNum = "" + (Integer.parseInt(tierNum) + 1);
}
GuiProfileViewer.PetLevel levelObj = GuiProfileViewer.getPetLevel(petname, tier, exp);
-
+ if (levelObj == null) return null;
float level = levelObj.level;
float currentLevelRequirement = levelObj.currentLevelRequirement;
float maxXP = levelObj.maxXP;
@@ -551,18 +535,15 @@ public class PlayerStats {
String key = entryBoost.getKey().toLowerCase();
try {
stats.addStat(key, entryBoost.getValue());
- } catch (Exception ignored) {
- }
+ } catch (Exception ignored) {}
}
-
}
if (petStatBootsMult != null) {
for (Map.Entry<String, Float> entryBoost : petStatBootsMult.entrySet()) {
String key = entryBoost.getKey().toLowerCase();
try {
stats.scale(key, entryBoost.getValue());
- } catch (Exception ignored) {
- }
+ } catch (Exception ignored) {}
}
}
}
@@ -619,24 +600,30 @@ public class PlayerStats {
}
for (Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) {
- if (statEntry.getKey().equals(CRIT_DAMAGE) ||
- statEntry.getKey().equals(INTELLIGENCE) ||
- statEntry.getKey().equals(BONUS_ATTACK_SPEED)) continue;
+ if (
+ statEntry.getKey().equals(CRIT_DAMAGE) ||
+ statEntry.getKey().equals(INTELLIGENCE) ||
+ statEntry.getKey().equals(BONUS_ATTACK_SPEED)
+ ) continue;
stats.statsJson.add(statEntry.getKey(), new JsonPrimitive(Math.max(0, statEntry.getValue().getAsFloat())));
}
}
public static Stats getStats(
- JsonObject skillInfo, JsonObject inventoryInfo, JsonObject collectionInfo,
- JsonObject petsInfo, JsonObject profile
+ Map<String, ProfileViewer.Level> skyblockInfo,
+ JsonObject inventoryInfo,
+ JsonObject collectionInfo,
+ JsonObject petsInfo,
+ JsonObject profile
) {
- if (skillInfo == null || inventoryInfo == null || collectionInfo == null || profile == null) return null;
+ if (skyblockInfo == null || inventoryInfo == null || collectionInfo == null || profile == null) return null;
JsonArray armor = Utils.getElement(inventoryInfo, "inv_armor").getAsJsonArray();
JsonArray inventory = Utils.getElement(inventoryInfo, "inv_contents").getAsJsonArray();
JsonArray talisman_bag = Utils.getElement(inventoryInfo, "talisman_bag").getAsJsonArray();
- Stats passiveBonuses = getPassiveBonuses(skillInfo, profile);
+ Stats passiveBonuses = getPassiveBonuses(skyblockInfo, profile);
+ Stats hotmBonuses = getHOTMBonuses(skyblockInfo, profile);
Stats armorBonuses = getItemBonuses(false, armor);
Stats talismanBonuses = getItemBonuses(true, inventory, talisman_bag);
@@ -650,10 +637,11 @@ public class PlayerStats {
}
Stats petBonus = getPetStatBonuses(petsInfo);
+ if (petBonus == null) return null;
- stats = stats.add(passiveBonuses).add(armorBonuses).add(talismanBonuses).add(petBonus);
+ stats = stats.add(passiveBonuses).add(armorBonuses).add(talismanBonuses).add(petBonus).add(hotmBonuses);
- stats.add(getSetBonuses(stats, inventoryInfo, collectionInfo, skillInfo, profile));
+ stats.add(getSetBonuses(stats, inventoryInfo, collectionInfo, skyblockInfo, profile));
stats.scaleAll(getStatMult(inventoryInfo));
@@ -661,4 +649,215 @@ public class PlayerStats {
return stats;
}
+
+ /**
+ * Calculates the amount of Magical Power the player has using the list of accessories
+ *
+ * @param inventoryInfo inventory info object
+ * @return the amount of Magical Power or -1
+ * @see io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer.Profile#getInventoryInfo(String)
+ */
+ public static int getMagicalPower(JsonObject inventoryInfo) {
+ if (inventoryInfo == null || !inventoryInfo.has("talisman_bag") || !inventoryInfo.get("talisman_bag").isJsonArray()) {
+ return -1;
+ }
+
+ Map<String, Integer> accessories = JsonUtils.getJsonArrayAsStream(inventoryInfo.get("talisman_bag").getAsJsonArray())
+ .map(o -> {
+ try {
+ return JsonToNBT.getTagFromJson(o.getAsJsonObject().get("nbttag").getAsString());
+ } catch (Exception ignored) {
+ return null;
+ }
+ }).filter(Objects::nonNull).map(tag -> {
+ NBTTagList loreTagList = tag.getCompoundTag("display").getTagList("Lore", 8);
+ String lastElement = loreTagList.getStringTagAt(loreTagList.tagCount() - 1);
+ if (lastElement.contains(EnumChatFormatting.OBFUSCATED.toString())) {
+ lastElement = lastElement.substring(lastElement.indexOf(' ')).trim().substring(4);
+ }
+ JsonArray lastElementJsonArray = new JsonArray();
+ lastElementJsonArray.add(new JsonPrimitive(lastElement));
+ return new AbstractMap.SimpleEntry<>(
+ tag.getCompoundTag("ExtraAttributes").getString("id"),
+ Utils.getRarityFromLore(lastElementJsonArray)
+ );
+ }).sorted(Comparator.comparingInt(e -> -e.getValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2)->v1, LinkedHashMap::new));
+
+ Set<String> ignoredTalismans = new HashSet<>();
+ int powderAmount = 0;
+ for (Map.Entry<String, Integer> entry : accessories.entrySet()) {
+ if (ignoredTalismans.contains(entry.getKey())) {
+ continue;
+ }
+
+ JsonArray children = Utils.getElementOrDefault(Constants.PARENTS, entry.getKey(), new JsonArray()).getAsJsonArray();
+ for (JsonElement child : children) {
+ ignoredTalismans.add(child.getAsString());
+ }
+
+ if (entry.getKey().equals("HEGEMONY_ARTIFACT")) {
+ switch (entry.getValue()) {
+ case 4:
+ powderAmount += 16;
+ break;
+ case 5:
+ powderAmount += 22;
+ break;
+ }
+ }
+ switch (entry.getValue()) {
+ case 0:
+ case 6:
+ powderAmount += 3;
+ break;
+ case 1:
+ case 7:
+ powderAmount += 5;
+ break;
+ case 2:
+ powderAmount += 8;
+ break;
+ case 3:
+ powderAmount += 12;
+ break;
+ case 4:
+ powderAmount += 16;
+ break;
+ case 5:
+ powderAmount += 22;
+ break;
+ }
+ }
+ return powderAmount;
+ }
+
+ /**
+ * Finds the Magical Power the player selected if applicable
+ *
+ * @param profileInfo profile information object
+ * @return selected magical power as a String or null
+ * @see io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer.Profile#getProfileInformation(String)
+ */
+ public static @Nullable String getSelectedMagicalPower(JsonObject profileInfo) {
+ String abs = "accessory_bag_storage";
+
+ if (
+ profileInfo == null ||
+ !profileInfo.has(abs) ||
+ !profileInfo.get(abs).isJsonObject() ||
+ !profileInfo.get(abs).getAsJsonObject().has("selected_power")
+ ) {
+ return null;
+ }
+ String selectedPower = profileInfo.get(abs).getAsJsonObject().get("selected_power").getAsString();
+ return selectedPower.substring(0, 1).toUpperCase() + selectedPower.substring(1);
+ }
+
+ public static @Nullable QuiverInfo getQuiverInfo(JsonObject inventoryInfo, JsonObject profileInfo) {
+ if (inventoryInfo == null
+ || !inventoryInfo.has("quiver")
+ || !inventoryInfo.get("quiver").isJsonArray()) {
+ return null;
+ }
+ QuiverInfo quiverInfo = new QuiverInfo();
+ quiverInfo.arrows = new HashMap<>();
+
+ JsonArray quiver = inventoryInfo.getAsJsonArray("quiver");
+ for (JsonElement quiverEntry : quiver) {
+ if (quiverEntry == null || quiverEntry.isJsonNull() || !quiverEntry.isJsonObject()) {
+ continue;
+ }
+ JsonObject stack = quiverEntry.getAsJsonObject();
+ if (!stack.has("internalname") || !stack.has("count")) {
+ continue;
+ }
+ String internalName = stack.get("internalname").getAsString();
+ int count = stack.get("count").getAsInt();
+
+ quiverInfo.arrows.computeIfPresent(internalName, (key, existing) -> existing + count);
+ quiverInfo.arrows.putIfAbsent(internalName, count);
+ }
+
+ if (profileInfo.has("favorite_arrow")) {
+ quiverInfo.selectedArrow = profileInfo.get("favorite_arrow").getAsString();
+ }
+
+ return quiverInfo;
+ }
+
+ public static class Stats {
+
+ JsonObject statsJson = new JsonObject();
+
+ /*public float health;
+ public float defence;
+ public float strength;
+ public float speed;
+ public float crit_chance;
+ public float crit_damage;
+ public float bonus_attack_speed;
+ public float intelligence;
+ public float sea_creature_chance;
+ public float magic_find;
+ public float pet_luck;*/
+
+ public Stats(Stats... statses) {
+ for (Stats stats : statses) {
+ add(stats);
+ }
+ }
+
+ /*@Override
+ public String toString() {
+ return String.format("{health=%s,defence=%s,strength=%s,speed=%s,crit_chance=%s,crit_damage=%s," +
+ "bonus_attack_speed=%s,intelligence=%s,sea_creature_chance=%s,magic_find=%s,pet_luck=%s}",
+ stats.get("health"), defence, strength, speed, crit_chance, crit_damage, bonus_attack_speed, intelligence,
+ sea_creature_chance, magic_find, pet_luck
+ );
+ }*/
+
+ public float get(String statName) {
+ if (statsJson.has(statName)) {
+ return statsJson.get(statName).getAsFloat();
+ } else {
+ return 0;
+ }
+ }
+
+ public Stats add(Stats stats) {
+ for (Map.Entry<String, JsonElement> statEntry : stats.statsJson.entrySet()) {
+ if (statEntry.getValue().isJsonPrimitive() && ((JsonPrimitive) statEntry.getValue()).isNumber()) {
+ if (!statsJson.has(statEntry.getKey())) {
+ statsJson.add(statEntry.getKey(), statEntry.getValue());
+ } else {
+ JsonPrimitive e = statsJson.get(statEntry.getKey()).getAsJsonPrimitive();
+ float statNum = e.getAsFloat() + statEntry.getValue().getAsFloat();
+ statsJson.add(statEntry.getKey(), new JsonPrimitive(statNum));
+ }
+ }
+ }
+ return this;
+ }
+
+ public void scale(String statName, float scale) {
+ if (statsJson.has(statName)) {
+ statsJson.add(statName, new JsonPrimitive(statsJson.get(statName).getAsFloat() * scale));
+ }
+ }
+
+ public void scaleAll(float scale) {
+ for (Map.Entry<String, JsonElement> statEntry : statsJson.entrySet()) {
+ statsJson.add(statEntry.getKey(), new JsonPrimitive(statEntry.getValue().getAsFloat() * scale));
+ }
+ }
+
+ public void addStat(String statName, float amount) {
+ if (!statsJson.has(statName)) {
+ statsJson.add(statName, new JsonPrimitive(amount));
+ } else {
+ JsonPrimitive e = statsJson.get(statName).getAsJsonPrimitive();
+ statsJson.add(statName, new JsonPrimitive(e.getAsFloat() + amount));
+ }
+ }
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
index 674f08af..4aeafb9e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.profileviewer;
import com.google.gson.JsonArray;
@@ -20,230 +39,419 @@ import net.minecraft.util.EnumChatFormatting;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ProfileViewer {
- private final NEUManager manager;
-
- public ProfileViewer(NEUManager manager) {
- this.manager = manager;
- }
-
- private static final HashMap<String, String> petRarityToNumMap = new HashMap<String, String>() {{
- put("COMMON", "0");
- put("UNCOMMON", "1");
- put("RARE", "2");
- put("EPIC", "3");
- put("LEGENDARY", "4");
- put("MYTHIC", "5");
- }};
+ private static final HashMap<String, String> petRarityToNumMap = new HashMap<String, String>() {
+ {
+ put("COMMON", "0");
+ put("UNCOMMON", "1");
+ put("RARE", "2");
+ put("EPIC", "3");
+ put("LEGENDARY", "4");
+ put("MYTHIC", "5");
+ }
+ };
private static final LinkedHashMap<String, ItemStack> skillToSkillDisplayMap =
- new LinkedHashMap<String, ItemStack>() {{
- put("skill_taming", Utils.createItemStack(Items.spawn_egg, EnumChatFormatting.LIGHT_PURPLE + "Taming"));
- put("skill_mining", Utils.createItemStack(Items.stone_pickaxe, EnumChatFormatting.GRAY + "Mining"));
- put(
- "skill_foraging",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.sapling), EnumChatFormatting.DARK_GREEN + "Foraging")
- );
- put(
- "skill_enchanting",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.enchanting_table), EnumChatFormatting.GREEN + "Enchanting")
- );
- put(
- "skill_carpentry",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.crafting_table), EnumChatFormatting.DARK_RED + "Carpentry")
- );
- put("skill_farming", Utils.createItemStack(Items.golden_hoe, EnumChatFormatting.YELLOW + "Farming"));
- put("skill_combat", Utils.createItemStack(Items.stone_sword, EnumChatFormatting.RED + "Combat"));
- put("skill_fishing", Utils.createItemStack(Items.fishing_rod, EnumChatFormatting.AQUA + "Fishing"));
- put("skill_alchemy", Utils.createItemStack(Items.brewing_stand, EnumChatFormatting.BLUE + "Alchemy"));
- put(
- "skill_runecrafting",
- Utils.createItemStack(Items.magma_cream, EnumChatFormatting.DARK_PURPLE + "Runecrafting")
- );
- // put("skill_catacombs", Utils.createItemStack(Item.getItemFromBlock(Blocks.deadbush), EnumChatFormatting.GOLD+"Catacombs"));
- put("slayer_zombie", Utils.createItemStack(Items.rotten_flesh, EnumChatFormatting.GOLD + "Rev Slayer"));
- put("slayer_spider", Utils.createItemStack(Items.spider_eye, EnumChatFormatting.GOLD + "Tara Slayer"));
- put("slayer_wolf", Utils.createItemStack(Items.bone, EnumChatFormatting.GOLD + "Sven Slayer"));
- put("slayer_enderman", Utils.createItemStack(Items.ender_pearl, EnumChatFormatting.GOLD + "Ender Slayer"));
- }};
-
- private static final ItemStack CAT_FARMING =
- Utils.createItemStack(Items.golden_hoe, EnumChatFormatting.YELLOW + "Farming");
- private static final ItemStack CAT_MINING =
- Utils.createItemStack(Items.stone_pickaxe, EnumChatFormatting.GRAY + "Mining");
- private static final ItemStack CAT_COMBAT =
- Utils.createItemStack(Items.stone_sword, EnumChatFormatting.RED + "Combat");
- private static final ItemStack CAT_FORAGING =
- Utils.createItemStack(Item.getItemFromBlock(Blocks.sapling), EnumChatFormatting.DARK_GREEN + "Foraging");
- private static final ItemStack CAT_FISHING =
- Utils.createItemStack(Items.fishing_rod, EnumChatFormatting.AQUA + "Fishing");
-
+ new LinkedHashMap<String, ItemStack>() {
+ {
+ put("taming", Utils.createItemStack(Items.spawn_egg, EnumChatFormatting.LIGHT_PURPLE + "Taming"));
+ put("mining", Utils.createItemStack(Items.stone_pickaxe, EnumChatFormatting.GRAY + "Mining"));
+ put(
+ "foraging",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.sapling), EnumChatFormatting.DARK_GREEN + "Foraging")
+ );
+ put(
+ "enchanting",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.enchanting_table), EnumChatFormatting.GREEN + "Enchanting")
+ );
+ put(
+ "carpentry",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.crafting_table), EnumChatFormatting.DARK_RED + "Carpentry")
+ );
+ put("farming", Utils.createItemStack(Items.golden_hoe, EnumChatFormatting.YELLOW + "Farming"));
+ put("combat", Utils.createItemStack(Items.stone_sword, EnumChatFormatting.RED + "Combat"));
+ put("fishing", Utils.createItemStack(Items.fishing_rod, EnumChatFormatting.AQUA + "Fishing"));
+ put("alchemy", Utils.createItemStack(Items.brewing_stand, EnumChatFormatting.BLUE + "Alchemy"));
+ put("runecrafting", Utils.createItemStack(Items.magma_cream, EnumChatFormatting.DARK_PURPLE + "Runecrafting"));
+ put("social", Utils.createItemStack(Items.emerald, EnumChatFormatting.DARK_GREEN + "Social"));
+ // put("catacombs", Utils.createItemStack(Item.getItemFromBlock(Blocks.deadbush), EnumChatFormatting.GOLD+"Catacombs"));
+ put("zombie", Utils.createItemStack(Items.rotten_flesh, EnumChatFormatting.GOLD + "Rev Slayer"));
+ put("spider", Utils.createItemStack(Items.spider_eye, EnumChatFormatting.GOLD + "Tara Slayer"));
+ put("wolf", Utils.createItemStack(Items.bone, EnumChatFormatting.GOLD + "Sven Slayer"));
+ put("enderman", Utils.createItemStack(Items.ender_pearl, EnumChatFormatting.GOLD + "Ender Slayer"));
+ put("blaze", Utils.createItemStack(Items.blaze_rod, EnumChatFormatting.GOLD + "Blaze Slayer"));
+ }
+ };
+ private static final ItemStack CAT_FARMING = Utils.createItemStack(
+ Items.golden_hoe,
+ EnumChatFormatting.YELLOW + "Farming"
+ );
+ private static final ItemStack CAT_MINING = Utils.createItemStack(
+ Items.stone_pickaxe,
+ EnumChatFormatting.GRAY + "Mining"
+ );
+ private static final ItemStack CAT_COMBAT = Utils.createItemStack(
+ Items.stone_sword,
+ EnumChatFormatting.RED + "Combat"
+ );
+ private static final ItemStack CAT_FORAGING = Utils.createItemStack(
+ Item.getItemFromBlock(Blocks.sapling),
+ EnumChatFormatting.DARK_GREEN + "Foraging"
+ );
+ private static final ItemStack CAT_FISHING = Utils.createItemStack(
+ Items.fishing_rod,
+ EnumChatFormatting.AQUA + "Fishing"
+ );
private static final LinkedHashMap<ItemStack, List<String>> collectionCatToCollectionMap =
- new LinkedHashMap<ItemStack, List<String>>() {{
- put(CAT_FARMING, Utils.createList("WHEAT", "CARROT_ITEM", "POTATO_ITEM", "PUMPKIN", "MELON", "SEEDS",
- "MUSHROOM_COLLECTION", "INK_SACK:3", "CACTUS", "SUGAR_CANE", "FEATHER", "LEATHER", "PORK", "RAW_CHICKEN",
- "MUTTON", "RABBIT", "NETHER_STALK"
- ));
- put(CAT_MINING, Utils.createList("COBBLESTONE", "COAL", "IRON_INGOT", "GOLD_INGOT", "DIAMOND", "INK_SACK:4",
- "EMERALD", "REDSTONE", "QUARTZ", "OBSIDIAN", "GLOWSTONE_DUST", "GRAVEL", "ICE", "NETHERRACK", "SAND",
- "ENDER_STONE", null, "MITHRIL_ORE", "HARD_STONE", "GEMSTONE_COLLECTION"
- ));
- put(CAT_COMBAT, Utils.createList("ROTTEN_FLESH", "BONE", "STRING", "SPIDER_EYE", "SULPHUR", "ENDER_PEARL",
- "GHAST_TEAR", "SLIME_BALL", "BLAZE_ROD", "MAGMA_CREAM", null, null, null
- ));
- put(CAT_FORAGING, Utils.createList("LOG", "LOG:1", "LOG:2", "LOG_2:1", "LOG_2", "LOG:3", null));
- put(CAT_FISHING, Utils.createList("RAW_FISH", "RAW_FISH:1", "RAW_FISH:2", "RAW_FISH:3", "PRISMARINE_SHARD",
- "PRISMARINE_CRYSTALS", "CLAY_BALL", "WATER_LILY", "INK_SACK", "SPONGE"
- ));
-
- }};
-
+ new LinkedHashMap<ItemStack, List<String>>() {
+ {
+ put(
+ CAT_FARMING,
+ Utils.createList(
+ "WHEAT",
+ "CARROT_ITEM",
+ "POTATO_ITEM",
+ "PUMPKIN",
+ "MELON",
+ "SEEDS",
+ "MUSHROOM_COLLECTION",
+ "INK_SACK:3",
+ "CACTUS",
+ "SUGAR_CANE",
+ "FEATHER",
+ "LEATHER",
+ "PORK",
+ "RAW_CHICKEN",
+ "MUTTON",
+ "RABBIT",
+ "NETHER_STALK"
+ )
+ );
+ put(
+ CAT_MINING,
+ Utils.createList(
+ "COBBLESTONE",
+ "COAL",
+ "IRON_INGOT",
+ "GOLD_INGOT",
+ "DIAMOND",
+ "INK_SACK:4",
+ "EMERALD",
+ "REDSTONE",
+ "QUARTZ",
+ "OBSIDIAN",
+ "GLOWSTONE_DUST",
+ "GRAVEL",
+ "ICE",
+ "NETHERRACK",
+ "SAND",
+ "ENDER_STONE",
+ null,
+ "MITHRIL_ORE",
+ "HARD_STONE",
+ "GEMSTONE_COLLECTION",
+ "MYCEL",
+ "SAND:1",
+ "SULPHUR_ORE"
+ )
+ );
+ put(
+ CAT_COMBAT,
+ Utils.createList(
+ "ROTTEN_FLESH",
+ "BONE",
+ "STRING",
+ "SPIDER_EYE",
+ "SULPHUR",
+ "ENDER_PEARL",
+ "GHAST_TEAR",
+ "SLIME_BALL",
+ "BLAZE_ROD",
+ "MAGMA_CREAM",
+ null,
+ null,
+ null,
+ null,
+ "CHILI_PEPPER"
+ )
+ );
+ put(CAT_FORAGING, Utils.createList("LOG", "LOG:1", "LOG:2", "LOG_2:1", "LOG_2", "LOG:3", null));
+ put(
+ CAT_FISHING,
+ Utils.createList(
+ "RAW_FISH",
+ "RAW_FISH:1",
+ "RAW_FISH:2",
+ "RAW_FISH:3",
+ "PRISMARINE_SHARD",
+ "PRISMARINE_CRYSTALS",
+ "CLAY_BALL",
+ "WATER_LILY",
+ "INK_SACK",
+ "SPONGE",
+ "MAGMA_FISH"
+ )
+ );
+ }
+ };
private static final LinkedHashMap<ItemStack, List<String>> collectionCatToMinionMap =
- new LinkedHashMap<ItemStack, List<String>>() {{
- put(CAT_FARMING, Utils.createList("WHEAT", "CARROT", "POTATO", "PUMPKIN", "MELON", null, "MUSHROOM",
- "COCOA", "CACTUS", "SUGAR_CANE", "CHICKEN", "COW", "PIG", null, "SHEEP", "RABBIT", "NETHER_WARTS"
- ));
- put(CAT_MINING, Utils.createList("COBBLESTONE", "COAL", "IRON", "GOLD", "DIAMOND", "LAPIS", "EMERALD",
- "REDSTONE", "QUARTZ", "OBSIDIAN", "GLOWSTONE", "GRAVEL", "ICE", null, "SAND", "ENDER_STONE", "SNOW",
- "MITHRIL", "HARD_STONE", null
- ));
- put(CAT_COMBAT, Utils.createList("ZOMBIE", "SKELETON", "SPIDER", "CAVESPIDER", "CREEPER", "ENDERMAN",
- "GHAST", "SLIME", "BLAZE", "MAGMA_CUBE", "REVENANT", "TARANTULA", "VOIDLING"
- ));
- put(CAT_FORAGING, Utils.createList("OAK", "SPRUCE", "BIRCH", "DARK_OAK", "ACACIA", "JUNGLE", "FLOWER"));
- put(CAT_FISHING, Utils.createList("FISHING", null, null, null, null, null, "CLAY", null, null, null));
-
- }};
-
+ new LinkedHashMap<ItemStack, List<String>>() {
+ {
+ put(
+ CAT_FARMING,
+ Utils.createList(
+ "WHEAT",
+ "CARROT",
+ "POTATO",
+ "PUMPKIN",
+ "MELON",
+ null,
+ "MUSHROOM",
+ "COCOA",
+ "CACTUS",
+ "SUGAR_CANE",
+ "CHICKEN",
+ "COW",
+ "PIG",
+ null,
+ "SHEEP",
+ "RABBIT",
+ "NETHER_WARTS"
+ )
+ );
+ put(
+ CAT_MINING,
+ Utils.createList(
+ "COBBLESTONE",
+ "COAL",
+ "IRON",
+ "GOLD",
+ "DIAMOND",
+ "LAPIS",
+ "EMERALD",
+ "REDSTONE",
+ "QUARTZ",
+ "OBSIDIAN",
+ "GLOWSTONE",
+ "GRAVEL",
+ "ICE",
+ null,
+ "SAND",
+ "ENDER_STONE",
+ "SNOW",
+ "MITHRIL",
+ "HARD_STONE",
+ null,
+ "MYCELIUM",
+ "RED_SAND",
+ null
+ )
+ );
+ put(
+ CAT_COMBAT,
+ Utils.createList(
+ "ZOMBIE",
+ "SKELETON",
+ "SPIDER",
+ "CAVESPIDER",
+ "CREEPER",
+ "ENDERMAN",
+ "GHAST",
+ "SLIME",
+ "BLAZE",
+ "MAGMA_CUBE",
+ "REVENANT",
+ "TARANTULA",
+ "VOIDLING",
+ "INFERNO"
+ )
+ );
+ put(CAT_FORAGING, Utils.createList("OAK", "SPRUCE", "BIRCH", "DARK_OAK", "ACACIA", "JUNGLE", "FLOWER"));
+ put(CAT_FISHING, Utils.createList("FISHING", null, null, null, null, null, "CLAY", null, null, null));
+ }
+ };
private static final LinkedHashMap<String, ItemStack> collectionToCollectionDisplayMap =
- new LinkedHashMap<String, ItemStack>() {{
- /* FARMING COLLECTIONS */
- put("WHEAT", Utils.createItemStack(Items.wheat, EnumChatFormatting.YELLOW + "Wheat"));
- put("CARROT_ITEM", Utils.createItemStack(Items.carrot, EnumChatFormatting.YELLOW + "Carrot"));
- put("POTATO_ITEM", Utils.createItemStack(Items.potato, EnumChatFormatting.YELLOW + "Potato"));
- put(
- "PUMPKIN",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.pumpkin), EnumChatFormatting.YELLOW + "Pumpkin")
- );
- put("MELON", Utils.createItemStack(Items.melon, EnumChatFormatting.YELLOW + "Melon"));
- put("SEEDS", Utils.createItemStack(Items.wheat_seeds, EnumChatFormatting.YELLOW + "Seeds"));
- put(
- "MUSHROOM_COLLECTION",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.red_mushroom), EnumChatFormatting.YELLOW + "Mushroom")
- );
- put("INK_SACK:3", Utils.createItemStack(Items.dye, EnumChatFormatting.YELLOW + "Cocoa Beans", 3));
- put("CACTUS", Utils.createItemStack(Item.getItemFromBlock(Blocks.cactus), EnumChatFormatting.YELLOW + "Cactus"));
- put("SUGAR_CANE", Utils.createItemStack(Items.reeds, EnumChatFormatting.YELLOW + "Sugar Cane"));
- put("FEATHER", Utils.createItemStack(Items.feather, EnumChatFormatting.YELLOW + "Feather"));
- put("LEATHER", Utils.createItemStack(Items.leather, EnumChatFormatting.YELLOW + "Leather"));
- put("PORK", Utils.createItemStack(Items.porkchop, EnumChatFormatting.YELLOW + "Porkchop"));
- put("RAW_CHICKEN", Utils.createItemStack(Items.chicken, EnumChatFormatting.YELLOW + "Chicken"));
- put("MUTTON", Utils.createItemStack(Items.mutton, EnumChatFormatting.YELLOW + "Mutton"));
- put("RABBIT", Utils.createItemStack(Items.rabbit, EnumChatFormatting.YELLOW + "Rabbit"));
- put("NETHER_STALK", Utils.createItemStack(Items.nether_wart, EnumChatFormatting.YELLOW + "Nether Wart"));
-
- /* MINING COLLECTIONS */
- put(
- "COBBLESTONE",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.cobblestone), EnumChatFormatting.GRAY + "Cobblestone")
- );
- put("COAL", Utils.createItemStack(Items.coal, EnumChatFormatting.GRAY + "Coal"));
- put("IRON_INGOT", Utils.createItemStack(Items.iron_ingot, EnumChatFormatting.GRAY + "Iron Ingot"));
- put("GOLD_INGOT", Utils.createItemStack(Items.gold_ingot, EnumChatFormatting.GRAY + "Gold Ingot"));
- put("DIAMOND", Utils.createItemStack(Items.diamond, EnumChatFormatting.GRAY + "Diamond"));
- put("INK_SACK:4", Utils.createItemStack(Items.dye, EnumChatFormatting.GRAY + "Lapis Lazuli", 4));
- put("EMERALD", Utils.createItemStack(Items.emerald, EnumChatFormatting.GRAY + "Emerald"));
- put("REDSTONE", Utils.createItemStack(Items.redstone, EnumChatFormatting.GRAY + "Redstone"));
- put("QUARTZ", Utils.createItemStack(Items.quartz, EnumChatFormatting.GRAY + "Nether Quartz"));
- put(
- "OBSIDIAN",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.obsidian), EnumChatFormatting.GRAY + "Obsidian")
- );
- put("GLOWSTONE_DUST", Utils.createItemStack(Items.glowstone_dust, EnumChatFormatting.GRAY + "Glowstone"));
- put("GRAVEL", Utils.createItemStack(Item.getItemFromBlock(Blocks.gravel), EnumChatFormatting.GRAY + "Gravel"));
- put("ICE", Utils.createItemStack(Item.getItemFromBlock(Blocks.ice), EnumChatFormatting.GRAY + "Ice"));
- put(
- "NETHERRACK",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.netherrack), EnumChatFormatting.GRAY + "Netherrack")
- );
- put("SAND", Utils.createItemStack(Item.getItemFromBlock(Blocks.sand), EnumChatFormatting.GRAY + "Sand"));
- put(
- "ENDER_STONE",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.end_stone), EnumChatFormatting.GRAY + "End Stone")
- );
- put("MITHRIL_ORE", Utils.createItemStack(Items.prismarine_crystals, EnumChatFormatting.GRAY + "Mithril"));
- put(
- "HARD_STONE",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.stone), EnumChatFormatting.GRAY + "Hard Stone")
- );
- put(
- "GEMSTONE_COLLECTION",
- Utils.createSkull(
- EnumChatFormatting.GRAY + "Gemstone",
- "e942eb66-a350-38e5-aafa-0dfc3e17b4ac",
- "ewogICJ0aW1lc3RhbXAiIDogMTYxODA4Mzg4ODc3MSwKICAicHJvZmlsZUlkIiA6ICJjNTBhZmE4YWJlYjk0ZTQ1OTRiZjFiNDI1YTk4MGYwMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUd29FQmFlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2FhYzE1ZjZmY2YyY2U5NjNlZjRjYTcxZjFhODY4NWFkYjk3ZWI3NjllMWQxMTE5NGNiYmQyZTk2NGE4ODk3OGMiCiAgICB9CiAgfQp9"
- )
- );
+ new LinkedHashMap<String, ItemStack>() {
+ {
+ /* FARMING COLLECTIONS */
+ put("WHEAT", Utils.createItemStack(Items.wheat, EnumChatFormatting.YELLOW + "Wheat"));
+ put("CARROT_ITEM", Utils.createItemStack(Items.carrot, EnumChatFormatting.YELLOW + "Carrot"));
+ put("POTATO_ITEM", Utils.createItemStack(Items.potato, EnumChatFormatting.YELLOW + "Potato"));
+ put(
+ "PUMPKIN",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.pumpkin), EnumChatFormatting.YELLOW + "Pumpkin")
+ );
+ put("MELON", Utils.createItemStack(Items.melon, EnumChatFormatting.YELLOW + "Melon"));
+ put("SEEDS", Utils.createItemStack(Items.wheat_seeds, EnumChatFormatting.YELLOW + "Seeds"));
+ put(
+ "MUSHROOM_COLLECTION",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.red_mushroom), EnumChatFormatting.YELLOW + "Mushroom")
+ );
+ put("INK_SACK:3", Utils.createItemStack(Items.dye, EnumChatFormatting.YELLOW + "Cocoa Beans", 3));
+ put(
+ "CACTUS",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.cactus), EnumChatFormatting.YELLOW + "Cactus")
+ );
+ put("SUGAR_CANE", Utils.createItemStack(Items.reeds, EnumChatFormatting.YELLOW + "Sugar Cane"));
+ put("FEATHER", Utils.createItemStack(Items.feather, EnumChatFormatting.YELLOW + "Feather"));
+ put("LEATHER", Utils.createItemStack(Items.leather, EnumChatFormatting.YELLOW + "Leather"));
+ put("PORK", Utils.createItemStack(Items.porkchop, EnumChatFormatting.YELLOW + "Raw Porkchop"));
+ put("RAW_CHICKEN", Utils.createItemStack(Items.chicken, EnumChatFormatting.YELLOW + "Raw Chicken"));
+ put("MUTTON", Utils.createItemStack(Items.mutton, EnumChatFormatting.YELLOW + "Mutton"));
+ put("RABBIT", Utils.createItemStack(Items.rabbit, EnumChatFormatting.YELLOW + "Raw Rabbit"));
+ put("NETHER_STALK", Utils.createItemStack(Items.nether_wart, EnumChatFormatting.YELLOW + "Nether Wart"));
+
+ /* MINING COLLECTIONS */
+ put(
+ "COBBLESTONE",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.cobblestone), EnumChatFormatting.GRAY + "Cobblestone")
+ );
+ put("COAL", Utils.createItemStack(Items.coal, EnumChatFormatting.GRAY + "Coal"));
+ put("IRON_INGOT", Utils.createItemStack(Items.iron_ingot, EnumChatFormatting.GRAY + "Iron Ingot"));
+ put("GOLD_INGOT", Utils.createItemStack(Items.gold_ingot, EnumChatFormatting.GRAY + "Gold Ingot"));
+ put("DIAMOND", Utils.createItemStack(Items.diamond, EnumChatFormatting.GRAY + "Diamond"));
+ put("INK_SACK:4", Utils.createItemStack(Items.dye, EnumChatFormatting.GRAY + "Lapis Lazuli", 4));
+ put("EMERALD", Utils.createItemStack(Items.emerald, EnumChatFormatting.GRAY + "Emerald"));
+ put("REDSTONE", Utils.createItemStack(Items.redstone, EnumChatFormatting.GRAY + "Redstone"));
+ put("QUARTZ", Utils.createItemStack(Items.quartz, EnumChatFormatting.GRAY + "Nether Quartz"));
+ put(
+ "OBSIDIAN",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.obsidian), EnumChatFormatting.GRAY + "Obsidian")
+ );
+ put("GLOWSTONE_DUST", Utils.createItemStack(Items.glowstone_dust, EnumChatFormatting.GRAY + "Glowstone Dust"));
+ put("GRAVEL", Utils.createItemStack(Item.getItemFromBlock(Blocks.gravel), EnumChatFormatting.GRAY + "Gravel"));
+ put("ICE", Utils.createItemStack(Item.getItemFromBlock(Blocks.ice), EnumChatFormatting.GRAY + "Ice"));
+ put(
+ "NETHERRACK",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.netherrack), EnumChatFormatting.GRAY + "Netherrack")
+ );
+ put("SAND", Utils.createItemStack(Item.getItemFromBlock(Blocks.sand), EnumChatFormatting.GRAY + "Sand"));
+ put(
+ "ENDER_STONE",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.end_stone), EnumChatFormatting.GRAY + "End Stone")
+ );
+ put("MITHRIL_ORE", Utils.createItemStack(Items.prismarine_crystals, EnumChatFormatting.GRAY + "Mithril"));
+ put(
+ "HARD_STONE",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.stone), EnumChatFormatting.GRAY + "Hard Stone")
+ );
+ put(
+ "GEMSTONE_COLLECTION",
+ Utils.createSkull(
+ EnumChatFormatting.GRAY + "Gemstone",
+ "e942eb66-a350-38e5-aafa-0dfc3e17b4ac",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxODA4Mzg4ODc3MSwKICAicHJvZmlsZUlkIiA6ICJjNTBhZmE4YWJlYjk0ZTQ1OTRiZjFiNDI1YTk4MGYwMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUd29FQmFlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2FhYzE1ZjZmY2YyY2U5NjNlZjRjYTcxZjFhODY4NWFkYjk3ZWI3NjllMWQxMTE5NGNiYmQyZTk2NGE4ODk3OGMiCiAgICB9CiAgfQp9"
+ )
+ );
+ put(
+ "MYCEL",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.mycelium), EnumChatFormatting.GRAY + "Mycelium")
+ );
+ put(
+ "SAND:1",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.sand), EnumChatFormatting.GRAY + "Red Sand", 1)
+ );
+ put("SULPHUR_ORE", Utils.createItemStack(Items.glowstone_dust, EnumChatFormatting.GRAY + "Sulphur"));
+
+ /* COMBAT COLLECTIONS */
+ put("ROTTEN_FLESH", Utils.createItemStack(Items.rotten_flesh, EnumChatFormatting.RED + "Rotten Flesh"));
+ put("BONE", Utils.createItemStack(Items.bone, EnumChatFormatting.RED + "Bone"));
+ put("STRING", Utils.createItemStack(Items.string, EnumChatFormatting.RED + "String"));
+ put("SPIDER_EYE", Utils.createItemStack(Items.spider_eye, EnumChatFormatting.RED + "Spider Eye"));
+ put("SULPHUR", Utils.createItemStack(Items.gunpowder, EnumChatFormatting.RED + "Gunpowder"));
+ put("ENDER_PEARL", Utils.createItemStack(Items.ender_pearl, EnumChatFormatting.RED + "Ender Pearl"));
+ put("GHAST_TEAR", Utils.createItemStack(Items.ghast_tear, EnumChatFormatting.RED + "Ghast Tear"));
+ put("SLIME_BALL", Utils.createItemStack(Items.slime_ball, EnumChatFormatting.RED + "Slimeball"));
+ put("BLAZE_ROD", Utils.createItemStack(Items.blaze_rod, EnumChatFormatting.RED + "Blaze Rod"));
+ put("MAGMA_CREAM", Utils.createItemStack(Items.magma_cream, EnumChatFormatting.RED + "Magma Cream"));
+ put(
+ "CHILI_PEPPER",
+ Utils.createSkull(
+ EnumChatFormatting.RED + "Chili Pepper",
+ "3d47abaa-b40b-3826-b20c-d83a7f053bd9",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjg1OWM4ZGYxMTA5YzA4YTc1NjI3NWYxZDI4ODdjMjc0ODA0OWZlMzM4Nzc3NjlhN2I0MTVkNTZlZGE0NjlkOCJ9fX0"
+ )
+ );
- /* COMBAT COLLECTIONS */
- put("ROTTEN_FLESH", Utils.createItemStack(Items.rotten_flesh, EnumChatFormatting.RED + "Rotten Flesh"));
- put("BONE", Utils.createItemStack(Items.bone, EnumChatFormatting.RED + "Bone"));
- put("STRING", Utils.createItemStack(Items.string, EnumChatFormatting.RED + "String"));
- put("SPIDER_EYE", Utils.createItemStack(Items.spider_eye, EnumChatFormatting.RED + "Spider Eye"));
- put("SULPHUR", Utils.createItemStack(Items.gunpowder, EnumChatFormatting.RED + "Gunpowder"));
- put("ENDER_PEARL", Utils.createItemStack(Items.ender_pearl, EnumChatFormatting.RED + "Ender Pearl"));
- put("GHAST_TEAR", Utils.createItemStack(Items.ghast_tear, EnumChatFormatting.RED + "Ghast Tear"));
- put("SLIME_BALL", Utils.createItemStack(Items.slime_ball, EnumChatFormatting.RED + "Slimeball"));
- put("BLAZE_ROD", Utils.createItemStack(Items.blaze_rod, EnumChatFormatting.RED + "Blaze Rod"));
- put("MAGMA_CREAM", Utils.createItemStack(Items.magma_cream, EnumChatFormatting.RED + "Magma Cream"));
-
- /* FORAGING COLLECTIONS */
- put("LOG", Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Oak"));
- put(
- "LOG:1",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Spruce", 1)
- );
- put(
- "LOG:2",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Birch", 2)
- );
- put(
- "LOG_2:1",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.log2), EnumChatFormatting.DARK_GREEN + "Dark Oak", 1)
- );
- put("LOG_2", Utils.createItemStack(Item.getItemFromBlock(Blocks.log2), EnumChatFormatting.DARK_GREEN + "Acacia"));
- put(
- "LOG:3",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Jungle", 3)
- );
+ /* FORAGING COLLECTIONS */
+ put(
+ "LOG",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Oak Wood")
+ );
+ put(
+ "LOG:1",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Spruce Wood", 1)
+ );
+ put(
+ "LOG:2",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Birch Wood", 2)
+ );
+ put(
+ "LOG_2:1",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.log2), EnumChatFormatting.DARK_GREEN + "Dark Oak Wood", 1)
+ );
+ put(
+ "LOG_2",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.log2), EnumChatFormatting.DARK_GREEN + "Acacia Wood")
+ );
+ put(
+ "LOG:3",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.log), EnumChatFormatting.DARK_GREEN + "Jungle Wood", 3)
+ );
- /* FISHING COLLECTIONS */
- put("RAW_FISH", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Fish"));
- put("RAW_FISH:1", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Salmon", 1));
- put("RAW_FISH:2", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Clownfish", 2));
- put("RAW_FISH:3", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Pufferfish", 3));
- put(
- "PRISMARINE_SHARD",
- Utils.createItemStack(Items.prismarine_shard, EnumChatFormatting.AQUA + "Prismarine Shard")
- );
- put(
- "PRISMARINE_CRYSTALS",
- Utils.createItemStack(Items.prismarine_crystals, EnumChatFormatting.AQUA + "Prismarine Crystals")
- );
- put("CLAY_BALL", Utils.createItemStack(Items.clay_ball, EnumChatFormatting.AQUA + "Clay"));
- put(
- "WATER_LILY",
- Utils.createItemStack(Item.getItemFromBlock(Blocks.waterlily), EnumChatFormatting.AQUA + "Lilypad")
- );
- put("INK_SACK", Utils.createItemStack(Items.dye, EnumChatFormatting.AQUA + "Ink Sack"));
- put("SPONGE", Utils.createItemStack(Item.getItemFromBlock(Blocks.sponge), EnumChatFormatting.AQUA + "Sponge"));
- }};
+ /* FISHING COLLECTIONS */
+ put("RAW_FISH", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Raw Fish"));
+ put("RAW_FISH:1", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Raw Salmon", 1));
+ put("RAW_FISH:2", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Clownfish", 2));
+ put("RAW_FISH:3", Utils.createItemStack(Items.fish, EnumChatFormatting.AQUA + "Pufferfish", 3));
+ put(
+ "PRISMARINE_SHARD",
+ Utils.createItemStack(Items.prismarine_shard, EnumChatFormatting.AQUA + "Prismarine Shard")
+ );
+ put(
+ "PRISMARINE_CRYSTALS",
+ Utils.createItemStack(Items.prismarine_crystals, EnumChatFormatting.AQUA + "Prismarine Crystals")
+ );
+ put("CLAY_BALL", Utils.createItemStack(Items.clay_ball, EnumChatFormatting.AQUA + "Clay"));
+ put(
+ "WATER_LILY",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.waterlily), EnumChatFormatting.AQUA + "Lily Pad")
+ );
+ put("INK_SACK", Utils.createItemStack(Items.dye, EnumChatFormatting.AQUA + "Ink Sac"));
+ put("SPONGE", Utils.createItemStack(Item.getItemFromBlock(Blocks.sponge), EnumChatFormatting.AQUA + "Sponge"));
+ put(
+ "MAGMA_FISH",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Magmafish",
+ "5c53195c-5b98-3476-9731-c32647b22723",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0MjQ4ODA3MDY2NiwKICAicHJvZmlsZUlkIiA6ICIzNDkxZjJiOTdjMDE0MWE2OTM2YjFjMjJhMmEwMGZiNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJKZXNzc3N1aGgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjU2YjU5NTViMjk1NTIyYzk2ODk0ODE5NjBjMDFhOTkyY2ExYzc3NTRjZjRlZTMxM2M4ZGQwYzM1NmQzMzVmIgogICAgfQogIH0KfQ"
+ )
+ );
+ }
+ };
+ private static final AtomicBoolean updatingResourceCollection = new AtomicBoolean(false);
+ private static JsonObject resourceCollection = null;
+ private final NEUManager manager;
+ private final HashMap<String, JsonObject> uuidToHypixelProfile = new HashMap<>();
+ private final HashMap<String, Profile> uuidToProfileMap = new HashMap<>();
+ private final HashMap<String, String> nameToUuid = new HashMap<>();
+
+ public ProfileViewer(NEUManager manager) {
+ this.manager = manager;
+ }
public static LinkedHashMap<ItemStack, List<String>> getCollectionCatToMinionMap() {
return collectionCatToMinionMap;
@@ -261,105 +469,262 @@ public class ProfileViewer {
return Collections.unmodifiableMap(skillToSkillDisplayMap);
}
- public static class Level {
- public float level = 0;
- public float maxXpForLevel = 0;
- public boolean maxed = false;
- public double totalXp;
- }
-
public static Level getLevel(JsonArray levelingArray, float xp, int levelCap, boolean cumulative) {
Level levelObj = new Level();
+ levelObj.totalXp = xp;
+ levelObj.maxLevel = levelCap;
+
for (int level = 0; level < levelingArray.size(); level++) {
float levelXp = levelingArray.get(level).getAsFloat();
+
if (levelXp > xp) {
if (cumulative) {
- float previous = 0;
- if (level > 0) previous = levelingArray.get(level - 1).getAsFloat();
+ float previous = level > 0 ? levelingArray.get(level - 1).getAsFloat() : 0;
levelObj.maxXpForLevel = (levelXp - previous);
levelObj.level = 1 + level + (xp - levelXp) / levelObj.maxXpForLevel;
} else {
levelObj.maxXpForLevel = levelXp;
levelObj.level = level + xp / levelXp;
}
+
if (levelObj.level > levelCap) {
levelObj.level = levelCap;
levelObj.maxed = true;
}
+
return levelObj;
} else {
- if (!cumulative) xp -= levelXp;
+ if (!cumulative) {
+ xp -= levelXp;
+ }
}
}
- levelObj.level = levelingArray.size();
- if (levelObj.level > levelCap) {
- levelObj.level = levelCap;
- }
+
+ levelObj.level = Math.min(levelingArray.size(), levelCap);
levelObj.maxed = true;
return levelObj;
}
- public class Profile {
- private final String uuid;
- private String latestProfile = null;
+ public static JsonObject getResourceCollectionInformation() {
+ if (resourceCollection != null) return resourceCollection;
+ if (updatingResourceCollection.get()) return null;
- private JsonArray playerInformation = null;
- private JsonObject guildInformation = null;
- private JsonObject basicInfo = null;
+ updatingResourceCollection.set(true);
+
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newHypixelApiRequest("resources/skyblock/collections")
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ updatingResourceCollection.set(false);
+ if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ resourceCollection = jsonObject.get("collections").getAsJsonObject();
+ }
+ });
+ return null;
+ }
+
+ public void getHypixelProfile(String name, Consumer<JsonObject> callback) {
+ String nameF = name.toLowerCase();
+ manager.apiUtils
+ .newHypixelApiRequest("player")
+ .queryArgument("name", nameF)
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ if (
+ jsonObject != null &&
+ jsonObject.has("success") &&
+ jsonObject.get("success").getAsBoolean() &&
+ jsonObject.get("player").isJsonObject()
+ ) {
+ nameToUuid.put(nameF, jsonObject.get("player").getAsJsonObject().get("uuid").getAsString());
+ uuidToHypixelProfile.put(
+ jsonObject.get("player").getAsJsonObject().get("uuid").getAsString(),
+ jsonObject.get("player").getAsJsonObject()
+ );
+ if (callback != null) callback.accept(jsonObject);
+ } else {
+ if (callback != null) callback.accept(null);
+ }
+ }
+ );
+ }
+
+ public void putNameUuid(String name, String uuid) {
+ nameToUuid.put(name, uuid);
+ }
+ public void getPlayerUUID(String name, Consumer<String> uuidCallback) {
+ String nameF = name.toLowerCase();
+ if (nameToUuid.containsKey(nameF)) {
+ uuidCallback.accept(nameToUuid.get(nameF));
+ return;
+ }
+
+ manager.apiUtils
+ .request()
+ .url("https://api.mojang.com/users/profiles/minecraft/" + nameF)
+ .requestJson()
+ .thenAccept(jsonObject -> {
+ if (jsonObject.has("id") && jsonObject.get("id").isJsonPrimitive() &&
+ ((JsonPrimitive) jsonObject.get("id")).isString()) {
+ String uuid = jsonObject.get("id").getAsString();
+ nameToUuid.put(nameF, uuid);
+ uuidCallback.accept(uuid);
+ return;
+ }
+ uuidCallback.accept(null);
+ });
+ }
+
+ public void getProfileByName(String name, Consumer<Profile> callback) {
+ String nameF = name.toLowerCase();
+
+ if (nameToUuid.containsKey(nameF) && nameToUuid.get(nameF) == null) {
+ callback.accept(null);
+ return;
+ }
+
+ getPlayerUUID(
+ nameF,
+ uuid -> {
+ if (uuid == null) {
+ getHypixelProfile(
+ nameF,
+ jsonObject -> {
+ if (jsonObject != null) {
+ callback.accept(getProfileReset(nameToUuid.get(nameF), ignored -> {}));
+ } else {
+ callback.accept(null);
+ nameToUuid.put(nameF, null);
+ }
+ }
+ );
+ } else {
+ if (!uuidToHypixelProfile.containsKey(uuid)) {
+ getHypixelProfile(nameF, jsonObject -> {});
+ }
+ callback.accept(getProfileReset(uuid, ignored -> {}));
+ }
+ }
+ );
+ }
+
+ public Profile getProfile(String uuid, Consumer<Profile> callback) {
+ Profile profile = uuidToProfileMap.computeIfAbsent(uuid, k -> new Profile(uuid));
+ if (profile.skyblockProfiles != null) {
+ callback.accept(profile);
+ } else {
+ profile.getSkyblockProfiles(() -> callback.accept(profile));
+ }
+ return profile;
+ }
+
+ public Profile getProfileReset(String uuid, Consumer<Profile> callback) {
+ if (uuidToProfileMap.containsKey(uuid)) uuidToProfileMap.get(uuid).resetCache();
+ return getProfile(uuid, callback);
+ }
+
+ public static class Level {
+
+ public float level = 0;
+ public float maxXpForLevel = 0;
+ public boolean maxed = false;
+ public int maxLevel;
+ public float totalXp;
+ }
+
+ public class Profile {
+
+ private final String uuid;
private final HashMap<String, JsonObject> profileMap = new HashMap<>();
private final HashMap<String, JsonObject> petsInfoMap = new HashMap<>();
private final HashMap<String, List<JsonObject>> coopProfileMap = new HashMap<>();
- private final HashMap<String, JsonObject> skillInfoMap = new HashMap<>();
- private final HashMap<String, JsonObject> inventoryInfoMap = new HashMap<>();
+ private final HashMap<String, Map<String, Level>> skyblockInfoCache = new HashMap<>();
+ private final HashMap<String, JsonObject> inventoryCacheMap = new HashMap<>();
private final HashMap<String, JsonObject> collectionInfoMap = new HashMap<>();
- private final List<String> profileIds = new ArrayList<>();
- private JsonObject playerStatus = null;
+ private final List<String> profileNames = new ArrayList<>();
private final HashMap<String, PlayerStats.Stats> stats = new HashMap<>();
private final HashMap<String, PlayerStats.Stats> passiveStats = new HashMap<>();
private final HashMap<String, Long> networth = new HashMap<>();
+ private final AtomicBoolean updatingSkyblockProfilesState = new AtomicBoolean(false);
+ private final AtomicBoolean updatingGuildInfoState = new AtomicBoolean(false);
+ private final AtomicBoolean updatingPlayerStatusState = new AtomicBoolean(false);
+ private final AtomicBoolean updatingBingoInfo = new AtomicBoolean(false);
+ private final Pattern COLL_TIER_PATTERN = Pattern.compile("_(-?\\d+)");
+ private String latestProfile = null;
+ private JsonArray skyblockProfiles = null;
+ private JsonObject guildInformation = null;
+ private JsonObject playerStatus = null;
+ private JsonObject bingoInformation = null;
+ private long lastPlayerInfoState = 0;
+ private long lastStatusInfoState = 0;
+ private long lastGuildInfoState = 0;
+ private long lastBingoInfoState = 0;
public Profile(String uuid) {
this.uuid = uuid;
}
- private final AtomicBoolean updatingPlayerInfoState = new AtomicBoolean(false);
- private long lastPlayerInfoState = 0;
- private final AtomicBoolean updatingPlayerStatusState = new AtomicBoolean(false);
- private final AtomicBoolean updatingGuildInfoState = new AtomicBoolean(false);
- private long lastGuildInfoState = 0;
- private final AtomicBoolean updatingGuildStatusState = new AtomicBoolean(false);
-
public JsonObject getPlayerStatus() {
if (playerStatus != null) return playerStatus;
if (updatingPlayerStatusState.get()) return null;
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - lastStatusInfoState < 15 * 1000) return null;
+ lastStatusInfoState = currentTime;
updatingPlayerStatusState.set(true);
HashMap<String, String> args = new HashMap<>();
args.put("uuid", "" + uuid);
- manager.hypixelApi.getHypixelApiAsync(NotEnoughUpdates.INSTANCE.config.apiKey.apiKey, "status",
- args, jsonObject -> {
- if (jsonObject == null) return;
-
+ manager.apiUtils
+ .newHypixelApiRequest("status")
+ .queryArgument("uuid", "" + uuid)
+ .requestJson()
+ .handle((jsonObject, ex) -> {
updatingPlayerStatusState.set(false);
- if (jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+
+ if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
playerStatus = jsonObject.get("session").getAsJsonObject();
}
- }, () -> updatingPlayerStatusState.set(false)
- );
-
+ return null;
+ });
return null;
}
- public long getNetWorth(String profileId) {
- if (profileId == null) profileId = latestProfile;
- if (networth.get(profileId) != null) return networth.get(profileId);
- if (getProfileInformation(profileId) == null) return -1;
- if (getInventoryInfo(profileId) == null) return -1;
+ public JsonObject getBingoInformation() {
+ long currentTime = System.currentTimeMillis();
+ if (bingoInformation != null && currentTime - lastBingoInfoState < 15 * 1000) return bingoInformation;
+ if (updatingBingoInfo.get() && bingoInformation != null) return bingoInformation;
+ if (updatingBingoInfo.get() && bingoInformation == null) return null;
+
+ lastBingoInfoState = currentTime;
+ updatingBingoInfo.set(true);
+
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newHypixelApiRequest("skyblock/bingo")
+ .queryArgument("uuid", "" + uuid)
+ .requestJson()
+ .handle(((jsonObject, throwable) -> {
+ updatingBingoInfo.set(false);
+
+ if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ bingoInformation = jsonObject;
+ } else {
+ bingoInformation = null;
+ }
+ return null;
+ }));
+ return bingoInformation != null ? bingoInformation : null;
+ }
+
+ public long getNetWorth(String profileName) {
+ if (profileName == null) profileName = latestProfile;
+ if (networth.get(profileName) != null) return networth.get(profileName);
+ if (getProfileInformation(profileName) == null) return -1;
+ if (getInventoryInfo(profileName) == null) return -1;
- JsonObject inventoryInfo = getInventoryInfo(profileId);
- JsonObject profileInfo = getProfileInformation(profileId);
+ JsonObject inventoryInfo = getInventoryInfo(profileName);
+ JsonObject profileInfo = getProfileInformation(profileName);
HashMap<String, Long> mostExpensiveInternal = new HashMap<>();
@@ -375,11 +740,11 @@ public class ProfileViewer {
JsonObject bzInfo = manager.auctionManager.getBazaarInfo(internalname);
- int auctionPrice;
+ long auctionPrice;
if (bzInfo != null && bzInfo.has("curr_sell")) {
auctionPrice = (int) bzInfo.get("curr_sell").getAsFloat();
} else {
- auctionPrice = (int) manager.auctionManager.getItemAvgBin(internalname);
+ auctionPrice = (long) manager.auctionManager.getItemAvgBin(internalname);
if (auctionPrice <= 0) {
auctionPrice = manager.auctionManager.getLowestBin(internalname);
}
@@ -403,11 +768,11 @@ public class ProfileViewer {
JsonObject bzInfo2 = manager.auctionManager.getBazaarInfo(internalname2);
- int auctionPrice2;
+ long auctionPrice2;
if (bzInfo2 != null && bzInfo2.has("curr_sell")) {
auctionPrice2 = (int) bzInfo2.get("curr_sell").getAsFloat();
} else {
- auctionPrice2 = (int) manager.auctionManager.getItemAvgBin(internalname2);
+ auctionPrice2 = (long) manager.auctionManager.getItemAvgBin(internalname2);
if (auctionPrice2 <= 0) {
auctionPrice2 = manager.auctionManager.getLowestBin(internalname2);
}
@@ -442,14 +807,9 @@ public class ProfileViewer {
}
if (networth == 0) return -1;
- //System.out.println(profileId);
- //for (Map.Entry<String, Long> entry : mostExpensiveInternal.entrySet()) {
- //System.out.println(entry.getKey() + ":" + entry.getValue());
- //}
-
networth = (int) (networth * 1.3f);
- JsonObject petsInfo = getPetsInfo(profileId);
+ JsonObject petsInfo = getPetsInfo(profileName);
if (petsInfo != null && petsInfo.has("pets")) {
if (petsInfo.get("pets").isJsonArray()) {
JsonArray pets = petsInfo.get("pets").getAsJsonArray();
@@ -478,7 +838,7 @@ public class ProfileViewer {
networth += bankBalance + purseBalance;
- this.networth.put(profileId, networth);
+ this.networth.put(profileName, networth);
return networth;
}
@@ -486,33 +846,33 @@ public class ProfileViewer {
return latestProfile;
}
- public JsonArray getPlayerInformation(Runnable runnable) {
- if (playerInformation != null) return playerInformation;
+ public JsonArray getSkyblockProfiles(Runnable runnable) {
+ if (skyblockProfiles != null) return skyblockProfiles;
long currentTime = System.currentTimeMillis();
- if (currentTime - lastPlayerInfoState < 15 * 1000 && updatingPlayerInfoState.get()) return null;
-
+ if (currentTime - lastPlayerInfoState < 15 * 1000 && updatingSkyblockProfilesState.get()) return null;
lastPlayerInfoState = currentTime;
- updatingPlayerInfoState.set(true);
+ updatingSkyblockProfilesState.set(true);
- HashMap<String, String> args = new HashMap<>();
- args.put("uuid", "" + uuid);
- manager.hypixelApi.getHypixelApiAsync(NotEnoughUpdates.INSTANCE.config.apiKey.apiKey, "skyblock/profiles",
- args, jsonObject -> {
- updatingPlayerInfoState.set(false);
+ manager.apiUtils
+ .newHypixelApiRequest("skyblock/profiles")
+ .queryArgument("uuid", "" + uuid)
+ .requestJson()
+ .handle((jsonObject, throwable) -> {
+ updatingSkyblockProfilesState.set(false);
+
+ if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ if (!jsonObject.has("profiles")) return null;
+ skyblockProfiles = jsonObject.get("profiles").getAsJsonArray();
- if (jsonObject == null) return;
- if (jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
- playerInformation = jsonObject.get("profiles").getAsJsonArray();
- if (playerInformation == null) return;
- String backup = null;
- long backupLastSave = 0;
+ String lastCuteName = null;
+ long lastLastSave = 0;
- profileIds.clear();
+ profileNames.clear();
- for (int i = 0; i < playerInformation.size(); i++) {
- JsonObject profile = playerInformation.get(i).getAsJsonObject();
+ for (JsonElement profileEle : skyblockProfiles) {
+ JsonObject profile = profileEle.getAsJsonObject();
if (!profile.has("members")) continue;
JsonObject members = profile.get("members").getAsJsonObject();
@@ -521,80 +881,81 @@ public class ProfileViewer {
JsonObject member = members.get(uuid).getAsJsonObject();
if (member.has("coop_invitation")) {
- JsonObject coop_invitation = member.get("coop_invitation").getAsJsonObject();
- if (!coop_invitation.get("confirmed").getAsBoolean()) {
+ if (!member.get("coop_invitation").getAsJsonObject().get("confirmed").getAsBoolean()) {
continue;
}
}
- String cute_name = profile.get("cute_name").getAsString();
- if (backup == null) backup = cute_name;
- profileIds.add(cute_name);
+ String cuteName = profile.get("cute_name").getAsString();
+ profileNames.add(cuteName);
+ if (profile.has("selected") && profile.get("selected").getAsBoolean()) {
+ lastCuteName = cuteName;
+ break;
+ }
+ if (lastCuteName == null) lastCuteName = cuteName;
if (member.has("last_save")) {
- long last_save = member.get("last_save").getAsLong();
- if (last_save > backupLastSave) {
- backupLastSave = last_save;
- backup = cute_name;
+ long lastSave = member.get("last_save").getAsLong();
+ if (lastSave > lastLastSave) {
+ lastLastSave = lastSave;
+ lastCuteName = cuteName;
}
}
-
}
}
- latestProfile = backup;
+ latestProfile = lastCuteName;
+
if (runnable != null) runnable.run();
}
- }, () -> updatingPlayerInfoState.set(false)
- );
-
+ return null;
+ });
return null;
}
- public JsonObject getGuildInfo(Runnable runnable) {
+ public JsonObject getGuildInformation(Runnable runnable) {
if (guildInformation != null) return guildInformation;
long currentTime = System.currentTimeMillis();
if (currentTime - lastGuildInfoState < 15 * 1000 && updatingGuildInfoState.get()) return null;
-
lastGuildInfoState = currentTime;
updatingGuildInfoState.set(true);
- HashMap<String, String> args = new HashMap<>();
- args.put("player", "" + uuid);
- manager.hypixelApi.getHypixelApiAsync(NotEnoughUpdates.INSTANCE.config.apiKey.apiKey, "guild",
- args, jsonObject -> {
+ manager.apiUtils
+ .newHypixelApiRequest("guild")
+ .queryArgument("player", "" + uuid)
+ .requestJson()
+ .handle((jsonObject, ex) -> {
updatingGuildInfoState.set(false);
- if (jsonObject == null) return;
- if (jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
+ if (!jsonObject.has("guild")) return null;
+
guildInformation = jsonObject.get("guild").getAsJsonObject();
- if (guildInformation == null) return;
+
if (runnable != null) runnable.run();
}
- }, () -> updatingGuildInfoState.set(false)
- );
-
+ return null;
+ });
return null;
}
- public List<String> getProfileIds() {
- return profileIds;
+ public List<String> getProfileNames() {
+ return profileNames;
}
- public JsonObject getProfileInformation(String profileId) {
- JsonArray playerInfo = getPlayerInformation(() -> {
- });
+ public JsonObject getProfileInformation(String profileName) {
+ JsonArray playerInfo = getSkyblockProfiles(() -> {});
if (playerInfo == null) return null;
- if (profileId == null) profileId = latestProfile;
- if (profileMap.containsKey(profileId)) return profileMap.get(profileId);
+ if (profileName == null) profileName = latestProfile;
+ if (profileMap.containsKey(profileName)) return profileMap.get(profileName);
- for (int i = 0; i < playerInformation.size(); i++) {
- if (!playerInformation.get(i).isJsonObject()) {
- playerInformation = null;
+ for (int i = 0; i < skyblockProfiles.size(); i++) {
+ if (!skyblockProfiles.get(i).isJsonObject()) {
+ skyblockProfiles = null;
return null;
}
- JsonObject profile = playerInformation.get(i).getAsJsonObject();
- if (profile.get("cute_name").getAsString().equalsIgnoreCase(profileId)) {
+ JsonObject profile = skyblockProfiles.get(i).getAsJsonObject();
+ if (profile.get("cute_name").getAsString().equalsIgnoreCase(profileName)) {
if (!profile.has("members")) return null;
JsonObject members = profile.get("members").getAsJsonObject();
if (!members.has(uuid)) continue;
@@ -605,7 +966,7 @@ public class ProfileViewer {
if (profile.has("game_mode")) {
profileInfo.add("game_mode", profile.get("game_mode"));
}
- profileMap.put(profileId, profileInfo);
+ profileMap.put(profileName, profileInfo);
return profileInfo;
}
}
@@ -613,20 +974,19 @@ public class ProfileViewer {
return null;
}
- public List<JsonObject> getCoopProfileInformation(String profileId) {
- JsonArray playerInfo = getPlayerInformation(() -> {
- });
+ public List<JsonObject> getCoopProfileInformation(String profileName) {
+ JsonArray playerInfo = getSkyblockProfiles(() -> {});
if (playerInfo == null) return null;
- if (profileId == null) profileId = latestProfile;
- if (coopProfileMap.containsKey(profileId)) return coopProfileMap.get(profileId);
+ if (profileName == null) profileName = latestProfile;
+ if (coopProfileMap.containsKey(profileName)) return coopProfileMap.get(profileName);
- for (int i = 0; i < playerInformation.size(); i++) {
- if (!playerInformation.get(i).isJsonObject()) {
- playerInformation = null;
+ for (int i = 0; i < skyblockProfiles.size(); i++) {
+ if (!skyblockProfiles.get(i).isJsonObject()) {
+ skyblockProfiles = null;
return null;
}
- JsonObject profile = playerInformation.get(i).getAsJsonObject();
- if (profile.get("cute_name").getAsString().equalsIgnoreCase(profileId)) {
+ JsonObject profile = skyblockProfiles.get(i).getAsJsonObject();
+ if (profile.get("cute_name").getAsString().equalsIgnoreCase(profileName)) {
if (!profile.has("members")) return null;
JsonObject members = profile.get("members").getAsJsonObject();
if (!members.has(uuid)) return null;
@@ -637,7 +997,7 @@ public class ProfileViewer {
coopList.add(coopProfileInfo);
}
}
- coopProfileMap.put(profileId, coopList);
+ coopProfileMap.put(profileName, coopList);
return coopList;
}
}
@@ -646,203 +1006,145 @@ public class ProfileViewer {
}
public void resetCache() {
- playerInformation = null;
+ skyblockProfiles = null;
guildInformation = null;
- basicInfo = null;
playerStatus = null;
stats.clear();
passiveStats.clear();
- profileIds.clear();
+ profileNames.clear();
profileMap.clear();
coopProfileMap.clear();
petsInfoMap.clear();
- skillInfoMap.clear();
- inventoryInfoMap.clear();
+ skyblockInfoCache.clear();
+ inventoryCacheMap.clear();
collectionInfoMap.clear();
networth.clear();
}
public int getCap(JsonObject leveling, String skillName) {
JsonElement capsElement = Utils.getElement(leveling, "leveling_caps");
- if (capsElement == null || !capsElement.isJsonObject()) {
- return 50;
- }
- JsonObject caps = capsElement.getAsJsonObject();
- if (caps.has(skillName)) {
- return caps.get(skillName).getAsInt();
- }
- return 50;
+ return capsElement != null && capsElement.isJsonObject() && capsElement.getAsJsonObject().has(skillName)
+ ? capsElement.getAsJsonObject().get(skillName).getAsInt()
+ : 50;
}
- public JsonObject getSkillInfo(String profileId) {
- JsonObject profileInfo = getProfileInformation(profileId);
+ public Map<String, Level> getSkyblockInfo(String profileName) {
+ JsonObject profileInfo = getProfileInformation(profileName);
+
if (profileInfo == null) return null;
- if (profileId == null) profileId = latestProfile;
- if (skillInfoMap.containsKey(profileId)) return skillInfoMap.get(profileId);
+ if (profileName == null) profileName = latestProfile;
+ if (skyblockInfoCache.containsKey(profileName)) return skyblockInfoCache.get(profileName);
+
JsonObject leveling = Constants.LEVELING;
- if (leveling == null) return null;
-
- float experience_skill_taming =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_taming"), 0);
- float experience_skill_mining =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_mining"), 0);
- float experience_skill_foraging =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_foraging"), 0);
- float experience_skill_enchanting =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_enchanting"), 0);
- float experience_skill_carpentry =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_carpentry"), 0);
- float experience_skill_farming =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_farming"), 0);
- float experience_skill_combat =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_combat"), 0);
- float experience_skill_fishing =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_fishing"), 0);
- float experience_skill_alchemy =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_alchemy"), 0);
- float experience_skill_runecrafting =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "experience_skill_runecrafting"), 0);
- float experience_skill_hotm = Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.experience"), 0);
-
- float experience_skill_catacombs =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.experience"), 0);
-
- float experience_slayer_zombie =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.zombie.xp"), 0);
- float experience_slayer_spider =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.spider.xp"), 0);
- float experience_slayer_wolf = Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.wolf.xp"), 0);
- float experience_slayer_enderman =
- Utils.getElementAsFloat(Utils.getElement(profileInfo, "slayer_bosses.enderman.xp"), 0);
-
- float totalSkillXP = experience_skill_taming + experience_skill_mining + experience_skill_foraging
- + experience_skill_enchanting + experience_skill_carpentry + experience_skill_farming
- + experience_skill_combat + experience_skill_fishing + experience_skill_alchemy
- + experience_skill_runecrafting;
+ if (leveling == null || !leveling.has("social")) {
+ Utils.showOutdatedRepoNotification();
+ return null;
+ }
+
+ Map<String, Level> out = new HashMap<>();
+
+ List<String> skills = Arrays.asList(
+ "taming",
+ "mining",
+ "foraging",
+ "enchanting",
+ "carpentry",
+ "farming",
+ "combat",
+ "fishing",
+ "alchemy",
+ "runecrafting",
+ "social"
+ );
+ float totalSkillXP = 0;
+ for (String skillName : skills) {
+ float skillExperience = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "experience_skill_" + (skillName.equals("social") ? "social2" : skillName)),
+ 0
+ );
+ totalSkillXP += skillExperience;
+ JsonArray levelingArray = Utils.getElement(leveling, "leveling_xp").getAsJsonArray();
+ if (skillName.equals("runecrafting")) {
+ levelingArray = Utils.getElement(leveling, "runecrafting_xp").getAsJsonArray();
+ } else if (skillName.equals("social")) {
+ levelingArray = Utils.getElement(leveling, "social").getAsJsonArray();
+ }
+
+ int maxLevel =
+ getCap(leveling, skillName) +
+ (
+ skillName.equals("farming")
+ ? Utils.getElementAsInt(Utils.getElement(profileInfo, "jacob2.perks.farming_level_cap"), 0)
+ : 0
+ );
+ out.put(skillName, getLevel(levelingArray, skillExperience, maxLevel, false));
+ }
+
+ // Skills API disabled?
if (totalSkillXP <= 0) {
return null;
}
- JsonObject skillInfo = new JsonObject();
-
- skillInfo.addProperty("experience_skill_taming", experience_skill_taming);
- skillInfo.addProperty("experience_skill_mining", experience_skill_mining);
- skillInfo.addProperty("experience_skill_foraging", experience_skill_foraging);
- skillInfo.addProperty("experience_skill_enchanting", experience_skill_enchanting);
- skillInfo.addProperty("experience_skill_carpentry", experience_skill_carpentry);
- skillInfo.addProperty("experience_skill_farming", experience_skill_farming);
- skillInfo.addProperty("experience_skill_combat", experience_skill_combat);
- skillInfo.addProperty("experience_skill_fishing", experience_skill_fishing);
- skillInfo.addProperty("experience_skill_alchemy", experience_skill_alchemy);
- skillInfo.addProperty("experience_skill_runecrafting", experience_skill_runecrafting);
- skillInfo.addProperty("experience_skill_hotm", experience_skill_hotm);
-
- skillInfo.addProperty("experience_skill_catacombs", experience_skill_catacombs);
-
- skillInfo.addProperty("experience_slayer_zombie", experience_slayer_zombie);
- skillInfo.addProperty("experience_slayer_spider", experience_slayer_spider);
- skillInfo.addProperty("experience_slayer_wolf", experience_slayer_wolf);
- skillInfo.addProperty("experience_slayer_enderman", experience_slayer_enderman);
-
- JsonArray levelingArray = Utils.getElement(leveling, "leveling_xp").getAsJsonArray();
- int farmingCap = getCap(leveling, "farming") + (int) Utils.getElementAsFloat(
- Utils.getElement(profileInfo, "jacob2.perks.farming_level_cap"), 0);
- Level level_skill_taming = getLevel(levelingArray, experience_skill_taming, getCap(leveling, "taming"), false);
- Level level_skill_mining = getLevel(levelingArray, experience_skill_mining, getCap(leveling, "mining"), false);
- Level level_skill_foraging =
- getLevel(levelingArray, experience_skill_foraging, getCap(leveling, "foraging"), false);
- Level level_skill_enchanting =
- getLevel(levelingArray, experience_skill_enchanting, getCap(leveling, "enchanting"), false);
- Level level_skill_carpentry =
- getLevel(levelingArray, experience_skill_carpentry, getCap(leveling, "carpentry"), false);
- Level level_skill_farming = getLevel(levelingArray, experience_skill_farming, farmingCap, false);
- Level level_skill_combat = getLevel(levelingArray, experience_skill_combat, getCap(leveling, "combat"), false);
- Level level_skill_fishing = getLevel(levelingArray, experience_skill_fishing, getCap(leveling, "fishing"), false);
- Level level_skill_alchemy = getLevel(levelingArray, experience_skill_alchemy, getCap(leveling, "alchemy"), false);
- Level level_skill_hotm = getLevel(levelingArray, experience_skill_hotm, getCap(leveling, "HOTM"), false);
- Level level_skill_runecrafting = getLevel(Utils.getElement(leveling, "runecrafting_xp").getAsJsonArray(),
- experience_skill_runecrafting, getCap(leveling, "runecrafting"), false
- );
- Level level_skill_catacombs = getLevel(Utils.getElement(leveling, "catacombs").getAsJsonArray(),
- experience_skill_catacombs, getCap(leveling, "catacombs"), false
+ out.put(
+ "hotm",
+ getLevel(
+ Utils.getElement(leveling, "leveling_xp").getAsJsonArray(),
+ Utils.getElementAsFloat(Utils.getElement(profileInfo, "mining_core.experience"), 0),
+ getCap(leveling, "HOTM"),
+ false
+ )
);
- Level level_slayer_zombie = getLevel(Utils.getElement(leveling, "slayer_xp.zombie").getAsJsonArray(),
- experience_slayer_zombie, 9, true
- );
- Level level_slayer_spider = getLevel(Utils.getElement(leveling, "slayer_xp.spider").getAsJsonArray(),
- experience_slayer_spider, 9, true
- );
- Level level_slayer_wolf = getLevel(Utils.getElement(leveling, "slayer_xp.wolf").getAsJsonArray(),
- experience_slayer_wolf, 9, true
- );
- Level level_slayer_enderman = getLevel(Utils.getElement(leveling, "slayer_xp.enderman").getAsJsonArray(),
- experience_slayer_enderman, 9, true
+ out.put(
+ "catacombs",
+ getLevel(
+ Utils.getElement(leveling, "catacombs").getAsJsonArray(),
+ Utils.getElementAsFloat(Utils.getElement(profileInfo, "dungeons.dungeon_types.catacombs.experience"), 0),
+ getCap(leveling, "catacombs"),
+ false
+ )
);
- skillInfo.addProperty("level_skill_taming", level_skill_taming.level);
- skillInfo.addProperty("level_skill_mining", level_skill_mining.level);
- skillInfo.addProperty("level_skill_foraging", level_skill_foraging.level);
- skillInfo.addProperty("level_skill_enchanting", level_skill_enchanting.level);
- skillInfo.addProperty("level_skill_carpentry", level_skill_carpentry.level);
- skillInfo.addProperty("level_skill_farming", level_skill_farming.level);
- skillInfo.addProperty("level_skill_combat", level_skill_combat.level);
- skillInfo.addProperty("level_skill_fishing", level_skill_fishing.level);
- skillInfo.addProperty("level_skill_alchemy", level_skill_alchemy.level);
- skillInfo.addProperty("level_skill_runecrafting", level_skill_runecrafting.level);
-
- skillInfo.addProperty("level_skill_catacombs", level_skill_catacombs.level);
-
- skillInfo.addProperty("level_slayer_zombie", level_slayer_zombie.level);
- skillInfo.addProperty("level_slayer_spider", level_slayer_spider.level);
- skillInfo.addProperty("level_slayer_wolf", level_slayer_wolf.level);
- skillInfo.addProperty("level_slayer_enderman", level_slayer_enderman.level);
-
- skillInfo.addProperty("maxed_skill_taming", level_skill_taming.maxed);
- skillInfo.addProperty("maxed_skill_mining", level_skill_mining.maxed);
- skillInfo.addProperty("maxed_skill_foraging", level_skill_foraging.maxed);
- skillInfo.addProperty("maxed_skill_enchanting", level_skill_enchanting.maxed);
- skillInfo.addProperty("maxed_skill_carpentry", level_skill_carpentry.maxed);
- skillInfo.addProperty("maxed_skill_farming", level_skill_farming.maxed);
- skillInfo.addProperty("maxed_skill_combat", level_skill_combat.maxed);
- skillInfo.addProperty("maxed_skill_fishing", level_skill_fishing.maxed);
- skillInfo.addProperty("maxed_skill_alchemy", level_skill_alchemy.maxed);
- skillInfo.addProperty("maxed_skill_runecrafting", level_skill_runecrafting.maxed);
-
- skillInfo.addProperty("maxed_skill_catacombs", level_skill_catacombs.maxed);
-
- skillInfo.addProperty("maxed_slayer_zombie", level_slayer_zombie.maxed);
- skillInfo.addProperty("maxed_slayer_spider", level_slayer_spider.maxed);
- skillInfo.addProperty("maxed_slayer_wolf", level_slayer_wolf.maxed);
- skillInfo.addProperty("maxed_slayer_enderman", level_slayer_enderman.maxed);
-
- skillInfo.addProperty("maxxp_skill_taming", level_skill_taming.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_mining", level_skill_mining.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_foraging", level_skill_foraging.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_enchanting", level_skill_enchanting.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_carpentry", level_skill_carpentry.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_farming", level_skill_farming.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_combat", level_skill_combat.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_fishing", level_skill_fishing.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_alchemy", level_skill_alchemy.maxXpForLevel);
- skillInfo.addProperty("maxxp_skill_runecrafting", level_skill_runecrafting.maxXpForLevel);
-
- skillInfo.addProperty("maxxp_skill_catacombs", level_skill_catacombs.maxXpForLevel);
-
- skillInfo.addProperty("maxxp_slayer_zombie", level_slayer_zombie.maxXpForLevel);
- skillInfo.addProperty("maxxp_slayer_spider", level_slayer_spider.maxXpForLevel);
- skillInfo.addProperty("maxxp_slayer_wolf", level_slayer_wolf.maxXpForLevel);
- skillInfo.addProperty("maxxp_slayer_enderman", level_slayer_enderman.maxXpForLevel);
-
- return skillInfo;
+ List<String> dungeonClasses = Arrays.asList("healer", "tank", "mage", "archer", "berserk");
+ for (String className : dungeonClasses) {
+ float classExperience = Utils.getElementAsFloat(
+ Utils.getElement(profileInfo, "dungeons.player_classes." + className + ".experience"),
+ 0
+ );
+ out.put(
+ className,
+ getLevel(
+ Utils.getElement(leveling, "catacombs").getAsJsonArray(),
+ classExperience,
+ getCap(leveling, "catacombs"),
+ false
+ )
+ );
+ }
+
+ List<String> slayers = Arrays.asList("zombie", "spider", "wolf", "enderman", "blaze");
+ for (String slayerName : slayers) {
+ float slayerExperience = Utils.getElementAsFloat(Utils.getElement(
+ profileInfo,
+ "slayer_bosses." + slayerName + ".xp"
+ ), 0);
+ out.put(
+ slayerName,
+ getLevel(Utils.getElement(leveling, "slayer_xp." + slayerName).getAsJsonArray(), slayerExperience, 9, true)
+ );
+ }
+
+ skyblockInfoCache.put(profileName, out);
+
+ return out;
}
- public JsonObject getInventoryInfo(String profileId) {
- JsonObject profileInfo = getProfileInformation(profileId);
+ public JsonObject getInventoryInfo(String profileName) {
+ JsonObject profileInfo = getProfileInformation(profileName);
if (profileInfo == null) return null;
- if (profileId == null) profileId = latestProfile;
- if (inventoryInfoMap.containsKey(profileId)) return inventoryInfoMap.get(profileId);
+ if (profileName == null) profileName = latestProfile;
+ if (inventoryCacheMap.containsKey(profileName)) return inventoryCacheMap.get(profileName);
String inv_armor_bytes = Utils.getElementAsString(
Utils.getElement(profileInfo, "inv_armor.data"),
@@ -889,6 +1191,10 @@ public class ProfileViewer {
Utils.getElement(profileInfo, "candy_inventory_contents.data"),
"Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="
);
+ String equipment_contents_bytes = Utils.getElementAsString(
+ Utils.getElement(profileInfo, "equippment_contents.data"),
+ "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA="
+ );
JsonObject inventoryInfo = new JsonObject();
@@ -903,7 +1209,8 @@ public class ProfileViewer {
"potion_bag",
"inv_contents",
"talisman_bag",
- "candy_inventory_contents"
+ "candy_inventory_contents",
+ "equippment_contents",
};
String[] inv_bytes = new String[]{
inv_armor_bytes,
@@ -916,7 +1223,8 @@ public class ProfileViewer {
potion_bag_bytes,
inv_contents_bytes,
talisman_bag_bytes,
- candy_inventory_contents_bytes
+ candy_inventory_contents_bytes,
+ equipment_contents_bytes,
};
for (int i = 0; i < inv_bytes.length; i++) {
try {
@@ -928,11 +1236,10 @@ public class ProfileViewer {
JsonObject temp = getBackpackData(backpack_contents_json, backpack_icons);
contents = (JsonArray) temp.get("contents");
inventoryInfo.add("backpack_sizes", temp.get("backpack_sizes"));
-
} else {
-
- NBTTagCompound inv_contents_nbt =
- CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(bytes)));
+ NBTTagCompound inv_contents_nbt = CompressedStreamTools.readCompressed(
+ new ByteArrayInputStream(Base64.getDecoder().decode(bytes))
+ );
NBTTagList items = inv_contents_nbt.getTagList("i", 10);
for (int j = 0; j < items.tagCount(); j++) {
JsonObject item = manager.getJsonFromNBTEntry(items.getCompoundTagAt(j));
@@ -945,19 +1252,13 @@ public class ProfileViewer {
}
}
- inventoryInfoMap.put(profileId, inventoryInfo);
+ inventoryCacheMap.put(profileName, inventoryInfo);
return inventoryInfo;
}
- public boolean checkIfValidJson(JsonElement element) {
- return element != null;
- }
-
- public JsonObject getBackpackData(JsonObject backpack_contents_json, JsonObject backpack_icons) {
-
- JsonArray contents = new JsonArray();
- if (!(checkIfValidJson(backpack_contents_json) && checkIfValidJson(backpack_icons))) {
+ public JsonObject getBackpackData(JsonObject backpackContentsJson, JsonObject backpackIcons) {
+ if (backpackContentsJson == null || backpackIcons == null) {
JsonObject bundledReturn = new JsonObject();
bundledReturn.add("contents", new JsonArray());
bundledReturn.add("backpack_sizes", new JsonArray());
@@ -968,9 +1269,9 @@ public class ProfileViewer {
String[] backpackArray = new String[0];
//Create backpack array which sizes up
- for (Map.Entry<String, JsonElement> backpackIcon : backpack_icons.entrySet()) {
+ for (Map.Entry<String, JsonElement> backpackIcon : backpackIcons.entrySet()) {
if (backpackIcon.getValue() instanceof JsonObject) {
- JsonObject backpackData = (JsonObject) backpack_contents_json.get(backpackIcon.getKey());
+ JsonObject backpackData = (JsonObject) backpackContentsJson.get(backpackIcon.getKey());
String bytes = Utils.getElementAsString(backpackData.get("data"), "Hz8IAAAAAAAAAD9iYD9kYD9kAAMAPwI/Gw0AAAA=");
backpackArray = growArray(bytes, Integer.parseInt(backpackIcon.getKey()), backpackArray);
}
@@ -978,11 +1279,9 @@ public class ProfileViewer {
//reduce backpack array to filter out not existent backpacks
{
- int backpackCount = 0;
String[] tempBackpackArray = new String[0];
for (String s : backpackArray) {
if (s != null) {
- backpackCount++;
String[] veryTempBackpackArray = new String[tempBackpackArray.length + 1];
System.arraycopy(tempBackpackArray, 0, veryTempBackpackArray, 0, tempBackpackArray.length);
@@ -994,11 +1293,13 @@ public class ProfileViewer {
}
JsonArray backpackSizes = new JsonArray();
+ JsonArray contents = new JsonArray();
for (String backpack : backpackArray) {
try {
- NBTTagCompound inv_contents_nbt =
- CompressedStreamTools.readCompressed(new ByteArrayInputStream(Base64.getDecoder().decode(backpack)));
+ NBTTagCompound inv_contents_nbt = CompressedStreamTools.readCompressed(
+ new ByteArrayInputStream(Base64.getDecoder().decode(backpack))
+ );
NBTTagList items = inv_contents_nbt.getTagList("i", 10);
backpackSizes.add(new JsonPrimitive(items.tagCount()));
@@ -1021,18 +1322,16 @@ public class ProfileViewer {
int newSize = Math.max(index + 1, oldArray.length);
String[] newArray = new String[newSize];
- for (int i = 0; i < oldArray.length; i++) {
- newArray[i] = oldArray[i];
- }
+ System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
newArray[index] = bytes;
return newArray;
}
- public JsonObject getPetsInfo(String profileId) {
- JsonObject profileInfo = getProfileInformation(profileId);
+ public JsonObject getPetsInfo(String profileName) {
+ JsonObject profileInfo = getProfileInformation(profileName);
if (profileInfo == null) return null;
- if (petsInfoMap.containsKey(profileId)) return petsInfoMap.get(profileId);
+ if (petsInfoMap.containsKey(profileName)) return petsInfoMap.get(profileName);
JsonObject petsInfo = new JsonObject();
JsonElement petsElement = profileInfo.get("pets");
@@ -1041,31 +1340,33 @@ public class ProfileViewer {
JsonArray pets = petsElement.getAsJsonArray();
for (int i = 0; i < pets.size(); i++) {
JsonObject pet = pets.get(i).getAsJsonObject();
- if (pet.has("active") && pet.get("active").getAsJsonPrimitive().getAsBoolean()) {
+ if (pet.has("active") && pet.get("active").getAsBoolean()) {
activePet = pet;
break;
}
}
petsInfo.add("active_pet", activePet);
petsInfo.add("pets", pets);
- petsInfoMap.put(profileId, petsInfo);
+ petsInfoMap.put(profileName, petsInfo);
return petsInfo;
}
return null;
}
- private final Pattern COLL_TIER_PATTERN = Pattern.compile("_(-?[0-9]+)");
-
- public JsonObject getCollectionInfo(String profileId) {
- JsonObject profileInfo = getProfileInformation(profileId);
+ public JsonObject getCollectionInfo(String profileName) {
+ JsonObject profileInfo = getProfileInformation(profileName);
if (profileInfo == null) return null;
JsonObject resourceCollectionInfo = getResourceCollectionInformation();
if (resourceCollectionInfo == null) return null;
- if (profileId == null) profileId = latestProfile;
- if (collectionInfoMap.containsKey(profileId)) return collectionInfoMap.get(profileId);
+ if (profileName == null) profileName = latestProfile;
+ if (collectionInfoMap.containsKey(profileName)) return collectionInfoMap.get(profileName);
+ List<JsonObject> coopMembers = getCoopProfileInformation(profileName);
JsonElement unlocked_coll_tiers_element = Utils.getElement(profileInfo, "unlocked_coll_tiers");
JsonElement crafted_generators_element = Utils.getElement(profileInfo, "crafted_generators");
+ JsonObject fakeMember = new JsonObject();
+ fakeMember.add("crafted_generators", crafted_generators_element);
+ coopMembers.add(coopMembers.size(), fakeMember);
JsonElement collectionInfoElement = Utils.getElement(profileInfo, "collection");
if (unlocked_coll_tiers_element == null || collectionInfoElement == null) {
@@ -1083,17 +1384,17 @@ public class ProfileViewer {
}
for (Map.Entry<String, JsonElement> entry : personalAmounts.entrySet()) {
- totalAmounts.addProperty(entry.getKey(), entry.getValue().getAsInt());
+ totalAmounts.addProperty(entry.getKey(), entry.getValue().getAsLong());
}
- List<JsonObject> coopProfiles = getCoopProfileInformation(profileId);
+ List<JsonObject> coopProfiles = getCoopProfileInformation(profileName);
if (coopProfiles != null) {
for (JsonObject coopProfile : coopProfiles) {
JsonElement coopCollectionInfoElement = Utils.getElement(coopProfile, "collection");
if (coopCollectionInfoElement != null && coopCollectionInfoElement.isJsonObject()) {
for (Map.Entry<String, JsonElement> entry : coopCollectionInfoElement.getAsJsonObject().entrySet()) {
float existing = Utils.getElementAsFloat(totalAmounts.get(entry.getKey()), 0);
- totalAmounts.addProperty(entry.getKey(), existing + entry.getValue().getAsInt());
+ totalAmounts.addProperty(entry.getKey(), existing + entry.getValue().getAsLong());
}
}
}
@@ -1116,17 +1417,17 @@ public class ProfileViewer {
}
}
}
-
- if (crafted_generators_element != null && crafted_generators_element.isJsonArray()) {
- JsonArray crafted_generators = crafted_generators_element.getAsJsonArray();
- for (int i = 0; i < crafted_generators.size(); i++) {
- String unlocked = crafted_generators.get(i).getAsString();
-
+ for (JsonObject current_member_info : coopMembers) {
+ if (
+ !current_member_info.has("crafted_generators") || !current_member_info.get("crafted_generators").isJsonArray()
+ ) continue;
+ JsonArray crafted_generators = Utils.getElement(current_member_info, "crafted_generators").getAsJsonArray();
+ for (int j = 0; j < crafted_generators.size(); j++) {
+ String unlocked = crafted_generators.get(j).getAsString();
Matcher matcher = COLL_TIER_PATTERN.matcher(unlocked);
-
if (matcher.find()) {
- String tier_str = matcher.group(1);
- int tier = Integer.parseInt(tier_str);
+ String tierString = matcher.group(1);
+ int tier = Integer.parseInt(tierString);
String coll = unlocked.substring(0, unlocked.length() - (matcher.group().length()));
if (!minionTiers.has(coll) || minionTiers.get(coll).getAsInt() < tier) {
minionTiers.addProperty(coll, tier);
@@ -1177,37 +1478,43 @@ public class ProfileViewer {
collectionInfo.add("total_amounts", totalAmounts);
collectionInfo.add("collection_tiers", collectionTiers);
+ collectionInfoMap.put(profileName, collectionInfo);
+
return collectionInfo;
}
- public PlayerStats.Stats getPassiveStats(String profileId) {
- if (passiveStats.get(profileId) != null) return passiveStats.get(profileId);
- JsonObject profileInfo = getProfileInformation(profileId);
+ public PlayerStats.Stats getPassiveStats(String profileName) {
+ if (passiveStats.get(profileName) != null) return passiveStats.get(profileName);
+ JsonObject profileInfo = getProfileInformation(profileName);
if (profileInfo == null) return null;
- PlayerStats.Stats passiveStats = PlayerStats.getPassiveBonuses(getSkillInfo(profileId), profileInfo);
+ PlayerStats.Stats passiveStats = PlayerStats.getPassiveBonuses(getSkyblockInfo(profileName), profileInfo);
if (passiveStats != null) {
passiveStats.add(PlayerStats.getBaseStats());
}
- this.passiveStats.put(profileId, passiveStats);
+ this.passiveStats.put(profileName, passiveStats);
return passiveStats;
}
- public PlayerStats.Stats getStats(String profileId) {
- //if(stats.get(profileId) != null) return stats.get(profileId);
- JsonObject profileInfo = getProfileInformation(profileId);
+ public PlayerStats.Stats getStats(String profileName) {
+ if (stats.get(profileName) != null) return stats.get(profileName);
+ JsonObject profileInfo = getProfileInformation(profileName);
if (profileInfo == null) {
return null;
}
- PlayerStats.Stats stats =
- PlayerStats.getStats(getSkillInfo(profileId), getInventoryInfo(profileId), getCollectionInfo(profileId),
- getPetsInfo(profileId), profileInfo
- );
- this.stats.put(profileId, stats);
+ PlayerStats.Stats stats = PlayerStats.getStats(
+ getSkyblockInfo(profileName),
+ getInventoryInfo(profileName),
+ getCollectionInfo(profileName),
+ getPetsInfo(profileName),
+ profileInfo
+ );
+ if (stats == null) return null;
+ this.stats.put(profileName, stats);
return stats;
}
@@ -1215,139 +1522,8 @@ public class ProfileViewer {
return uuid;
}
- public @Nullable
- JsonObject getHypixelProfile() {
- if (uuidToHypixelProfile.containsKey(uuid)) return uuidToHypixelProfile.get(uuid);
- return null;
- }
- }
-
- private final HashMap<String, JsonObject> nameToHypixelProfile = new HashMap<>();
- private final HashMap<String, JsonObject> uuidToHypixelProfile = new HashMap<>();
- private final HashMap<String, Profile> uuidToProfileMap = new HashMap<>();
-
- public void getHypixelProfile(String name, Consumer<JsonObject> callback) {
- String nameF = name.toLowerCase();
- HashMap<String, String> args = new HashMap<>();
- args.put("name", "" + nameF);
- manager.hypixelApi.getHypixelApiAsync(NotEnoughUpdates.INSTANCE.config.apiKey.apiKey, "player",
- args, jsonObject -> {
- if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()
- && jsonObject.get("player").isJsonObject()) {
- nameToUuid.put(nameF, jsonObject.get("player").getAsJsonObject().get("uuid").getAsString());
- uuidToHypixelProfile.put(
- jsonObject.get("player").getAsJsonObject().get("uuid").getAsString(),
- jsonObject.get("player").getAsJsonObject()
- );
- if (callback != null) callback.accept(jsonObject);
- } else {
- if (callback != null) callback.accept(null);
- }
- }
- );
- }
-
- private final HashMap<String, String> nameToUuid = new HashMap<>();
-
- public void putNameUuid(String name, String uuid) {
- nameToUuid.put(name, uuid);
- }
-
- public void getPlayerUUID(String name, Consumer<String> uuidCallback) {
- String nameF = name.toLowerCase();
- if (nameToUuid.containsKey(nameF)) {
- uuidCallback.accept(nameToUuid.get(nameF));
- return;
+ public @Nullable JsonObject getHypixelProfile() {
+ return uuidToHypixelProfile.getOrDefault(uuid, null);
}
-
- manager.hypixelApi.getApiAsync("https://api.mojang.com/users/profiles/minecraft/" + nameF,
- (jsonObject) -> {
- if (jsonObject.has("id") && jsonObject.get("id").isJsonPrimitive() &&
- ((JsonPrimitive) jsonObject.get("id")).isString()) {
- String uuid = jsonObject.get("id").getAsString();
- nameToUuid.put(nameF, uuid);
- uuidCallback.accept(uuid);
- return;
- }
- uuidCallback.accept(null);
- }, () -> uuidCallback.accept(null)
- );
- }
-
- public void getProfileByName(String name, Consumer<Profile> callback) {
- String nameF = name.toLowerCase();
-
- if (nameToUuid.containsKey(nameF) && nameToUuid.get(nameF) == null) {
- callback.accept(null);
- return;
- }
-
- getPlayerUUID(nameF, (uuid) -> {
- if (uuid == null) {
- getHypixelProfile(nameF, jsonObject -> {
- if (jsonObject != null) {
- callback.accept(getProfileReset(nameToUuid.get(nameF), ignored -> {
- }));
- } else {
- callback.accept(null);
- nameToUuid.put(nameF, null);
- }
- });
- } else {
- if (!uuidToHypixelProfile.containsKey(uuid)) {
- getHypixelProfile(nameF, jsonObject -> {
- });
- }
- callback.accept(getProfileReset(uuid, ignored -> {
- }));
- }
- });
-
- return;
- }
-
- public Profile getProfileRaw(String uuid) {
- return uuidToProfileMap.get(uuid);
- }
-
- public Profile getProfile(String uuid, Consumer<Profile> callback) {
- Profile profile = uuidToProfileMap.computeIfAbsent(uuid, k -> new Profile(uuid));
- if (profile.playerInformation != null) {
- callback.accept(profile);
- } else {
- profile.getPlayerInformation(() -> callback.accept(profile));
- }
- return profile;
- }
-
- public Profile getProfileReset(String uuid, Consumer<Profile> callback) {
- if (uuidToProfileMap.containsKey(uuid)) uuidToProfileMap.get(uuid).resetCache();
- return getProfile(uuid, callback);
- }
-
- private static JsonObject resourceCollection = null;
- private static final AtomicBoolean updatingResourceCollection = new AtomicBoolean(false);
-
- public static JsonObject getResourceCollectionInformation() {
- if (resourceCollection != null) return resourceCollection;
- if (updatingResourceCollection.get()) return null;
-
- updatingResourceCollection.set(true);
-
- HashMap<String, String> args = new HashMap<>();
- NotEnoughUpdates.INSTANCE.manager.hypixelApi.getHypixelApiAsync(
- NotEnoughUpdates.INSTANCE.config.apiKey.apiKey,
- "resources/skyblock/collections",
- args,
- jsonObject -> {
- updatingResourceCollection.set(false);
- if (jsonObject != null && jsonObject.has("success") && jsonObject.get("success").getAsBoolean()) {
- resourceCollection = jsonObject.get("collections").getAsJsonObject();
- }
- },
- () -> updatingResourceCollection.set(false)
- );
-
- return null;
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java
new file mode 100644
index 00000000..7df88964
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryData.java
@@ -0,0 +1,1093 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.bestiary;
+
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.LinkedHashMap;
+import java.util.List;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+
+public class BestiaryData {
+
+ private static final LinkedHashMap<ItemStack, List<String>> bestiaryLocations = new LinkedHashMap<ItemStack, List<String>>() {
+ {
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Private Island",
+ "bdee7687-9c85-4e7a-b789-b55e90d21d68",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzljODg4MWU0MjkxNWE5ZDI5YmI2MWExNmZiMjZkMDU5OTEzMjA0ZDI2NWRmNWI0MzliM2Q3OTJhY2Q1NiJ9fX0="
+ ),
+ Utils.createList(
+ "family_cave_spider",
+ "family_enderman_private",
+ "family_skeleton",
+ "family_slime",
+ "family_spider",
+ "family_witch",
+ "family_zombie"
+ )
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Hub",
+ "88208736-41cd-4ed8-8ed7-53179140a7fa",
+ "eyJ0aW1lc3RhbXAiOjE1NTkyMTU0MTY5MDksInByb2ZpbGVJZCI6IjQxZDNhYmMyZDc0OTQwMGM5MDkwZDU0MzRkMDM4MzFiIiwicHJvZmlsZU5hbWUiOiJNZWdha2xvb24iLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Q3Y2M2Njg3NDIzZDA1NzBkNTU2YWM1M2UwNjc2Y2I1NjNiYmRkOTcxN2NkODI2OWJkZWJlZDZmNmQ0ZTdiZjgifX19"
+ ),
+ Utils.createList("family_unburried_zombie", "family_old_wolf", "family_ruin_wolf", "family_zombie_villager")
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Spiders Den",
+ "acbeaf98-2081-40c5-b5a3-221a2957d532",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzc1NDMxOGEzMzc2ZjQ3MGU0ODFkZmNkNmM4M2E1OWFhNjkwYWQ0YjRkZDc1NzdmZGFkMWMyZWYwOGQ4YWVlNiJ9fX0"
+ ),
+ Utils.createList(
+ "family_arachne",
+ "family_arachne_brood",
+ "family_arachne_keeper",
+ "family_brood_mother_spider",
+ "family_dasher_spider",
+ "family_respawning_skeleton",
+ "family_random_slime",
+ "family_spider_jockey",
+ "family_splitter_spider",
+ "family_voracious_spider",
+ "family_weaver_spider"
+ )
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "The End",
+ "e39ea8b1-a267-48a9-907a-1b97b85342bc",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg0MGI4N2Q1MjI3MWQyYTc1NWRlZGM4Mjg3N2UwZWQzZGY2N2RjYzQyZWE0NzllYzE0NjE3NmIwMjc3OWE1In19fQ"
+ ),
+ Utils.createList(
+ "family_dragon",
+ "family_enderman",
+ "family_endermite",
+ "family_corrupted_protector",
+ "family_obsidian_wither",
+ "family_voidling_extremist",
+ "family_voidling_fanatic",
+ "family_watcher",
+ "family_zealot_enderman"
+ )
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Crimson Isles",
+ "d8489bfe-dcd7-41f0-bfbd-fb482bf61ecb",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzM2ODdlMjVjNjMyYmNlOGFhNjFlMGQ2NGMyNGU2OTRjM2VlYTYyOWVhOTQ0ZjRjZjMwZGNmYjRmYmNlMDcxIn19fQ"
+ ),
+ Utils.createList(
+ "family_ashfang",
+ "family_barbarian_duke_x",
+ "family_bladesoul",
+ "family_blaze",
+ "family_flaming_spider",
+ "family_ghast",
+ "family_mage_outlaw",
+ "family_magma_cube",
+ "family_magma_cube_boss",
+ "family_matcho",
+ "family_charging_mushroom_cow",
+ "family_pigman",
+ "family_wither_skeleton",
+ "family_wither_spectre"
+ )
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Deep Caverns",
+ "896b5137-a2dd-4de2-8c63-d5a5649bfc70",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTY5YTFmMTE0MTUxYjQ1MjEzNzNmMzRiYzE0YzI5NjNhNTAxMWNkYzI1YTY1NTRjNDhjNzA4Y2Q5NmViZmMifX19"
+ ),
+ Utils.createList(
+ "family_automaton",
+ "family_butterfly",
+ "family_emerald_slime",
+ "family_caverns_ghost",
+ "family_goblin",
+ "family_team_treasurite",
+ "family_ice_walker",
+ "family_lapis_zombie",
+ "family_diamond_skeleton",
+ "family_diamond_zombie",
+ "family_redstone_pigman",
+ "family_sludge",
+ "family_invisible_creeper",
+ "family_thyst",
+ "family_treasure_hoarder",
+ "family_worms",
+ "family_yog"
+ )
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "The Park",
+ "6473b2ff-0575-4aec-811f-5f0dca2131b6",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTIyMWY4MTNkYWNlZTBmZWY4YzU5Zjc2ODk0ZGJiMjY0MTU0NzhkOWRkZmM0NGMyZTcwOGE2ZDNiNzU0OWIifX19"
+ ),
+ Utils.createList("family_howling_spirit", "family_pack_spirit", "family_soul_of_the_alpha")
+ );
+ put(
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.lit_pumpkin), EnumChatFormatting.AQUA + "Spooky"),
+ Utils.createList(
+ "family_batty_witch",
+ "family_headless_horseman",
+ "family_phantom_spirit",
+ "family_scary_jerry",
+ "family_trick_or_treater",
+ "family_wither_gourd",
+ "family_wraith"
+ )
+ );
+ put(
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "Catacombs",
+ "00b3837d-9275-304c-8bf9-656659087e6b",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTY0ZTFjM2UzMTVjOGQ4ZmZmYzM3OTg1YjY2ODFjNWJkMTZhNmY5N2ZmZDA3MTk5ZThhMDVlZmJlZjEwMzc5MyJ9fX0"
+ ),
+ Utils.createList(
+ "family_diamond_guy",
+ "family_cellar_spider",
+ "family_crypt_dreadlord",
+ "family_crypt_lurker",
+ "family_crypt_souleater",
+ "family_king_midas",
+ "family_lonely_spider",
+ "family_lost_adventurer",
+ "family_scared_skeleton",
+ "family_shadow_assassin",
+ "family_skeleton_grunt",
+ "family_skeleton_master",
+ "family_skeleton_soldier",
+ "family_skeletor",
+ "family_sniper_skeleton",
+ "family_super_archer",
+ "family_super_tank_zombie",
+ "family_crypt_tank_zombie",
+ "family_watcher_summon_undead",
+ "family_dungeon_respawning_skeleton",
+ "family_crypt_witherskeleton",
+ "family_zombie_commander",
+ "family_zombie_grunt",
+ "family_zombie_knight",
+ "family_zombie_soldier"
+ )
+ );
+ }
+ };
+ private static final LinkedHashMap<String, ItemStack> bestiaryMobs = new LinkedHashMap<String, ItemStack>() {
+ {
+ // Private Island
+ put(
+ "family_cave_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aCave Spider",
+ "a8aee72d-0d1d-3db7-8cf8-be1ce6ec2dc4",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19"
+ )
+ );
+ put(
+ "family_enderman_private",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aEnderman",
+ "2005daad-730b-363c-abae-e6f3830816fb",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTZjMGIzNmQ1M2ZmZjY5YTQ5YzdkNmYzOTMyZjJiMGZlOTQ4ZTAzMjIyNmQ1ZTgwNDVlYzU4NDA4YTM2ZTk1MSJ9fX0="
+ )
+ );
+ put(
+ "family_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSkeleton",
+ "53924f1a-87e6-4709-8e53-f1c7d13dc239",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9="
+ )
+ );
+ put(
+ "family_slime",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSlime",
+ "3b70a2f3-319c-38d5-b7d1-5b2425770184",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1YWVlYzZiODQyYWRhODY2OWY4NDZkNjViYzQ5NzYyNTk3ODI0YWI5NDRmMjJmNDViZjNiYmI5NDFhYmU2YyJ9fX0="
+ )
+ );
+ put(
+ "family_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSpider",
+ "7c63f3cf-a963-311a-aeca-3a075b417806",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=="
+ )
+ );
+ put(
+ "family_witch",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWitch",
+ "cf4f97d7-2e1f-3678-9ca3-4a7b9666cc28",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmNlNjYwNDE1N2ZjNGFiNTU5MWU0YmNmNTA3YTc0OTkxOGVlOWM0MWUzNTdkNDczNzZlMGVlNzM0MjA3NGM5MCJ9fX0="
+ )
+ );
+ put(
+ "family_zombie",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aZombie",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+
+ // Hub
+ put("family_unburried_zombie", Utils.createItemStack(Items.golden_sword, EnumChatFormatting.AQUA + "§aCrypt Ghoul"));
+ put(
+ "family_old_wolf",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aOld Wolf",
+ "26e6f2d9-8a27-3a77-965c-5bd2b5d2dc93",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDM1OTUzN2MxNTUzNGY2MWMxY2Q4ODZiYzExODc3NGVkMjIyODBlN2NkYWI2NjEzODcwMTYwYWFkNGNhMzkifX19"
+ )
+ );
+ put(
+ "family_ruin_wolf",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWolf",
+ "7e9af289-f295-3f8c-bd54-58b7667d5759",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjlkMWQzMTEzZWM0M2FjMjk2MWRkNTlmMjgxNzVmYjQ3MTg4NzNjNmM0NDhkZmNhODcyMjMxN2Q2NyJ9fX0="
+ )
+ );
+ put(
+ "family_zombie_villager",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aZombie Villager",
+ "3acb9940-fc42-328e-91e8-c9a9a57e8698",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTVlMDhhODc3NmMxNzY0YzNmZTZhNmRkZDQxMmRmY2I4N2Y0MTMzMWRhZDQ3OWFjOTZjMjFkZjRiZjNhYzg5YyJ9fX0="
+ )
+ );
+
+ // Spiders Den
+ put(
+ "family_arachne",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aArachne",
+ "7c63f3cf-a963-311a-aeca-3a075b417806",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=="
+ )
+ );
+ put(
+ "family_arachne_brood",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aArachne's Brood",
+ "7c63f3cf-a963-311a-aeca-3a075b417806",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=="
+ )
+ );
+ put(
+ "family_arachne_keeper",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aArachne's Keeper",
+ "7c63f3cf-a963-311a-aeca-3a075b417806",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=="
+ )
+ );
+ put(
+ "family_brood_mother_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aBrood Mother",
+ "d7390e70-1e99-3c24-9b1c-bb098e0bbef1",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2YwNjIyYjM5OThkNDJiMzRkNWJjNzYwYmIyYzgzZmRiYzZlNjhmYWIwNWI3ZWExN2IzNTA5N2VkODExOTBkNiJ9fX0="
+ )
+ );
+ put(
+ "family_dasher_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aDasher Spider",
+ "7c63f3cf-a963-311a-aeca-3a075b417806",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=="
+ )
+ );
+ put(
+ "family_respawning_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aGravel Skeleton",
+ "53924f1a-87e6-4709-8e53-f1c7d13dc239",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9="
+ )
+ );
+ put(
+ "family_random_slime",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aRain Slime",
+ "3b70a2f3-319c-38d5-b7d1-5b2425770184",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1YWVlYzZiODQyYWRhODY2OWY4NDZkNjViYzQ5NzYyNTk3ODI0YWI5NDRmMjJmNDViZjNiYmI5NDFhYmU2YyJ9fX0="
+ )
+ );
+ put(
+ "family_spider_jockey",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSpider Jockey",
+ "4eb8745c-80d2-356b-b4fa-f3ffa74082e7",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA5MzkzNzNjYWZlNGIxZjUzOTdhYWZkMDlmM2JiMTY2M2U3YjYyOWE0MWE3NWZiZGMxODYwYjZiZjhiNDc1ZiJ9fX0="
+ )
+ );
+ put(
+ "family_splitter_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSplitter Spider",
+ "50010472-fa22-3519-b941-2d6d22f47bf1",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmFjZjY5ZmM3YWY1NDk3YTE3NDE4OTFkMWU1YmYzMmI5NmFlMGQ2YzBiYmQzYzE0NzU4ZWE0NGEwM2M1NzI4MyJ9fX0="
+ )
+ );
+ put(
+ "family_voracious_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aVoracious Spider",
+ "3e5474d4-4365-3ea7-b4bc-b4edc54da341",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODMwMDk4NmVkMGEwNGVhNzk5MDRmNmFlNTNmNDllZDNhMGZmNWIxZGY2MmJiYTYyMmVjYmQzNzc3ZjE1NmRmOCJ9fX0="
+ )
+ );
+ put(
+ "family_weaver_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWeaver Spider",
+ "97414c0c-623b-3df3-b1f6-bbcaddafc7fc",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxNDM4ZjY0NmRjMDQ1MTU5NjdlODE5NWNjYzNkMzFlMjNiMDJmOWFhMGFjOTE0ZWRjMjgyMmY5ODM5NGI4NiJ9fX0="
+ )
+ );
+
+ // The End
+ put("family_dragon", Utils.createItemStack(Item.getItemFromBlock(Blocks.dragon_egg), EnumChatFormatting.AQUA + "§aDragon"));
+ put(
+ "family_enderman",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aEnderman",
+ "2005daad-730b-363c-abae-e6f3830816fb",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTZjMGIzNmQ1M2ZmZjY5YTQ5YzdkNmYzOTMyZjJiMGZlOTQ4ZTAzMjIyNmQ1ZTgwNDVlYzU4NDA4YTM2ZTk1MSJ9fX0="
+ )
+ );
+ put(
+ "family_endermite",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aEndermite",
+ "b3224e56-73d2-32f9-9081-a23b7512035b",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWJjN2I5ZDM2ZmI5MmI2YmYyOTJiZTczZDMyYzZjNWIwZWNjMjViNDQzMjNhNTQxZmFlMWYxZTY3ZTM5M2EzZSJ9fX0="
+ )
+ );
+ put(
+ "family_corrupted_protector",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aEndstone Protector",
+ "a46a9adf-60a3-38f2-a3dd-335d85f1cc10",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJiY2FjZWViNDE2MmY0MDBkNDQ3NDMzMTU5MzJhYzgyMGQzMTE5YWM4OTg2YTAxNjFhNzI2MTYxY2NjOTNmYyJ9fX0="
+ )
+ );
+ put(
+ "family_obsidian_wither",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aObsidian Defender",
+ "d0e05de7-6067-454d-beae-c6d19d886191",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMjg1MTE1NCwKICAicHJvZmlsZUlkIiA6ICJkMGUwNWRlNzYwNjc0NTRkYmVhZWM2ZDE5ZDg4NjE5MSIsCiAgInByb2ZpbGVOYW1lIiA6ICJNb3VsYmVycnkiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNlMTU1MjI0ZWE0YmM0OWE4ZTkxOTA3MzdjYjA0MTdkOGE3YzM4YTAzN2Q4ZDAzODJkZGU0ODI5YzEwMzU5MCIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9"
+ )
+ );
+ put(
+ "family_voidling_extremist",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§dVoidling Extremist",
+ "159dcb01-74e3-382c-87d6-3afa022fb379",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWIwNzU5NGUyZGYyNzM5MjFhNzdjMTAxZDBiZmRmYTExMTVhYmVkNWI5YjIwMjllYjQ5NmNlYmE5YmRiYjRiMyJ9fX0="
+ )
+ );
+ put(
+ "family_voidling_fanatic",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aVoidling Fanatic",
+ "e86aab24-6245-3967-bf3d-07e31999b602",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTUzYjdiY2Q1NmYwYjk1Zjg3ZGQ3OWVkMTc2MzZiZWI5ZDgzNDY3NDQwMTQyMjhlYTJmNmIxMTBiMTQ4YzEifX19"
+ )
+ );
+ put(
+ "family_watcher",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWatcher",
+ "00a702b9-7bad-3205-a04b-52478d8c0e7f",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGFhOGZjOGRlNjQxN2I0OGQ0OGM4MGI0NDNjZjUzMjZlM2Q5ZGE0ZGJlOWIyNWZjZDQ5NTQ5ZDk2MTY4ZmMwIn19fQ=="
+ )
+ );
+ put(
+ "family_zealot_enderman",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.ender_chest), EnumChatFormatting.AQUA + "§aZealot")
+ );
+
+ // Crimson Isle
+ put(
+ "family_ashfang",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aAshfang",
+ "1bc8810e-2b57-3a89-8e00-a47a057d6ecc",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2QyYTViNGIxMDliZDc4OGVkYmEwMTcxZDBhYWI4YTU1MzA1YWMyZjU2MTg0ZGY3MGEzMTljZDQ4OGEzNmMzZSJ9fX0="
+ )
+ );
+ put(
+ "family_barbarian_duke_x",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aBarbarian Duke X",
+ "6ddece1d-8227-35f3-b9ca-476a9f6cd8c5",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0MTI0OTYyNTU3NSwKICAicHJvZmlsZUlkIiA6ICIyNzZlMDQ2YjI0MDM0M2VkOTk2NmU0OTRlN2U2Y2IzNCIsCiAgInByb2ZpbGVOYW1lIiA6ICJBRFJBTlM3MTAiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmVlOWZjN2MxODFlMmY2MzBmNmIxYWY4NWQ0OTUxMzU5Y2FmY2ZhODJmZjVlYTNiYzI4M2UwZTYwODhjNmU1NCIKICAgIH0KICB9Cn0"
+ )
+ );
+ put(
+ "family_bladesoul",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aBladesoul",
+ "9a1699a4-9b61-37a5-be7a-ca23a1f092a1",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NDA4Mjg1NzcxMCwKICAicHJvZmlsZUlkIiA6ICIwNTVhOTk2NTk2M2E0YjRmOGMwMjRmMTJmNDFkMmNmMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVWb3hlbGxlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdmNWYzMzg0Mzg0ZDdmMDNiZjk3YTczMDk5YjBiYWZiNzJjNTM4ZmMwNDE1YWM4NjEzYjY2NGY4NzU3OWEzNzkiCiAgICB9CiAgfQp9"
+ )
+ );
+ put(
+ "family_blaze",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aBlaze",
+ "118fe834-28aa-3b0d-afe6-f0c52d01afe8",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ=="
+ )
+ );
+ put(
+ "family_flaming_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aFlaming Spider",
+ "d27e14a2-f35e-3c7b-8062-089fa201a533",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NDQ5OTUzOTQ2NywKICAicHJvZmlsZUlkIiA6ICJhYTZhNzUwNWVkYmU0NjNiYjk1NWYyMWY0MjNiYTM1NCIsCiAgInByb2ZpbGVOYW1lIiA6ICJub3RhbmR5d2FyaG9sIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzVhNjVlZjIzZWEzNTA0NzE1MGQzMzg4MDQ3M2E0N2ZlNjM1ZjBjMGUzYzgyM2JkNzZkYzg0OWNiMDI0NDE2NTUiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ=="
+ )
+ );
+ put(
+ "family_ghast",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aGhast",
+ "69725d7d-1933-3dea-87bd-a3052482ab2c",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGU4YTM4ZTlhZmJkM2RhMTBkMTliNTc3YzU1YzdiZmQ2YjRmMmU0MDdlNDRkNDAxN2IyM2JlOTE2N2FiZmYwMiJ9fX0="
+ )
+ );
+ put(
+ "family_mage_outlaw",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aMage Outlaw",
+ "1d16c26c-d937-336f-821a-371968d050c2",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NDA4Mjg3Mzk2NywKICAicHJvZmlsZUlkIiA6ICJiNzQ3OWJhZTI5YzQ0YjIzYmE1NjI4MzM3OGYwZTNjNiIsCiAgInByb2ZpbGVOYW1lIiA6ICJTeWxlZXgiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWJlYzk5YjNhMDUwZmQyNzc1Mjg0MDc2NzYzNjZlMjBiOTIwMDZhZDg4ZDE0NzI3YTRkOTllYjhjYjI3M2I2MiIKICAgIH0KICB9Cn0"
+ )
+ );
+ put(
+ "family_magma_cube",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aMagma Cube",
+ "35f02923-7bec-3869-9ef5-b42a4794cac8",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0="
+ )
+ );
+ put(
+ "family_magma_cube_boss",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§6§lMagma Cube Boss",
+ "35f02923-7bec-3869-9ef5-b42a4794cac8",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0="
+ )
+ );
+ put(
+ "family_matcho",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aMatcho",
+ "61db73be-677f-554a-9450-e306a7ff0449",
+ "e3RleHR1cmVzOntTS0lOOnt1cmw6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWYyZGFhYmI3OGExZjdhYTEyZDE0NWQ4OGMwY2E0NmI5ZTg1NmY1NTM0ZTkyODZlNTU1ZmFmMGMyOTFmNGZkNSJ9fX0="
+ )
+ );
+ put(
+ "family_charging_mushroom_cow",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aMushroom Bull",
+ "2b9eb675-2097-4b51-8fec-c1a51562f19c",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTE2M2JjNDE2YjhlNjA1OGY5MmIyMzFlOWE1MjRiN2ZlMTE4ZWI2ZTdlZWFiNGFkMTZkMWI1MmEzZWMwNGZjZCJ9fX0="
+ )
+ );
+ put(
+ "family_pigman",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aPigman",
+ "3fc29372-e78e-3ad6-b0b0-05ca0a84babd",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOWM2ZTk4NTgyZmZkOGZmOGZlYjMzMjJjZDE4NDljNDNmYjE2YjE1OGFiYjExY2E3YjQyZWRhNzc0M2ViIn19fQ=="
+ )
+ );
+ put(
+ "family_wither_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWither Skeleton",
+ "2141b934-c877-3db1-bc6c-7c9a347ffa95",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzk1M2I2YzY4NDQ4ZTdlNmI2YmY4ZmIyNzNkNzIwM2FjZDhlMWJlMTllODE0ODFlYWQ1MWY0NWRlNTlhOCJ9fX0="
+ )
+ );
+ put(
+ "family_wither_spectre",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWither Spectre",
+ "9a1699a4-9b61-37a5-be7a-ca23a1f092a1",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0NDA4Mjg1NzcxMCwKICAicHJvZmlsZUlkIiA6ICIwNTVhOTk2NTk2M2E0YjRmOGMwMjRmMTJmNDFkMmNmMiIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaGVWb3hlbGxlIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzdmNWYzMzg0Mzg0ZDdmMDNiZjk3YTczMDk5YjBiYWZiNzJjNTM4ZmMwNDE1YWM4NjEzYjY2NGY4NzU3OWEzNzkiCiAgICB9CiAgfQp9"
+ )
+ );
+
+ // Deep Caverns
+ put(
+ "family_automaton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aAutomaton",
+ "a46a9adf-60a3-38f2-a3dd-335d85f1cc10",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjJiY2FjZWViNDE2MmY0MDBkNDQ3NDMzMTU5MzJhYzgyMGQzMTE5YWM4OTg2YTAxNjFhNzI2MTYxY2NjOTNmYyJ9fX0="
+ )
+ );
+ put(
+ "family_butterfly",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§eButterfly",
+ "9dd11ec6-cfea-34df-9336-416c946567bc",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYyNTUxMjE4ODY3NCwKICAicHJvZmlsZUlkIiA6ICI3MzgyZGRmYmU0ODU0NTVjODI1ZjkwMGY4OGZkMzJmOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJJb3lhbCIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS85ZmQ4MDZkZWZkZmRmNTliMWYyNjA5YzhlZTM2NDY2NmRlNjYxMjdhNjIzNDE1YjU0MzBjOTM1OGM2MDFlZjdjIgogICAgfQogIH0KfQ=="
+ )
+ );
+ put(
+ "family_emerald_slime",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aEmerald Slime",
+ "cb762e0d-a1e6-3888-8c05-eddabbbe49a2",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTc3NGU4NmFhNGNmZjc5MjM5NWI3N2FkZDU3YjAwYmIxYTEwMmY4ZjBmMDk4MGY0ZDU1YjNkN2FmZjFlNmRhOSJ9fX0="
+ )
+ );
+ put(
+ "family_caverns_ghost",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aGhost",
+ "c5752211-7503-3e77-9890-d1cf6ba1d0e7",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTgxOTc3OTE4YTExODBlMGRlYzg3OWU2YmNkMWFhMzk0OTQ5NzdiYjkxM2JlMmFiMDFhZmYxZGIxZmE0In19fQ=="
+ )
+ );
+ put(
+ "family_goblin",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aGoblin",
+ "7c7d07db-4911-31f1-9a19-1589899cfe25",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjZiOTcyZTMyZDc2MWIxOTI2MjZlNWQ2ZDAxZWRjMDk0OTQwOTEwMTAzY2VhNWUyZTJkMWYyMzFhZGI3NTVkNSJ9fX0="
+ )
+ );
+ put(
+ "family_team_treasurite",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aGrunt",
+ "a64ccd19-2a64-39a4-b2f5-cb6799c12a99",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxODE5NTA2MDUwMCwKICAicHJvZmlsZUlkIiA6ICI0ZTMwZjUwZTdiYWU0M2YzYWZkMmE3NDUyY2ViZTI5YyIsCiAgInByb2ZpbGVOYW1lIiA6ICJfdG9tYXRvel8iLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWY1ZTAzYjhkZTExOWY4NTg5YTgwODIyNGNiZWE3MzdmNWRjZjI0MjM1Nzk5YjczNzhhYzViZjA2YWJmNmRkNCIKICAgIH0KICB9Cn0="
+ )
+ );
+ put(
+ "family_ice_walker",
+ Utils.createItemStack(Item.getItemFromBlock(Blocks.packed_ice), EnumChatFormatting.AQUA + "§aIce Walker")
+ );
+ put("family_lapis_zombie", Utils.createItemStack(Items.dye, EnumChatFormatting.AQUA + "§aLapis Zombie", 4));
+ put(
+ "family_diamond_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aMiner Skeleton",
+ "39c843e6-237b-36b2-8a7b-c5ff5d3ebf99",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODM2YmJjNDIxNWNlYTFiNmE0ODRlODkzYjExNmU3MzQ1OWVmMzZiZmZjNjIyNzQxZTU3N2U5NDkzYTQxZTZlIn19fQ=="
+ )
+ );
+ put(
+ "family_diamond_zombie",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aMiner Zombie",
+ "468210c9-f4bd-34c7-aa8d-2c3d0d5e05c1",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDI4ZDlmZjU0MTg4YTFhZmVlNjViOTRmM2JmY2NlMzIxYzY0M2EzNDU5MGMxNGIxOTJiMmUzZWMyZjUyNWQzIn19fQ=="
+ )
+ );
+ put("family_redstone_pigman", Utils.createItemStack(Items.redstone, EnumChatFormatting.AQUA + "§aRedstone Pigman"));
+ put(
+ "family_sludge",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSludge",
+ "3b70a2f3-319c-38d5-b7d1-5b2425770184",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1YWVlYzZiODQyYWRhODY2OWY4NDZkNjViYzQ5NzYyNTk3ODI0YWI5NDRmMjJmNDViZjNiYmI5NDFhYmU2YyJ9fX0="
+ )
+ );
+ put(
+ "family_invisible_creeper",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSneaky Creeper",
+ "81fb1385-b2fc-4d4f-b5bb-0fe9b1d37d60",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYxOTE5MjI5MzI5OCwKICAicHJvZmlsZUlkIiA6ICI0ZjU2ZTg2ODk2OGU0ZWEwYmNjM2M2NzRlNzQ3ODdjOCIsCiAgInByb2ZpbGVOYW1lIiA6ICJDVUNGTDE1IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2E2ODIyNGNmOGVkNGMwM2I0NTdiZjQ5YmViNmY1NDQxOTM2NzkyNjhiODQyMWIwMWZmY2U2ZDI3YjI1YWMzMmQiCiAgICB9CiAgfQp9"
+ )
+ );
+ put(
+ "family_thyst",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aThyst",
+ "b3224e56-73d2-32f9-9081-a23b7512035b",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWJjN2I5ZDM2ZmI5MmI2YmYyOTJiZTczZDMyYzZjNWIwZWNjMjViNDQzMjNhNTQxZmFlMWYxZTY3ZTM5M2EzZSJ9fX0="
+ )
+ );
+ put(
+ "family_treasure_hoarder",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aTreasure Hoarder",
+ "b0f13fc2-07a5-3964-8303-784f802e5f0f",
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5MDE1NjYzNDYzOCwKICAicHJvZmlsZUlkIiA6ICI5MWZlMTk2ODdjOTA0NjU2YWExZmMwNTk4NmRkM2ZlNyIsCiAgInByb2ZpbGVOYW1lIiA6ICJoaGphYnJpcyIsCiAgInNpZ25hdHVyZVJlcXVpcmVkIiA6IHRydWUsCiAgInRleHR1cmVzIiA6IHsKICAgICJTS0lOIiA6IHsKICAgICAgInVybCIgOiAiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iMmIxMmE4MTRjZWQ4YWYwMmNkZGYyOWEzN2U3ZjMwMTFlNDMwZThhMThiMzhiNzA2ZjI3YzZiZDMxNjUwYjY1IgogICAgfQogIH0KfQ=="
+ )
+ );
+ put(
+ "family_worms",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWorm",
+ "29f95759-1a6f-3e85-9941-91a7a2275274",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYyMDQ0NTc2NDQ1MSwKICAicHJvZmlsZUlkIiA6ICJmNDY0NTcxNDNkMTU0ZmEwOTkxNjBlNGJmNzI3ZGNiOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJSZWxhcGFnbzA1IiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2RmMDNhZDk2MDkyZjNmNzg5OTAyNDM2NzA5Y2RmNjlkZTZiNzI3YzEyMWIzYzJkYWVmOWZmYTFjY2FlZDE4NmMiLAogICAgICAibWV0YWRhdGEiIDogewogICAgICAgICJtb2RlbCIgOiAic2xpbSIKICAgICAgfQogICAgfQogIH0KfQ=="
+ )
+ );
+ put(
+ "family_yog",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aYog",
+ "35f02923-7bec-3869-9ef5-b42a4794cac8",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzg5NTdkNTAyM2M5MzdjNGM0MWFhMjQxMmQ0MzQxMGJkYTIzY2Y3OWE5ZjZhYjM2Yjc2ZmVmMmQ3YzQyOSJ9fX0="
+ )
+ );
+
+ // The Park
+ put(
+ "family_howling_spirit",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§bHowling Spirit",
+ "802a167c-cbcd-3a1f-becd-5b1a25a4cf15",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjOGJlZjZiZWI3N2UyOWFmODYyN2VjZGMzOGQ4NmFhMmZlYTdjY2QxNjNkYzczYzAwZjlmMjU4ZjlhMTQ1NyJ9fX0="
+ )
+ );
+ put(
+ "family_pack_spirit",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§bPack Spirit",
+ "802a167c-cbcd-3a1f-becd-5b1a25a4cf15",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjOGJlZjZiZWI3N2UyOWFmODYyN2VjZGMzOGQ4NmFhMmZlYTdjY2QxNjNkYzczYzAwZjlmMjU4ZjlhMTQ1NyJ9fX0="
+ )
+ );
+ put(
+ "family_soul_of_the_alpha",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§3Soul of the Alpha",
+ "802a167c-cbcd-3a1f-becd-5b1a25a4cf15",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjdjOGJlZjZiZWI3N2UyOWFmODYyN2VjZGMzOGQ4NmFhMmZlYTdjY2QxNjNkYzczYzAwZjlmMjU4ZjlhMTQ1NyJ9fX0="
+ )
+ );
+
+ // Spooky
+ put(
+ "family_batty_witch",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§8Crazy Witch",
+ "cf4f97d7-2e1f-3678-9ca3-4a7b9666cc28",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmNlNjYwNDE1N2ZjNGFiNTU5MWU0YmNmNTA3YTc0OTkxOGVlOWM0MWUzNTdkNDczNzZlMGVlNzM0MjA3NGM5MCJ9fX0="
+ )
+ );
+ put(
+ "family_headless_horseman",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§6Headless Horseman",
+ "2594a979-1302-3d6e-a1da-c9dbf0959539",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGM2NTcwZjEyNDI5OTJmNmViYTIzZWU1ODI1OThjMzllM2U3NDUzODMyNzNkZWVmOGIzOTc3NTgzZmUzY2Y1In19fQ=="
+ )
+ );
+ put(
+ "family_phantom_spirit",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§cPhantom Spirit",
+ "805d7035-5f25-37ea-8530-7c0d09156c8e",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYwMzcyMjc5NzYzNywKICAicHJvZmlsZUlkIiA6ICJhMmY4MzQ1OTVjODk0YTI3YWRkMzA0OTcxNmNhOTEwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJiUHVuY2giLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjUzYjJmN2M1ZTE3N2JkNjdjZWFkMzBkMGVlNTM0MjVjNzY4NGM5NzVjOGMyYTUyNzNhMDljYTQ5YTFmNmNkZCIKICAgIH0KICB9Cn0="
+ )
+ );
+ put(
+ "family_scary_jerry",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§6Scary Jerry",
+ "127e3dec-4ab7-3798-9410-5fce3f227632",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYwMzczMzU4OTcxOSwKICAicHJvZmlsZUlkIiA6ICJhMmY4MzQ1OTVjODk0YTI3YWRkMzA0OTcxNmNhOTEwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJiUHVuY2giLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGYyMDJkYzI0ZDE1ZjdjZTM2ZTAyZmI0YjNlODE1M2IxNDZhYjljMTcyNGFhYTVkNDg0Yzc0MWRhMGVlYjZmZCIKICAgIH0KICB9Cn0="
+ )
+ );
+ put(
+ "family_trick_or_treater",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§eTrick or Treater",
+ "79dd9434-1fde-3aac-87a7-bb09d91eba77",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDdjYmUwNjFiNDQ1Yjg4Y2IyZGY1OWFjY2M4ZDJjMWMxMjExOGZlMGIyMTI3ZTZlNzU4MTM1NTBhZGFjNjdjZiJ9fX0="
+ )
+ );
+ put(
+ "family_wither_gourd",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§6Wither Gourd",
+ "3263c14e-c555-365e-a244-0ee97a8b2056",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjhmMmZmYzZmYjRlOTk1OWI5YTdhMzE3ZjUxYTY3NzVhMTU5ZGRjMjI0MWRiZDZjNzc0ZDNhYzA4YjYifX19"
+ )
+ );
+ put(
+ "family_wraith",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§8Wraith",
+ "bca22b11-8e4c-386a-8824-7b2bd6364cde",
+ "ewogICJ0aW1lc3RhbXAiIDogMTYwMzczMzcxNjI0MiwKICAicHJvZmlsZUlkIiA6ICJhMmY4MzQ1OTVjODk0YTI3YWRkMzA0OTcxNmNhOTEwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJiUHVuY2giLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYWVhYmMzMDc1Y2Y0MWYzOGU2ZGYxMjM2Yjk1Y2FhZmNiYTFiZWUyMmM0OWQ4MDRiOTQyNzQ4OGMyZjZlMGVmYyIKICAgIH0KICB9Cn0="
+ )
+ );
+
+ // Dungeons
+ put(
+ "family_diamond_guy",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§d§lAngry Archeologist",
+ "db784d7a-fae1-3d60-9a5a-42a1814037f8",
+ "eyJ0aW1lc3RhbXAiOjE1NzU0NzAzOTQwMzEsInByb2ZpbGVJZCI6IjdkYTJhYjNhOTNjYTQ4ZWU4MzA0OGFmYzNiODBlNjhlIiwicHJvZmlsZU5hbWUiOiJHb2xkYXBmZWwiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2M0OGM3ODM0NThlNGNmODUxOGU4YWI1ODYzZmJjNGNiOTQ4ZjkwNTY4ZWViOWE2MGQxNmM0ZmRlMmI5NmMwMzMifX19"
+ )
+ );
+ put(
+ "family_cellar_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aCellar Spider",
+ "a8aee72d-0d1d-3db7-8cf8-be1ce6ec2dc4",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19"
+ )
+ );
+ put(
+ "family_crypt_dreadlord",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aCrypt Dreadlord",
+ "68b4c885-7447-3382-b86b-b661b464d76e",
+ "eyJ0aW1lc3RhbXAiOjE1NjI0Mjc0MTA5MTQsInByb2ZpbGVJZCI6ImIwZDczMmZlMDBmNzQwN2U5ZTdmNzQ2MzAxY2Q5OGNhIiwicHJvZmlsZU5hbWUiOiJPUHBscyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjZmMzQ5MjcwYTNiODUxODk2Y2RhZDg0MmY1ZWVjNmUxNDBiZDkxMTliNzVjMDc0OTU1YzNiZTc4NjVlMjdjNyJ9fX0="
+ )
+ );
+ put(
+ "family_crypt_lurker",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aCrypt Lurker",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+ put(
+ "family_crypt_souleater",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aCrypt Souleater",
+ "68b4c885-7447-3382-b86b-b661b464d76e",
+ "eyJ0aW1lc3RhbXAiOjE1NjI0Mjc0MTA5MTQsInByb2ZpbGVJZCI6ImIwZDczMmZlMDBmNzQwN2U5ZTdmNzQ2MzAxY2Q5OGNhIiwicHJvZmlsZU5hbWUiOiJPUHBscyIsInNpZ25hdHVyZVJlcXVpcmVkIjp0cnVlLCJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjZmMzQ5MjcwYTNiODUxODk2Y2RhZDg0MmY1ZWVjNmUxNDBiZDkxMTliNzVjMDc0OTU1YzNiZTc4NjVlMjdjNyJ9fX0="
+ )
+ );
+ put(
+ "family_king_midas",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§d§lKing Midas",
+ "1a85d923-f8dd-35b8-899a-8f13b9469b0c",
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5MTU3NjA3MDMwMCwKICAicHJvZmlsZUlkIiA6ICJkYTQ5OGFjNGU5Mzc0ZTVjYjYxMjdiMzgwODU1Nzk4MyIsCiAgInByb2ZpbGVOYW1lIiA6ICJOaXRyb2hvbGljXzIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjJiY2EwODU3NTAwNDM1MDNmNWRmOWY3ZGVmODI0YTJlM2FjZmMyNzg0MmJjZDA5ZDJiNjY5NTg4MWU4MzJmNSIKICAgIH0KICB9Cn0="
+ )
+ );
+ put(
+ "family_lonely_spider",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aLonely Spider",
+ "7c63f3cf-a963-311a-aeca-3a075b417806",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvY2Q1NDE1NDFkYWFmZjUwODk2Y2QyNThiZGJkZDRjZjgwYzNiYTgxNjczNTcyNjA3OGJmZTM5MzkyN2U1N2YxIn19fQ=="
+ )
+ );
+ put(
+ "family_lost_adventurer",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§d§lLost Adventurer",
+ "f69ba621-a8b6-31a7-8de1-dc7ade140e1d",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHBzOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzFlMDMyOWY0MjE5MmVlN2MxYTBjNzA0ZjgyZGJiYmU3YzAwZmJmYTNmMDIwYzEwNjdhMjA4NjMwYjk5MWI5ODgifX19"
+ )
+ );
+ put(
+ "family_scared_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aScared Skeleton",
+ "53924f1a-87e6-4709-8e53-f1c7d13dc239",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9="
+ )
+ );
+ put(
+ "family_shadow_assassin",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§d§lShadow Assassin",
+ "ef18719c-db6a-3ffb-97ca-4ed764ce9464",
+ "ewogICJ0aW1lc3RhbXAiIDogMTU5MjI2ODE3MDkxMSwKICAicHJvZmlsZUlkIiA6ICJkYTQ5OGFjNGU5Mzc0ZTVjYjYxMjdiMzgwODU1Nzk4MyIsCiAgInByb2ZpbGVOYW1lIiA6ICJOaXRyb2hvbGljXzIiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzM5OWUwMGY0MDQ0MTFlNDY1ZDc0Mzg4ZGYxMzJkNTFmZTg2OGVjZjg2ZjFjMDczZmFmZmExZDkxNzJlYzBmMyIKICAgIH0KICB9Cn0="
+ )
+ );
+ put(
+ "family_skeleton_grunt",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSkeleton Grunt",
+ "dfed3415-919e-3358-b563-0abd0513f74c",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzA0NzE2NzdiMzdhZTg0MmMyYmQyMzJlMTZlZWI4NGQ1YTQ5MzIzMWVlY2VjMDcyZGEzOGJlMzEyN2RkNWM4In19fQ=="
+ )
+ );
+ put(
+ "family_skeleton_master",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSkeleton Master",
+ "ce22e0d7-c78e-3c8d-907a-2368c927808c",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzRlOTVlMWI3ZGM4MmJhNzg0NWE2OGZjNmEzMTJmNGNkOTBlZTJmNmNjZTI2YTY4Yzg4YjA0YjEwNzJkODc5In19fQ=="
+ )
+ );
+ put(
+ "family_skeleton_soldier",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSkeleton Soldier",
+ "cab75065-c896-338e-a399-c4a6da16d678",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjE5Njg4ZTBjMmYwNWFlYjk3OWQ2YTFiOGM5MTE5NTdiN2QzNjU3ZTE0YjU3YWY5M2M1ZWY2ZjZhNTk1NjlkZCJ9fX0="
+ )
+ );
+ put(
+ "family_skeletor",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSkeletor",
+ "49fcfb3e-da7e-3fda-b4f9-37df5ac8fbd3",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODlkMDc0YWQ5Yjk5NzE4NzllYjMyNWJkZGZmMzY3NWY3MjI0ODU2YmQ2ZDU2OWZjOGQ0ODNjMTMzZDczMDA1ZCJ9fX0K"
+ )
+ );
+ put(
+ "family_sniper_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSniper",
+ "848130dc-9c46-3818-a099-b429cb2f1d75",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjE4YzA3MWYwODBkYmE1MGE2MmE2MjYzZmY3MjRlZGMxNTdjZTRmYjQ4ODNjY2VmZjI0OTFkNWJiZGU4MzBjMSJ9fX0K"
+ )
+ );
+ put(
+ "family_super_archer",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSuper Archer",
+ "8ebf155b-7b8f-386f-91f1-2e425db4230f",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGNhZTZkYjBiNTlhNjQzMDUwNzZkOTY2ZDhlN2I5YTk3YmU0NmRhZTNhODA3NzE0ZmE4NmQzNzg0OGY2In19fQ=="
+ )
+ );
+ put(
+ "family_super_tank_zombie",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aSuper Tank Zombie",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+ put(
+ "family_crypt_tank_zombie",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aTank Zombie",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+ put(
+ "family_watcher_summon_undead",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§a§4§lUndead",
+ "0ac53e90-4e60-388c-a754-092dd4578592",
+ "eyJ0aW1lc3RhbXAiOjE1ODYwNDAyMDM1NzMsInByb2ZpbGVJZCI6ImRhNDk4YWM0ZTkzNzRlNWNiNjEyN2IzODA4NTU3OTgzIiwicHJvZmlsZU5hbWUiOiJOaXRyb2hvbGljXzIiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2Y0NjI0YTlhOGM2OWNhMjA0NTA0YWJiMDQzZDQ3NDU2Y2Q5YjA5NzQ5YTM2MzU3NDYyMzAzZjI3NmEyMjlkNCJ9fX0="
+ )
+ );
+ put(
+ "family_dungeon_respawning_skeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aUndead Skeleton",
+ "53924f1a-87e6-4709-8e53-f1c7d13dc239",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMTgzNjcwNCwKICAicHJvZmlsZUlkIiA6ICI1MzkyNGYxYTg3ZTY0NzA5OGU1M2YxYzdkMTNkYzIzOSIsCiAgInByb2ZpbGVOYW1lIiA6ICJUaHJvd3BvIiwKICAic2lnbmF0dXJlUmVxdWlyZWQiIDogdHJ1ZSwKICAidGV4dHVyZXMiIDogewogICAgIlNLSU4iIDogewogICAgICAidXJsIiA6ICJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlLzg4ZWI2OGE0ZDM4ZTlmNDQ2YjhlOTkyNzVmMTYwMzAyZjM2NmVmMTAyMTZhYmY5NDg0ODdlNTgyNTEyYmQwZjMiCiAgICB9CiAgfQp9="
+ )
+ );
+ put(
+ "family_crypt_witherskeleton",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aWithermancer",
+ "d0e05de7-6067-454d-beae-c6d19d886191",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY1NTYzMjg1MTE1NCwKICAicHJvZmlsZUlkIiA6ICJkMGUwNWRlNzYwNjc0NTRkYmVhZWM2ZDE5ZDg4NjE5MSIsCiAgInByb2ZpbGVOYW1lIiA6ICJNb3VsYmVycnkiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNlMTU1MjI0ZWE0YmM0OWE4ZTkxOTA3MzdjYjA0MTdkOGE3YzM4YTAzN2Q4ZDAzODJkZGU0ODI5YzEwMzU5MCIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9"
+ )
+ );
+ put(
+ "family_zombie_commander",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aZombie Commander",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+ put(
+ "family_zombie_grunt",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aZombie Grunt",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+ put(
+ "family_zombie_knight",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aZombie Knight",
+ "34af9e21-dff4-3b94-9fb5-07816e41af75",
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjVkMmYzMWJhMTYyZmU2MjcyZTgzMWFlZDE3ZjUzMjEzZGI2ZmExYzRjYmU0ZmM4MjdmMzk2M2NjOThiOSJ9fX0="
+ )
+ );
+ put(
+ "family_zombie_soldier",
+ Utils.createSkull(
+ EnumChatFormatting.AQUA + "§aZombie Soldier",
+ "9673d491-d589-44cb-b63e-5f8b3148b3df",
+ "ewogICJ0aW1lc3RhbXAiIDogMTY0Njc1NjU2MzM1MiwKICAicHJvZmlsZUlkIiA6ICJkYmQ4MDQ2M2EwMzY0Y2FjYjI3OGNhODBhMDBkZGIxMyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ4bG9nMjEiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjM2NjZkMWJkZjQ1NThiMGQxNjk5MGIyNDFlODE4NWNiZjU4YzNlMDNjMjRkOTA0NTQ0ZThjYzY1YjFjMzhkMSIKICAgIH0KICB9Cn0=\", \"n8vct7fj3NdiODy/h6PJhjxSR2U7d8gQxHjdVq553HqG60SSczt1Tl9XhvQbZP14ZrJGWxCziauuYb/HjZza0ugNAhfwh9z8hqR1PjBJGdvp+wpxoWpP2wd5RT9i5/GYEqpiAIAt9vHY1YeyejFqKZhXaGgp7gZZNjOQWQqB0SZzTUTAPzRW9FiY8x2re7H7Y1POThRXOvvkeQ6qWdPV6Hk5hTumV0rfEGm971jQRIbfdzBZDJRcro+8y+dlje/NpF5qf0JLy78Xr4hc2cwbT9+wqOeoUTcM/r9mwL15OKgFLjB44jszauKRHNfoqb6B3+1fNQEJrJK/7hIyvswpde7C5uOxkE7oMFib6X68VVEhb6PGC1+HWNaMaGjI0wWEkCahp48ihN9+sBEBFXOxIAhXG/pvJcbEi742/cBS1CTtOI8qui6JSL9MKX5jmyhtjjibOYRZbacosqayCnwsJAdMmwS7zIxc8jGhpfKECiSni/baS4zRla0bns4hfEM0l7ASv0Dh99WQD0We2ZMqltmix8lMEaAILXJVBln3CFrjYvncfku2hrSaqu1lNAtfMYYSITEUCBJ7McVAVmUHOrER0XGoVs9L237H0BQNSLqlGGEQ7OM8HV6G0YfXGlbNgNBx6O9k8ZijuK60JeEoJapcmbNj/LVHEU+dsgcFAbo="
+ )
+ );
+ }
+ };
+ private static final LinkedHashMap<String, String> mobTypeMap = new LinkedHashMap<String, String>() {
+ {
+ // Island
+ put("family_cave_spider", "ISLAND");
+ put("family_enderman_private", "ISLAND");
+ put("family_skeleton", "ISLAND");
+ put("family_slime", "ISLAND");
+ put("family_spider", "ISLAND");
+ put("family_witch", "ISLAND");
+ put("family_zombie", "ISLAND");
+
+ // Hub
+ put("family_unburried_zombie", "MOB");
+ put("family_old_wolf", "MOB");
+ put("family_ruin_wolf", "MOB");
+ put("family_zombie_villager", "MOB");
+
+ // Spiders Den
+ put("family_arachne", "BOSS");
+ put("family_arachne_brood", "MOB");
+ put("family_arachne_keeper", "MOB");
+ put("family_brood_mother_spider", "BOSS");
+ put("family_dasher_spider", "MOB");
+ put("family_respawning_skeleton", "MOB");
+ put("family_random_slime", "MOB");
+ put("family_spider_jockey", "MOB");
+ put("family_splitter_spider", "MOB");
+ put("family_voracious_spider", "MOB");
+ put("family_weaver_spider", "MOB");
+
+ // The End
+ put("family_dragon", "BOSS");
+ put("family_enderman", "MOB");
+ put("family_endermite", "MOB");
+ put("family_corrupted_protector", "BOSS");
+ put("family_obsidian_wither", "MOB");
+ put("family_voidling_extremist", "MOB");
+ put("family_voidling_fanatic", "MOB");
+ put("family_watcher", "MOB");
+ put("family_zealot_enderman", "MOB");
+
+ // Crimson Isles
+ put("family_ashfang", "BOSS");
+ put("family_barbarian_duke_x", "BOSS");
+ put("family_bladesoul", "BOSS");
+ put("family_blaze", "MOB");
+ put("family_flaming_spider", "MOB");
+ put("family_ghast", "MOB");
+ put("family_mage_outlaw", "BOSS");
+ put("family_magma_cube", "MOB");
+ put("family_magma_cube_boss", "BOSS");
+ put("family_matcho", "MOB");
+ put("family_charging_mushroom_cow", "MOB");
+ put("family_pigman", "MOB");
+ put("family_wither_skeleton", "MOB");
+ put("family_wither_spectre", "MOB");
+
+ // Deep Caverns
+ put("family_automaton", "MOB");
+ put("family_butterfly", "MOB");
+ put("family_emerald_slime", "MOB");
+ put("family_caverns_ghost", "MOB");
+ put("family_goblin", "MOB");
+ put("family_team_treasurite", "MOB");
+ put("family_ice_walker", "MOB");
+ put("family_lapis_zombie", "MOB");
+ put("family_diamond_skeleton", "MOB");
+ put("family_diamond_zombie", "MOB");
+ put("family_redstone_pigman", "MOB");
+ put("family_sludge", "MOB");
+ put("family_invisible_creeper", "MOB");
+ put("family_thyst", "MOB");
+ put("family_treasure_hoarder", "MOB");
+ put("family_worms", "MOB");
+ put("family_yog", "MOB");
+
+ // The Park
+ put("family_howling_spirit", "MOB");
+ put("family_pack_spirit", "MOB");
+ put("family_soul_of_the_alpha", "MOB");
+
+ // Spooky
+ put("family_batty_witch", "MOB");
+ put("family_headless_horseman", "BOSS");
+ put("family_phantom_spirit", "MOB");
+ put("family_scary_jerry", "MOB");
+ put("family_trick_or_treater", "MOB");
+ put("family_wither_gourd", "MOB");
+ put("family_wraith", "MOB");
+
+ // Catacombs
+ put("family_diamond_guy", "MOB");
+ put("family_cellar_spider", "MOB");
+ put("family_crypt_dreadlord", "MOB");
+ put("family_crypt_lurker", "MOB");
+ put("family_crypt_souleater", "MOB");
+ put("family_king_midas", "MOB");
+ put("family_lonely_spider", "MOB");
+ put("family_lost_adventurer", "MOB");
+ put("family_scared_skeleton", "MOB");
+ put("family_shadow_assassin", "MOB");
+ put("family_skeleton_grunt", "MOB");
+ put("family_skeleton_master", "MOB");
+ put("family_skeleton_soldier", "MOB");
+ put("family_skeletor", "MOB");
+ put("family_sniper_skeleton", "MOB");
+ put("family_super_archer", "MOB");
+ put("family_super_tank_zombie", "MOB");
+ put("family_crypt_tank_zombie", "MOB");
+ put("family_watcher_summon_undead", "MOB");
+ put("family_dungeon_respawning_skeleton", "MOB");
+ put("family_crypt_witherskeleton", "MOB");
+ put("family_zombie_commander", "MOB");
+ put("family_zombie_grunt", "MOB");
+ put("family_zombie_knight", "MOB");
+ put("family_zombie_soldier", "MOB");
+ }
+ };
+
+ public static LinkedHashMap<ItemStack, List<String>> getBestiaryLocations() {
+ return bestiaryLocations;
+ }
+
+ public static LinkedHashMap<String, ItemStack> getBestiaryMobs() {
+ return bestiaryMobs;
+ }
+
+ public static LinkedHashMap<String, String> getMobType() {
+ return mobTypeMap;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java
new file mode 100644
index 00000000..70ea051a
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/bestiary/BestiaryPage.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.bestiary;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewerPage;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.opengl.GL11;
+
+import java.awt.*;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+public class BestiaryPage extends GuiProfileViewerPage {
+
+ public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png");
+ private static final ResourceLocation BESTIARY_TEXTURE = new ResourceLocation("notenoughupdates:pv_bestiary_tab.png");
+ private static final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
+ private static final int XCOUNT = 7;
+ private static final int YCOUNT = 5;
+ private static final float XPADDING = (190 - XCOUNT * 20) / (float) (XCOUNT + 1);
+ private static final float YPADDING = (202 - YCOUNT * 20) / (float) (YCOUNT + 1);
+ private ItemStack selectedBestiaryLocation = null;
+ private List<String> tooltipToDisplay = null;
+
+ public BestiaryPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+ JsonObject profileInfo = GuiProfileViewer.getProfile().getProfileInformation(GuiProfileViewer.getProfileId());
+
+ int bestiarySize = BestiaryData.getBestiaryLocations().size();
+ int bestiaryXSize = (int) (350f / (bestiarySize - 1 + 0.0000001f));
+
+ {
+ int yIndex = 0;
+ for (ItemStack stack : BestiaryData.getBestiaryLocations().keySet()) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ if (mouseX > guiLeft + 30 + bestiaryXSize * yIndex && mouseX < guiLeft + 30 + bestiaryXSize * yIndex + 20) {
+ if (mouseY > guiTop + 10 && mouseY < guiTop + 10 + 20) {
+ tooltipToDisplay = stack.getTooltip(Minecraft.getMinecraft().thePlayer, false);
+ }
+ }
+ if (stack == selectedBestiaryLocation) {
+ Utils.drawTexturedRect(
+ guiLeft + 30 + bestiaryXSize * yIndex,
+ guiTop + 10,
+ 20,
+ 20,
+ 20 / 256f,
+ 0,
+ 20 / 256f,
+ 0,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStack(stack, guiLeft + 32 + bestiaryXSize * yIndex, guiTop + 12);
+ } else {
+ Utils.drawTexturedRect(
+ guiLeft + 30 + bestiaryXSize * yIndex,
+ guiTop + 10,
+ 20,
+ 20,
+ 0,
+ 20 / 256f,
+ 0,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStack(stack, guiLeft + 32 + bestiaryXSize * yIndex, guiTop + 12);
+ }
+ yIndex++;
+ }
+ }
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BESTIARY_TEXTURE);
+ Utils.drawTexturedRect(guiLeft, guiTop, 431, 202, GL11.GL_NEAREST);
+
+ GlStateManager.color(1, 1, 1, 1);
+ Color color = new Color(128, 128, 128, 255);
+ Utils.renderAlignedString(
+ EnumChatFormatting.RED + "Bestiary Level: ",
+ EnumChatFormatting.GRAY + "" + (float) getBestiaryTiers(profileInfo) / 10,
+ guiLeft + 220,
+ guiTop + 50,
+ 110
+ );
+
+ GlStateManager.disableLighting();
+ RenderHelper.enableGUIStandardItemLighting();
+ List<String> mobs = BestiaryData.getBestiaryLocations().get(selectedBestiaryLocation);
+ if (mobs != null) {
+ for (int i = 0; i < mobs.size(); i++) {
+ String mob = mobs.get(i);
+ if (mob != null) {
+ ItemStack mobItem = BestiaryData.getBestiaryMobs().get(mob);
+ if (mobItem != null) {
+ int xIndex = i % XCOUNT;
+ int yIndex = i / XCOUNT;
+
+ float x = 23 + XPADDING + (XPADDING + 20) * xIndex;
+ float y = 30 + YPADDING + (YPADDING + 20) * yIndex;
+
+ float completedness = 0;
+
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y,
+ 20,
+ 20 * (1 - completedness),
+ 0,
+ 20 / 256f,
+ 0,
+ 20 * (1 - completedness) / 256f,
+ GL11.GL_NEAREST
+ );
+ //GlStateManager.color(1, 185 / 255f, 0, 1);
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(
+ guiLeft + x,
+ guiTop + y + 20 * (1 - completedness),
+ 20,
+ 20 * (completedness),
+ 0,
+ 20 / 256f,
+ 20 * (1 - completedness) / 256f,
+ 20 / 256f,
+ GL11.GL_NEAREST
+ );
+ Utils.drawItemStack(mobItem, guiLeft + (int) x + 2, guiTop + (int) y + 2);
+ float kills = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.kills_" + mob), 0);
+ float deaths = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.deaths_" + mob), 0);
+
+ String type;
+ if (BestiaryData.getMobType().get(mob) != null) {
+ type = BestiaryData.getMobType().get(mob);
+ } else {
+ type = "MOB";
+ }
+ JsonObject leveling = Constants.LEVELING;
+ ProfileViewer.Level level = null;
+ if (leveling != null && Utils.getElement(leveling, "bestiary." + type) != null) {
+ JsonArray levelingArray = Utils.getElement(leveling, "bestiary." + type).getAsJsonArray();
+ int levelCap = Utils.getElementAsInt(Utils.getElement(leveling, "bestiary.caps." + type), 0);
+ level = ProfileViewer.getLevel(levelingArray, kills, levelCap, false);
+ } else {
+ Utils.showOutdatedRepoNotification();
+ }
+
+ float levelNum = -1;
+ if (level != null) {
+ levelNum = level.level;
+ }
+ if (mouseX > guiLeft + (int) x + 2 && mouseX < guiLeft + (int) x + 18) {
+ if (mouseY > guiTop + (int) y + 2 && mouseY < guiTop + (int) y + 18) {
+ tooltipToDisplay = new ArrayList<>();
+ tooltipToDisplay.add(
+ mobItem.getDisplayName() + " " + ((levelNum == -1) ? "?" : (int) Math.floor(levelNum))
+ );
+ tooltipToDisplay.add(
+ EnumChatFormatting.GRAY + "Kills: " + EnumChatFormatting.GREEN + numberFormat.format(kills)
+ );
+ tooltipToDisplay.add(
+ EnumChatFormatting.GRAY + "Deaths: " + EnumChatFormatting.GREEN + numberFormat.format(deaths)
+ );
+ if (level != null) {
+ String progressStr;
+ if (level.maxed) {
+ progressStr = EnumChatFormatting.GOLD + "MAXED!";
+ } else {
+ progressStr = EnumChatFormatting.AQUA +
+ StringUtils.shortNumberFormat(Math.round((levelNum % 1) * level.maxXpForLevel)) +
+ "/" +
+ StringUtils.shortNumberFormat(level.maxXpForLevel);
+ }
+ tooltipToDisplay.add(EnumChatFormatting.GRAY + "Progress: " + progressStr);
+ }
+ }
+ }
+
+ GlStateManager.color(1, 1, 1, 1);
+ // if (tier >= 0) {
+ // Utils.drawStringCentered(tierString, Minecraft.getMinecraft().fontRendererObj,
+ // guiLeft + x + 10, guiTop + y - 4, true,
+ // tierStringColour
+ // );
+ // }
+ Utils.drawStringCentered(
+ (int) Math.floor(levelNum) + "",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + x + 10,
+ guiTop + y + 26,
+ true,
+ color.getRGB()
+ );
+ }
+ }
+ }
+ }
+ if (tooltipToDisplay != null) {
+ List<String> grayTooltip = new ArrayList<>(tooltipToDisplay.size());
+ for (String line : tooltipToDisplay) {
+ grayTooltip.add(EnumChatFormatting.GRAY + line);
+ }
+ Utils.drawHoveringText(grayTooltip, mouseX, mouseY, width, height, -1, Minecraft.getMinecraft().fontRendererObj);
+ tooltipToDisplay = null;
+ }
+ }
+
+ @Override
+ public void mouseReleased(int mouseX, int mouseY, int mouseButton) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ int bestiarySize = BestiaryData.getBestiaryLocations().size();
+ int bestiaryYSize = (int) (350f / (bestiarySize - 1 + 0.0000001f));
+ int yIndex = 0;
+ for (ItemStack stack : BestiaryData.getBestiaryLocations().keySet()) {
+ if (mouseX > guiLeft + 30 + bestiaryYSize * yIndex && mouseX < guiLeft + 30 + bestiaryYSize * yIndex + 20) {
+ if (mouseY > guiTop + 10 && mouseY < guiTop + 10 + 20) {
+ selectedBestiaryLocation = stack;
+ Utils.playPressSound();
+ return;
+ }
+ }
+ yIndex++;
+ }
+ }
+
+ private int getBestiaryTiers(JsonObject profileInfo) {
+ int beLevel = 0;
+ for (ItemStack items : BestiaryData.getBestiaryLocations().keySet()) {
+ List<String> mobs = BestiaryData.getBestiaryLocations().get(items);
+ if (mobs != null) {
+ for (String mob : mobs) {
+ if (mob != null) {
+ float kills = Utils.getElementAsFloat(Utils.getElement(profileInfo, "bestiary.kills_" + mob), 0);
+ String type;
+ if (BestiaryData.getMobType().get(mob) != null) {
+ type = BestiaryData.getMobType().get(mob);
+ } else {
+ type = "MOB";
+ }
+ JsonObject leveling = Constants.LEVELING;
+ ProfileViewer.Level level = null;
+ if (leveling != null && Utils.getElement(leveling, "bestiary." + type) != null) {
+ JsonArray levelingArray = Utils.getElement(leveling, "bestiary." + type).getAsJsonArray();
+ int levelCap = Utils.getElementAsInt(Utils.getElement(leveling, "bestiary.caps." + type), 0);
+ level = ProfileViewer.getLevel(levelingArray, kills, levelCap, false);
+ }
+
+ float levelNum = 0;
+ if (level != null) {
+ levelNum = level.level;
+ }
+ beLevel += (int) Math.floor(levelNum);
+ }
+ }
+ }
+ }
+ return beLevel;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/info/QuiverInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/info/QuiverInfo.java
new file mode 100644
index 00000000..b4d92325
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/info/QuiverInfo.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.info;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import net.minecraft.util.EnumChatFormatting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class QuiverInfo {
+ public String selectedArrow;
+ public Map<String, Integer> arrows;
+
+ public List<String> generateProfileViewerTooltip() {
+ List<String> list = new ArrayList<>();
+ int totalCount = 0;
+ list.add(EnumChatFormatting.AQUA + "Quiver:");
+ for (Map.Entry<String, Integer> arrow : arrows.entrySet()) {
+ JsonObject repoInfo = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(arrow.getKey());
+ if (repoInfo == null || repoInfo.isJsonNull()) {
+ continue;
+ }
+ list.add(
+ " " + repoInfo.get("displayname").getAsString() + EnumChatFormatting.RESET + ": " + EnumChatFormatting.GREEN +
+ EnumChatFormatting.BOLD + arrow.getValue());
+ totalCount += arrow.getValue();
+ }
+
+ list.add("");
+ list.add(EnumChatFormatting.AQUA + "Total: " + EnumChatFormatting.GREEN + EnumChatFormatting.BOLD + totalCount);
+ if (selectedArrow != null) {
+ JsonObject repoInfo = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(selectedArrow);
+ if (repoInfo == null) {
+ list.add(EnumChatFormatting.AQUA + "Selected Arrow: " + EnumChatFormatting.RED + "ERROR");
+ } else {
+ list.add(EnumChatFormatting.AQUA + "Selected Arrow: " + repoInfo.get("displayname").getAsString());
+ }
+ }
+
+ return list;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFish.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFish.java
new file mode 100644
index 00000000..5a3027c3
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFish.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.trophy;
+
+import java.util.Map;
+
+public class TrophyFish {
+
+ public final Map<TrophyFishRarity, Integer> trophyFishRarityIntegerMap;
+ private final String name;
+ private int total = 0;
+
+ public TrophyFish(String name, Map<TrophyFishRarity, Integer> trophyFishRarityIntegerMap) {
+ this.name = name;
+ this.trophyFishRarityIntegerMap = trophyFishRarityIntegerMap;
+ }
+
+ public void addTotal(int n) {
+ total += n;
+ }
+
+ public int getTotal() {
+ return total;
+ }
+
+ public void removeTotal(int n) {
+ total -= n;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map<TrophyFishRarity, Integer> getTrophyFishRarityIntegerMap() {
+ return trophyFishRarityIntegerMap;
+ }
+
+ public void add(TrophyFishRarity rarity, int value) {
+ if (!trophyFishRarityIntegerMap.containsKey(rarity)) {
+ trophyFishRarityIntegerMap.put(rarity, value);
+ }
+ }
+
+ public String getInternalName() {
+ return name.toLowerCase().replace(" ", "_");
+ }
+
+ public enum TrophyFishRarity {
+ BRONZE,
+ SILVER,
+ GOLD,
+ DIAMOND,
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFishPage.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFishPage.java
new file mode 100644
index 00000000..cda47ffd
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/trophy/TrophyFishPage.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.trophy;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewerPage;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.RenderHelper;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.ResourceLocation;
+import org.apache.commons.lang3.text.WordUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.lwjgl.opengl.GL11;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+public class TrophyFishPage extends GuiProfileViewerPage {
+
+ public static final ResourceLocation pv_elements = new ResourceLocation("notenoughupdates:pv_elements.png");
+ private static final Map<String, EnumChatFormatting> internalTrophyFish = new HashMap<String, EnumChatFormatting>() {
+ {
+ put("gusher", EnumChatFormatting.WHITE);
+ put("flyfish", EnumChatFormatting.GREEN);
+ put("moldfin", EnumChatFormatting.DARK_PURPLE);
+ put("vanille", EnumChatFormatting.BLUE);
+ put("blobfish", EnumChatFormatting.WHITE);
+ put("mana_ray", EnumChatFormatting.BLUE);
+ put("slugfish", EnumChatFormatting.GREEN);
+ put("soul_fish", EnumChatFormatting.DARK_PURPLE);
+ put("lava_horse", EnumChatFormatting.BLUE);
+ put("golden_fish", EnumChatFormatting.GOLD);
+ put("karate_fish", EnumChatFormatting.DARK_PURPLE);
+ put("skeleton_fish", EnumChatFormatting.DARK_PURPLE);
+ put("sulphur_skitter", EnumChatFormatting.WHITE);
+ put("obfuscated_fish_1", EnumChatFormatting.WHITE);
+ put("obfuscated_fish_2", EnumChatFormatting.GREEN);
+ put("obfuscated_fish_3", EnumChatFormatting.BLUE);
+ put("volcanic_stonefish", EnumChatFormatting.BLUE);
+ put("steaming_hot_flounder", EnumChatFormatting.WHITE);
+ }
+ };
+ private static final LinkedHashMap<ItemStack, Pair<String, Integer>> armorHelmets = new LinkedHashMap<ItemStack, Pair<String, Integer>>() {
+ {
+ put(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("BRONZE_HUNTER_HELMET")
+ ),
+ Pair.of(EnumChatFormatting.GREEN + "Novice Fisher", 1)
+ );
+ put(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("SILVER_HUNTER_HELMET")
+ ),
+ Pair.of(EnumChatFormatting.BLUE + "Adept Fisher", 2)
+ );
+ put(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("GOLD_HUNTER_HELMET")
+ ),
+ Pair.of(EnumChatFormatting.DARK_PURPLE + "Expert Fisher", 3)
+ );
+ put(
+ NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("DIAMOND_HUNTER_HELMET")
+ ),
+ Pair.of(EnumChatFormatting.GOLD + "Master Fisher", 4)
+ );
+ }
+ };
+ private static final Map<Integer, Pair<Integer, Integer>> slotLocations = new HashMap<Integer, Pair<Integer, Integer>>() {
+ {
+ put(0, Pair.of(277, 46));
+ put(1, Pair.of(253, 58));
+ put(2, Pair.of(301, 58));
+ put(3, Pair.of(229, 70));
+ put(4, Pair.of(325, 70));
+ put(5, Pair.of(277, 70));
+ put(6, Pair.of(253, 82));
+ put(7, Pair.of(301, 82));
+ put(8, Pair.of(229, 94));
+ put(9, Pair.of(325, 94));
+ put(10, Pair.of(253, 106));
+ put(11, Pair.of(301, 106));
+ put(12, Pair.of(277, 118));
+ put(13, Pair.of(229, 118));
+ put(14, Pair.of(325, 118));
+ put(15, Pair.of(253, 130));
+ put(16, Pair.of(301, 130));
+ put(17, Pair.of(277, 142));
+ }
+ };
+ private static final ResourceLocation TROPHY_FISH_TEXTURE = new ResourceLocation("notenoughupdates:pv_trophy_fish_tab.png");
+ private static final String checkX = "§c✖";
+ private static final String check = "§a✔";
+ private final Map<String, Integer> total = new HashMap<>();
+ private final Map<String, TrophyFish> trophyFishList = new HashMap<>();
+ private long totalCount = 0;
+
+ public TrophyFishPage(GuiProfileViewer instance) {
+ super(instance);
+ }
+
+ @Override
+ public void drawPage(int mouseX, int mouseY, float partialTicks) {
+ int guiLeft = GuiProfileViewer.getGuiLeft();
+ int guiTop = GuiProfileViewer.getGuiTop();
+
+ trophyFishList.clear();
+
+ JsonObject profileInformation = GuiProfileViewer.getProfile().getProfileInformation(GuiProfileViewer.getProfileId());
+ if (profileInformation == null || !profileInformation.has("trophy_fish")) {
+ Utils.drawStringCentered(
+ EnumChatFormatting.RED + "No data found",
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 431 / 2f,
+ guiTop + 101,
+ true,
+ 0
+ );
+ return;
+ }
+ JsonObject trophyObject = profileInformation.get("trophy_fish").getAsJsonObject();
+
+ loadTrophyInformation(trophyObject);
+
+ ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft());
+ int width = scaledResolution.getScaledWidth();
+ int height = scaledResolution.getScaledHeight();
+
+ Minecraft.getMinecraft().getTextureManager().bindTexture(TROPHY_FISH_TEXTURE);
+ Utils.drawTexturedRect(guiLeft, guiTop, 431, 202, GL11.GL_NEAREST);
+
+ GlStateManager.color(1, 1, 1, 1);
+ GlStateManager.disableLighting();
+ RenderHelper.enableGUIStandardItemLighting();
+
+ JsonObject stats = profileInformation.get("stats").getAsJsonObject();
+
+ int thunderKills = 0;
+ if (stats.has("kills_thunder")) {
+ thunderKills = stats.getAsJsonObject().get("kills_thunder").getAsInt();
+ }
+ ItemStack thunder_sc = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("THUNDER_SC")
+ );
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(thunder_sc, guiLeft + 16, guiTop + 108);
+
+ Utils.drawStringF(
+ EnumChatFormatting.AQUA + "Thunder Kills: §f" + thunderKills,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 36,
+ guiTop + 112,
+ true,
+ 0
+ );
+
+ ItemStack lord_jawbus_sc = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("LORD_JAWBUS_SC")
+ );
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(lord_jawbus_sc, guiLeft + 16, guiTop + 120);
+ int jawbusKills = 0;
+ if (stats.has("kills_lord_jawbus")) {
+ jawbusKills = stats.getAsJsonObject().get("kills_lord_jawbus").getAsInt();
+ }
+
+ Utils.drawStringF(
+ EnumChatFormatting.AQUA + "Lord Jawbus Kills: §f" + jawbusKills,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 36,
+ guiTop + 124,
+ true,
+ 0
+ );
+
+ ItemStack fishing_rod = NotEnoughUpdates.INSTANCE.manager.jsonToStack(
+ NotEnoughUpdates.INSTANCE.manager.getItemInformation().get("FISHING_ROD")
+ );
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(fishing_rod, guiLeft + 20, guiTop + 21);
+
+ Utils.drawStringF(
+ EnumChatFormatting.AQUA + "Total Caught: §f" + totalCount,
+ Minecraft.getMinecraft().fontRendererObj,
+ guiLeft + 38,
+ guiTop + 25,
+ true,
+ 0
+ );
+
+ ArrayList<TrophyFish> arrayList = new ArrayList<>(trophyFishList.values());
+ arrayList.sort((c1, c2) -> Integer.compare(c2.getTotal(), c1.getTotal()));
+
+ int x;
+ int y;
+ for (TrophyFish value : arrayList) {
+ x = guiLeft + slotLocations.get(arrayList.indexOf(value)).getLeft();
+ y = guiTop + slotLocations.get(arrayList.indexOf(value)).getRight();
+ RenderHelper.enableGUIStandardItemLighting();
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Map<TrophyFish.TrophyFishRarity, Integer> trophyFishRarityIntegerMap = value.getTrophyFishRarityIntegerMap();
+ if (trophyFishRarityIntegerMap.containsKey(TrophyFish.TrophyFishRarity.BRONZE)) {
+ GlStateManager.color(255 / 255f, 130 / 255f, 0 / 255f, 1);
+ }
+ if (trophyFishRarityIntegerMap.containsKey(TrophyFish.TrophyFishRarity.SILVER)) {
+ GlStateManager.color(192 / 255f, 192 / 255f, 192 / 255f, 1);
+ }
+ if (trophyFishRarityIntegerMap.containsKey(TrophyFish.TrophyFishRarity.GOLD)) {
+ GlStateManager.color(1, 0.82F, 0, 1);
+ }
+ if (trophyFishRarityIntegerMap.containsKey(TrophyFish.TrophyFishRarity.DIAMOND)) {
+ GlStateManager.color(31 / 255f, 216 / 255f, 241 / 255f, 1);
+ }
+ Utils.drawTexturedRect(x - 2, y - 2, 20, 20, 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST);
+ GlStateManager.color(1, 1, 1, 1);
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(getItem(value.getName()), x, y);
+
+ if (mouseX >= x && mouseX < x + 24) {
+ if (mouseY >= y && mouseY <= y + 24) {
+ Utils.drawHoveringText(
+ getTooltip(value.getName(), value.getTrophyFishRarityIntegerMap()),
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+ }
+
+ if (arrayList.size() != internalTrophyFish.size()) {
+ List<String> clonedList = new ArrayList<>(internalTrophyFish.size());
+ clonedList.addAll(internalTrophyFish.keySet());
+ clonedList.removeAll(fixStringName(new ArrayList<>(trophyFishList.keySet())));
+ for (String difference : clonedList) {
+ RenderHelper.enableGUIStandardItemLighting();
+ x = guiLeft + slotLocations.get(clonedList.indexOf(difference) + (trophyFishList.keySet().size())).getLeft();
+ y = guiTop + slotLocations.get(clonedList.indexOf(difference) + (trophyFishList.keySet().size())).getRight();
+ ItemStack itemStack = new ItemStack(Items.dye, 1, 8);
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, x, y);
+ if (mouseX >= x && mouseX < x + 24) {
+ if (mouseY >= y && mouseY <= y + 24) {
+ Utils.drawHoveringText(
+ getTooltip(difference, null),
+ mouseX,
+ mouseY,
+ width,
+ height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ GlStateManager.color(1, 1, 1, 1);
+ }
+ }
+ Minecraft.getMinecraft().getTextureManager().bindTexture(pv_elements);
+ Utils.drawTexturedRect(x - 2, y - 2, 20, 20, 0, 20 / 256f, 0, 20 / 256f, GL11.GL_NEAREST);
+ }
+ }
+
+ if (!trophyObject.has("rewards")) return;
+
+ int[] trophiesPerTier = getTrophiesPerTier(trophyObject);
+ JsonArray rewards = trophyObject.get("rewards").getAsJsonArray();
+ int i = 0;
+ for (ItemStack itemStack : armorHelmets.keySet()) {
+ RenderHelper.enableGUIStandardItemLighting();
+ int integer = armorHelmets.get(itemStack).getRight();
+ x = guiLeft + 15;
+ y = guiTop + 50 + i;
+
+ Minecraft.getMinecraft().getRenderItem().renderItemIntoGUI(itemStack, x, y);
+ Utils.drawStringF(armorHelmets.get(itemStack).getLeft(), Minecraft.getMinecraft().fontRendererObj, x + 20, y + 4, true, 0);
+
+ int hasValue = trophiesPerTier[integer - 1];
+ int neededValue = integer == 1 ? 15 : 18;
+ String neededText = "§c" + hasValue + "/" + neededValue;
+
+ try {
+ JsonElement jsonElement = rewards.get(integer - 1);
+ if (!jsonElement.isJsonNull()) {
+ Utils.drawStringF(check, Minecraft.getMinecraft().fontRendererObj, x + 100, y + 2, true, 0);
+ } else {
+ Utils.drawStringF(neededText, Minecraft.getMinecraft().fontRendererObj, x + 100, y + 4, true, 0);
+ }
+ } catch (IndexOutOfBoundsException exception) {
+ Utils.drawStringF(neededText, Minecraft.getMinecraft().fontRendererObj, x + 100, y + 4, true, 0);
+ }
+ i += 10;
+ }
+
+ GlStateManager.enableLighting();
+ }
+
+ private int[] getTrophiesPerTier(JsonObject trophyFish) {
+ int[] trophiesPerTier = new int[] { 0, 0, 0, 0 };
+ for (String fishType : internalTrophyFish.keySet()) {
+ int highestTier = 0;
+ if (trophyFish.has((fishType + "_bronze"))) highestTier = 1;
+ if (trophyFish.has((fishType + "_silver"))) highestTier = 2;
+ if (trophyFish.has((fishType + "_gold"))) highestTier = 3;
+ if (trophyFish.has((fishType + "_diamond"))) highestTier = 4;
+
+ if (highestTier >= 1) trophiesPerTier[0]++;
+ if (highestTier >= 2) trophiesPerTier[1]++;
+ if (highestTier >= 3) trophiesPerTier[2]++;
+ if (highestTier >= 4) trophiesPerTier[3]++;
+ }
+ return trophiesPerTier;
+ }
+
+ private List<String> getTooltip(String name, Map<TrophyFish.TrophyFishRarity, Integer> trophyFishRarityIntegerMap) {
+ List<String> tooltip = new ArrayList<>();
+ tooltip.add(internalTrophyFish.get(name.toLowerCase(Locale.US).replace(" ", "_")) + WordUtils.capitalize(name.replace("_", " ")));
+
+ List<String> lore = readLoreFromRepo(name.toUpperCase(Locale.US));
+ List<String> description = readDescriptionFromLore(lore);
+ tooltip.addAll(description);
+ tooltip.add(" ");
+
+ if (trophyFishRarityIntegerMap == null) {
+ tooltip.add(EnumChatFormatting.RED + checkX + " Not Discovered");
+ tooltip.add(" ");
+ }
+
+ tooltip.add(display(trophyFishRarityIntegerMap, TrophyFish.TrophyFishRarity.DIAMOND, EnumChatFormatting.AQUA));
+ tooltip.add(display(trophyFishRarityIntegerMap, TrophyFish.TrophyFishRarity.GOLD, EnumChatFormatting.GOLD));
+ tooltip.add(display(trophyFishRarityIntegerMap, TrophyFish.TrophyFishRarity.SILVER, EnumChatFormatting.GRAY));
+ tooltip.add(display(trophyFishRarityIntegerMap, TrophyFish.TrophyFishRarity.BRONZE, EnumChatFormatting.DARK_GRAY));
+ return tooltip;
+ }
+
+ private String display(
+ Map<TrophyFish.TrophyFishRarity, Integer> trophyFishRarityIntegerMap,
+ TrophyFish.TrophyFishRarity rarity,
+ EnumChatFormatting color
+ ) {
+ String name = WordUtils.capitalize(rarity.name().toLowerCase(Locale.US));
+ if (trophyFishRarityIntegerMap == null) {
+ return color + name + ": " + checkX;
+ }
+
+ if (trophyFishRarityIntegerMap.containsKey(rarity)) {
+ return color + name + ": " + EnumChatFormatting.GOLD + trophyFishRarityIntegerMap.get(rarity);
+ } else {
+ return color + name + ": " + checkX;
+ }
+ }
+
+ private ItemStack getItem(String name) {
+ String repoName = name.toUpperCase(Locale.US).replace(" ", "_") + "_BRONZE";
+ JsonObject jsonItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(repoName);
+ return NotEnoughUpdates.INSTANCE.manager.jsonToStack(jsonItem);
+ }
+
+ private void loadTrophyInformation(JsonObject trophyObject) {
+ Map<String, List<Pair<TrophyFish.TrophyFishRarity, Integer>>> trophyFishRarityIntegerMap = new HashMap<>();
+ totalCount = 0;
+ for (Map.Entry<String, JsonElement> stringJsonElementEntry : trophyObject.entrySet()) {
+ String key = stringJsonElementEntry.getKey();
+ if (key.equalsIgnoreCase("rewards") || key.equalsIgnoreCase("total_caught")) {
+ if (key.equalsIgnoreCase("total_caught")) {
+ totalCount = stringJsonElementEntry.getValue().getAsInt();
+ }
+ continue;
+ }
+
+ String[] s = key.split("_");
+ String type = s[s.length - 1];
+ TrophyFish.TrophyFishRarity trophyFishRarity;
+ int value = stringJsonElementEntry.getValue().getAsInt();
+
+ if (key.startsWith("golden_fish_")) {
+ type = s[2];
+ }
+ try {
+ trophyFishRarity = TrophyFish.TrophyFishRarity.valueOf(type.toUpperCase(Locale.US));
+ } catch (IllegalArgumentException ignored) {
+ total.put(WordUtils.capitalize(key), value);
+ continue;
+ }
+
+ String replace = key.replace("_" + type, "");
+ String name = WordUtils.capitalize(replace);
+ List<Pair<TrophyFish.TrophyFishRarity, Integer>> pairs;
+
+ if (trophyFishRarityIntegerMap.containsKey(name)) {
+ pairs = trophyFishRarityIntegerMap.get(name);
+ } else {
+ pairs = new ArrayList<>();
+ }
+ pairs.add(Pair.of(trophyFishRarity, value));
+ trophyFishRarityIntegerMap.put(name, pairs);
+ }
+
+ trophyFishRarityIntegerMap.forEach((name, pair) -> {
+ if (!trophyFishList.containsKey(name)) {
+ TrophyFish trophyFish = new TrophyFish(name, new HashMap<>());
+ trophyFish.addTotal(total.get(name));
+ for (Pair<TrophyFish.TrophyFishRarity, Integer> pair1 : pair) {
+ trophyFish.add(pair1.getKey(), pair1.getValue());
+ }
+ trophyFishList.put(name, trophyFish);
+ } else {
+ TrophyFish trophyFish = trophyFishList.get(name);
+ for (Pair<TrophyFish.TrophyFishRarity, Integer> pair1 : pair) {
+ trophyFish.add(pair1.getKey(), pair1.getValue());
+ }
+ }
+ });
+ }
+
+ private List<String> fixStringName(List<String> list) {
+ List<String> fixedList = new ArrayList<>();
+ for (String s : list) {
+ fixedList.add(s.toLowerCase(Locale.US).replace(" ", "_"));
+ }
+ return fixedList;
+ }
+
+ private List<String> readDescriptionFromLore(List<String> lore) {
+ List<String> description = new ArrayList<>();
+ boolean found = false;
+
+ for (String line : lore) {
+ if (!found && line.startsWith("§7")) found = true;
+ if (found && line.isEmpty()) break;
+
+ if (found) {
+ description.add(line);
+ }
+ }
+
+ return description;
+ }
+
+ private List<String> readLoreFromRepo(String name) {
+ String repoName = name.toUpperCase(Locale.US).replace(" ", "_") + "_BRONZE";
+ JsonObject jsonItem = NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(repoName);
+
+ List<String> list = new ArrayList<>();
+ if (jsonItem != null && jsonItem.has("lore")) {
+ for (JsonElement line : jsonItem.getAsJsonArray("lore")) {
+ list.add(line.getAsString());
+ }
+ }
+
+ return list;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java
new file mode 100644
index 00000000..3ceabaf5
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyDungeonsWeight.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.lily;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.DungeonsWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.Map;
+
+public class LilyDungeonsWeight extends DungeonsWeight {
+
+ private final JsonObject profileJson;
+
+ public LilyDungeonsWeight(Map<String, ProfileViewer.Level> player, JsonObject profileJson) {
+ super(player);
+ this.profileJson = profileJson;
+ }
+
+ @Override
+ public void getDungeonWeight() {
+ ProfileViewer.Level catacombs = player.get("catacombs");
+
+ double extra = 0;
+ double n = 0;
+ if (catacombs.totalXp < CATACOMBS_LEVEL_50_XP) {
+ n = 0.2 * Math.pow(catacombs.level / 50, 1.538679118869934);
+ } else {
+ extra = 500.0 * Math.pow((catacombs.totalXp - CATACOMBS_LEVEL_50_XP) / 142452410.0, 1.0 / 1.781925776625157);
+ }
+
+ if (catacombs.level != 0) {
+ if (catacombs.totalXp < CATACOMBS_LEVEL_50_XP) {
+ weightStruct.add(
+ new WeightStruct(
+ Utils.getElement(Constants.WEIGHT, "lily.dungeons.overall").getAsDouble() *
+ ((Math.pow(1.18340401286164044, (catacombs.level + 1)) - 1.05994990217254) * (1 + n))
+ )
+ );
+ } else {
+ weightStruct.add(new WeightStruct((4100 + extra) * 2));
+ }
+ }
+ }
+
+ public void getDungeonCompletionWeight(String cataMode) {
+ double max1000 = 0;
+ double mMax1000 = 0;
+ JsonObject dungeonsCompletionWorth = Utils.getElement(Constants.WEIGHT, "lily.dungeons.completion_worth").getAsJsonObject();
+ for (Map.Entry<String, JsonElement> dcwEntry : dungeonsCompletionWorth.entrySet()) {
+ if (dcwEntry.getKey().startsWith("catacombs_")) {
+ max1000 += dcwEntry.getValue().getAsDouble();
+ } else {
+ mMax1000 += dcwEntry.getValue().getAsDouble();
+ }
+ }
+ max1000 *= 1000;
+ mMax1000 *= 1000;
+ double upperBound = 1500;
+ if (cataMode.equals("normal")) {
+ if (Utils.getElement(profileJson, "dungeons.dungeon_types.catacombs.tier_completions") == null) {
+ return;
+ }
+
+ double score = 0;
+ for (Map.Entry<String, JsonElement> normalFloor : Utils
+ .getElement(profileJson, "dungeons.dungeon_types.catacombs.tier_completions")
+ .getAsJsonObject()
+ .entrySet()) {
+ int amount = normalFloor.getValue().getAsInt();
+ double excess = 0;
+ if (amount > 1000) {
+ excess = amount - 1000;
+ amount = 1000;
+ }
+
+ double floorScore = amount * dungeonsCompletionWorth.get("catacombs_" + normalFloor.getKey()).getAsDouble();
+ if (excess > 0) floorScore *= Math.log(excess / 1000 + 1) / Math.log(7.5) + 1;
+ score += floorScore;
+ }
+
+ weightStruct.add(new WeightStruct(score / max1000 * upperBound * 2));
+ } else {
+ JsonObject dungeonsCompletionBuffs = Utils.getElement(Constants.WEIGHT, "lily.dungeons.completion_buffs").getAsJsonObject();
+
+ if (Utils.getElement(profileJson, "dungeons.dungeon_types.master_catacombs.tier_completions") == null) {
+ return;
+ }
+
+ for (Map.Entry<String, JsonElement> masterFloor : Utils
+ .getElement(profileJson, "dungeons.dungeon_types.master_catacombs.tier_completions")
+ .getAsJsonObject()
+ .entrySet()) {
+ if (dungeonsCompletionBuffs.get(masterFloor.getKey()) != null) {
+ int amount = masterFloor.getValue().getAsInt();
+ double threshold = 20;
+ if (amount >= threshold) {
+ upperBound += dungeonsCompletionBuffs.get(masterFloor.getKey()).getAsInt();
+ } else {
+ upperBound +=
+ dungeonsCompletionBuffs.get(masterFloor.getKey()).getAsInt() * Math.pow((amount / threshold), 1.840896416);
+ }
+ }
+ }
+
+ double masterScore = 0;
+ for (Map.Entry<String, JsonElement> masterFloor : Utils
+ .getElement(profileJson, "dungeons.dungeon_types.master_catacombs.tier_completions")
+ .getAsJsonObject()
+ .entrySet()) {
+ int amount = masterFloor.getValue().getAsInt();
+ double excess = 0;
+ if (amount > 1000) {
+ excess = amount - 1000;
+ amount = 1000;
+ }
+
+ double floorScore = amount * dungeonsCompletionWorth.get("master_catacombs_" + masterFloor.getKey()).getAsDouble();
+ if (excess > 0) {
+ floorScore *= (Math.log((excess / 1000) + 1) / Math.log(6)) + 1;
+ }
+ masterScore += floorScore;
+ }
+
+ weightStruct.add(new WeightStruct((masterScore / mMax1000) * upperBound * 2));
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java
new file mode 100644
index 00000000..8ed43f6e
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySkillsWeight.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.lily;
+
+import static io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight.SKILL_NAMES;
+
+import com.google.gson.JsonArray;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SkillsWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.Map;
+
+public class LilySkillsWeight extends SkillsWeight {
+
+ public LilySkillsWeight(Map<String, ProfileViewer.Level> player) {
+ super(player);
+ }
+
+ @Override
+ public void getSkillsWeight(String skillName) {
+ double skillAverage = 0;
+ for (String skill : SKILL_NAMES) {
+ skillAverage +=
+ (int) ProfileViewer.getLevel(
+ Utils.getElement(Constants.LEVELING, "leveling_xp").getAsJsonArray(),
+ player.get(skill).totalXp,
+ 60,
+ false
+ )
+ .level;
+ }
+ skillAverage /= SKILL_NAMES.size();
+
+ float currentExp = player.get(skillName).totalXp;
+ int currentLevel = (int) ProfileViewer.getLevel(
+ Utils.getElement(Constants.LEVELING, "leveling_xp").getAsJsonArray(),
+ currentExp,
+ 60,
+ false
+ )
+ .level;
+
+ JsonArray srwTable = Utils.getElement(Constants.WEIGHT, "lily.skills.ratio_weight." + skillName).getAsJsonArray();
+ double base =
+ (
+ (12 * Math.pow((skillAverage / 60), 2.44780217148309)) *
+ srwTable.get(currentLevel).getAsDouble() *
+ srwTable.get(srwTable.size() - 1).getAsDouble()
+ ) +
+ (srwTable.get(srwTable.size() - 1).getAsDouble() * Math.pow(currentLevel / 60.0, Math.pow(2, 0.5)));
+ base *= Utils.getElement(Constants.WEIGHT, "lily.skills.overall").getAsDouble();
+ double overflow = 0;
+ if (currentExp > SKILLS_LEVEL_60) {
+ double factor = Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "lily.skills.factors." + skillName), 0);
+ double effectiveOver = effectiveXP(currentExp - SKILLS_LEVEL_60, factor);
+ double t =
+ (effectiveOver / SKILLS_LEVEL_60) *
+ Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "lily.skills.overflow_multipliers." + skillName), 0);
+ if (t > 0) {
+ overflow += Utils.getElement(Constants.WEIGHT, "lily.skills.overall").getAsDouble() * t;
+ }
+ }
+
+ weightStruct.add(new WeightStruct(base, overflow));
+ }
+
+ private double effectiveXP(double xp, double factor) {
+ return Math.pow(xp, factor);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java
new file mode 100644
index 00000000..d26597a1
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilySlayerWeight.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.lily;
+
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SlayerWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.Map;
+
+public class LilySlayerWeight extends SlayerWeight {
+
+ public LilySlayerWeight(Map<String, ProfileViewer.Level> player) {
+ super(player);
+ }
+
+ public void getSlayerWeight(String slayerName) {
+ int currentSlayerXp = (int) player.get(slayerName).totalXp;
+
+ double score;
+ double d = currentSlayerXp / 100000.0;
+ if (currentSlayerXp >= 6416) {
+ double D = (d - Math.pow(3, (-5.0 / 2))) * (d + Math.pow(3, -5.0 / 2));
+ double u = Math.cbrt(3 * (d + Math.sqrt(D)));
+ double v = Math.cbrt(3 * (d - Math.sqrt(D)));
+ score = u + v - 1;
+ } else {
+ score = Math.sqrt(4.0 / 3) * Math.cos(Math.acos(d * Math.pow(3, 5.0 / 2)) / 3) - 1;
+ }
+
+ double scaleFactor = Utils.getElementAsFloat(
+ Utils.getElement(Constants.WEIGHT, "lily.slayer.deprecation_scaling." + slayerName),
+ 0
+ );
+ int intScore = (int) score;
+ double distance = currentSlayerXp - actualInt(intScore);
+ double effectiveDistance = distance * Math.pow(scaleFactor, intScore);
+ double effectiveScore = effectiveInt(intScore, scaleFactor) + effectiveDistance;
+ double weight;
+ switch (slayerName) {
+ case "zombie":
+ weight = (effectiveScore / 9250) + (currentSlayerXp / 1000000.0);
+ break;
+ case "spider":
+ weight = (effectiveScore / 7019.57) + ((currentSlayerXp * 1.6) / 1000000);
+ break;
+ case "wolf":
+ weight = (effectiveScore / 2982.06) + ((currentSlayerXp * 3.6) / 1000000);
+ break;
+ case "enderman":
+ weight = (effectiveScore / 996.3003) + ((currentSlayerXp * 10.0) / 1000000);
+ break;
+ case "blaze":
+ weight = (effectiveScore / 935.0455) + ((currentSlayerXp * 10.0) / 1000000);
+ break;
+ default:
+ return;
+ }
+
+ weightStruct.add(new WeightStruct(2 * weight));
+ }
+
+ private double actualInt(int intScore) {
+ return (((Math.pow(intScore, 3) / 6) + (Math.pow(intScore, 2) / 2) + (intScore / 3.0)) * 100000);
+ }
+
+ private double effectiveInt(int intScore, double scaleFactor) {
+ double total = 0;
+ for (int k = 0; k < intScore; k++) {
+ total += (Math.pow((k + 1), 2) + (k + 1)) * Math.pow(scaleFactor, (k + 1));
+ }
+ return 1000000 * total * (0.05 / scaleFactor);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java
new file mode 100644
index 00000000..4ffc9fdd
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/lily/LilyWeight.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.lily;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight;
+import java.util.Map;
+
+public class LilyWeight extends Weight {
+
+ public LilyWeight(Map<String, ProfileViewer.Level> player, JsonObject profileJson) {
+ super(new LilySlayerWeight(player), new LilySkillsWeight(player), new LilyDungeonsWeight(player, profileJson));
+ }
+
+ @Override
+ public void calculateWeight() {
+ slayerWeight.getWeightStruct().reset();
+ skillsWeight.getWeightStruct().reset();
+ dungeonsWeight.getWeightStruct().reset();
+
+ for (String slayerName : SLAYER_NAMES) {
+ slayerWeight.getSlayerWeight(slayerName);
+ }
+ for (String skillName : SKILL_NAMES) {
+ skillsWeight.getSkillsWeight(skillName);
+ }
+
+ dungeonsWeight.getDungeonWeight();
+ ((LilyDungeonsWeight) dungeonsWeight).getDungeonCompletionWeight("normal");
+ ((LilyDungeonsWeight) dungeonsWeight).getDungeonCompletionWeight("master");
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java
new file mode 100644
index 00000000..3b5adae5
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherDungeonsWeight.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.senither;
+
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.DungeonsWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.Map;
+
+public class SenitherDungeonsWeight extends DungeonsWeight {
+
+ public SenitherDungeonsWeight(Map<String, ProfileViewer.Level> player) {
+ super(player);
+ }
+
+ public void getClassWeight(String className) {
+ ProfileViewer.Level currentClass = player.get(className);
+ double base =
+ Math.pow(currentClass.level, 4.5) *
+ Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "senither.dungeons.classes." + className), 0);
+
+ if (currentClass.totalXp <= CATACOMBS_LEVEL_50_XP) {
+ weightStruct.add(new WeightStruct(base));
+ return;
+ }
+
+ double remaining = currentClass.totalXp - CATACOMBS_LEVEL_50_XP;
+ double splitter = (4 * CATACOMBS_LEVEL_50_XP) / base;
+ weightStruct.add(new WeightStruct(Math.floor(base), Math.pow(remaining / splitter, 0.968)));
+ }
+
+ @Override
+ public void getDungeonWeight() {
+ ProfileViewer.Level catacombs = player.get("catacombs");
+ double base =
+ Math.pow(catacombs.level, 4.5) * Utils.getElementAsFloat(Utils.getElement(Constants.WEIGHT, "senither.dungeons.catacombs"), 0);
+
+ if (catacombs.totalXp <= CATACOMBS_LEVEL_50_XP) {
+ weightStruct.add(new WeightStruct(base));
+ return;
+ }
+
+ double remaining = catacombs.totalXp - CATACOMBS_LEVEL_50_XP;
+ double splitter = (4 * CATACOMBS_LEVEL_50_XP) / base;
+ weightStruct.add(new WeightStruct(Math.floor(base), Math.pow(remaining / splitter, 0.968)));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java
new file mode 100644
index 00000000..2a4ee48c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSkillsWeight.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.senither;
+
+import com.google.gson.JsonArray;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SkillsWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.Map;
+
+public class SenitherSkillsWeight extends SkillsWeight {
+
+ public SenitherSkillsWeight(Map<String, ProfileViewer.Level> player) {
+ super(player);
+ }
+
+ @Override
+ public void getSkillsWeight(String skillName) {
+ JsonArray curWeights = Utils.getElement(Constants.WEIGHT, "senither.skills." + skillName).getAsJsonArray();
+ double exponent = curWeights.get(0).getAsDouble();
+ double divider = curWeights.get(1).getAsDouble();
+
+ float currentSkillXp = player.get(skillName).totalXp;
+
+ if (currentSkillXp > 0) {
+ int maxLevel = skillName.equals("farming")
+ ? 60
+ : Utils.getElementAsInt(Utils.getElement(Constants.LEVELING, "leveling_caps." + skillName), 50);
+ double level = ProfileViewer.getLevel(
+ Utils.getElement(Constants.LEVELING, "leveling_xp").getAsJsonArray(),
+ currentSkillXp,
+ maxLevel,
+ false
+ )
+ .level;
+
+ double maxLevelExp = maxLevel == 50 ? SKILLS_LEVEL_50 : SKILLS_LEVEL_60;
+ double base = Math.pow(level * 10, 0.5 + exponent + (level / 100)) / 1250;
+ if (currentSkillXp <= maxLevelExp) {
+ weightStruct.add(new WeightStruct(base));
+ return;
+ }
+
+ weightStruct.add(new WeightStruct(Math.round(base), Math.pow((currentSkillXp - maxLevelExp) / divider, 0.968)));
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java
new file mode 100644
index 00000000..80853853
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherSlayerWeight.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.senither;
+
+import com.google.gson.JsonArray;
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.SlayerWeight;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.WeightStruct;
+import io.github.moulberry.notenoughupdates.util.Constants;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import java.util.Map;
+
+public class SenitherSlayerWeight extends SlayerWeight {
+
+ public SenitherSlayerWeight(Map<String, ProfileViewer.Level> player) {
+ super(player);
+ }
+
+ public void getSlayerWeight(String slayerName) {
+ if (slayerName.equals("blaze")) {
+ return;
+ }
+
+ JsonArray curWeights = Utils.getElement(Constants.WEIGHT, "senither.slayer." + slayerName).getAsJsonArray();
+ double divider = curWeights.get(0).getAsDouble();
+ double modifier = curWeights.get(1).getAsDouble();
+
+ int currentSlayerXp = (int) player.get(slayerName).totalXp;
+
+ if (currentSlayerXp <= 1000000) {
+ weightStruct.add(new WeightStruct(currentSlayerXp == 0 ? 0 : currentSlayerXp / divider));
+ return;
+ }
+
+ double base = 1000000 / divider;
+ double remaining = currentSlayerXp - 1000000;
+ double overflow = 0;
+ double initialModifier = modifier;
+
+ while (remaining > 0) {
+ double left = Math.min(remaining, 1000000);
+
+ overflow += Math.pow(left / (divider * (1.5 + modifier)), 0.942);
+ modifier += initialModifier;
+ remaining -= left;
+ }
+
+ weightStruct.add(new WeightStruct(base, overflow));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java
new file mode 100644
index 00000000..2f813576
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/senither/SenitherWeight.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.senither;
+
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight;
+import java.util.Map;
+
+public class SenitherWeight extends Weight {
+
+ public SenitherWeight(Map<String, ProfileViewer.Level> player) {
+ super(new SenitherSlayerWeight(player), new SenitherSkillsWeight(player), new SenitherDungeonsWeight(player));
+ }
+
+ @Override
+ public void calculateWeight() {
+ slayerWeight.getWeightStruct().reset();
+ skillsWeight.getWeightStruct().reset();
+ dungeonsWeight.getWeightStruct().reset();
+
+ for (String slayerName : SLAYER_NAMES) {
+ slayerWeight.getSlayerWeight(slayerName);
+ }
+
+ for (String skillName : SKILL_NAMES) {
+ skillsWeight.getSkillsWeight(skillName);
+ }
+
+ dungeonsWeight.getDungeonWeight();
+ for (String dungeonClassName : DUNGEON_CLASS_NAMES) {
+ ((SenitherDungeonsWeight) dungeonsWeight).getClassWeight(dungeonClassName);
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java
new file mode 100644
index 00000000..39e743aa
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/DungeonsWeight.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.weight;
+
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import java.util.Map;
+
+public abstract class DungeonsWeight {
+
+ protected static final long CATACOMBS_LEVEL_50_XP = 569809640;
+
+ protected final Map<String, ProfileViewer.Level> player;
+ protected final WeightStruct weightStruct;
+
+ public DungeonsWeight(Map<String, ProfileViewer.Level> player) {
+ this.player = player;
+ this.weightStruct = new WeightStruct();
+ }
+
+ public WeightStruct getWeightStruct() {
+ return weightStruct;
+ }
+
+ public abstract void getDungeonWeight();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java
new file mode 100644
index 00000000..55669f7b
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SkillsWeight.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.weight;
+
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import java.util.Map;
+
+public abstract class SkillsWeight {
+
+ protected static final long SKILLS_LEVEL_50 = 55172425;
+ protected static final long SKILLS_LEVEL_60 = 111672425;
+ protected final Map<String, ProfileViewer.Level> player;
+ protected final WeightStruct weightStruct;
+
+ public SkillsWeight(Map<String, ProfileViewer.Level> player) {
+ this.player = player;
+ this.weightStruct = new WeightStruct();
+ }
+
+ public WeightStruct getWeightStruct() {
+ return weightStruct;
+ }
+
+ public abstract void getSkillsWeight(String skillName);
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java
new file mode 100644
index 00000000..20b2762d
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/SlayerWeight.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.weight;
+
+import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
+import java.util.Map;
+
+public abstract class SlayerWeight {
+
+ protected final Map<String, ProfileViewer.Level> player;
+ protected final WeightStruct weightStruct;
+
+ public SlayerWeight(Map<String, ProfileViewer.Level> player) {
+ this.player = player;
+ this.weightStruct = new WeightStruct();
+ }
+
+ public WeightStruct getWeightStruct() {
+ return weightStruct;
+ }
+
+ public abstract void getSlayerWeight(String slayerName);
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java
new file mode 100644
index 00000000..129f53fc
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/Weight.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.weight;
+
+import java.util.Arrays;
+import java.util.List;
+
+public abstract class Weight {
+
+ public static final List<String> SKILL_NAMES = Arrays.asList(
+ "taming",
+ "mining",
+ "foraging",
+ "enchanting",
+ "farming",
+ "combat",
+ "fishing",
+ "alchemy"
+ );
+ protected static final List<String> SLAYER_NAMES = Arrays.asList("wolf", "zombie", "spider", "enderman", "blaze");
+ protected static final List<String> DUNGEON_CLASS_NAMES = Arrays.asList("healer", "mage", "berserk", "archer", "tank");
+ protected final SlayerWeight slayerWeight;
+ protected final SkillsWeight skillsWeight;
+ protected final DungeonsWeight dungeonsWeight;
+
+ public Weight(SlayerWeight slayerWeight, SkillsWeight skillsWeight, DungeonsWeight dungeonsWeight) {
+ this.slayerWeight = slayerWeight;
+ this.skillsWeight = skillsWeight;
+ this.dungeonsWeight = dungeonsWeight;
+ this.calculateWeight();
+ }
+
+ public WeightStruct getTotalWeight() {
+ return new WeightStruct()
+ .add(slayerWeight.getWeightStruct())
+ .add(skillsWeight.getWeightStruct())
+ .add(dungeonsWeight.getWeightStruct());
+ }
+
+ public SlayerWeight getSlayerWeight() {
+ return slayerWeight;
+ }
+
+ public SkillsWeight getSkillsWeight() {
+ return skillsWeight;
+ }
+
+ public DungeonsWeight getDungeonsWeight() {
+ return dungeonsWeight;
+ }
+
+ protected abstract void calculateWeight();
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java
new file mode 100644
index 00000000..924dcb40
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/weight/weight/WeightStruct.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.profileviewer.weight.weight;
+
+public class WeightStruct {
+
+ private double base;
+ private double overflow;
+
+ public WeightStruct() {
+ this(0, 0);
+ }
+
+ public WeightStruct(double base) {
+ this(base, 0);
+ }
+
+ public WeightStruct(double base, double overflow) {
+ this.base = base;
+ this.overflow = overflow;
+ }
+
+ public WeightStruct add(WeightStruct o) {
+ this.base += o.base;
+ this.overflow += o.overflow;
+ return this;
+ }
+
+ public double getRaw() {
+ return base + overflow;
+ }
+
+ public void reset() {
+ this.base = 0;
+ this.overflow = 0;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java
index d0b464f6..004ea372 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingOverlay.java
@@ -1,6 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.mixins.AccessorGuiContainer;
import io.github.moulberry.notenoughupdates.util.Utils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
@@ -50,8 +70,8 @@ public class CraftingOverlay {
forEachSlot(chest, (recipeIngredient, slot) -> {
if (Utils.isWithinRect(
mouseX, mouseY,
- slot.xDisplayPosition + gui.guiLeft,
- slot.yDisplayPosition + gui.guiTop,
+ slot.xDisplayPosition + ((AccessorGuiContainer) gui).getGuiLeft(),
+ slot.yDisplayPosition + ((AccessorGuiContainer) gui).getGuiTop(),
16, 16
))
block.accept(recipeIngredient, slot);
@@ -82,7 +102,7 @@ public class CraftingOverlay {
fontRenderer.drawStringWithShadow(
currentRecipe.getCraftText(),
Utils.peekGuiScale().getScaledWidth() / 2f - fontRenderer.getStringWidth(currentRecipe.getCraftText()) / 2f,
- guiChest.guiTop - 15f, 0x808080
+ ((AccessorGuiContainer) guiChest).getGuiTop() - 15f, 0x808080
);
}
renderTooltip(guiChest, chest);
@@ -103,7 +123,7 @@ public class CraftingOverlay {
if (Keyboard.getEventKey() == Keyboard.KEY_R)
manager.showRecipe(recipeIngredient.getInternalItemId());
if (Keyboard.getEventKey() == Keyboard.KEY_U)
- manager.displayGuiItemRecipe(recipeIngredient.getInternalItemId(), null);
+ manager.displayGuiItemRecipe(recipeIngredient.getInternalItemId());
}
});
});
@@ -140,8 +160,8 @@ public class CraftingOverlay {
}
private void drawItemStack(GuiChest gui, Slot slot, ItemStack item) {
- int slotX = slot.xDisplayPosition + gui.guiLeft;
- int slotY = slot.yDisplayPosition + gui.guiTop;
+ int slotX = slot.xDisplayPosition + ((AccessorGuiContainer) gui).getGuiLeft();
+ int slotY = slot.yDisplayPosition + ((AccessorGuiContainer) gui).getGuiTop();
Gui.drawRect(slotX, slotY, slotX + 16, slotY + 16, 0x64ff0000);
if (item != null)
Utils.drawItemStack(item, slotX, slotY);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java
index 576cbbd4..a642187b 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/CraftingRecipe.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import com.google.common.collect.Sets;
@@ -17,10 +36,11 @@ import java.util.Set;
public class CraftingRecipe implements NeuRecipe {
- public static final ResourceLocation BACKGROUND = new ResourceLocation("textures/gui/container/crafting_table.png");
+ public static final ResourceLocation BACKGROUND = new ResourceLocation("notenoughupdates",
+ "textures/gui/crafting_table_tall.png");
private static final int EXTRA_STRING_X = 132;
- private static final int EXTRA_STRING_Y = 25;
+ private static final int EXTRA_STRING_Y = 50;
private final NEUManager manager;
private final Ingredient[] inputs;
@@ -45,6 +65,11 @@ public class CraftingRecipe implements NeuRecipe {
}
@Override
+ public RecipeType getType() {
+ return RecipeType.CRAFTING;
+ }
+
+ @Override
public boolean hasVariableCost() {
return false;
}
@@ -72,10 +97,10 @@ public class CraftingRecipe implements NeuRecipe {
if (input == null) continue;
ItemStack item = input.getItemStack();
if (item == null) continue;
- slots.add(new RecipeSlot(30 + x * GuiItemRecipe.SLOT_SPACING, 17 + y * GuiItemRecipe.SLOT_SPACING, item));
+ slots.add(new RecipeSlot(30 + x * GuiItemRecipe.SLOT_SPACING, 48 + y * GuiItemRecipe.SLOT_SPACING, item));
}
}
- slots.add(new RecipeSlot(124, 35, outputIngredient.getItemStack()));
+ slots.add(new RecipeSlot(124, 66, outputIngredient.getItemStack()));
return slots;
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java
index c971d82a..47eb0d11 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/ForgeRecipe.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import com.google.common.collect.Sets;
@@ -15,12 +34,18 @@ import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.ResourceLocation;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
public class ForgeRecipe implements NeuRecipe {
- private static final ResourceLocation BACKGROUND =
- new ResourceLocation("notenoughupdates", "textures/gui/forge_recipe.png");
+ private static final ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/forge_recipe_tall.png"
+ );
private static final int SLOT_IMAGE_U = 176;
private static final int SLOT_IMAGE_V = 0;
@@ -28,7 +53,7 @@ public class ForgeRecipe implements NeuRecipe {
private static final int SLOT_PADDING = 1;
private static final int EXTRA_INFO_MAX_WIDTH = 75;
public static final int EXTRA_INFO_X = 132;
- public static final int EXTRA_INFO_Y = 25;
+ public static final int EXTRA_INFO_Y = 55;
public enum ForgeType {
REFINING, ITEM_FORGING
@@ -77,6 +102,11 @@ public class ForgeRecipe implements NeuRecipe {
}
@Override
+ public RecipeType getType() {
+ return RecipeType.FORGE;
+ }
+
+ @Override
public Set<Ingredient> getIngredients() {
return Sets.newHashSet(inputs);
}
@@ -102,7 +132,7 @@ public class ForgeRecipe implements NeuRecipe {
int[] slotCoordinates = getSlotCoordinates(i, inputs.size());
slots.add(new RecipeSlot(slotCoordinates[0], slotCoordinates[1], itemStack));
}
- slots.add(new RecipeSlot(124, 35, output.getItemStack()));
+ slots.add(new RecipeSlot(124, 66, output.getItemStack()));
return slots;
}
@@ -214,14 +244,14 @@ public class ForgeRecipe implements NeuRecipe {
);
}
- private static final int RECIPE_CENTER_X = 40;
- private static final int RECIPE_CENTER_Y = 34;
- private static final int SLOT_DISTANCE_FROM_CENTER = 22;
+ private static final int RECIPE_CENTER_X = 49;
+ private static final int RECIPE_CENTER_Y = 74;
+ private static final int SLOT_DISTANCE_FROM_CENTER = 30;
private static final int RECIPE_FALLBACK_X = 20;
private static final int RECIPE_FALLBACK_Y = 15;
static int[] getSlotCoordinates(int slotNumber, int totalSlotCount) {
- if (totalSlotCount > 6) {
+ if (totalSlotCount > 8) {
return new int[]{
RECIPE_FALLBACK_X + (slotNumber % 4) * GuiItemRecipe.SLOT_SPACING,
RECIPE_FALLBACK_Y + (slotNumber / 4) * GuiItemRecipe.SLOT_SPACING,
@@ -236,7 +266,10 @@ public class ForgeRecipe implements NeuRecipe {
double rad = Math.PI * 2 * slotNumber / totalSlotCount;
int x = (int) (Math.cos(rad) * SLOT_DISTANCE_FROM_CENTER);
int y = (int) (Math.sin(rad) * SLOT_DISTANCE_FROM_CENTER);
- return new int[]{RECIPE_CENTER_X + x, RECIPE_CENTER_Y + y};
+ return new int[]{
+ RECIPE_CENTER_X + x - GuiItemRecipe.SLOT_SIZE / 2,
+ RECIPE_CENTER_Y + y - GuiItemRecipe.SLOT_SIZE / 2
+ };
}
static String formatDuration(int seconds) {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java
index 79b548da..c973f8c0 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/Ingredient.java
@@ -1,9 +1,27 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NEUManager;
-import io.github.moulberry.notenoughupdates.util.Utils;
-import net.minecraft.init.Items;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
import net.minecraft.item.ItemStack;
import java.util.HashMap;
@@ -75,9 +93,7 @@ public class Ingredient {
public ItemStack getItemStack() {
if (itemStack != null) return itemStack;
if (isCoins()) {
- itemStack = new ItemStack(Items.gold_nugget);
- itemStack.setStackDisplayName("\u00A7r\u00A76" + Utils.formatNumberWithDots(getCount()) + " Coins");
- return itemStack;
+ return ItemUtils.getCoinItemStack(count);
}
JsonObject itemInfo = manager.getItemInformation().get(internalItemId);
itemStack = manager.jsonToStack(itemInfo);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/ItemShopRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/ItemShopRecipe.java
new file mode 100644
index 00000000..235ba3ce
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/ItemShopRecipe.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.recipes;
+
+import com.google.common.collect.Sets;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
+import io.github.moulberry.notenoughupdates.miscgui.GuiNavigation;
+import io.github.moulberry.notenoughupdates.util.JsonUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.ResourceLocation;
+import org.lwjgl.input.Keyboard;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ItemShopRecipe implements NeuRecipe {
+ public static ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/item_shop_recipe.png"
+ );
+
+ private static final int SLOT_IMAGE_U = 176;
+ private static final int SLOT_IMAGE_V = 0;
+
+ private static final int SLOT_IMAGE_SIZE = 18;
+ public static final int RESULT_SLOT_Y = 66;
+ public static final int RESULT_SLOT_X = 124;
+
+ public static final int BUTTON_X = 130;
+ public static final int BUTTON_Y = 16;
+
+ private static final int COST_SLOT_X = 30;
+ private static final int COST_SLOT_SPACING = 6;
+ private static final int ROW_SPACING = 18;
+ private final List<Ingredient> cost;
+ private final Ingredient result;
+ private boolean selected;
+
+ private final Ingredient npcIngredient;
+ private final boolean hasWaypoint;
+ private final JsonObject npcObject;
+
+ public ItemShopRecipe(Ingredient npcIngredient, List<Ingredient> cost, Ingredient result, JsonObject npcObject) {
+ this.npcIngredient = npcIngredient;
+ this.cost = cost;
+ this.result = result;
+ this.npcObject = npcObject;
+ hasWaypoint = NotEnoughUpdates.INSTANCE.navigation.isValidWaypoint(npcObject);
+ }
+
+ @Override
+ public Set<Ingredient> getCatalystItems() {
+ return Sets.newHashSet(npcIngredient);
+ }
+
+ @Override
+ public Set<Ingredient> getIngredients() {
+ return new HashSet<>(cost);
+ }
+
+ @Override
+ public Set<Ingredient> getOutputs() {
+ return Sets.newHashSet(result);
+ }
+
+ @Override
+ public List<RecipeSlot> getSlots() {
+ List<RecipeSlot> slots = new ArrayList<>();
+
+ int i = 0;
+ int colCount = cost.size() / 4;
+ int startX = COST_SLOT_X - 8 * (colCount - 1);
+ int rowSize = cost.size();
+ if (rowSize > 4) rowSize = 4;
+ int startY = RESULT_SLOT_Y + 8 - (SLOT_IMAGE_SIZE * rowSize + COST_SLOT_SPACING * (rowSize - 1)) / 2;
+ for (Ingredient ingredient : cost) {
+ slots.add(new RecipeSlot(
+ startX + (i / 4) * ROW_SPACING + 1,
+ startY + (i % 4) * (SLOT_IMAGE_SIZE + COST_SLOT_SPACING) + 1,
+ ingredient.getItemStack()
+ ));
+ i++;
+ }
+ slots.add(new RecipeSlot(RESULT_SLOT_X, RESULT_SLOT_Y, result.getItemStack()));
+ return slots;
+ }
+
+ @Override
+ public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
+ Minecraft.getMinecraft().getTextureManager().bindTexture(BACKGROUND);
+ int colCount = cost.size() / 4;
+ int startX = COST_SLOT_X - 8 * (colCount - 1);
+ int rowSize = cost.size();
+ if (rowSize > 4) rowSize = 4;
+ int startY = RESULT_SLOT_Y + 8 - (SLOT_IMAGE_SIZE * rowSize + COST_SLOT_SPACING * (rowSize - 1)) / 2;
+ for (int i = 0; i < cost.size(); i++) {
+ gui.drawTexturedModalRect(
+ gui.guiLeft + startX + (i / 4) * ROW_SPACING,
+ gui.guiTop + startY + (i % 4) * (SLOT_IMAGE_SIZE + COST_SLOT_SPACING),
+ SLOT_IMAGE_U, SLOT_IMAGE_V,
+ SLOT_IMAGE_SIZE, SLOT_IMAGE_SIZE
+ );
+ }
+ if (!hasWaypoint) return;
+ Minecraft.getMinecraft().getTextureManager().bindTexture(GuiNavigation.BACKGROUND);
+ selected = npcIngredient.getInternalItemId().equals(NotEnoughUpdates.INSTANCE.navigation.getInternalname());
+ gui.drawTexturedModalRect(
+ gui.guiLeft + BUTTON_X,
+ gui.guiTop + BUTTON_Y,
+ selected ? GuiNavigation.TICK_POSITION_U : GuiNavigation.PIN_POSITION_U,
+ selected ? GuiNavigation.TICK_POSITION_V : GuiNavigation.PIN_POSITION_V,
+ GuiNavigation.ICON_SIZE,
+ GuiNavigation.ICON_SIZE
+ );
+ }
+
+ @Override
+ public void mouseClicked(GuiItemRecipe gui, int mouseX, int mouseY, int mouseButton) {
+ if (hasWaypoint && Utils.isWithinRect(
+ mouseX - gui.guiLeft,
+ mouseY - gui.guiTop,
+ BUTTON_X,
+ BUTTON_Y,
+ GuiNavigation.ICON_SIZE,
+ GuiNavigation.ICON_SIZE
+ )) {
+ boolean shiftPressed = Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
+ if (selected && !shiftPressed) {
+ NotEnoughUpdates.INSTANCE.navigation.untrackWaypoint();
+ } else {
+ NotEnoughUpdates.INSTANCE.navigation.trackWaypoint(npcIngredient.getInternalItemId());
+ if (shiftPressed) {
+ NotEnoughUpdates.INSTANCE.navigation.useWarpCommand();
+ }
+ }
+ Utils.playPressSound();
+ selected = !selected;
+ }
+ }
+
+ @Override
+ public String getTitle() {
+ return npcObject.get("displayname").getAsString();
+ }
+
+ @Override
+ public RecipeType getType() {
+ return RecipeType.NPC_SHOP;
+ }
+
+ @Override
+ public boolean hasVariableCost() {
+ return false;
+ }
+
+ @Override
+ public JsonObject serialize() {
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("type", "npc_shop");
+ jsonObject.addProperty("result", result.serialize());
+ jsonObject.add(
+ "cost",
+ JsonUtils.transformListToJsonArray(cost, costItem -> new JsonPrimitive(costItem.serialize()))
+ );
+ return jsonObject;
+ }
+
+ @Override
+ public ResourceLocation getBackground() {
+ return BACKGROUND;
+ }
+
+ public static NeuRecipe parseItemRecipe(NEUManager neuManager, JsonObject recipe, JsonObject outputItemJson) {
+ return new ItemShopRecipe(
+ new Ingredient(neuManager, outputItemJson.get("internalname").getAsString()),
+ JsonUtils.transformJsonArrayToList(
+ recipe.getAsJsonArray("cost"),
+ it -> new Ingredient(neuManager, it.getAsString())
+ ),
+ new Ingredient(neuManager, recipe.get("result").getAsString()),
+ outputItemJson
+ );
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
new file mode 100644
index 00000000..61749593
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/MobLootRecipe.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.recipes;
+
+import com.google.common.collect.Sets;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.miscfeatures.entityviewer.EntityViewer;
+import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import io.github.moulberry.notenoughupdates.profileviewer.Panorama;
+import io.github.moulberry.notenoughupdates.util.ItemUtils;
+import io.github.moulberry.notenoughupdates.util.JsonUtils;
+import io.github.moulberry.notenoughupdates.util.Utils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.ResourceLocation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+
+public class MobLootRecipe implements NeuRecipe {
+
+ private static final int MOB_POS_X = 38, MOB_POS_Y = 100;
+ private static final int SLOT_POS_X = 82, SLOT_POS_Y = 24;
+
+ public static class MobDrop {
+ public final Ingredient drop;
+ public final String chance;
+ public final List<String> extra;
+
+ private ItemStack itemStack;
+
+ public MobDrop(Ingredient drop, String chance, List<String> extra) {
+ this.drop = drop;
+ this.chance = chance;
+ this.extra = extra;
+ }
+
+ public ItemStack getItemStack() {
+ if (itemStack == null) {
+ itemStack = drop.getItemStack().copy();
+ List<String> arrayList = new ArrayList<>(extra);
+ arrayList.add("§r§e§lDrop Chance: §6" + formatDropChance());
+ ItemUtils.appendLore(itemStack, arrayList);
+ }
+ return itemStack;
+ }
+
+ private String formatDropChance() {
+ if (chance == null) {
+ return "";
+ }
+
+ if (!chance.endsWith("%")) {
+ return chance;
+ }
+
+ String chanceText = chance.substring(0, chance.length() - 1);
+ int chanceIn;
+ try {
+ chanceIn = (int) (100.0 / Double.parseDouble(chanceText));
+ } catch (NumberFormatException e) {
+ return chance;
+ }
+
+ String format = GuiProfileViewer.numberFormat.format(chanceIn);
+ return "1/" + format + " (" + chance + ")";
+ }
+ }
+
+ public static ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/mob_loot_tall.png"
+ );
+ private final Ingredient mobIngredient;
+ private final List<MobDrop> drops;
+ private final int coins;
+ private final int combatXp;
+ private final int xp;
+ private final String name;
+ private final String render;
+ private final int level;
+ private final List<String> extra;
+ private EntityLivingBase entityLivingBase;
+
+ private final String panoName;
+
+ private ResourceLocation[] panos = null;
+
+ public MobLootRecipe(
+ Ingredient mobIngredient,
+ List<MobDrop> drops,
+ int level,
+ int coins,
+ int xp,
+ int combatXp,
+ String name,
+ String render,
+ List<String> extra,
+ String panoName
+ ) {
+ this.mobIngredient = mobIngredient;
+ this.drops = drops;
+ this.level = level;
+ this.coins = coins;
+ this.xp = xp;
+ this.extra = extra;
+ this.combatXp = combatXp;
+ this.name = name;
+ this.render = render;
+ this.panoName = panoName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public List<MobDrop> getDrops() {
+ return drops;
+ }
+
+ public int getCoins() {
+ return coins;
+ }
+
+ public int getCombatXp() {
+ return combatXp;
+ }
+
+ public Ingredient getMob() {
+ return mobIngredient;
+ }
+
+ public int getXp() {
+ return xp;
+ }
+
+ public String getRender() {
+ return render;
+ }
+
+ public synchronized EntityLivingBase getRenderEntity() {
+ if (entityLivingBase == null) {
+ if (render == null) return null;
+ if (render.startsWith("@")) {
+ entityLivingBase = EntityViewer.constructEntity(new ResourceLocation(render.substring(1)));
+ } else {
+ entityLivingBase = EntityViewer.constructEntity(render, Collections.emptyList());
+ }
+ }
+ return entityLivingBase;
+ }
+
+ @Override
+ public Set<Ingredient> getIngredients() {
+ return Sets.newHashSet(mobIngredient);
+ }
+
+ @Override
+ public Set<Ingredient> getCatalystItems() {
+ return Sets.newHashSet(mobIngredient);
+ }
+
+ @Override
+ public Set<Ingredient> getOutputs() {
+ return drops.stream().map(it -> it.drop).collect(Collectors.toSet());
+ }
+
+ @Override
+ public String getTitle() {
+ return getFullMobName();
+ }
+
+ public String getFullMobName() {
+ return (level > 0 ? "§8[§7Lv " + level + "§8] §c" : "§c") + name;
+ }
+
+ @Override
+ public List<RecipeSlot> getSlots() {
+ List<RecipeSlot> slots = new ArrayList<>();
+ BiConsumer<Integer, ItemStack> addSlot = (sl, is) -> slots.add(
+ new RecipeSlot(
+ SLOT_POS_X + (sl % 5) * 16,
+ SLOT_POS_Y + (sl / 5) * 16,
+ is
+ ));
+ int i = 0;
+ for (; i < drops.size(); i++) {
+ MobDrop mobDrop = drops.get(i);
+ addSlot.accept(i, mobDrop.getItemStack());
+ }
+ return slots;
+ }
+
+ @Override
+ public RecipeType getType() {
+ return RecipeType.MOB_LOOT;
+ }
+
+ @Override
+ public boolean shouldUseForCraftCost() {
+ return false;
+ }
+
+ @Override
+ public boolean hasVariableCost() {
+ return true;
+ }
+
+ public static final int PANORAMA_POS_X = 13;
+ public static final int PANORAMA_POS_Y = 23;
+ public static final int PANORAMA_WIDTH = 50;
+ public static final int PANORAMA_HEIGHT = 80;
+
+ @Override
+ public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
+ if (panos == null) {
+ panos = Panorama.getPanoramasForLocation(panoName, "day");
+ }
+ Panorama.drawPanorama(
+ ((System.nanoTime() / 20000000000F) % 1) * 360,
+ gui.guiLeft + PANORAMA_POS_X,
+ gui.guiTop + PANORAMA_POS_Y,
+ PANORAMA_WIDTH,
+ PANORAMA_HEIGHT,
+ 0F,
+ 0F,
+ panos
+ );
+ if (getRenderEntity() != null)
+ EntityViewer.renderEntity(entityLivingBase, gui.guiLeft + MOB_POS_X, gui.guiTop + MOB_POS_Y, mouseX, mouseY);
+ }
+
+ @Override
+ public void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) {
+ if (gui.isWithinRect(
+ mouseX,
+ mouseY,
+ gui.guiLeft + PANORAMA_POS_X,
+ gui.guiTop + PANORAMA_POS_Y,
+ PANORAMA_WIDTH,
+ PANORAMA_HEIGHT
+ )) {
+ List<String> stuff = new ArrayList<>();
+ stuff.add(getFullMobName());
+ stuff.add("");
+ if (coins > 0)
+ stuff.add("§r§6Coins: " + coins);
+ if (xp > 0)
+ stuff.add("§r§aExperience: " + xp);
+ if (combatXp > 0)
+ stuff.add("§r§bCombat Experience: " + combatXp);
+ stuff.addAll(extra);
+ Utils.drawHoveringText(
+ stuff,
+ mouseX,
+ mouseY,
+ gui.width,
+ gui.height,
+ -1,
+ Minecraft.getMinecraft().fontRendererObj
+ );
+ }
+ }
+
+ @Override
+ public int[] getPageFlipPositionLeftTopCorner() {
+ return new int[]{14, 118};
+ }
+
+ @Override
+ public JsonObject serialize() {
+ JsonObject recipe = new JsonObject();
+ recipe.addProperty("level", level);
+ recipe.addProperty("coins", coins);
+ recipe.addProperty("xp", xp);
+ recipe.addProperty("combat_xp", combatXp);
+ recipe.addProperty("name", name);
+ recipe.addProperty("render", render);
+ recipe.addProperty("type", getType().getId());
+ recipe.addProperty("panorama", "unknown");
+ recipe.add("extra", JsonUtils.transformListToJsonArray(extra, JsonPrimitive::new));
+ recipe.add("drops", JsonUtils.transformListToJsonArray(drops, drop -> {
+ JsonObject dropObject = new JsonObject();
+ dropObject.addProperty("id", drop.drop.serialize());
+ dropObject.add("extra", JsonUtils.transformListToJsonArray(drop.extra, JsonPrimitive::new));
+ dropObject.addProperty("chance", drop.chance);
+ return dropObject;
+ }));
+ return recipe;
+ }
+
+ @Override
+ public ResourceLocation getBackground() {
+ return BACKGROUND;
+ }
+
+ public static MobLootRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson) {
+ List<MobDrop> drops = new ArrayList<>();
+ for (JsonElement jsonElement : recipe.getAsJsonArray("drops")) {
+ if (jsonElement.isJsonPrimitive()) {
+ drops.add(new MobDrop(new Ingredient(manager, jsonElement.getAsString()), null, Collections.emptyList()));
+ } else {
+ JsonObject jsonObject = jsonElement.getAsJsonObject();
+ drops.add(
+ new MobDrop(
+ new Ingredient(manager, jsonObject.get("id").getAsString()),
+ jsonObject.has("chance") ? jsonObject.get("chance").getAsString() : null,
+ JsonUtils.getJsonArrayOrEmpty(jsonObject, "extra", JsonElement::getAsString)
+ ));
+ }
+ }
+
+ return new MobLootRecipe(
+ new Ingredient(manager, outputItemJson.get("internalname").getAsString(), 1),
+ drops,
+ recipe.has("level") ? recipe.get("level").getAsInt() : 0,
+ recipe.has("coins") ? recipe.get("coins").getAsInt() : 0,
+ recipe.has("xp") ? recipe.get("xp").getAsInt() : 0,
+ recipe.has("combat_xp") ? recipe.get("combat_xp").getAsInt() : 0,
+ recipe.get("name").getAsString(),
+ recipe.has("render") && !recipe.get("render").isJsonNull() ? recipe.get("render").getAsString() : null,
+ JsonUtils.getJsonArrayOrEmpty(recipe, "extra", JsonElement::getAsString),
+ recipe.has("panorama") ? recipe.get("panorama").getAsString() : "unknown"
+ );
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java
index 3516f707..a0090050 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/NeuRecipe.java
@@ -1,10 +1,32 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NEUManager;
import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
+import net.minecraft.client.gui.GuiButton;
import net.minecraft.util.ResourceLocation;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -15,6 +37,12 @@ public interface NeuRecipe {
List<RecipeSlot> getSlots();
+ RecipeType getType();
+
+ default String getTitle() {
+ return getType().getLabel();
+ }
+
default void drawExtraInfo(GuiItemRecipe gui, int mouseX, int mouseY) {
}
@@ -24,22 +52,31 @@ public interface NeuRecipe {
default void drawHoverInformation(GuiItemRecipe gui, int mouseX, int mouseY) {
}
+ default void mouseClicked(GuiItemRecipe gui, int mouseX, int mouseY, int mouseButton) {}
+
+ default void handleKeyboardInput() {}
+
+ default Set<Ingredient> getCatalystItems() {
+ return Collections.emptySet();
+ }
+
boolean hasVariableCost();
JsonObject serialize();
+ default List<GuiButton> getExtraButtons(GuiItemRecipe guiItemRecipe) {
+ return new ArrayList<>();
+ }
+
ResourceLocation getBackground();
static NeuRecipe parseRecipe(NEUManager manager, JsonObject recipe, JsonObject output) {
+ RecipeType recipeType = RecipeType.CRAFTING;
if (recipe.has("type")) {
- switch (recipe.get("type").getAsString().intern()) {
- case "forge":
- return ForgeRecipe.parseForgeRecipe(manager, recipe, output);
- case "trade":
- return VillagerTradeRecipe.parseStaticRecipe(manager, recipe);
- }
+ recipeType = RecipeType.getRecipeTypeForId(recipe.get("type").getAsString());
}
- return CraftingRecipe.parseCraftingRecipe(manager, recipe, output);
+ if (recipeType == null) return null;
+ return recipeType.createRecipe(manager, recipe, output);
}
default boolean shouldUseForCraftCost() {
@@ -49,4 +86,13 @@ public interface NeuRecipe {
default boolean isAvailable() {
return true;
}
+
+ /**
+ * @return an array of length two in the format [leftmost x, topmost y] of the page buttons
+ */
+ default int[] getPageFlipPositionLeftTopCorner() {
+ return new int[]{110, 90};
+ }
+
+ default void actionPerformed(GuiButton button) {}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java
index 46aff6c4..d63ea42c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeGenerator.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import com.google.gson.JsonArray;
@@ -9,9 +28,11 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -20,9 +41,14 @@ import org.lwjgl.input.Keyboard;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
public class RecipeGenerator {
public static final String DURATION = "Duration: ";
@@ -41,7 +67,7 @@ public class RecipeGenerator {
@SubscribeEvent
public void onTick(TickEvent event) {
- if (!neu.config.hidden.enableItemEditing) return;
+ if (!neu.config.apiData.repositoryEditing) return;
GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen;
if (currentScreen == null) return;
if (!(currentScreen instanceof GuiChest)) return;
@@ -81,7 +107,7 @@ public class RecipeGenerator {
" seconds (no QF) ."));
boolean saved = false;
try {
- saved = saveRecipe(recipe);
+ saved = saveRecipes(recipe.getOutput().getInternalItemId(), Collections.singletonList(recipe));
} catch (IOException e) {
}
if (!saved)
@@ -93,21 +119,153 @@ public class RecipeGenerator {
" Failed to save recipe. Does the item already exist?"));
}
}
+ if (saveRecipe) attemptToSaveBestiary(menu);
+ }
+
+ private List<String> getLore(ItemStack item) {
+ NBTTagList loreTag = item.getTagCompound().getCompoundTag("display").getTagList("Lore", 8);
+ List<String> loreList = new ArrayList<>();
+ for (int i = 0; i < loreTag.tagCount(); i++) {
+ loreList.add(loreTag.getStringTagAt(i));
+ }
+ return loreList;
+ }
+
+ // §8[§7Lv1§8] §fZombie Villager
+ private static final Pattern MOB_DISPLAY_NAME_PATTERN = Pattern.compile("^§8\\[§7Lv(?<level>\\d+)§8] (?<name>.*)$");
+ // §7Coins per Kill: §61
+ // §7Combat Exp: §3120
+ // §8 ■ §7§5Skeleton Grunt Helmet §8(§a5%§8)
+ // §8 ■ §7§fRotten Flesh
+ // §8 ■ Dragon Essence §8x3-5
+ private static final Pattern LORE_PATTERN = Pattern.compile("^(?:" +
+ "§7Coins per Kill: §6(?<coins>[,\\d]+)|" +
+ "§7Combat Exp: §3(?<combatxp>[,\\d]+)|" +
+ "§7XP Orbs: §3(?<xp>[,\\d]+)|" +
+ "§8 ■ (?:§7)?(?<dropName>(?:§.)?.+?)(?: §8\\(§a(?<dropChances>[\\d.<]+%)§8\\)| §8(?<dropCount>x.*))?|" +
+ "§7Kills: §a[,\\d]+|" +
+ "§.[a-zA-Z]+ Loot|" +
+ "§7Deaths: §a[,\\d]+|" +
+ " §8■ (?<missing>§c\\?\\?\\?)|" +
+ "" +
+ ")$");
+
+ private void attemptToSaveBestiary(IInventory menu) {
+ if (!menu.getDisplayName().getUnformattedText().contains("➜")) return;
+ ItemStack backArrow = menu.getStackInSlot(48);
+ if (backArrow == null || backArrow.getItem() != Items.arrow) return;
+ if (!getLore(backArrow).stream().anyMatch(it -> it.startsWith("§7To Bestiary ➜"))) return;
+ List<NeuRecipe> recipes = new ArrayList<>();
+ String internalMobName =
+ menu.getDisplayName().getUnformattedText().split("➜")[1].toUpperCase(Locale.ROOT).trim() + "_MONSTER";
+ for (int i = 9; i < 44; i++) {
+ ItemStack mobStack = menu.getStackInSlot(i);
+ if (mobStack == null || mobStack.getItem() != Items.skull) continue;
+ Matcher matcher = MOB_DISPLAY_NAME_PATTERN.matcher(mobStack.getDisplayName());
+ if (!matcher.matches()) continue;
+ String name = matcher.group("name");
+ int level = parseIntIgnoringCommas(matcher.group("level"));
+ List<String> mobLore = getLore(mobStack);
+ int coins = 0, xp = 0, combatXp = 0;
+ List<MobLootRecipe.MobDrop> drops = new ArrayList<>();
+ for (String loreLine : mobLore) {
+ Matcher loreMatcher = LORE_PATTERN.matcher(loreLine);
+ if (!loreMatcher.matches()) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "[WARNING] Unknown lore line: " + loreLine));
+ continue;
+ }
+ if (loreMatcher.group("coins") != null)
+ coins = parseIntIgnoringCommas(loreMatcher.group("coins"));
+ if (loreMatcher.group("combatxp") != null)
+ combatXp = parseIntIgnoringCommas(loreMatcher.group("combatxp"));
+ if (loreMatcher.group("xp") != null)
+ xp = parseIntIgnoringCommas(loreMatcher.group("xp"));
+ if (loreMatcher.group("dropName") != null) {
+ String dropName = loreMatcher.group("dropName");
+ List<JsonObject> possibleItems = neu.manager.getItemInformation().values().stream().filter(it -> it.get(
+ "displayname").getAsString().equals(dropName)).collect(Collectors.toList());
+ if (possibleItems.size() != 1) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "[WARNING] Could not parse drop, ambiguous or missing item information: " + loreLine));
+ continue;
+ }
+ Ingredient item = new Ingredient(neu.manager, possibleItems.get(0).get("internalname").getAsString());
+ String chance = loreMatcher.group("dropChances") != null
+ ? loreMatcher.group("dropChances")
+ : loreMatcher.group("dropCount");
+ drops.add(new MobLootRecipe.MobDrop(item, chance, new ArrayList<>()));
+ }
+ if (loreMatcher.group("missing") != null) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(
+ "[WARNING] You are missing Bestiary levels for drop: " + loreLine));
+
+ }
+ }
+ recipes.add(new MobLootRecipe(
+ new Ingredient(neu.manager, internalMobName, 1),
+ drops,
+ level,
+ coins,
+ xp,
+ combatXp,
+ name,
+ null,
+ new ArrayList<>(),
+ "unknown"
+ ));
+ }
+ boolean saved = false;
+ try {
+ saved = saveRecipes(internalMobName, recipes);
+ } catch (IOException e) {
+ }
+ if (!saved)
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText("" +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + " ERROR " +
+ EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD + EnumChatFormatting.OBFUSCATED + "#" +
+ EnumChatFormatting.RESET + EnumChatFormatting.DARK_RED + EnumChatFormatting.BOLD +
+ " Failed to save recipe. Does the item already exist?")); // TODO: MERGE CODE OVER
+ }
+
+ private int parseIntIgnoringCommas(String text) {
+ return Integer.parseInt(text.replace(",", ""));
}
- public boolean saveRecipe(NeuRecipe recipe) throws IOException {
- JsonObject recipeJson = recipe.serialize();
- for (Ingredient i : recipe.getOutputs()) {
- if (i.isCoins()) continue;
- JsonObject outputJson = neu.manager.readJsonDefaultDir(i.getInternalItemId() + ".json");
- if (outputJson == null) return false;
- outputJson.addProperty("clickcommand", "viewrecipe");
- JsonArray array = new JsonArray();
- array.add(recipeJson);
- outputJson.add("recipes", array);
- neu.manager.writeJsonDefaultDir(outputJson, i.getInternalItemId() + ".json");
- neu.manager.loadItem(i.getInternalItemId());
+ /*{
+ id: "minecraft:skull",
+ Count: 1b,
+ tag: {
+ overrideMeta: 1b,
+ SkullOwner: {
+ Id: "2005daad-730b-363c-abae-e6f3830816fb",
+ Properties: {
+ textures: [{
+ Value: "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTZjMGIzNmQ1M2ZmZjY5YTQ5YzdkNmYzOTMyZjJiMGZlOTQ4ZTAzMjIyNmQ1ZTgwNDVlYzU4NDA4YTM2ZTk1MSJ9fX0="
+ }]
+ }
+ },
+ display: {
+ Lore: ["§7Coins per Kill: §610", "§7Combat Exp: §340", "§7XP Orbs: §312", "", "§7Kills: §a990", "§7Deaths: §a2", "", "§fCommon Loot", "§8 ■ §7§fEnder Pearl §8x1-3", "", "§9Rare Loot", "§8 ■ §7§aEnchanted Ender Pearl §8(§a1%§8)", "", "§6Legendary Loot", "§8 ■ §7§7[Lvl 1] §aEnderman §8(§a0.02%§8)", "§8 ■ §7§7[Lvl 1] §fEnderman §8(§a0.05%§8)", "§8 ■ §7§5Ender Helmet §8(§a0.1%§8)", "§8 ■ §7§5Ender Boots §8(§a0.1%§8)", "§8 ■ §7§5Ender Leggings §8(§a0.1%§8)", "§8 ■ §7§5Ender Chestplate §8(§a0.1%§8)", "", "§dRNGesus Loot", " §8■ §c???"],
+ Name: "§8[§7Lv42§8] §fEnderman"
+ },
+ AttributeModifiers: []
+ },
+ Damage: 3s
+}*/
+ public boolean saveRecipes(String relevantItem, List<NeuRecipe> recipes) throws IOException {
+ relevantItem = relevantItem.replace(" ", "_");
+ JsonObject outputJson = neu.manager.readJsonDefaultDir(relevantItem + ".json");
+ if (outputJson == null) return false;
+ outputJson.addProperty("clickcommand", "viewrecipe");
+ JsonArray array = new JsonArray();
+ for (NeuRecipe recipe : recipes) {
+ array.add(recipe.serialize());
}
+ outputJson.add("recipes", array);
+ neu.manager.writeJsonDefaultDir(outputJson, relevantItem + ".json");
+ neu.manager.loadItem(relevantItem);
return true;
}
@@ -149,7 +307,7 @@ public class RecipeGenerator {
);
}
- private static final Map<Character, Integer> durationSuffixLengthMap = new HashMap<Character, Integer>() {{
+ private static Map<Character, Integer> durationSuffixLengthMap = new HashMap<Character, Integer>() {{
put('d', 60 * 60 * 24);
put('h', 60 * 60);
put('m', 60);
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeSlot.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeSlot.java
index 61f8ef27..489485e4 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeSlot.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeSlot.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java
new file mode 100644
index 00000000..de9c869f
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/RecipeType.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.recipes;
+
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.ItemStack;
+
+public enum RecipeType {
+ CRAFTING("crafting", "Crafting", CraftingRecipe::parseCraftingRecipe, new ItemStack(Blocks.crafting_table)),
+ FORGE("forge", "Forging", ForgeRecipe::parseForgeRecipe, new ItemStack(Blocks.anvil)),
+ TRADE("trade", "Trading", VillagerTradeRecipe::parseStaticRecipe, new ItemStack(Items.emerald)),
+ MOB_LOOT("drops", "Mob Loot", MobLootRecipe::parseRecipe, new ItemStack(Items.diamond_sword)),
+ NPC_SHOP("npc_shop", "NPC Item Shop", ItemShopRecipe::parseItemRecipe, new ItemStack(Items.wheat_seeds));
+
+ private final String id;
+ private final String label;
+ private final RecipeFactory recipeFactory;
+ private final ItemStack icon;
+
+ RecipeType(String id, String label, RecipeFactory recipeFactory, ItemStack icon) {
+ this.id = id;
+ this.label = label;
+ this.recipeFactory = recipeFactory;
+ this.icon = icon;
+ icon.setStackDisplayName("neurecipe-" + id);
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public RecipeFactory getRecipeFactory() {
+ return recipeFactory;
+ }
+
+ public ItemStack getIcon() {
+ return icon;
+ }
+
+ public NeuRecipe createRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson) {
+ return recipeFactory.createRecipe(manager, recipe, outputItemJson);
+ }
+
+ public static RecipeType getRecipeTypeForId(String id) {
+ for (RecipeType value : values()) {
+ if (value.id.equals(id)) return value;
+ }
+ return null;
+ }
+
+ @FunctionalInterface
+ interface RecipeFactory {
+ NeuRecipe createRecipe(NEUManager manager, JsonObject recipe, JsonObject outputItemJson);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java b/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java
index 371d4f3c..9bb79604 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/recipes/VillagerTradeRecipe.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.recipes;
import com.google.common.collect.Sets;
@@ -17,18 +36,22 @@ import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.util.ResourceLocation;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
public class VillagerTradeRecipe implements NeuRecipe {
- public static final int COST_SLOT_X = 51;
- public static final int COST_SLOT_Y = 34;
- public static final int RESULT_SLOT_Y = 35;
+ public static final int COST_SLOT_X = 52;
+ public static final int COST_SLOT_Y = 66;
+ public static final int RESULT_SLOT_Y = 66;
public static final int RESULT_SLOT_X = 124;
private static class Holder { // This holder object exists to defer initialization to first access
- private static final GameProfile DREAM_PROFILE =
- new GameProfile(UUID.fromString("ec70bcaf-702f-4bb8-b48d-276fa52a780c"), "Dream");
+ private static final GameProfile DREAM_PROFILE = new GameProfile(UUID.fromString(
+ "ec70bcaf-702f-4bb8-b48d-276fa52a780c"), "Dream");
private static final EntityLivingBase DEMO_DREAM = new AbstractClientPlayer(null, DREAM_PROFILE) {
@Override
protected NetworkPlayerInfo getPlayerInfo() {
@@ -51,8 +74,10 @@ public class VillagerTradeRecipe implements NeuRecipe {
}
- private final static ResourceLocation BACKGROUND =
- new ResourceLocation("notenoughupdates", "textures/gui/villager_recipe.png");
+ private final static ResourceLocation BACKGROUND = new ResourceLocation(
+ "notenoughupdates",
+ "textures/gui/villager_recipe_tall.png"
+ );
private final Ingredient result;
private final Ingredient cost;
@@ -74,6 +99,11 @@ public class VillagerTradeRecipe implements NeuRecipe {
}
@Override
+ public RecipeType getType() {
+ return RecipeType.TRADE;
+ }
+
+ @Override
public Set<Ingredient> getIngredients() {
return Sets.newHashSet(cost);
}
@@ -108,7 +138,7 @@ public class VillagerTradeRecipe implements NeuRecipe {
FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
Utils.drawStringCenteredScaledMaxWidth(
minCost + " - " + maxCost, fontRenderer,
- gui.guiLeft + 50, gui.guiTop + 60, false, 75, 0xff00ff
+ gui.guiLeft + 50, gui.guiTop + 90, false, 75, 0xff00ff
);
}
@@ -118,9 +148,9 @@ public class VillagerTradeRecipe implements NeuRecipe {
public void drawExtraBackground(GuiItemRecipe gui, int mouseX, int mouseY) {
GuiInventory.drawEntityOnScreen(
gui.guiLeft + 90,
- gui.guiTop + 75,
+ gui.guiTop + 100,
30,
- gui.guiLeft - mouseX + 80,
+ gui.guiLeft - mouseX + 110,
gui.guiTop + 60 - mouseY,
Holder.DEMO_ENTITY
);
@@ -131,7 +161,7 @@ public class VillagerTradeRecipe implements NeuRecipe {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("type", "trade");
jsonObject.addProperty("result", result.serialize());
- jsonObject.addProperty("cost", cost.getInternalItemId());
+ jsonObject.addProperty("cost", cost.serialize());
if (minCost > 0)
jsonObject.addProperty("min", minCost);
if (maxCost > 0)
@@ -144,7 +174,7 @@ public class VillagerTradeRecipe implements NeuRecipe {
return BACKGROUND;
}
- public static VillagerTradeRecipe parseStaticRecipe(NEUManager manager, JsonObject recipe) {
+ public static VillagerTradeRecipe parseStaticRecipe(NEUManager manager, JsonObject recipe, JsonObject result) {
return new VillagerTradeRecipe(
new Ingredient(manager, recipe.get("result").getAsString()),
new Ingredient(manager, recipe.get("cost").getAsString()),
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/AllowEmptyHTMLTag.java b/src/main/java/io/github/moulberry/notenoughupdates/util/AllowEmptyHTMLTag.java
index b7fc55e4..5c223605 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/AllowEmptyHTMLTag.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/AllowEmptyHTMLTag.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import info.bliki.htmlcleaner.TagNode;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
new file mode 100644
index 00000000..8c594911
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.message.BasicNameValuePair;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.zip.GZIPInputStream;
+
+public class ApiUtil {
+ private static final Gson gson = new Gson();
+ private static final ExecutorService executorService = Executors.newFixedThreadPool(3);
+ private static final String USER_AGENT = "NotEnoughUpdates/" + NotEnoughUpdates.VERSION;
+ private static SSLContext ctx;
+
+ static {
+ try {
+ KeyStore letsEncryptStore = KeyStore.getInstance("JKS");
+ letsEncryptStore.load(ApiUtil.class.getResourceAsStream("/neukeystore.jks"), "neuneu".toCharArray());
+ ctx = SSLContext.getInstance("TLS");
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ kmf.init(letsEncryptStore, null);
+ tmf.init(letsEncryptStore);
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException |
+ IOException | CertificateException e) {
+ System.out.println("Failed to load NEU keystore. A lot of API requests won't work");
+ e.printStackTrace();
+ }
+ }
+
+ public static class Request {
+
+ private final List<NameValuePair> queryArguments = new ArrayList<>();
+ private String baseUrl = null;
+ private boolean shouldGunzip = false;
+ private String method = "GET";
+
+ public Request method(String method) {
+ this.method = method;
+ return this;
+ }
+
+ public Request url(String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ public Request queryArgument(String key, String value) {
+ queryArguments.add(new BasicNameValuePair(key, value));
+ return this;
+ }
+
+ public Request queryArguments(Collection<NameValuePair> queryArguments) {
+ this.queryArguments.addAll(queryArguments);
+ return this;
+ }
+
+ public Request gunzip() {
+ shouldGunzip = true;
+ return this;
+ }
+
+ private CompletableFuture<URL> buildUrl() {
+ CompletableFuture<URL> fut = new CompletableFuture<>();
+ try {
+ fut.complete(new URIBuilder(baseUrl)
+ .addParameters(queryArguments)
+ .build()
+ .toURL());
+ } catch (URISyntaxException |
+ MalformedURLException |
+ NullPointerException e) { // Using CompletableFuture as an exception monad, isn't that exiting?
+ fut.completeExceptionally(e);
+ }
+ return fut;
+ }
+
+ public CompletableFuture<String> requestString() {
+ return buildUrl().thenApplyAsync(url -> {
+ try {
+ InputStream inputStream = null;
+ URLConnection conn = null;
+ try {
+ conn = url.openConnection();
+ if (conn instanceof HttpsURLConnection && ctx != null) {
+ HttpsURLConnection sslConn = (HttpsURLConnection) conn;
+ sslConn.setSSLSocketFactory(ctx.getSocketFactory());
+ }
+ if (conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).setRequestMethod(method);
+ }
+ conn.setConnectTimeout(10000);
+ conn.setReadTimeout(10000);
+ conn.setRequestProperty("User-Agent", USER_AGENT);
+
+ inputStream = conn.getInputStream();
+
+ if (shouldGunzip) {
+ inputStream = new GZIPInputStream(inputStream);
+ }
+
+ // While the assumption of UTF8 isn't always true; it *should* always be true.
+ // Not in the sense that this will hold in most cases (although that as well),
+ // but in the sense that any violation of this better have a good reason.
+ return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+ } finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ } finally {
+ if (conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).disconnect();
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e); // We can rethrow, since supplyAsync catches exceptions.
+ }
+ }, executorService);
+ }
+
+ public CompletableFuture<JsonObject> requestJson() {
+ return requestJson(JsonObject.class);
+ }
+
+ public <T> CompletableFuture<T> requestJson(Class<? extends T> clazz) {
+ return requestString().thenApply(str -> gson.fromJson(str, clazz));
+ }
+
+ }
+
+ public Request request() {
+ return new Request();
+ }
+
+ public Request newHypixelApiRequest(String apiPath) {
+ return newAnonymousHypixelApiRequest(apiPath)
+ .queryArgument("key", NotEnoughUpdates.INSTANCE.config.apiData.apiKey);
+ }
+
+ public Request newAnonymousHypixelApiRequest(String apiPath) {
+ return new Request()
+ .url("https://api.hypixel.net/" + apiPath);
+ }
+
+ public Request newMoulberryRequest(String path) {
+ return new Request()
+ .url(getMyApiURL() + path);
+ }
+
+ private String getMyApiURL() {
+ return String.format("https://%s/", NotEnoughUpdates.INSTANCE.config.apiData.moulberryCodesApi);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java
new file mode 100644
index 00000000..37b0a187
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoader.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.common.base.Objects;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public interface AsyncDependencyLoader<T> {
+
+ Optional<T> peekValue();
+
+ public static <R, T> AsyncDependencyLoader<T> withObjectIdentity(
+ Supplier<R> supplier,
+ Function<R, CompletableFuture<T>> generator
+ ) {
+ return new AsyncDependencyLoaderImpl<>(supplier, generator, (a, b) -> a != b);
+ }
+
+ public static <R, T> AsyncDependencyLoader<T> withEqualsInvocation(
+ Supplier<R> supplier,
+ Function<R, CompletableFuture<T>> generator
+ ) {
+ return new AsyncDependencyLoaderImpl<>(supplier, generator, (a, b) -> !Objects.equal(a, b));
+ }
+
+ public static <R, T> AsyncDependencyLoader<T> withEqualityFunction(
+ Supplier<R> supplier,
+ Function<R, CompletableFuture<T>> generator,
+ BiFunction<R, R, Boolean> isEqual
+ ) {
+ return new AsyncDependencyLoaderImpl<>(supplier, generator, (a, b) -> !isEqual.apply(a, b));
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java
new file mode 100644
index 00000000..4b7f2fb8
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/AsyncDependencyLoaderImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+class AsyncDependencyLoaderImpl<R, T> implements AsyncDependencyLoader<T> {
+
+ private final Supplier<R> supplyDependency;
+ private final Function<R, CompletableFuture<T>> generator;
+ private final BiFunction<R, R, Boolean> isDifferent;
+ private volatile CompletableFuture<T> lastValue;
+ private volatile R lastDependency;
+ private volatile boolean isFirstFire = true;
+
+ @Override
+ public synchronized Optional<T> peekValue() {
+ R nextDependency = supplyDependency.get();
+ if (isFirstFire || isDifferent.apply(nextDependency, lastDependency)) {
+ isFirstFire = false;
+ if (lastValue != null)
+ lastValue.cancel(true);
+ lastValue = generator.apply(nextDependency);
+ }
+ lastDependency = nextDependency;
+ return Optional.ofNullable(lastValue.getNow(null));
+ }
+
+ AsyncDependencyLoaderImpl(
+ Supplier<R> supplyDependency,
+ Function<R, CompletableFuture<T>> generator,
+ BiFunction<R, R, Boolean> isDifferent
+ ) {
+ this.supplyDependency = supplyDependency;
+ this.generator = generator;
+ this.isDifferent = isDifferent;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
new file mode 100644
index 00000000..10bfa6a9
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Calculator.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+
+public class Calculator {
+ public static BigDecimal calculate(String source) throws CalculatorException {
+ source = source.toLowerCase(Locale.ROOT);
+ return evaluate(shuntingYard(lex(source)));
+ }
+
+ ///<editor-fold desc="Lexing Time">
+ public enum TokenType {
+ NUMBER, BINOP, LPAREN, RPAREN, POSTOP
+ }
+
+ public static class Token {
+ public TokenType type;
+ String operatorValue;
+ long numericValue;
+ int exponent;
+ int tokenStart;
+ int tokenLength;
+ }
+
+ static String binops = "+-*/x";
+ static String postops = "mkbts";
+ static String digits = "0123456789";
+
+ static void readDigitsInto(Token token, String source, boolean decimals) {
+ int startIndex = token.tokenStart + token.tokenLength;
+ for (int j = 0; j + startIndex < source.length(); j++) {
+ char d = source.charAt(j + startIndex);
+ int d0 = digits.indexOf(d);
+ if (d0 != -1) {
+ if (decimals)
+ token.exponent--;
+ token.numericValue *= 10;
+ token.numericValue += d0;
+ token.tokenLength += 1;
+ } else {
+ return;
+ }
+ }
+ }
+
+ public static class CalculatorException extends Exception {
+ int offset, length;
+
+ public CalculatorException(String message, int offset, int length) {
+ super(message);
+ this.offset = offset;
+ this.length = length;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+ }
+
+ public static List<Token> lex(String source) throws CalculatorException {
+ List<Token> tokens = new ArrayList<>();
+ for (int i = 0; i < source.length(); ) {
+ char c = source.charAt(i);
+ if (Character.isWhitespace(c)) {
+ i++;
+ continue;
+ }
+ Token token = new Token();
+ token.tokenStart = i;
+ if (binops.indexOf(c) != -1) {
+ token.tokenLength = 1;
+ token.type = TokenType.BINOP;
+ token.operatorValue = c + "";
+ } else if (postops.indexOf(c) != -1) {
+ token.tokenLength = 1;
+ token.type = TokenType.POSTOP;
+ token.operatorValue = c + "";
+ } else if (c == ')') {
+ token.tokenLength = 1;
+ token.type = TokenType.RPAREN;
+ token.operatorValue = ")";
+ } else if (c == '(') {
+ token.tokenLength = 1;
+ token.type = TokenType.LPAREN;
+ token.operatorValue = "(";
+ } else if ('.' == c) {
+ token.tokenLength = 1;
+ token.type = TokenType.NUMBER;
+ readDigitsInto(token, source, true);
+ if (token.tokenLength == 1) {
+ throw new CalculatorException("Invalid number literal", i, 1);
+ }
+ } else if (digits.indexOf(c) != -1) {
+ token.type = TokenType.NUMBER;
+ readDigitsInto(token, source, false);
+ if (i + token.tokenLength < source.length()) {
+ char p = source.charAt(i + token.tokenLength);
+ if ('.' == p) {
+ token.tokenLength++;
+ readDigitsInto(token, source, true);
+ }
+ }
+ } else {
+ throw new CalculatorException("Unknown thing " + c, i, 1);
+ }
+ tokens.add(token);
+ i += token.tokenLength;
+ }
+ return tokens;
+ }
+ ///</editor-fold>
+
+ ///<editor-fold desc="Shunting Time">
+ static int getPrecedence(Token token) throws CalculatorException {
+ switch (token.operatorValue.intern()) {
+ case "+":
+ case "-":
+ return 0;
+ case "*":
+ case "/":
+ case "x":
+ return 1;
+ }
+ throw new CalculatorException("Unknown operator " + token.operatorValue, token.tokenStart, token.tokenLength);
+ }
+
+ public static List<Token> shuntingYard(List<Token> toShunt) throws CalculatorException {
+ // IT'S SHUNTING TIME
+ // This is an implementation of the shunting yard algorithm
+
+ Deque<Token> op = new ArrayDeque<>();
+ List<Token> out = new ArrayList<>();
+
+ for (Token currentlyShunting : toShunt) {
+ switch (currentlyShunting.type) {
+ case NUMBER:
+ out.add(currentlyShunting);
+ break;
+ case BINOP:
+ int p = getPrecedence(currentlyShunting);
+ while (!op.isEmpty()) {
+ Token l = op.peek();
+ if (l.type == TokenType.LPAREN)
+ break;
+ assert (l.type == TokenType.BINOP);
+ int pl = getPrecedence(l);
+ if (pl >= p) { // Association order
+ out.add(op.pop());
+ } else {
+ break;
+ }
+ }
+ op.push(currentlyShunting);
+ break;
+ case LPAREN:
+ op.push(currentlyShunting);
+ break;
+ case RPAREN:
+ while (1 > 0) {
+ if (op.isEmpty())
+ throw new CalculatorException(
+ "Unbalanced right parenthesis",
+ currentlyShunting.tokenStart,
+ currentlyShunting.tokenLength
+ );
+ Token l = op.pop();
+ if (l.type == TokenType.LPAREN) {
+ break;
+ }
+ out.add(l);
+ }
+ break;
+ case POSTOP:
+ out.add(currentlyShunting);
+ break;
+ }
+ }
+ while (!op.isEmpty()) {
+ Token l = op.pop();
+ if (l.type == TokenType.LPAREN)
+ throw new CalculatorException("Unbalanced left parenthesis", l.tokenStart, l.tokenLength);
+ out.add(l);
+ }
+ return out;
+ }
+
+ /// </editor-fold>
+
+ ///<editor-fold desc="Evaluating Time">
+
+ public static BigDecimal evaluate(List<Token> rpnTokens) throws CalculatorException {
+ Deque<BigDecimal> values = new ArrayDeque<>();
+ try {
+ for (Token command : rpnTokens) {
+ switch (command.type) {
+ case NUMBER:
+ values.push(new BigDecimal(command.numericValue).scaleByPowerOfTen(command.exponent));
+ break;
+ case BINOP:
+ BigDecimal right = values.pop().setScale(2, RoundingMode.HALF_UP);
+ BigDecimal left = values.pop().setScale(2, RoundingMode.HALF_UP);
+ switch (command.operatorValue.intern()) {
+ case "x":
+ case "*":
+ values.push(left.multiply(right).setScale(2, RoundingMode.HALF_UP));
+ break;
+ case "/":
+ try {
+ values.push(left.divide(right, RoundingMode.HALF_UP).setScale(2, RoundingMode.HALF_UP));
+ } catch (ArithmeticException e) {
+ throw new CalculatorException("Encountered division by 0", command.tokenStart, command.tokenLength);
+ }
+ break;
+ case "+":
+ values.push(left.add(right).setScale(2, RoundingMode.HALF_UP));
+ break;
+ case "-":
+ values.push(left.subtract(right).setScale(2, RoundingMode.HALF_UP));
+ break;
+ default:
+ throw new CalculatorException(
+ "Unknown operation " + command.operatorValue,
+ command.tokenStart,
+ command.tokenLength
+ );
+ }
+ break;
+ case LPAREN:
+ case RPAREN:
+ throw new CalculatorException(
+ "Did not expect unshunted token in RPN",
+ command.tokenStart,
+ command.tokenLength
+ );
+ case POSTOP:
+ BigDecimal p = values.pop();
+ switch (command.operatorValue.intern()) {
+ case "s":
+ values.push(p.multiply(new BigDecimal(64)).setScale(2, RoundingMode.HALF_UP));
+ break;
+ case "k":
+ values.push(p.multiply(new BigDecimal(1_000)).setScale(2, RoundingMode.HALF_UP));
+ break;
+ case "m":
+ values.push(p.multiply(new BigDecimal(1_000_000)).setScale(2, RoundingMode.HALF_UP));
+ break;
+ case "b":
+ values.push(p.multiply(new BigDecimal(1_000_000_000)).setScale(2, RoundingMode.HALF_UP));
+ break;
+ case "t":
+ values.push(p.multiply(new BigDecimal("1000000000000")).setScale(2, RoundingMode.HALF_UP));
+ break;
+ default:
+ throw new CalculatorException(
+ "Unknown operation " + command.operatorValue,
+ command.tokenStart,
+ command.tokenLength
+ );
+ }
+ break;
+ }
+ }
+ BigDecimal peek = values.pop();
+ return peek.stripTrailingZeros();
+ } catch (NoSuchElementException e) {
+ throw new CalculatorException("Unfinished expression", 0, 0);
+ }
+ }
+
+ ///</editor-fold>
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java
index bb3b3425..ef030367 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Constants.java
@@ -1,7 +1,36 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
-import com.google.gson.*;
-import io.github.moulberry.notenoughupdates.collectionlog.CollectionConstant;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import io.github.moulberry.notenoughupdates.events.RepositoryReloadEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.lang.reflect.Type;
import java.util.concurrent.locks.ReentrantLock;
@@ -40,11 +69,14 @@ public class Constants {
public static JsonObject ESSENCECOSTS;
public static JsonObject FAIRYSOULS;
public static JsonObject REFORGESTONES;
- public static CollectionConstant COLLECTIONLOG;
+ public static JsonObject TROPHYFISH;
+ public static JsonObject WEIGHT;
+ public static JsonObject RNGSCORE;
private static final ReentrantLock lock = new ReentrantLock();
- public static void reload() {
+ @SubscribeEvent
+ public void reload(RepositoryReloadEvent event) {
try {
lock.lock();
@@ -59,7 +91,11 @@ public class Constants {
ESSENCECOSTS = Utils.getConstant("essencecosts", gson);
FAIRYSOULS = Utils.getConstant("fairy_souls", gson);
REFORGESTONES = Utils.getConstant("reforgestones", gson);
- //COLLECTIONLOG = Utils.getConstant("collectionlog", gson, CollectionConstant.class);
+ TROPHYFISH = Utils.getConstant("trophyfish", gson);
+ WEIGHT = Utils.getConstant("weight", gson);
+ RNGSCORE = Utils.getConstant("rngscore", gson);
+ } catch (Exception ex) {
+ ex.printStackTrace();
} finally {
lock.unlock();
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Debouncer.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Debouncer.java
index 15808a29..ec076a77 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Debouncer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Debouncer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
/**
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/DiscordMarkdownBuilder.java b/src/main/java/io/github/moulberry/notenoughupdates/util/DiscordMarkdownBuilder.java
index 1c78f924..3c6c5f3d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/DiscordMarkdownBuilder.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/DiscordMarkdownBuilder.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
public class DiscordMarkdownBuilder {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/GuiTextures.java b/src/main/java/io/github/moulberry/notenoughupdates/util/GuiTextures.java
index 48a6915b..3ead5a56 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/GuiTextures.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/GuiTextures.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import net.minecraft.util.ResourceLocation;
@@ -8,8 +27,6 @@ public class GuiTextures {
public static final ResourceLocation itemPaneTabArrow =
new ResourceLocation("notenoughupdates:item_pane_tab_arrow.png");
- //public static final ResourceLocation prev = new ResourceLocation("notenoughupdates:prev.png");
- //public static final ResourceLocation next = new ResourceLocation("notenoughupdates:next.png");
public static final ResourceLocation rightarrow_overlay =
new ResourceLocation("notenoughupdates:rightarrow_overlay.png");
public static final ResourceLocation rightarrow = new ResourceLocation("notenoughupdates:rightarrow.png");
@@ -19,8 +36,6 @@ public class GuiTextures {
public static final ResourceLocation off = new ResourceLocation("notenoughupdates:off.png");
public static final ResourceLocation on = new ResourceLocation("notenoughupdates:on.png");
public static final ResourceLocation help = new ResourceLocation("notenoughupdates:help.png");
- public static final ResourceLocation slider_off = new ResourceLocation("notenoughupdates:slider_off.png");
- public static final ResourceLocation slider_on = new ResourceLocation("notenoughupdates:slider_on.png");
public static final ResourceLocation slider_off_large = new ResourceLocation("notenoughupdates:slider_off_large.png");
public static final ResourceLocation slider_on_large = new ResourceLocation("notenoughupdates:slider_on_large.png");
public static final ResourceLocation slider_button = new ResourceLocation("notenoughupdates:slider_button.png");
@@ -34,36 +49,17 @@ public class GuiTextures {
public static final ResourceLocation item_mask = new ResourceLocation("notenoughupdates:item_mask.png");
public static final ResourceLocation item_haschild = new ResourceLocation("notenoughupdates:item_haschild.png");
+ public static final ResourceLocation button_white = new ResourceLocation("notenoughupdates:button_white.png");
public static final ResourceLocation button_tex = new ResourceLocation("notenoughupdates:button.png");
public static final ResourceLocation button_fsr =
new ResourceLocation("notenoughupdates:FSR_do_not_texture_this_please.png");
- public static final ResourceLocation setting_border = new ResourceLocation("notenoughupdates:setting_border.png");
-
- public static final ResourceLocation button_white = new ResourceLocation("notenoughupdates:button_white.png");
- public static final ResourceLocation colour_selector_dot =
- new ResourceLocation("notenoughupdates:colour_selector_dot.png");
- public static final ResourceLocation colour_selector_bar =
- new ResourceLocation("notenoughupdates:colour_selector_bar.png");
- public static final ResourceLocation colour_selector_bar_alpha =
- new ResourceLocation("notenoughupdates:colour_selector_bar_alpha.png");
- public static final ResourceLocation colour_selector_chroma =
- new ResourceLocation("notenoughupdates:colour_selector_chroma.png");
-
public static final ResourceLocation accessory_bag_overlay =
new ResourceLocation("notenoughupdates:accessory_bag_overlay.png");
public static final ResourceLocation quickcommand_background =
new ResourceLocation("notenoughupdates:quickcommand_background.png");
- public static final ResourceLocation gamemodes = new ResourceLocation("notenoughupdates:gamemodes.png");
- public static final ResourceLocation radial_square_off =
- new ResourceLocation("notenoughupdates:radial_square_off.png");
- public static final ResourceLocation radial_square_on = new ResourceLocation("notenoughupdates:radial_square_on.png");
- public static final ResourceLocation radial_circle_off =
- new ResourceLocation("notenoughupdates:radial_circle_off.png");
- public static final ResourceLocation radial_circle_on = new ResourceLocation("notenoughupdates:radial_circle_on.png");
-
public static final ResourceLocation dungeon_chest_worth =
new ResourceLocation("notenoughupdates:dungeon_chest_worth.png");
@@ -73,10 +69,6 @@ public class GuiTextures {
public static final ResourceLocation auction_view_buttons =
new ResourceLocation("notenoughupdates:auction_view_buttons.png");
- public static final ResourceLocation logo = new ResourceLocation("notenoughupdates:logo.png");
- public static final ResourceLocation logo_fg = new ResourceLocation("notenoughupdates:logo_fg.png");
- public static final ResourceLocation logo_bg = new ResourceLocation("notenoughupdates:logo_bg.png");
-
public static final ResourceLocation sort_all = new ResourceLocation("notenoughupdates:sort_all.png");
public static final ResourceLocation sort_mob = new ResourceLocation("notenoughupdates:sort_mob.png");
public static final ResourceLocation sort_pet = new ResourceLocation("notenoughupdates:sort_pet.png");
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/HastebinUploader.java b/src/main/java/io/github/moulberry/notenoughupdates/util/HastebinUploader.java
index 9cbad402..27993510 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/HastebinUploader.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/HastebinUploader.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import com.google.gson.Gson;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/HotmInformation.java b/src/main/java/io/github/moulberry/notenoughupdates/util/HotmInformation.java
index 7258fe9f..1968b51e 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/HotmInformation.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/HotmInformation.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import com.google.gson.JsonArray;
@@ -140,13 +159,11 @@ public class HotmInformation {
public synchronized void requestUpdate(boolean force) {
if (updateTask.isDone() || force) {
- updateTask = neu.manager.hypixelApi.getHypixelApiAsync(
- neu.config.apiKey.apiKey,
- "skyblock/profiles",
- new HashMap<String, String>() {{
- put("uuid", Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""));
- }}
- ).thenAccept(this::updateInformation);
+ updateTask = neu.manager.apiUtils
+ .newHypixelApiRequest("skyblock/profiles")
+ .queryArgument("uuid", Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""))
+ .requestJson()
+ .thenAccept(this::updateInformation);
}
}
@@ -176,7 +193,10 @@ public class HotmInformation {
Tree tree = new Tree();
JsonObject nodes = miningCore.getAsJsonObject("nodes");
for (Map.Entry<String, JsonElement> node : nodes.entrySet()) {
- tree.levels.put(node.getKey(), node.getValue().getAsInt());
+ String key = node.getKey();
+ if (!key.startsWith("toggle_")) {
+ tree.levels.put(key, node.getValue().getAsInt());
+ }
}
if (miningCore.has("powder_mithril_total")) {
tree.totalMithrilPowder = miningCore.get("powder_mithril_total").getAsInt();
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java b/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
deleted file mode 100644
index 2628eb7d..00000000
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/HypixelApi.java
+++ /dev/null
@@ -1,188 +0,0 @@
-package io.github.moulberry.notenoughupdates.util;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.ConnectException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.function.Consumer;
-import java.util.zip.GZIPInputStream;
-
-public class HypixelApi {
- private final Gson gson = new Gson();
- private final ExecutorService es = Executors.newFixedThreadPool(3);
-
- private static final int FAILS_BEFORE_SWITCH = 3;
- private int currentUrl = 0;
- private long lastPrimaryUrl = 0;
- private final String[] myApiURLs = {"https://moulberry.codes/"};
- //, "http://moulberry.codes/", "http://51.79.51.21/"};//, "http://51.75.78.252/" };
- private final Integer[] myApiSuccesses = {0, 0, 0, 0};
-
- public CompletableFuture<JsonObject> getHypixelApiAsync(String apiKey, String method, HashMap<String, String> args) {
- return getApiAsync(generateApiUrl(apiKey, method, args));
- }
-
- public void getHypixelApiAsync(
- String apiKey,
- String method,
- HashMap<String, String> args,
- Consumer<JsonObject> consumer
- ) {
- getHypixelApiAsync(apiKey, method, args, consumer, () -> {
- });
- }
-
- public void getHypixelApiAsync(
- String apiKey,
- String method,
- HashMap<String, String> args,
- Consumer<JsonObject> consumer,
- Runnable error
- ) {
- getApiAsync(generateApiUrl(apiKey, method, args), consumer, error);
- }
-
- private String getMyApiURL() {
- if (currentUrl == 0) {
- lastPrimaryUrl = System.currentTimeMillis();
- } else if (System.currentTimeMillis() - lastPrimaryUrl > 1000 * 60 * 30) { //Try switch back to main url after 30m
- currentUrl = 0;
- }
-
- myApiSuccesses[currentUrl] = Math.min(FAILS_BEFORE_SWITCH, myApiSuccesses[currentUrl] + 1);
- return myApiURLs[currentUrl];
- }
-
- private void myApiError(int index) {
- myApiSuccesses[index] = myApiSuccesses[index] - 2;
-
- if (myApiSuccesses[index] < 0) {
- myApiSuccesses[index] = 0;
-
- if (index == currentUrl) {
- currentUrl++;
- if (currentUrl >= myApiURLs.length) {
- currentUrl = 0;
- }
- }
- }
- }
-
- public CompletableFuture<JsonObject> getApiAsync(String urlS) {
- CompletableFuture<JsonObject> result = new CompletableFuture<>();
- es.submit(() -> {
- try {
- result.complete(getApiSync(urlS));
- } catch (Exception e) {
- result.completeExceptionally(e);
- }
- });
- return result;
- }
-
- public void getApiAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
- es.submit(() -> {
- try {
- consumer.accept(getApiSync(urlS));
- } catch (Exception e) {
- error.run();
- }
- });
- }
-
- public void getMyApiAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
- es.submit(() -> {
- int current = currentUrl;
- try {
- consumer.accept(getApiSync(getMyApiURL() + urlS));
- } catch (Exception e) {
- if (NotEnoughUpdates.INSTANCE.config.hidden.dev) {
- e.printStackTrace();
- }
- myApiError(current);
- error.run();
- }
- });
- }
-
- public void getMyApiGZIPAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
- es.submit(() -> {
- int current = currentUrl;
- try {
- consumer.accept(getApiGZIPSync(getMyApiURL() + urlS));
- } catch (Exception e) {
- myApiError(current);
- error.run();
- }
- });
- }
-
- public void getApiGZIPAsync(String urlS, Consumer<JsonObject> consumer, Runnable error) {
- es.submit(() -> {
- try {
- consumer.accept(getApiGZIPSync(urlS));
- } catch (Exception e) {
- error.run();
- }
- });
- }
-
- public JsonObject getApiSync(String urlS) throws IOException {
- URL url = new URL(urlS);
- URLConnection connection = url.openConnection();
- connection.setConnectTimeout(10000);
- connection.setReadTimeout(10000);
-
- String response = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8);
-
- JsonObject json = gson.fromJson(response, JsonObject.class);
- if (json == null) throw new ConnectException("Invalid JSON");
- return json;
- }
-
- public JsonObject getApiGZIPSync(String urlS) throws IOException {
- URL url = new URL(urlS);
- URLConnection connection = url.openConnection();
- connection.setConnectTimeout(10000);
- connection.setReadTimeout(10000);
-
- String response = IOUtils.toString(new GZIPInputStream(connection.getInputStream()), StandardCharsets.UTF_8);
-
- JsonObject json = gson.fromJson(response, JsonObject.class);
- return json;
- }
-
- public String generateApiUrl(String apiKey, String method, HashMap<String, String> args) {
- if (apiKey != null)
- args.put("key", apiKey.trim().replace("-", ""));
- StringBuilder url = new StringBuilder("https://api.hypixel.net/" + method);
- boolean first = true;
- for (Map.Entry<String, String> entry : args.entrySet()) {
- if (first) {
- url.append("?");
- first = false;
- } else {
- url.append("&");
- }
- try {
- url.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8.name())).append("=")
- .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()));
- } catch (UnsupportedEncodingException e) {
- }
- }
- return url.toString();
- }
-}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java
new file mode 100644
index 00000000..3692602a
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemResolutionQuery.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import io.github.moulberry.notenoughupdates.NEUManager;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.core.util.StringUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.init.Items;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.inventory.IInventory;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
+
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ItemResolutionQuery {
+
+ private static final Pattern ENCHANTED_BOOK_NAME_PATTERN = Pattern.compile("^((?:§.)+)([^§]+) ([IVXL]+)$");
+ private static final String EXTRA_ATTRIBUTES = "ExtraAttributes";
+ private static final List<String> PET_RARITIES = Arrays.asList(
+ "COMMON",
+ "UNCOMMON",
+ "RARE",
+ "EPIC",
+ "LEGENDARY",
+ "MYTHIC"
+ );
+ private final NEUManager manager;
+ private NBTTagCompound compound;
+ private Item itemType;
+ private int stackSize = -1;
+ private Gui guiContext;
+ private String knownInternalName;
+
+ public ItemResolutionQuery(NEUManager manager) {
+ this.manager = manager;
+ }
+
+ public ItemResolutionQuery withItemNBT(NBTTagCompound compound) {
+ this.compound = compound;
+ return this;
+ }
+
+ public ItemResolutionQuery withItemStack(ItemStack stack) {
+ if (stack == null) return this;
+ this.itemType = stack.getItem();
+ this.compound = stack.getTagCompound();
+ this.stackSize = stack.stackSize;
+ return this;
+ }
+
+ public ItemResolutionQuery withGuiContext(Gui gui) {
+ this.guiContext = gui;
+ return this;
+ }
+
+ public ItemResolutionQuery withCurrentGuiContext() {
+ this.guiContext = Minecraft.getMinecraft().currentScreen;
+ return this;
+ }
+
+ public ItemResolutionQuery withKnownInternalName(String knownInternalName) {
+ this.knownInternalName = knownInternalName;
+ return this;
+ }
+
+ @Nullable
+ public String resolveInternalName() {
+ if (knownInternalName != null) {
+ return knownInternalName;
+ }
+ String resolvedName = resolveFromSkyblock();
+ if (resolvedName == null) {
+ resolvedName = resolveContextualName();
+ } else {
+ switch (resolvedName.intern()) {
+ case "PET":
+ resolvedName = resolvePetName();
+ break;
+ case "RUNE":
+ resolvedName = resolveRuneName();
+ break;
+ case "ENCHANTED_BOOK":
+ resolvedName = resolveEnchantedBookNameFromNBT();
+ break;
+ case "PARTY_HAT_CRAB":
+ case "PARTY_HAT_CRAB_ANIMATED":
+ resolvedName = resolveCrabHatName();
+ break;
+ }
+ }
+
+ return resolvedName;
+ }
+
+ @Nullable
+ public JsonObject resolveToItemListJson() {
+ String internalName = resolveInternalName();
+ if (internalName == null) {
+ return null;
+ }
+ return manager.getItemInformation().get(internalName);
+ }
+
+ @Nullable
+ public ItemStack resolveToItemStack() {
+ JsonObject jsonObject = resolveToItemListJson();
+ if (jsonObject == null) return null;
+ return manager.jsonToStack(jsonObject);
+ }
+
+ @Nullable
+ public ItemStack resolveToItemStack(boolean useReplacements) {
+ JsonObject jsonObject = resolveToItemListJson();
+ if (jsonObject == null) return null;
+ return manager.jsonToStack(jsonObject, false, useReplacements);
+ }
+
+ // <editor-fold desc="Resolution Helpers">
+ private boolean isBazaar(IInventory chest) {
+ if (chest.getDisplayName().getFormattedText().startsWith("Bazaar ➜ ")) {
+ return true;
+ }
+ int bazaarSlot = chest.getSizeInventory() - 5;
+ if (bazaarSlot < 0) return false;
+ ItemStack stackInSlot = chest.getStackInSlot(bazaarSlot);
+ if (stackInSlot == null || stackInSlot.stackSize == 0) return false;
+ // NBT lore, we do not care about rendered lore
+ List<String> lore = ItemUtils.getLore(stackInSlot);
+ return lore.contains("§7To Bazaar");
+ }
+
+ private String resolveContextualName() {
+ if (!(guiContext instanceof GuiChest)) {
+ return null;
+ }
+ GuiChest chest = (GuiChest) guiContext;
+ ContainerChest inventorySlots = (ContainerChest) chest.inventorySlots;
+ String guiName = inventorySlots.getLowerChestInventory().getDisplayName().getUnformattedText();
+ boolean isOnBazaar = isBazaar(inventorySlots.getLowerChestInventory());
+ String displayName = ItemUtils.getDisplayName(compound);
+ if (displayName == null) return null;
+ if (itemType == Items.enchanted_book && isOnBazaar && compound != null) {
+ return resolveEnchantmentByName(displayName);
+ }
+ if (displayName.endsWith("Enchanted Book") && guiName.startsWith("Superpairs")) {
+ for (String loreLine : ItemUtils.getLore(compound)) {
+ String enchantmentIdCandidate = resolveEnchantmentByName(loreLine);
+ if (enchantmentIdCandidate != null) return enchantmentIdCandidate;
+ }
+ return null;
+ }
+ if (guiName.equals("Catacombs RNG Meter")) {
+ return resolveItemInCatacombsRngMeter();
+ }
+ return null;
+ }
+
+ private String resolveItemInCatacombsRngMeter() {
+ List<String> lore = ItemUtils.getLore(compound);
+ if (lore.size() > 16) {
+ String s = lore.get(15);
+ if (s.equals("§7Selected Drop")) {
+ String displayName = lore.get(16);
+ return getInternalNameByDisplayName(displayName);
+ }
+ }
+
+ return null;
+ }
+
+ private String getInternalNameByDisplayName(String displayName) {
+ String cleanDisplayName = StringUtils.cleanColour(displayName);
+ for (Map.Entry<String, JsonObject> entry : NotEnoughUpdates.INSTANCE.manager
+ .getItemInformation()
+ .entrySet()) {
+
+ JsonObject object = entry.getValue();
+ if (object.has("displayname")) {
+ String name = object.get("displayname").getAsString();
+ if (StringUtils.cleanColour(name).equals(cleanDisplayName)) {
+ return entry.getKey();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private String resolveEnchantmentByName(String name) {
+ Matcher matcher = ENCHANTED_BOOK_NAME_PATTERN.matcher(name);
+ if (!matcher.matches()) return null;
+ String format = matcher.group(1).toLowerCase(Locale.ROOT);
+ String enchantmentName = matcher.group(2).trim();
+ String romanLevel = matcher.group(3);
+ boolean ultimate = (format.contains("§l"));
+
+ return (ultimate ? "ULTIMATE_" : "")
+ + enchantmentName.replace(" ", "_").toUpperCase(Locale.ROOT)
+ + ";" + Utils.parseRomanNumeral(romanLevel);
+ }
+
+ private String resolveCrabHatName() {
+ int crabHatYear = getExtraAttributes().getInteger("party_hat_year");
+ String color = getExtraAttributes().getString("party_hat_color");
+ return "PARTY_HAT_CRAB_" + color.toUpperCase(Locale.ROOT) + (crabHatYear == 2022 ? "_ANIMATED" : "");
+ }
+
+ private String resolveEnchantedBookNameFromNBT() {
+ NBTTagCompound enchantments = getExtraAttributes().getCompoundTag("enchantments");
+ String enchantName = IteratorUtils.getOnlyElement(enchantments.getKeySet(), null);
+ if (enchantName == null || enchantName.isEmpty()) return null;
+ return enchantName.toUpperCase(Locale.ROOT) + ";" + enchantments.getInteger(enchantName);
+ }
+
+ private String resolveRuneName() {
+ NBTTagCompound runes = getExtraAttributes().getCompoundTag("runes");
+ String runeName = IteratorUtils.getOnlyElement(runes.getKeySet(), null);
+ if (runeName == null || runeName.isEmpty()) return null;
+ return runeName.toUpperCase(Locale.ROOT) + "_RUNE;" + runes.getInteger(runeName);
+ }
+
+ private String resolvePetName() {
+ String petInfo = getExtraAttributes().getString("petInfo");
+ if (petInfo == null || petInfo.isEmpty()) return null;
+ try {
+ JsonObject petInfoObject = manager.gson.fromJson(petInfo, JsonObject.class);
+ String petId = petInfoObject.get("type").getAsString();
+ String petTier = petInfoObject.get("tier").getAsString();
+ int rarityIndex = PET_RARITIES.indexOf(petTier);
+ return petId.toUpperCase(Locale.ROOT) + ";" + rarityIndex;
+ } catch (JsonParseException | ClassCastException ex) {
+ /* This happens if Hypixel changed the pet json format;
+ I still log this exception, since this case *is* exceptional and cannot easily be recovered from */
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ private NBTTagCompound getExtraAttributes() {
+ if (compound == null) return new NBTTagCompound();
+ return compound.getCompoundTag(EXTRA_ATTRIBUTES);
+ }
+
+ private String resolveFromSkyblock() {
+ String internalName = getExtraAttributes().getString("id");
+ if (internalName == null || internalName.isEmpty()) return null;
+ return internalName.toUpperCase(Locale.ROOT).replace(':', '-');
+ }
+
+ // </editor-fold>
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java
new file mode 100644
index 00000000..8b81d1b4
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ItemUtils.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.listener.ItemTooltipListener;
+import io.github.moulberry.notenoughupdates.miscfeatures.PetInfoOverlay;
+import io.github.moulberry.notenoughupdates.profileviewer.GuiProfileViewer;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTException;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.nbt.NBTTagList;
+import net.minecraft.nbt.NBTTagString;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.MathHelper;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+public class ItemUtils {
+
+ public static ItemStack getCoinItemStack(long coinAmount) {
+ String uuid = "2070f6cb-f5db-367a-acd0-64d39a7e5d1b";
+ String texture =
+ "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTM4MDcxNzIxY2M1YjRjZDQwNmNlNDMxYTEzZjg2MDgzYTg5NzNlMTA2NGQyZjg4OTc4Njk5MzBlZTZlNTIzNyJ9fX0=";
+ if (coinAmount >= 100000) {
+ uuid = "94fa2455-2881-31fe-bb4e-e3e24d58dbe3";
+ texture =
+ "eyJ0aW1lc3RhbXAiOjE2MzU5NTczOTM4MDMsInByb2ZpbGVJZCI6ImJiN2NjYTcxMDQzNDQ0MTI4ZDMwODllMTNiZGZhYjU5IiwicHJvZmlsZU5hbWUiOiJsYXVyZW5jaW8zMDMiLCJzaWduYXR1cmVSZXF1aXJlZCI6dHJ1ZSwidGV4dHVyZXMiOnsiU0tJTiI6eyJ1cmwiOiJodHRwOi8vdGV4dHVyZXMubWluZWNyYWZ0Lm5ldC90ZXh0dXJlL2M5Yjc3OTk5ZmVkM2EyNzU4YmZlYWYwNzkzZTUyMjgzODE3YmVhNjQwNDRiZjQzZWYyOTQzM2Y5NTRiYjUyZjYiLCJtZXRhZGF0YSI6eyJtb2RlbCI6InNsaW0ifX19fQo=";
+ }
+ if (coinAmount >= 10000000) {
+ uuid = "0af8df1f-098c-3b72-ac6b-65d65fd0b668";
+ texture =
+ "ewogICJ0aW1lc3RhbXAiIDogMTYzNTk1NzQ4ODQxNywKICAicHJvZmlsZUlkIiA6ICJmNThkZWJkNTlmNTA0MjIyOGY2MDIyMjExZDRjMTQwYyIsCiAgInByb2ZpbGVOYW1lIiA6ICJ1bnZlbnRpdmV0YWxlbnQiLAogICJzaWduYXR1cmVSZXF1aXJlZCIgOiB0cnVlLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2I5NTFmZWQ2YTdiMmNiYzIwMzY5MTZkZWM3YTQ2YzRhNTY0ODE1NjRkMTRmOTQ1YjZlYmMwMzM4Mjc2NmQzYiIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9";
+ }
+ ItemStack skull = Utils.createSkull(
+ "\u00A7r\u00A76" + NumberFormat.getInstance(Locale.US).format(coinAmount) + " Coins",
+ uuid,
+ texture
+ );
+ NBTTagCompound extraAttributes = skull.getTagCompound().getCompoundTag("ExtraAttributes");
+ extraAttributes.setString("id", "SKYBLOCK_COIN");
+ skull.getTagCompound().setTag("ExtraAttributes", extraAttributes);
+ return skull;
+ }
+
+ public static ItemStack createQuestionMarkSkull(String label) {
+ return Utils.createSkull(
+ label,
+ "00000000-0000-0000-0000-000000000000",
+ "bc8ea1f51f253ff5142ca11ae45193a4ad8c3ab5e9c6eec8ba7a4fcb7bac40"
+ );
+ }
+
+ public static NBTTagCompound getOrCreateTag(ItemStack is) {
+ if (is.hasTagCompound()) return is.getTagCompound();
+ NBTTagCompound nbtTagCompound = new NBTTagCompound();
+ is.setTagCompound(nbtTagCompound);
+ return nbtTagCompound;
+ }
+
+ public static void appendLore(ItemStack is, List<String> moreLore) {
+ NBTTagCompound tagCompound = is.getTagCompound();
+ if (tagCompound == null) {
+ tagCompound = new NBTTagCompound();
+ }
+ NBTTagCompound display = tagCompound.getCompoundTag("display");
+ NBTTagList lore = display.getTagList("Lore", 8);
+ for (String s : moreLore) {
+ lore.appendTag(new NBTTagString(s));
+ }
+ display.setTag("Lore", lore);
+ tagCompound.setTag("display", display);
+ is.setTagCompound(tagCompound);
+ }
+
+ public static List<String> getLore(ItemStack is) {
+ return getLore(is.getTagCompound());
+ }
+
+ public static List<String> getLore(NBTTagCompound tagCompound) {
+ if (tagCompound == null) {
+ return Collections.emptyList();
+ }
+ NBTTagList tagList = tagCompound.getCompoundTag("display").getTagList("Lore", 8);
+ List<String> list = new ArrayList<>();
+ for (int i = 0; i < tagList.tagCount(); i++) {
+ list.add(tagList.getStringTagAt(i));
+ }
+ return list;
+ }
+
+ public static String getDisplayName(NBTTagCompound compound) {
+ if (compound == null) return null;
+ String string = compound.getCompoundTag("display").getString("Name");
+ if (string == null || string.isEmpty())
+ return null;
+ return string;
+ }
+
+ public static String fixEnchantId(String enchId, boolean useId) {
+ if (Constants.ENCHANTS != null && Constants.ENCHANTS.has("enchant_mapping_id") &&
+ Constants.ENCHANTS.has("enchant_mapping_item")) {
+ JsonArray mappingFrom = Constants.ENCHANTS.getAsJsonArray("enchant_mapping_" + (useId ? "id" : "item"));
+ JsonArray mappingTo = Constants.ENCHANTS.getAsJsonArray("enchant_mapping_" + (useId ? "item" : "id"));
+
+ for (int i = 0; i < mappingFrom.size(); i++) {
+ if (mappingFrom.get(i).getAsString().equals(enchId)) {
+ return mappingTo.get(i).getAsString();
+ }
+ }
+
+ }
+ return enchId;
+ }
+
+ /**
+ * Mutates baseValues
+ */
+ public static <T> void modifyReplacement(
+ Map<String, String> baseValues,
+ Map<String, T> modifiers,
+ BiFunction<String, T, String> mapper
+ ) {
+ if (modifiers == null || baseValues == null) return;
+ for (Map.Entry<String, T> modifier : modifiers.entrySet()) {
+ String baseValue = baseValues.get(modifier.getKey());
+ if (baseValue == null) continue;
+ try {
+ baseValues.put(modifier.getKey(), mapper.apply(baseValue, modifier.getValue()));
+ } catch (Exception e) {
+ System.out.println("Exception during replacement mapping: ");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static String applyReplacements(Map<String, String> replacements, String text) {
+ for (Map.Entry<String, String> replacement : replacements.entrySet()) {
+ String search = "{" + replacement.getKey() + "}";
+ text = text.replace(search, replacement.getValue());
+ }
+ return text;
+ }
+
+ public static ItemStack createPetItemstackFromPetInfo(PetInfoOverlay.Pet currentPet) {
+ String petname = currentPet.petType;
+ String tier = Utils.getRarityFromInt(currentPet.rarity.petId).toUpperCase();
+ String heldItem = currentPet.petItem;
+ String skin = currentPet.skin;
+ JsonObject heldItemJson = heldItem == null ? null : NotEnoughUpdates.INSTANCE.manager.getItemInformation().get(
+ heldItem);
+ String petId = currentPet.getPetId(false);
+ float exp = currentPet.petLevel.totalXp;
+
+ GuiProfileViewer.PetLevel levelObj = GuiProfileViewer.getPetLevel(petname, tier, exp);
+
+ float level = levelObj.level;
+
+ ItemStack petItemstack = NotEnoughUpdates.INSTANCE.manager
+ .createItemResolutionQuery()
+ .withKnownInternalName(petId)
+ .resolveToItemStack(false);
+ if (petItemstack == null) {
+ petItemstack = ItemUtils.createQuestionMarkSkull(EnumChatFormatting.RED + "Unknown Pet");
+ appendLore(petItemstack, Arrays.asList(
+ "§cThis pet is not saved in the repository",
+ "",
+ "§cIf you expected it to be there please send a message in",
+ "§c§l#neu-support §r§con §ldiscord.gg/moulberry"
+ ));
+ }
+ Map<String, String> replacements = NotEnoughUpdates.INSTANCE.manager.getPetLoreReplacements(
+ petname,
+ tier,
+ MathHelper.floor_float(level)
+ );
+
+ if (heldItem != null) {
+ modifyReplacement(replacements, GuiProfileViewer.PET_STAT_BOOSTS.get(heldItem), (original, modifier) ->
+ "" + MathHelper.floor_float(Float.parseFloat(original) + modifier));
+ modifyReplacement(replacements, GuiProfileViewer.PET_STAT_BOOSTS_MULT.get(heldItem), (original, modifier) ->
+ "" + MathHelper.floor_float(Float.parseFloat(original) * modifier));
+ }
+
+ NBTTagCompound tag = getOrCreateTag(petItemstack);
+ if (tag.hasKey("display", 10)) {
+ NBTTagCompound displayTag = tag.getCompoundTag("display");
+ if (displayTag.hasKey("Lore", 9)) {
+ List<String> newLore = new ArrayList<>();
+ NBTTagList lore = displayTag.getTagList("Lore", 8);
+ int secondLastBlankLine = -1, lastBlankLine = -1;
+ for (int j = 0; j < lore.tagCount(); j++) {
+ String line = lore.getStringTagAt(j);
+ if (line.trim().isEmpty()) {
+ secondLastBlankLine = lastBlankLine;
+ lastBlankLine = j;
+ }
+ line = applyReplacements(replacements, line);
+ newLore.add(line);
+ }
+ if (skin != null) {
+ JsonObject petSkin = NotEnoughUpdates.INSTANCE.manager
+ .createItemResolutionQuery()
+ .withKnownInternalName("PET_SKIN_" + skin)
+ .resolveToItemListJson();
+ if (petSkin != null) {
+ try {
+ NBTTagCompound nbt = JsonToNBT.getTagFromJson(petSkin.get("nbttag").getAsString());
+ tag.setTag("SkullOwner", nbt.getTag("SkullOwner"));
+ String name = petSkin.get("displayname").getAsString();
+ if (name != null) {
+ name = Utils.cleanColour(name);
+ newLore.set(0, newLore.get(0) + ", " + name);
+ }
+ } catch (NBTException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ for (int i = 0; i < newLore.size(); i++) {
+ String cleaned = Utils.cleanColour(newLore.get(i));
+ if (cleaned.equals("Right-click to add this pet to")) {
+ newLore.remove(i + 1);
+ newLore.remove(i);
+ secondLastBlankLine = i - 1;
+ break;
+ }
+ }
+ if (secondLastBlankLine != -1) {
+ List<String> petItemLore = new ArrayList<>();
+ if (heldItem != null) {
+ petItemLore.add(EnumChatFormatting.GOLD + "Held Item: " + heldItemJson.get("displayname").getAsString());
+ List<String> heldItemLore = JsonUtils.getJsonArrayOrEmpty(heldItemJson, "lore", JsonElement::getAsString);
+ int blanks = 0;
+ for (String heldItemLoreLine : heldItemLore) {
+ if (heldItemLoreLine.trim().isEmpty()) {
+ blanks++;
+ } else if (blanks == 2) {
+ petItemLore.add(heldItemLoreLine);
+ } else if (blanks > 2) {
+ break;
+ }
+ }
+ }
+ if (currentPet.candyUsed > 0) {
+ if (petItemLore.size() > 0) {
+ petItemLore.add("");
+ }
+ petItemLore.add("§a(" + currentPet.candyUsed + "/10) Pet Candy Used");
+ }
+ newLore.addAll(secondLastBlankLine + 1, petItemLore);
+ }
+ NBTTagList temp = new NBTTagList();
+ for (String loreLine : newLore) {
+ temp.appendTag(new NBTTagString(loreLine));
+ }
+ displayTag.setTag("Lore", temp);
+ }
+
+ if (displayTag.hasKey("Name", 8)) {
+ String displayName = displayTag.getString("Name");
+ displayName = applyReplacements(replacements, displayName);
+ displayTag.setTag("Name", new NBTTagString(displayName));
+ }
+ tag.setTag("display", displayTag);
+ }
+
+ // Adds the missing pet fields to the tag
+ NBTTagCompound extraAttributes = new NBTTagCompound();
+ JsonObject petInfo = new JsonObject();
+ if (tag.hasKey("ExtraAttributes", 10)) {
+ extraAttributes = tag.getCompoundTag("ExtraAttributes");
+ if (extraAttributes.hasKey("petInfo", 8)) {
+ petInfo = new JsonParser().parse(extraAttributes.getString("petInfo")).getAsJsonObject();
+ }
+ }
+ petInfo.addProperty("exp", exp);
+ petInfo.addProperty("tier", tier);
+ petInfo.addProperty("type", petname);
+ if (heldItem != null) {
+ petInfo.addProperty("heldItem", heldItem);
+ }
+ if (skin != null) {
+ petInfo.addProperty("skin", skin);
+ }
+ extraAttributes.setString("petInfo", petInfo.toString());
+ tag.setTag("ExtraAttributes", extraAttributes);
+ petItemstack.setTagCompound(tag);
+ return petItemstack;
+ }
+
+ private static final DecimalFormat decimalFormatter = new DecimalFormat("#,###,###.###");
+
+ public static ItemStack petToolTipXPExtendPetOverlay(ItemStack stack) {
+ NBTTagCompound tag = stack.getTagCompound() == null ? new NBTTagCompound() : stack.getTagCompound();
+ if (tag.hasKey("display", 10)) {
+ NBTTagCompound display = tag.getCompoundTag("display");
+ if (display.hasKey("Lore", 9)) {
+ NBTTagList lore = display.getTagList("Lore", 8);
+ if (Utils.cleanColour(lore.getStringTagAt(0)).matches(ItemTooltipListener.petToolTipRegex) &&
+ lore.tagCount() > 7) {
+
+ GuiProfileViewer.PetLevel petLevel;
+
+ PetInfoOverlay.Pet pet = PetInfoOverlay.getPetFromStack(
+ stack.getTagCompound()
+ );
+ if (pet == null) return stack;
+ petLevel = pet.petLevel;
+ if (petLevel == null) return stack;
+
+ NBTTagList newLore = new NBTTagList();
+ int maxLvl = 100;
+ if (Constants.PETS != null && Constants.PETS.has("custom_pet_leveling") &&
+ Constants.PETS.getAsJsonObject("custom_pet_leveling").has(pet.petType.toUpperCase()) &&
+ Constants.PETS.getAsJsonObject("custom_pet_leveling").getAsJsonObject(pet.petType.toUpperCase()).has(
+ "max_level")) {
+ maxLvl =
+ Constants.PETS
+ .getAsJsonObject("custom_pet_leveling")
+ .getAsJsonObject(pet.petType.toUpperCase())
+ .get("max_level")
+ .getAsInt();
+ }
+ for (int i = 0; i < lore.tagCount(); i++) {
+ if (i == lore.tagCount() - 2) {
+ newLore.appendTag(new NBTTagString(""));
+ if (petLevel.level >= maxLvl) {
+ newLore.appendTag(new NBTTagString(
+ EnumChatFormatting.AQUA + "" + EnumChatFormatting.BOLD + "MAX LEVEL"));
+ } else {
+ double levelPercent = (Math.round(petLevel.levelPercentage * 1000) / 10.0);
+ newLore.appendTag(new NBTTagString(
+ EnumChatFormatting.GRAY + "Progress to Level " + (int) (petLevel.level + 1) + ": " +
+ EnumChatFormatting.YELLOW + levelPercent + "%"));
+ StringBuilder sb = new StringBuilder();
+
+ for (int j = 0; j < 20; j++) {
+ if (j < (levelPercent / 5)) {
+ sb.append(EnumChatFormatting.DARK_GREEN);
+ } else {
+ sb.append(EnumChatFormatting.WHITE);
+ }
+ sb.append(EnumChatFormatting.BOLD + "" + EnumChatFormatting.STRIKETHROUGH + " ");
+ }
+ newLore.appendTag(new NBTTagString(sb.toString()));
+ newLore.appendTag(new NBTTagString(
+ EnumChatFormatting.GRAY + "EXP: " + EnumChatFormatting.YELLOW +
+ decimalFormatter.format(petLevel.levelXp) +
+ EnumChatFormatting.GOLD + "/" + EnumChatFormatting.YELLOW +
+ decimalFormatter.format(petLevel.currentLevelRequirement)
+ ));
+ }
+ }
+ newLore.appendTag(lore.get(i));
+ }
+ display.setTag("Lore", newLore);
+ tag.setTag("display", display);
+ }
+ }
+ }
+ stack.setTagCompound(tag);
+ return stack;
+ }
+
+ public static boolean isSoulbound(ItemStack item) {
+ return ItemUtils.getLore(item).stream()
+ .anyMatch(line -> line.equals("§8§l* §8Co-op Soulbound §8§l*") ||
+ line.equals("§8§l* Soulbound §8§l*"));
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/IteratorUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/IteratorUtils.java
new file mode 100644
index 00000000..32cd5fad
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/IteratorUtils.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import java.util.Iterator;
+
+public class IteratorUtils {
+
+ public static <T> T getOnlyElement(Iterator<T> it, T defaultValue) {
+ if (!it.hasNext()) return defaultValue;
+ T ret = it.next();
+ if (it.hasNext()) return defaultValue;
+ return ret;
+ }
+
+ public static <T> T getOnlyElement(Iterable<T> it, T defaultValue) {
+ return getOnlyElement(it.iterator(), defaultValue);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java
new file mode 100644
index 00000000..2e2977cc
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/JsonUtils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+public class JsonUtils {
+ public static Stream<JsonElement> getJsonArrayAsStream(JsonArray array) {
+ return StreamSupport.stream(array.spliterator(), false);
+ }
+
+ public static <T> List<T> transformJsonArrayToList(
+ JsonArray array,
+ Function<? super JsonElement, ? extends T> mapper
+ ) {
+ return getJsonArrayAsStream(array).map(mapper).collect(Collectors.toList());
+ }
+
+ public static <T> List<T> getJsonArrayOrEmpty(
+ JsonObject rootObject,
+ String name,
+ Function<? super JsonElement, ? extends T> mapper
+ ) {
+ if (rootObject == null || !rootObject.has(name)) {
+ return Collections.emptyList();
+ }
+ JsonElement jsonElement = rootObject.get(name);
+ if (jsonElement.isJsonArray()) {
+ return transformJsonArrayToList(jsonElement.getAsJsonArray(), mapper);
+ }
+ return Collections.emptyList();
+ }
+
+ public static <T> JsonArray transformListToJsonArray(
+ List<T> things,
+ Function<? super T, ? extends JsonElement> mapper
+ ) {
+ JsonArray array = new JsonArray();
+ for (T t : things) {
+ array.add(mapper.apply(t));
+ }
+ return array;
+ }
+
+ public static <T> Map<String, T> transformJsonObjectToMap(
+ JsonObject object,
+ Function<? super JsonElement, ? extends T> mapper
+ ) {
+ Map<String, T> map = new HashMap<>();
+ for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
+ map.put(entry.getKey(), mapper.apply(entry.getValue()));
+ }
+ return map;
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/LerpingFloat.java b/src/main/java/io/github/moulberry/notenoughupdates/util/LerpingFloat.java
index a034fa8d..e2bfa711 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/LerpingFloat.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/LerpingFloat.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
public class LerpingFloat {
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java b/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java
new file mode 100644
index 00000000..bf973b76
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/MinecraftExecutor.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import net.minecraft.client.Minecraft;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.Executor;
+
+public class MinecraftExecutor implements Executor {
+
+ public static MinecraftExecutor INSTANCE = new MinecraftExecutor();
+
+ private MinecraftExecutor() {}
+
+ @Override
+ public void execute(@NotNull Runnable runnable) {
+ Minecraft.getMinecraft().addScheduledTask(runnable);
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/MoulSigner.java b/src/main/java/io/github/moulberry/notenoughupdates/util/MoulSigner.java
new file mode 100644
index 00000000..6510bc20
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/MoulSigner.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+public class MoulSigner {
+ private MoulSigner() {}
+
+ static PublicKey publicKey;
+
+ static {
+ try (InputStream is = MoulSigner.class.getResourceAsStream("/moulberry.key")) {
+ byte[] publicKeyBytes = IOUtils.toByteArray(is);
+ X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
+ publicKey = KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec);
+ } catch (IOException | NullPointerException | NoSuchAlgorithmException | InvalidKeySpecException e) {
+ NotEnoughUpdates.LOGGER.error("Cannot initialize MoulSigner", e);
+ }
+ }
+
+ public static boolean verifySignature(byte[] data, byte[] signatureBytes) {
+ if (Boolean.getBoolean("neu.noverifysignature")) return true;
+ if (publicKey == null) {
+ NotEnoughUpdates.LOGGER.warn("MoulSigner could not be initialized, will fail this request");
+ return false;
+ }
+ try {
+ Signature signature = Signature.getInstance("SHA256withRSA");
+ signature.initVerify(publicKey);
+ signature.update(data);
+ return signature.verify(signatureBytes);
+ } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
+ NotEnoughUpdates.LOGGER.error("Error while verifying signature. Considering this as invalid signature", e);
+ return false;
+ }
+ }
+
+ public static boolean verifySignature(File file) {
+ try {
+ return verifySignature(
+ IOUtils.toByteArray(file.toURI()),
+ IOUtils.toByteArray(new File(file.getParentFile(), file.getName() + ".asc").toURI())
+ );
+ } catch (IOException e) {
+ NotEnoughUpdates.LOGGER.error("Ran into an IOException while verifying a signature", e);
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java b/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java
new file mode 100644
index 00000000..230b8ae5
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
+
+import java.util.function.Consumer;
+
+public class NEUDebugLogger {
+ private static final Minecraft mc = Minecraft.getMinecraft();
+ public static Consumer<String> logMethod = NEUDebugLogger::chatLogger;
+ // Used to prevent accessing NEUConfig in unit tests
+ public static boolean allFlagsEnabled = false;
+
+ private static void chatLogger(String message) {
+ mc.thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.YELLOW + "[NEU DEBUG] " + message));
+ }
+
+ public static boolean isFlagEnabled(NEUDebugFlag flag) {
+ return NotEnoughUpdates.INSTANCE.config.hidden.debugFlags.contains(flag);
+ }
+
+ public static void log(NEUDebugFlag flag, String message) {
+ if (logMethod != null && (allFlagsEnabled || isFlagEnabled(flag))) {
+ logAlways(message);
+ }
+ }
+
+ public static void logAlways(String message) {
+ if (logMethod != null) {
+ logMethod.accept(message);
+ }
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/NEUResourceManager.java b/src/main/java/io/github/moulberry/notenoughupdates/util/NEUResourceManager.java
index 3ef40567..af681f2d 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/NEUResourceManager.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/NEUResourceManager.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import net.minecraft.client.resources.IResource;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java
new file mode 100644
index 00000000..b09dd839
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/NetUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.file.Files;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+
+public class NetUtils {
+
+ public static CompletableFuture<File> downloadAsync(URL httpURL, File outputFile) {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ try (
+ InputStream from = httpURL.openStream();
+ OutputStream to = Files.newOutputStream(outputFile.toPath());
+ ) {
+ IOUtils.copyLarge(from, to);
+ }
+ return outputFile;
+ } catch (IOException e) {
+ throw new CompletionException(e);
+ }
+ });
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/NotificationHandler.java b/src/main/java/io/github/moulberry/notenoughupdates/util/NotificationHandler.java
new file mode 100644
index 00000000..d373ef2c
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/NotificationHandler.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import io.github.moulberry.notenoughupdates.core.util.render.RenderUtils;
+import io.github.moulberry.notenoughupdates.miscgui.GuiItemRecipe;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.gui.inventory.GuiChest;
+import net.minecraft.client.gui.inventory.GuiContainer;
+import net.minecraft.inventory.ContainerChest;
+
+import java.util.List;
+
+public class NotificationHandler {
+ public static List<String> notificationLines = null;
+ public static boolean showNotificationOverInv = false;
+ public static long notificationDisplayMillis = 0;
+
+ public static void displayNotification(List<String> lines, boolean showForever) {
+ displayNotification(lines, showForever, false);
+ }
+
+ public static void displayNotification(List<String> lines, boolean showForever, boolean overInventory) {
+ if (showForever) {
+ notificationDisplayMillis = -420;
+ } else {
+ notificationDisplayMillis = System.currentTimeMillis();
+ }
+ notificationLines = lines;
+ showNotificationOverInv = overInventory;
+ }
+
+ /**
+ * Stops rendering the notification, if one is displayed
+ */
+ public static void cancelNotification() {
+ notificationDisplayMillis = 0;
+ }
+
+ public static void renderNotification() {
+ long timeRemaining = 15000 - (System.currentTimeMillis() - notificationDisplayMillis);
+ boolean display = timeRemaining > 0 || notificationDisplayMillis == -420;
+ if (display && notificationLines != null && notificationLines.size() > 0) {
+ int width = 0;
+ int height = notificationLines.size() * 10 + 10;
+
+ for (String line : notificationLines) {
+ int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(line) + 8;
+ if (len > width) {
+ width = len;
+ }
+ }
+
+ ScaledResolution sr = Utils.pushGuiScale(2);
+
+ int midX = sr.getScaledWidth() / 2;
+ int topY = sr.getScaledHeight() * 3 / 4 - height / 2;
+ RenderUtils.drawFloatingRectDark(midX - width / 2, sr.getScaledHeight() * 3 / 4 - height / 2, width, height);
+ /*Gui.drawRect(midX-width/2, sr.getScaledHeight()*3/4-height/2,
+ midX+width/2, sr.getScaledHeight()*3/4+height/2, 0xFF3C3C3C);
+ Gui.drawRect(midX-width/2+2, sr.getScaledHeight()*3/4-height/2+2,
+ midX+width/2-2, sr.getScaledHeight()*3/4+height/2-2, 0xFFC8C8C8);*/
+
+ int xLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth("[X] Close");
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ "[X] Close",
+ midX + width / 2f - 3 - xLen,
+ topY + 3,
+ 0xFFFF5555,
+ false
+ );
+
+ if (notificationDisplayMillis > 0) {
+ Minecraft.getMinecraft().fontRendererObj.drawString(
+ (timeRemaining / 1000) + "s",
+ midX - width / 2f + 3,
+ topY + 3,
+ 0xFFaaaaaa,
+ false
+ );
+ }
+
+ Utils.drawStringCentered(
+ notificationLines.get(0),
+ Minecraft.getMinecraft().fontRendererObj,
+ midX,
+ topY + 4 + 5,
+ false,
+ -1
+ );
+ for (int i = 1; i < notificationLines.size(); i++) {
+ String line = notificationLines.get(i);
+ Utils.drawStringCentered(
+ line,
+ Minecraft.getMinecraft().fontRendererObj,
+ midX,
+ topY + 4 + 5 + 2 + i * 10,
+ false,
+ -1
+ );
+ }
+
+ Utils.pushGuiScale(-1);
+ }
+ }
+
+ public static boolean shouldRenderOverlay(Gui gui) {
+ boolean validGui = gui instanceof GuiContainer || gui instanceof GuiItemRecipe;
+ if (gui instanceof GuiChest) {
+ GuiChest eventGui = (GuiChest) gui;
+ ContainerChest cc = (ContainerChest) eventGui.inventorySlots;
+ String containerName = cc.getLowerChestInventory().getDisplayName().getUnformattedText();
+ if (containerName.trim().equals("Fast Travel")) {
+ validGui = false;
+ }
+ }
+ return validGui;
+ }
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java
index 439ad571..b90e8087 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java b/src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java
new file mode 100644
index 00000000..4c0b73eb
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/PronounDB.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+public class PronounDB {
+
+ private static boolean isDisabled() {
+ JsonObject disabled = Constants.DISABLE;
+ return disabled != null && disabled.has("pronoundb");
+ }
+
+ /**
+ * Returns an Optional, since JVMs can be *very* funky with KeyStore loading
+ */
+ public static CompletableFuture<Optional<JsonObject>> performPronouning(String platform, String id) {
+ if (isDisabled()) return CompletableFuture.completedFuture(Optional.empty());
+ return NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .request()
+ .url("https://pronoundb.org/api/v1/lookup")
+ .queryArgument("platform", platform)
+ .queryArgument("id", id)
+ .requestJson()
+ .handle((result, ex) -> Optional.ofNullable(result));
+ }
+
+ public enum Pronoun {
+ HE("he", "him", "his"),
+ IT("it", "it", "its"),
+ SHE("she", "her", "hers"),
+ THEY("they", "them", "theirs");
+
+ private final String subject;
+ private final String object;
+ private final String possessive;
+
+ Pronoun(String subject, String object, String possessive) {
+ this.subject = subject;
+ this.object = object;
+ this.possessive = possessive;
+ }
+
+ public String getSubject() {
+ return subject;
+ }
+
+ public String getObject() {
+ return object;
+ }
+
+ public String getPossessive() {
+ return possessive;
+ }
+ }
+
+ public enum PronounChoice {
+ UNSPECIFIED("unspecified", "Unspecified"),
+ HE("hh", Pronoun.HE),
+ HEIT("hi", Pronoun.HE, Pronoun.IT),
+ HESHE("hs", Pronoun.HE, Pronoun.SHE),
+ HETHEY("ht", Pronoun.HE, Pronoun.THEY),
+ ITHE("ih", Pronoun.IT, Pronoun.HE),
+ IT("ii", Pronoun.IT),
+ ITSHE("is", Pronoun.IT, Pronoun.SHE),
+ ITTHEY("it", Pronoun.IT, Pronoun.THEY),
+ SHEHE("shh", Pronoun.SHE, Pronoun.HE),
+ SHE("sh", Pronoun.SHE),
+ SHEIT("si", Pronoun.SHE, Pronoun.IT),
+ SHETHEY("st", Pronoun.SHE, Pronoun.THEY),
+ THEYHE("th", Pronoun.THEY, Pronoun.HE),
+ THEYIT("ti", Pronoun.THEY, Pronoun.IT),
+ THEYSHE("ts", Pronoun.THEY, Pronoun.SHE),
+ THEY("tt", Pronoun.THEY),
+ ANY("any", "Any pronouns"),
+ OTHER("other", "Other pronouns"),
+ ASK("ask", "Ask me my pronouns"),
+ AVOID("avoid", "Avoid pronouns, use my name");
+ private final String id;
+ private List<Pronoun> pronouns = null;
+ private String override = null;
+
+ PronounChoice(String id, String override) {
+ this.override = override;
+ this.id = id;
+ }
+
+ PronounChoice(String id, Pronoun... pronouns) {
+ this.id = id;
+ this.pronouns = Arrays.asList(pronouns);
+ }
+
+ public static Optional<PronounChoice> findPronounsForId(String id) {
+ for (PronounChoice value : values()) {
+ if (value.id.equals(id)) return Optional.of(value);
+ }
+ return Optional.empty();
+ }
+
+ public String getOverride() {
+ return override;
+ }
+
+ public List<Pronoun> getPronounsInPreferredOrder() {
+ return pronouns;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public List<String> render() {
+ if (override != null)
+ return Arrays.asList(override);
+ return pronouns
+ .stream()
+ .map(pronoun -> pronoun.getSubject() + "/" + pronoun.getObject())
+ .collect(Collectors.toList());
+ }
+
+ public boolean isConsciousChoice() {
+ return this != UNSPECIFIED;
+ }
+
+ }
+
+ public static Optional<PronounChoice> parsePronouns(JsonObject pronounObject) {
+ if (pronounObject.has("pronouns")) {
+ JsonElement pronouns = pronounObject.get("pronouns");
+ if (pronouns.isJsonPrimitive() && pronouns.getAsJsonPrimitive().isString())
+ return PronounChoice.findPronounsForId(pronouns.getAsString());
+ }
+ return Optional.empty();
+ }
+
+ public static CompletableFuture<Optional<PronounChoice>> getPronounsFor(String platform, String name) {
+ return performPronouning(platform, name).thenApply(it -> it.flatMap(PronounDB::parsePronouns));
+ }
+
+ public static CompletableFuture<Optional<PronounChoice>> getPronounsFor(UUID minecraftPlayer) {
+ return getPronounsFor("minecraft", minecraftPlayer.toString() /* dashed UUID */);
+ }
+
+ public static void test() {
+ System.out.println("Pronouning...");
+ getPronounsFor(UUID.fromString("842204e6-6880-487b-ae5a-0595394f9948")).thenAccept(it -> {
+ PronounChoice pronounsFor = it.get();
+ pronounsFor.render().forEach(System.out::println);
+ });
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/RequestFocusListener.java b/src/main/java/io/github/moulberry/notenoughupdates/util/RequestFocusListener.java
index 3df5d9f1..092c8564 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/RequestFocusListener.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/RequestFocusListener.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import javax.swing.*;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ReverseWorldRenderer.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ReverseWorldRenderer.java
index c517bd08..634c94b6 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/ReverseWorldRenderer.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ReverseWorldRenderer.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import com.google.common.primitives.Floats;
@@ -9,10 +28,13 @@ import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.logging.log4j.LogManager;
-import java.nio.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
import java.util.Arrays;
import java.util.BitSet;
-import java.util.Comparator;
@SideOnly(Side.CLIENT)
public class ReverseWorldRenderer {
@@ -564,4 +586,4 @@ public class ReverseWorldRenderer {
return this.stateVertexFormat;
}
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java
index 4bf1d6aa..f3a09fcc 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java
@@ -1,12 +1,31 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import com.google.common.reflect.TypeToken;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import io.github.moulberry.notenoughupdates.listener.ScoreboardLocationChangeListener;
import io.github.moulberry.notenoughupdates.miscfeatures.customblockzones.LocationChangeEvent;
import io.github.moulberry.notenoughupdates.overlays.SlayerOverlay;
import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiChest;
import net.minecraft.client.network.NetworkPlayerInfo;
import net.minecraft.init.Blocks;
@@ -18,6 +37,8 @@ import net.minecraft.scoreboard.Score;
import net.minecraft.scoreboard.ScoreObjective;
import net.minecraft.scoreboard.ScorePlayerTeam;
import net.minecraft.scoreboard.Scoreboard;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import net.minecraftforge.client.event.ClientChatReceivedEvent;
import net.minecraftforge.client.event.GuiOpenEvent;
@@ -34,7 +55,12 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -57,15 +83,23 @@ public class SBInfo {
public String slayer = "";
public boolean stranded = false;
- public String mode = "";
+ public String mode = null;
public Date currentTimeDate = null;
- public String lastOpenContainerName = "";
+ private JsonObject mayorJson = new JsonObject();
+
+ /**
+ * Use Utils.getOpenChestName() instead
+ */
+ @Deprecated
+ public String currentlyOpenChestName = "";
+ public String lastOpenChestName = "";
private long lastManualLocRaw = -1;
private long lastLocRaw = -1;
public long joinedWorld = -1;
+ private long lastMayorUpdate;
public long unloadedWorld = -1;
private JsonObject locraw = null;
public boolean isInDungeon = false;
@@ -96,7 +130,8 @@ public class SBInfo {
private int tickCount = 0;
public String currentProfile = null;
- @SubscribeEvent
+ //Set the priority HIGH to allow other GuiOpenEvent's to use the new currentlyOpenChestName data
+ @SubscribeEvent(priority = EventPriority.HIGH)
public void onGuiOpen(GuiOpenEvent event) {
if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard()) return;
@@ -104,22 +139,32 @@ public class SBInfo {
GuiChest chest = (GuiChest) event.gui;
ContainerChest container = (ContainerChest) chest.inventorySlots;
- lastOpenContainerName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
+ currentlyOpenChestName = container.getLowerChestInventory().getDisplayName().getUnformattedText();
+ lastOpenChestName = currentlyOpenChestName;
+ } else {
+ currentlyOpenChestName = "";
}
}
@SubscribeEvent
public void onGuiTick(TickEvent event) {
if (tickCount++ % 10 != 0) return;
- GuiScreen currentScreen = Minecraft.getMinecraft().currentScreen;
- if (currentScreen instanceof GuiChest) {
- ContainerChest container = (ContainerChest) ((GuiChest) currentScreen).inventorySlots;
- if ("Profile Management".equals(container.getLowerChestInventory().getDisplayName().getUnformattedText())) {
- updateProfileInformation(container);
- }
+ if (Utils.getOpenChestName().equals("Profile Management")) {
+ ContainerChest container = (ContainerChest) ((GuiChest) Minecraft.getMinecraft().currentScreen).inventorySlots;
+ updateProfileInformation(container);
}
}
+ public boolean checkForSkyblockLocation() {
+ if (!NotEnoughUpdates.INSTANCE.hasSkyblockScoreboard() || getLocation() == null) {
+ Minecraft.getMinecraft().thePlayer.addChatMessage(new ChatComponentText(EnumChatFormatting.RED +
+ "[NEU] This command is not available outside SkyBlock"));
+ return false;
+ }
+
+ return true;
+ }
+
private static final Pattern PROFILE_PATTERN =
Pattern.compile("(?<type>(♲ Ironman)|(☀ Stranded)|()) *Profile: (?<name>[^ ]+)");
@@ -189,7 +234,8 @@ public class SBInfo {
locraw = null;
this.setLocation(null);
joinedWorld = System.currentTimeMillis();
- lastOpenContainerName = "";
+ currentlyOpenChestName = "";
+ lastOpenChestName = "";
hasNewTab = false;
}
@@ -254,7 +300,10 @@ public class SBInfo {
lastLocRaw = System.currentTimeMillis();
NotEnoughUpdates.INSTANCE.sendChatMessage("/locraw");
}
-
+ if (currentTime - lastMayorUpdate > 300 * 1000) {
+ updateMayor();
+ lastMayorUpdate = currentTime;
+ }
try {
for (NetworkPlayerInfo info : Minecraft.getMinecraft().thePlayer.sendQueue.getPlayerInfoMap()) {
String name = Minecraft.getMinecraft().ingameGUI.getTabList().getPlayerName(info);
@@ -293,7 +342,7 @@ public class SBInfo {
String cleanLine = Utils.cleanColour(line);
- if (cleanLine.contains("Dungeon") && cleanLine.contains("Cleared:") && cleanLine.contains("%")) {
+ if (cleanLine.contains("Cleared:") && cleanLine.contains("%")) {
tempIsInDungeon = true;
}
@@ -311,6 +360,8 @@ public class SBInfo {
slayer = "Sven";
} else if (line.contains("Voidgloom Seraph")) {
slayer = "Enderman";
+ } else if (line.contains("Inferno Demonlord")) {
+ slayer = "Blaze";
}
if (lines.contains("Slayer Quest") && SlayerOverlay.unloadOverlayTimer == -1 ||
lines.contains("Slayer Quest") && System.currentTimeMillis() - SlayerOverlay.unloadOverlayTimer > 500) {
@@ -353,7 +404,11 @@ public class SBInfo {
//Replaced with for loop because in crystal hollows with events the line it's on can shift.
for (String line : lines) {
if (line.contains("⏣")) {
- location = Utils.cleanColour(line).replaceAll("[^A-Za-z0-9() ]", "").trim();
+ String l = Utils.cleanColour(line).replaceAll("[^A-Za-z0-9() ]", "").trim();
+ if (!l.equals(location)) {
+ new ScoreboardLocationChangeListener(location, l);
+ }
+ location = l;
break;
}
}
@@ -372,4 +427,16 @@ public class SBInfo {
e.printStackTrace();
}
}
+
+ public void updateMayor() {
+ NotEnoughUpdates.INSTANCE.manager.apiUtils
+ .newHypixelApiRequest("resources/skyblock/election")
+ .requestJson()
+ .thenAccept(newJson -> mayorJson = newJson);
+ }
+
+
+ public JsonObject getMayorJson() {
+ return mayorJson;
+ }
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java
new file mode 100644
index 00000000..f0cb5732
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SkytilsCompat.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import net.minecraft.item.ItemStack;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+
+public class SkytilsCompat {
+ // Defer static initialization
+ private static class Holder {
+ // Skytils is present in some capacity
+ static boolean isSkytilsPresent = false;
+ // All classes successfully loaded
+ static boolean isSkytilsFullyPresent = false;
+
+ static Class<?> skytilsClass = null;
+ static Method renderRarityMethod = null;
+ static Class<?> renderUtilClass = null;
+
+ static Object skytilsCompanionObject = null;
+
+ static Class<?> skytilsConfigClass = null;
+
+ static Object skytilsConfigObject = null;
+ static Method skytilsGetShowItemRarity = null;
+
+ static {
+ Exception exception = null;
+ for (String packageStart : Arrays.asList("gg.skytils", "skytils")) {
+ isSkytilsPresent = false;
+ try {
+ skytilsClass = Class.forName(packageStart + ".skytilsmod.Skytils");
+ isSkytilsPresent = true;
+ } catch (ClassNotFoundException ignored) {
+ }
+
+ if (isSkytilsPresent) {
+ try {
+ Class<?> skytilsCompanionClass = Class.forName(packageStart + ".skytilsmod.Skytils$Companion");
+ skytilsConfigClass = Class.forName(packageStart + ".skytilsmod.core.Config");
+ Field skytilsCompanionField = skytilsClass.getField("Companion");
+ skytilsCompanionObject = skytilsCompanionField.get(null);
+ Method skytilsGetConfigMethod = skytilsCompanionClass.getMethod("getConfig");
+ skytilsConfigObject = skytilsGetConfigMethod.invoke(skytilsCompanionObject);
+ skytilsGetShowItemRarity = skytilsConfigClass.getMethod("getShowItemRarity");
+ renderUtilClass = Class.forName(packageStart + ".skytilsmod.utils.RenderUtil");
+ renderRarityMethod = renderUtilClass.getDeclaredMethod(
+ "renderRarity",
+ ItemStack.class,
+ Integer.TYPE,
+ Integer.TYPE
+ );
+ isSkytilsFullyPresent = true;
+ break;
+ } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException |
+ InvocationTargetException e) {
+ exception = e;
+ }
+ }
+ }
+
+ if (!isSkytilsFullyPresent) {
+ if (exception != null) {
+ System.err.println("Failed to get Skytils class even tho Skytils mod is present. This is (probably) a NEU bug");
+ exception.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public static boolean isSkytilsFullyLoaded() {
+ return Holder.isSkytilsFullyPresent;
+ }
+
+ public static boolean isSkytilsPresent() {
+ return Holder.isSkytilsPresent;
+ }
+
+ public static void renderSkytilsRarity(ItemStack stack, int x, int y) {
+ renderSkytilsRarity(stack, x, y, false);
+ }
+
+ public static void renderSkytilsRarity(ItemStack stack, int x, int y, boolean force) {
+ if (Holder.isSkytilsFullyPresent) {
+ try {
+ if (force || (boolean) Holder.skytilsGetShowItemRarity.invoke(Holder.skytilsConfigObject))
+ Holder.renderRarityMethod.invoke(null, stack, x, y);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java
index 27a40565..e3318e3c 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SpecialColour.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import java.awt.*;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java b/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java
index b38db88f..bcce86bb 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/TexLoc.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import org.lwjgl.input.Keyboard;
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
index 9b5f62e3..2267cbea 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/Utils.java
@@ -1,10 +1,34 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonPrimitive;
import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
import io.github.moulberry.notenoughupdates.miscfeatures.SlotLocking;
+import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -30,35 +54,98 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.network.play.client.C0DPacketCloseWindow;
-import net.minecraft.util.*;
+import net.minecraft.util.ChatComponentText;
+import net.minecraft.util.ChatStyle;
+import net.minecraft.util.EnumChatFormatting;
+import net.minecraft.util.Matrix4f;
+import net.minecraft.util.ResourceLocation;
+import net.minecraft.util.StatCollector;
import net.minecraftforge.fml.common.Loader;
import org.lwjgl.BufferUtils;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL14;
-import java.awt.Color;
+import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.math.BigInteger;
import java.nio.FloatBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Utils {
- public static boolean hasEffectOverride = false;
- public static boolean disableCustomDungColours = false;
private static final LinkedList<Integer> guiScales = new LinkedList<>();
- private static ScaledResolution lastScale = new ScaledResolution(Minecraft.getMinecraft());
//Labymod compatibility
private static final FloatBuffer projectionMatrixOld = BufferUtils.createFloatBuffer(16);
private static final FloatBuffer modelviewMatrixOld = BufferUtils.createFloatBuffer(16);
+ private static final EnumChatFormatting[] rainbow = new EnumChatFormatting[]{
+ EnumChatFormatting.RED,
+ EnumChatFormatting.GOLD,
+ EnumChatFormatting.YELLOW,
+ EnumChatFormatting.GREEN,
+ EnumChatFormatting.AQUA,
+ EnumChatFormatting.LIGHT_PURPLE,
+ EnumChatFormatting.DARK_PURPLE
+ };
+ private static final Pattern CHROMA_REPLACE_PATTERN = Pattern.compile("\u00a7z(.+?)(?=\u00a7|$)");
+ private static final char[] c = new char[]{'k', 'm', 'b', 't'};
+ private static final LerpingFloat scrollY = new LerpingFloat(0, 100);
+ public static boolean hasEffectOverride = false;
+ public static boolean disableCustomDungColours = false;
+ public static String[] rarityArr = new String[]{
+ "COMMON",
+ "UNCOMMON",
+ "RARE",
+ "EPIC",
+ "LEGENDARY",
+ "MYTHIC",
+ "SPECIAL",
+ "VERY SPECIAL",
+ "SUPREME",
+ "^^ THAT ONE IS DIVINE ^^"
+//, "DIVINE"
+ };
+ public static String[] rarityArrC = new String[]{
+ EnumChatFormatting.WHITE + EnumChatFormatting.BOLD.toString() + "COMMON",
+ EnumChatFormatting.GREEN + EnumChatFormatting.BOLD.toString() + "UNCOMMON",
+ EnumChatFormatting.BLUE + EnumChatFormatting.BOLD.toString() + "RARE",
+ EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.BOLD.toString() + "EPIC",
+ EnumChatFormatting.GOLD + EnumChatFormatting.BOLD.toString() + "LEGENDARY",
+ EnumChatFormatting.LIGHT_PURPLE + EnumChatFormatting.BOLD.toString() + "MYTHIC",
+ EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "SPECIAL",
+ EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "VERY SPECIAL",
+ EnumChatFormatting.AQUA + EnumChatFormatting.BOLD.toString() + "DIVINE",
+ EnumChatFormatting.AQUA + EnumChatFormatting.BOLD.toString() + "DIVINE",
+ //EnumChatFormatting.AQUA+EnumChatFormatting.BOLD.toString()+"DIVINE",
+ };
+ public static final HashMap<String, String> rarityArrMap = new HashMap<String, String>() {{
+ put("COMMON", rarityArrC[0]);
+ put("UNCOMMON", rarityArrC[1]);
+ put("RARE", rarityArrC[2]);
+ put("EPIC", rarityArrC[3]);
+ put("LEGENDARY", rarityArrC[4]);
+ put("MYTHIC", rarityArrC[5]);
+ put("SPECIAL", rarityArrC[6]);
+ put("VERY SPECIAL", rarityArrC[7]);
+ put("DIVINE", rarityArrC[8]);
+ // put("DIVINE", rarityArrC[9]);
+ }};
+ public static Splitter PATH_SPLITTER = Splitter.on(".").omitEmptyStrings().limit(2);
+ private static ScaledResolution lastScale = new ScaledResolution(Minecraft.getMinecraft());
+ private static long startTime = 0;
public static <T> ArrayList<T> createList(T... values) {
ArrayList<T> list = new ArrayList<>();
@@ -162,8 +249,13 @@ public class Utils {
}
public static void drawItemStackWithText(ItemStack stack, int x, int y, String text) {
- if (stack == null) return;
+ drawItemStackWithText(stack, x, y, text, false);
+ }
+ public static void drawItemStackWithText(ItemStack stack, int x, int y, String text, boolean skytilsRarity) {
+ if (stack == null) return;
+ if (skytilsRarity)
+ SkytilsCompat.renderSkytilsRarity(stack, x, y);
RenderItem itemRender = Minecraft.getMinecraft().getRenderItem();
disableCustomDungColours = true;
@@ -177,27 +269,17 @@ public class Utils {
}
public static void drawItemStack(ItemStack stack, int x, int y) {
- if (stack == null) return;
-
drawItemStackWithText(stack, x, y, null);
}
- private static final EnumChatFormatting[] rainbow = new EnumChatFormatting[]{
- EnumChatFormatting.RED,
- EnumChatFormatting.GOLD,
- EnumChatFormatting.YELLOW,
- EnumChatFormatting.GREEN,
- EnumChatFormatting.AQUA,
- EnumChatFormatting.LIGHT_PURPLE,
- EnumChatFormatting.DARK_PURPLE
- };
+ public static void drawItemStack(ItemStack stack, int x, int y, boolean skytilsRarity) {
+ drawItemStackWithText(stack, x, y, null, skytilsRarity);
+ }
public static String chromaString(String str) {
return chromaString(str, 0, false);
}
- private static final Pattern CHROMA_REPLACE_PATTERN = Pattern.compile("\u00a7z(.+?)(?=\u00a7|$)");
-
public static String chromaStringByColourCode(String str) {
if (str.contains("\u00a7z")) {
Matcher matcher = CHROMA_REPLACE_PATTERN.matcher(str);
@@ -219,8 +301,6 @@ public class Utils {
return str;
}
- private static long startTime = 0;
-
public static String chromaString(String str, float offset, boolean bold) {
str = cleanColour(str);
@@ -247,8 +327,6 @@ public class Utils {
return rainbowText.toString();
}
- private static final char[] c = new char[]{'k', 'm', 'b', 't'};
-
public static String shortNumberFormat(double n, int iteration) {
double d = ((long) n / 100) / 10.0;
boolean isRound = (d * 10) % 10 == 0;
@@ -301,6 +379,40 @@ public class Utils {
return "";
}
+ public static String trimWhitespaceAndFormatCodes(String str) {
+ int startIndex = indexOfFirstNonWhitespaceNonFormatCode(str);
+ int endIndex = lastIndexOfNonWhitespaceNonFormatCode(str);
+ if (startIndex == -1 || endIndex == -1) return "";
+ return str.substring(startIndex, endIndex + 1);
+ }
+
+ private static int indexOfFirstNonWhitespaceNonFormatCode(String str) {
+ int len = str.length();
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+ if (Character.isWhitespace(ch)) {
+ continue;
+ } else if (ch == '\u00a7') {
+ i++;
+ continue;
+ }
+ return i;
+ }
+ return -1;
+ }
+
+ private static int lastIndexOfNonWhitespaceNonFormatCode(String str) {
+ for (int i = str.length() - 1; i >= 0; i--) {
+ char ch = str.charAt(i);
+ if (Character.isWhitespace(ch) || ch == '\u00a7' || (i > 0 && str.charAt(i - 1) == '\u00a7')) {
+ continue;
+ }
+ return i;
+ }
+
+ return -1;
+ }
+
public static List<String> getRawTooltip(ItemStack stack) {
List<String> list = Lists.newArrayList();
String s = stack.getDisplayName();
@@ -477,46 +589,6 @@ public class Utils {
return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
}
- public static String[] rarityArr = new String[]{
- "COMMON",
- "UNCOMMON",
- "RARE",
- "EPIC",
- "LEGENDARY",
- "MYTHIC",
- "SPECIAL",
- "VERY SPECIAL",
- "SUPREME",
- "^^ THAT ONE IS DIVINE ^^"
-//, "DIVINE"
- };
-
- public static String[] rarityArrC = new String[]{
- EnumChatFormatting.WHITE + EnumChatFormatting.BOLD.toString() + "COMMON",
- EnumChatFormatting.GREEN + EnumChatFormatting.BOLD.toString() + "UNCOMMON",
- EnumChatFormatting.BLUE + EnumChatFormatting.BOLD.toString() + "RARE",
- EnumChatFormatting.DARK_PURPLE + EnumChatFormatting.BOLD.toString() + "EPIC",
- EnumChatFormatting.GOLD + EnumChatFormatting.BOLD.toString() + "LEGENDARY",
- EnumChatFormatting.LIGHT_PURPLE + EnumChatFormatting.BOLD.toString() + "MYTHIC",
- EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "SPECIAL",
- EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "VERY SPECIAL",
- EnumChatFormatting.AQUA + EnumChatFormatting.BOLD.toString() + "DIVINE",
- EnumChatFormatting.AQUA + EnumChatFormatting.BOLD.toString() + "DIVINE",
- //EnumChatFormatting.AQUA+EnumChatFormatting.BOLD.toString()+"DIVINE",
- };
- public static final HashMap<String, String> rarityArrMap = new HashMap<String, String>() {{
- put("COMMON", rarityArrC[0]);
- put("UNCOMMON", rarityArrC[1]);
- put("RARE", rarityArrC[2]);
- put("EPIC", rarityArrC[3]);
- put("LEGENDARY", rarityArrC[4]);
- put("MYTHIC", rarityArrC[5]);
- put("SPECIAL", rarityArrC[6]);
- put("VERY SPECIAL", rarityArrC[7]);
- put("DIVINE", rarityArrC[8]);
- // put("DIVINE", rarityArrC[9]);
- }};
-
public static String getRarityFromInt(int rarity) {
if (rarity < 0 || rarity >= rarityArr.length) {
return rarityArr[0];
@@ -598,6 +670,60 @@ public class Utils {
return (float) Math.round(value * scale) / scale;
}
+ public static int roundToNearestInt(double value) {
+ return (int) Math.round(value);
+ }
+
+ // Parses Roman numerals, allowing for single character irregular subtractive notation (e.g. IL is 49, IIL is invalid)
+ public static int parseRomanNumeral(String input) {
+ int prevVal = 0;
+ int total = 0;
+ for (int i = input.length() - 1; i >= 0; i--) {
+ int val;
+ char ch = input.charAt(i);
+ switch (ch) {
+ case 'I':
+ val = 1;
+ break;
+ case 'V':
+ val = 5;
+ break;
+ case 'X':
+ val = 10;
+ break;
+ case 'L':
+ val = 50;
+ break;
+ case 'C':
+ val = 100;
+ break;
+ case 'D':
+ val = 500;
+ break;
+ case 'M':
+ val = 1000;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid Roman Numeral Character: " + ch);
+ }
+ if (val < prevVal) val = -val;
+ total += val;
+ prevVal = val;
+ }
+
+ return total;
+ }
+
+ public static int parseIntOrRomanNumeral(String input) {
+ // 0 through 9, '-', and '+' come before 'A' in ANSI, UTF8, and UTF16 character sets
+ //
+ if (input.charAt(0) < 'A') {
+ return Integer.parseInt(input);
+ }
+
+ return parseRomanNumeral(input);
+ }
+
public static void playPressSound() {
playSound(new ResourceLocation("gui.button.press"), true);
}
@@ -717,11 +843,15 @@ public class Utils {
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
}
- public static ItemStack createItemStack(Item item, String displayname, String... lore) {
- return createItemStack(item, displayname, 0, lore);
+ public static ItemStack createItemStack(Item item, String displayName, String... lore) {
+ return createItemStack(item, displayName, 0, lore);
+ }
+
+ public static ItemStack createItemStack(Block item, String displayName, String... lore) {
+ return createItemStack(Item.getItemFromBlock(item), displayName, lore);
}
- public static ItemStack createItemStack(Item item, String displayname, int damage, String... lore) {
+ public static ItemStack createItemStack(Item item, String displayName, int damage, String... lore) {
ItemStack stack = new ItemStack(item, 1, damage);
NBTTagCompound tag = new NBTTagCompound();
NBTTagCompound display = new NBTTagCompound();
@@ -731,7 +861,7 @@ public class Utils {
Lore.appendTag(new NBTTagString(line));
}
- display.setString("Name", displayname);
+ display.setString("Name", displayName);
display.setTag("Lore", Lore);
tag.setTag("display", display);
@@ -749,6 +879,8 @@ public class Utils {
String... lore
) {
NBTTagCompound tag = itemStack.getTagCompound();
+ if (tag == null)
+ tag = new NBTTagCompound();
NBTTagCompound display = tag.getCompoundTag("display");
NBTTagList Lore = new NBTTagList();
@@ -1253,8 +1385,6 @@ public class Utils {
return prim.getAsString();
}
- public static Splitter PATH_SPLITTER = Splitter.on(".").omitEmptyStrings().limit(2);
-
public static JsonElement getElement(JsonElement element, String path) {
List<String> path_split = PATH_SPLITTER.splitToList(path);
if (element instanceof JsonObject) {
@@ -1269,6 +1399,11 @@ public class Utils {
}
}
+ public static JsonElement getElementOrDefault(JsonElement element, String path, JsonElement def) {
+ JsonElement result = getElement(element, path);
+ return result != null ? result : def;
+ }
+
public static ChatStyle createClickStyle(ClickEvent.Action action, String value) {
ChatStyle style = new ChatStyle();
style.setChatClickEvent(new ClickEvent(action, value));
@@ -1294,12 +1429,12 @@ public class Utils {
file.delete();
}
- public static char getPrimaryColourCode(String displayname) {
+ public static char getPrimaryColourCode(String displayName) {
int lastColourCode = -99;
int currentColour = 0;
int[] mostCommon = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- for (int i = 0; i < displayname.length(); i++) {
- char c = displayname.charAt(i);
+ for (int i = 0; i < displayName.length(); i++) {
+ char c = displayName.charAt(i);
if (c == '\u00A7') {
lastColourCode = i;
} else if (lastColourCode == i - 1) {
@@ -1326,8 +1461,8 @@ public class Utils {
return "0123456789abcdef".charAt(currentColour);
}
- public static Color getPrimaryColour(String displayname) {
- int colourInt = Minecraft.getMinecraft().fontRendererObj.getColorCode(getPrimaryColourCode(displayname));
+ public static Color getPrimaryColour(String displayName) {
+ int colourInt = Minecraft.getMinecraft().fontRendererObj.getColorCode(getPrimaryColourCode(displayName));
return new Color(colourInt).darker();
}
@@ -1336,8 +1471,6 @@ public class Utils {
scrollY.resetTimer();
}
- private static final LerpingFloat scrollY = new LerpingFloat(0, 100);
-
public static void drawHoveringText(
List<String> textLines,
final int mouseX,
@@ -1761,7 +1894,109 @@ public class Utils {
}
public static boolean isWithinRect(int x, int y, int left, int top, int width, int height) {
- return left <= x && x <= left + width &&
- top <= y && y <= top + height;
+ return left <= x && x < left + width &&
+ top <= y && y < top + height;
+ }
+
+ public static int getNumberOfStars(ItemStack stack) {
+ if (stack != null && stack.hasTagCompound()) {
+ NBTTagCompound tag = stack.getTagCompound();
+
+ if (tag.hasKey("ExtraAttributes", 10)) {
+ NBTTagCompound ea = tag.getCompoundTag("ExtraAttributes");
+ if (ea.hasKey("upgrade_level", 99)) {
+ return ea.getInteger("upgrade_level");
+ } else if (ea.hasKey("dungeon_item_level")) {
+ return ea.getInteger("dungeon_item_level");
+ }
+ }
+ }
+ return -1;
+ }
+
+ public static String getStarsString(int stars) {
+ EnumChatFormatting colorCode = null;
+ EnumChatFormatting defaultColorCode = EnumChatFormatting.GOLD;
+ int amount = 0;
+ if (stars > 5 && stars < 11) {
+ colorCode = EnumChatFormatting.LIGHT_PURPLE;
+ amount = stars - 5;
+ stars = 5;
+ }
+ if (stars > 10) {
+ colorCode = EnumChatFormatting.AQUA;
+ defaultColorCode = EnumChatFormatting.LIGHT_PURPLE;
+ amount = stars - 10;
+ stars = 5;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ for (int i = 0; i < stars; i++) {
+ if (i < amount) {
+ stringBuilder.append(colorCode).append('\u272A');
+ } else {
+ stringBuilder.append(defaultColorCode).append('\u272A');
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ public static void showOutdatedRepoNotification() {
+ if (NotEnoughUpdates.INSTANCE.config.notifications.outdatedRepo) {
+ NotificationHandler.displayNotification(Lists.newArrayList(
+ EnumChatFormatting.RED + EnumChatFormatting.BOLD.toString() + "Missing repo data",
+ EnumChatFormatting.RED +
+ "Data used for many NEU features is not up to date, this should normally not be the case.",
+ EnumChatFormatting.RED + "You can try " + EnumChatFormatting.BOLD + "/neuresetrepo" + EnumChatFormatting.RESET +
+ EnumChatFormatting.RED + " and restart your game" +
+ " to see if that fixes the issue.",
+ EnumChatFormatting.RED + "If the problem persists please join " + EnumChatFormatting.BOLD +
+ "discord.gg/moulberry" +
+ EnumChatFormatting.RESET + EnumChatFormatting.RED + " and message in " + EnumChatFormatting.BOLD +
+ "#neu-support" + EnumChatFormatting.RESET + EnumChatFormatting.RED + " to get support"
+ ),
+ true, true
+ );
+ }
+ }
+
+ /**
+ * Finds the rarity from the lore of an item.
+ * -1 = UNKNOWN
+ * 0 = COMMON
+ * 1 = UNCOMMON
+ * 2 = RARE
+ * 3 = EPIC
+ * 4 = LEGENDARY
+ * 5 = MYTHIC
+ * 6 = SPECIAL
+ * 7 = VERY SPECIAL
+ */
+ public static int getRarityFromLore(JsonArray lore) {
+ for (int i = lore.size() - 1; i >= 0; i--) {
+ String line = lore.get(i).getAsString();
+
+ for (int j = 0; j < rarityArrC.length; j++) {
+ if (line.startsWith(rarityArrC[j])) {
+ return j;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public static UUID parseDashlessUUID(String dashlessUuid) {
+ // From: https://stackoverflow.com/a/30760478/
+ BigInteger most = new BigInteger(dashlessUuid.substring(0, 16), 16);
+ BigInteger least = new BigInteger(dashlessUuid.substring(16, 32), 16);
+ return new UUID(most.longValue(), least.longValue());
+ }
+
+ public static String getOpenChestName() {
+ return SBInfo.getInstance().currentlyOpenChestName;
+ }
+
+ public static String getLastOpenChestName() {
+ return SBInfo.getInstance().lastOpenChestName;
}
}
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java b/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java
index aef2490e..81eea343 100644
--- a/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/XPInformation.java
@@ -1,8 +1,26 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
package io.github.moulberry.notenoughupdates.util;
import com.google.common.base.Splitter;
import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.moulberry.notenoughupdates.core.util.StringUtils;
import io.github.moulberry.notenoughupdates.profileviewer.ProfileViewer;
@@ -12,11 +30,9 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
public class XPInformation {
private static final XPInformation INSTANCE = new XPInformation();
@@ -171,6 +187,7 @@ public class XPInformation {
skillInfo.currentXp += updateWithPercentage.get(skill) / 100f * cap;
skillInfo.totalXp += skillInfo.currentXp;
skillInfo.currentXpMax = cap;
+ break;
} else {
skillInfo.totalXp += cap;
}
@@ -212,15 +229,16 @@ public class XPInformation {
};
private void onApiUpdated(ProfileViewer.Profile profile) {
- JsonObject skillInfo = profile.getSkillInfo(null);
+ Map<String, ProfileViewer.Level> skyblockInfo = profile.getSkyblockInfo(null);
for (String skill : skills) {
SkillInfo info = new SkillInfo();
- float level = skillInfo.get("level_skill_" + skill).getAsFloat();
+ ProfileViewer.Level levelInfo = skyblockInfo.get(skill);
+ float level = levelInfo.level;
- info.totalXp = skillInfo.get("experience_skill_" + skill).getAsFloat();
- info.currentXpMax = skillInfo.get("maxxp_skill_" + skill).getAsFloat();
+ info.totalXp = levelInfo.totalXp;
+ info.currentXpMax = levelInfo.maxXpForLevel;
info.level = (int) level;
info.currentXp = (level % 1) * info.currentXpMax;
info.fromApi = true;
@@ -228,29 +246,4 @@ public class XPInformation {
skillInfoMap.put(skill.toLowerCase(), info);
}
}
-
- public double getPetLevel(String petId, double exp, String rarity) {
- Stream<JsonElement> pet_levels =
- StreamSupport.stream(Constants.PETS.get("pet_levels").getAsJsonArray().spliterator(), false);
- int pet_rarity_offset = Constants.PETS.getAsJsonObject("pet_rarity_offset").get(rarity).getAsInt();
- JsonObject custom_pet_leveling = Constants.PETS.getAsJsonObject("custom_pet_leveling").getAsJsonObject(petId);
- List<Integer> xpLevelsRequired =
- pet_levels.skip(pet_rarity_offset).limit(100).map(JsonElement::getAsInt).collect(Collectors.toList());
- if (custom_pet_leveling != null && custom_pet_leveling.get("type").getAsInt() == 1)
- xpLevelsRequired.addAll(StreamSupport
- .stream(custom_pet_leveling.getAsJsonArray("pet_levels").spliterator(), false)
- .map(JsonElement::getAsInt)
- .collect(Collectors.toList()));
- double remainingExp = exp;
- for (int i = 0; i < xpLevelsRequired.size(); i++) {
- int xpForCurrentLevel = xpLevelsRequired.get(i);
- if (remainingExp >= xpForCurrentLevel) {
- remainingExp -= xpForCurrentLevel;
- } else {
- return i + 1 + remainingExp / xpForCurrentLevel;
- }
- }
- return xpLevelsRequired.size();
- }
-
}
diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml
new file mode 100644
index 00000000..412917d1
--- /dev/null
+++ b/src/main/resources/META-INF/mods.toml
@@ -0,0 +1,14 @@
+# This mods.toml is loaded by forge 1.13-1.19 and is only here to make forge display an error message
+modLoader = "javafml"
+loaderVersion = "[12,)"
+license = "LGPL"
+
+[[mods]]
+modId="notenoughupdateserrordisplay"
+version="${version}"
+displayName="NotEnoughUpdates (1.8.9)"
+description='''
+This mod description is only here to warn you about using the wrong version of Minecraft and Forge.
+'''
+
+
diff --git a/src/main/resources/assets/notenoughupdates/auc_search/master_star.png b/src/main/resources/assets/notenoughupdates/auc_search/master_star.png
new file mode 100644
index 00000000..210ecf49
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/auc_search/master_star.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/auc_search/star_board.png b/src/main/resources/assets/notenoughupdates/auc_search/star_board.png
index 8251731f..0a42884d 100644
--- a/src/main/resources/assets/notenoughupdates/auc_search/star_board.png
+++ b/src/main/resources/assets/notenoughupdates/auc_search/star_board.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/auction_profit.png b/src/main/resources/assets/notenoughupdates/auction_profit.png
new file mode 100644
index 00000000..80e06c10
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/auction_profit.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/button20x.png b/src/main/resources/assets/notenoughupdates/button20x.png
deleted file mode 100644
index 8d723798..00000000
--- a/src/main/resources/assets/notenoughupdates/button20x.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/capes/dg.png b/src/main/resources/assets/notenoughupdates/capes/dg.png
index 8625fbfc..47d3d1e0 100644
--- a/src/main/resources/assets/notenoughupdates/capes/dg.png
+++ b/src/main/resources/assets/notenoughupdates/capes/dg.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/capes/dg_preview.png b/src/main/resources/assets/notenoughupdates/capes/dg_preview.png
index 0ef73797..2e68d99d 100644
--- a/src/main/resources/assets/notenoughupdates/capes/dg_preview.png
+++ b/src/main/resources/assets/notenoughupdates/capes/dg_preview.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/capes/screensaver.png b/src/main/resources/assets/notenoughupdates/capes/screensaver.png
new file mode 100644
index 00000000..c6ce9e8c
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/capes/screensaver.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/capes/screensaver_preview.png b/src/main/resources/assets/notenoughupdates/capes/screensaver_preview.png
new file mode 100644
index 00000000..a7d890f8
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/capes/screensaver_preview.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/dream.json b/src/main/resources/assets/notenoughupdates/dream.json
new file mode 100644
index 00000000..9dda86c6
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/dream.json
@@ -0,0 +1,49 @@
+{
+ "entity": "Player",
+ "modifiers": [
+ {
+ "type": "playerdata",
+ "skin": "notenoughupdates:dreamskin.png"
+ },
+ {
+ "type": "riding",
+ "entity": "ArmorStand",
+ "modifiers": [
+ {
+ "type": "age",
+ "baby": true
+ },
+ {
+ "type": "riding",
+ "entity": "Zombie",
+ "modifiers": [
+ {
+ "type": "equipment",
+ "hand": "BOW",
+ "feet": "DIAMOND_BOOTS"
+ },
+ {
+ "type": "age",
+ "baby": true
+ },
+ {
+ "type": "riding",
+ "entity": "Sheep",
+ "modifiers": [
+ {
+ "type": "age",
+ "baby": true
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "type": "equipment",
+ "hand": "DIAMOND_SWORD",
+ "feet": "DIAMOND_BOOTS"
+ }
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/1.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/10.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/11.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/2.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/3.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/4.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/5.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/6.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/7.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json
index b2625fc5..b21bf2b8 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/8.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.21
-} \ No newline at end of file
+ "radiusSq": 0.21
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/large/9.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/1.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/10.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/11.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/2.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/3.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/4.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/5.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/6.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/7.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json
index 8c12699d..42f0d5e6 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/8.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.22
-} \ No newline at end of file
+ "radiusSq": 0.22
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/medium/9.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/1.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/10.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/11.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/2.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/3.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/4.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json
index 23e86d67..860548cf 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/5.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.25
-} \ No newline at end of file
+ "radiusSq": 0.25
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/6.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/7.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json
index 8c12699d..42f0d5e6 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/8.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 0.22
-} \ No newline at end of file
+ "radiusSq": 0.22
+}
diff --git a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json
index 9576ae4f..69245cb7 100644
--- a/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json
+++ b/src/main/resources/assets/notenoughupdates/dungeon_map/borders/small/9.json
@@ -1,3 +1,3 @@
{
- "radiusSq": 1
-} \ No newline at end of file
+ "radiusSq": 1
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-1.json
index 5b97e666..981f0029 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-1.json
@@ -1 +1,8 @@
-{"8:7":true,"9:7":true,"9:1":true,"7:8":true,"2:0":true,"8:3":true} \ No newline at end of file
+{
+ "8:7": true,
+ "9:7": true,
+ "9:1": true,
+ "7:8": true,
+ "2:0": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-2.json
index ec49e91c..05e5c008 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-2.json
@@ -1 +1,16 @@
-{"12:11":189,"14:9":true,"15:7":true,"9:15":true,"13:10":188,"10:10":185,"7:13":184,"15:8":true,"14:8":true,"8:12":184,"1:14":true,"14:10":189,"13:11":189,"4:12":true} \ No newline at end of file
+{
+ "12:11": 189,
+ "14:9": true,
+ "15:7": true,
+ "9:15": true,
+ "13:10": 188,
+ "10:10": 185,
+ "7:13": 184,
+ "15:8": true,
+ "14:8": true,
+ "8:12": 184,
+ "1:14": true,
+ "14:10": 189,
+ "13:11": 189,
+ "4:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-3.json
index 70660f8d..1763c9aa 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-3.json
@@ -1 +1,14 @@
-{"1:5":true,"0:6":true,"0:4":true,"1:6":[177,178],"1:4":true,"0:7":[177,179]} \ No newline at end of file
+{
+ "1:5": true,
+ "0:6": true,
+ "0:4": true,
+ "1:6": [
+ 177,
+ 178
+ ],
+ "1:4": true,
+ "0:7": [
+ 177,
+ 179
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-4.json
index 16206a50..1956eeb5 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-4.json
@@ -1 +1,36 @@
-{"6:0":true,"1:11":[199,201],"10:4":true,"10:3":true,"7:2":true,"2:9":true,"10:2":true,"0:10":[199,217],"3:12":199,"2:8":true,"7:0":true,"6:2":true,"2:11":true,"15:4":true,"2:12":[169,200],"15:3":true,"6:1":true,"15:2":true,"2:14":[169,172],"15:13":true,"2:10":true,"7:1":true} \ No newline at end of file
+{
+ "6:0": true,
+ "1:11": [
+ 199,
+ 201
+ ],
+ "10:4": true,
+ "10:3": true,
+ "7:2": true,
+ "2:9": true,
+ "10:2": true,
+ "0:10": [
+ 199,
+ 217
+ ],
+ "3:12": 199,
+ "2:8": true,
+ "7:0": true,
+ "6:2": true,
+ "2:11": true,
+ "15:4": true,
+ "2:12": [
+ 169,
+ 200
+ ],
+ "15:3": true,
+ "6:1": true,
+ "15:2": true,
+ "2:14": [
+ 169,
+ 172
+ ],
+ "15:13": true,
+ "2:10": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-5.json
index 897faaee..7f1786f9 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-5.json
@@ -1 +1,12 @@
-{"7:15":true,"6:13":true,"7:13":231,"6:14":true,"6:12":true,"6:15":true,"8:15":true,"7:0":true,"8:0":true,"5:13":true} \ No newline at end of file
+{
+ "7:15": true,
+ "6:13": true,
+ "7:13": 231,
+ "6:14": true,
+ "6:12": true,
+ "6:15": true,
+ "8:15": true,
+ "7:0": true,
+ "8:0": true,
+ "5:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-6.json
index ef35b97d..99a4c6e4 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-6.json
@@ -1 +1,31 @@
-{"12:1":200,"11:5":true,"12:5":true,"11:1":200,"10:12":true,"11:8":true,"12:8":true,"10:10":true,"4:1":true,"11:9":true,"10:0":true,"9:10":true,"5:1":true,"3:2":200,"11:7":true,"12:7":true,"11:0":201,"12:6":true,"10:9":true,"12:0":201,"9:9":true,"13:1":true,"4:2":200,"11:4":true,"9:11":true,"10:5":true,"5:0":true,"10:11":true,"8:15":true} \ No newline at end of file
+{
+ "12:1": 200,
+ "11:5": true,
+ "12:5": true,
+ "11:1": 200,
+ "10:12": true,
+ "11:8": true,
+ "12:8": true,
+ "10:10": true,
+ "4:1": true,
+ "11:9": true,
+ "10:0": true,
+ "9:10": true,
+ "5:1": true,
+ "3:2": 200,
+ "11:7": true,
+ "12:7": true,
+ "11:0": 201,
+ "12:6": true,
+ "10:9": true,
+ "12:0": 201,
+ "9:9": true,
+ "13:1": true,
+ "4:2": 200,
+ "11:4": true,
+ "9:11": true,
+ "10:5": true,
+ "5:0": true,
+ "10:11": true,
+ "8:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-7.json
index d23b3f4b..8c286333 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_-7.json
@@ -1 +1,7 @@
-{"11:15":[202,203],"10:15":true} \ No newline at end of file
+{
+ "11:15": [
+ 202,
+ 203
+ ],
+ "10:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_0.json
index 99a12616..a794f893 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_0.json
@@ -1 +1,27 @@
-{"14:14":true,"4:14":true,"3:13":true,"13:13":true,"10:14":true,"0:13":true,"15:14":true,"11:13":true,"12:13":true,"2:14":true,"1:13":true,"12:14":true,"2:13":true,"1:14":true,"7:13":true,"11:14":true,"15:13":true,"13:14":true,"10:13":true,"5:13":true,"0:14":true,"3:14":true,"14:13":true,"9:13":true,"4:13":true} \ No newline at end of file
+{
+ "14:14": true,
+ "4:14": true,
+ "3:13": true,
+ "13:13": true,
+ "10:14": true,
+ "0:13": true,
+ "15:14": true,
+ "11:13": true,
+ "12:13": true,
+ "2:14": true,
+ "1:13": true,
+ "12:14": true,
+ "2:13": true,
+ "1:14": true,
+ "7:13": true,
+ "11:14": true,
+ "15:13": true,
+ "13:14": true,
+ "10:13": true,
+ "5:13": true,
+ "0:14": true,
+ "3:14": true,
+ "14:13": true,
+ "9:13": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_3.json
index 857daba9..8d8fb9d1 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_3.json
@@ -1 +1,101 @@
-{"9:14":true,"2:7":[171,194],"8:8":true,"7:12":[174,176],"10:14":true,"11:11":true,"10:12":true,"6:13":175,"2:9":true,"9:15":184,"9:12":true,"3:6":170,"10:15":true,"7:14":176,"8:7":true,"5:5":true,"7:13":175,"2:8":[192,194],"9:10":true,"4:5":true,"6:14":true,"10:13":true,"8:9":true,"7:10":172,"6:12":176,"1:7":171,"9:13":true,"8:13":174,"2:12":true,"7:7":true,"9:9":true,"8:10":171,"7:9":172,"3:5":true,"0:11":true,"9:7":true,"2:14":true,"7:8":true,"8:12":173,"4:6":true,"2:13":true,"5:6":true,"6:7":true,"8:14":175,"9:8":true,"3:13":true,"1:5":171,"0:13":true,"6:6":true,"8:5":true,"5:7":true,"8:11":172,"4:7":171,"9:6":true,"3:12":true,"0:15":true,"0:12":true,"2:5":[171,192],"0:14":true,"3:14":true,"7:6":true,"4:14":true,"1:6":170,"11:10":true,"6:5":true,"5:14":true,"11:13":true,"5:12":176,"8:6":true,"4:12":true,"3:7":171,"9:11":[173,190],"10:11":true,"11:14":true,"11:12":true,"5:13":true,"7:5":true,"11:15":true,"7:11":173,"4:13":true,"2:6":[170,193]} \ No newline at end of file
+{
+ "9:14": true,
+ "2:7": [
+ 171,
+ 194
+ ],
+ "8:8": true,
+ "7:12": [
+ 174,
+ 176
+ ],
+ "10:14": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": 175,
+ "2:9": true,
+ "9:15": 184,
+ "9:12": true,
+ "3:6": 170,
+ "10:15": true,
+ "7:14": 176,
+ "8:7": true,
+ "5:5": true,
+ "7:13": 175,
+ "2:8": [
+ 192,
+ 194
+ ],
+ "9:10": true,
+ "4:5": true,
+ "6:14": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": 172,
+ "6:12": 176,
+ "1:7": 171,
+ "9:13": true,
+ "8:13": 174,
+ "2:12": true,
+ "7:7": true,
+ "9:9": true,
+ "8:10": 171,
+ "7:9": 172,
+ "3:5": true,
+ "0:11": true,
+ "9:7": true,
+ "2:14": true,
+ "7:8": true,
+ "8:12": 173,
+ "4:6": true,
+ "2:13": true,
+ "5:6": true,
+ "6:7": true,
+ "8:14": 175,
+ "9:8": true,
+ "3:13": true,
+ "1:5": 171,
+ "0:13": true,
+ "6:6": true,
+ "8:5": true,
+ "5:7": true,
+ "8:11": 172,
+ "4:7": 171,
+ "9:6": true,
+ "3:12": true,
+ "0:15": true,
+ "0:12": true,
+ "2:5": [
+ 171,
+ 192
+ ],
+ "0:14": true,
+ "3:14": true,
+ "7:6": true,
+ "4:14": true,
+ "1:6": 170,
+ "11:10": true,
+ "6:5": true,
+ "5:14": true,
+ "11:13": true,
+ "5:12": 176,
+ "8:6": true,
+ "4:12": true,
+ "3:7": 171,
+ "9:11": [
+ 173,
+ 190
+ ],
+ "10:11": true,
+ "11:14": true,
+ "11:12": true,
+ "5:13": true,
+ "7:5": true,
+ "11:15": true,
+ "7:11": 173,
+ "4:13": true,
+ "2:6": [
+ 170,
+ 193
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_4.json
index 31878b3e..39157aec 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_4.json
@@ -1 +1,95 @@
-{"1:1":true,"11:5":true,"3:0":true,"0:6":true,"0:0":true,"8:1":171,"3:6":true,"5:5":true,"0:2":true,"4:5":true,"3:2":true,"3:4":true,"0:3":true,"3:3":true,"0:4":true,"2:1":true,"11:0":true,"4:3":true,"5:4":true,"5:3":true,"6:1":true,"4:4":true,"3:5":true,"4:2":true,"0:11":true,"5:2":true,"0:5":true,"11:4":true,"9:1":[171,187],"4:6":true,"5:0":true,"10:1":true,"5:6":true,"11:3":true,"4:0":true,"11:2":true,"7:1":true,"9:3":171,"6:0":true,"10:4":true,"10:3":true,"1:5":true,"7:2":true,"6:6":true,"11:1":true,"9:4":171,"8:5":true,"7:4":true,"9:2":171,"10:2":true,"0:10":true,"7:3":true,"9:6":true,"4:1":true,"6:4":true,"10:0":true,"5:1":true,"9:0":[171,185],"6:3":true,"7:0":171,"2:5":true,"6:2":true,"7:6":true,"1:6":true,"6:5":true,"2:2":true,"0:8":true,"1:0":true,"2:4":true,"8:0":171,"0:1":true,"8:6":true,"3:1":true,"2:3":true,"10:5":true,"1:3":true,"9:5":true,"8:2":171,"1:4":true,"0:7":true,"2:0":true,"8:4":true,"1:2":true,"7:5":true,"8:3":true,"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "1:1": true,
+ "11:5": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "8:1": 171,
+ "3:6": true,
+ "5:5": true,
+ "0:2": true,
+ "4:5": true,
+ "3:2": true,
+ "3:4": true,
+ "0:3": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": true,
+ "11:0": true,
+ "4:3": true,
+ "5:4": true,
+ "5:3": true,
+ "6:1": true,
+ "4:4": true,
+ "3:5": true,
+ "4:2": true,
+ "0:11": true,
+ "5:2": true,
+ "0:5": true,
+ "11:4": true,
+ "9:1": [
+ 171,
+ 187
+ ],
+ "4:6": true,
+ "5:0": true,
+ "10:1": true,
+ "5:6": true,
+ "11:3": true,
+ "4:0": true,
+ "11:2": true,
+ "7:1": true,
+ "9:3": 171,
+ "6:0": true,
+ "10:4": true,
+ "10:3": true,
+ "1:5": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": 171,
+ "8:5": true,
+ "7:4": true,
+ "9:2": 171,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "9:6": true,
+ "4:1": true,
+ "6:4": true,
+ "10:0": true,
+ "5:1": true,
+ "9:0": [
+ 171,
+ 185
+ ],
+ "6:3": true,
+ "7:0": 171,
+ "2:5": true,
+ "6:2": true,
+ "7:6": true,
+ "1:6": true,
+ "6:5": true,
+ "2:2": true,
+ "0:8": true,
+ "1:0": true,
+ "2:4": true,
+ "8:0": 171,
+ "0:1": true,
+ "8:6": true,
+ "3:1": true,
+ "2:3": true,
+ "10:5": true,
+ "1:3": true,
+ "9:5": true,
+ "8:2": 171,
+ "1:4": true,
+ "0:7": true,
+ "2:0": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "8:3": true,
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_6.json
index 35cdf158..7520ac2c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_6.json
@@ -1 +1,219 @@
-{"8:8":true,"6:10":true,"13:13":true,"3:0":true,"3:6":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"13:14":true,"3:4":true,"8:9":true,"7:10":true,"3:3":true,"0:4":true,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"7:7":true,"5:3":true,"2:15":true,"15:14":true,"9:9":true,"4:4":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"13:1":[152,153],"4:2":true,"15:15":true,"14:12":true,"9:7":true,"5:2":true,"2:14":true,"1:13":true,"0:5":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"4:0":true,"15:13":true,"1:15":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"3:13":true,"1:5":true,"0:13":true,"13:0":true,"14:11":true,"4:1":true,"3:12":true,"0:15":true,"5:1":true,"3:15":true,"0:12":true,"15:11":true,"2:5":true,"0:14":true,"3:14":true,"4:14":true,"1:6":true,"5:14":[159,175],"2:2":true,"5:12":true,"2:4":true,"13:11":true,"4:15":162,"4:12":[162,164],"3:1":true,"5:15":[160,161],"2:3":true,"15:0":[150,151],"1:3":true,"1:4":true,"14:0":true,"2:0":true,"2:6":true,"12:11":true,"9:14":true,"2:7":true,"7:12":true,"10:14":true,"7:15":[165,202],"11:11":true,"10:12":true,"2:9":true,"9:12":true,"8:1":true,"10:15":true,"1:8":true,"7:13":true,"2:8":true,"6:14":[165,173],"10:13":true,"6:12":true,"1:7":true,"6:15":[157,159],"9:13":true,"11:0":true,"8:13":true,"1:10":true,"12:0":true,"6:1":true,"11:4":155,"9:1":true,"8:12":true,"10:1":true,"11:3":[154,156],"12:2":[154,156],"11:2":157,"7:1":true,"12:1":[154,156],"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":156,"7:2":true,"6:6":true,"4:9":true,"11:1":157,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"7:3":true,"9:6":true,"6:4":true,"10:0":true,"10:6":true,"9:0":true,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"6:5":true,"3:8":true,"6:11":true,"11:13":true,"8:0":true,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": true,
+ "3:6": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "13:14": true,
+ "3:4": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": [
+ 152,
+ 153
+ ],
+ "4:2": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "5:2": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "13:0": true,
+ "14:11": true,
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "2:5": true,
+ "0:14": true,
+ "3:14": true,
+ "4:14": true,
+ "1:6": true,
+ "5:14": [
+ 159,
+ 175
+ ],
+ "2:2": true,
+ "5:12": true,
+ "2:4": true,
+ "13:11": true,
+ "4:15": 162,
+ "4:12": [
+ 162,
+ 164
+ ],
+ "3:1": true,
+ "5:15": [
+ 160,
+ 161
+ ],
+ "2:3": true,
+ "15:0": [
+ 150,
+ 151
+ ],
+ "1:3": true,
+ "1:4": true,
+ "14:0": true,
+ "2:0": true,
+ "2:6": true,
+ "12:11": true,
+ "9:14": true,
+ "2:7": true,
+ "7:12": true,
+ "10:14": true,
+ "7:15": [
+ 165,
+ 202
+ ],
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "9:12": true,
+ "8:1": true,
+ "10:15": true,
+ "1:8": true,
+ "7:13": true,
+ "2:8": true,
+ "6:14": [
+ 165,
+ 173
+ ],
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": [
+ 157,
+ 159
+ ],
+ "9:13": true,
+ "11:0": true,
+ "8:13": true,
+ "1:10": true,
+ "12:0": true,
+ "6:1": true,
+ "11:4": 155,
+ "9:1": true,
+ "8:12": true,
+ "10:1": true,
+ "11:3": [
+ 154,
+ 156
+ ],
+ "12:2": [
+ 154,
+ 156
+ ],
+ "11:2": 157,
+ "7:1": true,
+ "12:1": [
+ 154,
+ 156
+ ],
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": 156,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": 157,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "3:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": true,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_7.json
index 5bfc81a7..a9da93d7 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_7.json
@@ -1 +1,244 @@
-{"1:1":true,"6:10":true,"13:13":true,"3:0":true,"0:6":true,"0:0":true,"3:6":true,"14:1":true,"13:15":true,"10:10":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"2:1":true,"14:14":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"15:14":true,"9:9":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":true,"0:5":true,"7:8":true,"4:6":true,"5:0":true,"5:6":true,"4:0":true,"15:13":true,"10:8":true,"6:7":true,"9:8":true,"14:13":true,"1:11":true,"1:5":true,"11:8":true,"13:6":true,"13:0":true,"12:8":true,"14:11":true,"4:1":true,"3:12":true,"11:9":true,"15:5":true,"14:5":true,"5:1":true,"15:11":true,"12:9":true,"11:7":true,"2:5":true,"13:4":true,"12:7":true,"2:11":true,"15:4":true,"14:3":true,"1:6":true,"11:10":true,"12:10":true,"2:2":true,"15:3":true,"1:0":true,"14:4":true,"5:12":true,"2:4":true,"14:2":true,"13:11":true,"0:1":true,"15:2":true,"4:12":true,"3:1":true,"13:5":true,"15:0":true,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"14:0":true,"2:0":true,"5:13":true,"1:2":true,"4:13":171,"2:6":true,"15:9":true,"12:11":true,"9:14":true,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"10:14":true,"7:15":[158,170],"14:9":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":[155,157],"13:10":true,"10:15":true,"7:14":true,"1:8":true,"7:13":true,"2:8":true,"6:14":[157,158],"1:9":true,"15:8":true,"10:13":true,"6:12":true,"1:7":true,"14:8":true,"9:13":true,"11:0":true,"12:6":true,"8:13":true,"13:8":true,"12:0":true,"6:1":true,"12:3":true,"11:4":true,"9:1":[162,202],"15:10":true,"14:10":true,"13:7":true,"12:4":true,"11:3":[172,202],"8:15":true,"2:10":true,"11:2":[180,195],"8:14":true,"13:9":true,"7:1":true,"12:1":[148,151],"9:3":true,"6:0":true,"10:4":true,"10:3":true,"7:2":true,"6:6":true,"4:9":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"4:7":true,"10:2":[162,202],"0:10":true,"7:3":true,"6:4":true,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"6:5":true,"3:8":true,"0:8":true,"6:11":true,"11:13":true,"8:0":[162,202],"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"0:7":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"8:3":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "2:1": true,
+ "14:14": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "0:5": true,
+ "7:8": true,
+ "4:6": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": true,
+ "10:8": true,
+ "6:7": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "1:5": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "4:1": true,
+ "3:12": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "15:11": true,
+ "12:9": true,
+ "11:7": true,
+ "2:5": true,
+ "13:4": true,
+ "12:7": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "2:2": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "0:1": true,
+ "15:2": true,
+ "4:12": true,
+ "3:1": true,
+ "13:5": true,
+ "15:0": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "5:13": true,
+ "1:2": true,
+ "4:13": 171,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": [
+ 158,
+ 170
+ ],
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": [
+ 155,
+ 157
+ ],
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "7:13": true,
+ "2:8": true,
+ "6:14": [
+ 157,
+ 158
+ ],
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "14:8": true,
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": [
+ 162,
+ 202
+ ],
+ "15:10": true,
+ "14:10": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": [
+ 172,
+ 202
+ ],
+ "8:15": true,
+ "2:10": true,
+ "11:2": [
+ 180,
+ 195
+ ],
+ "8:14": true,
+ "13:9": true,
+ "7:1": true,
+ "12:1": [
+ 148,
+ 151
+ ],
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": [
+ 162,
+ 202
+ ],
+ "0:10": true,
+ "7:3": true,
+ "6:4": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": [
+ 162,
+ 202
+ ],
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_8.json
index d6f006c3..d419dc47 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-10_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-10_8.json
@@ -1 +1,89 @@
-{"15:9":true,"12:11":true,"11:5":true,"13:13":true,"12:5":true,"14:9":true,"15:7":true,"14:7":true,"14:1":true,"13:15":true,"10:10":true,"13:12":true,"15:1":true,"15:8":true,"14:8":true,"11:0":true,"14:14":true,"12:6":true,"10:9":true,"13:8":true,"15:14":true,"12:0":true,"11:6":true,"10:7":true,"15:12":true,"14:15":true,"13:1":true,"15:15":true,"14:12":true,"9:7":151,"12:3":true,"11:4":true,"9:1":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"15:13":true,"12:2":true,"10:8":true,"11:2":true,"13:9":true,"14:13":true,"12:1":true,"10:3":true,"11:1":true,"11:8":true,"13:6":true,"13:0":true,"10:2":true,"12:8":true,"14:11":true,"13:2":true,"9:6":151,"11:9":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"15:11":true,"12:9":true,"9:0":true,"13:3":true,"11:7":true,"13:4":true,"15:4":true,"14:3":true,"11:10":true,"12:10":true,"15:3":true,"14:4":true,"8:0":[158,170],"14:2":true,"13:11":true,"15:2":true,"13:5":true,"15:0":true,"14:6":true,"15:6":true,"14:0":true,"12:15":true,"12:12":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "11:5": true,
+ "13:13": true,
+ "12:5": true,
+ "14:9": true,
+ "15:7": true,
+ "14:7": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "13:12": true,
+ "15:1": true,
+ "15:8": true,
+ "14:8": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": true,
+ "10:9": true,
+ "13:8": true,
+ "15:14": true,
+ "12:0": true,
+ "11:6": true,
+ "10:7": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": 151,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "15:13": true,
+ "12:2": true,
+ "10:8": true,
+ "11:2": true,
+ "13:9": true,
+ "14:13": true,
+ "12:1": true,
+ "10:3": true,
+ "11:1": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "10:2": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "9:6": 151,
+ "11:9": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "15:11": true,
+ "12:9": true,
+ "9:0": true,
+ "13:3": true,
+ "11:7": true,
+ "13:4": true,
+ "15:4": true,
+ "14:3": true,
+ "11:10": true,
+ "12:10": true,
+ "15:3": true,
+ "14:4": true,
+ "8:0": [
+ 158,
+ 170
+ ],
+ "14:2": true,
+ "13:11": true,
+ "15:2": true,
+ "13:5": true,
+ "15:0": true,
+ "14:6": true,
+ "15:6": true,
+ "14:0": true,
+ "12:15": true,
+ "12:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-3.json
index 352ead0c..ed4788e9 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-3.json
@@ -1 +1,188 @@
-{"12:11":true,"9:14":true,"11:5":true,"2:7":true,"8:8":true,"7:12":true,"6:10":true,"12:5":true,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"9:15":true,"0:6":true,"14:7":true,"9:12":true,"3:6":true,"13:10":true,"10:15":true,"7:14":true,"1:8":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"7:13":true,"2:8":true,"5:11":true,"4:5":true,"13:12":true,"6:14":true,"1:9":true,"15:8":true,"10:13":true,"3:4":true,"6:12":true,"3:3":true,"1:7":true,"6:15":true,"9:13":true,"12:6":true,"4:3":true,"8:13":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"1:10":true,"13:8":true,"11:6":true,"4:4":true,"10:7":true,"6:8":true,"3:5":true,"13:1":181,"0:11":true,"9:7":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"12:3":true,"11:4":true,"8:12":true,"6:9":true,"4:6":true,"2:13":true,"14:10":true,"10:1":179,"5:6":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"12:2":true,"2:10":true,"1:15":true,"10:8":true,"11:2":true,"8:14":true,"1:12":true,"13:9":true,"9:8":true,"12:1":[180,181],"9:3":true,"10:4":true,"3:13":true,"5:9":true,"10:3":true,"1:5":true,"0:13":true,"7:2":true,"6:6":true,"4:9":true,"11:1":180,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"11:8":true,"7:4":true,"13:6":true,"9:2":true,"4:7":true,"10:2":true,"0:10":true,"12:8":true,"7:3":true,"14:11":true,"13:2":true,"9:6":true,"3:12":true,"0:15":true,"11:9":true,"6:4":true,"14:5":true,"10:6":true,"3:15":true,"12:9":true,"6:3":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"5:8":true,"13:4":true,"12:7":true,"3:14":true,"6:2":true,"7:6":true,"4:8":true,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"11:10":true,"6:5":true,"3:8":true,"12:10":true,"5:14":true,"0:8":true,"15:3":true,"6:11":true,"14:4":true,"11:13":true,"5:12":true,"2:4":true,"14:2":true,"13:11":true,"4:15":true,"15:2":true,"8:6":true,"4:12":true,"13:5":true,"12:13":true,"5:15":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"0:7":true,"11:12":true,"8:4":true,"5:13":true,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"8:3":true,"0:9":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "9:15": true,
+ "0:6": true,
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "7:13": true,
+ "2:8": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "3:4": true,
+ "6:12": true,
+ "3:3": true,
+ "1:7": true,
+ "6:15": true,
+ "9:13": true,
+ "12:6": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "1:10": true,
+ "13:8": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "6:8": true,
+ "3:5": true,
+ "13:1": 181,
+ "0:11": true,
+ "9:7": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "12:3": true,
+ "11:4": true,
+ "8:12": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "14:10": true,
+ "10:1": 179,
+ "5:6": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": true,
+ "2:10": true,
+ "1:15": true,
+ "10:8": true,
+ "11:2": true,
+ "8:14": true,
+ "1:12": true,
+ "13:9": true,
+ "9:8": true,
+ "12:1": [
+ 180,
+ 181
+ ],
+ "9:3": true,
+ "10:4": true,
+ "3:13": true,
+ "5:9": true,
+ "10:3": true,
+ "1:5": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": 180,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "12:8": true,
+ "7:3": true,
+ "14:11": true,
+ "13:2": true,
+ "9:6": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "6:4": true,
+ "14:5": true,
+ "10:6": true,
+ "3:15": true,
+ "12:9": true,
+ "6:3": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "13:4": true,
+ "12:7": true,
+ "3:14": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "6:5": true,
+ "3:8": true,
+ "12:10": true,
+ "5:14": true,
+ "0:8": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "11:13": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "15:2": true,
+ "8:6": true,
+ "4:12": true,
+ "13:5": true,
+ "12:13": true,
+ "5:15": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "11:12": true,
+ "8:4": true,
+ "5:13": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-4.json
index 643d735d..3988841a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-4.json
@@ -1 +1,20 @@
-{"15:9":true,"12:6":true,"14:9":true,"11:6":true,"11:8":199,"15:7":true,"13:6":true,"14:7":true,"12:8":true,"10:5":true,"15:10":[199,217],"10:6":true,"13:7":true,"12:7":true,"13:9":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:6": true,
+ "14:9": true,
+ "11:6": true,
+ "11:8": 199,
+ "15:7": true,
+ "13:6": true,
+ "14:7": true,
+ "12:8": true,
+ "10:5": true,
+ "15:10": [
+ 199,
+ 217
+ ],
+ "10:6": true,
+ "13:7": true,
+ "12:7": true,
+ "13:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-5.json
index b7fc8ac8..3de191fa 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-5.json
@@ -1 +1,25 @@
-{"10:4":true,"12:5":true,"7:15":true,"9:4":true,"5:12":213,"4:12":[211,212],"7:14":true,"11:4":true,"10:5":true,"10:6":true,"12:4":true,"6:14":[214,216],"5:13":[211,216],"6:15":215} \ No newline at end of file
+{
+ "10:4": true,
+ "12:5": true,
+ "7:15": true,
+ "9:4": true,
+ "5:12": 213,
+ "4:12": [
+ 211,
+ 212
+ ],
+ "7:14": true,
+ "11:4": true,
+ "10:5": true,
+ "10:6": true,
+ "12:4": true,
+ "6:14": [
+ 214,
+ 216
+ ],
+ "5:13": [
+ 211,
+ 216
+ ],
+ "6:15": 215
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-6.json
index e79a0352..84cd9a00 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_-6.json
@@ -1 +1,11 @@
-{"12:6":[203,205],"8:13":[213,214],"8:12":212} \ No newline at end of file
+{
+ "12:6": [
+ 203,
+ 205
+ ],
+ "8:13": [
+ 213,
+ 214
+ ],
+ "8:12": 212
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_2.json
index 4d8c42a8..99a82999 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_2.json
@@ -1 +1,23 @@
-{"11:10":161,"13:13":159,"11:11":[160,161],"11:8":156,"9:2":true,"12:13":[160,161],"9:1":true,"11:9":167,"10:0":true,"10:1":true,"9:0":true,"12:12":[159,161]} \ No newline at end of file
+{
+ "11:10": 161,
+ "13:13": 159,
+ "11:11": [
+ 160,
+ 161
+ ],
+ "11:8": 156,
+ "9:2": true,
+ "12:13": [
+ 160,
+ 161
+ ],
+ "9:1": true,
+ "11:9": 167,
+ "10:0": true,
+ "10:1": true,
+ "9:0": true,
+ "12:12": [
+ 159,
+ 161
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_5.json
index b605be36..31bc4325 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_5.json
@@ -1 +1,29 @@
-{"12:1":true,"9:14":[164,165],"11:5":true,"12:5":true,"7:15":true,"11:1":true,"14:1":true,"15:5":true,"14:5":true,"15:1":true,"10:13":[163,165],"6:15":true,"11:13":true,"13:1":true,"13:5":true,"10:5":true,"9:5":true,"8:15":166,"11:12":true,"8:14":true,"7:1":175} \ No newline at end of file
+{
+ "12:1": true,
+ "9:14": [
+ 164,
+ 165
+ ],
+ "11:5": true,
+ "12:5": true,
+ "7:15": true,
+ "11:1": true,
+ "14:1": true,
+ "15:5": true,
+ "14:5": true,
+ "15:1": true,
+ "10:13": [
+ 163,
+ 165
+ ],
+ "6:15": true,
+ "11:13": true,
+ "13:1": true,
+ "13:5": true,
+ "10:5": true,
+ "9:5": true,
+ "8:15": 166,
+ "11:12": true,
+ "8:14": true,
+ "7:1": 175
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_6.json
index 22ad94f8..dd61311b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_6.json
@@ -1 +1,85 @@
-{"12:11":true,"8:8":true,"13:13":true,"11:11":true,"10:12":true,"13:15":true,"10:10":true,"8:7":true,"5:5":167,"9:10":true,"4:5":true,"13:12":true,"13:14":true,"8:9":true,"7:10":true,"14:14":true,"5:4":true,"7:7":true,"5:3":true,"15:14":true,"9:9":true,"6:1":true,"4:4":true,"8:10":true,"7:9":true,"6:8":true,"15:12":true,"14:15":true,"15:15":true,"14:12":true,"5:2":true,"7:8":true,"6:9":[163,166],"4:6":true,"5:6":[166,167],"15:13":true,"6:7":true,"9:8":true,"7:1":true,"14:13":true,"6:0":true,"7:2":true,"6:6":true,"5:7":[165,166],"7:4":true,"9:2":true,"8:11":165,"4:7":true,"7:3":true,"14:11":true,"6:4":true,"6:3":true,"7:0":true,"5:8":[163,165],"6:2":true,"7:6":true,"11:10":true,"6:5":true,"12:10":true,"11:13":true,"13:11":true,"12:13":true,"12:14":true,"9:11":true,"10:11":true,"8:2":true,"11:12":true,"8:4":true,"7:5":true,"12:12":true,"8:3":true} \ No newline at end of file
+{
+ "12:11": true,
+ "8:8": true,
+ "13:13": true,
+ "11:11": true,
+ "10:12": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": 167,
+ "9:10": true,
+ "4:5": true,
+ "13:12": true,
+ "13:14": true,
+ "8:9": true,
+ "7:10": true,
+ "14:14": true,
+ "5:4": true,
+ "7:7": true,
+ "5:3": true,
+ "15:14": true,
+ "9:9": true,
+ "6:1": true,
+ "4:4": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "15:12": true,
+ "14:15": true,
+ "15:15": true,
+ "14:12": true,
+ "5:2": true,
+ "7:8": true,
+ "6:9": [
+ 163,
+ 166
+ ],
+ "4:6": true,
+ "5:6": [
+ 166,
+ 167
+ ],
+ "15:13": true,
+ "6:7": true,
+ "9:8": true,
+ "7:1": true,
+ "14:13": true,
+ "6:0": true,
+ "7:2": true,
+ "6:6": true,
+ "5:7": [
+ 165,
+ 166
+ ],
+ "7:4": true,
+ "9:2": true,
+ "8:11": 165,
+ "4:7": true,
+ "7:3": true,
+ "14:11": true,
+ "6:4": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": [
+ 163,
+ 165
+ ],
+ "6:2": true,
+ "7:6": true,
+ "11:10": true,
+ "6:5": true,
+ "12:10": true,
+ "11:13": true,
+ "13:11": true,
+ "12:13": true,
+ "12:14": true,
+ "9:11": true,
+ "10:11": true,
+ "8:2": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "12:12": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_7.json
index 6b724e4e..feb2ef05 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-11_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-11_7.json
@@ -1 +1,15 @@
-{"15:9":true,"14:9":true,"15:7":true,"13:6":true,"14:7":true,"13:5":true,"15:0":true,"14:6":true,"15:5":true,"15:6":true,"14:0":true,"15:8":true,"14:8":true} \ No newline at end of file
+{
+ "15:9": true,
+ "14:9": true,
+ "15:7": true,
+ "13:6": true,
+ "14:7": true,
+ "13:5": true,
+ "15:0": true,
+ "14:6": true,
+ "15:5": true,
+ "15:6": true,
+ "14:0": true,
+ "15:8": true,
+ "14:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_0.json
index 2734cb56..bd0f39ea 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_0.json
@@ -1 +1,58 @@
-{"12:1":true,"9:3":true,"1:11":true,"11:5":true,"10:4":true,"12:5":true,"10:3":true,"11:1":true,"15:7":true,"13:6":true,"9:2":true,"13:0":true,"14:7":true,"8:1":true,"10:2":true,"14:1":true,"13:2":true,"15:5":true,"10:0":true,"14:5":true,"15:1":true,"9:0":true,"7:0":true,"13:3":true,"0:14":145,"13:4":true,"15:4":true,"11:0":true,"14:3":true,"12:6":true,"2:12":true,"15:3":true,"12:0":true,"14:4":true,"8:0":true,"14:2":true,"13:1":true,"0:11":true,"15:2":true,"13:5":true,"15:0":true,"14:6":true,"12:3":true,"11:4":true,"9:1":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"8:2":true,"15:6":true,"14:0":true,"12:2":true,"11:2":true,"1:12":true,"7:1":true} \ No newline at end of file
+{
+ "12:1": true,
+ "9:3": true,
+ "1:11": true,
+ "11:5": true,
+ "10:4": true,
+ "12:5": true,
+ "10:3": true,
+ "11:1": true,
+ "15:7": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "14:7": true,
+ "8:1": true,
+ "10:2": true,
+ "14:1": true,
+ "13:2": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "15:1": true,
+ "9:0": true,
+ "7:0": true,
+ "13:3": true,
+ "0:14": 145,
+ "13:4": true,
+ "15:4": true,
+ "11:0": true,
+ "14:3": true,
+ "12:6": true,
+ "2:12": true,
+ "15:3": true,
+ "12:0": true,
+ "14:4": true,
+ "8:0": true,
+ "14:2": true,
+ "13:1": true,
+ "0:11": true,
+ "15:2": true,
+ "13:5": true,
+ "15:0": true,
+ "14:6": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:2": true,
+ "15:6": true,
+ "14:0": true,
+ "12:2": true,
+ "11:2": true,
+ "1:12": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_1.json
index a52bf506..7f7300c1 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_1.json
@@ -1 +1,66 @@
-{"1:1":146,"10:10":true,"9:10":true,"3:2":146,"2:1":145,"4:3":145,"2:12":[143,144],"2:15":161,"9:9":true,"4:2":145,"15:15":true,"5:2":145,"2:14":136,"1:13":[137,139],"2:13":142,"1:14":136,"5:0":[167,169],"4:0":[168,169],"1:12":[140,146],"6:0":[166,167],"3:13":[143,146],"0:13":137,"4:1":145,"0:12":[143,147],"5:14":[144,145],"2:2":146,"3:1":145,"12:13":true,"12:14":true,"9:11":true,"11:14":true,"1:2":true,"11:15":true,"4:13":[144,146]} \ No newline at end of file
+{
+ "1:1": 146,
+ "10:10": true,
+ "9:10": true,
+ "3:2": 146,
+ "2:1": 145,
+ "4:3": 145,
+ "2:12": [
+ 143,
+ 144
+ ],
+ "2:15": 161,
+ "9:9": true,
+ "4:2": 145,
+ "15:15": true,
+ "5:2": 145,
+ "2:14": 136,
+ "1:13": [
+ 137,
+ 139
+ ],
+ "2:13": 142,
+ "1:14": 136,
+ "5:0": [
+ 167,
+ 169
+ ],
+ "4:0": [
+ 168,
+ 169
+ ],
+ "1:12": [
+ 140,
+ 146
+ ],
+ "6:0": [
+ 166,
+ 167
+ ],
+ "3:13": [
+ 143,
+ 146
+ ],
+ "0:13": 137,
+ "4:1": 145,
+ "0:12": [
+ 143,
+ 147
+ ],
+ "5:14": [
+ 144,
+ 145
+ ],
+ "2:2": 146,
+ "3:1": 145,
+ "12:13": true,
+ "12:14": true,
+ "9:11": true,
+ "11:14": true,
+ "1:2": true,
+ "11:15": true,
+ "4:13": [
+ 144,
+ 146
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_10.json
index aa6db439..3c099835 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_10.json
@@ -1 +1,51 @@
-{"11:5":true,"14:1":true,"13:15":true,"1:7":127,"11:0":true,"5:3":127,"15:14":true,"12:0":true,"4:4":127,"3:5":127,"14:15":true,"13:1":true,"15:15":true,"12:3":true,"11:4":true,"2:13":true,"5:0":207,"14:10":true,"12:4":true,"11:3":true,"4:0":127,"11:2":true,"13:9":true,"12:1":true,"6:0":207,"10:4":true,"10:3":true,"13:0":true,"10:2":true,"12:8":true,"7:3":true,"13:2":true,"10:6":true,"5:1":127,"3:15":true,"15:11":true,"11:7":127,"3:14":true,"6:2":127,"15:4":127,"14:3":true,"0:8":127,"15:3":127,"14:2":true,"15:2":127,"9:5":true,"14:0":127,"8:4":true,"2:6":127} \ No newline at end of file
+{
+ "11:5": true,
+ "14:1": true,
+ "13:15": true,
+ "1:7": 127,
+ "11:0": true,
+ "5:3": 127,
+ "15:14": true,
+ "12:0": true,
+ "4:4": 127,
+ "3:5": 127,
+ "14:15": true,
+ "13:1": true,
+ "15:15": true,
+ "12:3": true,
+ "11:4": true,
+ "2:13": true,
+ "5:0": 207,
+ "14:10": true,
+ "12:4": true,
+ "11:3": true,
+ "4:0": 127,
+ "11:2": true,
+ "13:9": true,
+ "12:1": true,
+ "6:0": 207,
+ "10:4": true,
+ "10:3": true,
+ "13:0": true,
+ "10:2": true,
+ "12:8": true,
+ "7:3": true,
+ "13:2": true,
+ "10:6": true,
+ "5:1": 127,
+ "3:15": true,
+ "15:11": true,
+ "11:7": 127,
+ "3:14": true,
+ "6:2": 127,
+ "15:4": 127,
+ "14:3": true,
+ "0:8": 127,
+ "15:3": 127,
+ "14:2": true,
+ "15:2": 127,
+ "9:5": true,
+ "14:0": 127,
+ "8:4": true,
+ "2:6": 127
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_11.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_11.json
index d3691eee..bac1f70b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_11.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_11.json
@@ -1 +1,67 @@
-{"12:1":true,"1:1":true,"11:5":true,"10:4":true,"2:7":115,"12:5":true,"11:1":true,"3:0":true,"13:0":true,"8:1":true,"3:6":true,"14:1":true,"13:2":true,"8:7":true,"9:6":true,"4:1":true,"0:2":true,"14:5":true,"10:6":true,"5:1":true,"4:5":true,"15:1":true,"13:3":true,"3:4":true,"2:5":true,"13:4":true,"3:3":true,"2:1":true,"15:4":true,"14:3":true,"12:6":true,"7:7":true,"2:2":true,"15:3":true,"6:1":true,"14:4":true,"11:6":true,"4:4":true,"10:7":true,"3:5":true,"2:4":true,"14:2":true,"13:1":true,"0:1":true,"9:7":true,"3:1":true,"13:5":true,"2:3":true,"12:3":true,"11:4":true,"10:5":true,"15:0":true,"9:1":true,"4:6":true,"3:7":true,"1:3":true,"10:1":true,"9:5":true,"12:4":true,"14:0":true,"2:0":true,"12:2":true,"1:2":true,"6:7":true,"7:1":true} \ No newline at end of file
+{
+ "12:1": true,
+ "1:1": true,
+ "11:5": true,
+ "10:4": true,
+ "2:7": 115,
+ "12:5": true,
+ "11:1": true,
+ "3:0": true,
+ "13:0": true,
+ "8:1": true,
+ "3:6": true,
+ "14:1": true,
+ "13:2": true,
+ "8:7": true,
+ "9:6": true,
+ "4:1": true,
+ "0:2": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": true,
+ "4:5": true,
+ "15:1": true,
+ "13:3": true,
+ "3:4": true,
+ "2:5": true,
+ "13:4": true,
+ "3:3": true,
+ "2:1": true,
+ "15:4": true,
+ "14:3": true,
+ "12:6": true,
+ "7:7": true,
+ "2:2": true,
+ "15:3": true,
+ "6:1": true,
+ "14:4": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "3:5": true,
+ "2:4": true,
+ "14:2": true,
+ "13:1": true,
+ "0:1": true,
+ "9:7": true,
+ "3:1": true,
+ "13:5": true,
+ "2:3": true,
+ "12:3": true,
+ "11:4": true,
+ "10:5": true,
+ "15:0": true,
+ "9:1": true,
+ "4:6": true,
+ "3:7": true,
+ "1:3": true,
+ "10:1": true,
+ "9:5": true,
+ "12:4": true,
+ "14:0": true,
+ "2:0": true,
+ "12:2": true,
+ "1:2": true,
+ "6:7": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_3.json
index 4fb265b7..8aaf3ecd 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_3.json
@@ -1 +1,16 @@
-{"7:13":true,"4:14":true,"7:12":true,"7:15":true,"0:7":true,"15:14":true,"5:12":true,"14:15":true,"4:15":true,"6:12":true,"15:15":true,"4:12":true,"7:14":true,"4:13":true} \ No newline at end of file
+{
+ "7:13": true,
+ "4:14": true,
+ "7:12": true,
+ "7:15": true,
+ "0:7": true,
+ "15:14": true,
+ "5:12": true,
+ "14:15": true,
+ "4:15": true,
+ "6:12": true,
+ "15:15": true,
+ "4:12": true,
+ "7:14": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_7.json
index e53a59df..bdceed93 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_7.json
@@ -1 +1,24 @@
-{"9:14":true,"6:0":true,"10:9":true,"10:14":true,"15:14":true,"9:9":true,"10:12":true,"14:15":true,"9:15":true,"15:15":true,"9:12":true,"10:15":true,"10:10":true,"9:11":true,"5:0":true,"10:11":true,"9:10":true,"4:0":true,"7:0":true,"10:13":true,"9:8":true,"9:13":true} \ No newline at end of file
+{
+ "9:14": true,
+ "6:0": true,
+ "10:9": true,
+ "10:14": true,
+ "15:14": true,
+ "9:9": true,
+ "10:12": true,
+ "14:15": true,
+ "9:15": true,
+ "15:15": true,
+ "9:12": true,
+ "10:15": true,
+ "10:10": true,
+ "9:11": true,
+ "5:0": true,
+ "10:11": true,
+ "9:10": true,
+ "4:0": true,
+ "7:0": true,
+ "10:13": true,
+ "9:8": true,
+ "9:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_8.json
index 4d1cb0dc..bc37be21 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_8.json
@@ -1 +1,40 @@
-{"12:11":true,"1:11":true,"3:13":true,"13:13":true,"6:13":true,"13:0":true,"14:11":true,"14:1":true,"13:15":true,"7:13":true,"15:11":true,"15:1":true,"9:0":true,"1:9":true,"15:8":true,"10:13":true,"14:8":true,"9:13":true,"8:13":true,"1:10":true,"13:8":true,"0:8":130,"11:13":true,"14:15":true,"13:11":true,"15:15":true,"15:2":true,"12:13":true,"1:13":true,"15:0":true,"2:13":true,"14:0":true,"15:13":true,"12:15":true,"5:13":true,"1:15":true,"14:13":true,"4:13":true} \ No newline at end of file
+{
+ "12:11": true,
+ "1:11": true,
+ "3:13": true,
+ "13:13": true,
+ "6:13": true,
+ "13:0": true,
+ "14:11": true,
+ "14:1": true,
+ "13:15": true,
+ "7:13": true,
+ "15:11": true,
+ "15:1": true,
+ "9:0": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "14:8": true,
+ "9:13": true,
+ "8:13": true,
+ "1:10": true,
+ "13:8": true,
+ "0:8": 130,
+ "11:13": true,
+ "14:15": true,
+ "13:11": true,
+ "15:15": true,
+ "15:2": true,
+ "12:13": true,
+ "1:13": true,
+ "15:0": true,
+ "2:13": true,
+ "14:0": true,
+ "15:13": true,
+ "12:15": true,
+ "5:13": true,
+ "1:15": true,
+ "14:13": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_9.json
index 1bd9898c..6352e1c4 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-1_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-1_9.json
@@ -1 +1,41 @@
-{"12:11":true,"9:14":213,"1:1":true,"10:14":214,"13:15":true,"10:10":127,"0:2":true,"7:13":true,"6:14":true,"1:9":true,"13:14":127,"10:13":215,"9:13":214,"14:14":127,"15:14":true,"15:12":127,"14:15":127,"3:11":127,"8:12":true,"13:7":127,"15:13":true,"2:10":true,"14:13":true,"12:8":127,"11:9":127,"15:5":127,"5:14":true,"0:8":127,"1:0":true,"4:12":true,"5:15":[127,208],"14:6":127,"9:11":127,"11:14":true,"12:15":true,"5:13":127} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": 213,
+ "1:1": true,
+ "10:14": 214,
+ "13:15": true,
+ "10:10": 127,
+ "0:2": true,
+ "7:13": true,
+ "6:14": true,
+ "1:9": true,
+ "13:14": 127,
+ "10:13": 215,
+ "9:13": 214,
+ "14:14": 127,
+ "15:14": true,
+ "15:12": 127,
+ "14:15": 127,
+ "3:11": 127,
+ "8:12": true,
+ "13:7": 127,
+ "15:13": true,
+ "2:10": true,
+ "14:13": true,
+ "12:8": 127,
+ "11:9": 127,
+ "15:5": 127,
+ "5:14": true,
+ "0:8": 127,
+ "1:0": true,
+ "4:12": true,
+ "5:15": [
+ 127,
+ 208
+ ],
+ "14:6": 127,
+ "9:11": 127,
+ "11:14": true,
+ "12:15": true,
+ "5:13": 127
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-2.json
index 7ead9273..e4e3ff1e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-2.json
@@ -1 +1,26 @@
-{"15:4":true,"11:0":true,"11:5":true,"12:5":true,"15:3":true,"8:5":true,"8:0":true,"15:2":true,"13:0":true,"13:5":true,"10:2":true,"15:0":true,"10:5":true,"15:5":true,"10:0":true,"14:5":true,"9:5":true,"11:3":true,"8:2":true,"15:1":true,"13:3":true,"8:4":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "15:4": true,
+ "11:0": true,
+ "11:5": true,
+ "12:5": true,
+ "15:3": true,
+ "8:5": true,
+ "8:0": true,
+ "15:2": true,
+ "13:0": true,
+ "13:5": true,
+ "10:2": true,
+ "15:0": true,
+ "10:5": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "9:5": true,
+ "11:3": true,
+ "8:2": true,
+ "15:1": true,
+ "13:3": true,
+ "8:4": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-3.json
index a278b911..ce28df65 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-3.json
@@ -1 +1,108 @@
-{"15:9":true,"1:1":true,"11:5":true,"8:8":true,"14:9":true,"15:7":true,"3:0":170,"0:6":true,"0:0":true,"14:7":true,"8:1":true,"3:6":true,"13:10":true,"14:1":true,"8:7":true,"5:5":true,"0:2":true,"4:5":true,"15:1":true,"15:8":true,"14:8":true,"2:1":true,"11:0":true,"4:3":170,"5:4":true,"5:3":true,"13:8":true,"15:14":true,"10:7":true,"3:5":true,"15:12":true,"13:1":true,"4:2":170,"15:15":true,"9:7":true,"5:2":true,"12:3":true,"11:4":true,"9:1":true,"4:6":true,"15:10":true,"5:0":true,"14:10":true,"10:1":true,"5:6":true,"13:7":true,"11:3":true,"4:0":170,"10:8":true,"11:2":true,"13:9":true,"9:8":true,"9:3":true,"10:4":true,"10:3":true,"1:5":true,"11:1":true,"9:4":true,"8:5":true,"13:6":true,"9:2":true,"13:0":true,"10:2":true,"13:2":true,"9:6":true,"4:1":170,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"5:1":170,"9:0":true,"13:3":true,"13:4":true,"15:4":true,"14:3":true,"1:6":[151,169],"15:3":true,"1:0":true,"14:4":true,"8:0":true,"14:2":true,"13:11":true,"0:1":true,"15:2":true,"8:6":true,"3:1":170,"13:5":true,"15:0":true,"14:6":true,"10:5":true,"9:5":true,"8:2":true,"15:6":true,"14:0":true,"2:0":170,"11:12":true,"8:4":true,"8:3":true,"2:6":[151,169]} \ No newline at end of file
+{
+ "15:9": true,
+ "1:1": true,
+ "11:5": true,
+ "8:8": true,
+ "14:9": true,
+ "15:7": true,
+ "3:0": 170,
+ "0:6": true,
+ "0:0": true,
+ "14:7": true,
+ "8:1": true,
+ "3:6": true,
+ "13:10": true,
+ "14:1": true,
+ "8:7": true,
+ "5:5": true,
+ "0:2": true,
+ "4:5": true,
+ "15:1": true,
+ "15:8": true,
+ "14:8": true,
+ "2:1": true,
+ "11:0": true,
+ "4:3": 170,
+ "5:4": true,
+ "5:3": true,
+ "13:8": true,
+ "15:14": true,
+ "10:7": true,
+ "3:5": true,
+ "15:12": true,
+ "13:1": true,
+ "4:2": 170,
+ "15:15": true,
+ "9:7": true,
+ "5:2": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "4:6": true,
+ "15:10": true,
+ "5:0": true,
+ "14:10": true,
+ "10:1": true,
+ "5:6": true,
+ "13:7": true,
+ "11:3": true,
+ "4:0": 170,
+ "10:8": true,
+ "11:2": true,
+ "13:9": true,
+ "9:8": true,
+ "9:3": true,
+ "10:4": true,
+ "10:3": true,
+ "1:5": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": 170,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": 170,
+ "9:0": true,
+ "13:3": true,
+ "13:4": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": [
+ 151,
+ 169
+ ],
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "8:0": true,
+ "14:2": true,
+ "13:11": true,
+ "0:1": true,
+ "15:2": true,
+ "8:6": true,
+ "3:1": 170,
+ "13:5": true,
+ "15:0": true,
+ "14:6": true,
+ "10:5": true,
+ "9:5": true,
+ "8:2": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": 170,
+ "11:12": true,
+ "8:4": true,
+ "8:3": true,
+ "2:6": [
+ 151,
+ 169
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-4.json
index 384c6db4..5c22c130 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-4.json
@@ -1 +1,205 @@
-{"1:1":170,"8:8":true,"6:10":true,"13:13":true,"3:6":true,"14:1":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"3:3":true,"0:4":true,"2:1":170,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"10:9":true,"5:3":true,"2:15":170,"15:14":true,"9:9":true,"4:4":true,"10:7":true,"8:10":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":true,"2:14":170,"1:13":170,"6:9":true,"4:6":true,"2:13":true,"1:14":170,"5:0":170,"5:6":true,"4:0":170,"15:13":true,"1:15":170,"10:8":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"11:8":true,"13:6":true,"13:0":true,"14:11":true,"13:2":true,"4:1":170,"3:12":true,"11:9":true,"15:5":true,"14:5":true,"5:1":170,"3:15":170,"15:11":true,"13:3":true,"11:7":true,"2:5":true,"13:4":true,"3:14":170,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"11:10":true,"5:14":true,"2:2":true,"15:3":true,"14:4":true,"5:12":true,"2:4":true,"14:2":true,"13:11":true,"4:15":170,"15:2":true,"4:12":true,"3:1":170,"13:5":true,"5:15":true,"2:3":true,"15:0":true,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"14:0":true,"5:13":true,"1:2":170,"4:13":true,"2:6":true,"15:9":true,"9:14":true,"11:5":true,"2:7":true,"10:14":true,"14:9":true,"11:11":true,"10:12":true,"2:9":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":170,"13:10":true,"10:15":true,"1:8":true,"2:8":true,"1:9":true,"15:8":true,"10:13":true,"6:12":true,"1:7":true,"14:8":true,"9:13":true,"8:13":true,"1:10":true,"13:8":true,"11:6":true,"11:4":true,"9:1":true,"8:12":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"11:3":true,"8:15":true,"2:10":true,"11:2":true,"8:14":true,"13:9":true,"12:1":true,"9:3":true,"10:4":true,"5:9":true,"10:3":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"9:6":true,"10:0":true,"10:6":true,"9:0":true,"5:8":true,"4:8":true,"3:8":true,"6:11":true,"11:13":true,"8:0":[170,212],"8:6":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"11:12":true,"8:4":true,"3:9":true,"11:15":true,"8:3":true,"0:9":true} \ No newline at end of file
+{
+ "1:1": 170,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": 170,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "5:3": true,
+ "2:15": 170,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "2:14": 170,
+ "1:13": 170,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "1:14": 170,
+ "5:0": 170,
+ "5:6": true,
+ "4:0": 170,
+ "15:13": true,
+ "1:15": 170,
+ "10:8": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "14:11": true,
+ "13:2": true,
+ "4:1": 170,
+ "3:12": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": 170,
+ "3:15": 170,
+ "15:11": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "13:4": true,
+ "3:14": 170,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "5:14": true,
+ "2:2": true,
+ "15:3": true,
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": 170,
+ "15:2": true,
+ "4:12": true,
+ "3:1": 170,
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": true,
+ "5:13": true,
+ "1:2": 170,
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": true,
+ "10:14": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": 170,
+ "13:10": true,
+ "10:15": true,
+ "1:8": true,
+ "2:8": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "14:8": true,
+ "9:13": true,
+ "8:13": true,
+ "1:10": true,
+ "13:8": true,
+ "11:6": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "11:3": true,
+ "8:15": true,
+ "2:10": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "12:1": true,
+ "9:3": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "9:6": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "5:8": true,
+ "4:8": true,
+ "3:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": [
+ 170,
+ 212
+ ],
+ "8:6": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "11:12": true,
+ "8:4": true,
+ "3:9": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-5.json
index f5fe8895..036f035b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-5.json
@@ -1 +1,172 @@
-{"15:9":true,"1:1":true,"2:7":true,"13:13":true,"12:5":true,"10:14":170,"14:9":true,"15:7":true,"3:0":true,"9:15":true,"0:0":true,"14:7":true,"9:12":true,"8:1":true,"3:6":true,"13:10":true,"10:15":[170,207],"1:8":true,"14:1":true,"13:15":true,"8:7":true,"5:5":true,"0:2":true,"2:8":true,"9:10":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"15:8":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"3:3":true,"1:7":true,"0:4":true,"14:8":true,"2:1":true,"11:0":true,"14:14":true,"4:3":true,"8:13":true,"5:4":true,"5:3":true,"13:8":true,"12:0":true,"15:14":true,"4:4":true,"10:7":true,"8:10":true,"3:5":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"15:15":true,"14:12":true,"9:7":true,"5:2":true,"2:14":[151,168],"11:4":true,"9:1":true,"8:12":true,"4:6":true,"1:14":[151,168],"15:10":true,"5:0":true,"14:10":true,"10:1":true,"5:6":true,"13:7":true,"8:15":true,"4:0":true,"15:13":true,"10:8":true,"13:9":true,"14:13":true,"6:0":true,"9:3":true,"10:4":true,"10:3":true,"1:5":true,"9:4":true,"8:5":true,"5:7":true,"13:6":true,"9:2":true,"13:0":true,"4:7":true,"10:2":true,"14:11":true,"13:2":true,"9:6":true,"4:1":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"5:1":true,"15:11":true,"9:0":true,"7:0":true,"13:3":true,"2:5":true,"0:14":[154,165],"5:8":true,"13:4":true,"3:14":[151,169],"6:2":true,"4:8":true,"15:4":true,"14:3":true,"4:14":[151,169],"1:6":true,"3:8":true,"5:14":[151,169],"2:2":true,"0:8":true,"15:3":true,"1:0":true,"14:4":true,"2:4":true,"8:0":true,"14:2":true,"13:11":true,"4:15":170,"15:2":true,"8:6":true,"3:1":true,"13:5":true,"5:15":170,"2:3":true,"15:0":true,"14:6":true,"10:5":true,"3:7":true,"1:3":true,"9:5":true,"11:14":true,"8:2":true,"1:4":true,"15:6":true,"14:0":true,"2:0":true,"8:4":true,"1:2":true,"8:3":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "1:1": true,
+ "2:7": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": 170,
+ "14:9": true,
+ "15:7": true,
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "3:6": true,
+ "13:10": true,
+ "10:15": [
+ 170,
+ 207
+ ],
+ "1:8": true,
+ "14:1": true,
+ "13:15": true,
+ "8:7": true,
+ "5:5": true,
+ "0:2": true,
+ "2:8": true,
+ "9:10": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "15:8": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "3:3": true,
+ "1:7": true,
+ "0:4": true,
+ "14:8": true,
+ "2:1": true,
+ "11:0": true,
+ "14:14": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "5:3": true,
+ "13:8": true,
+ "12:0": true,
+ "15:14": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "5:2": true,
+ "2:14": [
+ 151,
+ 168
+ ],
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "4:6": true,
+ "1:14": [
+ 151,
+ 168
+ ],
+ "15:10": true,
+ "5:0": true,
+ "14:10": true,
+ "10:1": true,
+ "5:6": true,
+ "13:7": true,
+ "8:15": true,
+ "4:0": true,
+ "15:13": true,
+ "10:8": true,
+ "13:9": true,
+ "14:13": true,
+ "6:0": true,
+ "9:3": true,
+ "10:4": true,
+ "10:3": true,
+ "1:5": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "4:7": true,
+ "10:2": true,
+ "14:11": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": true,
+ "15:11": true,
+ "9:0": true,
+ "7:0": true,
+ "13:3": true,
+ "2:5": true,
+ "0:14": [
+ 154,
+ 165
+ ],
+ "5:8": true,
+ "13:4": true,
+ "3:14": [
+ 151,
+ 169
+ ],
+ "6:2": true,
+ "4:8": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": [
+ 151,
+ 169
+ ],
+ "1:6": true,
+ "3:8": true,
+ "5:14": [
+ 151,
+ 169
+ ],
+ "2:2": true,
+ "0:8": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "2:4": true,
+ "8:0": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": 170,
+ "15:2": true,
+ "8:6": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": 170,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "10:5": true,
+ "3:7": true,
+ "1:3": true,
+ "9:5": true,
+ "11:14": true,
+ "8:2": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "8:4": true,
+ "1:2": true,
+ "8:3": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-7.json
index 0b2eacc6..2ddd3045 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_-7.json
@@ -1 +1,86 @@
-{"15:9":true,"12:11":true,"9:14":true,"13:13":true,"12:5":true,"10:14":true,"14:9":true,"11:11":true,"10:12":true,"11:8":true,"13:6":true,"9:15":true,"14:7":true,"9:12":true,"8:11":true,"8:1":true,"13:10":true,"10:15":true,"12:8":true,"14:11":true,"13:15":true,"10:10":true,"11:9":true,"15:5":true,"14:5":true,"9:10":true,"13:12":true,"15:11":true,"12:9":true,"15:8":true,"13:14":true,"11:7":true,"10:13":true,"8:9":true,"13:4":true,"12:7":true,"14:8":true,"9:13":true,"15:4":true,"14:3":true,"14:14":true,"12:6":true,"8:13":true,"10:9":true,"12:10":true,"13:8":true,"15:3":true,"15:14":true,"9:9":true,"14:4":true,"11:6":true,"10:7":true,"8:10":true,"15:12":true,"14:15":true,"13:11":true,"15:2":true,"15:15":true,"14:12":true,"13:5":true,"14:6":true,"12:14":true,"9:11":true,"8:12":true,"15:10":true,"14:10":true,"10:11":true,"13:7":true,"8:15":true,"15:6":true,"15:13":[155,215],"12:15":true,"11:12":true,"10:8":true,"12:12":true,"11:15":true,"8:14":true,"8:3":true,"13:9":true,"9:8":true,"14:13":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "11:8": true,
+ "13:6": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:11": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "12:8": true,
+ "14:11": true,
+ "13:15": true,
+ "10:10": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "9:10": true,
+ "13:12": true,
+ "15:11": true,
+ "12:9": true,
+ "15:8": true,
+ "13:14": true,
+ "11:7": true,
+ "10:13": true,
+ "8:9": true,
+ "13:4": true,
+ "12:7": true,
+ "14:8": true,
+ "9:13": true,
+ "15:4": true,
+ "14:3": true,
+ "14:14": true,
+ "12:6": true,
+ "8:13": true,
+ "10:9": true,
+ "12:10": true,
+ "13:8": true,
+ "15:3": true,
+ "15:14": true,
+ "9:9": true,
+ "14:4": true,
+ "11:6": true,
+ "10:7": true,
+ "8:10": true,
+ "15:12": true,
+ "14:15": true,
+ "13:11": true,
+ "15:2": true,
+ "15:15": true,
+ "14:12": true,
+ "13:5": true,
+ "14:6": true,
+ "12:14": true,
+ "9:11": true,
+ "8:12": true,
+ "15:10": true,
+ "14:10": true,
+ "10:11": true,
+ "13:7": true,
+ "8:15": true,
+ "15:6": true,
+ "15:13": [
+ 155,
+ 215
+ ],
+ "12:15": true,
+ "11:12": true,
+ "10:8": true,
+ "12:12": true,
+ "11:15": true,
+ "8:14": true,
+ "8:3": true,
+ "13:9": true,
+ "9:8": true,
+ "14:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_0.json
index ef608932..5f8b086a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_0.json
@@ -1 +1,61 @@
-{"12:11":147,"13:13":[148,149],"11:11":148,"2:9":[155,239],"2:8":154,"1:9":[154,239],"13:14":148,"14:14":147,"1:10":238,"15:14":146,"15:12":243,"14:15":[148,149],"14:12":145,"2:14":[175,176],"1:14":[174,175],"15:13":145,"2:10":238,"14:13":146,"1:11":237,"4:9":240,"5:7":153,"3:10":[238,239],"0:10":153,"9:6":152,"15:11":true,"3:14":[175,176],"2:11":[236,237],"4:14":175,"0:8":true,"3:9":240,"12:12":148,"0:9":153} \ No newline at end of file
+{
+ "12:11": 147,
+ "13:13": [
+ 148,
+ 149
+ ],
+ "11:11": 148,
+ "2:9": [
+ 155,
+ 239
+ ],
+ "2:8": 154,
+ "1:9": [
+ 154,
+ 239
+ ],
+ "13:14": 148,
+ "14:14": 147,
+ "1:10": 238,
+ "15:14": 146,
+ "15:12": 243,
+ "14:15": [
+ 148,
+ 149
+ ],
+ "14:12": 145,
+ "2:14": [
+ 175,
+ 176
+ ],
+ "1:14": [
+ 174,
+ 175
+ ],
+ "15:13": 145,
+ "2:10": 238,
+ "14:13": 146,
+ "1:11": 237,
+ "4:9": 240,
+ "5:7": 153,
+ "3:10": [
+ 238,
+ 239
+ ],
+ "0:10": 153,
+ "9:6": 152,
+ "15:11": true,
+ "3:14": [
+ 175,
+ 176
+ ],
+ "2:11": [
+ 236,
+ 237
+ ],
+ "4:14": 175,
+ "0:8": true,
+ "3:9": 240,
+ "12:12": 148,
+ "0:9": 153
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_10.json
index 2f50b994..51e98b28 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_10.json
@@ -1 +1,59 @@
-{"15:9":127,"6:13":true,"9:12":true,"8:1":true,"14:1":127,"7:13":true,"6:12":true,"2:12":true,"6:1":true,"13:1":127,"5:2":true,"1:13":[170,171],"12:3":127,"11:4":127,"9:1":true,"8:12":true,"2:13":169,"14:10":127,"11:3":127,"12:2":127,"11:2":true,"7:1":true,"9:3":true,"3:13":true,"10:3":true,"7:2":true,"9:2":true,"13:0":127,"10:2":true,"13:2":127,"3:12":true,"0:12":[129,133],"9:0":true,"7:0":127,"3:14":[145,173],"6:2":true,"4:14":[145,174],"5:14":true,"5:12":true,"8:0":true,"15:0":127,"8:2":true,"14:0":127,"5:13":true,"8:3":true} \ No newline at end of file
+{
+ "15:9": 127,
+ "6:13": true,
+ "9:12": true,
+ "8:1": true,
+ "14:1": 127,
+ "7:13": true,
+ "6:12": true,
+ "2:12": true,
+ "6:1": true,
+ "13:1": 127,
+ "5:2": true,
+ "1:13": [
+ 170,
+ 171
+ ],
+ "12:3": 127,
+ "11:4": 127,
+ "9:1": true,
+ "8:12": true,
+ "2:13": 169,
+ "14:10": 127,
+ "11:3": 127,
+ "12:2": 127,
+ "11:2": true,
+ "7:1": true,
+ "9:3": true,
+ "3:13": true,
+ "10:3": true,
+ "7:2": true,
+ "9:2": true,
+ "13:0": 127,
+ "10:2": true,
+ "13:2": 127,
+ "3:12": true,
+ "0:12": [
+ 129,
+ 133
+ ],
+ "9:0": true,
+ "7:0": 127,
+ "3:14": [
+ 145,
+ 173
+ ],
+ "6:2": true,
+ "4:14": [
+ 145,
+ 174
+ ],
+ "5:14": true,
+ "5:12": true,
+ "8:0": true,
+ "15:0": 127,
+ "8:2": true,
+ "14:0": 127,
+ "5:13": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_11.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_11.json
index 2b5520cf..5bae7eda 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_11.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_11.json
@@ -1 +1,17 @@
-{"15:4":true,"12:1":true,"15:3":true,"11:1":true,"8:0":true,"13:1":true,"15:2":true,"4:7":true,"15:0":true,"14:1":true,"15:5":true,"10:0":true,"15:6":true,"15:1":true,"9:0":true} \ No newline at end of file
+{
+ "15:4": true,
+ "12:1": true,
+ "15:3": true,
+ "11:1": true,
+ "8:0": true,
+ "13:1": true,
+ "15:2": true,
+ "4:7": true,
+ "15:0": true,
+ "14:1": true,
+ "15:5": true,
+ "10:0": true,
+ "15:6": true,
+ "15:1": true,
+ "9:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_3.json
index 1f44a377..a6a343e8 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_3.json
@@ -1 +1,3 @@
-{"0:3":true} \ No newline at end of file
+{
+ "0:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_4.json
index 50c8d9d0..030dac50 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_4.json
@@ -1 +1,193 @@
-{"15:9":true,"1:1":true,"2:7":true,"8:8":true,"7:12":true,"14:9":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"9:15":true,"0:6":[129,148],"14:7":true,"9:12":true,"3:6":true,"1:8":true,"13:15":true,"0:2":true,"14:1":true,"10:10":true,"8:7":true,"4:11":true,"7:13":true,"2:8":true,"9:10":true,"5:11":true,"3:2":true,"1:9":true,"15:8":true,"10:13":true,"0:3":true,"8:9":true,"6:12":true,"1:7":true,"0:4":[129,132],"14:8":true,"9:13":true,"12:6":true,"4:3":[111,177],"8:13":true,"5:4":[173,179],"2:12":true,"10:9":true,"7:7":true,"5:3":[111,179],"1:10":true,"13:8":true,"15:14":true,"9:9":true,"11:6":true,"4:4":[176,177],"10:7":true,"8:10":true,"7:9":true,"13:1":233,"4:2":true,"0:11":true,"15:15":true,"9:7":true,"3:11":true,"5:2":true,"1:13":true,"0:5":[129,132],"12:3":233,"11:4":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"5:6":true,"8:15":true,"13:7":true,"12:4":true,"12:2":234,"2:10":true,"10:8":true,"6:7":true,"1:12":true,"13:9":true,"9:8":true,"9:3":126,"1:11":true,"10:4":[129,132],"3:13":true,"10:3":[129,132],"0:13":true,"7:2":[129,132],"6:6":true,"4:9":true,"9:4":true,"5:7":true,"3:10":true,"11:8":true,"13:6":true,"9:2":[129,132],"8:11":true,"4:7":true,"10:2":[129,132],"0:10":true,"12:8":true,"13:2":true,"9:6":true,"3:12":true,"11:9":true,"15:5":true,"14:5":true,"10:6":true,"0:12":true,"12:9":true,"13:3":true,"11:7":true,"13:4":true,"12:7":true,"6:2":true,"7:6":true,"4:8":true,"2:11":true,"15:4":true,"14:3":true,"1:6":true,"3:8":true,"0:8":true,"15:3":true,"6:11":true,"14:4":true,"5:12":true,"14:2":true,"0:1":true,"15:2":true,"8:6":true,"4:12":true,"13:5":true,"14:6":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"8:2":[129,132],"0:7":true,"15:6":true,"12:15":true,"5:13":true,"3:9":true,"11:15":true,"0:9":true,"7:11":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "1:1": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "14:9": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "9:15": true,
+ "0:6": [
+ 129,
+ 148
+ ],
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "1:8": true,
+ "13:15": true,
+ "0:2": true,
+ "14:1": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "7:13": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "3:2": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "0:3": true,
+ "8:9": true,
+ "6:12": true,
+ "1:7": true,
+ "0:4": [
+ 129,
+ 132
+ ],
+ "14:8": true,
+ "9:13": true,
+ "12:6": true,
+ "4:3": [
+ 111,
+ 177
+ ],
+ "8:13": true,
+ "5:4": [
+ 173,
+ 179
+ ],
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": [
+ 111,
+ 179
+ ],
+ "1:10": true,
+ "13:8": true,
+ "15:14": true,
+ "9:9": true,
+ "11:6": true,
+ "4:4": [
+ 176,
+ 177
+ ],
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "13:1": 233,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "1:13": true,
+ "0:5": [
+ 129,
+ 132
+ ],
+ "12:3": 233,
+ "11:4": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "5:6": true,
+ "8:15": true,
+ "13:7": true,
+ "12:4": true,
+ "12:2": 234,
+ "2:10": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "13:9": true,
+ "9:8": true,
+ "9:3": 126,
+ "1:11": true,
+ "10:4": [
+ 129,
+ 132
+ ],
+ "3:13": true,
+ "10:3": [
+ 129,
+ 132
+ ],
+ "0:13": true,
+ "7:2": [
+ 129,
+ 132
+ ],
+ "6:6": true,
+ "4:9": true,
+ "9:4": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "13:6": true,
+ "9:2": [
+ 129,
+ 132
+ ],
+ "8:11": true,
+ "4:7": true,
+ "10:2": [
+ 129,
+ 132
+ ],
+ "0:10": true,
+ "12:8": true,
+ "13:2": true,
+ "9:6": true,
+ "3:12": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "10:6": true,
+ "0:12": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "13:4": true,
+ "12:7": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "3:8": true,
+ "0:8": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "5:12": true,
+ "14:2": true,
+ "0:1": true,
+ "15:2": true,
+ "8:6": true,
+ "4:12": true,
+ "13:5": true,
+ "14:6": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "8:2": [
+ 129,
+ 132
+ ],
+ "0:7": true,
+ "15:6": true,
+ "12:15": true,
+ "5:13": true,
+ "3:9": true,
+ "11:15": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_6.json
index 5a4f9d06..d5fffea6 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_6.json
@@ -1 +1,220 @@
-{"15:9":true,"1:1":[129,144],"11:5":true,"6:10":[129,132],"12:5":true,"14:9":true,"15:7":true,"3:0":[141,143],"0:6":[129,148],"0:0":true,"14:7":true,"8:1":true,"3:6":true,"13:10":true,"10:10":true,"5:5":[139,140],"0:2":true,"9:10":true,"4:5":[139,140],"3:2":[141,143],"15:8":true,"3:4":true,"0:3":true,"7:10":[129,132],"3:3":true,"0:4":[129,148],"14:8":true,"2:1":[129,144],"12:6":true,"4:3":[139,140],"10:9":true,"13:8":true,"9:9":true,"6:1":true,"11:6":true,"4:4":[139,140],"10:7":true,"8:10":true,"3:5":true,"4:2":[111,140],"0:11":[129,152],"9:7":true,"5:2":[111,120],"0:5":[129,148],"12:3":true,"11:4":true,"9:1":true,"4:6":true,"15:10":true,"5:0":true,"14:10":true,"10:1":true,"5:6":141,"13:7":true,"12:4":true,"11:3":true,"4:0":[141,143],"10:8":true,"13:9":true,"9:8":true,"7:1":true,"9:3":true,"6:0":true,"1:11":true,"10:4":true,"5:9":[111,179],"10:3":true,"1:5":144,"6:6":[141,168],"4:9":[111,177],"9:4":true,"8:5":true,"3:10":true,"7:4":true,"13:6":true,"9:2":true,"10:2":true,"0:10":[129,132],"7:3":true,"9:6":true,"4:1":[129,140],"15:5":true,"10:0":true,"14:5":true,"10:6":true,"5:1":true,"9:0":true,"6:3":true,"7:0":true,"13:3":true,"2:5":144,"5:8":[173,179],"13:4":true,"7:6":true,"4:8":true,"15:4":true,"14:3":true,"1:6":144,"6:5":[139,168],"2:2":144,"0:8":[129,132],"15:3":true,"1:0":true,"14:4":true,"2:4":144,"8:0":true,"0:1":true,"8:6":true,"3:1":[129,143],"13:5":true,"2:3":144,"14:6":true,"10:5":true,"5:10":[129,132],"1:3":144,"9:5":true,"4:10":[129,132],"8:2":true,"1:4":144,"0:7":[129,132],"15:6":true,"2:0":144,"8:4":true,"1:2":144,"7:5":true,"8:3":true,"0:9":[108,132],"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "1:1": [
+ 129,
+ 144
+ ],
+ "11:5": true,
+ "6:10": [
+ 129,
+ 132
+ ],
+ "12:5": true,
+ "14:9": true,
+ "15:7": true,
+ "3:0": [
+ 141,
+ 143
+ ],
+ "0:6": [
+ 129,
+ 148
+ ],
+ "0:0": true,
+ "14:7": true,
+ "8:1": true,
+ "3:6": true,
+ "13:10": true,
+ "10:10": true,
+ "5:5": [
+ 139,
+ 140
+ ],
+ "0:2": true,
+ "9:10": true,
+ "4:5": [
+ 139,
+ 140
+ ],
+ "3:2": [
+ 141,
+ 143
+ ],
+ "15:8": true,
+ "3:4": true,
+ "0:3": true,
+ "7:10": [
+ 129,
+ 132
+ ],
+ "3:3": true,
+ "0:4": [
+ 129,
+ 148
+ ],
+ "14:8": true,
+ "2:1": [
+ 129,
+ 144
+ ],
+ "12:6": true,
+ "4:3": [
+ 139,
+ 140
+ ],
+ "10:9": true,
+ "13:8": true,
+ "9:9": true,
+ "6:1": true,
+ "11:6": true,
+ "4:4": [
+ 139,
+ 140
+ ],
+ "10:7": true,
+ "8:10": true,
+ "3:5": true,
+ "4:2": [
+ 111,
+ 140
+ ],
+ "0:11": [
+ 129,
+ 152
+ ],
+ "9:7": true,
+ "5:2": [
+ 111,
+ 120
+ ],
+ "0:5": [
+ 129,
+ 148
+ ],
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "4:6": true,
+ "15:10": true,
+ "5:0": true,
+ "14:10": true,
+ "10:1": true,
+ "5:6": 141,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "4:0": [
+ 141,
+ 143
+ ],
+ "10:8": true,
+ "13:9": true,
+ "9:8": true,
+ "7:1": true,
+ "9:3": true,
+ "6:0": true,
+ "1:11": true,
+ "10:4": true,
+ "5:9": [
+ 111,
+ 179
+ ],
+ "10:3": true,
+ "1:5": 144,
+ "6:6": [
+ 141,
+ 168
+ ],
+ "4:9": [
+ 111,
+ 177
+ ],
+ "9:4": true,
+ "8:5": true,
+ "3:10": true,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "10:2": true,
+ "0:10": [
+ 129,
+ 132
+ ],
+ "7:3": true,
+ "9:6": true,
+ "4:1": [
+ 129,
+ 140
+ ],
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "2:5": 144,
+ "5:8": [
+ 173,
+ 179
+ ],
+ "13:4": true,
+ "7:6": true,
+ "4:8": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": 144,
+ "6:5": [
+ 139,
+ 168
+ ],
+ "2:2": 144,
+ "0:8": [
+ 129,
+ 132
+ ],
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "2:4": 144,
+ "8:0": true,
+ "0:1": true,
+ "8:6": true,
+ "3:1": [
+ 129,
+ 143
+ ],
+ "13:5": true,
+ "2:3": 144,
+ "14:6": true,
+ "10:5": true,
+ "5:10": [
+ 129,
+ 132
+ ],
+ "1:3": 144,
+ "9:5": true,
+ "4:10": [
+ 129,
+ 132
+ ],
+ "8:2": true,
+ "1:4": 144,
+ "0:7": [
+ 129,
+ 132
+ ],
+ "15:6": true,
+ "2:0": 144,
+ "8:4": true,
+ "1:2": 144,
+ "7:5": true,
+ "8:3": true,
+ "0:9": [
+ 108,
+ 132
+ ],
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_7.json
index cc177949..8522ddbe 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_7.json
@@ -1 +1,10 @@
-{"0:15":true,"0:3":232,"2:1":233,"2:2":true,"2:4":true,"2:3":true,"1:3":true,"1:2":true} \ No newline at end of file
+{
+ "0:15": true,
+ "0:3": 232,
+ "2:1": 233,
+ "2:2": true,
+ "2:4": true,
+ "2:3": true,
+ "1:3": true,
+ "1:2": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_8.json
index 3e21e3c3..032a1fb4 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_8.json
@@ -1 +1,48 @@
-{"15:9":true,"3:13":true,"7:15":true,"6:13":true,"9:15":true,"8:11":true,"10:15":true,"12:8":130,"1:8":true,"4:1":true,"4:11":true,"11:9":true,"7:13":true,"2:8":true,"5:11":true,"3:15":true,"15:8":[129,131],"10:13":true,"6:15":true,"14:8":[130,131],"9:13":true,"8:13":true,"13:8":[130,131],"0:8":true,"6:11":true,"11:13":true,"4:15":true,"5:15":true,"9:11":true,"10:11":true,"8:15":true,"5:13":true,"3:9":true,"11:15":true,"0:9":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "15:9": true,
+ "3:13": true,
+ "7:15": true,
+ "6:13": true,
+ "9:15": true,
+ "8:11": true,
+ "10:15": true,
+ "12:8": 130,
+ "1:8": true,
+ "4:1": true,
+ "4:11": true,
+ "11:9": true,
+ "7:13": true,
+ "2:8": true,
+ "5:11": true,
+ "3:15": true,
+ "15:8": [
+ 129,
+ 131
+ ],
+ "10:13": true,
+ "6:15": true,
+ "14:8": [
+ 130,
+ 131
+ ],
+ "9:13": true,
+ "8:13": true,
+ "13:8": [
+ 130,
+ 131
+ ],
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "4:15": true,
+ "5:15": true,
+ "9:11": true,
+ "10:11": true,
+ "8:15": true,
+ "5:13": true,
+ "3:9": true,
+ "11:15": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_9.json
index 2e8e27c8..4670975e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-2_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-2_9.json
@@ -1 +1,47 @@
-{"15:9":[211,214],"9:14":true,"10:14":true,"2:2":true,"11:1":true,"11:13":true,"15:12":206,"15:7":[127,216],"14:2":true,"14:15":127,"9:15":true,"0:1":true,"15:15":[202,203],"15:2":true,"3:1":true,"12:13":true,"14:6":true,"13:2":true,"13:15":127,"12:14":true,"0:2":true,"15:10":209,"11:14":true,"8:15":true,"15:11":true,"15:1":true,"15:8":[214,215],"13:14":true,"12:2":true,"11:12":true,"10:13":true,"1:2":true,"14:8":214} \ No newline at end of file
+{
+ "15:9": [
+ 211,
+ 214
+ ],
+ "9:14": true,
+ "10:14": true,
+ "2:2": true,
+ "11:1": true,
+ "11:13": true,
+ "15:12": 206,
+ "15:7": [
+ 127,
+ 216
+ ],
+ "14:2": true,
+ "14:15": 127,
+ "9:15": true,
+ "0:1": true,
+ "15:15": [
+ 202,
+ 203
+ ],
+ "15:2": true,
+ "3:1": true,
+ "12:13": true,
+ "14:6": true,
+ "13:2": true,
+ "13:15": 127,
+ "12:14": true,
+ "0:2": true,
+ "15:10": 209,
+ "11:14": true,
+ "8:15": true,
+ "15:11": true,
+ "15:1": true,
+ "15:8": [
+ 214,
+ 215
+ ],
+ "13:14": true,
+ "12:2": true,
+ "11:12": true,
+ "10:13": true,
+ "1:2": true,
+ "14:8": 214
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-3.json
index 442b6330..81b28ef2 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-3.json
@@ -1 +1,12 @@
-{"13:0":[152,166],"13:2":[152,166],"13:3":true,"8:0":true} \ No newline at end of file
+{
+ "13:0": [
+ 152,
+ 166
+ ],
+ "13:2": [
+ 152,
+ 166
+ ],
+ "13:3": true,
+ "8:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-4.json
index f30eae4d..64b7be65 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-4.json
@@ -1 +1,33 @@
-{"11:11":234,"8:1":[205,206],"13:15":[153,166],"5:5":208,"13:12":[153,166],"13:8":true,"13:1":true,"13:9":true,"7:2":206,"13:2":[152,166],"13:4":true,"11:10":true,"12:10":true,"13:11":[152,166],"13:5":true,"10:11":true} \ No newline at end of file
+{
+ "11:11": 234,
+ "8:1": [
+ 205,
+ 206
+ ],
+ "13:15": [
+ 153,
+ 166
+ ],
+ "5:5": 208,
+ "13:12": [
+ 153,
+ 166
+ ],
+ "13:8": true,
+ "13:1": true,
+ "13:9": true,
+ "7:2": 206,
+ "13:2": [
+ 152,
+ 166
+ ],
+ "13:4": true,
+ "11:10": true,
+ "12:10": true,
+ "13:11": [
+ 152,
+ 166
+ ],
+ "13:5": true,
+ "10:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-5.json
index 1817d7ae..a4f4b826 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_-5.json
@@ -1 +1,35 @@
-{"14:9":true,"10:12":199,"13:0":true,"8:11":187,"13:2":true,"10:10":[187,191],"10:13":[171,203],"13:4":true,"9:13":[171,202],"11:10":[187,188],"8:13":201,"13:1":true,"13:5":true,"15:0":true,"9:11":[187,189],"14:10":true,"14:0":true,"11:12":true} \ No newline at end of file
+{
+ "14:9": true,
+ "10:12": 199,
+ "13:0": true,
+ "8:11": 187,
+ "13:2": true,
+ "10:10": [
+ 187,
+ 191
+ ],
+ "10:13": [
+ 171,
+ 203
+ ],
+ "13:4": true,
+ "9:13": [
+ 171,
+ 202
+ ],
+ "11:10": [
+ 187,
+ 188
+ ],
+ "8:13": 201,
+ "13:1": true,
+ "13:5": true,
+ "15:0": true,
+ "9:11": [
+ 187,
+ 189
+ ],
+ "14:10": true,
+ "14:0": true,
+ "11:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_0.json
index c6a5087f..5ef00bba 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_0.json
@@ -1 +1,83 @@
-{"2:7":232,"8:8":232,"7:12":true,"6:10":true,"2:9":[231,232],"0:6":true,"3:6":231,"1:8":true,"8:7":232,"2:8":[231,232],"5:11":true,"13:12":true,"1:9":true,"15:8":true,"8:9":true,"6:12":true,"1:7":true,"2:12":true,"7:7":true,"1:10":true,"8:10":true,"6:8":true,"15:12":153,"0:11":true,"14:12":true,"3:11":232,"8:12":true,"4:6":231,"15:10":152,"5:6":true,"15:13":154,"2:10":true,"6:7":true,"1:12":true,"14:13":154,"1:11":true,"5:9":true,"6:6":true,"4:9":true,"5:7":true,"3:10":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"3:12":231,"15:11":153,"5:8":true,"7:6":true,"4:8":true,"2:11":true,"1:6":true,"3:8":[231,232],"0:8":true,"6:11":true,"5:12":true,"8:6":231,"4:12":231,"5:10":true,"3:7":232,"4:10":[231,232],"0:7":true,"3:9":[231,232],"0:9":true,"7:11":true,"2:6":231} \ No newline at end of file
+{
+ "2:7": 232,
+ "8:8": 232,
+ "7:12": true,
+ "6:10": true,
+ "2:9": [
+ 231,
+ 232
+ ],
+ "0:6": true,
+ "3:6": 231,
+ "1:8": true,
+ "8:7": 232,
+ "2:8": [
+ 231,
+ 232
+ ],
+ "5:11": true,
+ "13:12": true,
+ "1:9": true,
+ "15:8": true,
+ "8:9": true,
+ "6:12": true,
+ "1:7": true,
+ "2:12": true,
+ "7:7": true,
+ "1:10": true,
+ "8:10": true,
+ "6:8": true,
+ "15:12": 153,
+ "0:11": true,
+ "14:12": true,
+ "3:11": 232,
+ "8:12": true,
+ "4:6": 231,
+ "15:10": 152,
+ "5:6": true,
+ "15:13": 154,
+ "2:10": true,
+ "6:7": true,
+ "1:12": true,
+ "14:13": 154,
+ "1:11": true,
+ "5:9": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "3:12": 231,
+ "15:11": 153,
+ "5:8": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "1:6": true,
+ "3:8": [
+ 231,
+ 232
+ ],
+ "0:8": true,
+ "6:11": true,
+ "5:12": true,
+ "8:6": 231,
+ "4:12": 231,
+ "5:10": true,
+ "3:7": 232,
+ "4:10": [
+ 231,
+ 232
+ ],
+ "0:7": true,
+ "3:9": [
+ 231,
+ 232
+ ],
+ "0:9": true,
+ "7:11": true,
+ "2:6": 231
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_1.json
index ad608523..93f45ca0 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_1.json
@@ -1 +1,86 @@
-{"11:5":[192,193],"12:5":[188,189],"8:7":185,"4:11":204,"2:12":[159,183],"7:7":[200,201],"11:6":[189,192],"10:7":[190,191],"9:7":186,"3:11":183,"2:14":185,"12:3":193,"11:4":195,"6:9":202,"4:6":179,"2:13":184,"1:14":[184,185],"12:4":[188,193],"1:15":185,"10:8":191,"11:2":221,"10:4":196,"5:9":203,"10:3":[220,221],"4:9":[182,183],"8:5":201,"3:10":182,"4:7":true,"9:6":[184,185],"3:12":184,"13:3":[191,192],"0:14":207,"4:8":[181,182],"14:3":190,"14:2":191,"15:2":true,"8:6":200,"10:5":185,"5:10":203,"4:10":[183,204],"8:4":162,"7:5":162} \ No newline at end of file
+{
+ "11:5": [
+ 192,
+ 193
+ ],
+ "12:5": [
+ 188,
+ 189
+ ],
+ "8:7": 185,
+ "4:11": 204,
+ "2:12": [
+ 159,
+ 183
+ ],
+ "7:7": [
+ 200,
+ 201
+ ],
+ "11:6": [
+ 189,
+ 192
+ ],
+ "10:7": [
+ 190,
+ 191
+ ],
+ "9:7": 186,
+ "3:11": 183,
+ "2:14": 185,
+ "12:3": 193,
+ "11:4": 195,
+ "6:9": 202,
+ "4:6": 179,
+ "2:13": 184,
+ "1:14": [
+ 184,
+ 185
+ ],
+ "12:4": [
+ 188,
+ 193
+ ],
+ "1:15": 185,
+ "10:8": 191,
+ "11:2": 221,
+ "10:4": 196,
+ "5:9": 203,
+ "10:3": [
+ 220,
+ 221
+ ],
+ "4:9": [
+ 182,
+ 183
+ ],
+ "8:5": 201,
+ "3:10": 182,
+ "4:7": true,
+ "9:6": [
+ 184,
+ 185
+ ],
+ "3:12": 184,
+ "13:3": [
+ 191,
+ 192
+ ],
+ "0:14": 207,
+ "4:8": [
+ 181,
+ 182
+ ],
+ "14:3": 190,
+ "14:2": 191,
+ "15:2": true,
+ "8:6": 200,
+ "10:5": 185,
+ "5:10": 203,
+ "4:10": [
+ 183,
+ 204
+ ],
+ "8:4": 162,
+ "7:5": 162
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_11.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_11.json
index 4b6bb9b4..b61ddcbe 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_11.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_11.json
@@ -1 +1,4 @@
-{"8:0":true,"12:0":true} \ No newline at end of file
+{
+ "8:0": true,
+ "12:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_2.json
index c8568d98..c34866aa 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_2.json
@@ -1 +1,6 @@
-{"0:0":185,"1:0":185,"0:1":186,"2:0":185} \ No newline at end of file
+{
+ "0:0": 185,
+ "1:0": 185,
+ "0:1": 186,
+ "2:0": 185
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_4.json
index 004f6226..086843da 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_4.json
@@ -1 +1,167 @@
-{"15:9":true,"12:11":true,"2:7":true,"8:8":true,"7:12":true,"6:10":true,"13:13":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"0:6":true,"14:7":true,"9:12":true,"3:6":true,"13:10":true,"1:8":true,"14:1":216,"8:7":true,"0:2":true,"7:13":true,"2:8":true,"13:12":true,"3:2":true,"15:1":[130,151],"1:9":true,"15:8":true,"10:13":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"6:12":true,"3:3":true,"1:7":true,"0:4":true,"14:8":true,"9:13":true,"12:6":141,"8:13":true,"10:9":true,"7:7":true,"13:8":true,"9:9":true,"11:6":141,"10:7":[139,168],"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:12":true,"9:7":true,"0:5":true,"12:3":[111,177],"11:4":[173,179],"8:12":true,"7:8":true,"6:9":true,"4:6":true,"15:10":true,"14:10":true,"5:6":true,"13:7":true,"12:4":[173,177],"11:3":true,"15:13":true,"12:2":true,"6:7":true,"11:2":true,"13:9":true,"9:8":true,"14:13":true,"10:4":true,"5:9":true,"1:5":true,"7:2":true,"6:6":true,"4:9":true,"5:7":true,"7:4":true,"13:6":[141,143],"9:2":true,"8:11":true,"4:7":true,"10:2":true,"12:8":true,"7:3":true,"14:11":true,"13:2":[129,132],"9:6":true,"6:4":true,"10:6":[141,216],"15:11":true,"12:9":true,"6:3":true,"11:7":[139,140],"2:5":true,"5:8":true,"13:4":true,"12:7":true,"6:2":true,"7:6":true,"4:8":true,"1:6":true,"11:10":true,"6:5":true,"3:8":true,"12:10":true,"2:2":true,"0:8":true,"6:11":true,"11:13":true,"2:4":true,"13:11":true,"8:6":true,"12:13":true,"2:3":true,"14:6":144,"9:11":true,"3:7":true,"1:3":true,"10:11":true,"9:5":true,"8:2":true,"1:4":true,"0:7":true,"15:6":true,"11:12":true,"1:2":true,"7:5":true,"3:9":true,"12:12":true,"0:9":true,"7:11":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "0:6": true,
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "13:10": true,
+ "1:8": true,
+ "14:1": 216,
+ "8:7": true,
+ "0:2": true,
+ "7:13": true,
+ "2:8": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": [
+ 130,
+ 151
+ ],
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": true,
+ "1:7": true,
+ "0:4": true,
+ "14:8": true,
+ "9:13": true,
+ "12:6": 141,
+ "8:13": true,
+ "10:9": true,
+ "7:7": true,
+ "13:8": true,
+ "9:9": true,
+ "11:6": 141,
+ "10:7": [
+ 139,
+ 168
+ ],
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:12": true,
+ "9:7": true,
+ "0:5": true,
+ "12:3": [
+ 111,
+ 177
+ ],
+ "11:4": [
+ 173,
+ 179
+ ],
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "15:10": true,
+ "14:10": true,
+ "5:6": true,
+ "13:7": true,
+ "12:4": [
+ 173,
+ 177
+ ],
+ "11:3": true,
+ "15:13": true,
+ "12:2": true,
+ "6:7": true,
+ "11:2": true,
+ "13:9": true,
+ "9:8": true,
+ "14:13": true,
+ "10:4": true,
+ "5:9": true,
+ "1:5": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "7:4": true,
+ "13:6": [
+ 141,
+ 143
+ ],
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "12:8": true,
+ "7:3": true,
+ "14:11": true,
+ "13:2": [
+ 129,
+ 132
+ ],
+ "9:6": true,
+ "6:4": true,
+ "10:6": [
+ 141,
+ 216
+ ],
+ "15:11": true,
+ "12:9": true,
+ "6:3": true,
+ "11:7": [
+ 139,
+ 140
+ ],
+ "2:5": true,
+ "5:8": true,
+ "13:4": true,
+ "12:7": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "1:6": true,
+ "11:10": true,
+ "6:5": true,
+ "3:8": true,
+ "12:10": true,
+ "2:2": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "2:4": true,
+ "13:11": true,
+ "8:6": true,
+ "12:13": true,
+ "2:3": true,
+ "14:6": 144,
+ "9:11": true,
+ "3:7": true,
+ "1:3": true,
+ "10:11": true,
+ "9:5": true,
+ "8:2": true,
+ "1:4": true,
+ "0:7": true,
+ "15:6": true,
+ "11:12": true,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "0:9": true,
+ "7:11": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_5.json
index 1174ffa7..db267e0a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_5.json
@@ -1 +1,71 @@
-{"10:4":true,"7:12":true,"7:15":true,"9:4":true,"10:12":true,"3:10":true,"11:8":true,"2:9":true,"13:6":true,"9:15":true,"0:0":true,"9:12":true,"10:2":true,"10:15":true,"12:8":true,"13:15":true,"10:10":true,"4:11":true,"4:1":true,"3:12":true,"10:0":true,"5:11":true,"5:1":true,"3:2":true,"0:12":[221,227],"9:0":true,"6:3":true,"15:8":true,"6:12":true,"0:4":true,"6:15":true,"14:8":true,"2:1":true,"2:11":[217,222],"15:4":true,"2:12":true,"0:8":true,"6:11":true,"6:1":true,"14:4":true,"5:12":true,"14:15":true,"4:2":true,"15:15":true,"3:11":true,"3:1":true,"5:2":true,"14:6":true,"11:4":true,"6:9":true,"8:12":true,"5:10":true,"10:11":true,"10:1":true,"4:10":true,"12:4":true,"8:15":true,"15:6":true,"12:15":true,"10:8":true,"11:15":true,"1:12":224,"9:8":true} \ No newline at end of file
+{
+ "10:4": true,
+ "7:12": true,
+ "7:15": true,
+ "9:4": true,
+ "10:12": true,
+ "3:10": true,
+ "11:8": true,
+ "2:9": true,
+ "13:6": true,
+ "9:15": true,
+ "0:0": true,
+ "9:12": true,
+ "10:2": true,
+ "10:15": true,
+ "12:8": true,
+ "13:15": true,
+ "10:10": true,
+ "4:11": true,
+ "4:1": true,
+ "3:12": true,
+ "10:0": true,
+ "5:11": true,
+ "5:1": true,
+ "3:2": true,
+ "0:12": [
+ 221,
+ 227
+ ],
+ "9:0": true,
+ "6:3": true,
+ "15:8": true,
+ "6:12": true,
+ "0:4": true,
+ "6:15": true,
+ "14:8": true,
+ "2:1": true,
+ "2:11": [
+ 217,
+ 222
+ ],
+ "15:4": true,
+ "2:12": true,
+ "0:8": true,
+ "6:11": true,
+ "6:1": true,
+ "14:4": true,
+ "5:12": true,
+ "14:15": true,
+ "4:2": true,
+ "15:15": true,
+ "3:11": true,
+ "3:1": true,
+ "5:2": true,
+ "14:6": true,
+ "11:4": true,
+ "6:9": true,
+ "8:12": true,
+ "5:10": true,
+ "10:11": true,
+ "10:1": true,
+ "4:10": true,
+ "12:4": true,
+ "8:15": true,
+ "15:6": true,
+ "12:15": true,
+ "10:8": true,
+ "11:15": true,
+ "1:12": 224,
+ "9:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_6.json
index 19d48785..a0f17d70 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_6.json
@@ -1 +1,133 @@
-{"11:5":true,"2:7":true,"6:10":true,"12:5":true,"11:11":true,"2:9":true,"0:6":true,"8:1":true,"3:6":true,"13:10":true,"1:8":true,"14:1":true,"10:10":true,"5:5":true,"2:8":true,"9:10":true,"4:5":true,"15:1":true,"1:9":true,"3:4":true,"0:3":true,"7:10":true,"3:3":true,"1:7":true,"0:4":true,"11:0":true,"12:6":true,"4:3":true,"5:4":true,"7:7":true,"5:3":true,"1:10":true,"13:8":true,"12:0":true,"6:1":true,"11:6":true,"4:4":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"13:1":true,"0:5":true,"12:3":true,"9:1":true,"7:8":true,"6:9":true,"4:6":true,"10:1":true,"5:6":true,"12:4":true,"12:2":true,"2:10":true,"6:7":true,"11:2":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:3":true,"1:5":true,"7:2":true,"6:6":true,"11:1":true,"9:4":true,"8:5":true,"3:10":true,"11:8":true,"7:4":true,"13:6":true,"13:0":true,"0:10":true,"12:8":true,"7:3":true,"13:2":true,"9:6":true,"11:9":true,"6:4":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"15:11":[130,151],"12:9":true,"9:0":true,"6:3":true,"7:0":true,"13:3":true,"2:5":true,"13:4":true,"6:2":true,"7:6":true,"15:4":true,"14:3":true,"1:6":true,"11:10":true,"6:5":true,"3:8":true,"12:10":true,"0:8":true,"15:3":true,"14:4":true,"2:4":true,"8:0":true,"14:2":true,"4:15":true,"15:2":true,"8:6":true,"13:5":true,"5:15":222,"2:3":true,"15:0":true,"14:6":true,"10:5":true,"3:7":true,"1:3":true,"9:5":true,"8:2":true,"1:4":true,"0:7":true,"15:6":true,"14:0":true,"8:4":true,"7:5":true,"3:9":true,"8:3":true,"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "11:5": true,
+ "2:7": true,
+ "6:10": true,
+ "12:5": true,
+ "11:11": true,
+ "2:9": true,
+ "0:6": true,
+ "8:1": true,
+ "3:6": true,
+ "13:10": true,
+ "1:8": true,
+ "14:1": true,
+ "10:10": true,
+ "5:5": true,
+ "2:8": true,
+ "9:10": true,
+ "4:5": true,
+ "15:1": true,
+ "1:9": true,
+ "3:4": true,
+ "0:3": true,
+ "7:10": true,
+ "3:3": true,
+ "1:7": true,
+ "0:4": true,
+ "11:0": true,
+ "12:6": true,
+ "4:3": true,
+ "5:4": true,
+ "7:7": true,
+ "5:3": true,
+ "1:10": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": true,
+ "11:6": true,
+ "4:4": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "13:1": true,
+ "0:5": true,
+ "12:3": true,
+ "9:1": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "10:1": true,
+ "5:6": true,
+ "12:4": true,
+ "12:2": true,
+ "2:10": true,
+ "6:7": true,
+ "11:2": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:3": true,
+ "1:5": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "3:10": true,
+ "11:8": true,
+ "7:4": true,
+ "13:6": true,
+ "13:0": true,
+ "0:10": true,
+ "12:8": true,
+ "7:3": true,
+ "13:2": true,
+ "9:6": true,
+ "11:9": true,
+ "6:4": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "15:11": [
+ 130,
+ 151
+ ],
+ "12:9": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "2:5": true,
+ "13:4": true,
+ "6:2": true,
+ "7:6": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "11:10": true,
+ "6:5": true,
+ "3:8": true,
+ "12:10": true,
+ "0:8": true,
+ "15:3": true,
+ "14:4": true,
+ "2:4": true,
+ "8:0": true,
+ "14:2": true,
+ "4:15": true,
+ "15:2": true,
+ "8:6": true,
+ "13:5": true,
+ "5:15": 222,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "10:5": true,
+ "3:7": true,
+ "1:3": true,
+ "9:5": true,
+ "8:2": true,
+ "1:4": true,
+ "0:7": true,
+ "15:6": true,
+ "14:0": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "8:3": true,
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_7.json
index 16de57fc..93cf5660 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_7.json
@@ -1 +1,4 @@
-{"14:15":true,"15:15":true} \ No newline at end of file
+{
+ "14:15": true,
+ "15:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_8.json
index ff34c0ae..6bf7f26c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_8.json
@@ -1 +1,36 @@
-{"9:14":157,"10:14":[157,158],"7:15":153,"13:10":true,"3:15":153,"15:1":true,"15:8":true,"3:4":true,"0:3":true,"0:14":[152,154],"6:15":[153,154],"14:8":true,"10:9":156,"2:15":[151,177],"5:15":153,"2:3":true,"15:0":true,"1:3":true,"1:14":177,"11:14":true,"1:15":true,"13:9":true} \ No newline at end of file
+{
+ "9:14": 157,
+ "10:14": [
+ 157,
+ 158
+ ],
+ "7:15": 153,
+ "13:10": true,
+ "3:15": 153,
+ "15:1": true,
+ "15:8": true,
+ "3:4": true,
+ "0:3": true,
+ "0:14": [
+ 152,
+ 154
+ ],
+ "6:15": [
+ 153,
+ 154
+ ],
+ "14:8": true,
+ "10:9": 156,
+ "2:15": [
+ 151,
+ 177
+ ],
+ "5:15": 153,
+ "2:3": true,
+ "15:0": true,
+ "1:3": true,
+ "1:14": 177,
+ "11:14": true,
+ "1:15": true,
+ "13:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_9.json
index 022335ab..9c1516a2 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-3_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-3_9.json
@@ -1 +1,24 @@
-{"1:1":[142,145],"3:0":true,"9:2":true,"0:0":true,"8:1":true,"7:3":true,"3:2":true,"2:1":true,"5:3":true,"2:2":141,"1:0":true,"14:2":true,"15:2":true,"5:0":true,"10:1":true,"8:2":true,"4:0":true,"2:0":true,"8:3":true} \ No newline at end of file
+{
+ "1:1": [
+ 142,
+ 145
+ ],
+ "3:0": true,
+ "9:2": true,
+ "0:0": true,
+ "8:1": true,
+ "7:3": true,
+ "3:2": true,
+ "2:1": true,
+ "5:3": true,
+ "2:2": 141,
+ "1:0": true,
+ "14:2": true,
+ "15:2": true,
+ "5:0": true,
+ "10:1": true,
+ "8:2": true,
+ "4:0": true,
+ "2:0": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-1.json
index cebe97d4..11ba2b08 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-1.json
@@ -1 +1,50 @@
-{"0:6":[145,202],"0:0":true,"1:8":true,"0:2":[198,202],"15:8":true,"0:3":[198,202],"0:4":[143,202],"14:8":true,"0:11":true,"0:5":[198,202],"0:13":[198,202],"0:10":true,"0:15":true,"0:12":true,"7:0":[141,142],"0:14":[202,240],"1:6":true,"0:8":true,"0:1":true,"0:7":[198,202],"0:9":true} \ No newline at end of file
+{
+ "0:6": [
+ 145,
+ 202
+ ],
+ "0:0": true,
+ "1:8": true,
+ "0:2": [
+ 198,
+ 202
+ ],
+ "15:8": true,
+ "0:3": [
+ 198,
+ 202
+ ],
+ "0:4": [
+ 143,
+ 202
+ ],
+ "14:8": true,
+ "0:11": true,
+ "0:5": [
+ 198,
+ 202
+ ],
+ "0:13": [
+ 198,
+ 202
+ ],
+ "0:10": true,
+ "0:15": true,
+ "0:12": true,
+ "7:0": [
+ 141,
+ 142
+ ],
+ "0:14": [
+ 202,
+ 240
+ ],
+ "1:6": true,
+ "0:8": true,
+ "0:1": true,
+ "0:7": [
+ 198,
+ 202
+ ],
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-5.json
index e7de5fa3..879e632f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-5.json
@@ -1 +1,20 @@
-{"2:7":true,"7:15":209,"3:6":214,"3:4":215,"2:5":215,"1:7":164,"6:15":208,"1:6":[163,164],"3:8":214,"3:5":214,"2:4":216,"2:3":216,"3:7":214,"3:9":true,"2:6":true} \ No newline at end of file
+{
+ "2:7": true,
+ "7:15": 209,
+ "3:6": 214,
+ "3:4": 215,
+ "2:5": 215,
+ "1:7": 164,
+ "6:15": 208,
+ "1:6": [
+ 163,
+ 164
+ ],
+ "3:8": 214,
+ "3:5": 214,
+ "2:4": 216,
+ "2:3": 216,
+ "3:7": 214,
+ "3:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-6.json
index 63ccec79..5e345adf 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_-6.json
@@ -1 +1,21 @@
-{"3:12":true,"4:3":true,"5:0":true,"2:12":true,"5:1":true,"5:6":true,"4:5":true,"0:12":[220,226],"4:9":true,"5:7":true,"5:8":true,"1:12":[219,226],"5:2":true} \ No newline at end of file
+{
+ "3:12": true,
+ "4:3": true,
+ "5:0": true,
+ "2:12": true,
+ "5:1": true,
+ "5:6": true,
+ "4:5": true,
+ "0:12": [
+ 220,
+ 226
+ ],
+ "4:9": true,
+ "5:7": true,
+ "5:8": true,
+ "1:12": [
+ 219,
+ 226
+ ],
+ "5:2": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_0.json
index fac56be4..74ee4eb5 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_0.json
@@ -1 +1,102 @@
-{"15:9":true,"2:7":true,"8:8":true,"7:12":true,"6:10":true,"14:9":true,"2:9":true,"15:7":true,"0:6":true,"0:0":true,"14:7":true,"9:12":true,"3:6":true,"13:10":true,"1:8":true,"10:10":true,"8:7":232,"0:2":true,"2:8":true,"9:10":true,"1:9":true,"15:8":true,"0:3":true,"8:9":true,"7:10":true,"6:12":true,"1:7":true,"0:4":true,"14:8":true,"12:6":true,"10:9":true,"7:7":232,"1:10":true,"13:8":true,"9:9":true,"11:6":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"0:11":true,"9:7":true,"0:5":true,"8:12":true,"7:8":true,"6:9":true,"4:6":231,"15:10":true,"14:10":true,"5:6":231,"13:7":true,"2:10":true,"10:8":true,"6:7":232,"13:9":true,"9:8":true,"5:9":true,"0:13":true,"6:6":231,"4:9":true,"5:7":true,"3:10":true,"11:8":true,"13:6":true,"4:7":true,"0:10":true,"12:8":true,"14:11":true,"9:6":231,"0:15":true,"11:9":true,"10:6":true,"0:12":true,"15:11":true,"12:9":true,"11:7":true,"2:5":true,"0:14":true,"5:8":true,"12:7":true,"7:6":231,"4:8":true,"1:6":true,"11:10":true,"3:8":true,"12:10":true,"0:8":true,"0:1":true,"8:6":231,"14:6":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"4:10":true,"0:7":true,"15:6":true,"3:9":true,"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "14:9": true,
+ "2:9": true,
+ "15:7": true,
+ "0:6": true,
+ "0:0": true,
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "13:10": true,
+ "1:8": true,
+ "10:10": true,
+ "8:7": 232,
+ "0:2": true,
+ "2:8": true,
+ "9:10": true,
+ "1:9": true,
+ "15:8": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "1:7": true,
+ "0:4": true,
+ "14:8": true,
+ "12:6": true,
+ "10:9": true,
+ "7:7": 232,
+ "1:10": true,
+ "13:8": true,
+ "9:9": true,
+ "11:6": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "0:11": true,
+ "9:7": true,
+ "0:5": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": 231,
+ "15:10": true,
+ "14:10": true,
+ "5:6": 231,
+ "13:7": true,
+ "2:10": true,
+ "10:8": true,
+ "6:7": 232,
+ "13:9": true,
+ "9:8": true,
+ "5:9": true,
+ "0:13": true,
+ "6:6": 231,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "13:6": true,
+ "4:7": true,
+ "0:10": true,
+ "12:8": true,
+ "14:11": true,
+ "9:6": 231,
+ "0:15": true,
+ "11:9": true,
+ "10:6": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "12:7": true,
+ "7:6": 231,
+ "4:8": true,
+ "1:6": true,
+ "11:10": true,
+ "3:8": true,
+ "12:10": true,
+ "0:8": true,
+ "0:1": true,
+ "8:6": 231,
+ "14:6": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "4:10": true,
+ "0:7": true,
+ "15:6": true,
+ "3:9": true,
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_1.json
index c1c640ba..2ee90774 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_1.json
@@ -1 +1,28 @@
-{"2:7":true,"0:13":true,"5:7":true,"0:6":true,"0:0":true,"0:10":true,"0:2":true,"0:15":true,"0:12":true,"3:4":true,"0:3":true,"0:14":true,"3:3":true,"0:4":true,"5:4":true,"5:3":true,"14:15":true,"0:11":true,"0:1":true,"2:3":true,"0:5":true,"3:7":true,"1:14":true,"5:6":true,"0:7":true,"0:9":true} \ No newline at end of file
+{
+ "2:7": true,
+ "0:13": true,
+ "5:7": true,
+ "0:6": true,
+ "0:0": true,
+ "0:10": true,
+ "0:2": true,
+ "0:15": true,
+ "0:12": true,
+ "3:4": true,
+ "0:3": true,
+ "0:14": true,
+ "3:3": true,
+ "0:4": true,
+ "5:4": true,
+ "5:3": true,
+ "14:15": true,
+ "0:11": true,
+ "0:1": true,
+ "2:3": true,
+ "0:5": true,
+ "3:7": true,
+ "1:14": true,
+ "5:6": true,
+ "0:7": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_10.json
index f21789f0..7195ab3e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_10.json
@@ -1 +1,199 @@
-{"15:9":119,"12:11":true,"1:1":true,"11:5":119,"2:7":true,"8:8":true,"6:10":true,"13:13":true,"12:5":119,"14:9":120,"11:11":true,"10:12":true,"2:9":117,"15:7":119,"3:0":true,"0:6":true,"0:0":true,"14:7":119,"3:6":true,"13:10":true,"1:8":true,"10:10":true,"8:7":true,"5:5":120,"0:2":true,"2:8":true,"9:10":true,"4:5":true,"13:12":true,"3:2":true,"1:9":true,"15:8":119,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"1:7":true,"14:8":119,"2:1":true,"12:6":119,"4:3":true,"5:4":true,"10:9":true,"7:7":true,"5:3":true,"1:10":true,"13:8":120,"9:9":true,"6:1":true,"11:6":119,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"4:2":true,"0:11":true,"14:12":true,"9:7":true,"5:2":[121,139],"0:5":true,"11:4":118,"7:8":true,"6:9":true,"4:6":[120,161],"2:13":true,"1:14":true,"15:10":120,"5:0":true,"14:10":true,"5:6":120,"13:7":119,"12:4":[117,118],"11:3":true,"4:0":true,"15:13":true,"10:8":true,"6:7":true,"13:9":true,"9:8":true,"7:1":true,"14:13":true,"9:3":118,"6:0":true,"1:11":true,"10:4":119,"5:9":true,"10:3":[116,118],"1:5":true,"0:13":true,"7:2":true,"6:6":true,"4:9":119,"9:4":119,"8:5":true,"5:7":true,"11:8":true,"7:4":120,"13:6":119,"8:11":true,"4:7":120,"0:10":true,"12:8":120,"7:3":[120,163],"14:11":true,"9:6":true,"4:1":true,"0:15":true,"11:9":true,"6:4":true,"15:5":true,"14:5":118,"10:6":119,"5:1":true,"0:12":true,"15:11":120,"12:9":true,"6:3":[120,141],"11:7":120,"2:5":true,"0:14":true,"5:8":true,"13:4":true,"12:7":119,"6:2":true,"7:6":true,"4:8":120,"15:4":true,"1:6":true,"11:10":true,"6:5":120,"3:8":120,"12:10":true,"2:2":true,"0:8":true,"15:3":true,"1:0":true,"14:4":true,"2:4":true,"13:11":true,"0:1":true,"8:6":true,"3:1":true,"13:5":118,"12:13":true,"2:3":true,"14:6":118,"10:5":119,"9:11":true,"3:7":[120,161],"1:3":true,"10:11":true,"9:5":true,"8:2":true,"1:4":true,"0:7":true,"15:6":[118,161],"2:0":true,"11:12":true,"8:4":119,"1:2":true,"7:5":120,"3:9":[118,119],"12:12":true,"8:3":119,"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": 119,
+ "12:11": true,
+ "1:1": true,
+ "11:5": 119,
+ "2:7": true,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "12:5": 119,
+ "14:9": 120,
+ "11:11": true,
+ "10:12": true,
+ "2:9": 117,
+ "15:7": 119,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "14:7": 119,
+ "3:6": true,
+ "13:10": true,
+ "1:8": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": 120,
+ "0:2": true,
+ "2:8": true,
+ "9:10": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "1:9": true,
+ "15:8": 119,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "1:7": true,
+ "14:8": 119,
+ "2:1": true,
+ "12:6": 119,
+ "4:3": true,
+ "5:4": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "1:10": true,
+ "13:8": 120,
+ "9:9": true,
+ "6:1": true,
+ "11:6": 119,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "4:2": true,
+ "0:11": true,
+ "14:12": true,
+ "9:7": true,
+ "5:2": [
+ 121,
+ 139
+ ],
+ "0:5": true,
+ "11:4": 118,
+ "7:8": true,
+ "6:9": true,
+ "4:6": [
+ 120,
+ 161
+ ],
+ "2:13": true,
+ "1:14": true,
+ "15:10": 120,
+ "5:0": true,
+ "14:10": true,
+ "5:6": 120,
+ "13:7": 119,
+ "12:4": [
+ 117,
+ 118
+ ],
+ "11:3": true,
+ "4:0": true,
+ "15:13": true,
+ "10:8": true,
+ "6:7": true,
+ "13:9": true,
+ "9:8": true,
+ "7:1": true,
+ "14:13": true,
+ "9:3": 118,
+ "6:0": true,
+ "1:11": true,
+ "10:4": 119,
+ "5:9": true,
+ "10:3": [
+ 116,
+ 118
+ ],
+ "1:5": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": 119,
+ "9:4": 119,
+ "8:5": true,
+ "5:7": true,
+ "11:8": true,
+ "7:4": 120,
+ "13:6": 119,
+ "8:11": true,
+ "4:7": 120,
+ "0:10": true,
+ "12:8": 120,
+ "7:3": [
+ 120,
+ 163
+ ],
+ "14:11": true,
+ "9:6": true,
+ "4:1": true,
+ "0:15": true,
+ "11:9": true,
+ "6:4": true,
+ "15:5": true,
+ "14:5": 118,
+ "10:6": 119,
+ "5:1": true,
+ "0:12": true,
+ "15:11": 120,
+ "12:9": true,
+ "6:3": [
+ 120,
+ 141
+ ],
+ "11:7": 120,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "13:4": true,
+ "12:7": 119,
+ "6:2": true,
+ "7:6": true,
+ "4:8": 120,
+ "15:4": true,
+ "1:6": true,
+ "11:10": true,
+ "6:5": 120,
+ "3:8": 120,
+ "12:10": true,
+ "2:2": true,
+ "0:8": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "2:4": true,
+ "13:11": true,
+ "0:1": true,
+ "8:6": true,
+ "3:1": true,
+ "13:5": 118,
+ "12:13": true,
+ "2:3": true,
+ "14:6": 118,
+ "10:5": 119,
+ "9:11": true,
+ "3:7": [
+ 120,
+ 161
+ ],
+ "1:3": true,
+ "10:11": true,
+ "9:5": true,
+ "8:2": true,
+ "1:4": true,
+ "0:7": true,
+ "15:6": [
+ 118,
+ 161
+ ],
+ "2:0": true,
+ "11:12": true,
+ "8:4": 119,
+ "1:2": true,
+ "7:5": 120,
+ "3:9": [
+ 118,
+ 119
+ ],
+ "12:12": true,
+ "8:3": 119,
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_11.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_11.json
index 94a5299b..442a1304 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_11.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_11.json
@@ -1 +1,13 @@
-{"0:2":[156,158],"0:3":true,"0:1":[157,158],"0:0":true,"0:4":true} \ No newline at end of file
+{
+ "0:2": [
+ 156,
+ 158
+ ],
+ "0:3": true,
+ "0:1": [
+ 157,
+ 158
+ ],
+ "0:0": true,
+ "0:4": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_2.json
index 2663a92a..b3c7f83d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_2.json
@@ -1 +1,21 @@
-{"12:1":true,"10:4":[189,190],"13:0":true,"0:0":true,"0:2":true,"0:3":true,"0:4":true,"7:7":194,"6:5":true,"14:2":187,"13:1":true,"0:1":true,"0:5":true,"14:0":true,"7:5":true,"6:7":true} \ No newline at end of file
+{
+ "12:1": true,
+ "10:4": [
+ 189,
+ 190
+ ],
+ "13:0": true,
+ "0:0": true,
+ "0:2": true,
+ "0:3": true,
+ "0:4": true,
+ "7:7": 194,
+ "6:5": true,
+ "14:2": 187,
+ "13:1": true,
+ "0:1": true,
+ "0:5": true,
+ "14:0": true,
+ "7:5": true,
+ "6:7": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_3.json
index 06368a6b..26198543 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_3.json
@@ -1 +1,37 @@
-{"9:14":true,"10:12":true,"9:15":true,"9:12":true,"9:13":true,"11:0":[150,151],"12:0":176,"12:3":true,"10:1":[155,156],"11:3":true,"12:1":156,"9:3":[175,176],"11:1":[156,176],"9:4":177,"9:2":175,"10:2":176,"0:10":true,"12:13":true,"12:14":true,"12:15":true,"11:12":true,"12:12":true,"0:9":true} \ No newline at end of file
+{
+ "9:14": true,
+ "10:12": true,
+ "9:15": true,
+ "9:12": true,
+ "9:13": true,
+ "11:0": [
+ 150,
+ 151
+ ],
+ "12:0": 176,
+ "12:3": true,
+ "10:1": [
+ 155,
+ 156
+ ],
+ "11:3": true,
+ "12:1": 156,
+ "9:3": [
+ 175,
+ 176
+ ],
+ "11:1": [
+ 156,
+ 176
+ ],
+ "9:4": 177,
+ "9:2": 175,
+ "10:2": 176,
+ "0:10": true,
+ "12:13": true,
+ "12:14": true,
+ "12:15": true,
+ "11:12": true,
+ "12:12": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_4.json
index baade365..521c4837 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_4.json
@@ -1 +1,11 @@
-{"7:13":true,"0:4":138,"12:0":true,"0:5":139,"9:1":true,"10:1":true,"12:1":true,"11:1":true,"9:0":true} \ No newline at end of file
+{
+ "7:13": true,
+ "0:4": 138,
+ "12:0": true,
+ "0:5": 139,
+ "9:1": true,
+ "10:1": true,
+ "12:1": true,
+ "11:1": true,
+ "9:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_5.json
index 43d11448..93ee3533 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_5.json
@@ -1 +1,14 @@
-{"13:3":152,"13:4":true,"14:8":true,"14:3":[138,140],"13:8":true,"15:3":139,"12:0":183,"14:4":true,"12:3":true} \ No newline at end of file
+{
+ "13:3": 152,
+ "13:4": true,
+ "14:8": true,
+ "14:3": [
+ 138,
+ 140
+ ],
+ "13:8": true,
+ "15:3": 139,
+ "12:0": 183,
+ "14:4": true,
+ "12:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_6.json
index 08674183..eeb113d8 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_6.json
@@ -1 +1,25 @@
-{"12:11":true,"9:14":true,"11:11":true,"9:15":true,"9:12":true,"9:13":true,"2:12":true,"0:11":true,"1:13":true,"2:13":true,"1:12":true,"1:11":true,"3:13":true,"0:13":true,"0:10":true,"0:12":true,"0:1":true,"12:13":true,"9:11":true,"12:14":true,"10:11":true,"12:15":true,"12:12":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "11:11": true,
+ "9:15": true,
+ "9:12": true,
+ "9:13": true,
+ "2:12": true,
+ "0:11": true,
+ "1:13": true,
+ "2:13": true,
+ "1:12": true,
+ "1:11": true,
+ "3:13": true,
+ "0:13": true,
+ "0:10": true,
+ "0:12": true,
+ "0:1": true,
+ "12:13": true,
+ "9:11": true,
+ "12:14": true,
+ "10:11": true,
+ "12:15": true,
+ "12:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_7.json
index 82769773..2df26e51 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_7.json
@@ -1 +1,15 @@
-{"1:1":true,"0:2":true,"10:0":true,"9:0":true,"14:8":true,"2:1":true,"11:0":true,"2:2":197,"13:8":true,"12:0":true,"1:0":true,"0:1":true,"2:0":true} \ No newline at end of file
+{
+ "1:1": true,
+ "0:2": true,
+ "10:0": true,
+ "9:0": true,
+ "14:8": true,
+ "2:1": true,
+ "11:0": true,
+ "2:2": 197,
+ "13:8": true,
+ "12:0": true,
+ "1:0": true,
+ "0:1": true,
+ "2:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_8.json
index 6980d16e..059a2de6 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_8.json
@@ -1 +1,76 @@
-{"2:7":true,"8:8":true,"3:6":183,"8:7":137,"0:2":[162,171],"9:10":[157,184],"4:5":162,"13:12":181,"3:4":163,"0:3":[162,172],"8:9":[133,158],"10:9":[132,133],"7:7":183,"9:9":[133,183],"8:10":157,"7:9":133,"6:8":true,"3:5":161,"14:12":[153,180],"5:6":160,"15:13":153,"10:8":[134,182],"6:7":[160,184],"9:8":[135,182],"4:7":true,"11:9":133,"13:3":true,"5:8":true,"14:3":true,"11:10":157,"15:3":true,"2:4":[161,165],"0:1":true,"3:7":true,"1:3":[162,171],"1:4":160,"3:9":true,"2:6":true} \ No newline at end of file
+{
+ "2:7": true,
+ "8:8": true,
+ "3:6": 183,
+ "8:7": 137,
+ "0:2": [
+ 162,
+ 171
+ ],
+ "9:10": [
+ 157,
+ 184
+ ],
+ "4:5": 162,
+ "13:12": 181,
+ "3:4": 163,
+ "0:3": [
+ 162,
+ 172
+ ],
+ "8:9": [
+ 133,
+ 158
+ ],
+ "10:9": [
+ 132,
+ 133
+ ],
+ "7:7": 183,
+ "9:9": [
+ 133,
+ 183
+ ],
+ "8:10": 157,
+ "7:9": 133,
+ "6:8": true,
+ "3:5": 161,
+ "14:12": [
+ 153,
+ 180
+ ],
+ "5:6": 160,
+ "15:13": 153,
+ "10:8": [
+ 134,
+ 182
+ ],
+ "6:7": [
+ 160,
+ 184
+ ],
+ "9:8": [
+ 135,
+ 182
+ ],
+ "4:7": true,
+ "11:9": 133,
+ "13:3": true,
+ "5:8": true,
+ "14:3": true,
+ "11:10": 157,
+ "15:3": true,
+ "2:4": [
+ 161,
+ 165
+ ],
+ "0:1": true,
+ "3:7": true,
+ "1:3": [
+ 162,
+ 171
+ ],
+ "1:4": 160,
+ "3:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_9.json
index 9f64e883..8dd2259d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-4_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-4_9.json
@@ -1 +1,42 @@
-{"1:11":true,"3:13":true,"0:13":true,"3:10":true,"2:9":true,"0:6":true,"0:10":true,"4:11":true,"3:12":true,"0:15":true,"2:8":true,"0:12":true,"1:9":true,"0:14":true,"3:14":true,"2:11":true,"4:14":true,"2:12":true,"5:14":true,"1:10":true,"0:8":true,"4:15":true,"0:11":true,"4:12":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"15:0":true,"2:13":true,"1:14":true,"4:10":true,"0:7":true,"5:13":true,"2:10":true,"1:15":true,"3:9":true,"1:12":true,"0:9":true,"4:13":true} \ No newline at end of file
+{
+ "1:11": true,
+ "3:13": true,
+ "0:13": true,
+ "3:10": true,
+ "2:9": true,
+ "0:6": true,
+ "0:10": true,
+ "4:11": true,
+ "3:12": true,
+ "0:15": true,
+ "2:8": true,
+ "0:12": true,
+ "1:9": true,
+ "0:14": true,
+ "3:14": true,
+ "2:11": true,
+ "4:14": true,
+ "2:12": true,
+ "5:14": true,
+ "1:10": true,
+ "0:8": true,
+ "4:15": true,
+ "0:11": true,
+ "4:12": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "15:0": true,
+ "2:13": true,
+ "1:14": true,
+ "4:10": true,
+ "0:7": true,
+ "5:13": true,
+ "2:10": true,
+ "1:15": true,
+ "3:9": true,
+ "1:12": true,
+ "0:9": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-1.json
index fe872f4b..ad2dba34 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-1.json
@@ -1 +1,56 @@
-{"12:11":true,"12:5":true,"14:1":true,"15:1":true,"14:14":true,"12:6":true,"15:14":240,"12:0":202,"14:15":true,"14:12":[183,186],"12:3":true,"12:4":true,"15:13":198,"12:2":[198,202],"14:13":[144,189],"12:1":[198,202],"11:8":true,"12:8":true,"14:11":[182,183],"12:9":true,"12:7":true,"14:3":[182,183],"12:10":true,"14:2":[183,186],"12:13":true,"15:0":true,"12:14":true,"14:0":[146,192],"12:15":true,"12:12":true} \ No newline at end of file
+{
+ "12:11": true,
+ "12:5": true,
+ "14:1": true,
+ "15:1": true,
+ "14:14": true,
+ "12:6": true,
+ "15:14": 240,
+ "12:0": 202,
+ "14:15": true,
+ "14:12": [
+ 183,
+ 186
+ ],
+ "12:3": true,
+ "12:4": true,
+ "15:13": 198,
+ "12:2": [
+ 198,
+ 202
+ ],
+ "14:13": [
+ 144,
+ 189
+ ],
+ "12:1": [
+ 198,
+ 202
+ ],
+ "11:8": true,
+ "12:8": true,
+ "14:11": [
+ 182,
+ 183
+ ],
+ "12:9": true,
+ "12:7": true,
+ "14:3": [
+ 182,
+ 183
+ ],
+ "12:10": true,
+ "14:2": [
+ 183,
+ 186
+ ],
+ "12:13": true,
+ "15:0": true,
+ "12:14": true,
+ "14:0": [
+ 146,
+ 192
+ ],
+ "12:15": true,
+ "12:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-2.json
index 4ba1b08a..f45f2e4f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-2.json
@@ -1 +1,53 @@
-{"15:9":true,"12:11":202,"12:1":true,"12:5":true,"14:9":true,"14:7":[182,183],"12:8":true,"14:11":[155,198],"12:9":true,"12:7":true,"14:8":[183,186],"14:14":[148,198],"12:6":true,"12:10":true,"12:0":true,"14:15":[147,198],"15:15":true,"14:12":[152,198],"12:13":true,"12:14":true,"12:3":true,"14:10":[156,198],"12:4":true,"12:15":202,"12:2":true,"12:12":202,"14:13":[150,198]} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": 202,
+ "12:1": true,
+ "12:5": true,
+ "14:9": true,
+ "14:7": [
+ 182,
+ 183
+ ],
+ "12:8": true,
+ "14:11": [
+ 155,
+ 198
+ ],
+ "12:9": true,
+ "12:7": true,
+ "14:8": [
+ 183,
+ 186
+ ],
+ "14:14": [
+ 148,
+ 198
+ ],
+ "12:6": true,
+ "12:10": true,
+ "12:0": true,
+ "14:15": [
+ 147,
+ 198
+ ],
+ "15:15": true,
+ "14:12": [
+ 152,
+ 198
+ ],
+ "12:13": true,
+ "12:14": true,
+ "12:3": true,
+ "14:10": [
+ 156,
+ 198
+ ],
+ "12:4": true,
+ "12:15": 202,
+ "12:2": true,
+ "12:12": 202,
+ "14:13": [
+ 150,
+ 198
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-3.json
index d86589b5..d3194487 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-3.json
@@ -1 +1,50 @@
-{"12:11":true,"12:1":true,"12:5":true,"14:9":true,"14:7":true,"12:8":true,"14:11":true,"15:5":true,"14:5":true,"12:9":true,"12:7":true,"14:8":true,"14:14":[183,186],"14:3":[182,183],"12:6":true,"12:10":true,"12:0":true,"14:4":[183,186],"14:15":[182,183],"14:12":true,"12:13":true,"14:6":true,"12:14":true,"12:3":[198,202],"14:10":true,"12:4":true,"12:15":true,"12:2":[198,202],"12:12":true,"14:13":true} \ No newline at end of file
+{
+ "12:11": true,
+ "12:1": true,
+ "12:5": true,
+ "14:9": true,
+ "14:7": true,
+ "12:8": true,
+ "14:11": true,
+ "15:5": true,
+ "14:5": true,
+ "12:9": true,
+ "12:7": true,
+ "14:8": true,
+ "14:14": [
+ 183,
+ 186
+ ],
+ "14:3": [
+ 182,
+ 183
+ ],
+ "12:6": true,
+ "12:10": true,
+ "12:0": true,
+ "14:4": [
+ 183,
+ 186
+ ],
+ "14:15": [
+ 182,
+ 183
+ ],
+ "14:12": true,
+ "12:13": true,
+ "14:6": true,
+ "12:14": true,
+ "12:3": [
+ 198,
+ 202
+ ],
+ "14:10": true,
+ "12:4": true,
+ "12:15": true,
+ "12:2": [
+ 198,
+ 202
+ ],
+ "12:12": true,
+ "14:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-4.json
index 72b3a2bf..ccc6a675 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-4.json
@@ -1 +1,143 @@
-{"15:9":220,"12:11":true,"7:12":220,"13:13":220,"14:9":[164,193],"11:11":222,"10:12":222,"3:0":[201,202],"0:0":true,"14:7":[164,192],"9:12":[214,222],"13:10":222,"10:10":222,"7:13":[219,220],"9:10":true,"4:5":177,"13:12":222,"10:13":219,"3:4":[201,202],"7:10":220,"0:4":204,"14:8":true,"9:13":true,"5:4":[177,203],"10:9":219,"9:9":220,"4:4":[201,202],"8:10":true,"7:9":[219,220],"3:5":[175,177],"15:12":222,"0:11":true,"14:12":true,"1:13":true,"0:5":176,"8:12":222,"15:10":222,"14:10":[162,222],"15:13":220,"1:12":true,"13:9":220,"1:5":178,"8:11":222,"14:11":[162,222],"14:5":[172,188],"0:12":true,"15:11":222,"12:9":219,"6:3":177,"13:3":184,"2:5":[176,178],"3:14":true,"15:4":[182,184],"11:10":222,"12:10":222,"15:3":175,"1:0":true,"14:4":[173,184],"2:4":[202,203],"13:11":222,"12:13":[198,219],"14:6":[167,191],"12:14":[198,202],"9:11":222,"10:11":222,"1:4":[203,204],"15:6":190,"2:0":[202,203],"12:15":true,"11:12":222,"12:12":[198,222],"0:9":true} \ No newline at end of file
+{
+ "15:9": 220,
+ "12:11": true,
+ "7:12": 220,
+ "13:13": 220,
+ "14:9": [
+ 164,
+ 193
+ ],
+ "11:11": 222,
+ "10:12": 222,
+ "3:0": [
+ 201,
+ 202
+ ],
+ "0:0": true,
+ "14:7": [
+ 164,
+ 192
+ ],
+ "9:12": [
+ 214,
+ 222
+ ],
+ "13:10": 222,
+ "10:10": 222,
+ "7:13": [
+ 219,
+ 220
+ ],
+ "9:10": true,
+ "4:5": 177,
+ "13:12": 222,
+ "10:13": 219,
+ "3:4": [
+ 201,
+ 202
+ ],
+ "7:10": 220,
+ "0:4": 204,
+ "14:8": true,
+ "9:13": true,
+ "5:4": [
+ 177,
+ 203
+ ],
+ "10:9": 219,
+ "9:9": 220,
+ "4:4": [
+ 201,
+ 202
+ ],
+ "8:10": true,
+ "7:9": [
+ 219,
+ 220
+ ],
+ "3:5": [
+ 175,
+ 177
+ ],
+ "15:12": 222,
+ "0:11": true,
+ "14:12": true,
+ "1:13": true,
+ "0:5": 176,
+ "8:12": 222,
+ "15:10": 222,
+ "14:10": [
+ 162,
+ 222
+ ],
+ "15:13": 220,
+ "1:12": true,
+ "13:9": 220,
+ "1:5": 178,
+ "8:11": 222,
+ "14:11": [
+ 162,
+ 222
+ ],
+ "14:5": [
+ 172,
+ 188
+ ],
+ "0:12": true,
+ "15:11": 222,
+ "12:9": 219,
+ "6:3": 177,
+ "13:3": 184,
+ "2:5": [
+ 176,
+ 178
+ ],
+ "3:14": true,
+ "15:4": [
+ 182,
+ 184
+ ],
+ "11:10": 222,
+ "12:10": 222,
+ "15:3": 175,
+ "1:0": true,
+ "14:4": [
+ 173,
+ 184
+ ],
+ "2:4": [
+ 202,
+ 203
+ ],
+ "13:11": 222,
+ "12:13": [
+ 198,
+ 219
+ ],
+ "14:6": [
+ 167,
+ 191
+ ],
+ "12:14": [
+ 198,
+ 202
+ ],
+ "9:11": 222,
+ "10:11": 222,
+ "1:4": [
+ 203,
+ 204
+ ],
+ "15:6": 190,
+ "2:0": [
+ 202,
+ 203
+ ],
+ "12:15": true,
+ "11:12": 222,
+ "12:12": [
+ 198,
+ 222
+ ],
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-5.json
index 39e0ea2a..8d791b4b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-5.json
@@ -1 +1,6 @@
-{"3:0":true,"10:5":true,"5:0":true,"4:0":true} \ No newline at end of file
+{
+ "3:0": true,
+ "10:5": true,
+ "5:0": true,
+ "4:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-6.json
index 20dc2658..b4ec815d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_-6.json
@@ -1 +1,64 @@
-{"11:5":true,"7:12":true,"4:9":true,"11:1":true,"10:12":true,"11:8":true,"3:0":true,"13:6":true,"13:0":true,"9:12":true,"3:6":true,"13:10":230,"12:8":true,"13:2":true,"11:9":true,"4:5":true,"13:12":true,"3:2":true,"13:3":true,"11:7":true,"6:12":true,"13:4":true,"12:7":true,"6:15":true,"11:0":true,"12:6":true,"4:3":true,"11:10":true,"3:8":[214,225],"12:10":true,"13:8":true,"12:0":true,"11:6":true,"15:12":[219,227],"13:1":true,"14:12":[219,227],"3:1":true,"13:5":true,"12:3":true,"11:4":true,"8:12":true,"3:7":[214,226],"13:7":true,"12:4":true,"11:3":true,"12:2":true,"11:12":true,"12:12":true,"11:2":true,"13:9":230} \ No newline at end of file
+{
+ "11:5": true,
+ "7:12": true,
+ "4:9": true,
+ "11:1": true,
+ "10:12": true,
+ "11:8": true,
+ "3:0": true,
+ "13:6": true,
+ "13:0": true,
+ "9:12": true,
+ "3:6": true,
+ "13:10": 230,
+ "12:8": true,
+ "13:2": true,
+ "11:9": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "13:3": true,
+ "11:7": true,
+ "6:12": true,
+ "13:4": true,
+ "12:7": true,
+ "6:15": true,
+ "11:0": true,
+ "12:6": true,
+ "4:3": true,
+ "11:10": true,
+ "3:8": [
+ 214,
+ 225
+ ],
+ "12:10": true,
+ "13:8": true,
+ "12:0": true,
+ "11:6": true,
+ "15:12": [
+ 219,
+ 227
+ ],
+ "13:1": true,
+ "14:12": [
+ 219,
+ 227
+ ],
+ "3:1": true,
+ "13:5": true,
+ "12:3": true,
+ "11:4": true,
+ "8:12": true,
+ "3:7": [
+ 214,
+ 226
+ ],
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "12:2": true,
+ "11:12": true,
+ "12:12": true,
+ "11:2": true,
+ "13:9": 230
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_0.json
index 1a304ed3..03400aad 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_0.json
@@ -1 +1,102 @@
-{"15:9":true,"12:1":true,"12:11":true,"8:8":true,"6:10":true,"5:9":true,"12:5":true,"0:13":true,"14:9":true,"6:6":true,"4:9":true,"5:7":true,"11:8":true,"2:9":true,"15:7":true,"13:6":true,"14:7":[150,232],"4:7":true,"13:10":true,"12:8":true,"1:8":true,"14:11":true,"14:1":true,"8:7":true,"9:6":true,"11:9":true,"14:5":true,"10:6":true,"5:11":true,"3:15":true,"12:9":true,"1:9":true,"15:8":true,"11:7":true,"0:14":true,"8:9":true,"5:8":true,"12:7":true,"14:8":true,"7:6":true,"4:8":true,"14:14":true,"14:3":true,"12:6":true,"10:9":true,"7:7":true,"12:10":true,"13:8":true,"0:8":true,"12:0":true,"9:9":true,"14:4":true,"11:6":true,"10:7":true,"7:9":true,"6:8":true,"5:12":true,"14:15":[150,183],"14:2":true,"14:12":true,"9:7":true,"8:6":true,"12:13":true,"2:14":true,"1:13":true,"12:14":true,"12:3":true,"14:6":[140,231],"7:8":true,"6:9":true,"5:10":true,"4:6":true,"2:13":true,"1:14":true,"15:10":true,"14:10":true,"5:6":true,"4:10":true,"13:7":true,"12:4":true,"15:6":true,"14:0":true,"12:2":true,"12:15":true,"10:8":true,"6:7":true,"3:9":true,"12:12":true,"13:9":true,"9:8":true,"14:13":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:1": true,
+ "12:11": true,
+ "8:8": true,
+ "6:10": true,
+ "5:9": true,
+ "12:5": true,
+ "0:13": true,
+ "14:9": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "11:8": true,
+ "2:9": true,
+ "15:7": true,
+ "13:6": true,
+ "14:7": [
+ 150,
+ 232
+ ],
+ "4:7": true,
+ "13:10": true,
+ "12:8": true,
+ "1:8": true,
+ "14:11": true,
+ "14:1": true,
+ "8:7": true,
+ "9:6": true,
+ "11:9": true,
+ "14:5": true,
+ "10:6": true,
+ "5:11": true,
+ "3:15": true,
+ "12:9": true,
+ "1:9": true,
+ "15:8": true,
+ "11:7": true,
+ "0:14": true,
+ "8:9": true,
+ "5:8": true,
+ "12:7": true,
+ "14:8": true,
+ "7:6": true,
+ "4:8": true,
+ "14:14": true,
+ "14:3": true,
+ "12:6": true,
+ "10:9": true,
+ "7:7": true,
+ "12:10": true,
+ "13:8": true,
+ "0:8": true,
+ "12:0": true,
+ "9:9": true,
+ "14:4": true,
+ "11:6": true,
+ "10:7": true,
+ "7:9": true,
+ "6:8": true,
+ "5:12": true,
+ "14:15": [
+ 150,
+ 183
+ ],
+ "14:2": true,
+ "14:12": true,
+ "9:7": true,
+ "8:6": true,
+ "12:13": true,
+ "2:14": true,
+ "1:13": true,
+ "12:14": true,
+ "12:3": true,
+ "14:6": [
+ 140,
+ 231
+ ],
+ "7:8": true,
+ "6:9": true,
+ "5:10": true,
+ "4:6": true,
+ "2:13": true,
+ "1:14": true,
+ "15:10": true,
+ "14:10": true,
+ "5:6": true,
+ "4:10": true,
+ "13:7": true,
+ "12:4": true,
+ "15:6": true,
+ "14:0": true,
+ "12:2": true,
+ "12:15": true,
+ "10:8": true,
+ "6:7": true,
+ "3:9": true,
+ "12:12": true,
+ "13:9": true,
+ "9:8": true,
+ "14:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_1.json
index 9811e723..4d3f3779 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_1.json
@@ -1 +1,58 @@
-{"14:3":true,"12:1":true,"9:3":true,"1:1":true,"10:3":true,"2:15":true,"1:5":true,"15:3":true,"14:9":true,"12:0":true,"1:0":true,"14:4":true,"9:4":true,"2:4":true,"3:0":true,"14:2":true,"13:0":true,"0:0":true,"14:7":true,"3:1":true,"0:5":true,"7:3":true,"15:0":true,"14:11":[182,183],"14:6":true,"14:1":true,"12:3":true,"12:14":true,"0:15":true,"14:10":[183,186],"14:5":true,"3:15":true,"3:2":true,"1:4":true,"15:1":true,"14:0":[138,202],"2:0":true,"13:3":true,"12:2":true,"2:5":true,"1:15":true,"1:2":true,"12:7":true,"12:12":true,"3:3":true,"0:4":true,"14:8":true} \ No newline at end of file
+{
+ "14:3": true,
+ "12:1": true,
+ "9:3": true,
+ "1:1": true,
+ "10:3": true,
+ "2:15": true,
+ "1:5": true,
+ "15:3": true,
+ "14:9": true,
+ "12:0": true,
+ "1:0": true,
+ "14:4": true,
+ "9:4": true,
+ "2:4": true,
+ "3:0": true,
+ "14:2": true,
+ "13:0": true,
+ "0:0": true,
+ "14:7": true,
+ "3:1": true,
+ "0:5": true,
+ "7:3": true,
+ "15:0": true,
+ "14:11": [
+ 182,
+ 183
+ ],
+ "14:6": true,
+ "14:1": true,
+ "12:3": true,
+ "12:14": true,
+ "0:15": true,
+ "14:10": [
+ 183,
+ 186
+ ],
+ "14:5": true,
+ "3:15": true,
+ "3:2": true,
+ "1:4": true,
+ "15:1": true,
+ "14:0": [
+ 138,
+ 202
+ ],
+ "2:0": true,
+ "13:3": true,
+ "12:2": true,
+ "2:5": true,
+ "1:15": true,
+ "1:2": true,
+ "12:7": true,
+ "12:12": true,
+ "3:3": true,
+ "0:4": true,
+ "14:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_10.json
index abef05f3..3bcb1c7c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_10.json
@@ -1 +1,176 @@
-{"12:11":true,"9:14":true,"1:1":true,"11:5":true,"2:7":true,"6:10":true,"13:13":true,"12:5":true,"11:11":true,"6:13":true,"2:9":true,"15:7":true,"3:0":true,"9:15":true,"0:6":true,"0:0":true,"14:7":true,"3:6":true,"7:14":true,"1:8":true,"14:1":true,"13:15":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"7:13":true,"2:8":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"6:14":true,"1:9":true,"15:8":true,"13:14":true,"3:4":true,"0:3":true,"7:10":true,"6:12":true,"3:3":true,"1:7":true,"0:4":[150,180],"6:15":true,"2:1":true,"14:14":true,"4:3":true,"8:13":true,"5:4":true,"2:12":true,"2:15":true,"1:10":true,"15:14":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"15:15":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"11:4":true,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"1:14":true,"5:0":true,"5:6":true,"8:15":true,"4:0":true,"15:13":true,"2:10":true,"1:15":true,"6:7":true,"8:14":true,"1:12":true,"7:1":true,"14:13":true,"6:0":true,"1:11":true,"10:4":true,"3:13":true,"5:9":true,"1:5":[150,176],"0:13":true,"6:6":true,"4:9":true,"8:5":true,"5:7":true,"13:6":true,"13:0":true,"8:11":true,"4:7":true,"0:10":true,"13:2":true,"4:1":true,"3:12":true,"0:15":true,"6:4":true,"15:5":true,"14:5":true,"5:1":true,"3:15":true,"0:12":true,"15:11":true,"7:0":true,"13:3":true,"2:5":true,"0:14":true,"5:8":true,"3:14":true,"7:6":true,"4:8":true,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"6:5":true,"5:14":true,"2:2":true,"0:8":true,"15:3":true,"1:0":true,"14:4":true,"11:13":true,"5:12":true,"2:4":true,"14:2":true,"4:15":true,"0:1":true,"15:2":true,"8:6":true,"4:12":true,"3:1":true,"13:5":true,"5:15":true,"2:3":true,"15:0":true,"12:14":true,"10:5":true,"5:10":true,"3:7":true,"1:3":150,"9:5":true,"4:10":true,"1:4":true,"0:7":true,"15:6":true,"14:0":true,"2:0":true,"12:15":true,"5:13":true,"1:2":true,"7:5":true,"3:9":true,"12:12":true,"0:9":true,"7:11":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "1:1": true,
+ "11:5": true,
+ "2:7": true,
+ "6:10": true,
+ "13:13": true,
+ "12:5": true,
+ "11:11": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "3:0": true,
+ "9:15": true,
+ "0:6": true,
+ "0:0": true,
+ "14:7": true,
+ "3:6": true,
+ "7:14": true,
+ "1:8": true,
+ "14:1": true,
+ "13:15": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "7:13": true,
+ "2:8": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": true,
+ "1:7": true,
+ "0:4": [
+ 150,
+ 180
+ ],
+ "6:15": true,
+ "2:1": true,
+ "14:14": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "2:12": true,
+ "2:15": true,
+ "1:10": true,
+ "15:14": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "11:4": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "8:15": true,
+ "4:0": true,
+ "15:13": true,
+ "2:10": true,
+ "1:15": true,
+ "6:7": true,
+ "8:14": true,
+ "1:12": true,
+ "7:1": true,
+ "14:13": true,
+ "6:0": true,
+ "1:11": true,
+ "10:4": true,
+ "3:13": true,
+ "5:9": true,
+ "1:5": [
+ 150,
+ 176
+ ],
+ "0:13": true,
+ "6:6": true,
+ "4:9": true,
+ "8:5": true,
+ "5:7": true,
+ "13:6": true,
+ "13:0": true,
+ "8:11": true,
+ "4:7": true,
+ "0:10": true,
+ "13:2": true,
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "6:4": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "7:0": true,
+ "13:3": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "3:14": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "6:5": true,
+ "5:14": true,
+ "2:2": true,
+ "0:8": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "11:13": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "4:15": true,
+ "0:1": true,
+ "15:2": true,
+ "8:6": true,
+ "4:12": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "15:0": true,
+ "12:14": true,
+ "10:5": true,
+ "5:10": true,
+ "3:7": true,
+ "1:3": 150,
+ "9:5": true,
+ "4:10": true,
+ "1:4": true,
+ "0:7": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "12:15": true,
+ "5:13": true,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_2.json
index f2f501c9..976d30de 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_2.json
@@ -1 +1,40 @@
-{"14:3":[151,198],"4:3":true,"5:4":true,"6:5":true,"12:0":true,"14:4":[151,198],"4:4":[155,200],"8:5":true,"4:2":true,"14:7":true,"14:6":true,"13:2":true,"5:5":true,"4:6":true,"4:1":true,"6:4":true,"14:5":true,"4:5":[198,200],"4:0":true,"12:2":true,"7:5":true,"3:3":[154,155],"14:8":true} \ No newline at end of file
+{
+ "14:3": [
+ 151,
+ 198
+ ],
+ "4:3": true,
+ "5:4": true,
+ "6:5": true,
+ "12:0": true,
+ "14:4": [
+ 151,
+ 198
+ ],
+ "4:4": [
+ 155,
+ 200
+ ],
+ "8:5": true,
+ "4:2": true,
+ "14:7": true,
+ "14:6": true,
+ "13:2": true,
+ "5:5": true,
+ "4:6": true,
+ "4:1": true,
+ "6:4": true,
+ "14:5": true,
+ "4:5": [
+ 198,
+ 200
+ ],
+ "4:0": true,
+ "12:2": true,
+ "7:5": true,
+ "3:3": [
+ 154,
+ 155
+ ],
+ "14:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_4.json
index 3ff8084e..3c775a74 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_4.json
@@ -1 +1,10 @@
-{"15:9":true,"14:3":152,"13:8":166,"14:9":166,"15:10":167,"15:8":166,"13:9":166,"14:8":166} \ No newline at end of file
+{
+ "15:9": true,
+ "14:3": 152,
+ "13:8": 166,
+ "14:9": 166,
+ "15:10": 167,
+ "15:8": 166,
+ "13:9": 166,
+ "14:8": 166
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_6.json
index 6e5a9552..92a6e8ef 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_6.json
@@ -1 +1,4 @@
-{"3:10":158,"15:1":149} \ No newline at end of file
+{
+ "3:10": 158,
+ "15:1": 149
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_7.json
index 803a589b..b6239079 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_7.json
@@ -1 +1,32 @@
-{"3:13":true,"0:13":true,"7:15":true,"9:15":true,"10:15":true,"7:14":true,"3:12":true,"0:15":true,"3:15":true,"0:12":true,"6:14":true,"0:14":true,"3:14":true,"6:15":true,"2:11":true,"4:14":true,"2:12":true,"5:14":true,"2:15":true,"4:15":true,"4:12":true,"5:15":true,"2:14":true,"1:13":true,"2:13":true,"1:14":true,"8:15":true,"1:15":true,"1:12":true,"4:13":true} \ No newline at end of file
+{
+ "3:13": true,
+ "0:13": true,
+ "7:15": true,
+ "9:15": true,
+ "10:15": true,
+ "7:14": true,
+ "3:12": true,
+ "0:15": true,
+ "3:15": true,
+ "0:12": true,
+ "6:14": true,
+ "0:14": true,
+ "3:14": true,
+ "6:15": true,
+ "2:11": true,
+ "4:14": true,
+ "2:12": true,
+ "5:14": true,
+ "2:15": true,
+ "4:15": true,
+ "4:12": true,
+ "5:15": true,
+ "2:14": true,
+ "1:13": true,
+ "2:13": true,
+ "1:14": true,
+ "8:15": true,
+ "1:15": true,
+ "1:12": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_8.json
index 3271d484..244c8eb7 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_8.json
@@ -1 +1,183 @@
-{"1:1":true,"2:7":173,"6:10":true,"7:15":true,"6:13":129,"2:9":167,"15:7":true,"3:0":true,"9:15":true,"0:0":true,"14:7":true,"8:1":true,"3:6":true,"10:15":true,"7:14":true,"1:8":[169,173],"14:1":true,"10:10":true,"4:11":130,"0:2":true,"7:13":true,"2:8":[129,174],"5:11":129,"4:5":true,"3:2":true,"6:14":true,"1:9":[168,175],"3:4":true,"0:3":true,"7:10":true,"6:12":true,"3:3":true,"1:7":172,"0:4":true,"6:15":true,"2:1":true,"11:0":true,"12:6":true,"4:3":true,"5:4":true,"2:12":131,"5:3":true,"2:15":[131,151],"1:10":132,"12:0":true,"6:1":true,"4:4":true,"7:9":true,"13:1":true,"4:2":true,"0:11":true,"3:11":131,"5:2":true,"2:14":true,"1:13":true,"0:5":170,"12:3":true,"9:1":true,"6:9":true,"4:6":true,"2:13":true,"1:14":true,"5:0":true,"10:1":true,"5:6":true,"8:15":true,"4:0":true,"12:2":true,"1:15":[131,150],"10:8":true,"11:2":true,"12:1":true,"6:0":true,"10:4":true,"3:13":[131,149],"1:5":true,"0:13":true,"7:2":true,"6:6":true,"11:1":true,"9:4":true,"3:10":130,"7:4":true,"13:6":true,"9:2":true,"13:0":true,"10:2":true,"0:10":133,"13:2":true,"4:1":true,"3:12":131,"0:15":[130,150],"6:4":true,"10:0":true,"14:5":182,"5:1":true,"0:12":true,"9:0":true,"6:3":true,"7:0":true,"13:3":true,"11:7":true,"0:14":true,"3:14":[131,150],"6:2":true,"7:6":true,"2:11":132,"14:3":174,"4:14":131,"11:10":150,"3:8":true,"5:14":true,"2:2":true,"0:8":true,"15:3":[172,173],"1:0":true,"5:12":[130,144],"2:4":true,"8:0":true,"14:2":true,"4:15":true,"0:1":true,"15:2":true,"4:12":130,"3:1":true,"13:5":181,"5:15":131,"2:3":true,"10:5":true,"5:10":true,"3:7":true,"1:3":true,"4:10":128,"8:2":true,"1:4":true,"0:7":130,"15:6":true,"2:0":true,"5:13":130,"1:2":true,"7:5":true,"3:9":true,"11:15":125,"8:3":true,"0:9":132,"7:11":true,"4:13":[131,143],"2:6":true} \ No newline at end of file
+{
+ "1:1": true,
+ "2:7": 173,
+ "6:10": true,
+ "7:15": true,
+ "6:13": 129,
+ "2:9": 167,
+ "15:7": true,
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "14:7": true,
+ "8:1": true,
+ "3:6": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": [
+ 169,
+ 173
+ ],
+ "14:1": true,
+ "10:10": true,
+ "4:11": 130,
+ "0:2": true,
+ "7:13": true,
+ "2:8": [
+ 129,
+ 174
+ ],
+ "5:11": 129,
+ "4:5": true,
+ "3:2": true,
+ "6:14": true,
+ "1:9": [
+ 168,
+ 175
+ ],
+ "3:4": true,
+ "0:3": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": true,
+ "1:7": 172,
+ "0:4": true,
+ "6:15": true,
+ "2:1": true,
+ "11:0": true,
+ "12:6": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": 131,
+ "5:3": true,
+ "2:15": [
+ 131,
+ 151
+ ],
+ "1:10": 132,
+ "12:0": true,
+ "6:1": true,
+ "4:4": true,
+ "7:9": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "3:11": 131,
+ "5:2": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": 170,
+ "12:3": true,
+ "9:1": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "1:14": true,
+ "5:0": true,
+ "10:1": true,
+ "5:6": true,
+ "8:15": true,
+ "4:0": true,
+ "12:2": true,
+ "1:15": [
+ 131,
+ 150
+ ],
+ "10:8": true,
+ "11:2": true,
+ "12:1": true,
+ "6:0": true,
+ "10:4": true,
+ "3:13": [
+ 131,
+ 149
+ ],
+ "1:5": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "3:10": 130,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "0:10": 133,
+ "13:2": true,
+ "4:1": true,
+ "3:12": 131,
+ "0:15": [
+ 130,
+ 150
+ ],
+ "6:4": true,
+ "10:0": true,
+ "14:5": 182,
+ "5:1": true,
+ "0:12": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "0:14": true,
+ "3:14": [
+ 131,
+ 150
+ ],
+ "6:2": true,
+ "7:6": true,
+ "2:11": 132,
+ "14:3": 174,
+ "4:14": 131,
+ "11:10": 150,
+ "3:8": true,
+ "5:14": true,
+ "2:2": true,
+ "0:8": true,
+ "15:3": [
+ 172,
+ 173
+ ],
+ "1:0": true,
+ "5:12": [
+ 130,
+ 144
+ ],
+ "2:4": true,
+ "8:0": true,
+ "14:2": true,
+ "4:15": true,
+ "0:1": true,
+ "15:2": true,
+ "4:12": 130,
+ "3:1": true,
+ "13:5": 181,
+ "5:15": 131,
+ "2:3": true,
+ "10:5": true,
+ "5:10": true,
+ "3:7": true,
+ "1:3": true,
+ "4:10": 128,
+ "8:2": true,
+ "1:4": true,
+ "0:7": 130,
+ "15:6": true,
+ "2:0": true,
+ "5:13": 130,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "11:15": 125,
+ "8:3": true,
+ "0:9": 132,
+ "7:11": true,
+ "4:13": [
+ 131,
+ 143
+ ],
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_9.json
index cee24520..0b058a28 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-5_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-5_9.json
@@ -1 +1,229 @@
-{"1:1":true,"8:8":true,"6:10":true,"13:13":true,"0:6":true,"0:0":true,"3:6":true,"13:15":true,"10:10":true,"8:7":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"13:12":true,"3:2":[123,124],"13:14":true,"3:4":123,"0:3":true,"8:9":true,"7:10":true,"3:3":[123,124],"0:4":true,"2:1":128,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"15:14":true,"9:9":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"4:2":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":true,"2:14":true,"1:13":true,"0:5":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"4:0":true,"15:13":true,"1:15":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"0:13":true,"11:8":true,"13:6":true,"12:8":true,"14:11":true,"13:2":true,"4:1":true,"3:12":true,"0:15":true,"11:9":true,"15:5":true,"14:5":true,"5:1":true,"3:15":true,"0:12":true,"15:11":true,"12:9":true,"11:7":true,"2:5":true,"0:14":true,"13:4":true,"12:7":true,"3:14":true,"2:11":true,"4:14":true,"1:6":true,"11:10":true,"12:10":true,"5:14":true,"2:2":124,"1:0":true,"14:4":true,"5:12":true,"2:4":true,"13:11":true,"4:12":true,"3:1":129,"13:5":true,"2:3":true,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"5:13":true,"1:2":true,"4:13":true,"2:6":true,"15:9":true,"12:11":true,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"14:7":true,"9:12":true,"8:1":true,"13:10":true,"1:8":true,"2:8":true,"6:14":true,"1:9":true,"15:8":true,"10:13":true,"6:12":true,"1:7":true,"6:15":true,"14:8":true,"12:6":true,"1:10":true,"13:8":true,"6:1":true,"11:6":true,"11:4":true,"9:1":true,"8:12":true,"12:3":true,"15:10":true,"14:10":true,"13:7":true,"11:3":true,"12:2":true,"2:10":true,"11:2":true,"8:14":true,"13:9":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"6:6":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"7:3":true,"9:6":true,"10:0":true,"10:6":true,"9:0":127,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"6:5":true,"3:8":true,"0:8":true,"6:11":true,"11:13":true,"8:0":128,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"0:7":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"3:9":true,"12:12":true,"8:3":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "0:6": true,
+ "0:0": true,
+ "3:6": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "13:12": true,
+ "3:2": [
+ 123,
+ 124
+ ],
+ "13:14": true,
+ "3:4": 123,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": [
+ 123,
+ 124
+ ],
+ "0:4": true,
+ "2:1": 128,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": true,
+ "13:6": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": true,
+ "3:14": true,
+ "2:11": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "2:2": 124,
+ "1:0": true,
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "13:11": true,
+ "4:12": true,
+ "3:1": 129,
+ "13:5": true,
+ "2:3": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "5:13": true,
+ "1:2": true,
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": true,
+ "1:8": true,
+ "2:8": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "14:8": true,
+ "12:6": true,
+ "1:10": true,
+ "13:8": true,
+ "6:1": true,
+ "11:6": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "12:3": true,
+ "15:10": true,
+ "14:10": true,
+ "13:7": true,
+ "11:3": true,
+ "12:2": true,
+ "2:10": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "9:6": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": 127,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": 128,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-3.json
index ee4eb238..b06d77d3 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-3.json
@@ -1 +1,22 @@
-{"1:6":true,"5:4":true,"2:7":[174,218],"7:2":true,"0:1":true,"8:1":true,"3:6":true,"2:3":true,"0:5":true,"4:1":true,"0:2":true,"5:0":true,"4:5":true,"3:2":true,"1:4":true,"9:0":true,"6:3":true} \ No newline at end of file
+{
+ "1:6": true,
+ "5:4": true,
+ "2:7": [
+ 174,
+ 218
+ ],
+ "7:2": true,
+ "0:1": true,
+ "8:1": true,
+ "3:6": true,
+ "2:3": true,
+ "0:5": true,
+ "4:1": true,
+ "0:2": true,
+ "5:0": true,
+ "4:5": true,
+ "3:2": true,
+ "1:4": true,
+ "9:0": true,
+ "6:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-4.json
index d839a5ae..0bac7ab9 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-4.json
@@ -1 +1,106 @@
-{"1:1":true,"12:5":true,"3:0":true,"0:0":true,"14:7":true,"9:12":true,"8:1":true,"10:15":true,"7:14":true,"14:1":true,"0:2":true,"13:12":true,"3:2":true,"1:9":true,"15:8":[175,218],"0:3":true,"3:3":true,"0:4":true,"6:15":true,"2:1":true,"11:0":true,"4:3":true,"8:13":true,"5:4":true,"5:3":true,"1:10":true,"13:8":[175,217],"12:0":true,"15:12":true,"4:2":true,"0:11":true,"5:2":true,"1:13":true,"11:4":true,"15:10":true,"5:0":204,"13:7":true,"12:4":true,"1:12":true,"6:0":[203,204],"1:11":true,"10:4":[202,203],"10:3":true,"0:13":true,"9:4":[201,202],"7:4":true,"13:6":true,"9:2":218,"0:10":true,"14:11":true,"4:1":true,"6:4":true,"10:0":true,"5:1":161,"0:12":true,"12:9":true,"9:0":true,"6:3":true,"7:0":[202,218],"13:3":true,"13:4":true,"12:7":true,"14:3":true,"11:10":true,"1:0":true,"8:0":[201,202],"14:2":true,"0:1":true,"8:6":true,"3:1":true,"12:13":true,"1:3":true,"10:11":true,"11:14":true,"1:4":true,"2:0":true,"8:4":[201,202],"1:2":true,"7:5":true,"0:9":true} \ No newline at end of file
+{
+ "1:1": true,
+ "12:5": true,
+ "3:0": true,
+ "0:0": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "14:1": true,
+ "0:2": true,
+ "13:12": true,
+ "3:2": true,
+ "1:9": true,
+ "15:8": [
+ 175,
+ 218
+ ],
+ "0:3": true,
+ "3:3": true,
+ "0:4": true,
+ "6:15": true,
+ "2:1": true,
+ "11:0": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "5:3": true,
+ "1:10": true,
+ "13:8": [
+ 175,
+ 217
+ ],
+ "12:0": true,
+ "15:12": true,
+ "4:2": true,
+ "0:11": true,
+ "5:2": true,
+ "1:13": true,
+ "11:4": true,
+ "15:10": true,
+ "5:0": 204,
+ "13:7": true,
+ "12:4": true,
+ "1:12": true,
+ "6:0": [
+ 203,
+ 204
+ ],
+ "1:11": true,
+ "10:4": [
+ 202,
+ 203
+ ],
+ "10:3": true,
+ "0:13": true,
+ "9:4": [
+ 201,
+ 202
+ ],
+ "7:4": true,
+ "13:6": true,
+ "9:2": 218,
+ "0:10": true,
+ "14:11": true,
+ "4:1": true,
+ "6:4": true,
+ "10:0": true,
+ "5:1": 161,
+ "0:12": true,
+ "12:9": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": [
+ 202,
+ 218
+ ],
+ "13:3": true,
+ "13:4": true,
+ "12:7": true,
+ "14:3": true,
+ "11:10": true,
+ "1:0": true,
+ "8:0": [
+ 201,
+ 202
+ ],
+ "14:2": true,
+ "0:1": true,
+ "8:6": true,
+ "3:1": true,
+ "12:13": true,
+ "1:3": true,
+ "10:11": true,
+ "11:14": true,
+ "1:4": true,
+ "2:0": true,
+ "8:4": [
+ 201,
+ 202
+ ],
+ "1:2": true,
+ "7:5": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-5.json
index 998fbd6c..302a2cfe 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-5.json
@@ -1 +1,102 @@
-{"1:1":true,"8:8":true,"6:10":true,"0:6":true,"0:0":true,"1:8":177,"4:11":true,"0:2":177,"5:11":true,"1:9":177,"3:4":[208,209],"8:9":true,"1:7":true,"6:15":217,"5:3":209,"2:15":true,"1:10":[177,218],"12:0":209,"9:9":true,"7:9":true,"15:12":235,"0:11":177,"3:11":[237,238],"9:1":[210,212],"7:8":true,"6:9":true,"1:14":true,"10:1":[211,212],"6:7":224,"6:0":true,"1:11":[177,237],"1:5":true,"0:13":true,"7:2":[210,211],"11:1":[209,213],"13:0":[209,210],"0:10":177,"3:12":218,"5:1":[196,198],"2:5":true,"0:14":true,"6:2":210,"2:11":[218,237],"5:14":217,"0:8":177,"6:11":true,"1:0":true,"0:1":177,"5:10":true,"4:10":236,"8:2":true,"0:7":true,"14:0":[211,212],"2:0":true,"1:2":177,"0:9":[177,218],"7:11":true,"4:13":[217,218]} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "0:6": true,
+ "0:0": true,
+ "1:8": 177,
+ "4:11": true,
+ "0:2": 177,
+ "5:11": true,
+ "1:9": 177,
+ "3:4": [
+ 208,
+ 209
+ ],
+ "8:9": true,
+ "1:7": true,
+ "6:15": 217,
+ "5:3": 209,
+ "2:15": true,
+ "1:10": [
+ 177,
+ 218
+ ],
+ "12:0": 209,
+ "9:9": true,
+ "7:9": true,
+ "15:12": 235,
+ "0:11": 177,
+ "3:11": [
+ 237,
+ 238
+ ],
+ "9:1": [
+ 210,
+ 212
+ ],
+ "7:8": true,
+ "6:9": true,
+ "1:14": true,
+ "10:1": [
+ 211,
+ 212
+ ],
+ "6:7": 224,
+ "6:0": true,
+ "1:11": [
+ 177,
+ 237
+ ],
+ "1:5": true,
+ "0:13": true,
+ "7:2": [
+ 210,
+ 211
+ ],
+ "11:1": [
+ 209,
+ 213
+ ],
+ "13:0": [
+ 209,
+ 210
+ ],
+ "0:10": 177,
+ "3:12": 218,
+ "5:1": [
+ 196,
+ 198
+ ],
+ "2:5": true,
+ "0:14": true,
+ "6:2": 210,
+ "2:11": [
+ 218,
+ 237
+ ],
+ "5:14": 217,
+ "0:8": 177,
+ "6:11": true,
+ "1:0": true,
+ "0:1": 177,
+ "5:10": true,
+ "4:10": 236,
+ "8:2": true,
+ "0:7": true,
+ "14:0": [
+ 211,
+ 212
+ ],
+ "2:0": true,
+ "1:2": 177,
+ "0:9": [
+ 177,
+ 218
+ ],
+ "7:11": true,
+ "4:13": [
+ 217,
+ 218
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-6.json
index 32fc9d93..a9d5b23b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_-6.json
@@ -1 +1,21 @@
-{"1:6":true,"1:5":true,"0:8":true,"14:15":[209,210],"0:6":true,"0:5":true,"12:8":183,"1:8":true,"1:14":true,"0:15":true,"0:7":true,"1:9":true,"1:15":true,"0:14":true,"1:7":true,"0:9":true} \ No newline at end of file
+{
+ "1:6": true,
+ "1:5": true,
+ "0:8": true,
+ "14:15": [
+ 209,
+ 210
+ ],
+ "0:6": true,
+ "0:5": true,
+ "12:8": 183,
+ "1:8": true,
+ "1:14": true,
+ "0:15": true,
+ "0:7": true,
+ "1:9": true,
+ "1:15": true,
+ "0:14": true,
+ "1:7": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_0.json
index f4ef8dc2..55039193 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_0.json
@@ -1 +1,35 @@
-{"3:13":true,"13:13":true,"10:14":true,"0:13":190,"6:13":true,"7:14":true,"7:13":true,"3:15":true,"6:14":true,"13:14":true,"10:13":true,"0:14":190,"3:14":true,"9:13":true,"14:14":true,"4:14":true,"8:13":true,"5:14":true,"15:14":true,"11:13":true,"12:13":true,"5:15":true,"2:14":190,"1:13":true,"12:14":true,"2:13":true,"1:14":190,"11:14":true,"15:13":true,"5:13":true,"8:14":true,"14:13":true,"4:13":true} \ No newline at end of file
+{
+ "3:13": true,
+ "13:13": true,
+ "10:14": true,
+ "0:13": 190,
+ "6:13": true,
+ "7:14": true,
+ "7:13": true,
+ "3:15": true,
+ "6:14": true,
+ "13:14": true,
+ "10:13": true,
+ "0:14": 190,
+ "3:14": true,
+ "9:13": true,
+ "14:14": true,
+ "4:14": true,
+ "8:13": true,
+ "5:14": true,
+ "15:14": true,
+ "11:13": true,
+ "12:13": true,
+ "5:15": true,
+ "2:14": 190,
+ "1:13": true,
+ "12:14": true,
+ "2:13": true,
+ "1:14": 190,
+ "11:14": true,
+ "15:13": true,
+ "5:13": true,
+ "8:14": true,
+ "14:13": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_1.json
index 7e4d2f51..3c4e65c8 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_1.json
@@ -1 +1,98 @@
-{"1:1":true,"11:5":true,"12:5":true,"3:0":true,"0:0":[190,192],"10:15":true,"1:8":true,"13:15":[198,200],"5:5":true,"2:8":true,"4:5":true,"3:2":true,"15:1":true,"1:9":true,"3:4":true,"0:4":true,"11:0":true,"5:4":true,"12:0":true,"6:1":true,"4:4":true,"3:5":true,"14:15":[198,200],"13:1":true,"15:15":[198,200],"5:2":true,"0:5":true,"11:4":true,"9:1":true,"5:0":true,"12:4":true,"4:0":true,"11:2":true,"7:1":true,"6:0":true,"10:4":true,"1:5":true,"7:2":true,"11:1":true,"8:5":true,"7:4":true,"9:2":true,"13:0":true,"0:10":true,"13:2":true,"6:4":true,"15:5":true,"10:0":true,"14:5":true,"5:1":true,"9:0":true,"7:0":true,"2:5":true,"13:4":true,"4:8":true,"15:4":true,"6:5":true,"3:8":true,"0:8":true,"1:0":[190,192],"14:4":true,"2:4":true,"8:0":true,"15:2":true,"3:1":true,"13:5":true,"15:0":true,"10:5":true,"9:5":true,"1:4":true,"0:7":true,"14:0":true,"2:0":[190,192],"12:15":true,"8:4":true,"1:2":true,"7:5":true,"11:15":true} \ No newline at end of file
+{
+ "1:1": true,
+ "11:5": true,
+ "12:5": true,
+ "3:0": true,
+ "0:0": [
+ 190,
+ 192
+ ],
+ "10:15": true,
+ "1:8": true,
+ "13:15": [
+ 198,
+ 200
+ ],
+ "5:5": true,
+ "2:8": true,
+ "4:5": true,
+ "3:2": true,
+ "15:1": true,
+ "1:9": true,
+ "3:4": true,
+ "0:4": true,
+ "11:0": true,
+ "5:4": true,
+ "12:0": true,
+ "6:1": true,
+ "4:4": true,
+ "3:5": true,
+ "14:15": [
+ 198,
+ 200
+ ],
+ "13:1": true,
+ "15:15": [
+ 198,
+ 200
+ ],
+ "5:2": true,
+ "0:5": true,
+ "11:4": true,
+ "9:1": true,
+ "5:0": true,
+ "12:4": true,
+ "4:0": true,
+ "11:2": true,
+ "7:1": true,
+ "6:0": true,
+ "10:4": true,
+ "1:5": true,
+ "7:2": true,
+ "11:1": true,
+ "8:5": true,
+ "7:4": true,
+ "9:2": true,
+ "13:0": true,
+ "0:10": true,
+ "13:2": true,
+ "6:4": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "5:1": true,
+ "9:0": true,
+ "7:0": true,
+ "2:5": true,
+ "13:4": true,
+ "4:8": true,
+ "15:4": true,
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "1:0": [
+ 190,
+ 192
+ ],
+ "14:4": true,
+ "2:4": true,
+ "8:0": true,
+ "15:2": true,
+ "3:1": true,
+ "13:5": true,
+ "15:0": true,
+ "10:5": true,
+ "9:5": true,
+ "1:4": true,
+ "0:7": true,
+ "14:0": true,
+ "2:0": [
+ 190,
+ 192
+ ],
+ "12:15": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "11:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_2.json
index f01a6ff5..5da29662 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_2.json
@@ -1 +1,19 @@
-{"8:5":true,"8:1":true,"0:15":true,"15:5":176,"8:6":true,"8:2":[198,200],"8:4":[198,200],"8:3":[198,200]} \ No newline at end of file
+{
+ "8:5": true,
+ "8:1": true,
+ "0:15": true,
+ "15:5": 176,
+ "8:6": true,
+ "8:2": [
+ 198,
+ 200
+ ],
+ "8:4": [
+ 198,
+ 200
+ ],
+ "8:3": [
+ 198,
+ 200
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_4.json
index cba2dea8..90cca4a3 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_4.json
@@ -1 +1,141 @@
-{"1:1":true,"8:8":true,"7:12":true,"6:10":true,"10:14":true,"7:15":[147,148],"10:12":true,"6:13":147,"3:0":true,"9:15":true,"0:0":true,"8:1":true,"3:6":true,"10:15":true,"7:14":true,"10:10":true,"8:7":true,"5:5":true,"7:13":true,"9:10":true,"5:11":true,"4:5":true,"3:2":true,"6:14":147,"10:13":true,"3:4":true,"8:9":true,"7:10":true,"6:12":true,"3:3":true,"6:15":[147,148],"2:1":true,"4:3":true,"8:13":true,"5:4":true,"7:7":true,"5:3":true,"2:15":142,"9:9":true,"6:1":true,"4:4":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"4:2":true,"9:7":true,"5:2":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"5:0":true,"5:6":true,"8:15":true,"4:0":true,"6:7":true,"8:14":true,"9:8":true,"7:1":true,"6:0":true,"3:13":143,"5:9":true,"7:2":true,"6:6":true,"4:9":true,"8:5":true,"5:7":true,"3:10":145,"7:4":true,"8:11":true,"4:7":true,"7:3":true,"4:1":true,"3:12":144,"6:4":true,"5:1":true,"3:15":[142,145],"6:3":true,"7:0":true,"2:5":true,"5:8":true,"3:14":142,"6:2":true,"7:6":true,"4:8":true,"4:14":[143,146],"6:5":true,"3:8":true,"5:14":147,"2:2":true,"6:11":true,"1:0":true,"5:12":147,"2:4":true,"4:15":[142,148],"8:6":true,"4:12":[145,146],"3:1":true,"5:15":[147,148],"2:3":true,"5:10":true,"3:7":true,"4:10":[146,147],"8:2":true,"2:0":true,"8:4":true,"5:13":147,"1:2":true,"7:5":true,"3:9":145,"11:15":true,"8:3":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "10:14": true,
+ "7:15": [
+ 147,
+ 148
+ ],
+ "10:12": true,
+ "6:13": 147,
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "8:1": true,
+ "3:6": true,
+ "10:15": true,
+ "7:14": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "7:13": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "3:2": true,
+ "6:14": 147,
+ "10:13": true,
+ "3:4": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": true,
+ "6:15": [
+ 147,
+ 148
+ ],
+ "2:1": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": 142,
+ "9:9": true,
+ "6:1": true,
+ "4:4": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "4:2": true,
+ "9:7": true,
+ "5:2": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "5:0": true,
+ "5:6": true,
+ "8:15": true,
+ "4:0": true,
+ "6:7": true,
+ "8:14": true,
+ "9:8": true,
+ "7:1": true,
+ "6:0": true,
+ "3:13": 143,
+ "5:9": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": 145,
+ "7:4": true,
+ "8:11": true,
+ "4:7": true,
+ "7:3": true,
+ "4:1": true,
+ "3:12": 144,
+ "6:4": true,
+ "5:1": true,
+ "3:15": [
+ 142,
+ 145
+ ],
+ "6:3": true,
+ "7:0": true,
+ "2:5": true,
+ "5:8": true,
+ "3:14": 142,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "4:14": [
+ 143,
+ 146
+ ],
+ "6:5": true,
+ "3:8": true,
+ "5:14": 147,
+ "2:2": true,
+ "6:11": true,
+ "1:0": true,
+ "5:12": 147,
+ "2:4": true,
+ "4:15": [
+ 142,
+ 148
+ ],
+ "8:6": true,
+ "4:12": [
+ 145,
+ 146
+ ],
+ "3:1": true,
+ "5:15": [
+ 147,
+ 148
+ ],
+ "2:3": true,
+ "5:10": true,
+ "3:7": true,
+ "4:10": [
+ 146,
+ 147
+ ],
+ "8:2": true,
+ "2:0": true,
+ "8:4": true,
+ "5:13": 147,
+ "1:2": true,
+ "7:5": true,
+ "3:9": 145,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_5.json
index 46aeccfe..030b4d97 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_5.json
@@ -1 +1,178 @@
-{"9:14":true,"1:1":true,"11:5":true,"2:7":true,"8:8":true,"7:12":true,"6:10":true,"12:5":true,"10:14":true,"7:15":true,"10:12":true,"6:13":true,"2:9":true,"9:15":true,"9:12":true,"8:1":147,"3:6":145,"10:15":true,"7:14":true,"10:10":true,"8:7":true,"5:5":147,"4:11":147,"7:13":true,"2:8":true,"9:10":true,"5:11":true,"4:5":[145,146],"6:14":true,"10:13":true,"3:4":143,"8:9":true,"7:10":true,"6:12":true,"6:15":true,"9:13":true,"12:6":true,"4:3":[144,146],"8:13":true,"5:4":147,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"1:10":true,"9:9":true,"6:1":147,"11:6":true,"4:4":[144,146],"10:7":true,"8:10":true,"7:9":true,"6:8":147,"3:5":144,"4:2":[144,146],"9:7":true,"5:2":147,"2:14":146,"0:5":true,"4:6":146,"12:3":true,"11:4":true,"9:1":true,"8:12":true,"7:8":true,"6:9":true,"2:13":[145,147],"5:0":147,"10:1":true,"5:6":147,"8:15":true,"13:7":true,"12:4":true,"11:3":true,"4:0":[143,146],"2:10":true,"10:8":true,"6:7":147,"11:2":true,"8:14":true,"9:8":true,"7:1":147,"9:3":true,"6:0":147,"10:4":true,"3:13":147,"5:9":147,"10:3":true,"1:5":true,"7:2":147,"6:6":147,"4:9":147,"11:1":true,"9:4":true,"8:5":true,"5:7":147,"3:10":true,"11:8":true,"7:4":147,"13:6":true,"9:2":true,"8:11":true,"4:7":146,"10:2":true,"12:8":true,"7:3":147,"9:6":true,"4:1":[145,146],"6:4":147,"10:0":true,"10:6":true,"5:1":147,"3:15":true,"9:0":true,"6:3":true,"7:0":147,"11:7":true,"5:8":147,"3:14":true,"6:2":147,"7:6":true,"4:8":147,"2:11":true,"4:14":true,"6:5":147,"3:8":true,"5:14":true,"6:11":true,"5:12":true,"8:0":true,"4:15":true,"0:1":true,"8:6":true,"4:12":147,"5:15":true,"13:5":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"9:5":true,"4:10":147,"11:14":true,"8:2":true,"11:12":true,"8:4":true,"5:13":true,"7:5":147,"3:9":true,"11:15":true,"8:3":147,"7:11":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:1": true,
+ "11:5": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "9:15": true,
+ "9:12": true,
+ "8:1": 147,
+ "3:6": 145,
+ "10:15": true,
+ "7:14": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": 147,
+ "4:11": 147,
+ "7:13": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": [
+ 145,
+ 146
+ ],
+ "6:14": true,
+ "10:13": true,
+ "3:4": 143,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "6:15": true,
+ "9:13": true,
+ "12:6": true,
+ "4:3": [
+ 144,
+ 146
+ ],
+ "8:13": true,
+ "5:4": 147,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "1:10": true,
+ "9:9": true,
+ "6:1": 147,
+ "11:6": true,
+ "4:4": [
+ 144,
+ 146
+ ],
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": 147,
+ "3:5": 144,
+ "4:2": [
+ 144,
+ 146
+ ],
+ "9:7": true,
+ "5:2": 147,
+ "2:14": 146,
+ "0:5": true,
+ "4:6": 146,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "2:13": [
+ 145,
+ 147
+ ],
+ "5:0": 147,
+ "10:1": true,
+ "5:6": 147,
+ "8:15": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "4:0": [
+ 143,
+ 146
+ ],
+ "2:10": true,
+ "10:8": true,
+ "6:7": 147,
+ "11:2": true,
+ "8:14": true,
+ "9:8": true,
+ "7:1": 147,
+ "9:3": true,
+ "6:0": 147,
+ "10:4": true,
+ "3:13": 147,
+ "5:9": 147,
+ "10:3": true,
+ "1:5": true,
+ "7:2": 147,
+ "6:6": 147,
+ "4:9": 147,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": 147,
+ "3:10": true,
+ "11:8": true,
+ "7:4": 147,
+ "13:6": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": 146,
+ "10:2": true,
+ "12:8": true,
+ "7:3": 147,
+ "9:6": true,
+ "4:1": [
+ 145,
+ 146
+ ],
+ "6:4": 147,
+ "10:0": true,
+ "10:6": true,
+ "5:1": 147,
+ "3:15": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": 147,
+ "11:7": true,
+ "5:8": 147,
+ "3:14": true,
+ "6:2": 147,
+ "7:6": true,
+ "4:8": 147,
+ "2:11": true,
+ "4:14": true,
+ "6:5": 147,
+ "3:8": true,
+ "5:14": true,
+ "6:11": true,
+ "5:12": true,
+ "8:0": true,
+ "4:15": true,
+ "0:1": true,
+ "8:6": true,
+ "4:12": 147,
+ "5:15": true,
+ "13:5": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "9:5": true,
+ "4:10": 147,
+ "11:14": true,
+ "8:2": true,
+ "11:12": true,
+ "8:4": true,
+ "5:13": true,
+ "7:5": 147,
+ "3:9": true,
+ "11:15": true,
+ "8:3": 147,
+ "7:11": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_6.json
index 303f3022..9eac7411 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_6.json
@@ -1 +1,114 @@
-{"1:1":true,"2:7":true,"6:10":true,"2:9":true,"3:0":true,"8:1":true,"3:6":true,"5:5":true,"4:11":true,"2:8":true,"5:11":true,"4:5":true,"3:2":true,"1:9":true,"13:14":148,"3:4":true,"7:10":true,"6:12":true,"3:3":true,"6:15":true,"2:1":true,"4:3":true,"5:4":true,"2:12":true,"7:7":true,"5:3":true,"6:1":true,"4:4":true,"7:9":true,"6:8":true,"3:5":true,"4:2":true,"3:11":true,"5:2":true,"2:14":148,"9:1":true,"7:8":true,"6:9":true,"4:6":true,"5:0":true,"5:6":true,"4:0":true,"2:10":true,"6:7":true,"7:1":true,"9:3":true,"6:0":true,"3:13":true,"5:9":true,"7:2":true,"6:6":true,"4:9":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"4:7":true,"7:3":true,"4:1":true,"3:12":true,"6:4":true,"10:0":true,"5:1":true,"3:15":[170,171],"9:0":true,"6:3":true,"7:0":true,"2:5":true,"5:8":true,"3:14":[147,170],"6:2":true,"7:6":true,"4:8":true,"2:11":true,"4:14":true,"6:5":true,"3:8":true,"5:14":true,"2:2":true,"6:11":true,"1:0":true,"5:12":true,"2:4":true,"8:0":true,"4:15":true,"8:6":true,"4:12":true,"3:1":true,"5:15":true,"2:3":true,"5:10":true,"3:7":true,"1:3":true,"8:2":true,"1:4":true,"2:0":true,"8:4":true,"5:13":true,"1:2":true,"7:5":true,"3:9":true,"8:3":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "1:1": true,
+ "2:7": true,
+ "6:10": true,
+ "2:9": true,
+ "3:0": true,
+ "8:1": true,
+ "3:6": true,
+ "5:5": true,
+ "4:11": true,
+ "2:8": true,
+ "5:11": true,
+ "4:5": true,
+ "3:2": true,
+ "1:9": true,
+ "13:14": 148,
+ "3:4": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": true,
+ "6:15": true,
+ "2:1": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "7:7": true,
+ "5:3": true,
+ "6:1": true,
+ "4:4": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "4:2": true,
+ "3:11": true,
+ "5:2": true,
+ "2:14": 148,
+ "9:1": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "2:10": true,
+ "6:7": true,
+ "7:1": true,
+ "9:3": true,
+ "6:0": true,
+ "3:13": true,
+ "5:9": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "4:7": true,
+ "7:3": true,
+ "4:1": true,
+ "3:12": true,
+ "6:4": true,
+ "10:0": true,
+ "5:1": true,
+ "3:15": [
+ 170,
+ 171
+ ],
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "2:5": true,
+ "5:8": true,
+ "3:14": [
+ 147,
+ 170
+ ],
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "4:14": true,
+ "6:5": true,
+ "3:8": true,
+ "5:14": true,
+ "2:2": true,
+ "6:11": true,
+ "1:0": true,
+ "5:12": true,
+ "2:4": true,
+ "8:0": true,
+ "4:15": true,
+ "8:6": true,
+ "4:12": true,
+ "3:1": true,
+ "5:15": true,
+ "2:3": true,
+ "5:10": true,
+ "3:7": true,
+ "1:3": true,
+ "8:2": true,
+ "1:4": true,
+ "2:0": true,
+ "8:4": true,
+ "5:13": true,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "8:3": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_7.json
index 645ca655..81ba0e3a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_7.json
@@ -1 +1,136 @@
-{"9:14":true,"1:1":148,"8:8":true,"7:12":true,"6:10":true,"13:13":true,"10:14":true,"7:15":true,"10:12":true,"6:13":true,"2:9":true,"3:0":[148,171],"9:15":true,"9:12":true,"3:6":true,"10:15":true,"7:14":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"7:13":true,"2:8":true,"9:10":true,"5:11":true,"4:5":true,"3:2":true,"6:14":true,"1:9":true,"13:14":true,"10:13":true,"8:9":true,"7:10":true,"6:12":true,"3:3":true,"6:15":true,"9:13":true,"2:1":148,"14:14":true,"4:3":true,"8:13":true,"5:4":true,"2:12":true,"7:7":true,"5:3":true,"15:14":true,"9:9":true,"6:1":true,"4:4":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"14:15":true,"4:2":true,"15:15":true,"9:7":true,"3:11":true,"5:2":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"5:0":true,"5:6":true,"8:15":true,"4:0":true,"15:13":true,"2:10":true,"6:7":true,"8:14":true,"9:8":true,"14:13":true,"6:0":true,"3:13":true,"5:9":true,"6:6":true,"4:9":true,"5:7":true,"3:10":true,"7:4":true,"8:11":true,"4:7":true,"7:3":true,"4:1":true,"3:12":true,"6:4":true,"5:1":true,"6:3":true,"2:5":true,"5:8":true,"3:14":true,"6:2":true,"7:6":true,"4:8":true,"2:11":true,"4:14":true,"6:5":true,"3:8":true,"5:14":true,"2:2":148,"6:11":true,"11:13":true,"5:12":true,"4:15":true,"8:6":true,"4:12":true,"3:1":true,"12:13":true,"5:15":true,"2:3":true,"12:14":true,"9:11":true,"5:10":true,"3:7":true,"1:3":148,"10:11":true,"4:10":true,"11:14":true,"2:0":148,"11:12":true,"5:13":true,"1:2":148,"7:5":true,"3:9":true,"11:15":true,"7:11":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:1": 148,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "10:14": true,
+ "7:15": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "3:0": [
+ 148,
+ 171
+ ],
+ "9:15": true,
+ "9:12": true,
+ "3:6": true,
+ "10:15": true,
+ "7:14": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "7:13": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "3:2": true,
+ "6:14": true,
+ "1:9": true,
+ "13:14": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": true,
+ "6:15": true,
+ "9:13": true,
+ "2:1": 148,
+ "14:14": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "2:12": true,
+ "7:7": true,
+ "5:3": true,
+ "15:14": true,
+ "9:9": true,
+ "6:1": true,
+ "4:4": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "14:15": true,
+ "4:2": true,
+ "15:15": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "5:0": true,
+ "5:6": true,
+ "8:15": true,
+ "4:0": true,
+ "15:13": true,
+ "2:10": true,
+ "6:7": true,
+ "8:14": true,
+ "9:8": true,
+ "14:13": true,
+ "6:0": true,
+ "3:13": true,
+ "5:9": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "8:11": true,
+ "4:7": true,
+ "7:3": true,
+ "4:1": true,
+ "3:12": true,
+ "6:4": true,
+ "5:1": true,
+ "6:3": true,
+ "2:5": true,
+ "5:8": true,
+ "3:14": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "4:14": true,
+ "6:5": true,
+ "3:8": true,
+ "5:14": true,
+ "2:2": 148,
+ "6:11": true,
+ "11:13": true,
+ "5:12": true,
+ "4:15": true,
+ "8:6": true,
+ "4:12": true,
+ "3:1": true,
+ "12:13": true,
+ "5:15": true,
+ "2:3": true,
+ "12:14": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "1:3": 148,
+ "10:11": true,
+ "4:10": true,
+ "11:14": true,
+ "2:0": 148,
+ "11:12": true,
+ "5:13": true,
+ "1:2": 148,
+ "7:5": true,
+ "3:9": true,
+ "11:15": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_8.json
index c412285b..741c9bfe 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_8.json
@@ -1 +1,262 @@
-{"6:10":true,"13:15":true,"14:1":true,"10:10":true,"8:7":true,"4:11":true,"9:10":true,"5:11":true,"13:12":[131,172],"15:1":true,"8:9":true,"7:10":true,"2:12":true,"10:9":true,"7:7":true,"2:15":[138,152],"15:14":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"14:15":true,"13:1":true,"0:11":true,"15:15":[131,149],"14:12":true,"9:7":true,"3:11":true,"2:14":[138,150],"1:13":[138,151],"2:13":[138,150],"1:14":[138,150],"5:0":true,"5:6":true,"4:0":true,"15:13":true,"1:15":[138,152],"10:8":true,"6:7":true,"1:12":true,"9:8":true,"1:11":true,"3:13":true,"11:8":true,"13:6":true,"13:0":true,"12:8":true,"14:11":true,"13:2":[134,168],"3:12":true,"0:15":[138,152],"11:9":true,"14:5":[133,135],"5:1":true,"3:15":[138,150],"0:12":true,"15:11":true,"12:9":true,"13:3":true,"11:7":true,"0:14":151,"13:4":true,"12:7":true,"3:14":[137,149],"2:11":true,"4:14":true,"11:10":true,"12:10":true,"5:14":true,"15:3":169,"14:4":[133,134],"5:12":true,"14:2":true,"13:11":133,"4:15":[137,173],"15:2":true,"4:12":true,"13:5":true,"5:15":[137,173],"15:0":true,"14:6":true,"15:6":true,"14:0":true,"5:13":true,"4:13":true,"15:9":true,"12:11":133,"9:14":[133,173],"11:5":true,"7:12":true,"12:5":true,"10:14":[168,173],"7:15":[136,173],"14:9":133,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":true,"10:15":true,"13:10":true,"7:14":true,"7:13":true,"6:14":true,"15:8":true,"10:13":true,"6:15":[137,173],"14:8":true,"9:13":true,"11:0":true,"12:6":true,"8:13":true,"1:10":true,"13:8":true,"12:0":true,"6:1":true,"11:6":true,"12:3":true,"11:4":true,"9:1":true,"8:12":true,"15:10":133,"14:10":133,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"12:2":[136,139],"2:10":true,"11:2":true,"8:14":[135,170],"13:9":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"6:6":true,"4:9":true,"11:1":[136,167],"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"10:2":true,"0:10":true,"7:3":true,"9:6":true,"6:4":true,"10:0":true,"10:6":true,"9:0":true,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"6:5":true,"11:13":[132,174],"8:0":true,"8:6":true,"10:5":true,"9:11":true,"5:10":true,"10:11":true,"9:5":true,"4:10":true,"8:2":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"3:9":true,"12:12":132,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "6:10": true,
+ "13:15": true,
+ "14:1": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "9:10": true,
+ "5:11": true,
+ "13:12": [
+ 131,
+ 172
+ ],
+ "15:1": true,
+ "8:9": true,
+ "7:10": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": [
+ 138,
+ 152
+ ],
+ "15:14": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "14:15": true,
+ "13:1": true,
+ "0:11": true,
+ "15:15": [
+ 131,
+ 149
+ ],
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "2:14": [
+ 138,
+ 150
+ ],
+ "1:13": [
+ 138,
+ 151
+ ],
+ "2:13": [
+ 138,
+ 150
+ ],
+ "1:14": [
+ 138,
+ 150
+ ],
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": [
+ 138,
+ 152
+ ],
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "1:11": true,
+ "3:13": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": [
+ 134,
+ 168
+ ],
+ "3:12": true,
+ "0:15": [
+ 138,
+ 152
+ ],
+ "11:9": true,
+ "14:5": [
+ 133,
+ 135
+ ],
+ "5:1": true,
+ "3:15": [
+ 138,
+ 150
+ ],
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "0:14": 151,
+ "13:4": true,
+ "12:7": true,
+ "3:14": [
+ 137,
+ 149
+ ],
+ "2:11": true,
+ "4:14": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "15:3": 169,
+ "14:4": [
+ 133,
+ 134
+ ],
+ "5:12": true,
+ "14:2": true,
+ "13:11": 133,
+ "4:15": [
+ 137,
+ 173
+ ],
+ "15:2": true,
+ "4:12": true,
+ "13:5": true,
+ "5:15": [
+ 137,
+ 173
+ ],
+ "15:0": true,
+ "14:6": true,
+ "15:6": true,
+ "14:0": true,
+ "5:13": true,
+ "4:13": true,
+ "15:9": true,
+ "12:11": 133,
+ "9:14": [
+ 133,
+ 173
+ ],
+ "11:5": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": [
+ 168,
+ 173
+ ],
+ "7:15": [
+ 136,
+ 173
+ ],
+ "14:9": 133,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "10:15": true,
+ "13:10": true,
+ "7:14": true,
+ "7:13": true,
+ "6:14": true,
+ "15:8": true,
+ "10:13": true,
+ "6:15": [
+ 137,
+ 173
+ ],
+ "14:8": true,
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": true,
+ "1:10": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": true,
+ "11:6": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "15:10": 133,
+ "14:10": 133,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": [
+ 136,
+ 139
+ ],
+ "2:10": true,
+ "11:2": true,
+ "8:14": [
+ 135,
+ 170
+ ],
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": [
+ 136,
+ 167
+ ],
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "11:13": [
+ 132,
+ 174
+ ],
+ "8:0": true,
+ "8:6": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "8:2": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": 132,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_9.json
index e0ccf216..7d316b72 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-6_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-6_9.json
@@ -1 +1,256 @@
-{"1:1":138,"8:8":true,"6:10":true,"13:13":true,"0:6":true,"3:6":true,"14:1":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":[138,181],"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"0:4":true,"2:1":138,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"15:14":true,"9:9":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":true,"0:5":true,"4:6":true,"7:8":true,"6:9":true,"2:13":true,"5:0":[138,173],"5:6":true,"4:0":149,"15:13":true,"1:15":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"11:8":true,"13:6":true,"12:8":true,"14:11":true,"13:2":true,"4:1":true,"3:12":true,"0:15":true,"11:9":true,"15:5":true,"14:5":true,"5:1":true,"15:11":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"13:4":true,"12:7":true,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"11:10":true,"12:10":true,"5:14":true,"2:2":[138,183],"15:3":true,"1:0":138,"14:4":true,"5:12":true,"2:4":true,"14:2":true,"13:11":true,"4:15":true,"0:1":138,"15:2":true,"4:12":true,"3:1":[138,173],"13:5":true,"5:15":true,"2:3":true,"15:0":true,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"14:0":true,"2:0":138,"5:13":true,"1:2":[138,182],"4:13":true,"2:6":true,"15:9":true,"12:11":true,"9:14":true,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"10:14":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":true,"13:10":true,"10:15":true,"1:8":true,"2:8":true,"6:14":true,"1:9":true,"15:8":true,"10:13":true,"6:12":true,"1:7":true,"6:15":true,"14:8":true,"9:13":true,"12:6":true,"8:13":[132,148],"1:10":true,"13:8":true,"6:1":true,"11:6":true,"12:3":true,"11:4":true,"9:1":true,"8:12":true,"15:10":true,"14:10":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"12:2":true,"2:10":true,"11:2":true,"8:14":true,"13:9":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"6:6":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"7:3":true,"9:6":true,"6:4":true,"10:6":true,"9:0":true,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"6:5":true,"3:8":true,"0:8":true,"6:11":true,"11:13":true,"8:0":true,"8:6":true,"12:13":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"8:2":true,"0:7":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"8:3":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": 138,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "0:6": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": [
+ 138,
+ 181
+ ],
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": 138,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "0:5": true,
+ "4:6": true,
+ "7:8": true,
+ "6:9": true,
+ "2:13": true,
+ "5:0": [
+ 138,
+ 173
+ ],
+ "5:6": true,
+ "4:0": 149,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "11:8": true,
+ "13:6": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "2:2": [
+ 138,
+ 183
+ ],
+ "15:3": true,
+ "1:0": 138,
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "0:1": 138,
+ "15:2": true,
+ "4:12": true,
+ "3:1": [
+ 138,
+ 173
+ ],
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": 138,
+ "5:13": true,
+ "1:2": [
+ 138,
+ 182
+ ],
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "1:8": true,
+ "2:8": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "12:6": true,
+ "8:13": [
+ 132,
+ 148
+ ],
+ "1:10": true,
+ "13:8": true,
+ "6:1": true,
+ "11:6": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "15:10": true,
+ "14:10": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": true,
+ "2:10": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:6": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": true,
+ "8:6": true,
+ "12:13": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "8:2": true,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-1.json
index 6b55f55d..fe8dced2 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-1.json
@@ -1 +1,139 @@
-{"12:11":true,"11:5":171,"8:8":true,"12:5":[171,175],"7:15":true,"6:13":true,"9:15":true,"14:7":true,"8:1":true,"13:10":true,"10:15":true,"10:10":true,"8:7":true,"0:2":true,"9:10":true,"13:14":true,"8:9":true,"6:15":true,"14:8":224,"11:0":171,"14:14":true,"12:6":171,"10:9":true,"7:7":true,"13:8":true,"15:14":true,"12:0":true,"9:9":true,"6:1":true,"11:6":171,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"15:12":[216,222],"0:11":[152,153],"15:15":true,"9:7":true,"12:3":[171,175],"11:4":171,"9:1":171,"7:8":true,"6:9":true,"15:10":[216,222],"14:10":[216,222],"10:1":171,"13:7":true,"12:4":171,"11:3":171,"8:15":true,"15:13":true,"12:2":171,"10:8":true,"6:7":true,"11:2":171,"9:8":true,"7:1":171,"12:1":[171,175],"9:3":171,"6:0":171,"10:4":true,"10:3":171,"7:2":true,"6:6":true,"11:1":171,"9:4":171,"8:5":true,"11:8":true,"7:4":true,"9:2":true,"10:2":171,"12:8":true,"7:3":true,"9:6":true,"11:9":true,"6:4":true,"10:0":171,"10:6":171,"0:12":true,"15:11":[216,222],"12:9":true,"9:0":171,"6:3":true,"7:0":171,"11:7":171,"12:7":[171,223],"6:2":true,"7:6":true,"15:4":true,"11:10":true,"6:5":true,"12:10":true,"6:11":true,"14:4":true,"8:0":true,"0:1":true,"8:6":true,"12:13":true,"14:6":true,"12:14":true,"10:5":171,"9:5":171,"11:14":true,"8:2":171,"12:15":true,"8:4":true,"1:2":true,"7:5":true,"11:15":true,"8:3":true} \ No newline at end of file
+{
+ "12:11": true,
+ "11:5": 171,
+ "8:8": true,
+ "12:5": [
+ 171,
+ 175
+ ],
+ "7:15": true,
+ "6:13": true,
+ "9:15": true,
+ "14:7": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "10:10": true,
+ "8:7": true,
+ "0:2": true,
+ "9:10": true,
+ "13:14": true,
+ "8:9": true,
+ "6:15": true,
+ "14:8": 224,
+ "11:0": 171,
+ "14:14": true,
+ "12:6": 171,
+ "10:9": true,
+ "7:7": true,
+ "13:8": true,
+ "15:14": true,
+ "12:0": true,
+ "9:9": true,
+ "6:1": true,
+ "11:6": 171,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "15:12": [
+ 216,
+ 222
+ ],
+ "0:11": [
+ 152,
+ 153
+ ],
+ "15:15": true,
+ "9:7": true,
+ "12:3": [
+ 171,
+ 175
+ ],
+ "11:4": 171,
+ "9:1": 171,
+ "7:8": true,
+ "6:9": true,
+ "15:10": [
+ 216,
+ 222
+ ],
+ "14:10": [
+ 216,
+ 222
+ ],
+ "10:1": 171,
+ "13:7": true,
+ "12:4": 171,
+ "11:3": 171,
+ "8:15": true,
+ "15:13": true,
+ "12:2": 171,
+ "10:8": true,
+ "6:7": true,
+ "11:2": 171,
+ "9:8": true,
+ "7:1": 171,
+ "12:1": [
+ 171,
+ 175
+ ],
+ "9:3": 171,
+ "6:0": 171,
+ "10:4": true,
+ "10:3": 171,
+ "7:2": true,
+ "6:6": true,
+ "11:1": 171,
+ "9:4": 171,
+ "8:5": true,
+ "11:8": true,
+ "7:4": true,
+ "9:2": true,
+ "10:2": 171,
+ "12:8": true,
+ "7:3": true,
+ "9:6": true,
+ "11:9": true,
+ "6:4": true,
+ "10:0": 171,
+ "10:6": 171,
+ "0:12": true,
+ "15:11": [
+ 216,
+ 222
+ ],
+ "12:9": true,
+ "9:0": 171,
+ "6:3": true,
+ "7:0": 171,
+ "11:7": 171,
+ "12:7": [
+ 171,
+ 223
+ ],
+ "6:2": true,
+ "7:6": true,
+ "15:4": true,
+ "11:10": true,
+ "6:5": true,
+ "12:10": true,
+ "6:11": true,
+ "14:4": true,
+ "8:0": true,
+ "0:1": true,
+ "8:6": true,
+ "12:13": true,
+ "14:6": true,
+ "12:14": true,
+ "10:5": 171,
+ "9:5": 171,
+ "11:14": true,
+ "8:2": 171,
+ "12:15": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "11:15": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-2.json
index a1729354..0c07f450 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-2.json
@@ -1 +1,149 @@
-{"12:11":[171,175],"9:14":true,"11:5":true,"8:8":171,"7:12":171,"6:10":171,"12:5":true,"10:14":true,"7:15":true,"11:11":171,"10:12":true,"6:13":true,"9:15":171,"9:12":true,"8:1":true,"10:15":171,"7:14":true,"10:10":171,"8:7":171,"7:13":171,"9:10":171,"6:14":true,"10:13":true,"8:9":171,"7:10":171,"6:12":171,"6:15":[171,175],"9:13":true,"11:0":true,"12:6":true,"8:13":171,"10:9":171,"7:7":171,"12:0":true,"9:9":171,"6:1":[169,175],"11:6":true,"10:7":171,"8:10":171,"7:9":171,"6:8":171,"9:7":171,"12:3":true,"11:4":true,"9:1":true,"8:12":171,"7:8":171,"6:9":[171,175],"14:10":true,"10:1":true,"12:4":true,"11:3":true,"8:15":171,"12:2":true,"10:8":171,"6:7":[171,175],"11:2":true,"8:14":171,"9:8":171,"7:1":169,"12:1":true,"9:3":true,"6:0":168,"10:4":true,"10:3":true,"7:2":170,"6:6":171,"11:1":true,"9:4":171,"8:5":171,"11:8":171,"7:4":171,"9:2":true,"8:11":171,"10:2":true,"12:8":true,"7:3":171,"9:6":171,"11:9":171,"6:4":171,"10:0":true,"10:6":171,"15:11":true,"12:9":[171,175],"9:0":true,"6:3":[171,175],"7:0":true,"11:7":true,"12:7":true,"6:2":170,"7:6":171,"11:10":171,"6:5":[171,175],"12:10":171,"6:11":[171,175],"11:13":true,"8:0":true,"8:6":171,"12:13":[171,175],"12:14":171,"10:5":true,"9:11":171,"10:11":171,"9:5":171,"11:14":true,"8:2":170,"12:15":[171,175],"11:12":171,"8:4":171,"7:5":171,"12:12":171,"11:15":true,"8:3":171,"7:11":171} \ No newline at end of file
+{
+ "12:11": [
+ 171,
+ 175
+ ],
+ "9:14": true,
+ "11:5": true,
+ "8:8": 171,
+ "7:12": 171,
+ "6:10": 171,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": 171,
+ "10:12": true,
+ "6:13": true,
+ "9:15": 171,
+ "9:12": true,
+ "8:1": true,
+ "10:15": 171,
+ "7:14": true,
+ "10:10": 171,
+ "8:7": 171,
+ "7:13": 171,
+ "9:10": 171,
+ "6:14": true,
+ "10:13": true,
+ "8:9": 171,
+ "7:10": 171,
+ "6:12": 171,
+ "6:15": [
+ 171,
+ 175
+ ],
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": 171,
+ "10:9": 171,
+ "7:7": 171,
+ "12:0": true,
+ "9:9": 171,
+ "6:1": [
+ 169,
+ 175
+ ],
+ "11:6": true,
+ "10:7": 171,
+ "8:10": 171,
+ "7:9": 171,
+ "6:8": 171,
+ "9:7": 171,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": 171,
+ "7:8": 171,
+ "6:9": [
+ 171,
+ 175
+ ],
+ "14:10": true,
+ "10:1": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": 171,
+ "12:2": true,
+ "10:8": 171,
+ "6:7": [
+ 171,
+ 175
+ ],
+ "11:2": true,
+ "8:14": 171,
+ "9:8": 171,
+ "7:1": 169,
+ "12:1": true,
+ "9:3": true,
+ "6:0": 168,
+ "10:4": true,
+ "10:3": true,
+ "7:2": 170,
+ "6:6": 171,
+ "11:1": true,
+ "9:4": 171,
+ "8:5": 171,
+ "11:8": 171,
+ "7:4": 171,
+ "9:2": true,
+ "8:11": 171,
+ "10:2": true,
+ "12:8": true,
+ "7:3": 171,
+ "9:6": 171,
+ "11:9": 171,
+ "6:4": 171,
+ "10:0": true,
+ "10:6": 171,
+ "15:11": true,
+ "12:9": [
+ 171,
+ 175
+ ],
+ "9:0": true,
+ "6:3": [
+ 171,
+ 175
+ ],
+ "7:0": true,
+ "11:7": true,
+ "12:7": true,
+ "6:2": 170,
+ "7:6": 171,
+ "11:10": 171,
+ "6:5": [
+ 171,
+ 175
+ ],
+ "12:10": 171,
+ "6:11": [
+ 171,
+ 175
+ ],
+ "11:13": true,
+ "8:0": true,
+ "8:6": 171,
+ "12:13": [
+ 171,
+ 175
+ ],
+ "12:14": 171,
+ "10:5": true,
+ "9:11": 171,
+ "10:11": 171,
+ "9:5": 171,
+ "11:14": true,
+ "8:2": 170,
+ "12:15": [
+ 171,
+ 175
+ ],
+ "11:12": 171,
+ "8:4": 171,
+ "7:5": 171,
+ "12:12": 171,
+ "11:15": true,
+ "8:3": 171,
+ "7:11": 171
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-3.json
index c16c3f4a..9505661b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-3.json
@@ -1 +1,71 @@
-{"15:9":true,"12:11":true,"5:9":true,"0:13":195,"7:15":true,"4:9":true,"3:10":[192,193],"6:13":true,"2:9":true,"9:15":true,"14:7":true,"10:15":true,"11:9":true,"15:5":true,"3:15":true,"3:2":true,"15:1":true,"12:9":true,"0:14":195,"5:8":true,"6:15":[168,175],"14:8":true,"4:8":true,"2:11":true,"2:1":true,"15:4":true,"4:14":true,"2:12":[190,194],"3:8":true,"5:14":true,"2:2":true,"13:8":true,"9:9":true,"6:11":true,"7:9":true,"15:2":true,"3:1":true,"3:11":[190,192],"12:13":true,"1:13":[194,195],"12:14":true,"6:9":true,"4:10":true,"8:15":true,"12:15":true,"5:13":true,"2:10":159,"3:9":true,"11:15":true,"1:12":[192,193],"13:9":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "5:9": true,
+ "0:13": 195,
+ "7:15": true,
+ "4:9": true,
+ "3:10": [
+ 192,
+ 193
+ ],
+ "6:13": true,
+ "2:9": true,
+ "9:15": true,
+ "14:7": true,
+ "10:15": true,
+ "11:9": true,
+ "15:5": true,
+ "3:15": true,
+ "3:2": true,
+ "15:1": true,
+ "12:9": true,
+ "0:14": 195,
+ "5:8": true,
+ "6:15": [
+ 168,
+ 175
+ ],
+ "14:8": true,
+ "4:8": true,
+ "2:11": true,
+ "2:1": true,
+ "15:4": true,
+ "4:14": true,
+ "2:12": [
+ 190,
+ 194
+ ],
+ "3:8": true,
+ "5:14": true,
+ "2:2": true,
+ "13:8": true,
+ "9:9": true,
+ "6:11": true,
+ "7:9": true,
+ "15:2": true,
+ "3:1": true,
+ "3:11": [
+ 190,
+ 192
+ ],
+ "12:13": true,
+ "1:13": [
+ 194,
+ 195
+ ],
+ "12:14": true,
+ "6:9": true,
+ "4:10": true,
+ "8:15": true,
+ "12:15": true,
+ "5:13": true,
+ "2:10": 159,
+ "3:9": true,
+ "11:15": true,
+ "1:12": [
+ 192,
+ 193
+ ],
+ "13:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-4.json
index 87e54c02..28e49cd7 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-4.json
@@ -1 +1,61 @@
-{"15:9":true,"9:14":true,"1:11":true,"3:13":true,"2:7":true,"7:12":true,"4:9":true,"3:10":true,"2:9":true,"13:0":true,"10:15":true,"3:12":true,"6:4":true,"15:5":true,"5:1":164,"15:11":true,"15:1":true,"6:3":true,"1:9":true,"15:8":true,"0:14":203,"13:4":true,"3:14":[177,201],"6:2":true,"2:11":true,"15:4":true,"1:6":true,"8:13":true,"2:12":true,"3:8":true,"5:3":true,"1:10":true,"15:14":true,"15:3":true,"6:11":true,"14:4":true,"3:5":true,"15:12":true,"15:2":true,"3:11":true,"5:2":164,"2:14":202,"1:13":true,"0:5":true,"15:0":true,"5:10":true,"2:13":true,"15:10":true,"12:4":true,"14:0":true,"15:13":true,"5:13":199,"2:10":true,"3:9":true,"1:12":true,"4:13":200} \ No newline at end of file
+{
+ "15:9": true,
+ "9:14": true,
+ "1:11": true,
+ "3:13": true,
+ "2:7": true,
+ "7:12": true,
+ "4:9": true,
+ "3:10": true,
+ "2:9": true,
+ "13:0": true,
+ "10:15": true,
+ "3:12": true,
+ "6:4": true,
+ "15:5": true,
+ "5:1": 164,
+ "15:11": true,
+ "15:1": true,
+ "6:3": true,
+ "1:9": true,
+ "15:8": true,
+ "0:14": 203,
+ "13:4": true,
+ "3:14": [
+ 177,
+ 201
+ ],
+ "6:2": true,
+ "2:11": true,
+ "15:4": true,
+ "1:6": true,
+ "8:13": true,
+ "2:12": true,
+ "3:8": true,
+ "5:3": true,
+ "1:10": true,
+ "15:14": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "3:5": true,
+ "15:12": true,
+ "15:2": true,
+ "3:11": true,
+ "5:2": 164,
+ "2:14": 202,
+ "1:13": true,
+ "0:5": true,
+ "15:0": true,
+ "5:10": true,
+ "2:13": true,
+ "15:10": true,
+ "12:4": true,
+ "14:0": true,
+ "15:13": true,
+ "5:13": 199,
+ "2:10": true,
+ "3:9": true,
+ "1:12": true,
+ "4:13": 200
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-5.json
index 38a94887..01f4756c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-5.json
@@ -1 +1,72 @@
-{"15:9":177,"1:1":true,"2:7":true,"13:13":true,"11:11":199,"15:7":true,"3:0":true,"0:0":true,"14:7":[208,212],"3:6":177,"13:10":171,"1:8":177,"2:8":177,"13:12":true,"3:2":true,"15:1":true,"15:8":177,"3:3":true,"1:7":true,"2:1":true,"15:14":true,"10:7":[167,169],"7:9":[206,207],"15:12":true,"15:15":true,"14:12":true,"9:7":true,"15:10":177,"13:7":208,"15:13":true,"10:8":170,"14:13":true,"11:8":[170,208],"12:8":[207,209],"14:11":163,"15:11":[171,177],"3:8":true,"2:2":true,"15:3":177,"1:0":true,"8:0":true,"13:11":163,"15:2":true,"3:1":true,"15:0":177,"3:7":true,"15:6":[177,210],"2:0":true,"12:12":true} \ No newline at end of file
+{
+ "15:9": 177,
+ "1:1": true,
+ "2:7": true,
+ "13:13": true,
+ "11:11": 199,
+ "15:7": true,
+ "3:0": true,
+ "0:0": true,
+ "14:7": [
+ 208,
+ 212
+ ],
+ "3:6": 177,
+ "13:10": 171,
+ "1:8": 177,
+ "2:8": 177,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "15:8": 177,
+ "3:3": true,
+ "1:7": true,
+ "2:1": true,
+ "15:14": true,
+ "10:7": [
+ 167,
+ 169
+ ],
+ "7:9": [
+ 206,
+ 207
+ ],
+ "15:12": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "15:10": 177,
+ "13:7": 208,
+ "15:13": true,
+ "10:8": 170,
+ "14:13": true,
+ "11:8": [
+ 170,
+ 208
+ ],
+ "12:8": [
+ 207,
+ 209
+ ],
+ "14:11": 163,
+ "15:11": [
+ 171,
+ 177
+ ],
+ "3:8": true,
+ "2:2": true,
+ "15:3": 177,
+ "1:0": true,
+ "8:0": true,
+ "13:11": 163,
+ "15:2": true,
+ "3:1": true,
+ "15:0": 177,
+ "3:7": true,
+ "15:6": [
+ 177,
+ 210
+ ],
+ "2:0": true,
+ "12:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-6.json
index 19ba134e..06cf2b55 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_-6.json
@@ -1 +1,36 @@
-{"15:9":true,"3:13":true,"2:7":true,"1:5":true,"3:10":true,"2:9":177,"15:7":true,"3:6":true,"1:8":true,"2:8":true,"15:5":true,"3:15":true,"1:9":true,"15:8":true,"3:4":true,"2:5":true,"3:14":true,"1:7":true,"15:4":true,"1:6":true,"3:8":true,"2:15":true,"15:14":true,"3:5":true,"15:15":true,"2:14":true,"3:7":true,"1:14":true,"15:10":true,"15:6":true,"15:13":true,"1:15":true,"3:9":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "3:13": true,
+ "2:7": true,
+ "1:5": true,
+ "3:10": true,
+ "2:9": 177,
+ "15:7": true,
+ "3:6": true,
+ "1:8": true,
+ "2:8": true,
+ "15:5": true,
+ "3:15": true,
+ "1:9": true,
+ "15:8": true,
+ "3:4": true,
+ "2:5": true,
+ "3:14": true,
+ "1:7": true,
+ "15:4": true,
+ "1:6": true,
+ "3:8": true,
+ "2:15": true,
+ "15:14": true,
+ "3:5": true,
+ "15:15": true,
+ "2:14": true,
+ "3:7": true,
+ "1:14": true,
+ "15:10": true,
+ "15:6": true,
+ "15:13": true,
+ "1:15": true,
+ "3:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_0.json
index 102e124f..f8f28b67 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_0.json
@@ -1 +1,152 @@
-{"12:11":true,"9:14":true,"11:5":true,"8:8":true,"7:12":true,"6:10":true,"13:13":[190,192],"12:5":true,"10:14":true,"7:15":true,"11:11":true,"10:12":171,"6:13":[171,190],"9:15":true,"9:12":171,"8:1":true,"10:15":true,"7:14":[171,190],"10:10":true,"8:7":true,"7:13":[171,192],"9:10":true,"6:14":[171,190],"13:14":true,"10:13":true,"8:9":true,"7:10":true,"6:12":true,"6:15":true,"9:13":[171,192],"11:0":true,"8:13":[171,190],"10:9":true,"7:7":true,"15:14":190,"9:9":true,"6:1":true,"11:6":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"9:7":true,"2:14":true,"1:13":true,"2:13":true,"12:3":true,"11:4":true,"9:1":true,"8:12":171,"7:8":true,"6:9":true,"1:14":true,"10:1":true,"11:3":true,"8:15":true,"15:13":[190,192],"10:8":true,"6:7":true,"11:2":true,"8:14":true,"9:8":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"3:13":true,"10:3":true,"0:13":true,"7:2":true,"6:6":true,"11:1":true,"9:4":true,"8:5":true,"11:8":true,"7:4":true,"9:2":true,"8:11":true,"10:2":true,"7:3":true,"9:6":true,"11:9":true,"6:4":true,"10:0":true,"10:6":true,"12:9":true,"9:0":true,"6:3":true,"7:0":true,"11:7":true,"0:14":true,"12:7":true,"6:2":true,"7:6":true,"4:14":190,"11:10":true,"6:5":true,"5:14":190,"6:11":true,"11:13":[171,192],"8:0":true,"8:6":true,"12:13":[175,190],"12:14":true,"9:11":true,"10:5":true,"10:11":true,"9:5":true,"11:14":true,"8:2":true,"12:15":true,"11:12":171,"8:4":true,"5:13":true,"7:5":true,"11:15":true,"8:3":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": [
+ 190,
+ 192
+ ],
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "10:12": 171,
+ "6:13": [
+ 171,
+ 190
+ ],
+ "9:15": true,
+ "9:12": 171,
+ "8:1": true,
+ "10:15": true,
+ "7:14": [
+ 171,
+ 190
+ ],
+ "10:10": true,
+ "8:7": true,
+ "7:13": [
+ 171,
+ 192
+ ],
+ "9:10": true,
+ "6:14": [
+ 171,
+ 190
+ ],
+ "13:14": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "6:15": true,
+ "9:13": [
+ 171,
+ 192
+ ],
+ "11:0": true,
+ "8:13": [
+ 171,
+ 190
+ ],
+ "10:9": true,
+ "7:7": true,
+ "15:14": 190,
+ "9:9": true,
+ "6:1": true,
+ "11:6": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "9:7": true,
+ "2:14": true,
+ "1:13": true,
+ "2:13": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": 171,
+ "7:8": true,
+ "6:9": true,
+ "1:14": true,
+ "10:1": true,
+ "11:3": true,
+ "8:15": true,
+ "15:13": [
+ 190,
+ 192
+ ],
+ "10:8": true,
+ "6:7": true,
+ "11:2": true,
+ "8:14": true,
+ "9:8": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "3:13": true,
+ "10:3": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "11:8": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "11:9": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "12:9": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "11:7": true,
+ "0:14": true,
+ "12:7": true,
+ "6:2": true,
+ "7:6": true,
+ "4:14": 190,
+ "11:10": true,
+ "6:5": true,
+ "5:14": 190,
+ "6:11": true,
+ "11:13": [
+ 171,
+ 192
+ ],
+ "8:0": true,
+ "8:6": true,
+ "12:13": [
+ 175,
+ 190
+ ],
+ "12:14": true,
+ "9:11": true,
+ "10:5": true,
+ "10:11": true,
+ "9:5": true,
+ "11:14": true,
+ "8:2": true,
+ "12:15": true,
+ "11:12": 171,
+ "8:4": true,
+ "5:13": true,
+ "7:5": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_1.json
index 4574dc7f..ce03478f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_1.json
@@ -1 +1,167 @@
-{"12:11":true,"1:1":192,"11:5":true,"8:8":true,"6:10":true,"12:5":true,"7:15":true,"6:13":true,"3:0":true,"9:15":true,"0:0":true,"8:1":171,"10:15":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"9:10":true,"4:5":true,"3:2":192,"15:1":192,"8:9":true,"7:10":true,"0:4":190,"6:15":true,"11:0":true,"12:6":true,"5:4":true,"10:9":true,"7:7":true,"12:0":true,"9:9":true,"6:1":[171,175],"11:6":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"14:15":true,"13:1":192,"9:7":true,"5:2":192,"0:5":true,"12:3":true,"11:4":true,"9:1":[171,192],"7:8":true,"6:9":true,"5:0":true,"10:1":171,"12:4":true,"11:3":true,"8:15":true,"4:0":true,"10:8":true,"6:7":true,"11:2":true,"9:8":true,"7:1":[171,192],"12:1":175,"9:3":true,"6:0":[171,192],"10:4":true,"10:3":true,"1:5":true,"7:2":true,"6:6":true,"11:1":[171,192],"9:4":true,"8:5":true,"11:8":true,"7:4":true,"9:2":true,"13:0":true,"10:2":true,"12:8":true,"7:3":true,"13:2":192,"9:6":true,"11:9":true,"6:4":true,"15:5":true,"10:0":[171,192],"10:6":true,"5:1":192,"3:15":true,"12:9":true,"9:0":[171,192],"6:3":true,"7:0":[171,192],"11:7":true,"2:5":true,"13:4":true,"12:7":true,"6:2":171,"7:6":true,"15:4":true,"11:10":true,"6:5":true,"12:10":true,"6:11":true,"1:0":[190,192],"2:4":true,"8:0":[171,192],"4:15":true,"15:2":192,"8:6":true,"3:1":true,"13:5":true,"12:13":true,"5:15":true,"15:0":[190,192],"10:5":true,"9:5":true,"8:2":true,"1:4":190,"14:0":[190,192],"2:0":[190,192],"12:15":true,"8:4":true,"1:2":192,"7:5":true,"11:15":true,"8:3":true} \ No newline at end of file
+{
+ "12:11": true,
+ "1:1": 192,
+ "11:5": true,
+ "8:8": true,
+ "6:10": true,
+ "12:5": true,
+ "7:15": true,
+ "6:13": true,
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "8:1": 171,
+ "10:15": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "9:10": true,
+ "4:5": true,
+ "3:2": 192,
+ "15:1": 192,
+ "8:9": true,
+ "7:10": true,
+ "0:4": 190,
+ "6:15": true,
+ "11:0": true,
+ "12:6": true,
+ "5:4": true,
+ "10:9": true,
+ "7:7": true,
+ "12:0": true,
+ "9:9": true,
+ "6:1": [
+ 171,
+ 175
+ ],
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "14:15": true,
+ "13:1": 192,
+ "9:7": true,
+ "5:2": 192,
+ "0:5": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": [
+ 171,
+ 192
+ ],
+ "7:8": true,
+ "6:9": true,
+ "5:0": true,
+ "10:1": 171,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "4:0": true,
+ "10:8": true,
+ "6:7": true,
+ "11:2": true,
+ "9:8": true,
+ "7:1": [
+ 171,
+ 192
+ ],
+ "12:1": 175,
+ "9:3": true,
+ "6:0": [
+ 171,
+ 192
+ ],
+ "10:4": true,
+ "10:3": true,
+ "1:5": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": [
+ 171,
+ 192
+ ],
+ "9:4": true,
+ "8:5": true,
+ "11:8": true,
+ "7:4": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "12:8": true,
+ "7:3": true,
+ "13:2": 192,
+ "9:6": true,
+ "11:9": true,
+ "6:4": true,
+ "15:5": true,
+ "10:0": [
+ 171,
+ 192
+ ],
+ "10:6": true,
+ "5:1": 192,
+ "3:15": true,
+ "12:9": true,
+ "9:0": [
+ 171,
+ 192
+ ],
+ "6:3": true,
+ "7:0": [
+ 171,
+ 192
+ ],
+ "11:7": true,
+ "2:5": true,
+ "13:4": true,
+ "12:7": true,
+ "6:2": 171,
+ "7:6": true,
+ "15:4": true,
+ "11:10": true,
+ "6:5": true,
+ "12:10": true,
+ "6:11": true,
+ "1:0": [
+ 190,
+ 192
+ ],
+ "2:4": true,
+ "8:0": [
+ 171,
+ 192
+ ],
+ "4:15": true,
+ "15:2": 192,
+ "8:6": true,
+ "3:1": true,
+ "13:5": true,
+ "12:13": true,
+ "5:15": true,
+ "15:0": [
+ 190,
+ 192
+ ],
+ "10:5": true,
+ "9:5": true,
+ "8:2": true,
+ "1:4": 190,
+ "14:0": [
+ 190,
+ 192
+ ],
+ "2:0": [
+ 190,
+ 192
+ ],
+ "12:15": true,
+ "8:4": true,
+ "1:2": 192,
+ "7:5": true,
+ "11:15": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_2.json
index 3736f0b1..c1959b3c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_2.json
@@ -1 +1,100 @@
-{"12:11":true,"9:14":true,"7:12":true,"13:13":true,"12:5":true,"10:14":true,"7:15":true,"10:12":true,"6:13":true,"3:0":true,"9:15":true,"9:12":true,"10:15":true,"7:14":true,"1:8":true,"14:1":true,"13:15":true,"4:11":true,"7:13":true,"5:11":true,"6:14":true,"1:9":true,"13:14":true,"10:13":true,"6:12":true,"1:7":true,"6:15":true,"9:13":true,"14:14":true,"8:13":true,"2:12":true,"2:15":true,"1:10":true,"15:14":true,"6:1":true,"14:15":true,"13:1":true,"0:11":true,"15:15":true,"3:11":true,"2:14":true,"1:13":true,"12:3":true,"8:12":true,"6:9":true,"2:13":true,"1:14":true,"8:15":true,"2:10":true,"1:15":true,"6:7":true,"8:14":true,"1:12":true,"12:1":true,"1:11":true,"3:13":true,"5:9":true,"0:13":true,"4:9":true,"3:10":true,"0:10":true,"4:1":true,"3:12":true,"5:1":true,"3:15":true,"0:12":true,"12:9":true,"6:3":true,"0:14":true,"12:7":true,"3:14":true,"4:8":true,"2:11":true,"4:14":true,"6:5":true,"3:8":true,"5:14":true,"0:8":true,"6:11":true,"11:13":true,"5:12":true,"4:15":true,"4:12":true,"3:1":true,"12:13":true,"5:15":true,"12:14":true,"5:10":true,"4:10":true,"11:14":true,"0:7":true,"12:15":true,"11:12":true,"5:13":true,"3:9":true,"0:9":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "7:12": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "10:12": true,
+ "6:13": true,
+ "3:0": true,
+ "9:15": true,
+ "9:12": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "14:1": true,
+ "13:15": true,
+ "4:11": true,
+ "7:13": true,
+ "5:11": true,
+ "6:14": true,
+ "1:9": true,
+ "13:14": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "9:13": true,
+ "14:14": true,
+ "8:13": true,
+ "2:12": true,
+ "2:15": true,
+ "1:10": true,
+ "15:14": true,
+ "6:1": true,
+ "14:15": true,
+ "13:1": true,
+ "0:11": true,
+ "15:15": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "12:3": true,
+ "8:12": true,
+ "6:9": true,
+ "2:13": true,
+ "1:14": true,
+ "8:15": true,
+ "2:10": true,
+ "1:15": true,
+ "6:7": true,
+ "8:14": true,
+ "1:12": true,
+ "12:1": true,
+ "1:11": true,
+ "3:13": true,
+ "5:9": true,
+ "0:13": true,
+ "4:9": true,
+ "3:10": true,
+ "0:10": true,
+ "4:1": true,
+ "3:12": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "12:9": true,
+ "6:3": true,
+ "0:14": true,
+ "12:7": true,
+ "3:14": true,
+ "4:8": true,
+ "2:11": true,
+ "4:14": true,
+ "6:5": true,
+ "3:8": true,
+ "5:14": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "5:12": true,
+ "4:15": true,
+ "4:12": true,
+ "3:1": true,
+ "12:13": true,
+ "5:15": true,
+ "12:14": true,
+ "5:10": true,
+ "4:10": true,
+ "11:14": true,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "5:13": true,
+ "3:9": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_3.json
index aed53373..2266b3ad 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_3.json
@@ -1 +1,122 @@
-{"15:9":true,"12:11":true,"9:14":true,"11:5":true,"7:12":true,"6:10":true,"12:5":true,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"15:7":true,"3:0":true,"9:15":true,"14:7":true,"9:12":true,"8:1":true,"10:15":true,"7:14":true,"14:1":true,"10:10":true,"7:13":true,"9:10":true,"15:1":true,"6:14":true,"15:8":true,"10:13":true,"8:9":true,"7:10":171,"6:12":true,"6:15":true,"14:8":true,"9:13":true,"8:13":true,"13:8":true,"12:0":true,"6:1":true,"8:10":171,"7:9":171,"6:8":true,"15:12":true,"13:1":true,"12:3":true,"11:4":true,"9:1":true,"8:12":true,"7:8":true,"6:9":[171,175],"15:10":true,"5:0":true,"14:10":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"4:0":true,"15:13":true,"12:2":true,"6:7":true,"11:2":true,"8:14":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:3":true,"6:6":true,"11:1":true,"13:6":true,"9:2":true,"13:0":true,"8:11":true,"10:2":true,"13:2":true,"4:1":true,"15:5":true,"14:5":true,"5:1":true,"3:15":true,"15:11":true,"12:9":true,"6:3":true,"13:3":true,"13:4":true,"12:7":true,"15:4":true,"14:3":true,"4:14":true,"6:5":true,"12:10":true,"15:3":true,"6:11":true,"14:4":true,"11:13":true,"14:2":true,"15:2":true,"13:5":true,"12:13":true,"15:0":true,"14:6":true,"12:14":true,"9:11":true,"10:11":true,"11:14":true,"8:2":true,"15:6":true,"14:0":true,"12:15":true,"11:12":true,"5:13":true,"12:12":true,"11:15":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "7:12": true,
+ "6:10": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "15:7": true,
+ "3:0": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "14:1": true,
+ "10:10": true,
+ "7:13": true,
+ "9:10": true,
+ "15:1": true,
+ "6:14": true,
+ "15:8": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": 171,
+ "6:12": true,
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "8:13": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": true,
+ "8:10": 171,
+ "7:9": 171,
+ "6:8": true,
+ "15:12": true,
+ "13:1": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": [
+ 171,
+ 175
+ ],
+ "15:10": true,
+ "5:0": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "4:0": true,
+ "15:13": true,
+ "12:2": true,
+ "6:7": true,
+ "11:2": true,
+ "8:14": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:3": true,
+ "6:6": true,
+ "11:1": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "8:11": true,
+ "10:2": true,
+ "13:2": true,
+ "4:1": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "15:11": true,
+ "12:9": true,
+ "6:3": true,
+ "13:3": true,
+ "13:4": true,
+ "12:7": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "6:5": true,
+ "12:10": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "11:13": true,
+ "14:2": true,
+ "15:2": true,
+ "13:5": true,
+ "12:13": true,
+ "15:0": true,
+ "14:6": true,
+ "12:14": true,
+ "9:11": true,
+ "10:11": true,
+ "11:14": true,
+ "8:2": true,
+ "15:6": true,
+ "14:0": true,
+ "12:15": true,
+ "11:12": true,
+ "5:13": true,
+ "12:12": true,
+ "11:15": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_4.json
index 0dc13427..f52dabff 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_4.json
@@ -1 +1,33 @@
-{"11:0":true,"9:3":true,"5:4":true,"6:5":true,"5:3":true,"7:2":true,"12:0":true,"6:1":true,"11:1":true,"7:4":true,"8:0":true,"9:2":true,"8:1":true,"10:2":true,"5:2":true,"7:3":true,"9:1":true,"5:5":true,"6:4":true,"10:0":true,"10:1":true,"5:1":true,"8:2":true,"9:0":true,"6:3":true,"7:0":true,"8:4":true,"7:5":true,"8:3":true,"6:2":true,"7:1":true} \ No newline at end of file
+{
+ "11:0": true,
+ "9:3": true,
+ "5:4": true,
+ "6:5": true,
+ "5:3": true,
+ "7:2": true,
+ "12:0": true,
+ "6:1": true,
+ "11:1": true,
+ "7:4": true,
+ "8:0": true,
+ "9:2": true,
+ "8:1": true,
+ "10:2": true,
+ "5:2": true,
+ "7:3": true,
+ "9:1": true,
+ "5:5": true,
+ "6:4": true,
+ "10:0": true,
+ "10:1": true,
+ "5:1": true,
+ "8:2": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "8:4": true,
+ "7:5": true,
+ "8:3": true,
+ "6:2": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_8.json
index 25cbedf1..e554d428 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_8.json
@@ -1 +1,217 @@
-{"12:11":true,"9:14":true,"11:5":true,"2:7":[148,153],"8:8":true,"7:12":true,"6:10":true,"13:13":true,"10:14":true,"7:15":[136,153],"11:11":true,"10:12":true,"6:13":true,"2:9":true,"9:15":true,"0:6":[155,156],"9:12":true,"3:6":150,"10:15":true,"7:14":true,"1:8":true,"13:15":[138,153],"10:10":true,"8:7":true,"4:11":true,"7:13":true,"2:8":true,"9:10":true,"5:11":true,"4:5":151,"13:12":true,"6:14":true,"1:9":true,"13:14":[138,152],"10:13":true,"3:4":[145,146],"8:9":true,"7:10":true,"6:12":true,"3:3":[144,147],"1:7":[154,156],"0:4":153,"6:15":[134,156],"9:13":true,"14:14":[138,152],"8:13":true,"2:12":true,"7:7":true,"2:15":[135,161],"15:14":[138,152],"9:9":true,"8:10":true,"7:9":true,"6:8":true,"3:5":[146,149],"15:12":true,"14:15":[138,153],"15:15":[138,153],"14:12":true,"9:7":true,"2:14":true,"1:13":true,"0:5":154,"2:13":true,"12:3":145,"11:4":[145,147],"8:12":true,"7:8":true,"6:9":true,"1:14":true,"12:4":true,"8:15":[138,153],"15:13":[138,151],"1:15":[134,161],"6:7":true,"8:14":true,"1:12":true,"14:13":[138,152],"3:13":true,"5:9":true,"0:13":true,"6:6":true,"4:9":true,"5:7":true,"3:10":true,"7:4":181,"8:11":true,"4:7":true,"14:11":true,"9:6":true,"3:12":true,"0:15":[135,175],"10:6":true,"3:15":true,"0:12":true,"15:11":true,"2:5":true,"0:14":true,"5:8":true,"3:14":true,"4:8":true,"4:14":true,"1:6":[153,154],"11:10":true,"3:8":true,"12:10":true,"5:14":true,"0:8":157,"6:11":true,"11:13":true,"5:12":true,"13:11":true,"4:15":true,"8:6":true,"4:12":true,"12:13":true,"5:15":[133,159],"12:14":152,"10:5":true,"9:11":true,"3:7":true,"5:10":true,"10:11":true,"4:10":true,"11:14":true,"0:7":157,"12:15":[138,153],"11:12":true,"5:13":true,"3:9":true,"12:12":true,"11:15":[138,153],"8:3":181,"0:9":true,"7:11":true,"4:13":true,"2:6":[148,149]} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": [
+ 148,
+ 153
+ ],
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "10:14": true,
+ "7:15": [
+ 136,
+ 153
+ ],
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "9:15": true,
+ "0:6": [
+ 155,
+ 156
+ ],
+ "9:12": true,
+ "3:6": 150,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "13:15": [
+ 138,
+ 153
+ ],
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "7:13": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": 151,
+ "13:12": true,
+ "6:14": true,
+ "1:9": true,
+ "13:14": [
+ 138,
+ 152
+ ],
+ "10:13": true,
+ "3:4": [
+ 145,
+ 146
+ ],
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": [
+ 144,
+ 147
+ ],
+ "1:7": [
+ 154,
+ 156
+ ],
+ "0:4": 153,
+ "6:15": [
+ 134,
+ 156
+ ],
+ "9:13": true,
+ "14:14": [
+ 138,
+ 152
+ ],
+ "8:13": true,
+ "2:12": true,
+ "7:7": true,
+ "2:15": [
+ 135,
+ 161
+ ],
+ "15:14": [
+ 138,
+ 152
+ ],
+ "9:9": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": [
+ 146,
+ 149
+ ],
+ "15:12": true,
+ "14:15": [
+ 138,
+ 153
+ ],
+ "15:15": [
+ 138,
+ 153
+ ],
+ "14:12": true,
+ "9:7": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": 154,
+ "2:13": true,
+ "12:3": 145,
+ "11:4": [
+ 145,
+ 147
+ ],
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "1:14": true,
+ "12:4": true,
+ "8:15": [
+ 138,
+ 153
+ ],
+ "15:13": [
+ 138,
+ 151
+ ],
+ "1:15": [
+ 134,
+ 161
+ ],
+ "6:7": true,
+ "8:14": true,
+ "1:12": true,
+ "14:13": [
+ 138,
+ 152
+ ],
+ "3:13": true,
+ "5:9": true,
+ "0:13": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": 181,
+ "8:11": true,
+ "4:7": true,
+ "14:11": true,
+ "9:6": true,
+ "3:12": true,
+ "0:15": [
+ 135,
+ 175
+ ],
+ "10:6": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "3:14": true,
+ "4:8": true,
+ "4:14": true,
+ "1:6": [
+ 153,
+ 154
+ ],
+ "11:10": true,
+ "3:8": true,
+ "12:10": true,
+ "5:14": true,
+ "0:8": 157,
+ "6:11": true,
+ "11:13": true,
+ "5:12": true,
+ "13:11": true,
+ "4:15": true,
+ "8:6": true,
+ "4:12": true,
+ "12:13": true,
+ "5:15": [
+ 133,
+ 159
+ ],
+ "12:14": 152,
+ "10:5": true,
+ "9:11": true,
+ "3:7": true,
+ "5:10": true,
+ "10:11": true,
+ "4:10": true,
+ "11:14": true,
+ "0:7": 157,
+ "12:15": [
+ 138,
+ 153
+ ],
+ "11:12": true,
+ "5:13": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": [
+ 138,
+ 153
+ ],
+ "8:3": 181,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": [
+ 148,
+ 149
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_9.json
index 0bd4fdd5..970d3fc8 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-7_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-7_9.json
@@ -1 +1,316 @@
-{"1:1":[137,158],"8:8":true,"6:10":true,"13:13":true,"3:0":[135,158],"0:6":true,"0:0":[135,157],"3:6":true,"14:1":138,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":158,"15:1":138,"13:14":true,"3:4":[144,157],"0:3":true,"8:9":true,"7:10":true,"3:3":[144,158],"0:4":true,"2:1":[138,142],"14:14":true,"4:3":[144,157],"5:4":[144,157],"2:12":true,"10:9":true,"7:7":true,"5:3":[144,157],"2:15":true,"15:14":true,"9:9":true,"4:4":[144,157],"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"13:1":138,"4:2":[144,158],"0:11":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":[144,157],"2:14":true,"1:13":true,"0:5":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"4:0":true,"1:15":true,"10:8":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"0:13":true,"11:8":true,"13:6":true,"13:0":138,"13:2":[138,179],"4:1":[139,157],"3:12":true,"0:15":true,"11:9":true,"15:5":true,"14:5":true,"5:1":true,"3:15":true,"0:12":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"13:4":true,"3:14":true,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"11:10":true,"12:10":true,"5:14":true,"15:3":true,"1:0":[136,157],"14:4":true,"5:12":true,"2:4":true,"14:2":138,"13:11":true,"4:15":true,"0:1":true,"15:2":[138,182],"4:12":true,"3:1":[139,158],"13:5":true,"5:15":true,"2:3":[144,158],"15:0":138,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"14:0":138,"2:0":[140,158],"5:13":true,"1:2":[140,158],"4:13":true,"2:6":true,"15:9":true,"12:11":true,"9:14":true,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"10:14":true,"7:15":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":true,"13:10":true,"10:15":true,"7:14":true,"1:8":true,"7:13":true,"2:8":true,"6:14":true,"1:9":true,"15:8":true,"10:13":true,"6:12":true,"1:7":true,"6:15":true,"9:13":true,"11:0":true,"12:6":true,"8:13":true,"1:10":true,"6:1":140,"11:6":true,"11:4":true,"9:1":138,"8:12":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"12:2":[168,178],"2:10":true,"11:2":[138,177],"8:14":true,"13:9":true,"7:1":true,"12:1":true,"9:3":140,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":141,"6:6":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":143,"9:2":139,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"7:3":[142,155],"9:6":true,"6:4":144,"10:6":true,"6:3":[142,156],"5:8":true,"6:2":[141,143],"7:6":true,"4:8":true,"6:5":true,"3:8":true,"0:8":true,"6:11":true,"11:13":true,"8:0":151,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":140,"0:7":true,"12:15":true,"11:12":true,"8:4":142,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"8:3":141,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": [
+ 137,
+ 158
+ ],
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": [
+ 135,
+ 158
+ ],
+ "0:6": true,
+ "0:0": [
+ 135,
+ 157
+ ],
+ "3:6": true,
+ "14:1": 138,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": 158,
+ "15:1": 138,
+ "13:14": true,
+ "3:4": [
+ 144,
+ 157
+ ],
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": [
+ 144,
+ 158
+ ],
+ "0:4": true,
+ "2:1": [
+ 138,
+ 142
+ ],
+ "14:14": true,
+ "4:3": [
+ 144,
+ 157
+ ],
+ "5:4": [
+ 144,
+ 157
+ ],
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": [
+ 144,
+ 157
+ ],
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": [
+ 144,
+ 157
+ ],
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": 138,
+ "4:2": [
+ 144,
+ 158
+ ],
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": [
+ 144,
+ 157
+ ],
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "1:15": true,
+ "10:8": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": 138,
+ "13:2": [
+ 138,
+ 179
+ ],
+ "4:1": [
+ 139,
+ 157
+ ],
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": true,
+ "3:14": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "15:3": true,
+ "1:0": [
+ 136,
+ 157
+ ],
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": 138,
+ "13:11": true,
+ "4:15": true,
+ "0:1": true,
+ "15:2": [
+ 138,
+ 182
+ ],
+ "4:12": true,
+ "3:1": [
+ 139,
+ 158
+ ],
+ "13:5": true,
+ "5:15": true,
+ "2:3": [
+ 144,
+ 158
+ ],
+ "15:0": 138,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": 138,
+ "2:0": [
+ 140,
+ 158
+ ],
+ "5:13": true,
+ "1:2": [
+ 140,
+ 158
+ ],
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "7:13": true,
+ "2:8": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": true,
+ "1:10": true,
+ "6:1": 140,
+ "11:6": true,
+ "11:4": true,
+ "9:1": 138,
+ "8:12": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": [
+ 168,
+ 178
+ ],
+ "2:10": true,
+ "11:2": [
+ 138,
+ 177
+ ],
+ "8:14": true,
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": 140,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": 141,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": 143,
+ "9:2": 139,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": [
+ 142,
+ 155
+ ],
+ "9:6": true,
+ "6:4": 144,
+ "10:6": true,
+ "6:3": [
+ 142,
+ 156
+ ],
+ "5:8": true,
+ "6:2": [
+ 141,
+ 143
+ ],
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": 151,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": 140,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": 142,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": 141,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-1.json
index cd9b9487..7ab9b6cb 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-1.json
@@ -1 +1,31 @@
-{"10:3":[164,165],"11:1":164,"13:0":true,"10:2":160,"14:1":true,"13:2":true,"10:0":160,"15:1":true,"11:0":164,"12:0":217,"10:7":[178,179],"15:12":[153,154],"15:2":true,"10:1":160,"11:3":[164,165],"14:0":true,"11:2":165} \ No newline at end of file
+{
+ "10:3": [
+ 164,
+ 165
+ ],
+ "11:1": 164,
+ "13:0": true,
+ "10:2": 160,
+ "14:1": true,
+ "13:2": true,
+ "10:0": 160,
+ "15:1": true,
+ "11:0": 164,
+ "12:0": 217,
+ "10:7": [
+ 178,
+ 179
+ ],
+ "15:12": [
+ 153,
+ 154
+ ],
+ "15:2": true,
+ "10:1": 160,
+ "11:3": [
+ 164,
+ 165
+ ],
+ "14:0": true,
+ "11:2": 165
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-2.json
index e1b6709c..f9dfb020 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-2.json
@@ -1 +1,25 @@
-{"11:5":164,"11:11":true,"11:6":164,"3:5":true,"0:5":167,"12:3":149,"11:4":165,"11:3":true,"4:0":true,"12:1":158,"11:1":true,"11:8":true,"11:9":true,"10:6":160,"9:0":true,"11:7":165,"11:10":true,"11:13":true,"10:5":true,"11:14":true,"12:15":216,"11:12":true,"11:15":165} \ No newline at end of file
+{
+ "11:5": 164,
+ "11:11": true,
+ "11:6": 164,
+ "3:5": true,
+ "0:5": 167,
+ "12:3": 149,
+ "11:4": 165,
+ "11:3": true,
+ "4:0": true,
+ "12:1": 158,
+ "11:1": true,
+ "11:8": true,
+ "11:9": true,
+ "10:6": 160,
+ "9:0": true,
+ "11:7": 165,
+ "11:10": true,
+ "11:13": true,
+ "10:5": true,
+ "11:14": true,
+ "12:15": 216,
+ "11:12": true,
+ "11:15": 165
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-3.json
index 65b6d476..87cd0f65 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-3.json
@@ -1 +1,34 @@
-{"9:15":true,"13:14":164,"2:15":true,"15:14":196,"15:12":[166,167],"2:14":184,"1:13":184,"1:14":[170,185],"8:15":182,"2:10":183,"1:15":185,"14:13":[165,166],"0:13":185,"9:6":true,"0:15":[170,185],"0:14":[169,185],"14:3":true} \ No newline at end of file
+{
+ "9:15": true,
+ "13:14": 164,
+ "2:15": true,
+ "15:14": 196,
+ "15:12": [
+ 166,
+ 167
+ ],
+ "2:14": 184,
+ "1:13": 184,
+ "1:14": [
+ 170,
+ 185
+ ],
+ "8:15": 182,
+ "2:10": 183,
+ "1:15": 185,
+ "14:13": [
+ 165,
+ 166
+ ],
+ "0:13": 185,
+ "9:6": true,
+ "0:15": [
+ 170,
+ 185
+ ],
+ "0:14": [
+ 169,
+ 185
+ ],
+ "14:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-4.json
index aee1ef41..d984881a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-4.json
@@ -1 +1,30 @@
-{"6:10":[204,233],"5:11":204,"7:10":true,"6:12":true,"6:9":204,"14:13":true,"12:1":217,"9:3":205,"7:2":true,"7:4":[212,213],"7:3":[206,214],"13:2":true,"9:0":210,"15:4":true,"14:3":true,"6:11":true,"8:2":212,"8:4":true,"8:3":true} \ No newline at end of file
+{
+ "6:10": [
+ 204,
+ 233
+ ],
+ "5:11": 204,
+ "7:10": true,
+ "6:12": true,
+ "6:9": 204,
+ "14:13": true,
+ "12:1": 217,
+ "9:3": 205,
+ "7:2": true,
+ "7:4": [
+ 212,
+ 213
+ ],
+ "7:3": [
+ 206,
+ 214
+ ],
+ "13:2": true,
+ "9:0": 210,
+ "15:4": true,
+ "14:3": true,
+ "6:11": true,
+ "8:2": 212,
+ "8:4": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-5.json
index 50f3e00b..44379810 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-5.json
@@ -1 +1,21 @@
-{"2:7":true,"6:6":true,"0:6":171,"3:6":true,"10:15":211,"4:5":180,"15:8":true,"1:7":true,"7:6":true,"1:6":170,"6:5":181,"4:6":true,"3:7":true,"11:14":[211,212],"0:7":182,"2:6":true} \ No newline at end of file
+{
+ "2:7": true,
+ "6:6": true,
+ "0:6": 171,
+ "3:6": true,
+ "10:15": 211,
+ "4:5": 180,
+ "15:8": true,
+ "1:7": true,
+ "7:6": true,
+ "1:6": 170,
+ "6:5": 181,
+ "4:6": true,
+ "3:7": true,
+ "11:14": [
+ 211,
+ 212
+ ],
+ "0:7": 182,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-6.json
index 6dd850a8..8b25f421 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_-6.json
@@ -1 +1,5 @@
-{"12:6":true,"11:6":191,"10:6":192} \ No newline at end of file
+{
+ "12:6": true,
+ "11:6": 191,
+ "10:6": 192
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_0.json
index 4041bf83..1c778a7d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_0.json
@@ -1 +1,61 @@
-{"14:14":true,"9:14":true,"1:11":true,"3:13":[159,209],"2:12":true,"3:8":true,"13:13":true,"10:14":true,"2:15":true,"1:10":true,"0:13":true,"15:14":true,"11:13":true,"3:5":true,"3:10":true,"6:13":true,"8:0":true,"3:6":true,"3:11":[150,209],"12:13":true,"2:14":true,"1:13":true,"7:14":true,"12:14":true,"3:7":true,"3:12":[150,209],"2:13":true,"1:14":true,"7:13":true,"11:14":true,"3:15":[163,210],"6:14":true,"15:13":true,"13:14":true,"10:13":true,"5:13":true,"3:4":true,"2:10":true,"1:15":true,"0:14":true,"3:9":true,"3:14":true,"1:12":true,"14:13":true,"9:13":true,"4:13":true,"2:11":true} \ No newline at end of file
+{
+ "14:14": true,
+ "9:14": true,
+ "1:11": true,
+ "3:13": [
+ 159,
+ 209
+ ],
+ "2:12": true,
+ "3:8": true,
+ "13:13": true,
+ "10:14": true,
+ "2:15": true,
+ "1:10": true,
+ "0:13": true,
+ "15:14": true,
+ "11:13": true,
+ "3:5": true,
+ "3:10": true,
+ "6:13": true,
+ "8:0": true,
+ "3:6": true,
+ "3:11": [
+ 150,
+ 209
+ ],
+ "12:13": true,
+ "2:14": true,
+ "1:13": true,
+ "7:14": true,
+ "12:14": true,
+ "3:7": true,
+ "3:12": [
+ 150,
+ 209
+ ],
+ "2:13": true,
+ "1:14": true,
+ "7:13": true,
+ "11:14": true,
+ "3:15": [
+ 163,
+ 210
+ ],
+ "6:14": true,
+ "15:13": true,
+ "13:14": true,
+ "10:13": true,
+ "5:13": true,
+ "3:4": true,
+ "2:10": true,
+ "1:15": true,
+ "0:14": true,
+ "3:9": true,
+ "3:14": true,
+ "1:12": true,
+ "14:13": true,
+ "9:13": true,
+ "4:13": true,
+ "2:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_1.json
index 7d15d4b4..72b5e29c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_1.json
@@ -1 +1,106 @@
-{"6:0":true,"1:1":true,"11:5":true,"10:4":true,"3:13":true,"2:7":true,"12:5":true,"1:5":true,"7:2":true,"11:1":true,"9:4":true,"3:10":true,"7:4":true,"3:0":[160,210],"9:2":true,"13:0":true,"0:0":true,"3:6":[150,205],"1:8":true,"13:2":true,"5:5":true,"3:12":true,"0:2":true,"6:4":true,"2:8":true,"15:5":true,"10:0":true,"14:5":true,"5:1":true,"4:5":true,"3:2":[168,210],"15:1":true,"9:0":true,"7:0":true,"3:4":true,"2:5":true,"13:4":true,"3:14":true,"3:3":[163,210],"1:7":true,"0:4":true,"2:1":true,"15:4":true,"11:0":true,"14:3":true,"1:6":true,"6:5":true,"3:8":true,"2:2":true,"12:0":true,"1:0":true,"14:4":true,"3:5":[159,205],"2:4":true,"8:0":true,"13:1":true,"0:1":true,"15:2":192,"3:11":true,"3:1":[167,210],"13:5":true,"5:2":true,"2:3":true,"0:5":true,"15:0":true,"11:4":true,"10:5":true,"9:1":true,"3:7":[150,205],"1:3":true,"5:0":true,"9:5":true,"12:4":true,"1:4":true,"14:0":true,"4:0":true,"2:0":true,"1:2":true,"7:5":true,"3:9":true,"11:2":true,"7:1":true,"2:6":true} \ No newline at end of file
+{
+ "6:0": true,
+ "1:1": true,
+ "11:5": true,
+ "10:4": true,
+ "3:13": true,
+ "2:7": true,
+ "12:5": true,
+ "1:5": true,
+ "7:2": true,
+ "11:1": true,
+ "9:4": true,
+ "3:10": true,
+ "7:4": true,
+ "3:0": [
+ 160,
+ 210
+ ],
+ "9:2": true,
+ "13:0": true,
+ "0:0": true,
+ "3:6": [
+ 150,
+ 205
+ ],
+ "1:8": true,
+ "13:2": true,
+ "5:5": true,
+ "3:12": true,
+ "0:2": true,
+ "6:4": true,
+ "2:8": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "5:1": true,
+ "4:5": true,
+ "3:2": [
+ 168,
+ 210
+ ],
+ "15:1": true,
+ "9:0": true,
+ "7:0": true,
+ "3:4": true,
+ "2:5": true,
+ "13:4": true,
+ "3:14": true,
+ "3:3": [
+ 163,
+ 210
+ ],
+ "1:7": true,
+ "0:4": true,
+ "2:1": true,
+ "15:4": true,
+ "11:0": true,
+ "14:3": true,
+ "1:6": true,
+ "6:5": true,
+ "3:8": true,
+ "2:2": true,
+ "12:0": true,
+ "1:0": true,
+ "14:4": true,
+ "3:5": [
+ 159,
+ 205
+ ],
+ "2:4": true,
+ "8:0": true,
+ "13:1": true,
+ "0:1": true,
+ "15:2": 192,
+ "3:11": true,
+ "3:1": [
+ 167,
+ 210
+ ],
+ "13:5": true,
+ "5:2": true,
+ "2:3": true,
+ "0:5": true,
+ "15:0": true,
+ "11:4": true,
+ "10:5": true,
+ "9:1": true,
+ "3:7": [
+ 150,
+ 205
+ ],
+ "1:3": true,
+ "5:0": true,
+ "9:5": true,
+ "12:4": true,
+ "1:4": true,
+ "14:0": true,
+ "4:0": true,
+ "2:0": true,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "11:2": true,
+ "7:1": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_2.json
index 1024acf2..a1ab3fb3 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_2.json
@@ -1 +1,110 @@
-{"15:9":true,"12:11":true,"2:7":true,"8:8":true,"7:12":true,"6:10":true,"13:13":true,"14:9":true,"11:11":true,"10:12":true,"2:9":true,"15:7":true,"14:7":true,"9:12":true,"13:10":true,"1:8":true,"10:10":true,"8:7":true,"4:11":true,"2:8":true,"9:10":true,"5:11":true,"1:9":true,"15:8":true,"8:9":true,"7:10":true,"6:12":true,"1:7":true,"14:8":true,"14:14":true,"12:6":true,"2:12":true,"10:9":true,"7:7":true,"1:10":true,"13:8":true,"15:14":true,"9:9":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"15:12":true,"14:12":true,"9:7":true,"3:11":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"15:10":true,"14:10":true,"5:6":true,"13:7":true,"15:13":true,"2:10":true,"10:8":true,"6:7":true,"13:9":true,"9:8":true,"14:13":true,"3:13":true,"5:9":true,"6:6":true,"4:9":true,"5:7":true,"3:10":true,"11:8":true,"13:6":true,"8:11":true,"12:8":true,"14:11":true,"9:6":true,"3:12":true,"11:9":true,"10:6":true,"15:11":true,"12:9":true,"11:7":true,"5:8":true,"12:7":true,"7:6":true,"4:8":true,"2:11":true,"11:10":true,"3:8":true,"12:10":true,"0:8":true,"6:11":true,"11:13":true,"5:12":true,"13:11":true,"8:6":true,"4:12":true,"12:13":true,"14:6":true,"5:10":true,"9:11":true,"3:7":true,"10:11":true,"4:10":true,"15:6":true,"3:9":true,"12:12":true,"0:9":179,"7:11":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "15:7": true,
+ "14:7": true,
+ "9:12": true,
+ "13:10": true,
+ "1:8": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "1:9": true,
+ "15:8": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "1:7": true,
+ "14:8": true,
+ "14:14": true,
+ "12:6": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "1:10": true,
+ "13:8": true,
+ "15:14": true,
+ "9:9": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "15:12": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "15:10": true,
+ "14:10": true,
+ "5:6": true,
+ "13:7": true,
+ "15:13": true,
+ "2:10": true,
+ "10:8": true,
+ "6:7": true,
+ "13:9": true,
+ "9:8": true,
+ "14:13": true,
+ "3:13": true,
+ "5:9": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "13:6": true,
+ "8:11": true,
+ "12:8": true,
+ "14:11": true,
+ "9:6": true,
+ "3:12": true,
+ "11:9": true,
+ "10:6": true,
+ "15:11": true,
+ "12:9": true,
+ "11:7": true,
+ "5:8": true,
+ "12:7": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "11:10": true,
+ "3:8": true,
+ "12:10": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "5:12": true,
+ "13:11": true,
+ "8:6": true,
+ "4:12": true,
+ "12:13": true,
+ "14:6": true,
+ "5:10": true,
+ "9:11": true,
+ "3:7": true,
+ "10:11": true,
+ "4:10": true,
+ "15:6": true,
+ "3:9": true,
+ "12:12": true,
+ "0:9": 179,
+ "7:11": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_3.json
index a3278b89..d250466e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_3.json
@@ -1 +1,42 @@
-{"15:9":true,"14:9":true,"9:10":true,"4:5":169,"3:2":true,"15:8":[198,199],"3:4":[169,170],"3:3":true,"14:8":[198,199],"2:1":173,"10:9":true,"13:8":199,"4:4":true,"8:10":true,"4:2":true,"5:2":174,"12:3":true,"12:2":true,"11:2":[186,187],"13:9":true,"10:2":186,"4:1":[173,174],"13:3":true,"3:1":173,"10:11":true} \ No newline at end of file
+{
+ "15:9": true,
+ "14:9": true,
+ "9:10": true,
+ "4:5": 169,
+ "3:2": true,
+ "15:8": [
+ 198,
+ 199
+ ],
+ "3:4": [
+ 169,
+ 170
+ ],
+ "3:3": true,
+ "14:8": [
+ 198,
+ 199
+ ],
+ "2:1": 173,
+ "10:9": true,
+ "13:8": 199,
+ "4:4": true,
+ "8:10": true,
+ "4:2": true,
+ "5:2": 174,
+ "12:3": true,
+ "12:2": true,
+ "11:2": [
+ 186,
+ 187
+ ],
+ "13:9": true,
+ "10:2": 186,
+ "4:1": [
+ 173,
+ 174
+ ],
+ "13:3": true,
+ "3:1": 173,
+ "10:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_4.json
index 789747c8..232e64b6 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_4.json
@@ -1 +1,82 @@
-{"9:3":true,"6:0":true,"1:1":true,"11:5":true,"10:4":true,"10:3":true,"1:5":true,"7:2":true,"6:6":true,"11:1":true,"9:4":true,"8:5":true,"7:4":true,"3:0":true,"9:2":true,"0:6":true,"0:0":true,"8:1":true,"3:6":true,"10:2":true,"7:3":true,"9:6":true,"5:5":true,"4:1":true,"0:2":true,"6:4":true,"5:1":true,"4:5":true,"3:2":true,"9:0":true,"6:3":true,"7:0":true,"3:4":true,"2:5":true,"0:3":true,"3:3":true,"0:4":true,"6:2":true,"7:6":true,"2:1":true,"4:3":true,"1:6":true,"5:4":true,"6:5":true,"5:3":true,"2:2":true,"6:1":true,"1:0":true,"4:4":true,"3:5":true,"2:4":true,"8:0":true,"4:2":true,"0:1":true,"8:6":true,"3:1":true,"5:2":true,"2:3":true,"0:5":true,"11:4":true,"10:5":true,"9:1":true,"4:6":true,"1:3":true,"5:0":true,"10:1":true,"9:5":true,"5:6":true,"11:3":true,"8:2":true,"1:4":true,"4:0":true,"2:0":true,"8:4":true,"1:2":true,"7:5":true,"11:2":true,"8:3":true,"7:1":true,"2:6":true} \ No newline at end of file
+{
+ "9:3": true,
+ "6:0": true,
+ "1:1": true,
+ "11:5": true,
+ "10:4": true,
+ "10:3": true,
+ "1:5": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "7:4": true,
+ "3:0": true,
+ "9:2": true,
+ "0:6": true,
+ "0:0": true,
+ "8:1": true,
+ "3:6": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "5:5": true,
+ "4:1": true,
+ "0:2": true,
+ "6:4": true,
+ "5:1": true,
+ "4:5": true,
+ "3:2": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "3:4": true,
+ "2:5": true,
+ "0:3": true,
+ "3:3": true,
+ "0:4": true,
+ "6:2": true,
+ "7:6": true,
+ "2:1": true,
+ "4:3": true,
+ "1:6": true,
+ "5:4": true,
+ "6:5": true,
+ "5:3": true,
+ "2:2": true,
+ "6:1": true,
+ "1:0": true,
+ "4:4": true,
+ "3:5": true,
+ "2:4": true,
+ "8:0": true,
+ "4:2": true,
+ "0:1": true,
+ "8:6": true,
+ "3:1": true,
+ "5:2": true,
+ "2:3": true,
+ "0:5": true,
+ "11:4": true,
+ "10:5": true,
+ "9:1": true,
+ "4:6": true,
+ "1:3": true,
+ "5:0": true,
+ "10:1": true,
+ "9:5": true,
+ "5:6": true,
+ "11:3": true,
+ "8:2": true,
+ "1:4": true,
+ "4:0": true,
+ "2:0": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "11:2": true,
+ "8:3": true,
+ "7:1": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_5.json
index e9b7db0b..8e06143e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_5.json
@@ -1 +1,41 @@
-{"12:1":true,"1:1":true,"11:5":202,"12:5":true,"1:5":true,"11:1":true,"8:5":true,"8:1":true,"10:2":true,"14:1":true,"5:5":true,"4:1":true,"0:2":true,"15:5":true,"14:5":true,"5:1":true,"4:5":true,"15:1":true,"2:5":true,"0:3":true,"0:4":true,"2:1":true,"6:5":true,"6:1":true,"3:5":true,"13:1":true,"0:1":true,"3:1":true,"13:5":true,"0:5":true,"10:5":[198,202],"9:1":true,"10:1":true,"9:5":true,"7:5":true,"7:1":true} \ No newline at end of file
+{
+ "12:1": true,
+ "1:1": true,
+ "11:5": 202,
+ "12:5": true,
+ "1:5": true,
+ "11:1": true,
+ "8:5": true,
+ "8:1": true,
+ "10:2": true,
+ "14:1": true,
+ "5:5": true,
+ "4:1": true,
+ "0:2": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "4:5": true,
+ "15:1": true,
+ "2:5": true,
+ "0:3": true,
+ "0:4": true,
+ "2:1": true,
+ "6:5": true,
+ "6:1": true,
+ "3:5": true,
+ "13:1": true,
+ "0:1": true,
+ "3:1": true,
+ "13:5": true,
+ "0:5": true,
+ "10:5": [
+ 198,
+ 202
+ ],
+ "9:1": true,
+ "10:1": true,
+ "9:5": true,
+ "7:5": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_6.json
index e47f1f03..29c4dc07 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_6.json
@@ -1 +1,31 @@
-{"3:13":[146,147],"0:13":true,"14:1":true,"4:11":true,"3:12":true,"0:15":true,"5:11":[144,145],"0:12":true,"0:14":true,"4:12":[145,146],"2:14":[147,148],"2:13":true,"1:14":true,"1:15":[148,149]} \ No newline at end of file
+{
+ "3:13": [
+ 146,
+ 147
+ ],
+ "0:13": true,
+ "14:1": true,
+ "4:11": true,
+ "3:12": true,
+ "0:15": true,
+ "5:11": [
+ 144,
+ 145
+ ],
+ "0:12": true,
+ "0:14": true,
+ "4:12": [
+ 145,
+ 146
+ ],
+ "2:14": [
+ 147,
+ 148
+ ],
+ "2:13": true,
+ "1:14": true,
+ "1:15": [
+ 148,
+ 149
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_7.json
index 3154cd03..d3cf2923 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_7.json
@@ -1 +1,85 @@
-{"7:15":true,"2:9":158,"0:6":[157,159],"0:0":true,"3:6":true,"7:14":true,"13:15":152,"5:5":true,"0:2":true,"4:5":true,"13:12":true,"6:14":true,"1:9":true,"3:4":149,"0:3":151,"1:7":146,"6:15":true,"5:4":true,"2:12":true,"2:15":true,"1:10":true,"4:4":true,"3:5":true,"15:12":222,"0:11":true,"14:12":true,"2:14":true,"1:13":true,"0:5":157,"4:6":true,"2:13":true,"1:14":true,"5:6":true,"2:10":true,"1:15":true,"1:12":true,"3:13":true,"0:13":true,"6:6":true,"7:4":true,"0:10":true,"7:3":true,"3:12":true,"0:15":[151,159],"6:4":true,"3:15":true,"0:12":true,"2:5":149,"0:14":true,"3:14":true,"6:2":156,"7:6":true,"4:14":true,"1:6":[147,149],"6:5":true,"5:14":true,"0:8":[147,160],"4:15":true,"0:1":true,"8:6":true,"4:12":true,"0:7":[147,159],"5:13":true,"1:2":true,"12:12":true,"0:9":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "7:15": true,
+ "2:9": 158,
+ "0:6": [
+ 157,
+ 159
+ ],
+ "0:0": true,
+ "3:6": true,
+ "7:14": true,
+ "13:15": 152,
+ "5:5": true,
+ "0:2": true,
+ "4:5": true,
+ "13:12": true,
+ "6:14": true,
+ "1:9": true,
+ "3:4": 149,
+ "0:3": 151,
+ "1:7": 146,
+ "6:15": true,
+ "5:4": true,
+ "2:12": true,
+ "2:15": true,
+ "1:10": true,
+ "4:4": true,
+ "3:5": true,
+ "15:12": 222,
+ "0:11": true,
+ "14:12": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": 157,
+ "4:6": true,
+ "2:13": true,
+ "1:14": true,
+ "5:6": true,
+ "2:10": true,
+ "1:15": true,
+ "1:12": true,
+ "3:13": true,
+ "0:13": true,
+ "6:6": true,
+ "7:4": true,
+ "0:10": true,
+ "7:3": true,
+ "3:12": true,
+ "0:15": [
+ 151,
+ 159
+ ],
+ "6:4": true,
+ "3:15": true,
+ "0:12": true,
+ "2:5": 149,
+ "0:14": true,
+ "3:14": true,
+ "6:2": 156,
+ "7:6": true,
+ "4:14": true,
+ "1:6": [
+ 147,
+ 149
+ ],
+ "6:5": true,
+ "5:14": true,
+ "0:8": [
+ 147,
+ 160
+ ],
+ "4:15": true,
+ "0:1": true,
+ "8:6": true,
+ "4:12": true,
+ "0:7": [
+ 147,
+ 159
+ ],
+ "5:13": true,
+ "1:2": true,
+ "12:12": true,
+ "0:9": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_8.json
index 575f6f03..4863ca14 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_8.json
@@ -1 +1,265 @@
-{"13:13":[172,173],"3:0":true,"0:6":[149,155],"0:0":[153,159],"14:1":true,"13:15":true,"4:11":true,"0:2":true,"5:11":true,"13:12":172,"3:2":[153,155],"13:14":true,"0:3":true,"0:4":[149,154],"2:1":[153,154],"14:14":174,"4:3":true,"5:4":[152,153],"2:12":true,"5:3":[154,155],"2:15":true,"15:14":157,"15:12":true,"14:15":true,"13:1":154,"4:2":[156,158],"0:11":true,"15:15":[136,175],"2:14":true,"1:13":true,"0:5":[149,154],"1:14":true,"4:0":true,"15:13":true,"1:15":true,"10:8":166,"1:12":true,"1:11":true,"3:13":true,"0:13":true,"13:6":157,"13:0":true,"12:8":153,"13:2":true,"4:1":true,"3:12":true,"0:15":true,"11:9":167,"14:5":157,"3:15":true,"0:12":true,"12:9":[168,169],"0:14":true,"13:4":157,"12:7":[154,156],"3:14":true,"2:11":true,"15:4":154,"14:3":155,"4:14":true,"11:10":167,"12:10":[169,170],"5:14":true,"15:3":153,"1:0":153,"5:12":true,"14:2":155,"13:11":[153,171],"4:15":true,"0:1":[154,156],"4:12":true,"3:1":[155,158],"13:5":157,"5:15":true,"15:0":true,"14:6":157,"15:6":157,"2:0":true,"5:13":true,"4:13":true,"15:9":true,"12:11":[153,170],"9:14":true,"11:5":156,"12:5":157,"10:14":true,"7:15":true,"14:9":157,"11:11":[151,152],"10:12":[149,153],"6:13":true,"15:7":157,"9:15":true,"14:7":157,"9:12":true,"8:1":true,"13:10":152,"10:15":true,"7:14":true,"7:13":true,"6:14":true,"15:8":157,"10:13":true,"6:12":true,"6:15":true,"14:8":157,"9:13":true,"12:6":157,"8:13":true,"1:10":true,"13:8":[154,156],"6:1":true,"11:6":[153,156],"12:3":true,"11:4":157,"9:1":true,"8:12":true,"15:10":true,"14:10":[153,156],"13:7":157,"12:4":157,"11:3":true,"8:15":true,"11:2":true,"8:14":true,"13:9":[153,156],"7:1":true,"9:3":true,"6:0":true,"10:4":157,"10:3":true,"9:4":156,"8:5":true,"7:4":[153,156],"9:2":true,"10:2":true,"0:10":[149,182],"7:3":true,"6:4":[152,155],"10:6":[153,154],"6:3":156,"7:0":true,"0:8":[149,157],"6:11":true,"11:13":155,"8:0":true,"12:13":155,"12:14":true,"10:5":[155,156],"5:10":183,"9:5":true,"11:14":true,"0:7":[148,155],"12:15":true,"11:12":[150,154],"8:4":[155,157],"7:5":true,"12:12":154,"11:15":true,"8:3":158,"0:9":[151,157]} \ No newline at end of file
+{
+ "13:13": [
+ 172,
+ 173
+ ],
+ "3:0": true,
+ "0:6": [
+ 149,
+ 155
+ ],
+ "0:0": [
+ 153,
+ 159
+ ],
+ "14:1": true,
+ "13:15": true,
+ "4:11": true,
+ "0:2": true,
+ "5:11": true,
+ "13:12": 172,
+ "3:2": [
+ 153,
+ 155
+ ],
+ "13:14": true,
+ "0:3": true,
+ "0:4": [
+ 149,
+ 154
+ ],
+ "2:1": [
+ 153,
+ 154
+ ],
+ "14:14": 174,
+ "4:3": true,
+ "5:4": [
+ 152,
+ 153
+ ],
+ "2:12": true,
+ "5:3": [
+ 154,
+ 155
+ ],
+ "2:15": true,
+ "15:14": 157,
+ "15:12": true,
+ "14:15": true,
+ "13:1": 154,
+ "4:2": [
+ 156,
+ 158
+ ],
+ "0:11": true,
+ "15:15": [
+ 136,
+ 175
+ ],
+ "2:14": true,
+ "1:13": true,
+ "0:5": [
+ 149,
+ 154
+ ],
+ "1:14": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": 166,
+ "1:12": true,
+ "1:11": true,
+ "3:13": true,
+ "0:13": true,
+ "13:6": 157,
+ "13:0": true,
+ "12:8": 153,
+ "13:2": true,
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": 167,
+ "14:5": 157,
+ "3:15": true,
+ "0:12": true,
+ "12:9": [
+ 168,
+ 169
+ ],
+ "0:14": true,
+ "13:4": 157,
+ "12:7": [
+ 154,
+ 156
+ ],
+ "3:14": true,
+ "2:11": true,
+ "15:4": 154,
+ "14:3": 155,
+ "4:14": true,
+ "11:10": 167,
+ "12:10": [
+ 169,
+ 170
+ ],
+ "5:14": true,
+ "15:3": 153,
+ "1:0": 153,
+ "5:12": true,
+ "14:2": 155,
+ "13:11": [
+ 153,
+ 171
+ ],
+ "4:15": true,
+ "0:1": [
+ 154,
+ 156
+ ],
+ "4:12": true,
+ "3:1": [
+ 155,
+ 158
+ ],
+ "13:5": 157,
+ "5:15": true,
+ "15:0": true,
+ "14:6": 157,
+ "15:6": 157,
+ "2:0": true,
+ "5:13": true,
+ "4:13": true,
+ "15:9": true,
+ "12:11": [
+ 153,
+ 170
+ ],
+ "9:14": true,
+ "11:5": 156,
+ "12:5": 157,
+ "10:14": true,
+ "7:15": true,
+ "14:9": 157,
+ "11:11": [
+ 151,
+ 152
+ ],
+ "10:12": [
+ 149,
+ 153
+ ],
+ "6:13": true,
+ "15:7": 157,
+ "9:15": true,
+ "14:7": 157,
+ "9:12": true,
+ "8:1": true,
+ "13:10": 152,
+ "10:15": true,
+ "7:14": true,
+ "7:13": true,
+ "6:14": true,
+ "15:8": 157,
+ "10:13": true,
+ "6:12": true,
+ "6:15": true,
+ "14:8": 157,
+ "9:13": true,
+ "12:6": 157,
+ "8:13": true,
+ "1:10": true,
+ "13:8": [
+ 154,
+ 156
+ ],
+ "6:1": true,
+ "11:6": [
+ 153,
+ 156
+ ],
+ "12:3": true,
+ "11:4": 157,
+ "9:1": true,
+ "8:12": true,
+ "15:10": true,
+ "14:10": [
+ 153,
+ 156
+ ],
+ "13:7": 157,
+ "12:4": 157,
+ "11:3": true,
+ "8:15": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": [
+ 153,
+ 156
+ ],
+ "7:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": 157,
+ "10:3": true,
+ "9:4": 156,
+ "8:5": true,
+ "7:4": [
+ 153,
+ 156
+ ],
+ "9:2": true,
+ "10:2": true,
+ "0:10": [
+ 149,
+ 182
+ ],
+ "7:3": true,
+ "6:4": [
+ 152,
+ 155
+ ],
+ "10:6": [
+ 153,
+ 154
+ ],
+ "6:3": 156,
+ "7:0": true,
+ "0:8": [
+ 149,
+ 157
+ ],
+ "6:11": true,
+ "11:13": 155,
+ "8:0": true,
+ "12:13": 155,
+ "12:14": true,
+ "10:5": [
+ 155,
+ 156
+ ],
+ "5:10": 183,
+ "9:5": true,
+ "11:14": true,
+ "0:7": [
+ 148,
+ 155
+ ],
+ "12:15": true,
+ "11:12": [
+ 150,
+ 154
+ ],
+ "8:4": [
+ 155,
+ 157
+ ],
+ "7:5": true,
+ "12:12": 154,
+ "11:15": true,
+ "8:3": 158,
+ "0:9": [
+ 151,
+ 157
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_9.json
index 9990588f..65c19273 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-8_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-8_9.json
@@ -1 +1,213 @@
-{"1:1":true,"13:13":true,"3:0":true,"0:6":[171,173],"0:0":true,"3:6":174,"14:1":true,"10:10":[152,154],"8:7":true,"5:5":177,"0:2":true,"9:10":154,"4:5":176,"13:12":true,"3:2":true,"15:1":true,"3:4":true,"0:3":true,"8:9":154,"7:10":156,"3:3":true,"0:4":true,"2:1":true,"14:14":true,"4:3":true,"5:4":true,"10:9":152,"7:7":true,"5:3":true,"15:14":true,"9:9":153,"4:4":true,"10:7":true,"8:10":155,"7:9":155,"3:5":175,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"15:15":true,"14:12":true,"9:7":true,"5:2":true,"0:5":[171,175],"7:8":154,"4:6":175,"5:0":true,"5:6":176,"4:0":true,"15:13":true,"10:8":true,"6:7":[175,176],"14:13":true,"1:5":[170,173],"11:8":true,"13:6":true,"13:0":true,"12:8":true,"14:11":true,"13:2":true,"4:1":true,"11:9":[137,142],"15:5":true,"14:5":true,"5:1":true,"15:11":true,"12:9":true,"13:3":true,"11:7":true,"2:5":174,"13:4":true,"12:7":true,"15:4":true,"14:3":true,"11:10":true,"12:10":true,"2:2":true,"15:3":true,"1:0":true,"14:4":true,"2:4":true,"14:2":true,"13:11":true,"0:1":true,"15:2":true,"3:1":true,"13:5":true,"2:3":true,"15:0":true,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"14:0":true,"2:0":true,"1:2":true,"2:6":173,"15:9":true,"12:11":true,"9:14":true,"11:5":true,"7:12":true,"12:5":true,"10:14":true,"14:9":true,"11:11":true,"10:12":true,"15:7":true,"14:7":true,"9:12":true,"8:1":true,"13:10":true,"10:15":true,"7:13":155,"15:8":true,"10:13":true,"14:8":true,"9:13":true,"11:0":true,"12:6":true,"8:13":true,"13:8":true,"12:0":true,"6:1":true,"11:6":true,"12:3":true,"11:4":true,"9:1":true,"8:12":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"12:2":true,"11:2":true,"13:9":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"10:3":true,"7:2":true,"6:6":177,"11:1":true,"9:4":true,"8:5":true,"5:7":[174,175],"7:4":true,"9:2":true,"8:11":true,"4:7":[173,174],"10:2":true,"7:3":true,"9:6":true,"6:4":true,"10:0":true,"10:6":true,"9:0":true,"6:3":true,"7:0":true,"6:2":true,"7:6":true,"6:5":true,"11:13":true,"8:0":true,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"3:7":173,"10:11":true,"9:5":true,"11:14":true,"8:2":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "13:13": true,
+ "3:0": true,
+ "0:6": [
+ 171,
+ 173
+ ],
+ "0:0": true,
+ "3:6": 174,
+ "14:1": true,
+ "10:10": [
+ 152,
+ 154
+ ],
+ "8:7": true,
+ "5:5": 177,
+ "0:2": true,
+ "9:10": 154,
+ "4:5": 176,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": 154,
+ "7:10": 156,
+ "3:3": true,
+ "0:4": true,
+ "2:1": true,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "10:9": 152,
+ "7:7": true,
+ "5:3": true,
+ "15:14": true,
+ "9:9": 153,
+ "4:4": true,
+ "10:7": true,
+ "8:10": 155,
+ "7:9": 155,
+ "3:5": 175,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "5:2": true,
+ "0:5": [
+ 171,
+ 175
+ ],
+ "7:8": 154,
+ "4:6": 175,
+ "5:0": true,
+ "5:6": 176,
+ "4:0": true,
+ "15:13": true,
+ "10:8": true,
+ "6:7": [
+ 175,
+ 176
+ ],
+ "14:13": true,
+ "1:5": [
+ 170,
+ 173
+ ],
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "4:1": true,
+ "11:9": [
+ 137,
+ 142
+ ],
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": 174,
+ "13:4": true,
+ "12:7": true,
+ "15:4": true,
+ "14:3": true,
+ "11:10": true,
+ "12:10": true,
+ "2:2": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "0:1": true,
+ "15:2": true,
+ "3:1": true,
+ "13:5": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "1:2": true,
+ "2:6": 173,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "15:7": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "7:13": 155,
+ "15:8": true,
+ "10:13": true,
+ "14:8": true,
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": true,
+ "11:6": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "12:2": true,
+ "11:2": true,
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": 177,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": [
+ 174,
+ 175
+ ],
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": [
+ 173,
+ 174
+ ],
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "6:2": true,
+ "7:6": true,
+ "6:5": true,
+ "11:13": true,
+ "8:0": true,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "3:7": 173,
+ "10:11": true,
+ "9:5": true,
+ "11:14": true,
+ "8:2": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-1.json
index d31fa63e..3b14a2de 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-1.json
@@ -1 +1,20 @@
-{"11:5":true,"8:5":true,"0:6":197,"7:14":[165,168],"10:6":true,"6:14":[166,167],"11:6":true,"10:7":true,"9:7":true,"5:15":166,"0:5":196,"8:14":true} \ No newline at end of file
+{
+ "11:5": true,
+ "8:5": true,
+ "0:6": 197,
+ "7:14": [
+ 165,
+ 168
+ ],
+ "10:6": true,
+ "6:14": [
+ 166,
+ 167
+ ],
+ "11:6": true,
+ "10:7": true,
+ "9:7": true,
+ "5:15": 166,
+ "0:5": 196,
+ "8:14": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-2.json
index aca1f76c..3f60da15 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-2.json
@@ -1 +1,36 @@
-{"0:6":true,"0:0":[168,212],"14:1":[169,170],"0:2":true,"3:4":true,"5:3":true,"13:1":169,"10:1":211,"10:3":211,"13:0":168,"10:2":211,"13:2":true,"15:5":true,"2:5":true,"14:3":168,"1:0":168,"14:2":169,"0:1":[167,216],"15:0":[169,170],"15:6":true,"14:0":168,"1:2":216} \ No newline at end of file
+{
+ "0:6": true,
+ "0:0": [
+ 168,
+ 212
+ ],
+ "14:1": [
+ 169,
+ 170
+ ],
+ "0:2": true,
+ "3:4": true,
+ "5:3": true,
+ "13:1": 169,
+ "10:1": 211,
+ "10:3": 211,
+ "13:0": 168,
+ "10:2": 211,
+ "13:2": true,
+ "15:5": true,
+ "2:5": true,
+ "14:3": 168,
+ "1:0": 168,
+ "14:2": 169,
+ "0:1": [
+ 167,
+ 216
+ ],
+ "15:0": [
+ 169,
+ 170
+ ],
+ "15:6": true,
+ "14:0": 168,
+ "1:2": 216
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-3.json
index 9a2f6ba9..84181f40 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-3.json
@@ -1 +1,31 @@
-{"12:5":true,"10:12":true,"10:13":true,"12:6":true,"15:14":185,"14:15":168,"15:15":169,"3:11":169,"12:4":210,"13:6":201,"13:2":211,"15:5":201,"14:5":201,"13:3":[210,211],"11:7":208,"13:4":[201,211],"12:7":201,"14:3":201,"14:4":true,"14:2":212,"13:5":201,"14:6":201,"10:11":true} \ No newline at end of file
+{
+ "12:5": true,
+ "10:12": true,
+ "10:13": true,
+ "12:6": true,
+ "15:14": 185,
+ "14:15": 168,
+ "15:15": 169,
+ "3:11": 169,
+ "12:4": 210,
+ "13:6": 201,
+ "13:2": 211,
+ "15:5": 201,
+ "14:5": 201,
+ "13:3": [
+ 210,
+ 211
+ ],
+ "11:7": 208,
+ "13:4": [
+ 201,
+ 211
+ ],
+ "12:7": 201,
+ "14:3": 201,
+ "14:4": true,
+ "14:2": 212,
+ "13:5": 201,
+ "14:6": 201,
+ "10:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-4.json
index 3994b683..146a0bba 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-4.json
@@ -1 +1,23 @@
-{"7:7":true,"5:9":true,"10:3":true,"0:13":true,"6:6":true,"4:9":true,"6:8":true,"5:7":true,"5:12":true,"7:8":true,"5:10":true,"1:3":true,"0:2":true,"5:11":true,"1:4":true,"0:12":true,"0:14":true,"1:2":true,"6:7":true,"5:8":true,"0:4":true} \ No newline at end of file
+{
+ "7:7": true,
+ "5:9": true,
+ "10:3": true,
+ "0:13": true,
+ "6:6": true,
+ "4:9": true,
+ "6:8": true,
+ "5:7": true,
+ "5:12": true,
+ "7:8": true,
+ "5:10": true,
+ "1:3": true,
+ "0:2": true,
+ "5:11": true,
+ "1:4": true,
+ "0:12": true,
+ "0:14": true,
+ "1:2": true,
+ "6:7": true,
+ "5:8": true,
+ "0:4": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-5.json
index 8cf4d4b1..ead7e176 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-5.json
@@ -1 +1,49 @@
-{"8:8":true,"6:6":true,"5:7":true,"0:0":188,"12:8":[172,173],"0:2":true,"10:10":[222,223],"14:5":[200,201],"9:10":224,"8:9":true,"5:8":true,"2:11":true,"15:4":[201,202],"2:12":true,"10:9":223,"7:7":true,"2:15":true,"9:9":true,"14:4":200,"8:10":true,"7:9":true,"6:8":true,"0:1":true,"2:14":true,"14:6":[200,201],"9:11":224,"7:8":true,"2:13":true,"10:11":223,"5:6":true,"13:7":172,"6:7":true} \ No newline at end of file
+{
+ "8:8": true,
+ "6:6": true,
+ "5:7": true,
+ "0:0": 188,
+ "12:8": [
+ 172,
+ 173
+ ],
+ "0:2": true,
+ "10:10": [
+ 222,
+ 223
+ ],
+ "14:5": [
+ 200,
+ 201
+ ],
+ "9:10": 224,
+ "8:9": true,
+ "5:8": true,
+ "2:11": true,
+ "15:4": [
+ 201,
+ 202
+ ],
+ "2:12": true,
+ "10:9": 223,
+ "7:7": true,
+ "2:15": true,
+ "9:9": true,
+ "14:4": 200,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "0:1": true,
+ "2:14": true,
+ "14:6": [
+ 200,
+ 201
+ ],
+ "9:11": 224,
+ "7:8": true,
+ "2:13": true,
+ "10:11": 223,
+ "5:6": true,
+ "13:7": 172,
+ "6:7": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-6.json
index 69ff3534..2bb76172 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_-6.json
@@ -1 +1,22 @@
-{"7:12":true,"0:2":201,"3:4":true,"0:3":[201,216],"6:12":true,"3:14":226,"7:6":true,"4:14":226,"5:14":true,"4:4":true,"2:4":true,"2:3":201,"1:3":201,"1:4":true,"5:13":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "7:12": true,
+ "0:2": 201,
+ "3:4": true,
+ "0:3": [
+ 201,
+ 216
+ ],
+ "6:12": true,
+ "3:14": 226,
+ "7:6": true,
+ "4:14": 226,
+ "5:14": true,
+ "4:4": true,
+ "2:4": true,
+ "2:3": 201,
+ "1:3": 201,
+ "1:4": true,
+ "5:13": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_0.json
index 5d27980e..405d0278 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_0.json
@@ -1 +1,29 @@
-{"12:1":true,"9:14":true,"8:13":true,"3:13":true,"0:13":true,"13:13":true,"10:14":true,"5:14":true,"12:0":true,"14:4":true,"11:1":true,"11:13":true,"6:13":true,"1:13":true,"7:14":true,"12:3":true,"7:13":true,"6:14":true,"15:13":true,"0:14":true,"12:2":true,"10:13":true,"5:13":true,"13:4":true,"11:2":true,"8:14":true,"9:13":true} \ No newline at end of file
+{
+ "12:1": true,
+ "9:14": true,
+ "8:13": true,
+ "3:13": true,
+ "0:13": true,
+ "13:13": true,
+ "10:14": true,
+ "5:14": true,
+ "12:0": true,
+ "14:4": true,
+ "11:1": true,
+ "11:13": true,
+ "6:13": true,
+ "1:13": true,
+ "7:14": true,
+ "12:3": true,
+ "7:13": true,
+ "6:14": true,
+ "15:13": true,
+ "0:14": true,
+ "12:2": true,
+ "10:13": true,
+ "5:13": true,
+ "13:4": true,
+ "11:2": true,
+ "8:14": true,
+ "9:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_2.json
index f2607f0a..a73a600d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_2.json
@@ -1 +1,23 @@
-{"11:0":true,"15:9":true,"12:1":true,"12:11":true,"6:10":true,"13:13":[177,179],"12:10":true,"14:9":true,"12:0":true,"6:11":true,"11:1":true,"13:10":true,"12:8":true,"15:8":true,"12:2":true,"13:9":true,"14:8":true,"14:13":178} \ No newline at end of file
+{
+ "11:0": true,
+ "15:9": true,
+ "12:1": true,
+ "12:11": true,
+ "6:10": true,
+ "13:13": [
+ 177,
+ 179
+ ],
+ "12:10": true,
+ "14:9": true,
+ "12:0": true,
+ "6:11": true,
+ "11:1": true,
+ "13:10": true,
+ "12:8": true,
+ "15:8": true,
+ "12:2": true,
+ "13:9": true,
+ "14:8": true,
+ "14:13": 178
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_3.json
index 1ccf4ded..aee761df 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_3.json
@@ -1 +1,6 @@
-{"10:7":true,"9:7":true,"10:6":true,"10:8":true} \ No newline at end of file
+{
+ "10:7": true,
+ "9:7": true,
+ "10:6": true,
+ "10:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_4.json
index 4471b7ad..66948398 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_4.json
@@ -1 +1,84 @@
-{"12:1":true,"9:3":true,"11:5":true,"10:4":true,"12:5":true,"10:3":true,"7:2":true,"11:1":true,"9:4":true,"8:5":true,"7:4":true,"13:6":true,"9:2":true,"13:0":true,"8:1":true,"10:2":true,"7:3":true,"14:1":true,"13:2":true,"9:6":true,"5:5":true,"6:4":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"5:1":true,"15:1":true,"9:0":true,"6:3":true,"7:0":true,"0:3":true,"13:3":true,"13:4":true,"6:2":true,"7:6":true,"15:4":true,"11:0":true,"14:3":true,"12:6":true,"5:4":true,"6:5":true,"5:3":true,"15:3":true,"12:0":true,"6:1":true,"14:4":true,"11:6":true,"8:0":true,"14:2":true,"13:1":true,"0:1":[174,175],"15:2":true,"8:6":true,"13:5":true,"5:2":true,"0:5":[174,175],"15:0":true,"14:6":true,"12:3":true,"11:4":true,"10:5":true,"9:1":true,"10:1":true,"9:5":true,"12:4":true,"11:3":true,"8:2":true,"15:6":true,"14:0":true,"12:2":true,"8:4":true,"7:5":true,"11:2":true,"8:3":true,"7:1":true} \ No newline at end of file
+{
+ "12:1": true,
+ "9:3": true,
+ "11:5": true,
+ "10:4": true,
+ "12:5": true,
+ "10:3": true,
+ "7:2": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "8:1": true,
+ "10:2": true,
+ "7:3": true,
+ "14:1": true,
+ "13:2": true,
+ "9:6": true,
+ "5:5": true,
+ "6:4": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": true,
+ "15:1": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "0:3": true,
+ "13:3": true,
+ "13:4": true,
+ "6:2": true,
+ "7:6": true,
+ "15:4": true,
+ "11:0": true,
+ "14:3": true,
+ "12:6": true,
+ "5:4": true,
+ "6:5": true,
+ "5:3": true,
+ "15:3": true,
+ "12:0": true,
+ "6:1": true,
+ "14:4": true,
+ "11:6": true,
+ "8:0": true,
+ "14:2": true,
+ "13:1": true,
+ "0:1": [
+ 174,
+ 175
+ ],
+ "15:2": true,
+ "8:6": true,
+ "13:5": true,
+ "5:2": true,
+ "0:5": [
+ 174,
+ 175
+ ],
+ "15:0": true,
+ "14:6": true,
+ "12:3": true,
+ "11:4": true,
+ "10:5": true,
+ "9:1": true,
+ "10:1": true,
+ "9:5": true,
+ "12:4": true,
+ "11:3": true,
+ "8:2": true,
+ "15:6": true,
+ "14:0": true,
+ "12:2": true,
+ "8:4": true,
+ "7:5": true,
+ "11:2": true,
+ "8:3": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_7.json
index 771280f8..822d27e8 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_7.json
@@ -1 +1,292 @@
-{"1:1":true,"8:8":true,"6:10":true,"13:13":true,"3:0":true,"0:6":true,"0:0":true,"3:6":true,"14:1":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"0:4":true,"2:1":true,"4:3":true,"5:4":true,"2:12":[152,154],"10:9":true,"7:7":true,"5:3":true,"15:14":[154,155],"9:9":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"13:1":true,"4:2":true,"0:11":true,"14:12":true,"9:7":true,"3:11":[154,173],"5:2":true,"1:13":true,"0:5":true,"2:13":[149,151],"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"4:0":true,"15:13":true,"1:15":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"0:13":true,"11:8":true,"13:6":true,"13:0":true,"12:8":true,"14:11":true,"13:2":true,"4:1":true,"3:12":[150,175],"0:15":true,"11:9":true,"14:5":true,"5:1":true,"3:15":true,"0:12":true,"15:11":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"13:4":true,"12:7":true,"3:14":[164,175],"2:11":155,"15:4":true,"14:3":true,"1:6":true,"11:10":true,"12:10":true,"2:2":true,"15:3":true,"1:0":true,"14:4":true,"5:12":[147,152],"2:4":true,"14:2":true,"13:11":true,"0:1":true,"15:2":true,"4:12":[148,152],"3:1":true,"13:5":true,"2:3":true,"15:0":true,"14:6":true,"1:3":true,"1:4":true,"15:6":150,"14:0":true,"2:0":true,"5:13":147,"1:2":true,"2:6":true,"15:9":true,"12:11":true,"9:14":152,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"10:14":151,"7:15":[149,151],"14:9":true,"11:11":true,"10:12":151,"6:13":[148,149],"2:9":true,"15:7":[148,157],"9:15":152,"14:7":true,"9:12":151,"8:1":true,"13:10":true,"10:15":152,"7:14":[148,151],"1:8":true,"7:13":true,"2:8":true,"6:14":[146,147],"1:9":[155,202],"15:8":true,"10:13":151,"6:12":true,"1:7":true,"6:15":[146,148],"14:8":true,"9:13":true,"12:6":true,"8:13":true,"1:10":true,"13:8":true,"6:1":true,"11:6":true,"12:3":true,"11:4":true,"8:12":true,"15:10":true,"14:10":true,"13:7":true,"12:4":true,"11:3":true,"8:15":152,"12:2":true,"2:10":[155,192],"11:2":true,"8:14":152,"13:9":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"4:9":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"7:3":true,"9:6":true,"10:6":true,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"3:8":true,"0:8":[156,202],"6:11":true,"11:13":[149,150],"8:6":true,"12:13":[147,148],"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"0:7":true,"11:12":150,"8:4":true,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"8:3":true,"0:9":[156,194],"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "3:6": true,
+ "14:1": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": [
+ 152,
+ 154
+ ],
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "15:14": [
+ 154,
+ 155
+ ],
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": [
+ 154,
+ 173
+ ],
+ "5:2": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": [
+ 149,
+ 151
+ ],
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "4:1": true,
+ "3:12": [
+ 150,
+ 175
+ ],
+ "0:15": true,
+ "11:9": true,
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": true,
+ "3:14": [
+ 164,
+ 175
+ ],
+ "2:11": 155,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "2:2": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "5:12": [
+ 147,
+ 152
+ ],
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "0:1": true,
+ "15:2": true,
+ "4:12": [
+ 148,
+ 152
+ ],
+ "3:1": true,
+ "13:5": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": 150,
+ "14:0": true,
+ "2:0": true,
+ "5:13": 147,
+ "1:2": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": 152,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": 151,
+ "7:15": [
+ 149,
+ 151
+ ],
+ "14:9": true,
+ "11:11": true,
+ "10:12": 151,
+ "6:13": [
+ 148,
+ 149
+ ],
+ "2:9": true,
+ "15:7": [
+ 148,
+ 157
+ ],
+ "9:15": 152,
+ "14:7": true,
+ "9:12": 151,
+ "8:1": true,
+ "13:10": true,
+ "10:15": 152,
+ "7:14": [
+ 148,
+ 151
+ ],
+ "1:8": true,
+ "7:13": true,
+ "2:8": true,
+ "6:14": [
+ 146,
+ 147
+ ],
+ "1:9": [
+ 155,
+ 202
+ ],
+ "15:8": true,
+ "10:13": 151,
+ "6:12": true,
+ "1:7": true,
+ "6:15": [
+ 146,
+ 148
+ ],
+ "14:8": true,
+ "9:13": true,
+ "12:6": true,
+ "8:13": true,
+ "1:10": true,
+ "13:8": true,
+ "6:1": true,
+ "11:6": true,
+ "12:3": true,
+ "11:4": true,
+ "8:12": true,
+ "15:10": true,
+ "14:10": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": 152,
+ "12:2": true,
+ "2:10": [
+ 155,
+ 192
+ ],
+ "11:2": true,
+ "8:14": 152,
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "4:9": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "9:6": true,
+ "10:6": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "3:8": true,
+ "0:8": [
+ 156,
+ 202
+ ],
+ "6:11": true,
+ "11:13": [
+ 149,
+ 150
+ ],
+ "8:6": true,
+ "12:13": [
+ 147,
+ 148
+ ],
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "11:12": 150,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": [
+ 156,
+ 194
+ ],
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_8.json
index d412a806..dec30d93 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_8.json
@@ -1 +1,279 @@
-{"1:1":true,"8:8":true,"6:10":true,"13:13":true,"3:0":true,"0:6":true,"0:0":true,"3:6":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"0:4":true,"2:1":true,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"15:14":true,"9:9":true,"4:4":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"4:2":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":true,"2:14":true,"1:13":true,"0:5":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"15:13":true,"1:15":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"0:13":true,"11:8":true,"13:6":155,"12:8":true,"14:11":true,"4:1":true,"3:12":true,"0:15":true,"11:9":true,"14:5":[151,152],"5:1":true,"3:15":true,"0:12":true,"15:11":true,"12:9":true,"13:3":[152,153],"11:7":true,"2:5":true,"0:14":true,"13:4":[149,153],"12:7":true,"2:11":true,"4:14":true,"1:6":true,"11:10":true,"12:10":true,"5:14":true,"2:2":true,"1:0":true,"5:12":true,"2:4":true,"13:11":true,"4:15":true,"0:1":true,"4:12":true,"3:1":true,"13:5":[147,154],"5:15":true,"2:3":true,"14:6":[148,154],"1:3":true,"1:4":true,"2:0":true,"5:13":true,"4:13":true,"2:6":true,"15:9":true,"12:11":true,"9:14":true,"2:7":true,"7:12":true,"12:5":155,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"2:9":true,"15:7":[150,154],"9:15":true,"14:7":[148,155],"9:12":true,"8:1":152,"13:10":true,"10:15":true,"7:14":true,"1:8":true,"7:13":true,"2:8":true,"6:14":true,"1:9":true,"15:8":[150,155],"10:13":true,"6:12":true,"1:7":true,"6:15":true,"14:8":true,"9:13":true,"11:0":[146,151],"12:6":true,"8:13":true,"1:10":true,"6:1":true,"11:6":true,"11:4":154,"9:1":153,"8:12":true,"12:3":[147,154],"15:10":true,"14:10":true,"10:1":153,"12:4":[146,154],"11:3":[146,154],"8:15":true,"12:2":[149,153],"2:10":true,"11:2":[147,153],"8:14":true,"13:9":true,"7:1":152,"9:3":true,"6:0":[148,151],"10:4":true,"5:9":true,"10:3":154,"7:2":true,"6:6":true,"4:9":true,"11:1":[148,152],"9:4":true,"5:7":true,"3:10":true,"7:4":true,"9:2":153,"8:11":true,"4:7":true,"10:2":153,"0:10":true,"7:3":true,"9:6":true,"6:4":true,"10:0":152,"10:6":true,"9:0":152,"6:3":true,"7:0":152,"5:8":true,"6:2":true,"7:6":true,"4:8":true,"3:8":true,"0:8":true,"6:11":true,"11:13":true,"8:0":152,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"0:7":true,"12:15":true,"11:12":true,"8:4":true,"3:9":true,"12:12":true,"11:15":true,"8:3":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "3:6": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": true,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": true,
+ "13:6": 155,
+ "12:8": true,
+ "14:11": true,
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "14:5": [
+ 151,
+ 152
+ ],
+ "5:1": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": [
+ 152,
+ 153
+ ],
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": [
+ 149,
+ 153
+ ],
+ "12:7": true,
+ "2:11": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "2:2": true,
+ "1:0": true,
+ "5:12": true,
+ "2:4": true,
+ "13:11": true,
+ "4:15": true,
+ "0:1": true,
+ "4:12": true,
+ "3:1": true,
+ "13:5": [
+ 147,
+ 154
+ ],
+ "5:15": true,
+ "2:3": true,
+ "14:6": [
+ 148,
+ 154
+ ],
+ "1:3": true,
+ "1:4": true,
+ "2:0": true,
+ "5:13": true,
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": 155,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": [
+ 150,
+ 154
+ ],
+ "9:15": true,
+ "14:7": [
+ 148,
+ 155
+ ],
+ "9:12": true,
+ "8:1": 152,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "7:13": true,
+ "2:8": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": [
+ 150,
+ 155
+ ],
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "11:0": [
+ 146,
+ 151
+ ],
+ "12:6": true,
+ "8:13": true,
+ "1:10": true,
+ "6:1": true,
+ "11:6": true,
+ "11:4": 154,
+ "9:1": 153,
+ "8:12": true,
+ "12:3": [
+ 147,
+ 154
+ ],
+ "15:10": true,
+ "14:10": true,
+ "10:1": 153,
+ "12:4": [
+ 146,
+ 154
+ ],
+ "11:3": [
+ 146,
+ 154
+ ],
+ "8:15": true,
+ "12:2": [
+ 149,
+ 153
+ ],
+ "2:10": true,
+ "11:2": [
+ 147,
+ 153
+ ],
+ "8:14": true,
+ "13:9": true,
+ "7:1": 152,
+ "9:3": true,
+ "6:0": [
+ 148,
+ 151
+ ],
+ "10:4": true,
+ "5:9": true,
+ "10:3": 154,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": [
+ 148,
+ 152
+ ],
+ "9:4": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": 153,
+ "8:11": true,
+ "4:7": true,
+ "10:2": 153,
+ "0:10": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": 152,
+ "10:6": true,
+ "9:0": 152,
+ "6:3": true,
+ "7:0": 152,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": 152,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_9.json
index 27bc3ed4..e59d8282 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/-9_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/-9_9.json
@@ -1 +1,74 @@
-{"12:1":true,"9:3":true,"11:5":true,"10:4":true,"12:5":true,"10:3":true,"7:2":true,"11:1":true,"7:4":149,"9:2":true,"13:0":true,"0:0":true,"8:1":true,"10:2":true,"7:3":true,"14:1":true,"13:2":true,"4:1":true,"15:5":true,"10:0":true,"14:5":true,"5:1":true,"3:2":true,"15:1":true,"9:0":true,"6:3":true,"7:0":true,"13:3":true,"13:4":true,"6:2":true,"2:1":true,"15:4":true,"11:0":true,"14:3":true,"12:6":153,"5:3":true,"15:3":true,"12:0":true,"6:1":true,"1:0":true,"14:4":true,"8:0":true,"14:2":true,"13:1":true,"4:2":true,"15:2":true,"3:1":true,"13:5":true,"5:2":true,"15:0":true,"12:3":true,"11:4":true,"10:5":[151,152],"9:1":true,"10:1":true,"12:4":true,"11:3":true,"8:2":true,"14:0":true,"4:0":true,"2:0":true,"12:2":true,"8:4":[150,151],"11:2":true,"8:3":true,"7:1":true} \ No newline at end of file
+{
+ "12:1": true,
+ "9:3": true,
+ "11:5": true,
+ "10:4": true,
+ "12:5": true,
+ "10:3": true,
+ "7:2": true,
+ "11:1": true,
+ "7:4": 149,
+ "9:2": true,
+ "13:0": true,
+ "0:0": true,
+ "8:1": true,
+ "10:2": true,
+ "7:3": true,
+ "14:1": true,
+ "13:2": true,
+ "4:1": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "5:1": true,
+ "3:2": true,
+ "15:1": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "13:4": true,
+ "6:2": true,
+ "2:1": true,
+ "15:4": true,
+ "11:0": true,
+ "14:3": true,
+ "12:6": 153,
+ "5:3": true,
+ "15:3": true,
+ "12:0": true,
+ "6:1": true,
+ "1:0": true,
+ "14:4": true,
+ "8:0": true,
+ "14:2": true,
+ "13:1": true,
+ "4:2": true,
+ "15:2": true,
+ "3:1": true,
+ "13:5": true,
+ "5:2": true,
+ "15:0": true,
+ "12:3": true,
+ "11:4": true,
+ "10:5": [
+ 151,
+ 152
+ ],
+ "9:1": true,
+ "10:1": true,
+ "12:4": true,
+ "11:3": true,
+ "8:2": true,
+ "14:0": true,
+ "4:0": true,
+ "2:0": true,
+ "12:2": true,
+ "8:4": [
+ 150,
+ 151
+ ],
+ "11:2": true,
+ "8:3": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/0_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/0_0.json
index a30cb4a9..58bf1e76 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/0_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/0_0.json
@@ -1 +1,72 @@
-{"6:0":true,"1:1":true,"2:7":true,"1:5":true,"7:2":true,"3:0":true,"0:6":true,"0:0":true,"13:0":true,"8:1":true,"3:6":true,"7:3":true,"5:5":true,"4:1":true,"0:2":true,"6:4":true,"10:0":true,"5:1":true,"4:5":true,"3:2":true,"9:0":true,"6:3":true,"7:0":true,"3:4":true,"2:5":true,"0:3":true,"3:3":true,"1:7":true,"0:4":true,"6:2":true,"2:1":true,"11:0":true,"4:3":true,"1:6":true,"5:4":true,"5:3":true,"2:2":true,"12:0":true,"6:1":true,"1:0":true,"4:4":true,"3:5":true,"2:4":true,"8:0":true,"14:15":true,"4:2":true,"0:1":true,"15:15":[146,233],"3:1":true,"5:2":true,"2:3":true,"0:5":true,"15:0":true,"9:1":true,"4:6":true,"3:7":true,"1:3":true,"5:0":true,"8:2":true,"1:4":true,"0:7":true,"14:0":true,"4:0":true,"2:0":true,"1:2":true,"7:1":true,"2:6":true} \ No newline at end of file
+{
+ "6:0": true,
+ "1:1": true,
+ "2:7": true,
+ "1:5": true,
+ "7:2": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "13:0": true,
+ "8:1": true,
+ "3:6": true,
+ "7:3": true,
+ "5:5": true,
+ "4:1": true,
+ "0:2": true,
+ "6:4": true,
+ "10:0": true,
+ "5:1": true,
+ "4:5": true,
+ "3:2": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "3:4": true,
+ "2:5": true,
+ "0:3": true,
+ "3:3": true,
+ "1:7": true,
+ "0:4": true,
+ "6:2": true,
+ "2:1": true,
+ "11:0": true,
+ "4:3": true,
+ "1:6": true,
+ "5:4": true,
+ "5:3": true,
+ "2:2": true,
+ "12:0": true,
+ "6:1": true,
+ "1:0": true,
+ "4:4": true,
+ "3:5": true,
+ "2:4": true,
+ "8:0": true,
+ "14:15": true,
+ "4:2": true,
+ "0:1": true,
+ "15:15": [
+ 146,
+ 233
+ ],
+ "3:1": true,
+ "5:2": true,
+ "2:3": true,
+ "0:5": true,
+ "15:0": true,
+ "9:1": true,
+ "4:6": true,
+ "3:7": true,
+ "1:3": true,
+ "5:0": true,
+ "8:2": true,
+ "1:4": true,
+ "0:7": true,
+ "14:0": true,
+ "4:0": true,
+ "2:0": true,
+ "1:2": true,
+ "7:1": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/0_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/0_10.json
index 27c8872f..5c459232 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/0_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/0_10.json
@@ -1 +1,59 @@
-{"9:3":127,"6:0":true,"1:11":true,"11:5":true,"3:13":true,"12:5":[205,207],"0:13":true,"6:6":true,"11:1":127,"5:7":true,"15:7":true,"3:0":true,"10:2":true,"4:1":127,"3:12":true,"0:2":127,"3:2":true,"0:12":true,"0:3":127,"0:14":true,"0:4":127,"4:8":true,"2:1":127,"12:6":202,"2:2":127,"12:0":127,"11:6":202,"4:12":[113,114],"3:1":127,"13:5":127,"2:3":127,"1:13":true,"0:5":127,"14:6":true,"11:4":true,"2:13":true,"1:3":127,"5:0":true,"12:4":[127,208],"11:3":127,"1:4":127,"4:0":true,"2:0":true,"8:4":true,"2:10":true,"1:2":127,"7:5":true,"3:9":true} \ No newline at end of file
+{
+ "9:3": 127,
+ "6:0": true,
+ "1:11": true,
+ "11:5": true,
+ "3:13": true,
+ "12:5": [
+ 205,
+ 207
+ ],
+ "0:13": true,
+ "6:6": true,
+ "11:1": 127,
+ "5:7": true,
+ "15:7": true,
+ "3:0": true,
+ "10:2": true,
+ "4:1": 127,
+ "3:12": true,
+ "0:2": 127,
+ "3:2": true,
+ "0:12": true,
+ "0:3": 127,
+ "0:14": true,
+ "0:4": 127,
+ "4:8": true,
+ "2:1": 127,
+ "12:6": 202,
+ "2:2": 127,
+ "12:0": 127,
+ "11:6": 202,
+ "4:12": [
+ 113,
+ 114
+ ],
+ "3:1": 127,
+ "13:5": 127,
+ "2:3": 127,
+ "1:13": true,
+ "0:5": 127,
+ "14:6": true,
+ "11:4": true,
+ "2:13": true,
+ "1:3": 127,
+ "5:0": true,
+ "12:4": [
+ 127,
+ 208
+ ],
+ "11:3": 127,
+ "1:4": 127,
+ "4:0": true,
+ "2:0": true,
+ "8:4": true,
+ "2:10": true,
+ "1:2": 127,
+ "7:5": true,
+ "3:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/0_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/0_3.json
index c490d54b..e5302331 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/0_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/0_3.json
@@ -1 +1,21 @@
-{"9:14":true,"2:15":true,"0:13":true,"10:12":true,"9:15":true,"9:12":true,"10:15":true,"12:13":true,"12:14":true,"1:14":true,"0:15":true,"12:15":true,"11:12":true,"1:15":true,"0:14":true,"11:15":true,"12:12":true,"9:8":true,"9:13":true} \ No newline at end of file
+{
+ "9:14": true,
+ "2:15": true,
+ "0:13": true,
+ "10:12": true,
+ "9:15": true,
+ "9:12": true,
+ "10:15": true,
+ "12:13": true,
+ "12:14": true,
+ "1:14": true,
+ "0:15": true,
+ "12:15": true,
+ "11:12": true,
+ "1:15": true,
+ "0:14": true,
+ "11:15": true,
+ "12:12": true,
+ "9:8": true,
+ "9:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/0_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/0_7.json
index 519dafcc..8ca05ce1 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/0_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/0_7.json
@@ -1 +1,31 @@
-{"7:12":true,"6:10":true,"0:13":127,"7:15":true,"6:13":true,"7:14":true,"0:15":true,"7:13":true,"10:0":true,"9:0":true,"6:14":true,"0:14":true,"7:10":true,"6:12":true,"6:15":true,"11:0":true,"2:15":127,"12:0":true,"6:11":true,"7:9":true,"0:1":true,"7:8":[117,120],"6:9":true,"1:14":127,"1:15":127,"7:11":true} \ No newline at end of file
+{
+ "7:12": true,
+ "6:10": true,
+ "0:13": 127,
+ "7:15": true,
+ "6:13": true,
+ "7:14": true,
+ "0:15": true,
+ "7:13": true,
+ "10:0": true,
+ "9:0": true,
+ "6:14": true,
+ "0:14": true,
+ "7:10": true,
+ "6:12": true,
+ "6:15": true,
+ "11:0": true,
+ "2:15": 127,
+ "12:0": true,
+ "6:11": true,
+ "7:9": true,
+ "0:1": true,
+ "7:8": [
+ 117,
+ 120
+ ],
+ "6:9": true,
+ "1:14": 127,
+ "1:15": 127,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/0_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/0_8.json
index 83229162..a4dfb68b 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/0_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/0_8.json
@@ -1 +1,45 @@
-{"15:9":true,"1:11":true,"1:1":true,"3:13":true,"13:13":true,"0:13":true,"6:13":true,"3:0":127,"4:11":true,"0:15":true,"0:2":true,"7:13":true,"3:15":true,"0:12":true,"15:11":true,"7:0":true,"10:13":true,"0:14":true,"0:3":true,"9:13":true,"2:11":true,"2:1":127,"8:13":true,"2:15":true,"0:8":true,"1:0":127,"11:13":true,"4:15":true,"0:11":true,"0:1":true,"15:15":true,"3:11":true,"12:13":true,"1:13":true,"2:13":true,"15:10":true,"15:13":true,"2:0":127,"5:13":true,"1:15":true,"1:2":true,"14:13":true,"4:13":true} \ No newline at end of file
+{
+ "15:9": true,
+ "1:11": true,
+ "1:1": true,
+ "3:13": true,
+ "13:13": true,
+ "0:13": true,
+ "6:13": true,
+ "3:0": 127,
+ "4:11": true,
+ "0:15": true,
+ "0:2": true,
+ "7:13": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "7:0": true,
+ "10:13": true,
+ "0:14": true,
+ "0:3": true,
+ "9:13": true,
+ "2:11": true,
+ "2:1": 127,
+ "8:13": true,
+ "2:15": true,
+ "0:8": true,
+ "1:0": 127,
+ "11:13": true,
+ "4:15": true,
+ "0:11": true,
+ "0:1": true,
+ "15:15": true,
+ "3:11": true,
+ "12:13": true,
+ "1:13": true,
+ "2:13": true,
+ "15:10": true,
+ "15:13": true,
+ "2:0": 127,
+ "5:13": true,
+ "1:15": true,
+ "1:2": true,
+ "14:13": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/0_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/0_9.json
index 7dfe7b5f..bc399186 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/0_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/0_9.json
@@ -1 +1,52 @@
-{"15:9":127,"6:10":127,"10:14":127,"7:15":[115,116],"6:13":117,"9:15":116,"7:14":117,"15:1":true,"6:14":true,"6:12":117,"0:4":true,"6:15":116,"9:13":true,"2:15":true,"0:11":127,"2:14":true,"1:13":true,"8:12":127,"2:13":true,"1:14":true,"14:10":true,"8:15":[115,117],"1:12":127,"5:9":127,"1:5":true,"0:13":true,"14:11":true,"3:15":true,"0:12":127,"0:14":true,"3:14":true,"4:8":127,"11:13":127,"5:12":117,"13:11":true,"4:15":true,"5:15":true,"15:0":true,"3:7":true,"5:13":117,"12:12":true,"11:15":true,"7:11":127,"2:6":true} \ No newline at end of file
+{
+ "15:9": 127,
+ "6:10": 127,
+ "10:14": 127,
+ "7:15": [
+ 115,
+ 116
+ ],
+ "6:13": 117,
+ "9:15": 116,
+ "7:14": 117,
+ "15:1": true,
+ "6:14": true,
+ "6:12": 117,
+ "0:4": true,
+ "6:15": 116,
+ "9:13": true,
+ "2:15": true,
+ "0:11": 127,
+ "2:14": true,
+ "1:13": true,
+ "8:12": 127,
+ "2:13": true,
+ "1:14": true,
+ "14:10": true,
+ "8:15": [
+ 115,
+ 117
+ ],
+ "1:12": 127,
+ "5:9": 127,
+ "1:5": true,
+ "0:13": true,
+ "14:11": true,
+ "3:15": true,
+ "0:12": 127,
+ "0:14": true,
+ "3:14": true,
+ "4:8": 127,
+ "11:13": 127,
+ "5:12": 117,
+ "13:11": true,
+ "4:15": true,
+ "5:15": true,
+ "15:0": true,
+ "3:7": true,
+ "5:13": 117,
+ "12:12": true,
+ "11:15": true,
+ "7:11": 127,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/10_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/10_1.json
index e31b7d9f..b8dde378 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/10_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/10_1.json
@@ -1 +1,202 @@
-{"15:9":true,"9:14":true,"11:5":[167,169],"2:7":true,"8:8":true,"7:12":true,"6:10":true,"12:5":[167,171],"10:14":true,"7:15":true,"14:9":true,"10:12":true,"6:13":true,"2:9":true,"15:7":167,"9:15":true,"0:6":[151,154],"14:7":168,"9:12":true,"10:15":true,"7:14":true,"1:8":true,"4:11":true,"7:13":true,"2:8":true,"9:10":true,"5:11":true,"6:14":true,"1:9":true,"15:8":true,"10:13":true,"8:9":true,"7:10":true,"6:12":true,"1:7":true,"0:4":[156,157],"6:15":true,"14:8":true,"9:13":true,"2:1":true,"12:6":true,"8:13":true,"2:12":true,"10:9":true,"7:7":true,"2:15":true,"1:10":true,"13:8":true,"9:9":true,"11:6":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"0:11":true,"9:7":true,"3:11":true,"2:14":true,"1:13":true,"0:5":[154,190],"11:4":170,"8:12":true,"7:8":true,"6:9":true,"2:13":true,"1:14":true,"15:10":true,"13:7":true,"8:15":true,"2:10":true,"1:15":true,"10:8":true,"6:7":true,"8:14":true,"1:12":true,"13:9":true,"9:8":true,"1:11":true,"3:13":true,"5:9":true,"1:5":[151,189],"0:13":true,"4:9":true,"5:7":true,"3:10":true,"11:8":true,"13:6":170,"8:11":true,"4:7":true,"0:10":true,"12:8":true,"9:6":true,"3:12":true,"0:15":true,"11:9":true,"15:5":168,"14:5":169,"10:6":true,"3:15":true,"0:12":true,"11:7":true,"2:5":[151,226],"0:14":true,"5:8":true,"13:4":[166,167],"12:7":true,"3:14":true,"4:8":true,"2:11":true,"15:4":[164,165],"4:14":true,"1:6":150,"3:8":true,"5:14":true,"2:2":[187,221],"0:8":154,"6:11":true,"14:4":[165,169],"5:12":true,"2:4":[152,222],"4:15":true,"8:6":true,"4:12":true,"13:5":[167,170],"5:15":true,"2:3":[187,222],"14:6":169,"10:5":[168,170],"9:11":true,"5:10":true,"3:7":true,"1:3":156,"9:5":true,"4:10":true,"11:14":true,"1:4":[154,155],"0:7":[151,154],"15:6":168,"12:15":true,"5:13":true,"3:9":true,"11:15":true,"0:9":true,"7:11":true,"4:13":true,"2:6":[192,223]} \ No newline at end of file
+{
+ "15:9": true,
+ "9:14": true,
+ "11:5": [
+ 167,
+ 169
+ ],
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "12:5": [
+ 167,
+ 171
+ ],
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": 167,
+ "9:15": true,
+ "0:6": [
+ 151,
+ 154
+ ],
+ "14:7": 168,
+ "9:12": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "4:11": true,
+ "7:13": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "6:14": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "1:7": true,
+ "0:4": [
+ 156,
+ 157
+ ],
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "2:1": true,
+ "12:6": true,
+ "8:13": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": true,
+ "1:10": true,
+ "13:8": true,
+ "9:9": true,
+ "11:6": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "0:11": true,
+ "9:7": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": [
+ 154,
+ 190
+ ],
+ "11:4": 170,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "2:13": true,
+ "1:14": true,
+ "15:10": true,
+ "13:7": true,
+ "8:15": true,
+ "2:10": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "8:14": true,
+ "1:12": true,
+ "13:9": true,
+ "9:8": true,
+ "1:11": true,
+ "3:13": true,
+ "5:9": true,
+ "1:5": [
+ 151,
+ 189
+ ],
+ "0:13": true,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "13:6": 170,
+ "8:11": true,
+ "4:7": true,
+ "0:10": true,
+ "12:8": true,
+ "9:6": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "15:5": 168,
+ "14:5": 169,
+ "10:6": true,
+ "3:15": true,
+ "0:12": true,
+ "11:7": true,
+ "2:5": [
+ 151,
+ 226
+ ],
+ "0:14": true,
+ "5:8": true,
+ "13:4": [
+ 166,
+ 167
+ ],
+ "12:7": true,
+ "3:14": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": [
+ 164,
+ 165
+ ],
+ "4:14": true,
+ "1:6": 150,
+ "3:8": true,
+ "5:14": true,
+ "2:2": [
+ 187,
+ 221
+ ],
+ "0:8": 154,
+ "6:11": true,
+ "14:4": [
+ 165,
+ 169
+ ],
+ "5:12": true,
+ "2:4": [
+ 152,
+ 222
+ ],
+ "4:15": true,
+ "8:6": true,
+ "4:12": true,
+ "13:5": [
+ 167,
+ 170
+ ],
+ "5:15": true,
+ "2:3": [
+ 187,
+ 222
+ ],
+ "14:6": 169,
+ "10:5": [
+ 168,
+ 170
+ ],
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "1:3": 156,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "1:4": [
+ 154,
+ 155
+ ],
+ "0:7": [
+ 151,
+ 154
+ ],
+ "15:6": 168,
+ "12:15": true,
+ "5:13": true,
+ "3:9": true,
+ "11:15": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": [
+ 192,
+ 223
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/10_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/10_3.json
index 9c96f830..98cae537 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/10_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/10_3.json
@@ -1 +1,215 @@
-{"8:8":true,"6:10":true,"13:13":true,"0:6":true,"3:6":true,"14:1":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"15:1":true,"13:14":[161,163],"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"0:4":true,"2:1":true,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"15:14":true,"9:9":true,"4:4":true,"10:7":true,"3:5":true,"15:12":true,"14:15":160,"13:1":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:6":true,"15:13":true,"1:15":true,"10:8":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"0:13":true,"11:8":true,"13:6":true,"13:0":true,"12:8":true,"14:11":true,"13:2":true,"3:12":true,"0:15":true,"11:9":true,"14:5":true,"3:15":true,"0:12":true,"15:11":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"13:4":true,"12:7":true,"2:11":true,"14:3":true,"1:6":true,"11:10":true,"12:10":true,"2:2":true,"15:3":true,"14:4":true,"2:4":true,"14:2":true,"13:11":true,"4:15":true,"15:2":true,"4:12":true,"13:5":true,"5:15":true,"2:3":true,"15:0":true,"14:6":true,"1:4":true,"15:6":true,"14:0":true,"5:13":153,"4:13":true,"2:6":true,"15:9":true,"12:11":true,"2:7":true,"7:12":[149,150],"12:5":true,"14:9":true,"11:11":true,"10:12":true,"2:9":true,"15:7":true,"14:7":true,"9:12":[150,151],"13:10":true,"1:8":true,"2:8":true,"1:9":true,"15:8":true,"6:12":[148,149],"1:7":true,"14:8":true,"11:0":true,"1:10":true,"13:8":true,"12:0":true,"11:4":true,"9:1":true,"8:12":[149,151],"12:3":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"12:2":true,"2:10":true,"11:2":true,"13:9":true,"12:1":true,"5:9":true,"10:3":true,"6:6":true,"4:9":true,"11:1":true,"8:5":true,"3:10":true,"7:4":true,"9:2":true,"8:11":148,"10:2":true,"0:10":true,"9:6":true,"6:4":true,"10:0":true,"10:6":true,"9:0":true,"6:3":true,"5:8":true,"7:6":true,"4:8":true,"6:5":true,"3:8":true,"0:8":true,"6:11":147,"11:13":[161,163],"8:0":true,"8:6":true,"12:13":true,"12:14":[161,162],"9:11":true,"5:10":true,"10:11":true,"4:10":true,"0:7":true,"11:12":true,"7:5":true,"3:9":true,"12:12":true,"0:9":true,"7:11":[147,148]} \ No newline at end of file
+{
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "0:6": true,
+ "3:6": true,
+ "14:1": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "15:1": true,
+ "13:14": [
+ 161,
+ 163
+ ],
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": true,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": 160,
+ "13:1": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:6": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "14:5": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": true,
+ "2:11": true,
+ "14:3": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "2:2": true,
+ "15:3": true,
+ "14:4": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "15:2": true,
+ "4:12": true,
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": true,
+ "5:13": 153,
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "2:7": true,
+ "7:12": [
+ 149,
+ 150
+ ],
+ "12:5": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "15:7": true,
+ "14:7": true,
+ "9:12": [
+ 150,
+ 151
+ ],
+ "13:10": true,
+ "1:8": true,
+ "2:8": true,
+ "1:9": true,
+ "15:8": true,
+ "6:12": [
+ 148,
+ 149
+ ],
+ "1:7": true,
+ "14:8": true,
+ "11:0": true,
+ "1:10": true,
+ "13:8": true,
+ "12:0": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": [
+ 149,
+ 151
+ ],
+ "12:3": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "12:2": true,
+ "2:10": true,
+ "11:2": true,
+ "13:9": true,
+ "12:1": true,
+ "5:9": true,
+ "10:3": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "8:5": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": 148,
+ "10:2": true,
+ "0:10": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "6:3": true,
+ "5:8": true,
+ "7:6": true,
+ "4:8": true,
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": 147,
+ "11:13": [
+ 161,
+ 163
+ ],
+ "8:0": true,
+ "8:6": true,
+ "12:13": true,
+ "12:14": [
+ 161,
+ 162
+ ],
+ "9:11": true,
+ "5:10": true,
+ "10:11": true,
+ "4:10": true,
+ "0:7": true,
+ "11:12": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "0:9": true,
+ "7:11": [
+ 147,
+ 148
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/10_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/10_4.json
index d59a6e28..967958bf 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/10_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/10_4.json
@@ -1 +1,47 @@
-{"12:11":true,"9:14":true,"10:14":true,"0:13":true,"10:12":156,"6:13":true,"3:0":true,"9:15":true,"0:0":true,"13:10":true,"7:14":true,"0:15":true,"7:13":true,"3:15":true,"6:14":true,"10:13":true,"0:14":true,"3:14":true,"6:15":true,"9:13":true,"4:14":true,"8:13":true,"5:14":true,"2:15":true,"1:0":true,"11:13":true,"13:11":true,"4:15":true,"0:1":true,"5:15":true,"2:14":true,"1:13":true,"15:0":true,"2:13":true,"1:14":true,"5:0":true,"14:0":160,"4:0":true,"2:0":true,"11:12":true,"5:13":true,"1:15":true,"12:12":true,"8:14":true,"4:13":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "10:14": true,
+ "0:13": true,
+ "10:12": 156,
+ "6:13": true,
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "13:10": true,
+ "7:14": true,
+ "0:15": true,
+ "7:13": true,
+ "3:15": true,
+ "6:14": true,
+ "10:13": true,
+ "0:14": true,
+ "3:14": true,
+ "6:15": true,
+ "9:13": true,
+ "4:14": true,
+ "8:13": true,
+ "5:14": true,
+ "2:15": true,
+ "1:0": true,
+ "11:13": true,
+ "13:11": true,
+ "4:15": true,
+ "0:1": true,
+ "5:15": true,
+ "2:14": true,
+ "1:13": true,
+ "15:0": true,
+ "2:13": true,
+ "1:14": true,
+ "5:0": true,
+ "14:0": 160,
+ "4:0": true,
+ "2:0": true,
+ "11:12": true,
+ "5:13": true,
+ "1:15": true,
+ "12:12": true,
+ "8:14": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/10_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/10_5.json
index 44c446c1..075087ce 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/10_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/10_5.json
@@ -1 +1,96 @@
-{"1:1":true,"1:11":[170,189],"10:4":156,"2:7":true,"1:5":true,"0:13":[161,170],"4:9":[158,160],"3:10":[158,161],"2:9":true,"3:0":true,"0:6":true,"0:0":true,"0:10":true,"13:2":154,"3:12":true,"0:2":true,"0:15":true,"2:8":true,"0:12":[170,171],"15:1":true,"2:5":true,"0:3":true,"0:14":true,"5:8":158,"2:1":true,"2:11":[158,226],"2:12":[159,222],"7:7":[156,158],"2:2":true,"2:15":true,"0:8":true,"1:0":true,"6:8":[156,158],"2:4":true,"14:2":153,"0:1":true,"0:11":[171,190],"8:6":[156,158],"3:1":true,"2:14":true,"2:3":true,"1:13":true,"0:5":true,"2:13":true,"1:14":true,"5:0":true,"11:3":155,"1:4":true,"4:0":true,"2:0":true,"2:10":[192,223],"1:2":true,"1:15":true,"1:12":[160,169],"2:6":true} \ No newline at end of file
+{
+ "1:1": true,
+ "1:11": [
+ 170,
+ 189
+ ],
+ "10:4": 156,
+ "2:7": true,
+ "1:5": true,
+ "0:13": [
+ 161,
+ 170
+ ],
+ "4:9": [
+ 158,
+ 160
+ ],
+ "3:10": [
+ 158,
+ 161
+ ],
+ "2:9": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "0:10": true,
+ "13:2": 154,
+ "3:12": true,
+ "0:2": true,
+ "0:15": true,
+ "2:8": true,
+ "0:12": [
+ 170,
+ 171
+ ],
+ "15:1": true,
+ "2:5": true,
+ "0:3": true,
+ "0:14": true,
+ "5:8": 158,
+ "2:1": true,
+ "2:11": [
+ 158,
+ 226
+ ],
+ "2:12": [
+ 159,
+ 222
+ ],
+ "7:7": [
+ 156,
+ 158
+ ],
+ "2:2": true,
+ "2:15": true,
+ "0:8": true,
+ "1:0": true,
+ "6:8": [
+ 156,
+ 158
+ ],
+ "2:4": true,
+ "14:2": 153,
+ "0:1": true,
+ "0:11": [
+ 171,
+ 190
+ ],
+ "8:6": [
+ 156,
+ 158
+ ],
+ "3:1": true,
+ "2:14": true,
+ "2:3": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "1:14": true,
+ "5:0": true,
+ "11:3": 155,
+ "1:4": true,
+ "4:0": true,
+ "2:0": true,
+ "2:10": [
+ 192,
+ 223
+ ],
+ "1:2": true,
+ "1:15": true,
+ "1:12": [
+ 160,
+ 169
+ ],
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/11_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/11_1.json
index 0540c5c2..225a6e2d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/11_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/11_1.json
@@ -1 +1,72 @@
-{"4:14":true,"1:11":true,"1:6":true,"3:13":true,"2:7":[162,166],"6:10":true,"5:9":158,"3:8":161,"5:14":true,"1:10":true,"1:5":true,"0:8":[166,167],"4:9":true,"5:12":true,"3:10":163,"6:13":true,"2:9":[164,166],"4:15":true,"0:6":167,"4:7":true,"4:12":[162,164],"3:6":true,"3:11":167,"1:8":true,"5:10":[157,161],"4:11":[162,163],"3:7":true,"3:12":165,"2:8":165,"5:11":true,"4:10":[162,164],"3:15":true,"1:4":true,"0:7":167,"1:9":166,"5:13":true,"2:10":true,"6:12":true,"3:9":[163,164],"1:12":true,"1:7":166,"0:4":true,"0:9":true,"4:8":true,"4:13":true,"2:6":162} \ No newline at end of file
+{
+ "4:14": true,
+ "1:11": true,
+ "1:6": true,
+ "3:13": true,
+ "2:7": [
+ 162,
+ 166
+ ],
+ "6:10": true,
+ "5:9": 158,
+ "3:8": 161,
+ "5:14": true,
+ "1:10": true,
+ "1:5": true,
+ "0:8": [
+ 166,
+ 167
+ ],
+ "4:9": true,
+ "5:12": true,
+ "3:10": 163,
+ "6:13": true,
+ "2:9": [
+ 164,
+ 166
+ ],
+ "4:15": true,
+ "0:6": 167,
+ "4:7": true,
+ "4:12": [
+ 162,
+ 164
+ ],
+ "3:6": true,
+ "3:11": 167,
+ "1:8": true,
+ "5:10": [
+ 157,
+ 161
+ ],
+ "4:11": [
+ 162,
+ 163
+ ],
+ "3:7": true,
+ "3:12": 165,
+ "2:8": 165,
+ "5:11": true,
+ "4:10": [
+ 162,
+ 164
+ ],
+ "3:15": true,
+ "1:4": true,
+ "0:7": 167,
+ "1:9": 166,
+ "5:13": true,
+ "2:10": true,
+ "6:12": true,
+ "3:9": [
+ 163,
+ 164
+ ],
+ "1:12": true,
+ "1:7": 166,
+ "0:4": true,
+ "0:9": true,
+ "4:8": true,
+ "4:13": true,
+ "2:6": 162
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/11_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/11_3.json
index ccf6e685..b60a43f7 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/11_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/11_3.json
@@ -1 +1,60 @@
-{"1:11":true,"0:13":true,"6:6":true,"4:9":true,"5:7":true,"3:10":true,"2:9":true,"0:0":true,"4:7":true,"3:6":true,"0:10":true,"1:8":true,"5:5":true,"4:1":true,"0:15":true,"6:4":true,"2:8":true,"5:1":true,"4:5":true,"0:12":true,"6:3":true,"1:9":true,"0:14":true,"7:6":true,"4:8":true,"2:11":true,"4:3":true,"5:4":true,"7:7":true,"6:5":true,"3:8":true,"5:3":true,"1:10":true,"0:8":true,"6:1":[156,158],"4:4":true,"6:8":true,"4:2":true,"0:11":true,"3:1":true,"5:2":true,"4:6":true,"3:7":true,"5:0":[155,164],"5:6":true,"0:7":true,"4:0":166,"2:10":true,"6:7":true,"3:9":true,"1:12":true,"0:9":true} \ No newline at end of file
+{
+ "1:11": true,
+ "0:13": true,
+ "6:6": true,
+ "4:9": true,
+ "5:7": true,
+ "3:10": true,
+ "2:9": true,
+ "0:0": true,
+ "4:7": true,
+ "3:6": true,
+ "0:10": true,
+ "1:8": true,
+ "5:5": true,
+ "4:1": true,
+ "0:15": true,
+ "6:4": true,
+ "2:8": true,
+ "5:1": true,
+ "4:5": true,
+ "0:12": true,
+ "6:3": true,
+ "1:9": true,
+ "0:14": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "4:3": true,
+ "5:4": true,
+ "7:7": true,
+ "6:5": true,
+ "3:8": true,
+ "5:3": true,
+ "1:10": true,
+ "0:8": true,
+ "6:1": [
+ 156,
+ 158
+ ],
+ "4:4": true,
+ "6:8": true,
+ "4:2": true,
+ "0:11": true,
+ "3:1": true,
+ "5:2": true,
+ "4:6": true,
+ "3:7": true,
+ "5:0": [
+ 155,
+ 164
+ ],
+ "5:6": true,
+ "0:7": true,
+ "4:0": 166,
+ "2:10": true,
+ "6:7": true,
+ "3:9": true,
+ "1:12": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/11_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/11_4.json
index b1c880dc..ee4dac0f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/11_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/11_4.json
@@ -1 +1,17 @@
-{"2:15":true,"1:5":true,"4:9":true,"5:7":true,"0:1":true,"0:0":true,"0:5":true,"1:3":true,"0:2":true,"5:6":true,"1:4":true,"1:2":true,"0:3":true,"5:8":true,"4:8":true} \ No newline at end of file
+{
+ "2:15": true,
+ "1:5": true,
+ "4:9": true,
+ "5:7": true,
+ "0:1": true,
+ "0:0": true,
+ "0:5": true,
+ "1:3": true,
+ "0:2": true,
+ "5:6": true,
+ "1:4": true,
+ "1:2": true,
+ "0:3": true,
+ "5:8": true,
+ "4:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_-1.json
index 07c13c50..5f3ff028 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_-1.json
@@ -1 +1,119 @@
-{"7:12":196,"13:13":198,"7:15":[189,196],"10:12":199,"6:13":true,"9:15":[188,198],"9:12":198,"8:1":true,"10:15":[187,199],"14:1":[200,201],"13:15":198,"7:13":[189,196],"13:12":[198,202],"13:14":true,"10:13":[187,199],"8:9":173,"6:12":true,"6:15":true,"9:13":[188,198],"14:14":true,"8:13":[189,197],"2:12":true,"2:15":true,"15:14":196,"8:10":[172,174],"7:9":true,"15:12":[196,201],"14:15":true,"15:15":196,"14:12":[197,201],"1:13":true,"9:1":233,"8:12":197,"2:13":true,"8:15":[189,197],"15:13":196,"1:15":true,"1:12":true,"14:13":197,"9:3":147,"10:4":148,"3:13":true,"0:13":true,"8:5":true,"11:8":167,"13:0":153,"13:2":152,"3:12":true,"0:15":true,"3:15":true,"0:12":true,"13:3":157,"11:7":167,"12:7":166,"11:13":[186,199],"5:12":true,"4:15":true,"15:2":200,"4:12":true,"12:13":[185,199],"5:15":true,"11:14":226,"8:2":true,"14:0":198,"12:15":true,"11:12":true,"8:4":true,"5:13":true,"12:12":true,"11:15":true,"8:3":true,"4:13":true} \ No newline at end of file
+{
+ "7:12": 196,
+ "13:13": 198,
+ "7:15": [
+ 189,
+ 196
+ ],
+ "10:12": 199,
+ "6:13": true,
+ "9:15": [
+ 188,
+ 198
+ ],
+ "9:12": 198,
+ "8:1": true,
+ "10:15": [
+ 187,
+ 199
+ ],
+ "14:1": [
+ 200,
+ 201
+ ],
+ "13:15": 198,
+ "7:13": [
+ 189,
+ 196
+ ],
+ "13:12": [
+ 198,
+ 202
+ ],
+ "13:14": true,
+ "10:13": [
+ 187,
+ 199
+ ],
+ "8:9": 173,
+ "6:12": true,
+ "6:15": true,
+ "9:13": [
+ 188,
+ 198
+ ],
+ "14:14": true,
+ "8:13": [
+ 189,
+ 197
+ ],
+ "2:12": true,
+ "2:15": true,
+ "15:14": 196,
+ "8:10": [
+ 172,
+ 174
+ ],
+ "7:9": true,
+ "15:12": [
+ 196,
+ 201
+ ],
+ "14:15": true,
+ "15:15": 196,
+ "14:12": [
+ 197,
+ 201
+ ],
+ "1:13": true,
+ "9:1": 233,
+ "8:12": 197,
+ "2:13": true,
+ "8:15": [
+ 189,
+ 197
+ ],
+ "15:13": 196,
+ "1:15": true,
+ "1:12": true,
+ "14:13": 197,
+ "9:3": 147,
+ "10:4": 148,
+ "3:13": true,
+ "0:13": true,
+ "8:5": true,
+ "11:8": 167,
+ "13:0": 153,
+ "13:2": 152,
+ "3:12": true,
+ "0:15": true,
+ "3:15": true,
+ "0:12": true,
+ "13:3": 157,
+ "11:7": 167,
+ "12:7": 166,
+ "11:13": [
+ 186,
+ 199
+ ],
+ "5:12": true,
+ "4:15": true,
+ "15:2": 200,
+ "4:12": true,
+ "12:13": [
+ 185,
+ 199
+ ],
+ "5:15": true,
+ "11:14": 226,
+ "8:2": true,
+ "14:0": 198,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "5:13": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_-2.json
index f84a02d8..fbe1c1b7 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_-2.json
@@ -1 +1,36 @@
-{"3:0":true,"0:0":true,"8:1":234,"0:2":true,"3:3":true,"0:4":true,"4:3":true,"5:3":[177,178],"3:5":true,"9:7":192,"0:5":true,"5:0":true,"6:7":233,"9:8":[191,192],"1:5":true,"7:4":174,"4:7":true,"7:0":[195,223],"2:5":true,"4:8":true,"1:0":true,"1:3":true,"8:4":true,"3:9":true,"11:15":224} \ No newline at end of file
+{
+ "3:0": true,
+ "0:0": true,
+ "8:1": 234,
+ "0:2": true,
+ "3:3": true,
+ "0:4": true,
+ "4:3": true,
+ "5:3": [
+ 177,
+ 178
+ ],
+ "3:5": true,
+ "9:7": 192,
+ "0:5": true,
+ "5:0": true,
+ "6:7": 233,
+ "9:8": [
+ 191,
+ 192
+ ],
+ "1:5": true,
+ "7:4": 174,
+ "4:7": true,
+ "7:0": [
+ 195,
+ 223
+ ],
+ "2:5": true,
+ "4:8": true,
+ "1:0": true,
+ "1:3": true,
+ "8:4": true,
+ "3:9": true,
+ "11:15": 224
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_-3.json
index 2585400c..9499a2e1 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_-3.json
@@ -1 +1,151 @@
-{"9:14":[179,221],"1:1":true,"11:5":true,"2:7":true,"8:8":true,"6:10":true,"12:5":true,"10:14":[179,222],"2:9":true,"3:0":true,"0:6":true,"0:0":true,"8:1":true,"3:6":true,"7:14":true,"1:8":true,"14:1":true,"8:7":true,"5:5":true,"2:8":true,"4:5":true,"3:2":true,"15:1":true,"1:9":true,"13:14":true,"3:4":true,"8:9":true,"3:3":true,"1:7":true,"2:1":true,"11:0":true,"14:14":true,"12:6":true,"4:3":true,"7:7":true,"15:14":true,"12:0":true,"6:1":true,"11:6":true,"8:10":true,"6:8":true,"3:5":true,"13:1":true,"0:11":true,"5:2":true,"0:5":true,"12:3":true,"11:4":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:6":true,"12:4":true,"11:3":true,"12:2":true,"2:10":true,"6:7":true,"11:2":true,"8:14":[179,220],"1:12":true,"7:1":true,"12:1":true,"6:0":true,"5:9":true,"1:5":true,"7:2":true,"6:6":true,"4:9":true,"11:1":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"13:6":true,"13:0":true,"8:11":true,"4:7":true,"0:10":true,"7:3":true,"13:2":true,"6:4":true,"15:5":true,"14:5":true,"0:12":true,"6:3":true,"7:0":true,"13:3":true,"2:5":true,"0:14":true,"5:8":true,"13:4":true,"6:2":true,"7:6":true,"4:8":true,"15:4":true,"14:3":true,"1:6":true,"6:5":true,"3:8":true,"2:2":true,"0:8":true,"15:3":true,"1:0":true,"14:4":true,"2:4":true,"8:0":true,"14:2":true,"15:2":true,"8:6":true,"3:1":true,"13:5":true,"2:3":true,"15:0":true,"14:6":true,"12:14":[184,224],"5:10":true,"3:7":true,"1:3":true,"4:10":true,"11:14":[184,223],"8:2":true,"1:4":true,"0:7":true,"15:6":true,"14:0":true,"2:0":true,"8:4":true,"1:2":true,"7:5":true,"3:9":true,"8:3":true,"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "9:14": [
+ 179,
+ 221
+ ],
+ "1:1": true,
+ "11:5": true,
+ "2:7": true,
+ "8:8": true,
+ "6:10": true,
+ "12:5": true,
+ "10:14": [
+ 179,
+ 222
+ ],
+ "2:9": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "8:1": true,
+ "3:6": true,
+ "7:14": true,
+ "1:8": true,
+ "14:1": true,
+ "8:7": true,
+ "5:5": true,
+ "2:8": true,
+ "4:5": true,
+ "3:2": true,
+ "15:1": true,
+ "1:9": true,
+ "13:14": true,
+ "3:4": true,
+ "8:9": true,
+ "3:3": true,
+ "1:7": true,
+ "2:1": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": true,
+ "4:3": true,
+ "7:7": true,
+ "15:14": true,
+ "12:0": true,
+ "6:1": true,
+ "11:6": true,
+ "8:10": true,
+ "6:8": true,
+ "3:5": true,
+ "13:1": true,
+ "0:11": true,
+ "5:2": true,
+ "0:5": true,
+ "12:3": true,
+ "11:4": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:6": true,
+ "12:4": true,
+ "11:3": true,
+ "12:2": true,
+ "2:10": true,
+ "6:7": true,
+ "11:2": true,
+ "8:14": [
+ 179,
+ 220
+ ],
+ "1:12": true,
+ "7:1": true,
+ "12:1": true,
+ "6:0": true,
+ "5:9": true,
+ "1:5": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "13:6": true,
+ "13:0": true,
+ "8:11": true,
+ "4:7": true,
+ "0:10": true,
+ "7:3": true,
+ "13:2": true,
+ "6:4": true,
+ "15:5": true,
+ "14:5": true,
+ "0:12": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "13:4": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "6:5": true,
+ "3:8": true,
+ "2:2": true,
+ "0:8": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "2:4": true,
+ "8:0": true,
+ "14:2": true,
+ "15:2": true,
+ "8:6": true,
+ "3:1": true,
+ "13:5": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "12:14": [
+ 184,
+ 224
+ ],
+ "5:10": true,
+ "3:7": true,
+ "1:3": true,
+ "4:10": true,
+ "11:14": [
+ 184,
+ 223
+ ],
+ "8:2": true,
+ "1:4": true,
+ "0:7": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "8:3": true,
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_0.json
index e9baac3c..82bb1ab6 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_0.json
@@ -1 +1,89 @@
-{"3:0":true,"0:0":true,"13:10":214,"4:11":[146,151],"5:11":150,"11:0":[199,226],"12:0":[199,226],"3:11":145,"2:14":148,"1:13":145,"2:13":[145,149],"9:1":[174,175],"1:14":148,"15:10":213,"5:0":true,"14:10":[213,214],"4:0":true,"1:15":147,"6:0":true,"3:13":[149,150],"4:9":146,"3:10":145,"13:0":[198,226],"10:2":173,"3:12":145,"0:15":147,"10:0":[175,200],"9:0":[175,199],"7:0":[196,197],"1:0":true,"8:0":[197,198],"4:12":[146,150],"15:0":[196,202],"5:10":[147,152],"4:10":[146,147],"8:2":143,"14:0":true,"2:0":true,"4:13":149} \ No newline at end of file
+{
+ "3:0": true,
+ "0:0": true,
+ "13:10": 214,
+ "4:11": [
+ 146,
+ 151
+ ],
+ "5:11": 150,
+ "11:0": [
+ 199,
+ 226
+ ],
+ "12:0": [
+ 199,
+ 226
+ ],
+ "3:11": 145,
+ "2:14": 148,
+ "1:13": 145,
+ "2:13": [
+ 145,
+ 149
+ ],
+ "9:1": [
+ 174,
+ 175
+ ],
+ "1:14": 148,
+ "15:10": 213,
+ "5:0": true,
+ "14:10": [
+ 213,
+ 214
+ ],
+ "4:0": true,
+ "1:15": 147,
+ "6:0": true,
+ "3:13": [
+ 149,
+ 150
+ ],
+ "4:9": 146,
+ "3:10": 145,
+ "13:0": [
+ 198,
+ 226
+ ],
+ "10:2": 173,
+ "3:12": 145,
+ "0:15": 147,
+ "10:0": [
+ 175,
+ 200
+ ],
+ "9:0": [
+ 175,
+ 199
+ ],
+ "7:0": [
+ 196,
+ 197
+ ],
+ "1:0": true,
+ "8:0": [
+ 197,
+ 198
+ ],
+ "4:12": [
+ 146,
+ 150
+ ],
+ "15:0": [
+ 196,
+ 202
+ ],
+ "5:10": [
+ 147,
+ 152
+ ],
+ "4:10": [
+ 146,
+ 147
+ ],
+ "8:2": 143,
+ "14:0": true,
+ "2:0": true,
+ "4:13": 149
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_10.json
index 1c619aa1..15873317 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_10.json
@@ -1 +1,90 @@
-{"11:5":true,"7:12":true,"13:13":true,"12:5":true,"10:12":true,"3:0":true,"8:1":true,"14:1":true,"13:12":true,"3:2":127,"15:1":true,"1:9":true,"15:8":true,"13:14":true,"10:13":true,"14:8":true,"9:13":true,"2:1":true,"12:6":true,"4:3":127,"5:4":true,"5:3":true,"13:8":true,"11:6":true,"10:7":true,"13:1":true,"4:2":[127,202],"14:12":true,"9:7":true,"5:2":true,"9:1":true,"8:12":true,"13:7":true,"12:4":true,"15:13":true,"12:2":true,"2:10":127,"10:8":true,"11:2":true,"7:1":true,"14:13":true,"12:1":true,"10:4":true,"10:3":true,"7:2":true,"11:8":true,"13:6":true,"9:2":true,"10:2":true,"12:8":true,"13:2":true,"9:6":true,"15:5":true,"14:5":true,"10:6":true,"5:1":201,"9:0":true,"6:3":127,"7:0":true,"13:3":true,"11:7":true,"13:4":true,"12:7":true,"6:2":127,"7:6":true,"15:4":true,"0:8":true,"15:3":true,"1:0":127,"14:4":true,"11:13":true,"8:0":true,"14:2":true,"15:2":true,"8:6":true,"3:1":true,"14:6":true,"12:14":true,"10:5":true,"9:5":true,"11:14":true,"15:6":true,"14:0":true,"2:0":true,"11:12":true} \ No newline at end of file
+{
+ "11:5": true,
+ "7:12": true,
+ "13:13": true,
+ "12:5": true,
+ "10:12": true,
+ "3:0": true,
+ "8:1": true,
+ "14:1": true,
+ "13:12": true,
+ "3:2": 127,
+ "15:1": true,
+ "1:9": true,
+ "15:8": true,
+ "13:14": true,
+ "10:13": true,
+ "14:8": true,
+ "9:13": true,
+ "2:1": true,
+ "12:6": true,
+ "4:3": 127,
+ "5:4": true,
+ "5:3": true,
+ "13:8": true,
+ "11:6": true,
+ "10:7": true,
+ "13:1": true,
+ "4:2": [
+ 127,
+ 202
+ ],
+ "14:12": true,
+ "9:7": true,
+ "5:2": true,
+ "9:1": true,
+ "8:12": true,
+ "13:7": true,
+ "12:4": true,
+ "15:13": true,
+ "12:2": true,
+ "2:10": 127,
+ "10:8": true,
+ "11:2": true,
+ "7:1": true,
+ "14:13": true,
+ "12:1": true,
+ "10:4": true,
+ "10:3": true,
+ "7:2": true,
+ "11:8": true,
+ "13:6": true,
+ "9:2": true,
+ "10:2": true,
+ "12:8": true,
+ "13:2": true,
+ "9:6": true,
+ "15:5": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": 201,
+ "9:0": true,
+ "6:3": 127,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "13:4": true,
+ "12:7": true,
+ "6:2": 127,
+ "7:6": true,
+ "15:4": true,
+ "0:8": true,
+ "15:3": true,
+ "1:0": 127,
+ "14:4": true,
+ "11:13": true,
+ "8:0": true,
+ "14:2": true,
+ "15:2": true,
+ "8:6": true,
+ "3:1": true,
+ "14:6": true,
+ "12:14": true,
+ "10:5": true,
+ "9:5": true,
+ "11:14": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "11:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_7.json
index 8c280ebc..a961528d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_7.json
@@ -1 +1,7 @@
-{"13:15":true,"10:14":true,"12:15":true,"11:15":true,"10:15":true} \ No newline at end of file
+{
+ "13:15": true,
+ "10:14": true,
+ "12:15": true,
+ "11:15": true,
+ "10:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_8.json
index 84dcdb8b..646a75b5 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_8.json
@@ -1 +1,44 @@
-{"12:1":true,"12:11":true,"5:9":true,"13:13":true,"7:15":true,"11:1":true,"11:11":true,"6:13":true,"9:15":true,"13:0":true,"8:11":true,"10:15":true,"1:8":true,"13:15":true,"7:13":true,"2:8":true,"10:0":true,"15:8":true,"10:13":true,"6:15":true,"14:8":true,"4:8":true,"9:13":true,"11:0":true,"8:13":true,"3:8":true,"0:8":true,"12:0":true,"6:11":true,"11:13":true,"5:15":true,"12:13":true,"9:1":true,"9:11":true,"10:1":true,"10:11":true,"8:15":true,"12:15":true,"5:13":true,"11:15":true,"13:9":true,"7:11":true} \ No newline at end of file
+{
+ "12:1": true,
+ "12:11": true,
+ "5:9": true,
+ "13:13": true,
+ "7:15": true,
+ "11:1": true,
+ "11:11": true,
+ "6:13": true,
+ "9:15": true,
+ "13:0": true,
+ "8:11": true,
+ "10:15": true,
+ "1:8": true,
+ "13:15": true,
+ "7:13": true,
+ "2:8": true,
+ "10:0": true,
+ "15:8": true,
+ "10:13": true,
+ "6:15": true,
+ "14:8": true,
+ "4:8": true,
+ "9:13": true,
+ "11:0": true,
+ "8:13": true,
+ "3:8": true,
+ "0:8": true,
+ "12:0": true,
+ "6:11": true,
+ "11:13": true,
+ "5:15": true,
+ "12:13": true,
+ "9:1": true,
+ "9:11": true,
+ "10:1": true,
+ "10:11": true,
+ "8:15": true,
+ "12:15": true,
+ "5:13": true,
+ "11:15": true,
+ "13:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/1_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/1_9.json
index 2b778aa2..e84aa3ad 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/1_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/1_9.json
@@ -1 +1,96 @@
-{"15:9":true,"8:8":true,"13:13":true,"7:15":127,"14:9":true,"6:13":127,"15:7":true,"7:14":127,"10:10":true,"8:7":true,"5:5":true,"0:2":true,"9:10":true,"4:5":true,"13:12":true,"3:2":true,"6:14":127,"15:8":true,"13:14":true,"3:4":true,"8:9":true,"7:10":[117,118],"1:7":true,"0:4":true,"14:8":true,"14:14":true,"10:9":true,"7:7":true,"2:15":true,"13:8":true,"15:14":true,"9:9":true,"8:10":true,"7:9":119,"6:8":120,"3:5":true,"15:12":true,"13:1":true,"4:2":true,"15:15":true,"7:8":true,"15:10":true,"14:10":true,"5:6":true,"8:15":true,"15:13":true,"6:7":true,"1:12":[116,117],"13:9":true,"14:13":true,"6:6":true,"5:7":true,"8:11":117,"12:8":true,"14:11":true,"11:9":true,"5:1":true,"3:15":true,"0:12":[117,118],"12:9":true,"3:14":true,"7:6":true,"4:14":true,"11:10":true,"6:5":true,"5:14":127,"2:2":true,"0:8":true,"15:3":true,"11:13":true,"5:12":true,"2:4":true,"14:2":true,"13:11":true,"15:2":true,"12:13":true,"12:14":true,"9:11":true,"1:4":true,"15:6":true,"5:13":true,"1:2":true,"11:15":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "8:8": true,
+ "13:13": true,
+ "7:15": 127,
+ "14:9": true,
+ "6:13": 127,
+ "15:7": true,
+ "7:14": 127,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "0:2": true,
+ "9:10": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "6:14": 127,
+ "15:8": true,
+ "13:14": true,
+ "3:4": true,
+ "8:9": true,
+ "7:10": [
+ 117,
+ 118
+ ],
+ "1:7": true,
+ "0:4": true,
+ "14:8": true,
+ "14:14": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": true,
+ "13:8": true,
+ "15:14": true,
+ "9:9": true,
+ "8:10": true,
+ "7:9": 119,
+ "6:8": 120,
+ "3:5": true,
+ "15:12": true,
+ "13:1": true,
+ "4:2": true,
+ "15:15": true,
+ "7:8": true,
+ "15:10": true,
+ "14:10": true,
+ "5:6": true,
+ "8:15": true,
+ "15:13": true,
+ "6:7": true,
+ "1:12": [
+ 116,
+ 117
+ ],
+ "13:9": true,
+ "14:13": true,
+ "6:6": true,
+ "5:7": true,
+ "8:11": 117,
+ "12:8": true,
+ "14:11": true,
+ "11:9": true,
+ "5:1": true,
+ "3:15": true,
+ "0:12": [
+ 117,
+ 118
+ ],
+ "12:9": true,
+ "3:14": true,
+ "7:6": true,
+ "4:14": true,
+ "11:10": true,
+ "6:5": true,
+ "5:14": 127,
+ "2:2": true,
+ "0:8": true,
+ "15:3": true,
+ "11:13": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "15:2": true,
+ "12:13": true,
+ "12:14": true,
+ "9:11": true,
+ "1:4": true,
+ "15:6": true,
+ "5:13": true,
+ "1:2": true,
+ "11:15": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-1.json
index 70315fcb..d8d42d25 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-1.json
@@ -1 +1,18 @@
-{"10:12":true,"9:12":true,"13:12":true,"11:0":196,"9:9":true,"0:11":205,"10:8":true,"9:8":true,"1:11":205,"8:11":true,"14:11":true,"10:0":197,"15:11":true,"11:12":true,"12:12":true,"7:11":true} \ No newline at end of file
+{
+ "10:12": true,
+ "9:12": true,
+ "13:12": true,
+ "11:0": 196,
+ "9:9": true,
+ "0:11": 205,
+ "10:8": true,
+ "9:8": true,
+ "1:11": 205,
+ "8:11": true,
+ "14:11": true,
+ "10:0": 197,
+ "15:11": true,
+ "11:12": true,
+ "12:12": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-2.json
index ea803f53..511a2a33 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-2.json
@@ -1 +1,48 @@
-{"12:11":233,"13:13":true,"6:13":true,"13:0":true,"13:10":234,"14:11":true,"14:1":true,"15:5":[174,175],"13:12":true,"15:1":true,"6:12":227,"15:4":[173,174],"15:3":[173,174],"9:9":[213,215],"11:6":[211,213],"10:7":[211,212],"8:10":214,"13:11":true,"13:1":true,"14:12":true,"12:13":true,"15:0":true,"15:6":[174,175],"14:0":true,"12:12":234} \ No newline at end of file
+{
+ "12:11": 233,
+ "13:13": true,
+ "6:13": true,
+ "13:0": true,
+ "13:10": 234,
+ "14:11": true,
+ "14:1": true,
+ "15:5": [
+ 174,
+ 175
+ ],
+ "13:12": true,
+ "15:1": true,
+ "6:12": 227,
+ "15:4": [
+ 173,
+ 174
+ ],
+ "15:3": [
+ 173,
+ 174
+ ],
+ "9:9": [
+ 213,
+ 215
+ ],
+ "11:6": [
+ 211,
+ 213
+ ],
+ "10:7": [
+ 211,
+ 212
+ ],
+ "8:10": 214,
+ "13:11": true,
+ "13:1": true,
+ "14:12": true,
+ "12:13": true,
+ "15:0": true,
+ "15:6": [
+ 174,
+ 175
+ ],
+ "14:0": true,
+ "12:12": 234
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-4.json
index 06c33ad1..9a9539b0 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-4.json
@@ -1 +1,71 @@
-{"9:14":true,"7:12":true,"5:9":true,"13:13":true,"4:9":true,"11:1":true,"9:4":true,"7:4":true,"9:12":true,"0:10":true,"7:14":true,"9:6":true,"4:1":true,"3:12":true,"0:2":true,"7:13":true,"6:4":true,"9:10":true,"5:1":true,"13:12":true,"3:15":true,"3:2":true,"9:0":true,"6:14":true,"6:3":true,"7:0":true,"3:4":true,"0:3":true,"7:10":true,"5:8":true,"0:4":true,"6:15":true,"6:2":true,"7:6":true,"4:8":true,"9:13":true,"11:0":true,"4:14":true,"4:3":true,"5:4":true,"7:7":true,"3:8":true,"5:14":true,"5:3":true,"9:9":true,"4:4":true,"7:9":true,"3:5":true,"4:15":true,"4:2":true,"0:11":true,"9:7":true,"3:1":true,"3:11":true,"5:15":true,"5:2":true,"9:11":true,"9:1":true,"7:8":true,"6:9":true,"5:10":true,"9:5":true,"4:10":true,"7:5":true,"3:9":true,"0:9":true,"9:8":true,"7:11":true,"7:1":true} \ No newline at end of file
+{
+ "9:14": true,
+ "7:12": true,
+ "5:9": true,
+ "13:13": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "7:4": true,
+ "9:12": true,
+ "0:10": true,
+ "7:14": true,
+ "9:6": true,
+ "4:1": true,
+ "3:12": true,
+ "0:2": true,
+ "7:13": true,
+ "6:4": true,
+ "9:10": true,
+ "5:1": true,
+ "13:12": true,
+ "3:15": true,
+ "3:2": true,
+ "9:0": true,
+ "6:14": true,
+ "6:3": true,
+ "7:0": true,
+ "3:4": true,
+ "0:3": true,
+ "7:10": true,
+ "5:8": true,
+ "0:4": true,
+ "6:15": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "9:13": true,
+ "11:0": true,
+ "4:14": true,
+ "4:3": true,
+ "5:4": true,
+ "7:7": true,
+ "3:8": true,
+ "5:14": true,
+ "5:3": true,
+ "9:9": true,
+ "4:4": true,
+ "7:9": true,
+ "3:5": true,
+ "4:15": true,
+ "4:2": true,
+ "0:11": true,
+ "9:7": true,
+ "3:1": true,
+ "3:11": true,
+ "5:15": true,
+ "5:2": true,
+ "9:11": true,
+ "9:1": true,
+ "7:8": true,
+ "6:9": true,
+ "5:10": true,
+ "9:5": true,
+ "4:10": true,
+ "7:5": true,
+ "3:9": true,
+ "0:9": true,
+ "9:8": true,
+ "7:11": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-5.json
index b7f553d7..2390fe19 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-5.json
@@ -1 +1,60 @@
-{"9:14":true,"7:12":true,"6:10":true,"5:9":true,"12:5":true,"7:15":true,"4:9":true,"11:11":true,"11:8":true,"6:13":true,"9:15":true,"9:12":true,"4:7":true,"7:14":true,"4:11":true,"0:2":true,"11:9":true,"7:13":true,"9:10":true,"5:11":true,"3:2":true,"9:0":true,"3:4":true,"0:3":true,"0:14":true,"7:10":true,"6:12":true,"5:8":true,"0:4":true,"4:8":true,"9:13":true,"11:10":true,"5:4":true,"0:8":true,"6:11":true,"4:4":true,"11:13":true,"7:9":true,"6:8":true,"5:12":true,"3:5":true,"2:4":true,"0:1":true,"4:12":true,"3:1":true,"9:11":true,"7:8":true,"6:9":true,"5:10":true,"4:10":true,"11:14":true,"1:4":true,"11:12":true,"5:13":true,"11:15":true,"7:11":true,"7:1":true,"4:13":true} \ No newline at end of file
+{
+ "9:14": true,
+ "7:12": true,
+ "6:10": true,
+ "5:9": true,
+ "12:5": true,
+ "7:15": true,
+ "4:9": true,
+ "11:11": true,
+ "11:8": true,
+ "6:13": true,
+ "9:15": true,
+ "9:12": true,
+ "4:7": true,
+ "7:14": true,
+ "4:11": true,
+ "0:2": true,
+ "11:9": true,
+ "7:13": true,
+ "9:10": true,
+ "5:11": true,
+ "3:2": true,
+ "9:0": true,
+ "3:4": true,
+ "0:3": true,
+ "0:14": true,
+ "7:10": true,
+ "6:12": true,
+ "5:8": true,
+ "0:4": true,
+ "4:8": true,
+ "9:13": true,
+ "11:10": true,
+ "5:4": true,
+ "0:8": true,
+ "6:11": true,
+ "4:4": true,
+ "11:13": true,
+ "7:9": true,
+ "6:8": true,
+ "5:12": true,
+ "3:5": true,
+ "2:4": true,
+ "0:1": true,
+ "4:12": true,
+ "3:1": true,
+ "9:11": true,
+ "7:8": true,
+ "6:9": true,
+ "5:10": true,
+ "4:10": true,
+ "11:14": true,
+ "1:4": true,
+ "11:12": true,
+ "5:13": true,
+ "11:15": true,
+ "7:11": true,
+ "7:1": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-7.json
index 175d154e..c1e5c107 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_-7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_-7.json
@@ -1 +1,40 @@
-{"12:11":true,"1:11":true,"2:7":true,"2:12":true,"13:13":true,"1:10":true,"13:8":true,"10:7":true,"5:7":true,"13:11":true,"9:7":true,"4:7":true,"13:10":true,"12:13":true,"10:15":true,"5:15":true,"1:13":true,"1:8":true,"13:15":true,"8:7":true,"2:13":true,"1:14":true,"0:15":true,"11:9":true,"13:12":true,"13:7":true,"3:15":true,"1:9":true,"13:14":true,"1:15":true,"6:7":true,"3:9":true,"12:7":true,"12:12":true,"1:12":true,"1:7":true,"13:9":true,"2:11":true} \ No newline at end of file
+{
+ "12:11": true,
+ "1:11": true,
+ "2:7": true,
+ "2:12": true,
+ "13:13": true,
+ "1:10": true,
+ "13:8": true,
+ "10:7": true,
+ "5:7": true,
+ "13:11": true,
+ "9:7": true,
+ "4:7": true,
+ "13:10": true,
+ "12:13": true,
+ "10:15": true,
+ "5:15": true,
+ "1:13": true,
+ "1:8": true,
+ "13:15": true,
+ "8:7": true,
+ "2:13": true,
+ "1:14": true,
+ "0:15": true,
+ "11:9": true,
+ "13:12": true,
+ "13:7": true,
+ "3:15": true,
+ "1:9": true,
+ "13:14": true,
+ "1:15": true,
+ "6:7": true,
+ "3:9": true,
+ "12:7": true,
+ "12:12": true,
+ "1:12": true,
+ "1:7": true,
+ "13:9": true,
+ "2:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_0.json
index 046b2dbc..e6bb771d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_0.json
@@ -1 +1,87 @@
-{"1:1":true,"3:0":[196,202],"0:0":[193,203],"8:1":205,"14:1":205,"15:1":205,"11:0":[157,202],"5:4":true,"7:7":true,"12:0":[141,202],"4:4":true,"9:1":159,"5:0":true,"4:0":true,"12:2":true,"11:2":true,"7:1":205,"6:0":true,"7:2":[154,158],"6:6":true,"11:1":156,"13:0":[141,202],"10:2":true,"13:2":[157,159],"6:4":true,"10:0":[142,202],"9:0":[143,202],"6:3":true,"7:0":[152,202],"6:2":157,"1:0":true,"8:0":[150,202],"14:2":158,"0:1":true,"15:0":[198,202],"11:14":214,"14:0":[198,202],"2:0":[196,202],"12:15":true,"11:15":[212,213]} \ No newline at end of file
+{
+ "1:1": true,
+ "3:0": [
+ 196,
+ 202
+ ],
+ "0:0": [
+ 193,
+ 203
+ ],
+ "8:1": 205,
+ "14:1": 205,
+ "15:1": 205,
+ "11:0": [
+ 157,
+ 202
+ ],
+ "5:4": true,
+ "7:7": true,
+ "12:0": [
+ 141,
+ 202
+ ],
+ "4:4": true,
+ "9:1": 159,
+ "5:0": true,
+ "4:0": true,
+ "12:2": true,
+ "11:2": true,
+ "7:1": 205,
+ "6:0": true,
+ "7:2": [
+ 154,
+ 158
+ ],
+ "6:6": true,
+ "11:1": 156,
+ "13:0": [
+ 141,
+ 202
+ ],
+ "10:2": true,
+ "13:2": [
+ 157,
+ 159
+ ],
+ "6:4": true,
+ "10:0": [
+ 142,
+ 202
+ ],
+ "9:0": [
+ 143,
+ 202
+ ],
+ "6:3": true,
+ "7:0": [
+ 152,
+ 202
+ ],
+ "6:2": 157,
+ "1:0": true,
+ "8:0": [
+ 150,
+ 202
+ ],
+ "14:2": 158,
+ "0:1": true,
+ "15:0": [
+ 198,
+ 202
+ ],
+ "11:14": 214,
+ "14:0": [
+ 198,
+ 202
+ ],
+ "2:0": [
+ 196,
+ 202
+ ],
+ "12:15": true,
+ "11:15": [
+ 212,
+ 213
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_10.json
index 59e038d9..18003fa5 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_10.json
@@ -1 +1,278 @@
-{"1:1":true,"8:8":[139,141],"6:10":true,"13:13":true,"0:0":true,"3:6":true,"14:1":true,"13:15":true,"8:7":true,"5:5":154,"4:11":[165,166],"0:2":true,"5:11":[134,176],"13:12":true,"3:2":182,"15:1":true,"13:14":true,"0:3":true,"8:9":true,"7:10":true,"0:4":true,"2:1":true,"14:14":true,"5:4":154,"10:9":true,"7:7":true,"5:3":155,"15:14":true,"9:9":141,"10:7":true,"8:10":true,"7:9":true,"3:5":[169,173],"15:12":true,"14:15":true,"13:1":true,"15:15":true,"14:12":true,"9:7":true,"0:5":true,"7:8":true,"6:9":[134,135],"15:13":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"1:5":true,"11:8":true,"13:6":[168,169],"13:0":true,"12:8":true,"14:11":true,"11:9":true,"15:5":[146,173],"14:5":[144,174],"0:12":true,"15:11":true,"12:9":true,"13:3":true,"2:5":true,"13:4":true,"15:4":[147,149],"14:3":true,"4:14":146,"11:10":true,"12:10":true,"5:14":true,"2:2":183,"1:0":true,"5:12":[134,176],"2:4":true,"14:2":true,"13:11":true,"0:1":true,"15:2":true,"4:12":[132,165],"13:5":[145,173],"2:3":[180,183],"15:0":true,"14:6":[168,169],"1:3":true,"1:4":true,"15:6":[168,172],"14:0":true,"2:0":true,"5:13":[167,176],"1:2":true,"4:13":[164,166],"2:6":true,"15:9":true,"12:11":true,"11:5":true,"2:7":true,"12:5":[148,170],"14:9":true,"11:11":true,"6:13":[169,174],"2:9":true,"13:10":true,"10:15":true,"1:8":true,"2:8":true,"15:8":true,"6:12":[140,174],"1:7":true,"14:8":158,"13:8":true,"6:1":156,"12:3":true,"11:4":[139,170],"15:10":true,"14:10":true,"10:1":[171,178],"12:4":[142,174],"11:3":[135,176],"12:2":true,"11:2":[131,178],"13:9":true,"7:1":[154,155],"12:1":true,"10:4":[134,138],"5:9":[170,174],"10:3":[131,173],"6:6":true,"4:9":[166,176],"11:1":[169,170],"9:4":132,"8:5":true,"7:4":true,"4:7":[168,169],"10:2":[174,176],"6:4":true,"10:0":[174,178],"10:6":true,"6:3":true,"7:0":true,"6:2":true,"7:6":true,"4:8":[167,175],"6:5":true,"3:8":true,"0:8":true,"6:11":[136,172],"11:13":true,"8:6":true,"12:13":true,"3:7":true,"12:14":true,"10:5":true,"5:10":[168,176],"9:5":true,"4:10":[166,177],"11:14":true,"12:15":true,"11:12":true,"7:5":true,"3:9":true,"12:12":true,"11:15":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": [
+ 139,
+ 141
+ ],
+ "6:10": true,
+ "13:13": true,
+ "0:0": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": true,
+ "8:7": true,
+ "5:5": 154,
+ "4:11": [
+ 165,
+ 166
+ ],
+ "0:2": true,
+ "5:11": [
+ 134,
+ 176
+ ],
+ "13:12": true,
+ "3:2": 182,
+ "15:1": true,
+ "13:14": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "0:4": true,
+ "2:1": true,
+ "14:14": true,
+ "5:4": 154,
+ "10:9": true,
+ "7:7": true,
+ "5:3": 155,
+ "15:14": true,
+ "9:9": 141,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "3:5": [
+ 169,
+ 173
+ ],
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "0:5": true,
+ "7:8": true,
+ "6:9": [
+ 134,
+ 135
+ ],
+ "15:13": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:5": true,
+ "11:8": true,
+ "13:6": [
+ 168,
+ 169
+ ],
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "11:9": true,
+ "15:5": [
+ 146,
+ 173
+ ],
+ "14:5": [
+ 144,
+ 174
+ ],
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "2:5": true,
+ "13:4": true,
+ "15:4": [
+ 147,
+ 149
+ ],
+ "14:3": true,
+ "4:14": 146,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "2:2": 183,
+ "1:0": true,
+ "5:12": [
+ 134,
+ 176
+ ],
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "0:1": true,
+ "15:2": true,
+ "4:12": [
+ 132,
+ 165
+ ],
+ "13:5": [
+ 145,
+ 173
+ ],
+ "2:3": [
+ 180,
+ 183
+ ],
+ "15:0": true,
+ "14:6": [
+ 168,
+ 169
+ ],
+ "1:3": true,
+ "1:4": true,
+ "15:6": [
+ 168,
+ 172
+ ],
+ "14:0": true,
+ "2:0": true,
+ "5:13": [
+ 167,
+ 176
+ ],
+ "1:2": true,
+ "4:13": [
+ 164,
+ 166
+ ],
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "11:5": true,
+ "2:7": true,
+ "12:5": [
+ 148,
+ 170
+ ],
+ "14:9": true,
+ "11:11": true,
+ "6:13": [
+ 169,
+ 174
+ ],
+ "2:9": true,
+ "13:10": true,
+ "10:15": true,
+ "1:8": true,
+ "2:8": true,
+ "15:8": true,
+ "6:12": [
+ 140,
+ 174
+ ],
+ "1:7": true,
+ "14:8": 158,
+ "13:8": true,
+ "6:1": 156,
+ "12:3": true,
+ "11:4": [
+ 139,
+ 170
+ ],
+ "15:10": true,
+ "14:10": true,
+ "10:1": [
+ 171,
+ 178
+ ],
+ "12:4": [
+ 142,
+ 174
+ ],
+ "11:3": [
+ 135,
+ 176
+ ],
+ "12:2": true,
+ "11:2": [
+ 131,
+ 178
+ ],
+ "13:9": true,
+ "7:1": [
+ 154,
+ 155
+ ],
+ "12:1": true,
+ "10:4": [
+ 134,
+ 138
+ ],
+ "5:9": [
+ 170,
+ 174
+ ],
+ "10:3": [
+ 131,
+ 173
+ ],
+ "6:6": true,
+ "4:9": [
+ 166,
+ 176
+ ],
+ "11:1": [
+ 169,
+ 170
+ ],
+ "9:4": 132,
+ "8:5": true,
+ "7:4": true,
+ "4:7": [
+ 168,
+ 169
+ ],
+ "10:2": [
+ 174,
+ 176
+ ],
+ "6:4": true,
+ "10:0": [
+ 174,
+ 178
+ ],
+ "10:6": true,
+ "6:3": true,
+ "7:0": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": [
+ 167,
+ 175
+ ],
+ "6:5": true,
+ "3:8": true,
+ "0:8": true,
+ "6:11": [
+ 136,
+ 172
+ ],
+ "11:13": true,
+ "8:6": true,
+ "12:13": true,
+ "3:7": true,
+ "12:14": true,
+ "10:5": true,
+ "5:10": [
+ 168,
+ 176
+ ],
+ "9:5": true,
+ "4:10": [
+ 166,
+ 177
+ ],
+ "11:14": true,
+ "12:15": true,
+ "11:12": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_3.json
index 86d84cb3..e0fb583d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_3.json
@@ -1 +1,3 @@
-{"1:4":true} \ No newline at end of file
+{
+ "1:4": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_4.json
index 182d0153..3f26cae9 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_4.json
@@ -1 +1,145 @@
-{"15:9":true,"1:1":true,"2:7":true,"8:8":true,"7:12":true,"14:9":true,"10:12":true,"6:13":true,"2:9":true,"15:7":true,"0:6":true,"14:7":true,"9:12":true,"3:6":true,"1:8":true,"10:10":true,"8:7":true,"4:11":true,"7:13":true,"2:8":true,"9:10":true,"5:11":true,"3:2":true,"1:9":true,"15:8":true,"10:13":true,"3:4":true,"0:3":true,"8:9":true,"6:12":true,"1:7":true,"14:8":true,"9:13":true,"12:6":true,"4:3":true,"8:13":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"1:10":true,"13:8":true,"9:9":true,"11:6":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"4:2":true,"0:11":true,"9:7":true,"3:11":true,"5:2":true,"1:13":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"5:6":true,"13:7":true,"2:10":true,"10:8":true,"6:7":true,"1:12":true,"13:9":true,"9:8":true,"9:3":true,"1:11":true,"10:4":true,"3:13":true,"10:3":true,"0:13":true,"7:2":true,"6:6":true,"4:9":true,"9:4":true,"5:7":true,"3:10":true,"11:8":true,"13:6":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"12:8":true,"13:2":true,"9:6":true,"3:12":true,"11:9":true,"15:5":true,"14:5":true,"10:6":true,"0:12":true,"12:9":true,"13:3":true,"11:7":true,"13:4":true,"12:7":true,"6:2":true,"7:6":true,"4:8":true,"2:11":true,"15:4":true,"14:3":true,"1:6":true,"3:8":true,"0:8":true,"15:3":true,"6:11":true,"14:4":true,"5:12":true,"14:2":[154,157],"0:1":true,"15:2":[154,157],"8:6":true,"4:12":true,"13:5":true,"14:6":true,"9:11":true,"5:10":true,"10:5":true,"3:7":true,"10:11":true,"9:5":true,"4:10":true,"8:2":true,"0:7":true,"15:6":true,"5:13":true,"3:9":true,"0:9":true,"7:11":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "1:1": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": true,
+ "14:9": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "15:7": true,
+ "0:6": true,
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "1:8": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "7:13": true,
+ "2:8": true,
+ "9:10": true,
+ "5:11": true,
+ "3:2": true,
+ "1:9": true,
+ "15:8": true,
+ "10:13": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "6:12": true,
+ "1:7": true,
+ "14:8": true,
+ "9:13": true,
+ "12:6": true,
+ "4:3": true,
+ "8:13": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "1:10": true,
+ "13:8": true,
+ "9:9": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "4:2": true,
+ "0:11": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "1:13": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "5:6": true,
+ "13:7": true,
+ "2:10": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "13:9": true,
+ "9:8": true,
+ "9:3": true,
+ "1:11": true,
+ "10:4": true,
+ "3:13": true,
+ "10:3": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "9:4": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "13:6": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "12:8": true,
+ "13:2": true,
+ "9:6": true,
+ "3:12": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "10:6": true,
+ "0:12": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "13:4": true,
+ "12:7": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "3:8": true,
+ "0:8": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "5:12": true,
+ "14:2": [
+ 154,
+ 157
+ ],
+ "0:1": true,
+ "15:2": [
+ 154,
+ 157
+ ],
+ "8:6": true,
+ "4:12": true,
+ "13:5": true,
+ "14:6": true,
+ "9:11": true,
+ "5:10": true,
+ "10:5": true,
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "8:2": true,
+ "0:7": true,
+ "15:6": true,
+ "5:13": true,
+ "3:9": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_6.json
index 458177bc..71567b5a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_6.json
@@ -1 +1,132 @@
-{"15:9":true,"1:1":true,"11:5":true,"6:10":true,"12:5":true,"14:9":true,"15:7":true,"3:0":true,"0:6":true,"0:0":true,"14:7":true,"8:1":true,"3:6":true,"13:10":true,"10:10":true,"5:5":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"3:2":true,"15:8":true,"3:4":true,"0:3":true,"7:10":true,"3:3":true,"0:4":true,"6:15":true,"14:8":true,"2:1":true,"12:6":true,"4:3":true,"10:9":true,"13:8":true,"9:9":true,"6:1":true,"11:6":true,"4:4":true,"10:7":true,"8:10":true,"3:5":true,"4:2":true,"0:11":true,"9:7":true,"5:2":true,"0:5":true,"12:3":true,"11:4":true,"9:1":true,"4:6":true,"15:10":true,"5:0":true,"14:10":true,"10:1":true,"5:6":true,"13:7":true,"12:4":true,"11:3":true,"4:0":true,"10:8":true,"13:9":true,"9:8":true,"7:1":true,"9:3":true,"6:0":true,"1:11":true,"10:4":true,"5:9":true,"10:3":true,"1:5":true,"6:6":true,"4:9":true,"9:4":true,"8:5":true,"3:10":true,"7:4":true,"13:6":true,"9:2":true,"10:2":true,"7:3":true,"9:6":true,"4:1":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"5:1":true,"9:0":true,"6:3":true,"7:0":true,"13:3":true,"2:5":true,"5:8":true,"13:4":true,"7:6":true,"4:8":true,"15:4":true,"14:3":true,"1:6":true,"6:5":true,"3:8":true,"2:2":true,"15:3":true,"1:0":true,"14:4":true,"5:12":true,"2:4":true,"8:0":true,"0:1":true,"8:6":true,"3:1":true,"13:5":true,"2:3":true,"14:6":true,"10:5":true,"5:10":true,"1:3":true,"9:5":true,"4:10":true,"8:2":true,"1:4":true,"15:6":true,"2:0":true,"8:4":true,"5:13":true,"1:2":true,"7:5":true,"8:3":true,"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": true,
+ "1:1": true,
+ "11:5": true,
+ "6:10": true,
+ "12:5": true,
+ "14:9": true,
+ "15:7": true,
+ "3:0": true,
+ "0:6": true,
+ "0:0": true,
+ "14:7": true,
+ "8:1": true,
+ "3:6": true,
+ "13:10": true,
+ "10:10": true,
+ "5:5": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "3:2": true,
+ "15:8": true,
+ "3:4": true,
+ "0:3": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "6:15": true,
+ "14:8": true,
+ "2:1": true,
+ "12:6": true,
+ "4:3": true,
+ "10:9": true,
+ "13:8": true,
+ "9:9": true,
+ "6:1": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "3:5": true,
+ "4:2": true,
+ "0:11": true,
+ "9:7": true,
+ "5:2": true,
+ "0:5": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "4:6": true,
+ "15:10": true,
+ "5:0": true,
+ "14:10": true,
+ "10:1": true,
+ "5:6": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "4:0": true,
+ "10:8": true,
+ "13:9": true,
+ "9:8": true,
+ "7:1": true,
+ "9:3": true,
+ "6:0": true,
+ "1:11": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "1:5": true,
+ "6:6": true,
+ "4:9": true,
+ "9:4": true,
+ "8:5": true,
+ "3:10": true,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "4:1": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "2:5": true,
+ "5:8": true,
+ "13:4": true,
+ "7:6": true,
+ "4:8": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "6:5": true,
+ "3:8": true,
+ "2:2": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "8:0": true,
+ "0:1": true,
+ "8:6": true,
+ "3:1": true,
+ "13:5": true,
+ "2:3": true,
+ "14:6": true,
+ "10:5": true,
+ "5:10": true,
+ "1:3": true,
+ "9:5": true,
+ "4:10": true,
+ "8:2": true,
+ "1:4": true,
+ "15:6": true,
+ "2:0": true,
+ "8:4": true,
+ "5:13": true,
+ "1:2": true,
+ "7:5": true,
+ "8:3": true,
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_7.json
index 3b0bf529..2c97d46a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_7.json
@@ -1 +1,3 @@
-{"4:12":true} \ No newline at end of file
+{
+ "4:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_8.json
index 56f5e08c..706c7308 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_8.json
@@ -1 +1,103 @@
-{"12:11":true,"6:10":[142,201],"7:15":[155,156],"11:11":true,"10:12":true,"9:15":153,"9:12":true,"10:15":[149,154],"13:10":119,"1:8":true,"13:15":[149,153],"4:11":[150,151],"2:8":true,"9:10":120,"13:14":[142,189],"10:13":true,"6:15":[132,160],"9:13":true,"14:14":true,"8:13":true,"15:14":[150,151],"7:9":200,"15:12":[143,190],"14:15":[151,152],"14:12":[142,189],"6:9":true,"15:10":true,"14:10":119,"15:13":true,"9:8":172,"14:13":[142,190],"13:6":[176,177],"3:15":[153,161],"15:11":[142,190],"0:8":true,"13:11":true,"4:15":[133,162],"5:15":[132,161],"12:14":true,"9:11":true,"10:11":true,"12:15":[141,189],"11:12":true,"11:15":[141,188]} \ No newline at end of file
+{
+ "12:11": true,
+ "6:10": [
+ 142,
+ 201
+ ],
+ "7:15": [
+ 155,
+ 156
+ ],
+ "11:11": true,
+ "10:12": true,
+ "9:15": 153,
+ "9:12": true,
+ "10:15": [
+ 149,
+ 154
+ ],
+ "13:10": 119,
+ "1:8": true,
+ "13:15": [
+ 149,
+ 153
+ ],
+ "4:11": [
+ 150,
+ 151
+ ],
+ "2:8": true,
+ "9:10": 120,
+ "13:14": [
+ 142,
+ 189
+ ],
+ "10:13": true,
+ "6:15": [
+ 132,
+ 160
+ ],
+ "9:13": true,
+ "14:14": true,
+ "8:13": true,
+ "15:14": [
+ 150,
+ 151
+ ],
+ "7:9": 200,
+ "15:12": [
+ 143,
+ 190
+ ],
+ "14:15": [
+ 151,
+ 152
+ ],
+ "14:12": [
+ 142,
+ 189
+ ],
+ "6:9": true,
+ "15:10": true,
+ "14:10": 119,
+ "15:13": true,
+ "9:8": 172,
+ "14:13": [
+ 142,
+ 190
+ ],
+ "13:6": [
+ 176,
+ 177
+ ],
+ "3:15": [
+ 153,
+ 161
+ ],
+ "15:11": [
+ 142,
+ 190
+ ],
+ "0:8": true,
+ "13:11": true,
+ "4:15": [
+ 133,
+ 162
+ ],
+ "5:15": [
+ 132,
+ 161
+ ],
+ "12:14": true,
+ "9:11": true,
+ "10:11": true,
+ "12:15": [
+ 141,
+ 189
+ ],
+ "11:12": true,
+ "11:15": [
+ 141,
+ 188
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/2_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/2_9.json
index b1c8feb6..0019a44d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/2_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/2_9.json
@@ -1 +1,265 @@
-{"8:8":true,"6:10":true,"13:13":185,"0:6":true,"14:1":191,"13:15":184,"10:10":true,"8:7":true,"5:5":[157,158],"0:2":true,"9:10":true,"13:12":true,"15:1":192,"13:14":185,"0:3":true,"8:9":true,"7:10":true,"0:4":true,"2:1":true,"14:14":184,"4:3":158,"5:4":158,"2:12":true,"10:9":true,"7:7":true,"2:15":true,"15:14":[141,183],"9:9":true,"10:7":true,"8:10":true,"7:9":true,"6:8":158,"3:5":177,"15:12":[132,186],"14:15":[134,183],"13:1":[152,153],"4:2":158,"0:11":true,"15:15":true,"14:12":[152,187],"9:7":true,"3:11":182,"2:14":182,"1:13":true,"2:13":true,"7:8":true,"6:9":true,"1:14":true,"5:0":[132,133],"5:6":158,"4:0":133,"15:13":184,"1:15":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":186,"1:11":true,"1:5":true,"0:13":true,"11:8":true,"13:6":true,"13:0":[150,190],"12:8":true,"14:11":188,"13:2":true,"3:12":182,"11:9":true,"15:5":true,"14:5":true,"0:12":true,"15:11":[132,188],"12:9":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"13:4":true,"12:7":true,"2:11":true,"15:4":true,"1:6":true,"11:10":true,"12:10":true,"2:2":true,"15:3":192,"14:4":true,"2:4":true,"14:2":192,"13:11":true,"15:2":192,"3:1":158,"13:5":true,"2:3":[174,183],"15:0":192,"14:6":true,"1:3":true,"1:4":true,"15:6":true,"14:0":[152,191],"1:2":true,"2:6":true,"15:9":190,"12:11":true,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"10:14":[174,175],"7:15":[155,157],"14:9":191,"11:11":true,"10:12":true,"2:9":true,"9:12":[154,182],"13:10":true,"10:15":[174,176],"7:14":true,"7:13":true,"2:8":true,"15:8":190,"10:13":true,"6:12":160,"1:7":true,"14:8":191,"9:13":[153,181],"11:0":[141,188],"12:6":true,"8:13":true,"1:10":true,"13:8":true,"12:0":[147,149],"6:1":[132,133],"11:6":true,"11:4":true,"8:12":true,"12:3":true,"15:10":189,"14:10":[132,189],"13:7":true,"12:4":true,"11:3":true,"8:15":154,"12:2":true,"2:10":true,"11:2":true,"8:14":true,"13:9":true,"12:1":[149,151],"10:4":184,"6:6":true,"11:1":[144,189],"3:10":[181,183],"8:11":true,"9:6":true,"10:6":true,"7:6":true,"3:8":[180,182],"0:8":true,"6:11":true,"11:13":[172,185],"12:13":185,"12:14":185,"10:5":true,"9:11":[155,182],"3:7":[179,180],"10:11":true,"11:14":[171,172],"0:7":true,"12:15":184,"11:12":true,"3:9":[181,183],"12:12":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "8:8": true,
+ "6:10": true,
+ "13:13": 185,
+ "0:6": true,
+ "14:1": 191,
+ "13:15": 184,
+ "10:10": true,
+ "8:7": true,
+ "5:5": [
+ 157,
+ 158
+ ],
+ "0:2": true,
+ "9:10": true,
+ "13:12": true,
+ "15:1": 192,
+ "13:14": 185,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "0:4": true,
+ "2:1": true,
+ "14:14": 184,
+ "4:3": 158,
+ "5:4": 158,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": true,
+ "15:14": [
+ 141,
+ 183
+ ],
+ "9:9": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": 158,
+ "3:5": 177,
+ "15:12": [
+ 132,
+ 186
+ ],
+ "14:15": [
+ 134,
+ 183
+ ],
+ "13:1": [
+ 152,
+ 153
+ ],
+ "4:2": 158,
+ "0:11": true,
+ "15:15": true,
+ "14:12": [
+ 152,
+ 187
+ ],
+ "9:7": true,
+ "3:11": 182,
+ "2:14": 182,
+ "1:13": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "1:14": true,
+ "5:0": [
+ 132,
+ 133
+ ],
+ "5:6": 158,
+ "4:0": 133,
+ "15:13": 184,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": 186,
+ "1:11": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": [
+ 150,
+ 190
+ ],
+ "12:8": true,
+ "14:11": 188,
+ "13:2": true,
+ "3:12": 182,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "0:12": true,
+ "15:11": [
+ 132,
+ 188
+ ],
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": true,
+ "2:11": true,
+ "15:4": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "2:2": true,
+ "15:3": 192,
+ "14:4": true,
+ "2:4": true,
+ "14:2": 192,
+ "13:11": true,
+ "15:2": 192,
+ "3:1": 158,
+ "13:5": true,
+ "2:3": [
+ 174,
+ 183
+ ],
+ "15:0": 192,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": true,
+ "14:0": [
+ 152,
+ 191
+ ],
+ "1:2": true,
+ "2:6": true,
+ "15:9": 190,
+ "12:11": true,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": [
+ 174,
+ 175
+ ],
+ "7:15": [
+ 155,
+ 157
+ ],
+ "14:9": 191,
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "9:12": [
+ 154,
+ 182
+ ],
+ "13:10": true,
+ "10:15": [
+ 174,
+ 176
+ ],
+ "7:14": true,
+ "7:13": true,
+ "2:8": true,
+ "15:8": 190,
+ "10:13": true,
+ "6:12": 160,
+ "1:7": true,
+ "14:8": 191,
+ "9:13": [
+ 153,
+ 181
+ ],
+ "11:0": [
+ 141,
+ 188
+ ],
+ "12:6": true,
+ "8:13": true,
+ "1:10": true,
+ "13:8": true,
+ "12:0": [
+ 147,
+ 149
+ ],
+ "6:1": [
+ 132,
+ 133
+ ],
+ "11:6": true,
+ "11:4": true,
+ "8:12": true,
+ "12:3": true,
+ "15:10": 189,
+ "14:10": [
+ 132,
+ 189
+ ],
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": 154,
+ "12:2": true,
+ "2:10": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "12:1": [
+ 149,
+ 151
+ ],
+ "10:4": 184,
+ "6:6": true,
+ "11:1": [
+ 144,
+ 189
+ ],
+ "3:10": [
+ 181,
+ 183
+ ],
+ "8:11": true,
+ "9:6": true,
+ "10:6": true,
+ "7:6": true,
+ "3:8": [
+ 180,
+ 182
+ ],
+ "0:8": true,
+ "6:11": true,
+ "11:13": [
+ 172,
+ 185
+ ],
+ "12:13": 185,
+ "12:14": 185,
+ "10:5": true,
+ "9:11": [
+ 155,
+ 182
+ ],
+ "3:7": [
+ 179,
+ 180
+ ],
+ "10:11": true,
+ "11:14": [
+ 171,
+ 172
+ ],
+ "0:7": true,
+ "12:15": 184,
+ "11:12": true,
+ "3:9": [
+ 181,
+ 183
+ ],
+ "12:12": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-1.json
index d4457364..1935090e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-1.json
@@ -1 +1,27 @@
-{"15:4":true,"15:9":true,"2:12":true,"7:12":true,"15:3":true,"6:11":true,"10:12":true,"15:12":true,"13:11":true,"15:2":true,"14:12":true,"14:7":true,"9:12":true,"4:12":true,"14:6":true,"8:12":true,"3:12":true,"15:10":true,"5:11":true,"0:12":true,"15:11":true,"15:8":true,"11:12":true,"1:12":true,"14:8":true} \ No newline at end of file
+{
+ "15:4": true,
+ "15:9": true,
+ "2:12": true,
+ "7:12": true,
+ "15:3": true,
+ "6:11": true,
+ "10:12": true,
+ "15:12": true,
+ "13:11": true,
+ "15:2": true,
+ "14:12": true,
+ "14:7": true,
+ "9:12": true,
+ "4:12": true,
+ "14:6": true,
+ "8:12": true,
+ "3:12": true,
+ "15:10": true,
+ "5:11": true,
+ "0:12": true,
+ "15:11": true,
+ "15:8": true,
+ "11:12": true,
+ "1:12": true,
+ "14:8": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-10.json
index b6c9743e..cac50614 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-10.json
@@ -1 +1,5 @@
-{"5:12":true,"4:12":true,"3:11":true} \ No newline at end of file
+{
+ "5:12": true,
+ "4:12": true,
+ "3:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-3.json
index 5b792a9b..2bff09f0 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-3.json
@@ -1 +1,30 @@
-{"15:4":true,"14:3":203,"4:14":true,"4:3":true,"12:5":true,"5:14":true,"2:15":true,"7:15":true,"4:9":true,"14:4":true,"4:4":true,"5:12":true,"6:13":true,"4:15":true,"4:2":true,"5:15":true,"5:10":true,"0:15":true,"5:11":true,"3:15":true,"6:14":true,"5:13":true,"1:15":true,"0:14":true,"6:12":true,"13:4":true,"3:14":true,"6:15":true} \ No newline at end of file
+{
+ "15:4": true,
+ "14:3": 203,
+ "4:14": true,
+ "4:3": true,
+ "12:5": true,
+ "5:14": true,
+ "2:15": true,
+ "7:15": true,
+ "4:9": true,
+ "14:4": true,
+ "4:4": true,
+ "5:12": true,
+ "6:13": true,
+ "4:15": true,
+ "4:2": true,
+ "5:15": true,
+ "5:10": true,
+ "0:15": true,
+ "5:11": true,
+ "3:15": true,
+ "6:14": true,
+ "5:13": true,
+ "1:15": true,
+ "0:14": true,
+ "6:12": true,
+ "13:4": true,
+ "3:14": true,
+ "6:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-4.json
index 2cee3332..29e72fe4 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-4.json
@@ -1 +1,19 @@
-{"5:9":true,"4:9":true,"2:9":true,"4:7":true,"0:10":true,"4:11":true,"10:0":182,"5:11":true,"7:0":true,"5:8":true,"4:8":true,"3:8":true,"6:9":true,"5:10":true,"4:10":true,"3:9":true,"7:1":true} \ No newline at end of file
+{
+ "5:9": true,
+ "4:9": true,
+ "2:9": true,
+ "4:7": true,
+ "0:10": true,
+ "4:11": true,
+ "10:0": 182,
+ "5:11": true,
+ "7:0": true,
+ "5:8": true,
+ "4:8": true,
+ "3:8": true,
+ "6:9": true,
+ "5:10": true,
+ "4:10": true,
+ "3:9": true,
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-5.json
index 09062bf7..0cf9c03f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-5.json
@@ -1 +1,34 @@
-{"11:5":true,"10:4":true,"10:3":[185,186],"10:14":true,"6:6":187,"10:12":true,"3:0":true,"10:15":true,"10:2":[183,185],"5:5":186,"10:6":true,"10:13":true,"4:3":true,"6:5":187,"5:3":181,"9:7":true,"11:4":true,"10:5":[186,187],"11:3":[183,184],"6:7":187} \ No newline at end of file
+{
+ "11:5": true,
+ "10:4": true,
+ "10:3": [
+ 185,
+ 186
+ ],
+ "10:14": true,
+ "6:6": 187,
+ "10:12": true,
+ "3:0": true,
+ "10:15": true,
+ "10:2": [
+ 183,
+ 185
+ ],
+ "5:5": 186,
+ "10:6": true,
+ "10:13": true,
+ "4:3": true,
+ "6:5": 187,
+ "5:3": 181,
+ "9:7": true,
+ "11:4": true,
+ "10:5": [
+ 186,
+ 187
+ ],
+ "11:3": [
+ 183,
+ 184
+ ],
+ "6:7": 187
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-6.json
index eb9d426f..cab1d428 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_-6.json
@@ -1 +1,58 @@
-{"12:11":true,"1:1":[188,189],"7:12":true,"6:13":true,"2:9":true,"0:6":true,"13:10":true,"7:14":true,"1:8":true,"0:2":true,"7:13":true,"2:8":true,"5:11":true,"6:14":true,"1:9":true,"0:3":true,"6:12":true,"0:4":true,"2:1":[187,188],"8:13":true,"10:7":214,"0:5":true,"8:14":188,"1:5":true,"9:4":217,"3:10":true,"4:1":185,"3:12":true,"5:14":true,"2:2":[189,190],"0:8":true,"6:11":true,"5:12":true,"13:11":true,"0:1":true,"3:1":[185,186],"5:15":true,"1:3":true,"4:10":true,"1:4":true,"0:7":true,"5:13":true,"1:2":true,"7:11":true} \ No newline at end of file
+{
+ "12:11": true,
+ "1:1": [
+ 188,
+ 189
+ ],
+ "7:12": true,
+ "6:13": true,
+ "2:9": true,
+ "0:6": true,
+ "13:10": true,
+ "7:14": true,
+ "1:8": true,
+ "0:2": true,
+ "7:13": true,
+ "2:8": true,
+ "5:11": true,
+ "6:14": true,
+ "1:9": true,
+ "0:3": true,
+ "6:12": true,
+ "0:4": true,
+ "2:1": [
+ 187,
+ 188
+ ],
+ "8:13": true,
+ "10:7": 214,
+ "0:5": true,
+ "8:14": 188,
+ "1:5": true,
+ "9:4": 217,
+ "3:10": true,
+ "4:1": 185,
+ "3:12": true,
+ "5:14": true,
+ "2:2": [
+ 189,
+ 190
+ ],
+ "0:8": true,
+ "6:11": true,
+ "5:12": true,
+ "13:11": true,
+ "0:1": true,
+ "3:1": [
+ 185,
+ 186
+ ],
+ "5:15": true,
+ "1:3": true,
+ "4:10": true,
+ "1:4": true,
+ "0:7": true,
+ "5:13": true,
+ "1:2": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_0.json
index 0d735233..1ac48101 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_0.json
@@ -1 +1,55 @@
-{"7:12":true,"3:0":true,"0:0":[198,202],"8:7":146,"11:0":true,"2:12":true,"7:7":[146,147],"12:0":true,"6:1":true,"3:5":[151,153],"15:12":222,"13:1":205,"0:11":true,"5:0":true,"5:6":[149,150],"4:0":true,"1:12":225,"6:0":true,"12:1":true,"1:11":true,"0:13":224,"6:6":149,"13:0":true,"8:11":true,"0:10":true,"10:0":true,"5:1":true,"9:0":true,"7:0":true,"2:11":true,"1:0":true,"8:0":true,"15:0":[198,202],"14:0":[198,202],"2:0":true} \ No newline at end of file
+{
+ "7:12": true,
+ "3:0": true,
+ "0:0": [
+ 198,
+ 202
+ ],
+ "8:7": 146,
+ "11:0": true,
+ "2:12": true,
+ "7:7": [
+ 146,
+ 147
+ ],
+ "12:0": true,
+ "6:1": true,
+ "3:5": [
+ 151,
+ 153
+ ],
+ "15:12": 222,
+ "13:1": 205,
+ "0:11": true,
+ "5:0": true,
+ "5:6": [
+ 149,
+ 150
+ ],
+ "4:0": true,
+ "1:12": 225,
+ "6:0": true,
+ "12:1": true,
+ "1:11": true,
+ "0:13": 224,
+ "6:6": 149,
+ "13:0": true,
+ "8:11": true,
+ "0:10": true,
+ "10:0": true,
+ "5:1": true,
+ "9:0": true,
+ "7:0": true,
+ "2:11": true,
+ "1:0": true,
+ "8:0": true,
+ "15:0": [
+ 198,
+ 202
+ ],
+ "14:0": [
+ 198,
+ 202
+ ],
+ "2:0": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_11.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_11.json
index 051878c9..07a9fcf6 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_11.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_11.json
@@ -1 +1,47 @@
-{"11:0":152,"12:11":true,"9:3":true,"9:14":true,"6:0":152,"1:1":true,"1:11":true,"1:10":true,"9:9":true,"1:0":true,"11:11":true,"9:4":true,"3:0":153,"13:11":true,"9:15":true,"9:2":true,"0:1":true,"0:0":true,"9:7":true,"9:12":true,"3:1":152,"14:11":true,"9:1":true,"9:6":true,"4:1":152,"1:3":true,"0:2":true,"5:0":153,"10:11":true,"9:5":true,"9:10":true,"5:1":true,"15:11":true,"9:0":true,"4:0":153,"2:0":true,"0:3":true,"1:12":true,"0:4":true,"9:8":true,"9:13":true,"2:1":[150,152]} \ No newline at end of file
+{
+ "11:0": 152,
+ "12:11": true,
+ "9:3": true,
+ "9:14": true,
+ "6:0": 152,
+ "1:1": true,
+ "1:11": true,
+ "1:10": true,
+ "9:9": true,
+ "1:0": true,
+ "11:11": true,
+ "9:4": true,
+ "3:0": 153,
+ "13:11": true,
+ "9:15": true,
+ "9:2": true,
+ "0:1": true,
+ "0:0": true,
+ "9:7": true,
+ "9:12": true,
+ "3:1": 152,
+ "14:11": true,
+ "9:1": true,
+ "9:6": true,
+ "4:1": 152,
+ "1:3": true,
+ "0:2": true,
+ "5:0": 153,
+ "10:11": true,
+ "9:5": true,
+ "9:10": true,
+ "5:1": true,
+ "15:11": true,
+ "9:0": true,
+ "4:0": 153,
+ "2:0": true,
+ "0:3": true,
+ "1:12": true,
+ "0:4": true,
+ "9:8": true,
+ "9:13": true,
+ "2:1": [
+ 150,
+ 152
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_3.json
index dfd5cdf8..8cde17ab 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_3.json
@@ -1 +1,22 @@
-{"7:12":true,"7:2":true,"7:15":true,"7:4":true,"7:3":true,"7:14":true,"14:1":true,"7:13":true,"2:5":true,"6:12":true,"4:14":true,"6:1":true,"5:12":true,"3:5":true,"14:2":true,"4:15":true,"4:12":true,"8:2":true,"7:1":true,"4:13":true} \ No newline at end of file
+{
+ "7:12": true,
+ "7:2": true,
+ "7:15": true,
+ "7:4": true,
+ "7:3": true,
+ "7:14": true,
+ "14:1": true,
+ "7:13": true,
+ "2:5": true,
+ "6:12": true,
+ "4:14": true,
+ "6:1": true,
+ "5:12": true,
+ "3:5": true,
+ "14:2": true,
+ "4:15": true,
+ "4:12": true,
+ "8:2": true,
+ "7:1": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_4.json
index f6207f88..e99a3f13 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_4.json
@@ -1 +1,52 @@
-{"6:0":true,"0:6":true,"4:1":true,"0:2":true,"5:1":true,"7:0":true,"0:3":true,"7:10":[167,168],"6:12":172,"0:4":true,"6:15":[173,174],"0:8":true,"9:9":[166,167],"6:11":[166,170],"6:1":true,"10:7":167,"8:10":[164,167],"5:15":[174,176],"0:5":true,"5:0":true,"0:7":true,"4:0":true,"10:8":[166,167],"0:9":true,"7:11":[165,166],"7:1":true} \ No newline at end of file
+{
+ "6:0": true,
+ "0:6": true,
+ "4:1": true,
+ "0:2": true,
+ "5:1": true,
+ "7:0": true,
+ "0:3": true,
+ "7:10": [
+ 167,
+ 168
+ ],
+ "6:12": 172,
+ "0:4": true,
+ "6:15": [
+ 173,
+ 174
+ ],
+ "0:8": true,
+ "9:9": [
+ 166,
+ 167
+ ],
+ "6:11": [
+ 166,
+ 170
+ ],
+ "6:1": true,
+ "10:7": 167,
+ "8:10": [
+ 164,
+ 167
+ ],
+ "5:15": [
+ 174,
+ 176
+ ],
+ "0:5": true,
+ "5:0": true,
+ "0:7": true,
+ "4:0": true,
+ "10:8": [
+ 166,
+ 167
+ ],
+ "0:9": true,
+ "7:11": [
+ 165,
+ 166
+ ],
+ "7:1": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_5.json
index ded0da87..2703053d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_5.json
@@ -1 +1,19 @@
-{"5:11":true,"4:10":true,"7:15":[138,171],"8:15":[140,171],"6:14":true,"5:12":true,"6:13":true,"5:13":true,"6:12":true,"6:15":true,"7:14":171} \ No newline at end of file
+{
+ "5:11": true,
+ "4:10": true,
+ "7:15": [
+ 138,
+ 171
+ ],
+ "8:15": [
+ 140,
+ 171
+ ],
+ "6:14": true,
+ "5:12": true,
+ "6:13": true,
+ "5:13": true,
+ "6:12": true,
+ "6:15": true,
+ "7:14": 171
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_6.json
index e283ddec..02d5d9bb 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_6.json
@@ -1 +1,79 @@
-{"8:8":true,"7:12":true,"10:14":true,"7:15":true,"10:12":true,"9:15":true,"0:6":true,"9:12":true,"8:1":181,"13:10":[171,172],"10:15":true,"7:14":true,"4:11":true,"7:13":true,"5:11":true,"0:3":true,"8:9":true,"0:4":true,"6:15":true,"8:13":true,"15:14":170,"9:9":true,"15:12":172,"14:12":171,"9:7":true,"0:5":true,"8:12":true,"7:8":true,"15:13":171,"9:8":true,"7:2":183,"8:5":true,"8:11":true,"0:10":true,"7:3":true,"14:11":[170,171],"9:6":[189,190],"12:9":[170,171],"7:0":170,"7:6":true,"4:14":true,"0:8":true,"6:11":true,"4:15":true,"8:6":true,"4:12":true,"5:15":true,"10:11":196,"9:5":[187,188],"8:2":169,"0:7":true,"12:15":194,"8:4":186,"7:5":true,"11:15":true,"8:3":[183,185],"0:9":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "8:8": true,
+ "7:12": true,
+ "10:14": true,
+ "7:15": true,
+ "10:12": true,
+ "9:15": true,
+ "0:6": true,
+ "9:12": true,
+ "8:1": 181,
+ "13:10": [
+ 171,
+ 172
+ ],
+ "10:15": true,
+ "7:14": true,
+ "4:11": true,
+ "7:13": true,
+ "5:11": true,
+ "0:3": true,
+ "8:9": true,
+ "0:4": true,
+ "6:15": true,
+ "8:13": true,
+ "15:14": 170,
+ "9:9": true,
+ "15:12": 172,
+ "14:12": 171,
+ "9:7": true,
+ "0:5": true,
+ "8:12": true,
+ "7:8": true,
+ "15:13": 171,
+ "9:8": true,
+ "7:2": 183,
+ "8:5": true,
+ "8:11": true,
+ "0:10": true,
+ "7:3": true,
+ "14:11": [
+ 170,
+ 171
+ ],
+ "9:6": [
+ 189,
+ 190
+ ],
+ "12:9": [
+ 170,
+ 171
+ ],
+ "7:0": 170,
+ "7:6": true,
+ "4:14": true,
+ "0:8": true,
+ "6:11": true,
+ "4:15": true,
+ "8:6": true,
+ "4:12": true,
+ "5:15": true,
+ "10:11": 196,
+ "9:5": [
+ 187,
+ 188
+ ],
+ "8:2": 169,
+ "0:7": true,
+ "12:15": 194,
+ "8:4": 186,
+ "7:5": true,
+ "11:15": true,
+ "8:3": [
+ 183,
+ 185
+ ],
+ "0:9": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/3_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/3_7.json
index 208d6c92..beb2731e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/3_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/3_7.json
@@ -1 +1,16 @@
-{"6:0":true,"7:15":true,"12:0":true,"12:13":true,"10:15":true,"12:14":true,"10:0":true,"5:0":true,"10:1":true,"11:14":true,"4:0":true,"7:0":true,"11:2":true,"6:15":true} \ No newline at end of file
+{
+ "6:0": true,
+ "7:15": true,
+ "12:0": true,
+ "12:13": true,
+ "10:15": true,
+ "12:14": true,
+ "10:0": true,
+ "5:0": true,
+ "10:1": true,
+ "11:14": true,
+ "4:0": true,
+ "7:0": true,
+ "11:2": true,
+ "6:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-1.json
index 24c0a054..57fcf162 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-1.json
@@ -1 +1,49 @@
-{"1:1":true,"11:11":true,"3:0":true,"4:11":205,"0:2":true,"9:10":225,"3:2":true,"2:1":true,"2:15":true,"8:10":225,"0:11":true,"3:11":205,"2:14":true,"1:13":[164,166],"4:6":true,"1:14":165,"5:0":true,"5:6":true,"4:0":true,"1:12":[198,201],"5:7":true,"8:11":225,"4:7":true,"0:10":true,"4:1":true,"3:15":true,"0:12":[165,202],"5:8":true,"3:14":true,"4:8":true,"2:2":true,"0:1":true,"3:1":true,"9:11":224,"10:11":true,"2:0":true,"1:2":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "11:11": true,
+ "3:0": true,
+ "4:11": 205,
+ "0:2": true,
+ "9:10": 225,
+ "3:2": true,
+ "2:1": true,
+ "2:15": true,
+ "8:10": 225,
+ "0:11": true,
+ "3:11": 205,
+ "2:14": true,
+ "1:13": [
+ 164,
+ 166
+ ],
+ "4:6": true,
+ "1:14": 165,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "1:12": [
+ 198,
+ 201
+ ],
+ "5:7": true,
+ "8:11": 225,
+ "4:7": true,
+ "0:10": true,
+ "4:1": true,
+ "3:15": true,
+ "0:12": [
+ 165,
+ 202
+ ],
+ "5:8": true,
+ "3:14": true,
+ "4:8": true,
+ "2:2": true,
+ "0:1": true,
+ "3:1": true,
+ "9:11": 224,
+ "10:11": true,
+ "2:0": true,
+ "1:2": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-2.json
index eb8125af..520d0e1f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-2.json
@@ -1 +1,8 @@
-{"15:7":true,"14:7":true,"3:15":true,"0:4":212,"2:15":true,"12:12":true} \ No newline at end of file
+{
+ "15:7": true,
+ "14:7": true,
+ "3:15": true,
+ "0:4": 212,
+ "2:15": true,
+ "12:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-8.json
index e604dcb9..76bfe654 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-8.json
@@ -1 +1,69 @@
-{"15:9":true,"12:11":true,"13:13":true,"10:14":true,"14:9":true,"11:11":true,"10:12":true,"3:0":226,"14:7":true,"9:12":true,"13:10":true,"13:15":true,"10:10":true,"13:12":true,"15:1":210,"15:8":true,"13:14":true,"10:13":true,"14:8":true,"9:13":true,"14:14":true,"12:6":true,"13:8":true,"15:14":true,"15:12":true,"14:15":true,"15:15":true,"14:12":true,"15:10":true,"14:10":true,"13:7":true,"15:13":true,"13:9":true,"14:13":true,"11:8":true,"13:6":true,"12:8":true,"14:11":true,"11:9":true,"15:5":true,"10:0":221,"14:5":true,"15:11":true,"12:9":true,"13:4":true,"12:7":true,"15:4":true,"14:3":true,"11:10":true,"12:10":true,"15:3":true,"14:4":true,"11:13":true,"14:2":210,"13:11":true,"15:2":211,"13:5":true,"12:13":true,"14:6":true,"12:14":true,"10:11":true,"11:14":true,"15:6":true,"12:15":true,"11:12":true,"12:12":true,"11:15":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "13:13": true,
+ "10:14": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "3:0": 226,
+ "14:7": true,
+ "9:12": true,
+ "13:10": true,
+ "13:15": true,
+ "10:10": true,
+ "13:12": true,
+ "15:1": 210,
+ "15:8": true,
+ "13:14": true,
+ "10:13": true,
+ "14:8": true,
+ "9:13": true,
+ "14:14": true,
+ "12:6": true,
+ "13:8": true,
+ "15:14": true,
+ "15:12": true,
+ "14:15": true,
+ "15:15": true,
+ "14:12": true,
+ "15:10": true,
+ "14:10": true,
+ "13:7": true,
+ "15:13": true,
+ "13:9": true,
+ "14:13": true,
+ "11:8": true,
+ "13:6": true,
+ "12:8": true,
+ "14:11": true,
+ "11:9": true,
+ "15:5": true,
+ "10:0": 221,
+ "14:5": true,
+ "15:11": true,
+ "12:9": true,
+ "13:4": true,
+ "12:7": true,
+ "15:4": true,
+ "14:3": true,
+ "11:10": true,
+ "12:10": true,
+ "15:3": true,
+ "14:4": true,
+ "11:13": true,
+ "14:2": 210,
+ "13:11": true,
+ "15:2": 211,
+ "13:5": true,
+ "12:13": true,
+ "14:6": true,
+ "12:14": true,
+ "10:11": true,
+ "11:14": true,
+ "15:6": true,
+ "12:15": true,
+ "11:12": true,
+ "12:12": true,
+ "11:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-9.json
index a4276076..ded6312e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/4_-9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/4_-9.json
@@ -1 +1,4 @@
-{"0:12":true,"1:12":true} \ No newline at end of file
+{
+ "0:12": true,
+ "1:12": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/4_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/4_0.json
index f9d3a234..2e59477c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/4_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/4_0.json
@@ -1 +1,129 @@
-{"6:10":[212,214],"13:13":true,"7:15":true,"15:7":true,"3:0":[161,202],"0:0":[198,202],"8:1":true,"7:14":true,"5:5":true,"7:13":true,"13:12":true,"7:10":true,"6:15":true,"11:0":[158,204],"4:3":165,"5:4":true,"12:0":[159,199],"4:2":[164,165],"0:11":202,"15:15":true,"9:1":169,"5:0":[198,202],"10:1":168,"12:4":true,"8:15":true,"4:0":[198,202],"12:2":166,"2:10":203,"11:2":167,"8:14":true,"9:3":169,"6:0":[198,202],"1:11":203,"10:3":168,"7:2":true,"11:1":167,"7:4":true,"9:2":169,"13:0":[160,198],"10:2":168,"7:3":true,"13:2":159,"4:1":205,"6:4":true,"15:5":[159,160],"10:0":[198,204],"14:5":159,"9:0":[198,202],"6:3":true,"7:0":[198,202],"13:3":true,"13:4":true,"6:2":true,"2:11":204,"15:4":[159,161],"14:3":true,"6:5":true,"15:3":[158,160],"1:0":true,"14:4":true,"8:0":[198,202],"14:2":160,"15:2":true,"3:1":[162,205],"13:5":true,"14:6":158,"8:2":true,"15:6":true,"2:0":true,"12:15":true,"7:5":168,"3:9":true,"8:3":true} \ No newline at end of file
+{
+ "6:10": [
+ 212,
+ 214
+ ],
+ "13:13": true,
+ "7:15": true,
+ "15:7": true,
+ "3:0": [
+ 161,
+ 202
+ ],
+ "0:0": [
+ 198,
+ 202
+ ],
+ "8:1": true,
+ "7:14": true,
+ "5:5": true,
+ "7:13": true,
+ "13:12": true,
+ "7:10": true,
+ "6:15": true,
+ "11:0": [
+ 158,
+ 204
+ ],
+ "4:3": 165,
+ "5:4": true,
+ "12:0": [
+ 159,
+ 199
+ ],
+ "4:2": [
+ 164,
+ 165
+ ],
+ "0:11": 202,
+ "15:15": true,
+ "9:1": 169,
+ "5:0": [
+ 198,
+ 202
+ ],
+ "10:1": 168,
+ "12:4": true,
+ "8:15": true,
+ "4:0": [
+ 198,
+ 202
+ ],
+ "12:2": 166,
+ "2:10": 203,
+ "11:2": 167,
+ "8:14": true,
+ "9:3": 169,
+ "6:0": [
+ 198,
+ 202
+ ],
+ "1:11": 203,
+ "10:3": 168,
+ "7:2": true,
+ "11:1": 167,
+ "7:4": true,
+ "9:2": 169,
+ "13:0": [
+ 160,
+ 198
+ ],
+ "10:2": 168,
+ "7:3": true,
+ "13:2": 159,
+ "4:1": 205,
+ "6:4": true,
+ "15:5": [
+ 159,
+ 160
+ ],
+ "10:0": [
+ 198,
+ 204
+ ],
+ "14:5": 159,
+ "9:0": [
+ 198,
+ 202
+ ],
+ "6:3": true,
+ "7:0": [
+ 198,
+ 202
+ ],
+ "13:3": true,
+ "13:4": true,
+ "6:2": true,
+ "2:11": 204,
+ "15:4": [
+ 159,
+ 161
+ ],
+ "14:3": true,
+ "6:5": true,
+ "15:3": [
+ 158,
+ 160
+ ],
+ "1:0": true,
+ "14:4": true,
+ "8:0": [
+ 198,
+ 202
+ ],
+ "14:2": 160,
+ "15:2": true,
+ "3:1": [
+ 162,
+ 205
+ ],
+ "13:5": true,
+ "14:6": 158,
+ "8:2": true,
+ "15:6": true,
+ "2:0": true,
+ "12:15": true,
+ "7:5": 168,
+ "3:9": true,
+ "8:3": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/4_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/4_6.json
index 5dd48953..b283ecd9 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/4_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/4_6.json
@@ -1 +1,61 @@
-{"9:14":true,"8:8":true,"7:12":true,"10:14":true,"7:15":true,"11:11":true,"10:12":true,"6:13":true,"15:7":true,"9:15":true,"9:12":true,"10:15":true,"7:14":true,"13:15":true,"10:10":true,"7:13":true,"9:10":true,"15:1":true,"6:14":true,"10:13":true,"8:9":true,"7:10":true,"6:15":true,"9:13":true,"8:13":true,"10:9":true,"2:15":175,"9:9":true,"8:10":true,"7:9":true,"9:7":true,"8:12":true,"8:15":true,"2:10":150,"1:15":190,"10:8":true,"8:14":true,"8:5":true,"11:8":true,"8:11":true,"12:8":true,"9:6":true,"3:12":158,"11:9":true,"15:5":true,"15:4":true,"11:10":true,"15:3":true,"11:13":true,"15:2":true,"8:6":true,"15:0":true,"9:11":true,"10:11":true,"11:14":true,"15:6":true,"12:15":true,"11:12":true,"11:15":true} \ No newline at end of file
+{
+ "9:14": true,
+ "8:8": true,
+ "7:12": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "15:7": true,
+ "9:15": true,
+ "9:12": true,
+ "10:15": true,
+ "7:14": true,
+ "13:15": true,
+ "10:10": true,
+ "7:13": true,
+ "9:10": true,
+ "15:1": true,
+ "6:14": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": true,
+ "6:15": true,
+ "9:13": true,
+ "8:13": true,
+ "10:9": true,
+ "2:15": 175,
+ "9:9": true,
+ "8:10": true,
+ "7:9": true,
+ "9:7": true,
+ "8:12": true,
+ "8:15": true,
+ "2:10": 150,
+ "1:15": 190,
+ "10:8": true,
+ "8:14": true,
+ "8:5": true,
+ "11:8": true,
+ "8:11": true,
+ "12:8": true,
+ "9:6": true,
+ "3:12": 158,
+ "11:9": true,
+ "15:5": true,
+ "15:4": true,
+ "11:10": true,
+ "15:3": true,
+ "11:13": true,
+ "15:2": true,
+ "8:6": true,
+ "15:0": true,
+ "9:11": true,
+ "10:11": true,
+ "11:14": true,
+ "15:6": true,
+ "12:15": true,
+ "11:12": true,
+ "11:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_-5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_-5.json
index 07d74c09..5abb4b54 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_-5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_-5.json
@@ -1 +1,7 @@
-{"9:12":210,"8:15":[205,206]} \ No newline at end of file
+{
+ "9:12": 210,
+ "8:15": [
+ 205,
+ 206
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_-6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_-6.json
index 9d96fa2f..81d36f69 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_-6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_-6.json
@@ -1 +1,8 @@
-{"15:4":217,"15:5":216,"15:3":218,"15:6":true,"15:8":true,"15:7":true} \ No newline at end of file
+{
+ "15:4": 217,
+ "15:5": 216,
+ "15:3": 218,
+ "15:6": true,
+ "15:8": true,
+ "15:7": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_-8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_-8.json
index 7854cd61..b18293dd 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_-8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_-8.json
@@ -1 +1,102 @@
-{"1:1":true,"7:12":true,"6:10":true,"7:15":true,"2:9":true,"0:6":true,"3:6":true,"7:14":true,"1:8":true,"5:5":true,"4:11":true,"0:2":212,"7:13":true,"2:8":true,"5:11":true,"4:5":true,"3:2":212,"6:14":true,"1:9":true,"3:4":true,"0:3":true,"7:10":true,"6:12":true,"3:3":212,"0:4":true,"6:15":true,"4:3":212,"8:13":212,"5:4":212,"2:12":true,"5:3":212,"2:15":true,"1:10":true,"4:4":true,"7:9":true,"6:8":true,"3:5":true,"0:11":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"8:12":222,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"1:14":true,"5:6":true,"8:15":true,"2:10":true,"1:15":true,"8:14":true,"1:12":true,"1:11":true,"3:13":true,"5:9":true,"1:5":true,"0:13":true,"6:6":true,"4:9":true,"3:10":true,"0:10":true,"3:12":true,"0:15":true,"6:4":212,"3:15":true,"0:12":true,"2:5":true,"0:14":true,"5:8":true,"3:14":true,"4:8":true,"2:11":true,"4:14":true,"1:6":true,"6:5":true,"3:8":true,"5:14":true,"2:2":212,"0:8":true,"6:11":true,"5:12":true,"2:4":true,"4:15":true,"0:1":211,"4:12":true,"5:15":true,"2:3":true,"5:10":true,"1:3":true,"4:10":true,"1:4":true,"5:13":true,"1:2":212,"3:9":true,"0:9":true,"7:11":true,"4:13":true,"2:6":true} \ No newline at end of file
+{
+ "1:1": true,
+ "7:12": true,
+ "6:10": true,
+ "7:15": true,
+ "2:9": true,
+ "0:6": true,
+ "3:6": true,
+ "7:14": true,
+ "1:8": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": 212,
+ "7:13": true,
+ "2:8": true,
+ "5:11": true,
+ "4:5": true,
+ "3:2": 212,
+ "6:14": true,
+ "1:9": true,
+ "3:4": true,
+ "0:3": true,
+ "7:10": true,
+ "6:12": true,
+ "3:3": 212,
+ "0:4": true,
+ "6:15": true,
+ "4:3": 212,
+ "8:13": 212,
+ "5:4": 212,
+ "2:12": true,
+ "5:3": 212,
+ "2:15": true,
+ "1:10": true,
+ "4:4": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "0:11": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "8:12": 222,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "1:14": true,
+ "5:6": true,
+ "8:15": true,
+ "2:10": true,
+ "1:15": true,
+ "8:14": true,
+ "1:12": true,
+ "1:11": true,
+ "3:13": true,
+ "5:9": true,
+ "1:5": true,
+ "0:13": true,
+ "6:6": true,
+ "4:9": true,
+ "3:10": true,
+ "0:10": true,
+ "3:12": true,
+ "0:15": true,
+ "6:4": 212,
+ "3:15": true,
+ "0:12": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "3:14": true,
+ "4:8": true,
+ "2:11": true,
+ "4:14": true,
+ "1:6": true,
+ "6:5": true,
+ "3:8": true,
+ "5:14": true,
+ "2:2": 212,
+ "0:8": true,
+ "6:11": true,
+ "5:12": true,
+ "2:4": true,
+ "4:15": true,
+ "0:1": 211,
+ "4:12": true,
+ "5:15": true,
+ "2:3": true,
+ "5:10": true,
+ "1:3": true,
+ "4:10": true,
+ "1:4": true,
+ "5:13": true,
+ "1:2": 212,
+ "3:9": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_0.json
index 53a6fea3..cfa532fa 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_0.json
@@ -1 +1,10 @@
-{"1:1":true,"7:3":198,"6:3":[196,197],"13:14":193,"5:3":196} \ No newline at end of file
+{
+ "1:1": true,
+ "7:3": 198,
+ "6:3": [
+ 196,
+ 197
+ ],
+ "13:14": 193,
+ "5:3": 196
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_10.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_10.json
index deaaa360..c87f7fa3 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_10.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_10.json
@@ -1 +1,161 @@
-{"9:14":true,"1:1":[153,171],"11:5":true,"2:7":true,"7:12":true,"6:10":true,"12:5":true,"10:14":true,"10:12":true,"6:13":true,"2:9":true,"3:0":[168,169],"0:6":true,"0:0":true,"9:12":true,"3:6":[171,227],"7:14":true,"14:1":true,"10:10":true,"5:5":true,"0:2":[151,173],"7:13":true,"9:10":true,"4:5":true,"6:14":true,"1:9":true,"10:13":true,"0:3":true,"8:9":true,"7:10":true,"6:12":true,"1:7":true,"9:13":true,"12:6":true,"8:13":true,"2:12":true,"10:9":true,"1:10":true,"12:0":true,"9:9":true,"11:6":true,"8:10":true,"7:9":true,"3:5":true,"13:1":true,"0:11":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"12:3":true,"11:4":true,"8:12":true,"6:9":true,"4:6":[171,227],"2:13":true,"1:14":true,"5:0":[169,170],"5:6":[165,227],"12:4":true,"4:0":[168,170],"12:2":true,"2:10":true,"8:14":true,"1:12":true,"12:1":true,"1:11":true,"10:4":true,"3:13":true,"1:5":true,"0:13":true,"6:6":[164,227],"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"13:6":true,"13:0":true,"8:11":true,"4:7":true,"0:10":true,"7:3":true,"13:2":true,"9:6":true,"3:12":true,"14:5":true,"10:6":true,"0:12":true,"13:3":true,"2:5":[172,201],"0:14":true,"13:4":true,"3:14":true,"7:6":[164,227],"2:11":true,"15:4":true,"1:6":true,"6:5":true,"2:2":true,"6:11":true,"1:0":152,"14:4":true,"14:2":true,"0:1":[152,172],"8:6":true,"13:5":true,"14:6":true,"10:5":true,"3:7":true,"9:11":true,"1:3":true,"10:11":true,"9:5":true,"1:4":true,"14:0":true,"2:0":168,"1:2":172,"7:5":true,"3:9":true,"0:9":true,"7:11":true,"2:6":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:1": [
+ 153,
+ 171
+ ],
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "6:10": true,
+ "12:5": true,
+ "10:14": true,
+ "10:12": true,
+ "6:13": true,
+ "2:9": true,
+ "3:0": [
+ 168,
+ 169
+ ],
+ "0:6": true,
+ "0:0": true,
+ "9:12": true,
+ "3:6": [
+ 171,
+ 227
+ ],
+ "7:14": true,
+ "14:1": true,
+ "10:10": true,
+ "5:5": true,
+ "0:2": [
+ 151,
+ 173
+ ],
+ "7:13": true,
+ "9:10": true,
+ "4:5": true,
+ "6:14": true,
+ "1:9": true,
+ "10:13": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "1:7": true,
+ "9:13": true,
+ "12:6": true,
+ "8:13": true,
+ "2:12": true,
+ "10:9": true,
+ "1:10": true,
+ "12:0": true,
+ "9:9": true,
+ "11:6": true,
+ "8:10": true,
+ "7:9": true,
+ "3:5": true,
+ "13:1": true,
+ "0:11": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "12:3": true,
+ "11:4": true,
+ "8:12": true,
+ "6:9": true,
+ "4:6": [
+ 171,
+ 227
+ ],
+ "2:13": true,
+ "1:14": true,
+ "5:0": [
+ 169,
+ 170
+ ],
+ "5:6": [
+ 165,
+ 227
+ ],
+ "12:4": true,
+ "4:0": [
+ 168,
+ 170
+ ],
+ "12:2": true,
+ "2:10": true,
+ "8:14": true,
+ "1:12": true,
+ "12:1": true,
+ "1:11": true,
+ "10:4": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "6:6": [
+ 164,
+ 227
+ ],
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "13:6": true,
+ "13:0": true,
+ "8:11": true,
+ "4:7": true,
+ "0:10": true,
+ "7:3": true,
+ "13:2": true,
+ "9:6": true,
+ "3:12": true,
+ "14:5": true,
+ "10:6": true,
+ "0:12": true,
+ "13:3": true,
+ "2:5": [
+ 172,
+ 201
+ ],
+ "0:14": true,
+ "13:4": true,
+ "3:14": true,
+ "7:6": [
+ 164,
+ 227
+ ],
+ "2:11": true,
+ "15:4": true,
+ "1:6": true,
+ "6:5": true,
+ "2:2": true,
+ "6:11": true,
+ "1:0": 152,
+ "14:4": true,
+ "14:2": true,
+ "0:1": [
+ 152,
+ 172
+ ],
+ "8:6": true,
+ "13:5": true,
+ "14:6": true,
+ "10:5": true,
+ "3:7": true,
+ "9:11": true,
+ "1:3": true,
+ "10:11": true,
+ "9:5": true,
+ "1:4": true,
+ "14:0": true,
+ "2:0": 168,
+ "1:2": 172,
+ "7:5": true,
+ "3:9": true,
+ "0:9": true,
+ "7:11": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_7.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_7.json
index 85efb804..14670145 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_7.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_7.json
@@ -1 +1,227 @@
-{"12:11":true,"9:14":true,"1:1":true,"11:5":true,"2:7":[122,123],"7:12":true,"6:10":true,"13:13":true,"12:5":true,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"2:9":true,"3:0":true,"9:15":true,"0:6":true,"0:0":true,"14:7":true,"9:12":true,"3:6":true,"13:10":true,"10:15":true,"7:14":true,"1:8":[120,173],"14:1":true,"13:15":true,"10:10":true,"4:11":true,"0:2":true,"7:13":true,"2:8":[119,171],"9:10":true,"5:11":[170,171],"4:5":true,"13:12":true,"15:1":true,"1:9":[174,175],"13:14":true,"10:13":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"1:7":122,"0:4":true,"14:8":true,"9:13":true,"11:0":true,"14:14":true,"12:6":true,"8:13":true,"10:9":true,"5:3":true,"2:15":[175,177],"1:10":true,"13:8":true,"15:14":true,"9:9":true,"11:6":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"0:11":true,"15:15":true,"14:12":true,"2:14":true,"0:5":true,"12:3":true,"11:4":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"2:13":true,"15:10":true,"14:10":true,"10:1":true,"5:6":true,"13:7":true,"12:4":true,"8:15":true,"15:13":true,"12:2":true,"8:14":true,"13:9":true,"7:1":true,"14:13":true,"12:1":true,"1:11":true,"3:13":true,"5:9":126,"1:5":[122,123],"11:1":true,"5:7":true,"11:8":true,"13:6":true,"8:11":true,"4:7":true,"0:10":true,"12:8":true,"14:11":true,"13:2":true,"3:12":true,"11:9":true,"10:0":true,"15:11":true,"12:9":true,"9:0":true,"13:3":true,"11:7":true,"2:5":true,"5:8":true,"13:4":true,"12:7":true,"3:14":176,"6:2":true,"4:8":true,"15:4":true,"14:3":true,"4:14":[172,175],"1:6":[122,123],"11:10":true,"3:8":[118,122],"12:10":true,"5:14":[165,171],"0:8":[174,175],"15:3":true,"6:11":true,"1:0":true,"11:13":true,"5:12":[169,172],"2:4":true,"8:0":true,"14:2":true,"13:11":true,"4:15":[164,174],"0:1":true,"15:2":true,"4:12":true,"13:5":true,"12:13":true,"5:15":true,"15:0":true,"14:6":true,"12:14":true,"9:11":true,"3:7":true,"1:3":true,"4:10":171,"11:14":true,"1:4":true,"0:7":[121,172],"14:0":true,"2:0":true,"12:15":true,"11:12":true,"5:13":[167,173],"3:9":[171,172],"12:12":true,"11:15":true,"0:9":[176,177],"7:11":true,"4:13":174,"2:6":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "1:1": true,
+ "11:5": true,
+ "2:7": [
+ 122,
+ 123
+ ],
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "3:0": true,
+ "9:15": true,
+ "0:6": true,
+ "0:0": true,
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": [
+ 120,
+ 173
+ ],
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "4:11": true,
+ "0:2": true,
+ "7:13": true,
+ "2:8": [
+ 119,
+ 171
+ ],
+ "9:10": true,
+ "5:11": [
+ 170,
+ 171
+ ],
+ "4:5": true,
+ "13:12": true,
+ "15:1": true,
+ "1:9": [
+ 174,
+ 175
+ ],
+ "13:14": true,
+ "10:13": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "1:7": 122,
+ "0:4": true,
+ "14:8": true,
+ "9:13": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": true,
+ "8:13": true,
+ "10:9": true,
+ "5:3": true,
+ "2:15": [
+ 175,
+ 177
+ ],
+ "1:10": true,
+ "13:8": true,
+ "15:14": true,
+ "9:9": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "2:14": true,
+ "0:5": true,
+ "12:3": true,
+ "11:4": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "2:13": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "5:6": true,
+ "13:7": true,
+ "12:4": true,
+ "8:15": true,
+ "15:13": true,
+ "12:2": true,
+ "8:14": true,
+ "13:9": true,
+ "7:1": true,
+ "14:13": true,
+ "12:1": true,
+ "1:11": true,
+ "3:13": true,
+ "5:9": 126,
+ "1:5": [
+ 122,
+ 123
+ ],
+ "11:1": true,
+ "5:7": true,
+ "11:8": true,
+ "13:6": true,
+ "8:11": true,
+ "4:7": true,
+ "0:10": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "3:12": true,
+ "11:9": true,
+ "10:0": true,
+ "15:11": true,
+ "12:9": true,
+ "9:0": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "5:8": true,
+ "13:4": true,
+ "12:7": true,
+ "3:14": 176,
+ "6:2": true,
+ "4:8": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": [
+ 172,
+ 175
+ ],
+ "1:6": [
+ 122,
+ 123
+ ],
+ "11:10": true,
+ "3:8": [
+ 118,
+ 122
+ ],
+ "12:10": true,
+ "5:14": [
+ 165,
+ 171
+ ],
+ "0:8": [
+ 174,
+ 175
+ ],
+ "15:3": true,
+ "6:11": true,
+ "1:0": true,
+ "11:13": true,
+ "5:12": [
+ 169,
+ 172
+ ],
+ "2:4": true,
+ "8:0": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": [
+ 164,
+ 174
+ ],
+ "0:1": true,
+ "15:2": true,
+ "4:12": true,
+ "13:5": true,
+ "12:13": true,
+ "5:15": true,
+ "15:0": true,
+ "14:6": true,
+ "12:14": true,
+ "9:11": true,
+ "3:7": true,
+ "1:3": true,
+ "4:10": 171,
+ "11:14": true,
+ "1:4": true,
+ "0:7": [
+ 121,
+ 172
+ ],
+ "14:0": true,
+ "2:0": true,
+ "12:15": true,
+ "11:12": true,
+ "5:13": [
+ 167,
+ 173
+ ],
+ "3:9": [
+ 171,
+ 172
+ ],
+ "12:12": true,
+ "11:15": true,
+ "0:9": [
+ 176,
+ 177
+ ],
+ "7:11": true,
+ "4:13": 174,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_8.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_8.json
index 0a576965..e6c41903 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_8.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_8.json
@@ -1 +1,157 @@
-{"15:9":true,"12:11":true,"9:14":true,"8:8":true,"7:12":true,"6:10":true,"13:13":true,"12:5":true,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"9:15":true,"14:7":true,"9:12":true,"8:1":true,"13:10":true,"10:15":true,"7:14":true,"14:1":true,"10:10":true,"8:7":true,"7:13":true,"9:10":true,"5:11":true,"13:12":true,"15:1":true,"6:14":true,"15:8":true,"13:14":true,"10:13":true,"8:9":true,"7:10":true,"6:12":true,"6:15":true,"14:8":true,"9:13":true,"2:1":true,"14:14":true,"12:6":true,"10:9":true,"7:7":true,"2:15":true,"13:8":true,"12:0":true,"9:9":true,"11:6":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"13:1":true,"9:7":true,"12:3":true,"11:4":true,"9:1":true,"7:8":true,"6:9":true,"15:10":true,"14:10":true,"10:1":true,"5:6":true,"13:7":true,"11:3":true,"4:0":[162,169],"12:2":true,"10:8":true,"6:7":true,"11:2":true,"13:9":true,"9:8":true,"14:13":true,"12:1":true,"9:3":true,"10:4":true,"5:9":true,"10:3":true,"6:6":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"11:8":true,"13:6":true,"9:2":true,"13:0":true,"8:11":true,"10:2":true,"12:8":true,"14:11":true,"13:2":true,"9:6":true,"4:1":[160,167],"11:9":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"3:15":true,"15:11":true,"12:9":true,"9:0":true,"13:3":true,"11:7":true,"5:8":true,"12:7":true,"7:6":true,"15:4":true,"14:3":true,"11:10":true,"6:5":true,"12:10":true,"15:3":true,"6:11":true,"14:4":true,"11:13":true,"5:12":true,"8:0":true,"4:15":true,"14:2":true,"13:11":true,"15:2":true,"8:6":true,"5:15":true,"13:5":true,"12:13":true,"15:0":true,"14:6":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"10:11":true,"9:5":true,"11:14":true,"8:2":true,"15:6":true,"14:0":true,"2:0":true,"12:15":true,"11:12":true,"5:13":true,"7:5":true,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "14:1": true,
+ "10:10": true,
+ "8:7": true,
+ "7:13": true,
+ "9:10": true,
+ "5:11": true,
+ "13:12": true,
+ "15:1": true,
+ "6:14": true,
+ "15:8": true,
+ "13:14": true,
+ "10:13": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "2:1": true,
+ "14:14": true,
+ "12:6": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": true,
+ "13:8": true,
+ "12:0": true,
+ "9:9": true,
+ "11:6": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "13:1": true,
+ "9:7": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "7:8": true,
+ "6:9": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "5:6": true,
+ "13:7": true,
+ "11:3": true,
+ "4:0": [
+ 162,
+ 169
+ ],
+ "12:2": true,
+ "10:8": true,
+ "6:7": true,
+ "11:2": true,
+ "13:9": true,
+ "9:8": true,
+ "14:13": true,
+ "12:1": true,
+ "9:3": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "11:8": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "8:11": true,
+ "10:2": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": [
+ 160,
+ 167
+ ],
+ "11:9": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "3:15": true,
+ "15:11": true,
+ "12:9": true,
+ "9:0": true,
+ "13:3": true,
+ "11:7": true,
+ "5:8": true,
+ "12:7": true,
+ "7:6": true,
+ "15:4": true,
+ "14:3": true,
+ "11:10": true,
+ "6:5": true,
+ "12:10": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "11:13": true,
+ "5:12": true,
+ "8:0": true,
+ "4:15": true,
+ "14:2": true,
+ "13:11": true,
+ "15:2": true,
+ "8:6": true,
+ "5:15": true,
+ "13:5": true,
+ "12:13": true,
+ "15:0": true,
+ "14:6": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "10:11": true,
+ "9:5": true,
+ "11:14": true,
+ "8:2": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": true,
+ "12:15": true,
+ "11:12": true,
+ "5:13": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/5_9.json b/src/main/resources/assets/notenoughupdates/dwarven_data/5_9.json
index cd6ee4fd..da6f35d7 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/5_9.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/5_9.json
@@ -1 +1,197 @@
-{"12:11":true,"11:5":true,"2:7":true,"8:8":true,"7:12":[156,193],"6:10":true,"13:13":true,"12:5":true,"14:9":true,"10:12":true,"2:9":true,"15:7":true,"0:6":true,"14:7":true,"9:12":true,"3:6":true,"13:10":true,"1:8":true,"14:1":true,"13:15":true,"8:7":true,"5:5":true,"4:11":[154,170],"7:13":[157,193],"2:8":true,"9:10":true,"5:11":[156,158],"4:5":true,"13:12":true,"3:2":true,"15:1":true,"1:9":true,"15:8":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"7:10":[154,161],"3:3":true,"1:7":true,"0:4":true,"14:8":true,"11:0":true,"14:14":true,"12:6":true,"4:3":true,"2:12":true,"10:9":true,"7:7":true,"2:15":155,"1:10":true,"13:8":true,"12:0":true,"11:6":true,"4:4":true,"10:7":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"14:12":true,"9:7":true,"3:11":true,"2:14":[151,153],"1:13":true,"0:5":true,"2:13":true,"12:3":true,"11:4":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"10:1":true,"5:6":true,"13:7":true,"12:4":true,"11:3":true,"12:2":true,"2:10":true,"1:15":true,"10:8":true,"6:7":true,"11:2":true,"8:14":true,"1:12":true,"13:9":true,"9:8":true,"12:1":true,"9:3":true,"1:11":true,"5:9":true,"10:3":true,"1:5":true,"0:13":true,"4:9":true,"11:1":true,"5:7":true,"3:10":true,"11:8":true,"7:4":true,"13:6":true,"8:11":193,"4:7":true,"0:10":true,"12:8":true,"13:2":true,"3:12":true,"0:15":true,"11:9":true,"15:5":true,"10:0":true,"14:5":true,"0:12":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"0:14":true,"5:8":true,"13:4":true,"12:7":true,"3:14":155,"7:6":true,"4:8":true,"2:11":true,"15:4":true,"14:3":true,"1:6":true,"3:8":true,"12:10":true,"0:8":true,"15:3":true,"14:4":true,"11:13":true,"5:12":157,"2:4":true,"14:2":true,"13:11":true,"15:2":true,"4:12":[155,156],"13:5":true,"12:13":true,"2:3":true,"14:6":true,"12:14":true,"3:7":true,"5:10":[155,160],"1:3":true,"4:10":true,"1:4":true,"0:7":true,"15:6":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"3:9":true,"12:12":true,"8:3":true,"0:9":true,"7:11":[155,160],"4:13":157,"2:6":true} \ No newline at end of file
+{
+ "12:11": true,
+ "11:5": true,
+ "2:7": true,
+ "8:8": true,
+ "7:12": [
+ 156,
+ 193
+ ],
+ "6:10": true,
+ "13:13": true,
+ "12:5": true,
+ "14:9": true,
+ "10:12": true,
+ "2:9": true,
+ "15:7": true,
+ "0:6": true,
+ "14:7": true,
+ "9:12": true,
+ "3:6": true,
+ "13:10": true,
+ "1:8": true,
+ "14:1": true,
+ "13:15": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": [
+ 154,
+ 170
+ ],
+ "7:13": [
+ 157,
+ 193
+ ],
+ "2:8": true,
+ "9:10": true,
+ "5:11": [
+ 156,
+ 158
+ ],
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "1:9": true,
+ "15:8": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": [
+ 154,
+ 161
+ ],
+ "3:3": true,
+ "1:7": true,
+ "0:4": true,
+ "14:8": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": true,
+ "4:3": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": 155,
+ "1:10": true,
+ "13:8": true,
+ "12:0": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "2:14": [
+ 151,
+ 153
+ ],
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "12:3": true,
+ "11:4": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "10:1": true,
+ "5:6": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "12:2": true,
+ "2:10": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "11:2": true,
+ "8:14": true,
+ "1:12": true,
+ "13:9": true,
+ "9:8": true,
+ "12:1": true,
+ "9:3": true,
+ "1:11": true,
+ "5:9": true,
+ "10:3": true,
+ "1:5": true,
+ "0:13": true,
+ "4:9": true,
+ "11:1": true,
+ "5:7": true,
+ "3:10": true,
+ "11:8": true,
+ "7:4": true,
+ "13:6": true,
+ "8:11": 193,
+ "4:7": true,
+ "0:10": true,
+ "12:8": true,
+ "13:2": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "0:12": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": true,
+ "5:8": true,
+ "13:4": true,
+ "12:7": true,
+ "3:14": 155,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "1:6": true,
+ "3:8": true,
+ "12:10": true,
+ "0:8": true,
+ "15:3": true,
+ "14:4": true,
+ "11:13": true,
+ "5:12": 157,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "15:2": true,
+ "4:12": [
+ 155,
+ 156
+ ],
+ "13:5": true,
+ "12:13": true,
+ "2:3": true,
+ "14:6": true,
+ "12:14": true,
+ "3:7": true,
+ "5:10": [
+ 155,
+ 160
+ ],
+ "1:3": true,
+ "4:10": true,
+ "1:4": true,
+ "0:7": true,
+ "15:6": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "3:9": true,
+ "12:12": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": [
+ 155,
+ 160
+ ],
+ "4:13": 157,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_-3.json
index ea179d82..9afd8d50 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_-3.json
@@ -1 +1,12 @@
-{"10:14":[203,205],"13:15":true,"14:15":204,"12:14":222,"12:15":true,"5:13":208,"4:13":208} \ No newline at end of file
+{
+ "10:14": [
+ 203,
+ 205
+ ],
+ "13:15": true,
+ "14:15": 204,
+ "12:14": 222,
+ "12:15": true,
+ "5:13": 208,
+ "4:13": 208
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_0.json
index 57d53e17..138ea888 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_0.json
@@ -1 +1,65 @@
-{"9:14":true,"7:12":true,"13:13":true,"10:14":true,"7:15":true,"11:11":true,"10:12":true,"6:13":true,"13:6":true,"9:15":true,"9:12":true,"8:11":true,"13:10":true,"10:15":true,"7:14":true,"13:15":true,"10:10":true,"11:9":true,"7:13":true,"10:6":true,"13:12":true,"6:14":true,"13:14":true,"11:7":true,"10:13":true,"6:12":true,"6:15":true,"9:13":true,"14:14":true,"4:14":[188,224],"8:13":true,"10:9":true,"13:8":true,"15:14":true,"6:11":true,"11:13":true,"10:7":true,"14:15":true,"13:11":true,"4:15":true,"15:15":true,"10:5":[212,213],"9:11":true,"8:12":true,"9:5":true,"13:7":true,"11:14":true,"8:15":true,"11:12":true,"11:15":true,"8:14":true,"13:9":true,"7:11":true,"4:13":[188,223]} \ No newline at end of file
+{
+ "9:14": true,
+ "7:12": true,
+ "13:13": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "13:6": true,
+ "9:15": true,
+ "9:12": true,
+ "8:11": true,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "13:15": true,
+ "10:10": true,
+ "11:9": true,
+ "7:13": true,
+ "10:6": true,
+ "13:12": true,
+ "6:14": true,
+ "13:14": true,
+ "11:7": true,
+ "10:13": true,
+ "6:12": true,
+ "6:15": true,
+ "9:13": true,
+ "14:14": true,
+ "4:14": [
+ 188,
+ 224
+ ],
+ "8:13": true,
+ "10:9": true,
+ "13:8": true,
+ "15:14": true,
+ "6:11": true,
+ "11:13": true,
+ "10:7": true,
+ "14:15": true,
+ "13:11": true,
+ "4:15": true,
+ "15:15": true,
+ "10:5": [
+ 212,
+ 213
+ ],
+ "9:11": true,
+ "8:12": true,
+ "9:5": true,
+ "13:7": true,
+ "11:14": true,
+ "8:15": true,
+ "11:12": true,
+ "11:15": true,
+ "8:14": true,
+ "13:9": true,
+ "7:11": true,
+ "4:13": [
+ 188,
+ 223
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_1.json
index 106e74e5..66594b9d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_1.json
@@ -1 +1,233 @@
-{"12:11":171,"9:14":true,"11:5":true,"8:8":true,"7:12":true,"6:10":true,"13:13":[182,186],"10:14":236,"7:15":true,"11:11":[172,237],"10:12":true,"6:13":true,"9:15":235,"0:6":true,"9:12":true,"8:1":true,"13:10":[170,186],"10:15":235,"7:14":true,"14:1":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":[187,221],"7:13":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"15:1":true,"6:14":true,"13:14":true,"10:13":[172,236],"0:3":[187,222],"8:9":true,"7:10":true,"6:12":true,"0:4":[189,222],"6:15":true,"9:13":true,"11:0":true,"14:14":true,"4:3":true,"8:13":true,"10:9":true,"7:7":true,"13:8":[182,186],"15:14":true,"9:9":true,"6:1":true,"11:6":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"0:5":[192,226],"11:4":true,"9:1":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"11:3":true,"8:15":true,"4:0":true,"15:13":true,"10:8":true,"6:7":true,"11:2":true,"8:14":true,"13:9":[182,186],"9:8":true,"7:1":true,"14:13":true,"9:3":true,"6:0":true,"1:11":true,"10:4":true,"10:3":true,"1:5":true,"0:13":true,"7:2":true,"6:6":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"11:8":true,"7:4":true,"13:6":true,"9:2":true,"13:0":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"12:8":true,"7:3":true,"14:11":true,"13:2":true,"9:6":true,"4:1":true,"0:15":[187,221],"11:9":true,"6:4":true,"15:5":true,"10:0":true,"14:5":true,"10:6":true,"0:12":true,"15:11":true,"12:9":true,"9:0":true,"6:3":true,"7:0":true,"13:3":true,"11:7":true,"2:5":true,"0:14":[187,221],"13:4":true,"6:2":true,"7:6":true,"4:8":true,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"11:10":true,"6:5":true,"12:10":[171,172],"0:8":true,"15:3":true,"6:11":true,"14:4":true,"11:13":true,"8:0":true,"14:2":true,"13:11":true,"4:15":true,"0:1":[187,221],"15:2":true,"8:6":true,"4:12":true,"13:5":true,"12:13":true,"15:0":true,"14:6":true,"12:14":true,"10:5":true,"9:11":true,"10:11":true,"9:5":true,"4:10":true,"11:14":[236,251],"8:2":true,"0:7":true,"15:6":true,"14:0":true,"12:15":true,"11:12":[171,251],"8:4":true,"7:5":true,"12:12":true,"11:15":true,"8:3":true,"0:9":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "12:11": 171,
+ "9:14": true,
+ "11:5": true,
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": [
+ 182,
+ 186
+ ],
+ "10:14": 236,
+ "7:15": true,
+ "11:11": [
+ 172,
+ 237
+ ],
+ "10:12": true,
+ "6:13": true,
+ "9:15": 235,
+ "0:6": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": [
+ 170,
+ 186
+ ],
+ "10:15": 235,
+ "7:14": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": [
+ 187,
+ 221
+ ],
+ "7:13": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "15:1": true,
+ "6:14": true,
+ "13:14": true,
+ "10:13": [
+ 172,
+ 236
+ ],
+ "0:3": [
+ 187,
+ 222
+ ],
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "0:4": [
+ 189,
+ 222
+ ],
+ "6:15": true,
+ "9:13": true,
+ "11:0": true,
+ "14:14": true,
+ "4:3": true,
+ "8:13": true,
+ "10:9": true,
+ "7:7": true,
+ "13:8": [
+ 182,
+ 186
+ ],
+ "15:14": true,
+ "9:9": true,
+ "6:1": true,
+ "11:6": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "0:5": [
+ 192,
+ 226
+ ],
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "11:3": true,
+ "8:15": true,
+ "4:0": true,
+ "15:13": true,
+ "10:8": true,
+ "6:7": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": [
+ 182,
+ 186
+ ],
+ "9:8": true,
+ "7:1": true,
+ "14:13": true,
+ "9:3": true,
+ "6:0": true,
+ "1:11": true,
+ "10:4": true,
+ "10:3": true,
+ "1:5": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "11:8": true,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "12:8": true,
+ "7:3": true,
+ "14:11": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": true,
+ "0:15": [
+ 187,
+ 221
+ ],
+ "11:9": true,
+ "6:4": true,
+ "15:5": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "0:14": [
+ 187,
+ 221
+ ],
+ "13:4": true,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "11:10": true,
+ "6:5": true,
+ "12:10": [
+ 171,
+ 172
+ ],
+ "0:8": true,
+ "15:3": true,
+ "6:11": true,
+ "14:4": true,
+ "11:13": true,
+ "8:0": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "0:1": [
+ 187,
+ 221
+ ],
+ "15:2": true,
+ "8:6": true,
+ "4:12": true,
+ "13:5": true,
+ "12:13": true,
+ "15:0": true,
+ "14:6": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": [
+ 236,
+ 251
+ ],
+ "8:2": true,
+ "0:7": true,
+ "15:6": true,
+ "14:0": true,
+ "12:15": true,
+ "11:12": [
+ 171,
+ 251
+ ],
+ "8:4": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_2.json
index 0c4de502..17a53bab 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_2.json
@@ -1 +1,184 @@
-{"12:11":true,"9:14":[168,232],"11:5":true,"7:12":true,"13:13":true,"12:5":true,"10:14":[168,232],"7:15":233,"11:11":true,"10:12":true,"6:13":true,"9:15":233,"0:0":[149,155],"9:12":true,"8:1":233,"13:10":true,"10:15":[168,233],"7:14":232,"14:1":true,"13:15":true,"10:10":true,"7:13":true,"9:10":true,"13:12":true,"15:1":true,"6:14":true,"13:14":true,"10:13":[165,231],"8:9":true,"7:10":true,"6:12":true,"6:15":true,"9:13":[169,231],"11:0":[234,252],"14:14":true,"12:6":true,"4:3":true,"8:13":[169,231],"5:4":true,"10:9":true,"13:8":true,"15:14":254,"12:0":true,"9:9":true,"6:1":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"14:15":true,"13:1":true,"4:2":true,"15:15":true,"12:3":true,"11:4":true,"9:1":233,"8:12":true,"6:9":true,"10:1":[159,233],"13:7":true,"12:4":true,"11:3":true,"8:15":true,"4:0":true,"12:2":true,"10:8":true,"11:2":true,"8:14":232,"13:9":true,"9:8":true,"7:1":true,"12:1":true,"9:3":231,"6:0":true,"10:4":true,"10:3":true,"7:2":true,"11:1":true,"9:4":true,"8:5":[189,190],"7:4":true,"13:6":true,"9:2":232,"13:0":true,"8:11":true,"10:2":232,"12:8":true,"7:3":231,"13:2":true,"9:6":true,"4:1":true,"11:9":true,"6:4":true,"10:0":[234,240],"10:6":true,"12:9":true,"9:0":[234,240],"6:3":true,"7:0":true,"13:3":true,"11:7":true,"13:4":true,"12:7":true,"6:2":true,"14:3":true,"4:14":[188,224],"6:5":true,"12:10":true,"6:11":true,"14:4":true,"11:13":true,"8:0":true,"14:2":true,"13:11":true,"4:15":true,"15:2":true,"13:5":true,"15:0":true,"10:5":true,"9:11":true,"5:10":true,"10:11":true,"9:5":189,"11:14":true,"8:2":[158,232],"1:4":true,"14:0":true,"11:12":true,"8:4":[228,230],"7:5":true,"11:15":true,"8:3":231,"7:11":true,"4:13":[188,223]} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": [
+ 168,
+ 232
+ ],
+ "11:5": true,
+ "7:12": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": [
+ 168,
+ 232
+ ],
+ "7:15": 233,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "9:15": 233,
+ "0:0": [
+ 149,
+ 155
+ ],
+ "9:12": true,
+ "8:1": 233,
+ "13:10": true,
+ "10:15": [
+ 168,
+ 233
+ ],
+ "7:14": 232,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "7:13": true,
+ "9:10": true,
+ "13:12": true,
+ "15:1": true,
+ "6:14": true,
+ "13:14": true,
+ "10:13": [
+ 165,
+ 231
+ ],
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "6:15": true,
+ "9:13": [
+ 169,
+ 231
+ ],
+ "11:0": [
+ 234,
+ 252
+ ],
+ "14:14": true,
+ "12:6": true,
+ "4:3": true,
+ "8:13": [
+ 169,
+ 231
+ ],
+ "5:4": true,
+ "10:9": true,
+ "13:8": true,
+ "15:14": 254,
+ "12:0": true,
+ "9:9": true,
+ "6:1": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "15:15": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": 233,
+ "8:12": true,
+ "6:9": true,
+ "10:1": [
+ 159,
+ 233
+ ],
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "4:0": true,
+ "12:2": true,
+ "10:8": true,
+ "11:2": true,
+ "8:14": 232,
+ "13:9": true,
+ "9:8": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": 231,
+ "6:0": true,
+ "10:4": true,
+ "10:3": true,
+ "7:2": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": [
+ 189,
+ 190
+ ],
+ "7:4": true,
+ "13:6": true,
+ "9:2": 232,
+ "13:0": true,
+ "8:11": true,
+ "10:2": 232,
+ "12:8": true,
+ "7:3": 231,
+ "13:2": true,
+ "9:6": true,
+ "4:1": true,
+ "11:9": true,
+ "6:4": true,
+ "10:0": [
+ 234,
+ 240
+ ],
+ "10:6": true,
+ "12:9": true,
+ "9:0": [
+ 234,
+ 240
+ ],
+ "6:3": true,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "13:4": true,
+ "12:7": true,
+ "6:2": true,
+ "14:3": true,
+ "4:14": [
+ 188,
+ 224
+ ],
+ "6:5": true,
+ "12:10": true,
+ "6:11": true,
+ "14:4": true,
+ "11:13": true,
+ "8:0": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "15:2": true,
+ "13:5": true,
+ "15:0": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "10:11": true,
+ "9:5": 189,
+ "11:14": true,
+ "8:2": [
+ 158,
+ 232
+ ],
+ "1:4": true,
+ "14:0": true,
+ "11:12": true,
+ "8:4": [
+ 228,
+ 230
+ ],
+ "7:5": true,
+ "11:15": true,
+ "8:3": 231,
+ "7:11": true,
+ "4:13": [
+ 188,
+ 223
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_3.json
index bb5f8edd..c20fc48e 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_3.json
@@ -1 +1,236 @@
-{"15:9":[160,162],"9:14":true,"11:5":[165,237],"8:8":true,"7:12":true,"6:10":true,"13:13":true,"12:5":[164,165],"10:14":true,"7:15":true,"14:9":[161,164],"11:11":true,"10:12":true,"6:13":true,"9:15":true,"0:6":true,"9:12":true,"8:1":[188,235],"13:10":true,"10:15":true,"7:14":true,"14:1":true,"13:15":true,"10:10":true,"8:7":true,"4:11":true,"0:2":true,"7:13":true,"9:10":true,"4:5":true,"13:12":true,"15:1":254,"6:14":true,"13:14":true,"10:13":true,"0:3":true,"8:9":true,"7:10":true,"6:12":true,"0:4":true,"6:15":true,"14:8":[162,163],"9:13":true,"11:0":true,"14:14":true,"12:6":[163,164],"4:3":true,"8:13":true,"10:9":true,"7:7":true,"13:8":[162,186],"15:14":true,"12:0":true,"9:9":true,"6:1":true,"11:6":[164,237],"4:4":true,"10:7":236,"8:10":true,"7:9":true,"6:8":true,"15:12":true,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"0:5":true,"12:3":true,"11:4":[165,251],"9:1":true,"8:12":true,"7:8":true,"6:9":true,"4:6":true,"15:10":[163,254],"14:10":true,"10:1":235,"13:7":[163,186],"12:4":165,"11:3":[165,252],"8:15":true,"4:0":true,"15:13":true,"12:2":true,"10:8":true,"6:7":true,"11:2":true,"8:14":true,"13:9":true,"9:8":true,"7:1":true,"14:13":true,"12:1":true,"9:3":236,"6:0":true,"10:4":[188,236],"10:3":[188,236],"0:13":true,"7:2":true,"6:6":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"11:8":true,"7:4":true,"13:6":[165,186],"9:2":236,"13:0":true,"8:11":true,"4:7":true,"10:2":236,"0:10":true,"7:3":true,"14:11":true,"13:2":true,"9:6":true,"4:1":true,"0:15":true,"11:9":true,"6:4":true,"15:5":254,"10:0":[168,234],"14:5":true,"10:6":true,"0:12":true,"15:11":true,"9:0":234,"6:3":true,"7:0":234,"13:3":[167,186],"11:7":true,"0:14":true,"13:4":true,"12:7":162,"6:2":true,"7:6":true,"4:8":true,"15:4":254,"14:3":254,"4:14":true,"11:10":true,"6:5":true,"0:8":true,"15:3":254,"6:11":true,"14:4":254,"11:13":true,"8:0":true,"14:2":254,"13:11":true,"4:15":true,"0:1":true,"15:2":254,"8:6":true,"4:12":true,"13:5":true,"15:0":true,"14:6":true,"10:5":true,"9:11":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":236,"0:7":true,"15:6":true,"14:0":true,"11:12":true,"8:4":true,"7:5":true,"11:15":true,"8:3":true,"0:9":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "15:9": [
+ 160,
+ 162
+ ],
+ "9:14": true,
+ "11:5": [
+ 165,
+ 237
+ ],
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "13:13": true,
+ "12:5": [
+ 164,
+ 165
+ ],
+ "10:14": true,
+ "7:15": true,
+ "14:9": [
+ 161,
+ 164
+ ],
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "9:15": true,
+ "0:6": true,
+ "9:12": true,
+ "8:1": [
+ 188,
+ 235
+ ],
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": true,
+ "0:2": true,
+ "7:13": true,
+ "9:10": true,
+ "4:5": true,
+ "13:12": true,
+ "15:1": 254,
+ "6:14": true,
+ "13:14": true,
+ "10:13": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "6:12": true,
+ "0:4": true,
+ "6:15": true,
+ "14:8": [
+ 162,
+ 163
+ ],
+ "9:13": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": [
+ 163,
+ 164
+ ],
+ "4:3": true,
+ "8:13": true,
+ "10:9": true,
+ "7:7": true,
+ "13:8": [
+ 162,
+ 186
+ ],
+ "15:14": true,
+ "12:0": true,
+ "9:9": true,
+ "6:1": true,
+ "11:6": [
+ 164,
+ 237
+ ],
+ "4:4": true,
+ "10:7": 236,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "0:5": true,
+ "12:3": true,
+ "11:4": [
+ 165,
+ 251
+ ],
+ "9:1": true,
+ "8:12": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "15:10": [
+ 163,
+ 254
+ ],
+ "14:10": true,
+ "10:1": 235,
+ "13:7": [
+ 163,
+ 186
+ ],
+ "12:4": 165,
+ "11:3": [
+ 165,
+ 252
+ ],
+ "8:15": true,
+ "4:0": true,
+ "15:13": true,
+ "12:2": true,
+ "10:8": true,
+ "6:7": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "9:8": true,
+ "7:1": true,
+ "14:13": true,
+ "12:1": true,
+ "9:3": 236,
+ "6:0": true,
+ "10:4": [
+ 188,
+ 236
+ ],
+ "10:3": [
+ 188,
+ 236
+ ],
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "11:8": true,
+ "7:4": true,
+ "13:6": [
+ 165,
+ 186
+ ],
+ "9:2": 236,
+ "13:0": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": 236,
+ "0:10": true,
+ "7:3": true,
+ "14:11": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": true,
+ "0:15": true,
+ "11:9": true,
+ "6:4": true,
+ "15:5": 254,
+ "10:0": [
+ 168,
+ 234
+ ],
+ "14:5": true,
+ "10:6": true,
+ "0:12": true,
+ "15:11": true,
+ "9:0": 234,
+ "6:3": true,
+ "7:0": 234,
+ "13:3": [
+ 167,
+ 186
+ ],
+ "11:7": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": 162,
+ "6:2": true,
+ "7:6": true,
+ "4:8": true,
+ "15:4": 254,
+ "14:3": 254,
+ "4:14": true,
+ "11:10": true,
+ "6:5": true,
+ "0:8": true,
+ "15:3": 254,
+ "6:11": true,
+ "14:4": 254,
+ "11:13": true,
+ "8:0": true,
+ "14:2": 254,
+ "13:11": true,
+ "4:15": true,
+ "0:1": true,
+ "15:2": 254,
+ "8:6": true,
+ "4:12": true,
+ "13:5": true,
+ "15:0": true,
+ "14:6": true,
+ "10:5": true,
+ "9:11": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": 236,
+ "0:7": true,
+ "15:6": true,
+ "14:0": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_5.json
index 5df021c3..e318a13a 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_5.json
@@ -1 +1,303 @@
-{"8:8":[161,236],"6:10":true,"13:13":[182,186],"0:6":true,"14:1":true,"13:15":true,"10:10":236,"8:7":[164,236],"5:5":true,"4:11":true,"0:2":true,"9:10":236,"5:11":true,"4:5":true,"13:12":true,"15:1":true,"13:14":[182,186],"0:3":true,"8:9":[162,236],"7:10":236,"0:4":true,"14:14":true,"4:3":true,"2:12":true,"10:9":236,"7:7":true,"2:15":true,"15:14":true,"9:9":236,"4:4":true,"10:7":236,"8:10":236,"7:9":[163,236],"6:8":true,"15:12":254,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"15:15":true,"14:12":254,"9:7":236,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"4:0":true,"15:13":true,"1:15":true,"10:8":236,"6:7":true,"9:8":[160,236],"14:13":254,"1:11":true,"3:13":true,"1:5":true,"0:13":true,"11:8":[236,251],"13:6":[182,186],"13:0":true,"12:8":182,"14:11":true,"13:2":[166,186],"4:1":true,"3:12":true,"0:15":true,"11:9":[236,251],"15:5":254,"14:5":254,"3:15":true,"0:12":true,"15:11":254,"12:9":true,"13:3":[182,186],"11:7":[236,251],"2:5":true,"0:14":true,"13:4":[182,186],"12:7":true,"3:14":true,"2:11":true,"15:4":254,"14:3":254,"4:14":true,"11:10":true,"12:10":true,"5:14":true,"15:3":254,"14:4":254,"14:2":[166,254],"13:11":true,"4:15":[129,227],"0:1":true,"15:2":[165,254],"4:12":true,"13:5":[182,186],"15:0":true,"14:6":254,"15:6":true,"14:0":true,"5:13":[124,128],"4:13":true,"12:11":true,"9:14":236,"11:5":[236,237],"7:12":true,"12:5":182,"10:14":236,"7:15":235,"11:11":true,"10:12":236,"6:13":true,"9:15":235,"9:12":236,"8:1":true,"13:10":true,"10:15":235,"7:14":true,"7:13":true,"6:14":true,"10:13":236,"6:12":236,"6:15":true,"9:13":236,"11:0":true,"12:6":[153,182],"8:13":[126,236],"13:8":true,"6:1":true,"11:6":[236,237],"11:4":[166,251],"9:1":true,"8:12":236,"15:10":254,"14:10":254,"10:1":true,"13:7":true,"12:4":182,"11:3":[166,252],"8:15":true,"12:2":[166,168],"11:2":true,"8:14":[127,236],"13:9":true,"7:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"6:6":true,"4:9":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"4:7":true,"10:2":true,"0:10":true,"7:3":true,"9:6":[165,236],"6:4":true,"10:0":true,"10:6":236,"9:0":true,"6:3":true,"7:0":true,"6:2":true,"7:6":236,"4:8":true,"6:5":true,"0:8":true,"6:11":true,"11:13":[236,252],"8:0":true,"8:6":true,"12:13":182,"12:14":182,"10:5":[166,236],"9:11":236,"10:11":true,"9:5":true,"4:10":true,"11:14":[236,251],"8:2":true,"0:7":true,"12:15":182,"11:12":true,"8:4":true,"7:5":true,"12:12":182,"11:15":[235,237],"8:3":true,"0:9":true,"7:11":236} \ No newline at end of file
+{
+ "8:8": [
+ 161,
+ 236
+ ],
+ "6:10": true,
+ "13:13": [
+ 182,
+ 186
+ ],
+ "0:6": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": 236,
+ "8:7": [
+ 164,
+ 236
+ ],
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": 236,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "15:1": true,
+ "13:14": [
+ 182,
+ 186
+ ],
+ "0:3": true,
+ "8:9": [
+ 162,
+ 236
+ ],
+ "7:10": 236,
+ "0:4": true,
+ "14:14": true,
+ "4:3": true,
+ "2:12": true,
+ "10:9": 236,
+ "7:7": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": 236,
+ "4:4": true,
+ "10:7": 236,
+ "8:10": 236,
+ "7:9": [
+ 163,
+ 236
+ ],
+ "6:8": true,
+ "15:12": 254,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": 254,
+ "9:7": 236,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": 236,
+ "6:7": true,
+ "9:8": [
+ 160,
+ 236
+ ],
+ "14:13": 254,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "0:13": true,
+ "11:8": [
+ 236,
+ 251
+ ],
+ "13:6": [
+ 182,
+ 186
+ ],
+ "13:0": true,
+ "12:8": 182,
+ "14:11": true,
+ "13:2": [
+ 166,
+ 186
+ ],
+ "4:1": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": [
+ 236,
+ 251
+ ],
+ "15:5": 254,
+ "14:5": 254,
+ "3:15": true,
+ "0:12": true,
+ "15:11": 254,
+ "12:9": true,
+ "13:3": [
+ 182,
+ 186
+ ],
+ "11:7": [
+ 236,
+ 251
+ ],
+ "2:5": true,
+ "0:14": true,
+ "13:4": [
+ 182,
+ 186
+ ],
+ "12:7": true,
+ "3:14": true,
+ "2:11": true,
+ "15:4": 254,
+ "14:3": 254,
+ "4:14": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "15:3": 254,
+ "14:4": 254,
+ "14:2": [
+ 166,
+ 254
+ ],
+ "13:11": true,
+ "4:15": [
+ 129,
+ 227
+ ],
+ "0:1": true,
+ "15:2": [
+ 165,
+ 254
+ ],
+ "4:12": true,
+ "13:5": [
+ 182,
+ 186
+ ],
+ "15:0": true,
+ "14:6": 254,
+ "15:6": true,
+ "14:0": true,
+ "5:13": [
+ 124,
+ 128
+ ],
+ "4:13": true,
+ "12:11": true,
+ "9:14": 236,
+ "11:5": [
+ 236,
+ 237
+ ],
+ "7:12": true,
+ "12:5": 182,
+ "10:14": 236,
+ "7:15": 235,
+ "11:11": true,
+ "10:12": 236,
+ "6:13": true,
+ "9:15": 235,
+ "9:12": 236,
+ "8:1": true,
+ "13:10": true,
+ "10:15": 235,
+ "7:14": true,
+ "7:13": true,
+ "6:14": true,
+ "10:13": 236,
+ "6:12": 236,
+ "6:15": true,
+ "9:13": 236,
+ "11:0": true,
+ "12:6": [
+ 153,
+ 182
+ ],
+ "8:13": [
+ 126,
+ 236
+ ],
+ "13:8": true,
+ "6:1": true,
+ "11:6": [
+ 236,
+ 237
+ ],
+ "11:4": [
+ 166,
+ 251
+ ],
+ "9:1": true,
+ "8:12": 236,
+ "15:10": 254,
+ "14:10": 254,
+ "10:1": true,
+ "13:7": true,
+ "12:4": 182,
+ "11:3": [
+ 166,
+ 252
+ ],
+ "8:15": true,
+ "12:2": [
+ 166,
+ 168
+ ],
+ "11:2": true,
+ "8:14": [
+ 127,
+ 236
+ ],
+ "13:9": true,
+ "7:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "4:9": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "9:6": [
+ 165,
+ 236
+ ],
+ "6:4": true,
+ "10:0": true,
+ "10:6": 236,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "6:2": true,
+ "7:6": 236,
+ "4:8": true,
+ "6:5": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": [
+ 236,
+ 252
+ ],
+ "8:0": true,
+ "8:6": true,
+ "12:13": 182,
+ "12:14": 182,
+ "10:5": [
+ 166,
+ 236
+ ],
+ "9:11": 236,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": [
+ 236,
+ 251
+ ],
+ "8:2": true,
+ "0:7": true,
+ "12:15": 182,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "12:12": 182,
+ "11:15": [
+ 235,
+ 237
+ ],
+ "8:3": true,
+ "0:9": true,
+ "7:11": 236
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/6_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/6_6.json
index 23298771..efbef311 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/6_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/6_6.json
@@ -1 +1,298 @@
-{"15:9":[116,232],"12:11":true,"1:1":true,"11:5":true,"2:7":true,"8:8":123,"6:10":125,"7:15":true,"14:9":118,"11:11":true,"2:9":true,"15:7":[116,184],"3:0":true,"9:15":true,"0:0":true,"14:7":[109,184],"8:1":233,"3:6":true,"10:15":true,"1:8":true,"14:1":true,"13:15":true,"8:7":[118,165],"5:5":[112,113],"4:11":true,"0:2":true,"2:8":true,"5:11":true,"4:5":112,"3:2":123,"15:1":true,"1:9":true,"15:8":true,"0:3":true,"8:9":124,"7:10":125,"6:12":true,"1:7":true,"6:15":true,"14:8":true,"2:1":true,"11:0":[234,237],"12:6":[111,115],"4:3":[188,223],"5:4":111,"10:9":[122,123],"7:7":true,"2:15":true,"1:10":true,"13:8":119,"12:0":true,"9:9":[123,124],"6:1":233,"11:6":[112,120],"4:4":111,"10:7":[116,189],"7:9":124,"6:8":[120,123],"14:15":true,"13:1":true,"4:2":[171,224],"0:11":true,"15:15":true,"9:7":[117,121],"11:4":true,"9:1":233,"7:8":123,"6:9":[123,124],"4:6":113,"15:10":[117,118],"14:10":[118,119],"10:1":true,"5:6":[113,117],"13:7":[114,184],"11:3":true,"8:15":true,"4:0":[174,226],"2:10":true,"1:15":true,"10:8":[121,166],"6:7":[117,120],"11:2":true,"1:12":true,"13:9":120,"9:8":[122,164],"7:1":233,"9:3":true,"6:0":234,"1:11":true,"10:4":true,"5:9":[121,122],"10:3":true,"0:13":true,"7:2":232,"6:6":116,"4:9":119,"11:1":true,"9:4":true,"8:5":true,"5:7":[117,121],"3:10":true,"11:8":[120,167],"7:4":true,"13:6":[110,182],"9:2":true,"13:0":true,"4:7":118,"10:2":true,"0:10":true,"12:8":[120,166],"7:3":[110,231],"14:11":true,"13:2":true,"9:6":true,"4:1":[123,225],"3:12":true,"11:9":122,"6:4":[111,230],"10:0":234,"10:6":true,"3:15":true,"0:12":true,"15:11":true,"12:9":[120,121],"9:0":234,"6:3":[110,231],"7:0":234,"13:3":true,"11:7":[116,120],"5:8":[118,122],"13:4":true,"12:7":[114,120],"6:2":232,"7:6":true,"4:8":true,"2:11":true,"6:5":[112,190],"3:8":true,"2:2":true,"0:8":true,"1:0":true,"5:12":true,"8:0":234,"14:2":true,"13:11":true,"4:15":true,"0:1":true,"15:2":true,"8:6":true,"4:12":true,"3:1":true,"13:5":true,"5:15":true,"2:3":true,"15:0":true,"10:5":true,"9:11":true,"5:10":true,"3:7":true,"1:3":true,"10:11":true,"9:5":true,"4:10":true,"8:2":232,"14:0":true,"2:0":true,"12:15":true,"8:4":true,"5:13":true,"1:2":true,"7:5":[115,190],"3:9":true,"11:15":true,"8:3":[109,231],"0:9":true,"2:6":true} \ No newline at end of file
+{
+ "15:9": [
+ 116,
+ 232
+ ],
+ "12:11": true,
+ "1:1": true,
+ "11:5": true,
+ "2:7": true,
+ "8:8": 123,
+ "6:10": 125,
+ "7:15": true,
+ "14:9": 118,
+ "11:11": true,
+ "2:9": true,
+ "15:7": [
+ 116,
+ 184
+ ],
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "14:7": [
+ 109,
+ 184
+ ],
+ "8:1": 233,
+ "3:6": true,
+ "10:15": true,
+ "1:8": true,
+ "14:1": true,
+ "13:15": true,
+ "8:7": [
+ 118,
+ 165
+ ],
+ "5:5": [
+ 112,
+ 113
+ ],
+ "4:11": true,
+ "0:2": true,
+ "2:8": true,
+ "5:11": true,
+ "4:5": 112,
+ "3:2": 123,
+ "15:1": true,
+ "1:9": true,
+ "15:8": true,
+ "0:3": true,
+ "8:9": 124,
+ "7:10": 125,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "14:8": true,
+ "2:1": true,
+ "11:0": [
+ 234,
+ 237
+ ],
+ "12:6": [
+ 111,
+ 115
+ ],
+ "4:3": [
+ 188,
+ 223
+ ],
+ "5:4": 111,
+ "10:9": [
+ 122,
+ 123
+ ],
+ "7:7": true,
+ "2:15": true,
+ "1:10": true,
+ "13:8": 119,
+ "12:0": true,
+ "9:9": [
+ 123,
+ 124
+ ],
+ "6:1": 233,
+ "11:6": [
+ 112,
+ 120
+ ],
+ "4:4": 111,
+ "10:7": [
+ 116,
+ 189
+ ],
+ "7:9": 124,
+ "6:8": [
+ 120,
+ 123
+ ],
+ "14:15": true,
+ "13:1": true,
+ "4:2": [
+ 171,
+ 224
+ ],
+ "0:11": true,
+ "15:15": true,
+ "9:7": [
+ 117,
+ 121
+ ],
+ "11:4": true,
+ "9:1": 233,
+ "7:8": 123,
+ "6:9": [
+ 123,
+ 124
+ ],
+ "4:6": 113,
+ "15:10": [
+ 117,
+ 118
+ ],
+ "14:10": [
+ 118,
+ 119
+ ],
+ "10:1": true,
+ "5:6": [
+ 113,
+ 117
+ ],
+ "13:7": [
+ 114,
+ 184
+ ],
+ "11:3": true,
+ "8:15": true,
+ "4:0": [
+ 174,
+ 226
+ ],
+ "2:10": true,
+ "1:15": true,
+ "10:8": [
+ 121,
+ 166
+ ],
+ "6:7": [
+ 117,
+ 120
+ ],
+ "11:2": true,
+ "1:12": true,
+ "13:9": 120,
+ "9:8": [
+ 122,
+ 164
+ ],
+ "7:1": 233,
+ "9:3": true,
+ "6:0": 234,
+ "1:11": true,
+ "10:4": true,
+ "5:9": [
+ 121,
+ 122
+ ],
+ "10:3": true,
+ "0:13": true,
+ "7:2": 232,
+ "6:6": 116,
+ "4:9": 119,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": [
+ 117,
+ 121
+ ],
+ "3:10": true,
+ "11:8": [
+ 120,
+ 167
+ ],
+ "7:4": true,
+ "13:6": [
+ 110,
+ 182
+ ],
+ "9:2": true,
+ "13:0": true,
+ "4:7": 118,
+ "10:2": true,
+ "0:10": true,
+ "12:8": [
+ 120,
+ 166
+ ],
+ "7:3": [
+ 110,
+ 231
+ ],
+ "14:11": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": [
+ 123,
+ 225
+ ],
+ "3:12": true,
+ "11:9": 122,
+ "6:4": [
+ 111,
+ 230
+ ],
+ "10:0": 234,
+ "10:6": true,
+ "3:15": true,
+ "0:12": true,
+ "15:11": true,
+ "12:9": [
+ 120,
+ 121
+ ],
+ "9:0": 234,
+ "6:3": [
+ 110,
+ 231
+ ],
+ "7:0": 234,
+ "13:3": true,
+ "11:7": [
+ 116,
+ 120
+ ],
+ "5:8": [
+ 118,
+ 122
+ ],
+ "13:4": true,
+ "12:7": [
+ 114,
+ 120
+ ],
+ "6:2": 232,
+ "7:6": true,
+ "4:8": true,
+ "2:11": true,
+ "6:5": [
+ 112,
+ 190
+ ],
+ "3:8": true,
+ "2:2": true,
+ "0:8": true,
+ "1:0": true,
+ "5:12": true,
+ "8:0": 234,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "0:1": true,
+ "15:2": true,
+ "8:6": true,
+ "4:12": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "15:0": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "3:7": true,
+ "1:3": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "8:2": 232,
+ "14:0": true,
+ "2:0": true,
+ "12:15": true,
+ "8:4": true,
+ "5:13": true,
+ "1:2": true,
+ "7:5": [
+ 115,
+ 190
+ ],
+ "3:9": true,
+ "11:15": true,
+ "8:3": [
+ 109,
+ 231
+ ],
+ "0:9": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_-1.json
index 96e0e727..beb62e5f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_-1.json
@@ -1 +1,4 @@
-{"12:1":true,"9:0":233} \ No newline at end of file
+{
+ "12:1": true,
+ "9:0": 233
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_-2.json
index 3200d788..471796ed 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_-2.json
@@ -1 +1,22 @@
-{"14:1":true,"4:11":true,"15:1":true,"0:3":true,"0:4":true,"12:0":true,"13:1":true,"0:5":true,"12:2":228,"1:5":true,"11:1":228,"15:4":true,"15:3":true,"5:12":true,"14:2":true,"15:2":true,"15:0":true,"4:10":true,"5:13":true,"2:6":true} \ No newline at end of file
+{
+ "14:1": true,
+ "4:11": true,
+ "15:1": true,
+ "0:3": true,
+ "0:4": true,
+ "12:0": true,
+ "13:1": true,
+ "0:5": true,
+ "12:2": 228,
+ "1:5": true,
+ "11:1": 228,
+ "15:4": true,
+ "15:3": true,
+ "5:12": true,
+ "14:2": true,
+ "15:2": true,
+ "15:0": true,
+ "4:10": true,
+ "5:13": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_-3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_-3.json
index 5d043173..3e1ceb41 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_-3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_-3.json
@@ -1 +1,28 @@
-{"11:11":true,"15:7":true,"12:8":222,"11:9":222,"15:11":true,"15:8":true,"10:9":[222,223],"12:10":true,"15:14":true,"9:9":[222,223],"11:13":true,"15:12":true,"15:15":true,"12:13":true,"15:10":true,"15:6":true,"15:13":true,"12:15":true,"12:12":true,"11:15":true} \ No newline at end of file
+{
+ "11:11": true,
+ "15:7": true,
+ "12:8": 222,
+ "11:9": 222,
+ "15:11": true,
+ "15:8": true,
+ "10:9": [
+ 222,
+ 223
+ ],
+ "12:10": true,
+ "15:14": true,
+ "9:9": [
+ 222,
+ 223
+ ],
+ "11:13": true,
+ "15:12": true,
+ "15:15": true,
+ "12:13": true,
+ "15:10": true,
+ "15:6": true,
+ "15:13": true,
+ "12:15": true,
+ "12:12": true,
+ "11:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_0.json
index eda3d134..91d97e1c 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_0.json
@@ -1 +1,24 @@
-{"9:14":true,"10:14":true,"7:15":true,"9:15":true,"10:15":true,"7:14":true,"13:15":true,"13:14":true,"14:14":true,"15:14":true,"15:15":true,"1:14":true,"8:15":true,"1:15":true,"8:14":true,"9:6":true,"0:15":true,"0:14":true,"12:14":true,"11:14":true,"12:15":true,"11:15":true} \ No newline at end of file
+{
+ "9:14": true,
+ "10:14": true,
+ "7:15": true,
+ "9:15": true,
+ "10:15": true,
+ "7:14": true,
+ "13:15": true,
+ "13:14": true,
+ "14:14": true,
+ "15:14": true,
+ "15:15": true,
+ "1:14": true,
+ "8:15": true,
+ "1:15": true,
+ "8:14": true,
+ "9:6": true,
+ "0:15": true,
+ "0:14": true,
+ "12:14": true,
+ "11:14": true,
+ "12:15": true,
+ "11:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_1.json
index f0ae8c33..984bdc75 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_1.json
@@ -1 +1,115 @@
-{"12:11":true,"9:14":true,"1:1":true,"11:5":true,"8:8":254,"7:12":true,"13:13":true,"12:5":true,"10:14":true,"7:15":true,"11:11":true,"9:15":true,"0:6":true,"0:0":true,"8:1":true,"10:15":true,"7:14":true,"10:10":true,"0:2":true,"7:13":true,"15:1":true,"0:3":true,"0:4":true,"9:13":true,"11:0":true,"14:14":true,"12:6":true,"8:13":true,"10:9":true,"1:10":true,"15:14":true,"12:0":true,"9:9":true,"11:6":[181,254],"10:7":true,"0:11":true,"15:15":true,"9:7":true,"1:13":true,"0:5":true,"1:14":true,"9:1":true,"11:4":true,"8:12":true,"10:1":true,"12:4":true,"11:3":true,"8:15":true,"15:13":true,"1:15":true,"10:8":254,"8:14":true,"1:12":true,"9:8":254,"7:1":true,"14:13":true,"9:3":true,"1:11":true,"1:5":true,"0:13":true,"7:2":true,"11:1":true,"11:8":[183,254],"7:4":true,"9:2":true,"13:0":true,"10:2":true,"0:10":true,"12:8":true,"7:3":true,"0:15":true,"11:9":true,"10:0":true,"10:6":254,"0:12":true,"12:9":true,"9:0":true,"7:0":true,"13:3":true,"11:7":true,"0:14":true,"12:7":254,"14:3":true,"1:6":true,"11:10":true,"12:10":true,"15:3":true,"1:0":true,"11:13":true,"8:0":true,"14:2":true,"0:1":true,"15:2":true,"15:0":true,"1:3":true,"11:14":true,"8:2":true,"1:4":true,"14:0":true,"11:12":true,"8:4":true,"1:2":true,"7:5":254,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "1:1": true,
+ "11:5": true,
+ "8:8": 254,
+ "7:12": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "9:15": true,
+ "0:6": true,
+ "0:0": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "10:10": true,
+ "0:2": true,
+ "7:13": true,
+ "15:1": true,
+ "0:3": true,
+ "0:4": true,
+ "9:13": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": true,
+ "8:13": true,
+ "10:9": true,
+ "1:10": true,
+ "15:14": true,
+ "12:0": true,
+ "9:9": true,
+ "11:6": [
+ 181,
+ 254
+ ],
+ "10:7": true,
+ "0:11": true,
+ "15:15": true,
+ "9:7": true,
+ "1:13": true,
+ "0:5": true,
+ "1:14": true,
+ "9:1": true,
+ "11:4": true,
+ "8:12": true,
+ "10:1": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": 254,
+ "8:14": true,
+ "1:12": true,
+ "9:8": 254,
+ "7:1": true,
+ "14:13": true,
+ "9:3": true,
+ "1:11": true,
+ "1:5": true,
+ "0:13": true,
+ "7:2": true,
+ "11:1": true,
+ "11:8": [
+ 183,
+ 254
+ ],
+ "7:4": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "0:10": true,
+ "12:8": true,
+ "7:3": true,
+ "0:15": true,
+ "11:9": true,
+ "10:0": true,
+ "10:6": 254,
+ "0:12": true,
+ "12:9": true,
+ "9:0": true,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "0:14": true,
+ "12:7": 254,
+ "14:3": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "15:3": true,
+ "1:0": true,
+ "11:13": true,
+ "8:0": true,
+ "14:2": true,
+ "0:1": true,
+ "15:2": true,
+ "15:0": true,
+ "1:3": true,
+ "11:14": true,
+ "8:2": true,
+ "1:4": true,
+ "14:0": true,
+ "11:12": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": 254,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_2.json
index 98887d05..daccb954 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_2.json
@@ -1 +1,66 @@
-{"9:14":true,"1:1":true,"11:5":true,"10:14":true,"7:15":254,"11:11":true,"9:15":254,"0:0":true,"8:1":true,"10:15":true,"7:14":254,"13:15":true,"0:2":true,"15:1":true,"13:14":true,"11:0":true,"14:14":true,"15:14":true,"12:0":true,"11:6":true,"13:1":true,"15:15":true,"11:4":true,"9:1":true,"1:14":254,"10:1":true,"11:3":true,"8:15":254,"12:2":true,"1:15":true,"11:2":true,"8:14":254,"7:1":true,"12:1":true,"7:2":true,"11:1":true,"11:8":true,"9:2":true,"13:0":true,"10:2":true,"13:2":true,"0:15":true,"11:9":true,"10:0":true,"9:0":true,"7:0":true,"11:7":true,"0:14":254,"11:10":true,"1:0":true,"11:13":true,"8:0":true,"14:2":true,"0:1":true,"15:2":true,"12:14":true,"15:0":true,"11:14":true,"8:2":true,"14:0":true,"12:15":true,"11:12":true,"1:2":true,"11:15":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:1": true,
+ "11:5": true,
+ "10:14": true,
+ "7:15": 254,
+ "11:11": true,
+ "9:15": 254,
+ "0:0": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": 254,
+ "13:15": true,
+ "0:2": true,
+ "15:1": true,
+ "13:14": true,
+ "11:0": true,
+ "14:14": true,
+ "15:14": true,
+ "12:0": true,
+ "11:6": true,
+ "13:1": true,
+ "15:15": true,
+ "11:4": true,
+ "9:1": true,
+ "1:14": 254,
+ "10:1": true,
+ "11:3": true,
+ "8:15": 254,
+ "12:2": true,
+ "1:15": true,
+ "11:2": true,
+ "8:14": 254,
+ "7:1": true,
+ "12:1": true,
+ "7:2": true,
+ "11:1": true,
+ "11:8": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "13:2": true,
+ "0:15": true,
+ "11:9": true,
+ "10:0": true,
+ "9:0": true,
+ "7:0": true,
+ "11:7": true,
+ "0:14": 254,
+ "11:10": true,
+ "1:0": true,
+ "11:13": true,
+ "8:0": true,
+ "14:2": true,
+ "0:1": true,
+ "15:2": true,
+ "12:14": true,
+ "15:0": true,
+ "11:14": true,
+ "8:2": true,
+ "14:0": true,
+ "12:15": true,
+ "11:12": true,
+ "1:2": true,
+ "11:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_3.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_3.json
index c58be254..8dfb29e5 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_3.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_3.json
@@ -1 +1,135 @@
-{"12:11":true,"9:14":true,"1:1":254,"11:5":true,"8:8":true,"7:12":true,"13:13":true,"12:5":true,"10:14":true,"7:15":true,"11:11":true,"9:15":true,"0:6":true,"0:0":254,"8:1":true,"10:15":true,"7:14":true,"10:10":true,"0:2":254,"7:13":true,"15:1":true,"0:3":true,"0:4":254,"9:13":true,"11:0":[181,254],"14:14":true,"12:6":true,"8:13":true,"10:9":true,"2:15":155,"1:10":true,"15:14":true,"12:0":true,"9:9":true,"11:6":true,"10:7":true,"13:1":true,"0:11":254,"15:15":true,"9:7":true,"2:14":[155,156],"1:13":[157,254],"0:5":254,"11:4":true,"9:1":true,"8:12":true,"1:14":254,"10:1":true,"12:4":true,"11:3":true,"8:15":true,"15:13":true,"1:15":true,"10:8":true,"11:2":[183,184],"8:14":true,"1:12":[158,254],"9:8":true,"7:1":true,"14:13":true,"9:3":254,"1:11":[159,254],"1:5":254,"0:13":254,"7:2":true,"11:1":[182,254],"11:8":true,"7:4":254,"9:2":254,"10:2":254,"0:10":[160,254],"12:8":true,"7:3":254,"0:15":true,"11:9":true,"10:0":254,"10:6":true,"0:12":254,"12:9":true,"9:0":254,"7:0":254,"13:3":true,"11:7":true,"0:14":254,"12:7":true,"14:3":true,"1:6":254,"11:10":true,"12:10":true,"15:3":true,"1:0":254,"11:13":true,"8:0":254,"14:2":true,"0:1":254,"15:2":true,"15:0":true,"1:3":true,"11:14":true,"8:2":254,"1:4":true,"11:12":true,"8:4":true,"1:2":true,"7:5":true,"12:12":true,"11:15":true,"8:3":254,"7:11":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "1:1": 254,
+ "11:5": true,
+ "8:8": true,
+ "7:12": true,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "9:15": true,
+ "0:6": true,
+ "0:0": 254,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "10:10": true,
+ "0:2": 254,
+ "7:13": true,
+ "15:1": true,
+ "0:3": true,
+ "0:4": 254,
+ "9:13": true,
+ "11:0": [
+ 181,
+ 254
+ ],
+ "14:14": true,
+ "12:6": true,
+ "8:13": true,
+ "10:9": true,
+ "2:15": 155,
+ "1:10": true,
+ "15:14": true,
+ "12:0": true,
+ "9:9": true,
+ "11:6": true,
+ "10:7": true,
+ "13:1": true,
+ "0:11": 254,
+ "15:15": true,
+ "9:7": true,
+ "2:14": [
+ 155,
+ 156
+ ],
+ "1:13": [
+ 157,
+ 254
+ ],
+ "0:5": 254,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "1:14": 254,
+ "10:1": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "11:2": [
+ 183,
+ 184
+ ],
+ "8:14": true,
+ "1:12": [
+ 158,
+ 254
+ ],
+ "9:8": true,
+ "7:1": true,
+ "14:13": true,
+ "9:3": 254,
+ "1:11": [
+ 159,
+ 254
+ ],
+ "1:5": 254,
+ "0:13": 254,
+ "7:2": true,
+ "11:1": [
+ 182,
+ 254
+ ],
+ "11:8": true,
+ "7:4": 254,
+ "9:2": 254,
+ "10:2": 254,
+ "0:10": [
+ 160,
+ 254
+ ],
+ "12:8": true,
+ "7:3": 254,
+ "0:15": true,
+ "11:9": true,
+ "10:0": 254,
+ "10:6": true,
+ "0:12": 254,
+ "12:9": true,
+ "9:0": 254,
+ "7:0": 254,
+ "13:3": true,
+ "11:7": true,
+ "0:14": 254,
+ "12:7": true,
+ "14:3": true,
+ "1:6": 254,
+ "11:10": true,
+ "12:10": true,
+ "15:3": true,
+ "1:0": 254,
+ "11:13": true,
+ "8:0": 254,
+ "14:2": true,
+ "0:1": 254,
+ "15:2": true,
+ "15:0": true,
+ "1:3": true,
+ "11:14": true,
+ "8:2": 254,
+ "1:4": true,
+ "11:12": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": 254,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_4.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_4.json
index c3b7ea88..9c649007 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_4.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_4.json
@@ -1 +1,122 @@
-{"9:14":true,"1:1":true,"11:5":true,"8:8":true,"10:14":true,"7:15":true,"11:11":true,"10:12":true,"2:9":true,"9:15":true,"0:6":true,"0:0":true,"9:12":true,"8:1":true,"10:15":true,"7:14":true,"1:8":true,"13:15":true,"10:10":true,"0:2":true,"9:10":true,"15:1":true,"1:9":true,"13:14":true,"10:13":true,"9:13":true,"11:0":true,"14:14":true,"4:3":true,"8:13":true,"2:12":true,"10:9":true,"5:3":true,"1:10":true,"15:14":true,"12:0":true,"9:9":true,"11:6":true,"10:7":true,"14:15":true,"13:1":true,"0:11":true,"15:15":true,"9:7":true,"3:11":true,"2:14":true,"1:13":true,"0:5":true,"11:4":true,"9:1":true,"8:12":true,"2:13":true,"1:14":true,"10:1":true,"12:4":true,"11:3":true,"8:15":true,"12:2":true,"2:10":true,"1:15":true,"10:8":true,"11:2":true,"8:14":true,"1:12":true,"9:8":true,"7:1":true,"12:1":true,"1:11":true,"10:3":true,"0:13":true,"7:2":true,"11:1":true,"9:4":true,"3:10":true,"11:8":true,"9:2":true,"13:0":true,"10:2":true,"0:10":true,"7:3":true,"13:2":true,"3:12":true,"0:15":true,"11:9":true,"10:0":true,"0:12":true,"9:0":true,"7:0":true,"13:3":true,"11:7":true,"0:14":true,"2:11":true,"15:4":true,"14:3":true,"11:10":true,"0:8":true,"15:3":true,"1:0":true,"14:4":true,"11:13":true,"8:0":true,"14:2":true,"0:1":true,"15:2":true,"15:0":true,"12:14":true,"9:11":true,"10:11":true,"11:14":true,"8:2":true,"0:7":true,"14:0":true,"2:0":true,"12:15":true,"11:12":true,"8:4":true,"1:2":true,"11:15":true,"8:3":true,"0:9":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:1": true,
+ "11:5": true,
+ "8:8": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "10:12": true,
+ "2:9": true,
+ "9:15": true,
+ "0:6": true,
+ "0:0": true,
+ "9:12": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "13:15": true,
+ "10:10": true,
+ "0:2": true,
+ "9:10": true,
+ "15:1": true,
+ "1:9": true,
+ "13:14": true,
+ "10:13": true,
+ "9:13": true,
+ "11:0": true,
+ "14:14": true,
+ "4:3": true,
+ "8:13": true,
+ "2:12": true,
+ "10:9": true,
+ "5:3": true,
+ "1:10": true,
+ "15:14": true,
+ "12:0": true,
+ "9:9": true,
+ "11:6": true,
+ "10:7": true,
+ "14:15": true,
+ "13:1": true,
+ "0:11": true,
+ "15:15": true,
+ "9:7": true,
+ "3:11": true,
+ "2:14": true,
+ "1:13": true,
+ "0:5": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "2:13": true,
+ "1:14": true,
+ "10:1": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": true,
+ "2:10": true,
+ "1:15": true,
+ "10:8": true,
+ "11:2": true,
+ "8:14": true,
+ "1:12": true,
+ "9:8": true,
+ "7:1": true,
+ "12:1": true,
+ "1:11": true,
+ "10:3": true,
+ "0:13": true,
+ "7:2": true,
+ "11:1": true,
+ "9:4": true,
+ "3:10": true,
+ "11:8": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "0:10": true,
+ "7:3": true,
+ "13:2": true,
+ "3:12": true,
+ "0:15": true,
+ "11:9": true,
+ "10:0": true,
+ "0:12": true,
+ "9:0": true,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "0:14": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "11:10": true,
+ "0:8": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "11:13": true,
+ "8:0": true,
+ "14:2": true,
+ "0:1": true,
+ "15:2": true,
+ "15:0": true,
+ "12:14": true,
+ "9:11": true,
+ "10:11": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "14:0": true,
+ "2:0": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "1:2": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_5.json
index 106d07c3..898cca1f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_5.json
@@ -1 +1,120 @@
-{"12:11":true,"9:14":true,"1:1":true,"11:5":[182,254],"8:8":true,"7:12":254,"13:13":true,"12:5":true,"10:14":true,"7:15":true,"11:11":true,"9:15":true,"0:6":true,"0:0":true,"8:1":254,"10:15":true,"7:14":true,"10:10":true,"0:2":254,"7:13":true,"15:1":true,"0:3":254,"0:4":254,"9:13":true,"11:0":true,"14:14":true,"12:6":true,"8:13":true,"10:9":true,"1:10":254,"15:14":true,"12:0":true,"9:9":254,"11:6":true,"10:7":true,"0:11":254,"15:15":true,"9:7":true,"1:13":true,"0:5":254,"11:4":[181,182],"9:1":254,"8:12":true,"1:14":true,"10:1":254,"12:4":true,"11:3":true,"8:15":true,"15:13":true,"1:15":true,"10:8":true,"11:2":[156,165],"8:14":true,"1:12":true,"9:8":254,"7:1":254,"14:13":true,"9:3":254,"1:11":true,"1:5":254,"0:13":true,"7:2":254,"11:1":[156,254],"11:8":true,"7:4":254,"9:2":254,"10:2":254,"0:10":254,"12:8":true,"7:3":254,"0:15":true,"11:9":true,"10:0":true,"10:6":true,"0:12":254,"12:9":true,"9:0":254,"7:0":254,"13:3":true,"11:7":true,"0:14":true,"12:7":true,"14:3":true,"1:6":true,"11:10":true,"12:10":true,"15:3":true,"1:0":true,"11:13":true,"8:0":254,"14:2":true,"0:1":true,"15:2":true,"15:0":true,"1:3":254,"11:14":true,"8:2":254,"1:4":true,"11:12":true,"8:4":254,"1:2":254,"7:5":254,"12:12":true,"11:15":true,"8:3":254,"7:11":true} \ No newline at end of file
+{
+ "12:11": true,
+ "9:14": true,
+ "1:1": true,
+ "11:5": [
+ 182,
+ 254
+ ],
+ "8:8": true,
+ "7:12": 254,
+ "13:13": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "9:15": true,
+ "0:6": true,
+ "0:0": true,
+ "8:1": 254,
+ "10:15": true,
+ "7:14": true,
+ "10:10": true,
+ "0:2": 254,
+ "7:13": true,
+ "15:1": true,
+ "0:3": 254,
+ "0:4": 254,
+ "9:13": true,
+ "11:0": true,
+ "14:14": true,
+ "12:6": true,
+ "8:13": true,
+ "10:9": true,
+ "1:10": 254,
+ "15:14": true,
+ "12:0": true,
+ "9:9": 254,
+ "11:6": true,
+ "10:7": true,
+ "0:11": 254,
+ "15:15": true,
+ "9:7": true,
+ "1:13": true,
+ "0:5": 254,
+ "11:4": [
+ 181,
+ 182
+ ],
+ "9:1": 254,
+ "8:12": true,
+ "1:14": true,
+ "10:1": 254,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "15:13": true,
+ "1:15": true,
+ "10:8": true,
+ "11:2": [
+ 156,
+ 165
+ ],
+ "8:14": true,
+ "1:12": true,
+ "9:8": 254,
+ "7:1": 254,
+ "14:13": true,
+ "9:3": 254,
+ "1:11": true,
+ "1:5": 254,
+ "0:13": true,
+ "7:2": 254,
+ "11:1": [
+ 156,
+ 254
+ ],
+ "11:8": true,
+ "7:4": 254,
+ "9:2": 254,
+ "10:2": 254,
+ "0:10": 254,
+ "12:8": true,
+ "7:3": 254,
+ "0:15": true,
+ "11:9": true,
+ "10:0": true,
+ "10:6": true,
+ "0:12": 254,
+ "12:9": true,
+ "9:0": 254,
+ "7:0": 254,
+ "13:3": true,
+ "11:7": true,
+ "0:14": true,
+ "12:7": true,
+ "14:3": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "15:3": true,
+ "1:0": true,
+ "11:13": true,
+ "8:0": 254,
+ "14:2": true,
+ "0:1": true,
+ "15:2": true,
+ "15:0": true,
+ "1:3": 254,
+ "11:14": true,
+ "8:2": 254,
+ "1:4": true,
+ "11:12": true,
+ "8:4": 254,
+ "1:2": 254,
+ "7:5": 254,
+ "12:12": true,
+ "11:15": true,
+ "8:3": 254,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/7_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/7_6.json
index 6b6caa51..54740b3d 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/7_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/7_6.json
@@ -1 +1,179 @@
-{"15:9":true,"12:11":true,"1:1":true,"11:5":true,"2:7":true,"13:13":true,"7:15":[187,223],"14:9":true,"11:11":true,"2:9":[112,236],"15:7":true,"9:15":true,"0:0":true,"14:7":true,"8:1":true,"13:10":true,"10:15":true,"1:8":114,"13:15":true,"10:10":true,"8:7":true,"4:11":[189,221],"0:2":true,"5:11":[192,219],"13:12":true,"15:1":true,"1:9":[110,236],"15:8":true,"13:14":true,"6:12":[109,110],"1:7":true,"6:15":[187,223],"14:8":true,"11:0":true,"14:14":true,"2:12":true,"10:9":true,"7:7":true,"2:15":true,"1:10":[114,115],"13:8":true,"15:14":true,"12:0":true,"9:9":true,"11:6":true,"10:7":true,"8:10":true,"15:12":true,"14:15":true,"13:1":true,"0:11":true,"15:15":true,"14:12":true,"9:7":true,"3:11":[109,222],"11:4":true,"9:1":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"11:3":true,"8:15":[187,230],"15:13":true,"12:2":true,"2:10":[110,113],"1:15":true,"6:7":true,"11:2":true,"13:9":true,"7:1":true,"14:13":true,"12:1":true,"1:11":true,"5:9":true,"7:2":true,"4:9":true,"11:1":true,"5:7":true,"9:2":true,"4:7":true,"10:2":true,"0:10":116,"12:8":true,"14:11":true,"13:2":true,"3:12":113,"0:15":true,"11:9":true,"10:0":true,"3:15":true,"15:11":true,"12:9":true,"9:0":true,"7:0":true,"11:7":true,"12:7":true,"2:11":[112,223],"11:10":true,"12:10":true,"0:8":true,"1:0":true,"5:12":[108,111],"8:0":true,"14:2":true,"13:11":true,"4:15":[187,223],"0:1":true,"15:2":true,"4:12":[110,112],"5:15":[187,223],"15:0":true,"3:7":184,"10:11":true,"8:2":true,"0:7":[115,184],"15:6":true,"12:15":true,"1:2":true,"3:9":true,"12:12":true,"11:15":true,"0:9":[111,233]} \ No newline at end of file
+{
+ "15:9": true,
+ "12:11": true,
+ "1:1": true,
+ "11:5": true,
+ "2:7": true,
+ "13:13": true,
+ "7:15": [
+ 187,
+ 223
+ ],
+ "14:9": true,
+ "11:11": true,
+ "2:9": [
+ 112,
+ 236
+ ],
+ "15:7": true,
+ "9:15": true,
+ "0:0": true,
+ "14:7": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "1:8": 114,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "4:11": [
+ 189,
+ 221
+ ],
+ "0:2": true,
+ "5:11": [
+ 192,
+ 219
+ ],
+ "13:12": true,
+ "15:1": true,
+ "1:9": [
+ 110,
+ 236
+ ],
+ "15:8": true,
+ "13:14": true,
+ "6:12": [
+ 109,
+ 110
+ ],
+ "1:7": true,
+ "6:15": [
+ 187,
+ 223
+ ],
+ "14:8": true,
+ "11:0": true,
+ "14:14": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "2:15": true,
+ "1:10": [
+ 114,
+ 115
+ ],
+ "13:8": true,
+ "15:14": true,
+ "12:0": true,
+ "9:9": true,
+ "11:6": true,
+ "10:7": true,
+ "8:10": true,
+ "15:12": true,
+ "14:15": true,
+ "13:1": true,
+ "0:11": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": [
+ 109,
+ 222
+ ],
+ "11:4": true,
+ "9:1": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "11:3": true,
+ "8:15": [
+ 187,
+ 230
+ ],
+ "15:13": true,
+ "12:2": true,
+ "2:10": [
+ 110,
+ 113
+ ],
+ "1:15": true,
+ "6:7": true,
+ "11:2": true,
+ "13:9": true,
+ "7:1": true,
+ "14:13": true,
+ "12:1": true,
+ "1:11": true,
+ "5:9": true,
+ "7:2": true,
+ "4:9": true,
+ "11:1": true,
+ "5:7": true,
+ "9:2": true,
+ "4:7": true,
+ "10:2": true,
+ "0:10": 116,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "3:12": 113,
+ "0:15": true,
+ "11:9": true,
+ "10:0": true,
+ "3:15": true,
+ "15:11": true,
+ "12:9": true,
+ "9:0": true,
+ "7:0": true,
+ "11:7": true,
+ "12:7": true,
+ "2:11": [
+ 112,
+ 223
+ ],
+ "11:10": true,
+ "12:10": true,
+ "0:8": true,
+ "1:0": true,
+ "5:12": [
+ 108,
+ 111
+ ],
+ "8:0": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": [
+ 187,
+ 223
+ ],
+ "0:1": true,
+ "15:2": true,
+ "4:12": [
+ 110,
+ 112
+ ],
+ "5:15": [
+ 187,
+ 223
+ ],
+ "15:0": true,
+ "3:7": 184,
+ "10:11": true,
+ "8:2": true,
+ "0:7": [
+ 115,
+ 184
+ ],
+ "15:6": true,
+ "12:15": true,
+ "1:2": true,
+ "3:9": true,
+ "12:12": true,
+ "11:15": true,
+ "0:9": [
+ 111,
+ 233
+ ]
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/8_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/8_-1.json
index e6dc6263..4a306305 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/8_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/8_-1.json
@@ -1 +1,29 @@
-{"10:4":true,"9:4":true,"9:2":true,"13:0":true,"14:7":true,"8:1":true,"10:2":true,"9:6":true,"10:0":true,"15:11":true,"9:0":true,"7:0":true,"12:7":true,"11:0":true,"12:6":true,"13:8":true,"12:0":true,"11:6":true,"10:7":true,"15:12":186,"15:0":true,"14:6":true,"10:5":true,"14:10":true,"10:1":true,"14:0":true,"13:9":true} \ No newline at end of file
+{
+ "10:4": true,
+ "9:4": true,
+ "9:2": true,
+ "13:0": true,
+ "14:7": true,
+ "8:1": true,
+ "10:2": true,
+ "9:6": true,
+ "10:0": true,
+ "15:11": true,
+ "9:0": true,
+ "7:0": true,
+ "12:7": true,
+ "11:0": true,
+ "12:6": true,
+ "13:8": true,
+ "12:0": true,
+ "11:6": true,
+ "10:7": true,
+ "15:12": 186,
+ "15:0": true,
+ "14:6": true,
+ "10:5": true,
+ "14:10": true,
+ "10:1": true,
+ "14:0": true,
+ "13:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/8_-2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/8_-2.json
index 3dbb3534..613e25ff 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/8_-2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/8_-2.json
@@ -1 +1,50 @@
-{"12:11":true,"1:1":true,"8:8":true,"7:12":true,"13:13":true,"7:15":true,"11:11":true,"3:0":true,"10:15":true,"10:10":true,"13:15":true,"8:7":true,"4:11":186,"0:2":true,"13:12":true,"6:14":true,"14:14":true,"9:9":true,"15:15":true,"9:7":true,"0:5":true,"5:0":true,"10:8":true,"9:8":true,"8:5":true,"7:4":true,"8:11":true,"7:3":true,"9:6":true,"4:1":true,"11:9":true,"6:4":true,"5:1":true,"6:2":true,"7:6":true,"1:6":186,"11:10":true,"6:5":true,"2:2":true,"5:12":186,"0:1":true,"8:6":true,"3:1":true,"12:14":true,"12:15":true,"5:13":true,"7:5":true,"3:9":true} \ No newline at end of file
+{
+ "12:11": true,
+ "1:1": true,
+ "8:8": true,
+ "7:12": true,
+ "13:13": true,
+ "7:15": true,
+ "11:11": true,
+ "3:0": true,
+ "10:15": true,
+ "10:10": true,
+ "13:15": true,
+ "8:7": true,
+ "4:11": 186,
+ "0:2": true,
+ "13:12": true,
+ "6:14": true,
+ "14:14": true,
+ "9:9": true,
+ "15:15": true,
+ "9:7": true,
+ "0:5": true,
+ "5:0": true,
+ "10:8": true,
+ "9:8": true,
+ "8:5": true,
+ "7:4": true,
+ "8:11": true,
+ "7:3": true,
+ "9:6": true,
+ "4:1": true,
+ "11:9": true,
+ "6:4": true,
+ "5:1": true,
+ "6:2": true,
+ "7:6": true,
+ "1:6": 186,
+ "11:10": true,
+ "6:5": true,
+ "2:2": true,
+ "5:12": 186,
+ "0:1": true,
+ "8:6": true,
+ "3:1": true,
+ "12:14": true,
+ "12:15": true,
+ "5:13": true,
+ "7:5": true,
+ "3:9": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/8_0.json b/src/main/resources/assets/notenoughupdates/dwarven_data/8_0.json
index da92c247..a4650235 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/8_0.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/8_0.json
@@ -1 +1,21 @@
-{"9:14":true,"4:14":true,"10:14":true,"5:14":true,"7:15":true,"14:15":true,"9:15":true,"10:15":true,"5:15":true,"7:14":true,"13:15":true,"11:14":true,"8:15":true,"6:14":true,"12:15":true,"1:15":true,"11:15":true,"8:14":true,"6:15":true} \ No newline at end of file
+{
+ "9:14": true,
+ "4:14": true,
+ "10:14": true,
+ "5:14": true,
+ "7:15": true,
+ "14:15": true,
+ "9:15": true,
+ "10:15": true,
+ "5:15": true,
+ "7:14": true,
+ "13:15": true,
+ "11:14": true,
+ "8:15": true,
+ "6:14": true,
+ "12:15": true,
+ "1:15": true,
+ "11:15": true,
+ "8:14": true,
+ "6:15": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/8_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/8_1.json
index 4b3610ad..917a084f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/8_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/8_1.json
@@ -1 +1,144 @@
-{"9:14":true,"1:1":true,"11:5":[163,254],"8:8":true,"7:12":true,"6:10":true,"10:14":true,"7:15":true,"11:11":true,"10:12":254,"3:0":true,"9:15":true,"0:0":true,"8:1":true,"10:15":true,"7:14":true,"14:1":true,"8:7":true,"0:2":true,"7:13":true,"3:2":true,"15:1":true,"10:13":true,"0:3":true,"8:9":254,"7:10":[184,254],"6:12":true,"3:3":true,"9:13":true,"2:1":true,"11:0":true,"4:3":true,"7:7":true,"5:3":true,"2:15":true,"12:0":true,"9:9":true,"8:10":254,"7:9":[184,254],"6:8":true,"13:1":true,"4:2":true,"9:7":true,"2:14":true,"1:13":true,"11:4":[163,254],"1:14":true,"9:1":true,"7:8":[183,254],"6:9":254,"2:13":true,"5:0":true,"10:1":true,"11:3":true,"8:15":true,"4:0":true,"12:2":true,"1:15":true,"10:8":true,"6:7":254,"11:2":true,"8:14":true,"9:8":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"3:13":true,"10:3":true,"0:13":true,"7:2":true,"6:6":true,"11:1":true,"7:4":true,"9:2":true,"13:0":true,"10:2":true,"7:3":true,"13:2":true,"0:15":true,"6:4":true,"10:0":true,"3:15":true,"9:0":true,"7:0":true,"13:3":true,"0:14":true,"13:4":[165,167],"3:14":true,"7:6":true,"15:4":[159,166],"14:3":true,"4:14":true,"6:5":true,"2:2":true,"15:3":true,"6:11":true,"1:0":true,"14:4":true,"11:13":254,"8:0":true,"14:2":true,"0:1":true,"15:2":true,"8:6":true,"3:1":true,"2:3":true,"15:0":true,"1:3":true,"11:14":true,"8:2":true,"14:0":true,"2:0":true,"11:12":254,"5:13":true,"1:2":true,"7:5":true,"11:15":true,"7:11":true,"4:13":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:1": true,
+ "11:5": [
+ 163,
+ 254
+ ],
+ "8:8": true,
+ "7:12": true,
+ "6:10": true,
+ "10:14": true,
+ "7:15": true,
+ "11:11": true,
+ "10:12": 254,
+ "3:0": true,
+ "9:15": true,
+ "0:0": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "14:1": true,
+ "8:7": true,
+ "0:2": true,
+ "7:13": true,
+ "3:2": true,
+ "15:1": true,
+ "10:13": true,
+ "0:3": true,
+ "8:9": 254,
+ "7:10": [
+ 184,
+ 254
+ ],
+ "6:12": true,
+ "3:3": true,
+ "9:13": true,
+ "2:1": true,
+ "11:0": true,
+ "4:3": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "12:0": true,
+ "9:9": true,
+ "8:10": 254,
+ "7:9": [
+ 184,
+ 254
+ ],
+ "6:8": true,
+ "13:1": true,
+ "4:2": true,
+ "9:7": true,
+ "2:14": true,
+ "1:13": true,
+ "11:4": [
+ 163,
+ 254
+ ],
+ "1:14": true,
+ "9:1": true,
+ "7:8": [
+ 183,
+ 254
+ ],
+ "6:9": 254,
+ "2:13": true,
+ "5:0": true,
+ "10:1": true,
+ "11:3": true,
+ "8:15": true,
+ "4:0": true,
+ "12:2": true,
+ "1:15": true,
+ "10:8": true,
+ "6:7": 254,
+ "11:2": true,
+ "8:14": true,
+ "9:8": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "3:13": true,
+ "10:3": true,
+ "0:13": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "7:4": true,
+ "9:2": true,
+ "13:0": true,
+ "10:2": true,
+ "7:3": true,
+ "13:2": true,
+ "0:15": true,
+ "6:4": true,
+ "10:0": true,
+ "3:15": true,
+ "9:0": true,
+ "7:0": true,
+ "13:3": true,
+ "0:14": true,
+ "13:4": [
+ 165,
+ 167
+ ],
+ "3:14": true,
+ "7:6": true,
+ "15:4": [
+ 159,
+ 166
+ ],
+ "14:3": true,
+ "4:14": true,
+ "6:5": true,
+ "2:2": true,
+ "15:3": true,
+ "6:11": true,
+ "1:0": true,
+ "14:4": true,
+ "11:13": 254,
+ "8:0": true,
+ "14:2": true,
+ "0:1": true,
+ "15:2": true,
+ "8:6": true,
+ "3:1": true,
+ "2:3": true,
+ "15:0": true,
+ "1:3": true,
+ "11:14": true,
+ "8:2": true,
+ "14:0": true,
+ "2:0": true,
+ "11:12": 254,
+ "5:13": true,
+ "1:2": true,
+ "7:5": true,
+ "11:15": true,
+ "7:11": true,
+ "4:13": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/9_-1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/9_-1.json
index 4887712a..979a9b2f 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/9_-1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/9_-1.json
@@ -1 +1,35 @@
-{"9:14":true,"1:6":true,"8:13":true,"7:12":true,"6:10":true,"5:9":true,"1:5":true,"0:13":true,"4:9":true,"3:5":true,"2:4":true,"9:15":true,"0:1":true,"0:0":true,"4:7":true,"3:6":true,"7:14":true,"5:10":true,"1:3":true,"1:14":186,"7:13":true,"5:11":[220,221],"8:15":true,"0:7":true,"1:2":true,"1:15":true,"6:12":true,"5:8":true,"7:11":true,"2:6":true} \ No newline at end of file
+{
+ "9:14": true,
+ "1:6": true,
+ "8:13": true,
+ "7:12": true,
+ "6:10": true,
+ "5:9": true,
+ "1:5": true,
+ "0:13": true,
+ "4:9": true,
+ "3:5": true,
+ "2:4": true,
+ "9:15": true,
+ "0:1": true,
+ "0:0": true,
+ "4:7": true,
+ "3:6": true,
+ "7:14": true,
+ "5:10": true,
+ "1:3": true,
+ "1:14": 186,
+ "7:13": true,
+ "5:11": [
+ 220,
+ 221
+ ],
+ "8:15": true,
+ "0:7": true,
+ "1:2": true,
+ "1:15": true,
+ "6:12": true,
+ "5:8": true,
+ "7:11": true,
+ "2:6": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/9_1.json b/src/main/resources/assets/notenoughupdates/dwarven_data/9_1.json
index c4fd1b66..f957a1ba 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/9_1.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/9_1.json
@@ -1 +1,280 @@
-{"1:1":true,"8:8":true,"6:10":true,"13:13":true,"3:0":true,"0:0":true,"3:6":true,"14:1":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"4:11":254,"0:2":true,"9:10":true,"5:11":[182,186],"4:5":true,"13:12":true,"3:2":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"0:4":true,"2:1":true,"14:14":true,"4:3":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"15:14":true,"9:9":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":true,"14:15":true,"4:2":true,"15:15":true,"14:12":true,"9:7":true,"3:11":true,"5:2":true,"2:14":true,"1:13":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"4:0":true,"15:13":true,"1:15":254,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":true,"1:11":true,"3:13":true,"1:5":true,"11:8":true,"12:8":true,"14:11":true,"4:1":true,"3:12":true,"11:9":true,"15:5":[157,158],"14:5":true,"5:1":true,"3:15":true,"15:11":true,"12:9":true,"11:7":true,"2:5":true,"12:7":true,"3:14":true,"2:11":true,"14:3":true,"4:14":true,"1:6":254,"11:10":[160,236],"12:10":[159,236],"5:14":true,"2:2":true,"1:0":true,"14:4":true,"5:12":[182,186],"2:4":true,"14:2":true,"13:11":true,"4:15":true,"0:1":true,"4:12":true,"3:1":true,"13:5":true,"5:15":true,"2:3":true,"14:6":true,"1:3":true,"1:4":true,"15:6":[155,158],"14:0":true,"2:0":true,"5:13":true,"1:2":true,"4:13":true,"2:6":true,"15:9":[154,156],"12:11":true,"9:14":[172,236],"11:5":true,"7:12":[236,251],"12:5":true,"10:14":true,"7:15":true,"14:9":[157,233],"11:11":[159,236],"10:12":true,"6:13":true,"15:7":[155,158],"9:15":true,"14:7":[232,233],"9:12":true,"8:1":true,"10:15":true,"7:14":true,"7:13":[236,252],"6:14":true,"15:8":[155,157],"10:13":true,"6:15":true,"14:8":[158,233],"9:13":true,"11:0":true,"12:6":true,"8:13":[174,236],"1:10":true,"12:0":true,"11:6":true,"11:4":true,"9:1":true,"8:12":true,"12:3":true,"15:10":true,"14:10":[169,232],"10:1":true,"12:4":true,"11:3":true,"8:15":[176,235],"12:2":true,"2:10":254,"11:2":true,"8:14":[175,236],"13:9":[159,160],"7:1":true,"12:1":true,"9:3":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":254,"7:4":true,"9:2":true,"8:11":true,"10:2":true,"7:3":true,"9:6":true,"10:0":true,"10:6":true,"9:0":true,"7:0":true,"5:8":true,"7:6":true,"6:11":true,"11:13":true,"8:0":true,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":[157,186],"3:7":true,"10:11":true,"9:5":true,"4:10":254,"11:14":true,"8:2":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": true,
+ "0:0": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": 254,
+ "0:2": true,
+ "9:10": true,
+ "5:11": [
+ 182,
+ 186
+ ],
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "0:4": true,
+ "2:1": true,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": true,
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": true,
+ "14:15": true,
+ "4:2": true,
+ "15:15": true,
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "2:14": true,
+ "1:13": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": true,
+ "1:15": 254,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": true,
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "11:8": true,
+ "12:8": true,
+ "14:11": true,
+ "4:1": true,
+ "3:12": true,
+ "11:9": true,
+ "15:5": [
+ 157,
+ 158
+ ],
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "15:11": true,
+ "12:9": true,
+ "11:7": true,
+ "2:5": true,
+ "12:7": true,
+ "3:14": true,
+ "2:11": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": 254,
+ "11:10": [
+ 160,
+ 236
+ ],
+ "12:10": [
+ 159,
+ 236
+ ],
+ "5:14": true,
+ "2:2": true,
+ "1:0": true,
+ "14:4": true,
+ "5:12": [
+ 182,
+ 186
+ ],
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "0:1": true,
+ "4:12": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "15:6": [
+ 155,
+ 158
+ ],
+ "14:0": true,
+ "2:0": true,
+ "5:13": true,
+ "1:2": true,
+ "4:13": true,
+ "2:6": true,
+ "15:9": [
+ 154,
+ 156
+ ],
+ "12:11": true,
+ "9:14": [
+ 172,
+ 236
+ ],
+ "11:5": true,
+ "7:12": [
+ 236,
+ 251
+ ],
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": [
+ 157,
+ 233
+ ],
+ "11:11": [
+ 159,
+ 236
+ ],
+ "10:12": true,
+ "6:13": true,
+ "15:7": [
+ 155,
+ 158
+ ],
+ "9:15": true,
+ "14:7": [
+ 232,
+ 233
+ ],
+ "9:12": true,
+ "8:1": true,
+ "10:15": true,
+ "7:14": true,
+ "7:13": [
+ 236,
+ 252
+ ],
+ "6:14": true,
+ "15:8": [
+ 155,
+ 157
+ ],
+ "10:13": true,
+ "6:15": true,
+ "14:8": [
+ 158,
+ 233
+ ],
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": [
+ 174,
+ 236
+ ],
+ "1:10": true,
+ "12:0": true,
+ "11:6": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "12:3": true,
+ "15:10": true,
+ "14:10": [
+ 169,
+ 232
+ ],
+ "10:1": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": [
+ 176,
+ 235
+ ],
+ "12:2": true,
+ "2:10": 254,
+ "11:2": true,
+ "8:14": [
+ 175,
+ 236
+ ],
+ "13:9": [
+ 159,
+ 160
+ ],
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": 254,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "7:0": true,
+ "5:8": true,
+ "7:6": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": true,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": [
+ 157,
+ 186
+ ],
+ "3:7": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": 254,
+ "11:14": true,
+ "8:2": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/9_2.json b/src/main/resources/assets/notenoughupdates/dwarven_data/9_2.json
index c7c85d2d..77777607 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/9_2.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/9_2.json
@@ -1 +1,217 @@
-{"1:1":true,"8:8":true,"6:10":true,"3:0":true,"0:6":true,"3:6":true,"14:1":true,"13:15":true,"10:10":true,"8:7":true,"5:5":true,"9:10":true,"5:11":true,"4:5":true,"3:2":true,"15:1":true,"3:4":true,"8:9":true,"7:10":true,"2:1":true,"14:14":true,"4:3":true,"5:4":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"9:9":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"14:15":true,"13:1":true,"4:2":true,"9:7":true,"5:2":true,"2:14":true,"7:8":true,"6:9":true,"1:14":true,"5:0":[182,186],"5:6":true,"4:0":254,"1:15":true,"10:8":true,"6:7":true,"9:8":true,"14:13":true,"11:8":true,"13:6":true,"13:0":true,"12:8":true,"13:2":true,"4:1":true,"11:9":true,"15:5":true,"14:5":true,"5:1":[182,186],"3:15":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"12:7":true,"3:14":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"5:14":true,"2:2":true,"15:3":true,"1:0":true,"14:4":true,"5:12":true,"14:2":true,"4:15":true,"15:2":true,"3:1":true,"13:5":true,"5:15":true,"15:0":true,"14:6":true,"15:6":true,"14:0":true,"2:0":254,"5:13":true,"1:2":true,"2:6":true,"15:9":true,"12:11":true,"9:14":true,"11:5":true,"2:7":true,"7:12":true,"12:5":true,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":[177,233],"10:15":true,"7:14":true,"1:8":true,"7:13":true,"6:14":true,"15:8":true,"10:13":true,"6:12":true,"1:7":true,"6:15":true,"14:8":true,"9:13":true,"11:0":true,"12:6":true,"8:13":true,"13:8":true,"12:0":true,"6:1":182,"11:6":true,"12:3":true,"11:4":true,"9:1":[132,233],"8:12":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"12:2":true,"11:2":true,"8:14":true,"13:9":true,"7:1":[181,251],"12:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"6:6":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"7:4":true,"9:2":true,"8:11":true,"10:2":true,"7:3":true,"9:6":true,"6:4":true,"10:0":true,"10:6":true,"9:0":[174,240],"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"6:5":true,"0:8":true,"6:11":true,"11:13":true,"8:0":[177,240],"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"10:11":true,"9:5":true,"11:14":true,"8:2":true,"0:7":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "3:0": true,
+ "0:6": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": true,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "3:2": true,
+ "15:1": true,
+ "3:4": true,
+ "8:9": true,
+ "7:10": true,
+ "2:1": true,
+ "14:14": true,
+ "4:3": true,
+ "5:4": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "9:7": true,
+ "5:2": true,
+ "2:14": true,
+ "7:8": true,
+ "6:9": true,
+ "1:14": true,
+ "5:0": [
+ 182,
+ 186
+ ],
+ "5:6": true,
+ "4:0": 254,
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "9:8": true,
+ "14:13": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "13:2": true,
+ "4:1": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": [
+ 182,
+ 186
+ ],
+ "3:15": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "12:7": true,
+ "3:14": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "5:14": true,
+ "2:2": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "5:12": true,
+ "14:2": true,
+ "4:15": true,
+ "15:2": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": true,
+ "15:0": true,
+ "14:6": true,
+ "15:6": true,
+ "14:0": true,
+ "2:0": 254,
+ "5:13": true,
+ "1:2": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "2:7": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": [
+ 177,
+ 233
+ ],
+ "10:15": true,
+ "7:14": true,
+ "1:8": true,
+ "7:13": true,
+ "6:14": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "1:7": true,
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": 182,
+ "11:6": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": [
+ 132,
+ 233
+ ],
+ "8:12": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "7:1": [
+ 181,
+ 251
+ ],
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": [
+ 174,
+ 240
+ ],
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "6:5": true,
+ "0:8": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": [
+ 177,
+ 240
+ ],
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "10:11": true,
+ "9:5": true,
+ "11:14": true,
+ "8:2": true,
+ "0:7": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/9_5.json b/src/main/resources/assets/notenoughupdates/dwarven_data/9_5.json
index 51fce837..03686205 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/9_5.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/9_5.json
@@ -1 +1,253 @@
-{"1:1":true,"8:8":true,"6:10":true,"13:13":true,"3:0":true,"0:0":true,"3:6":true,"14:1":true,"13:15":172,"10:10":true,"8:7":true,"5:5":true,"4:11":true,"0:2":true,"9:10":true,"5:11":true,"4:5":true,"13:12":true,"3:2":true,"15:1":true,"13:14":true,"3:4":true,"0:3":true,"8:9":true,"7:10":true,"3:3":true,"2:1":true,"14:14":[172,228],"4:3":true,"5:4":true,"2:12":true,"10:9":true,"7:7":true,"5:3":true,"2:15":true,"15:14":[158,171],"9:9":true,"4:4":true,"10:7":true,"8:10":true,"7:9":true,"6:8":true,"3:5":true,"15:12":[172,173],"14:15":[158,227],"13:1":true,"4:2":true,"15:15":[164,170],"14:12":true,"9:7":true,"3:11":true,"5:2":true,"2:14":true,"1:13":true,"2:13":true,"7:8":true,"6:9":true,"4:6":true,"1:14":true,"5:0":true,"5:6":true,"4:0":true,"15:13":[171,172],"1:15":true,"10:8":true,"6:7":true,"1:12":true,"9:8":true,"14:13":[173,229],"1:11":true,"3:13":true,"1:5":true,"11:8":true,"13:6":true,"13:0":true,"12:8":true,"14:11":true,"13:2":true,"4:1":true,"3:12":true,"11:9":true,"15:5":true,"14:5":true,"5:1":true,"3:15":true,"15:11":true,"12:9":true,"13:3":true,"11:7":true,"2:5":true,"13:4":true,"12:7":true,"3:14":true,"2:11":true,"15:4":true,"14:3":true,"4:14":true,"1:6":true,"11:10":true,"12:10":true,"5:14":true,"2:2":true,"15:3":true,"1:0":true,"14:4":true,"5:12":true,"2:4":true,"14:2":true,"13:11":true,"4:15":true,"15:2":true,"4:12":true,"3:1":true,"13:5":true,"5:15":true,"2:3":true,"15:0":true,"14:6":true,"1:3":true,"1:4":true,"14:0":true,"2:0":true,"5:13":true,"1:2":true,"4:13":true,"2:6":true,"15:9":true,"12:11":true,"9:14":true,"11:5":true,"7:12":true,"12:5":true,"10:14":true,"7:15":true,"14:9":true,"11:11":true,"10:12":true,"6:13":true,"15:7":true,"9:15":true,"14:7":true,"9:12":true,"8:1":true,"13:10":true,"10:15":true,"7:14":true,"7:13":true,"6:14":true,"15:8":true,"10:13":true,"6:12":true,"6:15":true,"14:8":true,"9:13":true,"11:0":true,"12:6":true,"8:13":true,"1:10":true,"13:8":true,"12:0":true,"6:1":true,"11:6":true,"11:4":true,"9:1":true,"8:12":true,"12:3":true,"15:10":true,"14:10":true,"10:1":true,"13:7":true,"12:4":true,"11:3":true,"8:15":true,"12:2":true,"2:10":true,"11:2":true,"8:14":true,"13:9":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"10:4":true,"5:9":true,"10:3":true,"7:2":true,"6:6":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"3:10":true,"7:4":true,"9:2":true,"8:11":true,"10:2":true,"7:3":true,"9:6":true,"6:4":true,"10:0":true,"10:6":true,"9:0":true,"6:3":true,"7:0":true,"5:8":true,"6:2":true,"7:6":true,"6:5":true,"6:11":true,"11:13":true,"8:0":true,"8:6":true,"12:13":true,"12:14":true,"10:5":true,"9:11":true,"5:10":true,"10:11":true,"9:5":true,"4:10":true,"11:14":true,"8:2":true,"12:15":true,"11:12":true,"8:4":true,"7:5":true,"12:12":true,"11:15":true,"8:3":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "8:8": true,
+ "6:10": true,
+ "13:13": true,
+ "3:0": true,
+ "0:0": true,
+ "3:6": true,
+ "14:1": true,
+ "13:15": 172,
+ "10:10": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "0:2": true,
+ "9:10": true,
+ "5:11": true,
+ "4:5": true,
+ "13:12": true,
+ "3:2": true,
+ "15:1": true,
+ "13:14": true,
+ "3:4": true,
+ "0:3": true,
+ "8:9": true,
+ "7:10": true,
+ "3:3": true,
+ "2:1": true,
+ "14:14": [
+ 172,
+ 228
+ ],
+ "4:3": true,
+ "5:4": true,
+ "2:12": true,
+ "10:9": true,
+ "7:7": true,
+ "5:3": true,
+ "2:15": true,
+ "15:14": [
+ 158,
+ 171
+ ],
+ "9:9": true,
+ "4:4": true,
+ "10:7": true,
+ "8:10": true,
+ "7:9": true,
+ "6:8": true,
+ "3:5": true,
+ "15:12": [
+ 172,
+ 173
+ ],
+ "14:15": [
+ 158,
+ 227
+ ],
+ "13:1": true,
+ "4:2": true,
+ "15:15": [
+ 164,
+ 170
+ ],
+ "14:12": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "2:14": true,
+ "1:13": true,
+ "2:13": true,
+ "7:8": true,
+ "6:9": true,
+ "4:6": true,
+ "1:14": true,
+ "5:0": true,
+ "5:6": true,
+ "4:0": true,
+ "15:13": [
+ 171,
+ 172
+ ],
+ "1:15": true,
+ "10:8": true,
+ "6:7": true,
+ "1:12": true,
+ "9:8": true,
+ "14:13": [
+ 173,
+ 229
+ ],
+ "1:11": true,
+ "3:13": true,
+ "1:5": true,
+ "11:8": true,
+ "13:6": true,
+ "13:0": true,
+ "12:8": true,
+ "14:11": true,
+ "13:2": true,
+ "4:1": true,
+ "3:12": true,
+ "11:9": true,
+ "15:5": true,
+ "14:5": true,
+ "5:1": true,
+ "3:15": true,
+ "15:11": true,
+ "12:9": true,
+ "13:3": true,
+ "11:7": true,
+ "2:5": true,
+ "13:4": true,
+ "12:7": true,
+ "3:14": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "4:14": true,
+ "1:6": true,
+ "11:10": true,
+ "12:10": true,
+ "5:14": true,
+ "2:2": true,
+ "15:3": true,
+ "1:0": true,
+ "14:4": true,
+ "5:12": true,
+ "2:4": true,
+ "14:2": true,
+ "13:11": true,
+ "4:15": true,
+ "15:2": true,
+ "4:12": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": true,
+ "2:3": true,
+ "15:0": true,
+ "14:6": true,
+ "1:3": true,
+ "1:4": true,
+ "14:0": true,
+ "2:0": true,
+ "5:13": true,
+ "1:2": true,
+ "4:13": true,
+ "2:6": true,
+ "15:9": true,
+ "12:11": true,
+ "9:14": true,
+ "11:5": true,
+ "7:12": true,
+ "12:5": true,
+ "10:14": true,
+ "7:15": true,
+ "14:9": true,
+ "11:11": true,
+ "10:12": true,
+ "6:13": true,
+ "15:7": true,
+ "9:15": true,
+ "14:7": true,
+ "9:12": true,
+ "8:1": true,
+ "13:10": true,
+ "10:15": true,
+ "7:14": true,
+ "7:13": true,
+ "6:14": true,
+ "15:8": true,
+ "10:13": true,
+ "6:12": true,
+ "6:15": true,
+ "14:8": true,
+ "9:13": true,
+ "11:0": true,
+ "12:6": true,
+ "8:13": true,
+ "1:10": true,
+ "13:8": true,
+ "12:0": true,
+ "6:1": true,
+ "11:6": true,
+ "11:4": true,
+ "9:1": true,
+ "8:12": true,
+ "12:3": true,
+ "15:10": true,
+ "14:10": true,
+ "10:1": true,
+ "13:7": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "12:2": true,
+ "2:10": true,
+ "11:2": true,
+ "8:14": true,
+ "13:9": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "10:4": true,
+ "5:9": true,
+ "10:3": true,
+ "7:2": true,
+ "6:6": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "3:10": true,
+ "7:4": true,
+ "9:2": true,
+ "8:11": true,
+ "10:2": true,
+ "7:3": true,
+ "9:6": true,
+ "6:4": true,
+ "10:0": true,
+ "10:6": true,
+ "9:0": true,
+ "6:3": true,
+ "7:0": true,
+ "5:8": true,
+ "6:2": true,
+ "7:6": true,
+ "6:5": true,
+ "6:11": true,
+ "11:13": true,
+ "8:0": true,
+ "8:6": true,
+ "12:13": true,
+ "12:14": true,
+ "10:5": true,
+ "9:11": true,
+ "5:10": true,
+ "10:11": true,
+ "9:5": true,
+ "4:10": true,
+ "11:14": true,
+ "8:2": true,
+ "12:15": true,
+ "11:12": true,
+ "8:4": true,
+ "7:5": true,
+ "12:12": true,
+ "11:15": true,
+ "8:3": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/9_6.json b/src/main/resources/assets/notenoughupdates/dwarven_data/9_6.json
index fab5a1e8..1cad6220 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/9_6.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/9_6.json
@@ -1 +1,129 @@
-{"1:1":true,"11:5":true,"2:7":true,"8:8":true,"12:5":true,"7:15":true,"2:9":true,"3:0":true,"9:15":true,"8:1":true,"10:15":true,"14:1":true,"13:15":true,"8:7":true,"5:5":true,"4:11":true,"5:11":true,"3:2":true,"15:1":true,"1:9":true,"1:7":true,"6:15":true,"2:1":true,"11:0":true,"12:6":true,"5:4":true,"5:3":true,"2:15":true,"12:0":234,"6:1":true,"11:6":true,"10:7":true,"14:15":true,"13:1":true,"4:2":true,"0:11":true,"15:15":true,"9:7":true,"3:11":true,"5:2":true,"12:3":true,"11:4":true,"9:1":true,"7:8":true,"5:0":true,"10:1":true,"5:6":true,"12:4":true,"11:3":true,"8:15":true,"4:0":true,"12:2":true,"1:15":true,"10:8":true,"11:2":true,"9:8":true,"7:1":true,"12:1":true,"9:3":true,"6:0":true,"1:11":true,"10:4":true,"10:3":true,"0:13":true,"7:2":true,"11:1":true,"9:4":true,"8:5":true,"5:7":true,"7:4":true,"13:6":true,"9:2":true,"13:0":172,"8:11":true,"4:7":true,"10:2":true,"7:3":true,"13:2":true,"9:6":true,"4:1":true,"0:15":true,"10:0":true,"14:5":true,"10:6":true,"5:1":true,"3:15":true,"9:0":true,"7:0":true,"13:3":true,"11:7":true,"0:14":true,"13:4":true,"12:7":true,"2:11":true,"15:4":true,"14:3":true,"2:2":true,"15:3":true,"6:11":true,"1:0":true,"14:4":true,"8:0":true,"14:2":true,"4:15":true,"15:2":true,"8:6":true,"3:1":true,"13:5":true,"5:15":true,"15:0":true,"10:5":true,"9:11":true,"3:7":true,"9:5":true,"8:2":true,"0:7":true,"14:0":true,"2:0":true,"12:15":true,"8:4":true,"1:2":true,"7:5":true,"3:9":true,"11:15":true,"8:3":true,"0:9":true,"7:11":true} \ No newline at end of file
+{
+ "1:1": true,
+ "11:5": true,
+ "2:7": true,
+ "8:8": true,
+ "12:5": true,
+ "7:15": true,
+ "2:9": true,
+ "3:0": true,
+ "9:15": true,
+ "8:1": true,
+ "10:15": true,
+ "14:1": true,
+ "13:15": true,
+ "8:7": true,
+ "5:5": true,
+ "4:11": true,
+ "5:11": true,
+ "3:2": true,
+ "15:1": true,
+ "1:9": true,
+ "1:7": true,
+ "6:15": true,
+ "2:1": true,
+ "11:0": true,
+ "12:6": true,
+ "5:4": true,
+ "5:3": true,
+ "2:15": true,
+ "12:0": 234,
+ "6:1": true,
+ "11:6": true,
+ "10:7": true,
+ "14:15": true,
+ "13:1": true,
+ "4:2": true,
+ "0:11": true,
+ "15:15": true,
+ "9:7": true,
+ "3:11": true,
+ "5:2": true,
+ "12:3": true,
+ "11:4": true,
+ "9:1": true,
+ "7:8": true,
+ "5:0": true,
+ "10:1": true,
+ "5:6": true,
+ "12:4": true,
+ "11:3": true,
+ "8:15": true,
+ "4:0": true,
+ "12:2": true,
+ "1:15": true,
+ "10:8": true,
+ "11:2": true,
+ "9:8": true,
+ "7:1": true,
+ "12:1": true,
+ "9:3": true,
+ "6:0": true,
+ "1:11": true,
+ "10:4": true,
+ "10:3": true,
+ "0:13": true,
+ "7:2": true,
+ "11:1": true,
+ "9:4": true,
+ "8:5": true,
+ "5:7": true,
+ "7:4": true,
+ "13:6": true,
+ "9:2": true,
+ "13:0": 172,
+ "8:11": true,
+ "4:7": true,
+ "10:2": true,
+ "7:3": true,
+ "13:2": true,
+ "9:6": true,
+ "4:1": true,
+ "0:15": true,
+ "10:0": true,
+ "14:5": true,
+ "10:6": true,
+ "5:1": true,
+ "3:15": true,
+ "9:0": true,
+ "7:0": true,
+ "13:3": true,
+ "11:7": true,
+ "0:14": true,
+ "13:4": true,
+ "12:7": true,
+ "2:11": true,
+ "15:4": true,
+ "14:3": true,
+ "2:2": true,
+ "15:3": true,
+ "6:11": true,
+ "1:0": true,
+ "14:4": true,
+ "8:0": true,
+ "14:2": true,
+ "4:15": true,
+ "15:2": true,
+ "8:6": true,
+ "3:1": true,
+ "13:5": true,
+ "5:15": true,
+ "15:0": true,
+ "10:5": true,
+ "9:11": true,
+ "3:7": true,
+ "9:5": true,
+ "8:2": true,
+ "0:7": true,
+ "14:0": true,
+ "2:0": true,
+ "12:15": true,
+ "8:4": true,
+ "1:2": true,
+ "7:5": true,
+ "3:9": true,
+ "11:15": true,
+ "8:3": true,
+ "0:9": true,
+ "7:11": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dwarven_data/all.json b/src/main/resources/assets/notenoughupdates/dwarven_data/all.json
index 18d6bee9..a0831fbf 100644
--- a/src/main/resources/assets/notenoughupdates/dwarven_data/all.json
+++ b/src/main/resources/assets/notenoughupdates/dwarven_data/all.json
@@ -1 +1,206 @@
-{"1_-6":true,"0_-1":true,"8_8":true,"6_10":true,"-1_-2":true,"-9_5":true,"-2_-9":true,"-1_4":true,"-7_10":true,"-2_5":true,"10_10":true,"-1_6":true,"5_11":true,"4_5":true,"0_-5":true,"0_-3":true,"-1_-4":true,"-3_-10":true,"2_12":true,"5_4":true,"0_-9":true,"7_7":true,"-1_-8":true,"9_9":true,"8_10":true,"7_9":true,"6_8":true,"-4_-9":true,"9_7":true,"-3_-8":true,"0_5":true,"-1_-10":true,"-11_1":true,"5_6":true,"-13_1":true,"10_8":true,"1_11":true,"-9_1":true,"7_16":true,"4_-7":true,"-13_-3":true,"9_16":true,"-12_11":true,"12_8":true,"11_9":true,"1_-8":true,"-13_-1":true,"2_-9":true,"-11_-1":true,"11_7":true,"2_5":true,"1_-10":true,"1_6":true,"-14_11":true,"6_17":true,"12_10":true,"-10_11":true,"-12_0":true,"1_-4":true,"4_12":true,"2_-3":true,"10_17":true,"-1_-6":true,"1_4":true,"-4_-7":true,"-12_-2":true,"0_-7":true,"-3_-6":true,"7_15":true,"11_11":true,"10_12":true,"9_15":true,"7_13":true,"-11_10":true,"6_14":true,"-12_9":true,"6_12":true,"-5_-7":true,"-13_10":true,"9_13":true,"5_16":true,"8_12":true,"6_-7":true,"-10_9":true,"-7_-7":true,"8_14":true,"11_2":true,"2_-11":true,"-5_-9":true,"9_4":true,"8_5":true,"0_-11":true,"-6_11":true,"9_0":true,"-7_-9":true,"11_13":true,"-7_5":true,"-2_-11":true,"9_11":true,"12_12":true,"8_3":true,"7_11":true,"8_-3":true,"0_-4":true,"-1_-3":true,"0_6":true,"-12_1":true,"-1_-5":true,"8_7":true,"4_11":true,"5_5":true,"-2_-10":true,"1_-7":true,"9_10":true,"-1_-1":true,"8_9":true,"7_10":true,"0_4":true,"2_-6":true,"0_-2":true,"-9_6":true,"10_9":true,"-10_1":true,"4_4":true,"10_7":true,"0_11":true,"7_8":true,"6_9":true,"-4_-8":true,"0_-10":true,"-1_5":true,"-3_-9":true,"0_-8":true,"-1_-9":true,"6_7":true,"9_8":true,"5_-7":true,"2_-10":true,"-11_-2":true,"1_5":true,"-11_4":true,"1_-9":true,"-13_-2":true,"10_16":true,"-2_-6":true,"3_12":true,"-11_0":true,"12_9":true,"12_7":true,"6_16":true,"-13_0":true,"2_11":true,"-10_5":true,"11_10":true,"-12_-1":true,"-1_-7":true,"5_12":true,"0_-6":true,"-3_-7":true,"-11_11":true,"9_17":true,"8_16":true,"-13_11":true,"1_-5":true,"-12_-3":true,"-10_10":true,"12_11":true,"9_14":true,"11_5":true,"7_12":true,"-6_-7":true,"6_13":true,"9_12":true,"7_14":true,"5_17":true,"10_13":true,"6_15":true,"1_-11":true,"8_13":true,"-11_9":true,"6_-6":true,"-12_10":true,"8_15":true,"9_3":true,"-5_11":true,"3_-11":true,"8_11":true,"10_2":true,"-1_-11":true,"6_4":true,"10_6":true,"-5_-8":true,"-6_-9":true,"-6_3":true,"6_11":true,"8_6":true,"12_13":true,"-7_11":true,"10_11":true,"8_2":true,"11_12":true,"8_4":true,"-7_-8":true,"-8_10":true} \ No newline at end of file
+{
+ "1_-6": true,
+ "0_-1": true,
+ "8_8": true,
+ "6_10": true,
+ "-1_-2": true,
+ "-9_5": true,
+ "-2_-9": true,
+ "-1_4": true,
+ "-7_10": true,
+ "-2_5": true,
+ "10_10": true,
+ "-1_6": true,
+ "5_11": true,
+ "4_5": true,
+ "0_-5": true,
+ "0_-3": true,
+ "-1_-4": true,
+ "-3_-10": true,
+ "2_12": true,
+ "5_4": true,
+ "0_-9": true,
+ "7_7": true,
+ "-1_-8": true,
+ "9_9": true,
+ "8_10": true,
+ "7_9": true,
+ "6_8": true,
+ "-4_-9": true,
+ "9_7": true,
+ "-3_-8": true,
+ "0_5": true,
+ "-1_-10": true,
+ "-11_1": true,
+ "5_6": true,
+ "-13_1": true,
+ "10_8": true,
+ "1_11": true,
+ "-9_1": true,
+ "7_16": true,
+ "4_-7": true,
+ "-13_-3": true,
+ "9_16": true,
+ "-12_11": true,
+ "12_8": true,
+ "11_9": true,
+ "1_-8": true,
+ "-13_-1": true,
+ "2_-9": true,
+ "-11_-1": true,
+ "11_7": true,
+ "2_5": true,
+ "1_-10": true,
+ "1_6": true,
+ "-14_11": true,
+ "6_17": true,
+ "12_10": true,
+ "-10_11": true,
+ "-12_0": true,
+ "1_-4": true,
+ "4_12": true,
+ "2_-3": true,
+ "10_17": true,
+ "-1_-6": true,
+ "1_4": true,
+ "-4_-7": true,
+ "-12_-2": true,
+ "0_-7": true,
+ "-3_-6": true,
+ "7_15": true,
+ "11_11": true,
+ "10_12": true,
+ "9_15": true,
+ "7_13": true,
+ "-11_10": true,
+ "6_14": true,
+ "-12_9": true,
+ "6_12": true,
+ "-5_-7": true,
+ "-13_10": true,
+ "9_13": true,
+ "5_16": true,
+ "8_12": true,
+ "6_-7": true,
+ "-10_9": true,
+ "-7_-7": true,
+ "8_14": true,
+ "11_2": true,
+ "2_-11": true,
+ "-5_-9": true,
+ "9_4": true,
+ "8_5": true,
+ "0_-11": true,
+ "-6_11": true,
+ "9_0": true,
+ "-7_-9": true,
+ "11_13": true,
+ "-7_5": true,
+ "-2_-11": true,
+ "9_11": true,
+ "12_12": true,
+ "8_3": true,
+ "7_11": true,
+ "8_-3": true,
+ "0_-4": true,
+ "-1_-3": true,
+ "0_6": true,
+ "-12_1": true,
+ "-1_-5": true,
+ "8_7": true,
+ "4_11": true,
+ "5_5": true,
+ "-2_-10": true,
+ "1_-7": true,
+ "9_10": true,
+ "-1_-1": true,
+ "8_9": true,
+ "7_10": true,
+ "0_4": true,
+ "2_-6": true,
+ "0_-2": true,
+ "-9_6": true,
+ "10_9": true,
+ "-10_1": true,
+ "4_4": true,
+ "10_7": true,
+ "0_11": true,
+ "7_8": true,
+ "6_9": true,
+ "-4_-8": true,
+ "0_-10": true,
+ "-1_5": true,
+ "-3_-9": true,
+ "0_-8": true,
+ "-1_-9": true,
+ "6_7": true,
+ "9_8": true,
+ "5_-7": true,
+ "2_-10": true,
+ "-11_-2": true,
+ "1_5": true,
+ "-11_4": true,
+ "1_-9": true,
+ "-13_-2": true,
+ "10_16": true,
+ "-2_-6": true,
+ "3_12": true,
+ "-11_0": true,
+ "12_9": true,
+ "12_7": true,
+ "6_16": true,
+ "-13_0": true,
+ "2_11": true,
+ "-10_5": true,
+ "11_10": true,
+ "-12_-1": true,
+ "-1_-7": true,
+ "5_12": true,
+ "0_-6": true,
+ "-3_-7": true,
+ "-11_11": true,
+ "9_17": true,
+ "8_16": true,
+ "-13_11": true,
+ "1_-5": true,
+ "-12_-3": true,
+ "-10_10": true,
+ "12_11": true,
+ "9_14": true,
+ "11_5": true,
+ "7_12": true,
+ "-6_-7": true,
+ "6_13": true,
+ "9_12": true,
+ "7_14": true,
+ "5_17": true,
+ "10_13": true,
+ "6_15": true,
+ "1_-11": true,
+ "8_13": true,
+ "-11_9": true,
+ "6_-6": true,
+ "-12_10": true,
+ "8_15": true,
+ "9_3": true,
+ "-5_11": true,
+ "3_-11": true,
+ "8_11": true,
+ "10_2": true,
+ "-1_-11": true,
+ "6_4": true,
+ "10_6": true,
+ "-5_-8": true,
+ "-6_-9": true,
+ "-6_3": true,
+ "6_11": true,
+ "8_6": true,
+ "12_13": true,
+ "-7_11": true,
+ "10_11": true,
+ "8_2": true,
+ "11_12": true,
+ "8_4": true,
+ "-7_-8": true,
+ "-8_10": true
+}
diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json
index 05dbf61a..43135433 100644
--- a/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json
+++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style1/dynamic_config.json
@@ -1,3 +1,3 @@
{
- "text-colour": "FF000000"
-} \ No newline at end of file
+ "text-colour": "FF000000"
+}
diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json
index 05dbf61a..43135433 100644
--- a/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json
+++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style2/dynamic_config.json
@@ -1,3 +1,3 @@
{
- "text-colour": "FF000000"
-} \ No newline at end of file
+ "text-colour": "FF000000"
+}
diff --git a/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json
index 5ae75066..11b64060 100644
--- a/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json
+++ b/src/main/resources/assets/notenoughupdates/dynamic_54/style3/dynamic_config.json
@@ -1,3 +1,3 @@
{
- "text-colour": "FFC8C8C8"
-} \ No newline at end of file
+ "text-colour": "FFC8C8C8"
+}
diff --git a/src/main/resources/assets/notenoughupdates/gamemodes.png b/src/main/resources/assets/notenoughupdates/gamemodes.png
deleted file mode 100644
index 8a1aa2fa..00000000
--- a/src/main/resources/assets/notenoughupdates/gamemodes.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/invbuttons/extraicons.json b/src/main/resources/assets/notenoughupdates/invbuttons/extraicons.json
index 5a99f3f0..d4e501c4 100644
--- a/src/main/resources/assets/notenoughupdates/invbuttons/extraicons.json
+++ b/src/main/resources/assets/notenoughupdates/invbuttons/extraicons.json
@@ -1,18 +1,18 @@
{
- "baubles ring": "baubles",
- "baubles gold ring": "baubles_gold",
- "cross x": "cross",
- "green check mark": "green_check",
- "white check mark": "white_check",
- "question mark help": "question",
- "settings cog config": "settings",
- "accessory ring": "accessory",
- "accessory ring gold": "accessory_gold",
- "armor chestplate": "armor",
- "armor gold chestplate": "armor_gold",
- "pet cat": "pet",
- "pet cat gold": "pet_gold",
- "skyblock menu": "skyblock_menu",
- "recipe book": "recipe",
- "search glass": "search"
-} \ No newline at end of file
+ "baubles ring": "baubles",
+ "baubles gold ring": "baubles_gold",
+ "cross x": "cross",
+ "green check mark": "green_check",
+ "white check mark": "white_check",
+ "question mark help": "question",
+ "settings cog config": "settings",
+ "accessory ring": "accessory",
+ "accessory ring gold": "accessory_gold",
+ "armor chestplate": "armor",
+ "armor gold chestplate": "armor_gold",
+ "pet cat": "pet",
+ "pet cat gold": "pet_gold",
+ "skyblock menu": "skyblock_menu",
+ "recipe book": "recipe",
+ "search glass": "search"
+}
diff --git a/src/main/resources/assets/notenoughupdates/invbuttons/presets.json b/src/main/resources/assets/notenoughupdates/invbuttons/presets.json
index 4184e6d4..4de328ae 100644
--- a/src/main/resources/assets/notenoughupdates/invbuttons/presets.json
+++ b/src/main/resources/assets/notenoughupdates/invbuttons/presets.json
@@ -1,2735 +1,2739 @@
{
- "Empty":[
- {
- "x":87,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":108,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":129,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":150,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":87,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":108,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":129,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":150,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":87,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":87,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":143,
- "y":35,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":60,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":60,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":2,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- }
- ],
- "Empty (Dark)":[
- {
- "x":87,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":"",
- "icon":""
- },
- {
- "x":108,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":"",
- "icon":""
- },
- {
- "x":129,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":"",
- "icon":""
- },
- {
- "x":150,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":"",
- "icon":""
- },
- {
- "x":87,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":108,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":129,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":150,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":87,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":105,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":87,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":105,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":143,
- "y":35,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":60,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":"",
- "icon":""
- },
- {
- "x":60,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":26,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":26,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":"",
- "icon":""
- },
- {
- "x":2,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":2,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":4,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":25,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":46,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":67,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":88,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":109,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":130,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":151,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":-19,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":4,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":25,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":46,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":67,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":88,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":109,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":130,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- },
- {
- "x":151,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":1,
- "command":""
- }
- ],
- "Simple":[
- {
- "x":87,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/warp home",
- "icon":"skull:c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"
- },
- {
- "x":108,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/warp hub",
- "icon":"skull:d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"
- },
- {
- "x":129,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/enderchest",
- "icon":"ENDER_CHEST"
- },
- {
- "x":150,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/pets",
- "icon":"extra:pet_gold"
- },
- {
- "x":87,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":108,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":129,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":150,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":87,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":87,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":143,
- "y":35,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":60,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":2,
- "command":"/wardrobe",
- "icon":"extra:baubles_gold"
- },
- {
- "x":60,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"",
- "icon":"BONE"
- },
- {
- "x":2,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- }
- ],
- "All Warps":[
- {
- "x":87,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"pets",
- "icon":"extra:pet_gold"
- },
- {
- "x":108,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/wardrobe",
- "icon":"extra:armor"
- },
- {
- "x":129,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/enderchest",
- "icon":"ENDER_CHEST"
- },
- {
- "x":150,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"hotm",
- "icon":"skull:86f06eaa3004aeed09b3d5b45d976de584e691c0e9cade133635de93d23b9edb"
- },
- {
- "x":87,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":"GOLD_BLOCK"
- },
- {
- "x":108,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":129,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":150,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/pv",
- "icon":"PAINTING"
- },
- {
- "x":87,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":87,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":143,
- "y":35,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":60,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":"extra:baubles_gold"
- },
- {
- "x":60,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/ah",
- "icon":"GOLD_BLOCK"
- },
- {
- "x":2,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/bz",
- "icon":"GOLD_BARDING"
- },
- {
- "x":2,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp home",
- "icon":"skull:c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"
- },
- {
- "x":2,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp hub",
- "icon":"skull:d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"
- },
- {
- "x":2,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp dungeon_hub",
- "icon":"skull:9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d"
- },
- {
- "x":2,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp end",
- "icon":"skull:7840b87d52271d2a755dedc82877e0ed3df67dcc42ea479ec146176b02779a5"
- },
- {
- "x":4,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp barn",
- "icon":"skull:4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b"
- },
- {
- "x":25,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp desert",
- "icon":"skull:2116b9d8df346a25edd05f842e7a9345beaf16dca4118abf5a68c75bcaae10"
- },
- {
- "x":46,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp gold",
- "icon":"skull:73bc965d579c3c6039f0a17eb7c2e6faf538c7a5de8e60ec7a719360d0a857a9"
- },
- {
- "x":67,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp deep",
- "icon":"skull:569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc"
- },
- {
- "x":88,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp mines",
- "icon":"skull:c754318a3376f470e481dfcd6c83a59aa690ad4b4dd7577fdad1c2ef08d8aee6"
- },
- {
- "x":109,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp park",
- "icon":"skull:a221f813dacee0fef8c59f76894dbb26415478d9ddfc44c2e708a6d3b7549b"
- },
- {
- "x":130,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp spider",
- "icon":"skull:9d7e3b19ac4f3dee9c5677c135333b9d35a7f568b63d1ef4ada4b068b5a25"
- },
- {
- "x":151,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"/warp nether",
- "icon":"skull:38957d5023c937c4c41aa2412d43410bda23cf79a9f6ab36b76fef2d7c429"
- }
- ],
- "More Buttons":[
- {
- "x":87,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/sbmenu",
- "icon":"SKYBLOCK_MENU"
- },
- {
- "x":108,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"enderchest",
- "icon":"ENDER_CHEST"
- },
- {
- "x":129,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"pets",
- "icon":"BONE"
- },
- {
- "x":150,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"effects",
- "icon":"POTION"
- },
- {
- "x":87,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/recipes",
- "icon":"extra:recipe"
- },
- {
- "x":108,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/collections",
- "icon":"PAINTING"
- },
- {
- "x":129,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/scg",
- "icon":"BOOK"
- },
- {
- "x":150,
- "y":5,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/calendar",
- "icon":"BOOK_AND_QUILL"
- },
- {
- "x":87,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":"CHEST"
- },
- {
- "x":105,
- "y":25,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":87,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":105,
- "y":43,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":143,
- "y":35,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"craft",
- "icon":"WORKBENCH"
- },
- {
- "x":60,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":2,
- "command":"/wardrobe",
- "icon":"extra:baubles_gold"
- },
- {
- "x":60,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":8,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":26,
- "y":60,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/warp hub",
- "icon":"skull:d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"
- },
- {
- "x":2,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/warp home",
- "icon":"skull:c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"
- },
- {
- "x":2,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x":2,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":"",
- "icon":"BONE"
- },
- {
- "x":2,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":2,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":true,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":-19,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/ah",
- "icon":"GOLD_BLOCK"
- },
- {
- "x":-19,
- "y":22,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"/bz",
- "icon":"GOLD_BARDING"
- },
- {
- "x":-19,
- "y":42,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":62,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-84,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-64,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-44,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":-19,
- "y":-24,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":4,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":25,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":46,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":67,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":88,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":109,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":130,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- },
- {
- "x":151,
- "y":2,
- "playerInvOnly":false,
- "anchorRight":false,
- "anchorBottom":true,
- "backgroundIndex":0,
- "command":""
- }
- ],
- "Dungeons":[
- {
- "x":87,
- "y":63,
- "playerInvOnly":true,
- "anchorRight":false,
- "anchorBottom":false,
- "backgroundIndex":0,
- "command":"",
- "icon":""
- },
- {
- "x": 108,
- "y": 63,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "warp dungeon_hub",
- "icon": "skull:9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d"
- },
- {
- "x": 129,
- "y": 63,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "reparty",
- "icon": "COMMAND"
- },
- {
- "x": 150,
- "y": 63,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "pets",
- "icon": "extra:pet_gold"
- },
- {
- "x": 87,
- "y": 5,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 108,
- "y": 5,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 129,
- "y": 5,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 150,
- "y": 5,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 87,
- "y": 25,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 105,
- "y": 25,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 87,
- "y": 43,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 105,
- "y": 43,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 143,
- "y": 35,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 60,
- "y": 8,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 2,
- "command": "/wardrobe",
- "icon": "extra:baubles_gold"
- },
- {
- "x": 60,
- "y": 60,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 26,
- "y": 8,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 26,
- "y": 60,
- "playerInvOnly": true,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": 22,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": 42,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": 62,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": -84,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": -64,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": "",
- "icon": ""
- },
- {
- "x": 2,
- "y": -44,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 2,
- "y": -24,
- "playerInvOnly": false,
- "anchorRight": true,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 4,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon master_catacombs 1",
- "icon": "DIAMOND_BONZO_HEAD"
- },
- {
- "x": 25,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon master_catacombs 2",
- "icon": "DIAMOND_SCARF_HEAD"
- },
- {
- "x": 46,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon master_catacombs 3",
- "icon": "DIAMOND_PROFESSOR_HEAD"
- },
- {
- "x": 67,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon master_catacombs 4",
- "icon": "DIAMOND_THORN_HEAD"
- },
- {
- "x": 88,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon master_catacombs 5",
- "icon": "DIAMOND_LIVID_HEAD"
- },
- {
- "x": 109,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon master_catacombs 6",
- "icon": "DIAMOND_SADAN_HEAD"
- },
- {
- "x": 130,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 151,
- "y": -19,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": -19,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon catacombs 1",
- "icon": "GOLD_BONZO_HEAD"
- },
- {
- "x": -19,
- "y": 22,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon catacombs 2",
- "icon": "GOLD_SCARF_HEAD"
- },
- {
- "x": -19,
- "y": 42,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon catacombs 3",
- "icon": "GOLD_PROFESSOR_HEAD"
- },
- {
- "x": -19,
- "y": 62,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": false,
- "backgroundIndex": 0,
- "command": "joindungeon catacombs 4",
- "icon": "GOLD_THORN_HEAD"
- },
- {
- "x": -19,
- "y": -84,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": "joindungeon catacombs 5",
- "icon": "GOLD_LIVID_HEAD"
- },
- {
- "x": -19,
- "y": -64,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": "/joindungeon catacombs 6",
- "icon": "GOLD_SADAN_HEAD"
- },
- {
- "x": -19,
- "y": -44,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": "joindungeon catacombs 7",
- "icon": "GOLD_NECRON_HEAD"
- },
- {
- "x": -19,
- "y": -24,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 4,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 25,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 46,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 67,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 88,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 109,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 130,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- },
- {
- "x": 151,
- "y": 2,
- "playerInvOnly": false,
- "anchorRight": false,
- "anchorBottom": true,
- "backgroundIndex": 0,
- "command": ""
- }
- ]
+ "Empty": [
+ {
+ "x": 87,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 108,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 129,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 150,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 87,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 108,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 129,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 150,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 143,
+ "y": 35,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 60,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 60,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 2,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ }
+ ],
+ "Empty (Dark)": [
+ {
+ "x": 87,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 108,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 129,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 150,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 87,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 108,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 129,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 150,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 143,
+ "y": 35,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 60,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 60,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 2,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 1,
+ "command": ""
+ }
+ ],
+ "Simple": [
+ {
+ "x": 87,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/warp home",
+ "icon": "skull:c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"
+ },
+ {
+ "x": 108,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/warp hub",
+ "icon": "skull:d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"
+ },
+ {
+ "x": 129,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/enderchest",
+ "icon": "ENDER_CHEST"
+ },
+ {
+ "x": 150,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/pets",
+ "icon": "extra:pet_gold"
+ },
+ {
+ "x": 87,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 108,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 129,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 150,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 143,
+ "y": 35,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 60,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 2,
+ "command": "/wardrobe",
+ "icon": "extra:baubles_gold"
+ },
+ {
+ "x": 60,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": "BONE"
+ },
+ {
+ "x": 2,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ }
+ ],
+ "All Warps": [
+ {
+ "x": 87,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "pets",
+ "icon": "extra:pet_gold"
+ },
+ {
+ "x": 108,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/wardrobe",
+ "icon": "extra:armor"
+ },
+ {
+ "x": 129,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/enderchest",
+ "icon": "ENDER_CHEST"
+ },
+ {
+ "x": 150,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "hotm",
+ "icon": "skull:86f06eaa3004aeed09b3d5b45d976de584e691c0e9cade133635de93d23b9edb"
+ },
+ {
+ "x": 87,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": "GOLD_BLOCK"
+ },
+ {
+ "x": 108,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 129,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 150,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/pv",
+ "icon": "PAINTING"
+ },
+ {
+ "x": 87,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 143,
+ "y": 35,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 60,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": "extra:baubles_gold"
+ },
+ {
+ "x": 60,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/ah",
+ "icon": "GOLD_BLOCK"
+ },
+ {
+ "x": 2,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/bz",
+ "icon": "GOLD_BARDING"
+ },
+ {
+ "x": 2,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "warp museum",
+ "icon": "skull:438cf3f8e54afc3b3f91d20a49f324dca1486007fe545399055524c17941f4dc"
+ },
+ {
+ "x": 2,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp home",
+ "icon": "skull:c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"
+ },
+ {
+ "x": 2,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp hub",
+ "icon": "skull:d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"
+ },
+ {
+ "x": 2,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp dungeon_hub",
+ "icon": "skull:9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d"
+ },
+ {
+ "x": 2,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp end",
+ "icon": "skull:7840b87d52271d2a755dedc82877e0ed3df67dcc42ea479ec146176b02779a5"
+ },
+ {
+ "x": 4,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "warp barn",
+ "icon": "skull:4d3a6bd98ac1833c664c4909ff8d2dc62ce887bdcf3cc5b3848651ae5af6b"
+ },
+ {
+ "x": -19,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "warp desert",
+ "icon": "skull:51539dddf9ed255ece6348193cd75012c82c93aec381f05572cecf7379711b3b"
+ },
+ {
+ "x": 4,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp gold",
+ "icon": "skull:73bc965d579c3c6039f0a17eb7c2e6faf538c7a5de8e60ec7a719360d0a857a9"
+ },
+ {
+ "x": 25,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp deep",
+ "icon": "skull:569a1f114151b4521373f34bc14c2963a5011cdc25a6554c48c708cd96ebfc"
+ },
+ {
+ "x": 46,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp crystals",
+ "icon": "skull:21dbe30b027acbceb612563bd877cd7ebb719ea6ed1399027dcee58bb9049d4a"
+ },
+ {
+ "x": 67,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp forge",
+ "icon": "skull:5cbd9f5ec1ed007259996491e69ff649a3106cf920227b1bb3a71ee7a89863f"
+ },
+ {
+ "x": 88,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp mines",
+ "icon": "skull:6b20b23c1aa2be0270f016b4c90d6ee6b8330a17cfef87869d6ad60b2ffbf3b5"
+ },
+ {
+ "x": 109,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp park",
+ "icon": "skull:a221f813dacee0fef8c59f76894dbb26415478d9ddfc44c2e708a6d3b7549b"
+ },
+ {
+ "x": 130,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp spider",
+ "icon": "skull:9d7e3b19ac4f3dee9c5677c135333b9d35a7f568b63d1ef4ada4b068b5a25"
+ },
+ {
+ "x": 151,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/warp nether",
+ "icon": "skull:c3687e25c632bce8aa61e0d64c24e694c3eea629ea944f4cf30dcfb4fbce071"
+ }
+ ],
+ "More Buttons": [
+ {
+ "x": 87,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/sbmenu",
+ "icon": "SKYBLOCK_MENU"
+ },
+ {
+ "x": 108,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "enderchest",
+ "icon": "ENDER_CHEST"
+ },
+ {
+ "x": 129,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "pets",
+ "icon": "BONE"
+ },
+ {
+ "x": 150,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "effects",
+ "icon": "POTION"
+ },
+ {
+ "x": 87,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/recipes",
+ "icon": "extra:recipe"
+ },
+ {
+ "x": 108,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/collections",
+ "icon": "PAINTING"
+ },
+ {
+ "x": 129,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/scg",
+ "icon": "BOOK"
+ },
+ {
+ "x": 150,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/calendar",
+ "icon": "BOOK_AND_QUILL"
+ },
+ {
+ "x": 87,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": "CHEST"
+ },
+ {
+ "x": 105,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 143,
+ "y": 35,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "craft",
+ "icon": "WORKBENCH"
+ },
+ {
+ "x": 60,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 2,
+ "command": "/wardrobe",
+ "icon": "extra:baubles_gold"
+ },
+ {
+ "x": 60,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/warp hub",
+ "icon": "skull:d7cc6687423d0570d556ac53e0676cb563bbdd9717cd8269bdebed6f6d4e7bf8"
+ },
+ {
+ "x": 2,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/warp home",
+ "icon": "skull:c9c8881e42915a9d29bb61a16fb26d059913204d265df5b439b3d792acd56"
+ },
+ {
+ "x": 2,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 2,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": "BONE"
+ },
+ {
+ "x": 2,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/ah",
+ "icon": "GOLD_BLOCK"
+ },
+ {
+ "x": -19,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "/bz",
+ "icon": "GOLD_BARDING"
+ },
+ {
+ "x": -19,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ }
+ ],
+ "Dungeons": [
+ {
+ "x": 87,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 108,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "warp dungeon_hub",
+ "icon": "skull:9b56895b9659896ad647f58599238af532d46db9c1b0389b8bbeb70999dab33d"
+ },
+ {
+ "x": 129,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "reparty",
+ "icon": "COMMAND"
+ },
+ {
+ "x": 150,
+ "y": 63,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "pets",
+ "icon": "extra:pet_gold"
+ },
+ {
+ "x": 87,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 108,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 129,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 150,
+ "y": 5,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 25,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 87,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 105,
+ "y": 43,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 143,
+ "y": 35,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 60,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 2,
+ "command": "/wardrobe",
+ "icon": "extra:baubles_gold"
+ },
+ {
+ "x": 60,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 8,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 26,
+ "y": 60,
+ "playerInvOnly": true,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "",
+ "icon": ""
+ },
+ {
+ "x": 2,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 2,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": true,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 1",
+ "icon": "DIAMOND_BONZO_HEAD"
+ },
+ {
+ "x": 25,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 2",
+ "icon": "DIAMOND_SCARF_HEAD"
+ },
+ {
+ "x": 46,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 3",
+ "icon": "DIAMOND_PROFESSOR_HEAD"
+ },
+ {
+ "x": 67,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 4",
+ "icon": "DIAMOND_THORN_HEAD"
+ },
+ {
+ "x": 88,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 5",
+ "icon": "DIAMOND_LIVID_HEAD"
+ },
+ {
+ "x": 109,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 6",
+ "icon": "DIAMOND_SADAN_HEAD"
+ },
+ {
+ "x": 130,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon master_catacombs 7",
+ "icon": "DIAMOND_NECRON_HEAD"
+ },
+ {
+ "x": 151,
+ "y": -19,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": -19,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon catacombs 1",
+ "icon": "GOLD_BONZO_HEAD"
+ },
+ {
+ "x": -19,
+ "y": 22,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon catacombs 2",
+ "icon": "GOLD_SCARF_HEAD"
+ },
+ {
+ "x": -19,
+ "y": 42,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon catacombs 3",
+ "icon": "GOLD_PROFESSOR_HEAD"
+ },
+ {
+ "x": -19,
+ "y": 62,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": false,
+ "backgroundIndex": 0,
+ "command": "joindungeon catacombs 4",
+ "icon": "GOLD_THORN_HEAD"
+ },
+ {
+ "x": -19,
+ "y": -84,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "joindungeon catacombs 5",
+ "icon": "GOLD_LIVID_HEAD"
+ },
+ {
+ "x": -19,
+ "y": -64,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "/joindungeon catacombs 6",
+ "icon": "GOLD_SADAN_HEAD"
+ },
+ {
+ "x": -19,
+ "y": -44,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": "joindungeon catacombs 7",
+ "icon": "GOLD_NECRON_HEAD"
+ },
+ {
+ "x": -19,
+ "y": -24,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 4,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 25,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 46,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 67,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 88,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 109,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 130,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ },
+ {
+ "x": 151,
+ "y": 2,
+ "playerInvOnly": false,
+ "anchorRight": false,
+ "anchorBottom": true,
+ "backgroundIndex": 0,
+ "command": ""
+ }
+ ]
}
diff --git a/src/main/resources/assets/notenoughupdates/logo_bg.png b/src/main/resources/assets/notenoughupdates/logo_bg.png
deleted file mode 100644
index 188c3126..00000000
--- a/src/main/resources/assets/notenoughupdates/logo_bg.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/logo_fg.png b/src/main/resources/assets/notenoughupdates/logo_fg.png
deleted file mode 100644
index 1f170cbc..00000000
--- a/src/main/resources/assets/notenoughupdates/logo_fg.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/next.png b/src/main/resources/assets/notenoughupdates/next.png
deleted file mode 100644
index d215a7e8..00000000
--- a/src/main/resources/assets/notenoughupdates/next.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/next.xcf b/src/main/resources/assets/notenoughupdates/next.xcf
deleted file mode 100644
index f93cc5b9..00000000
--- a/src/main/resources/assets/notenoughupdates/next.xcf
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/nohup.out b/src/main/resources/assets/notenoughupdates/nohup.out
deleted file mode 100644
index 14abc1f2..00000000
--- a/src/main/resources/assets/notenoughupdates/nohup.out
+++ /dev/null
@@ -1,2 +0,0 @@
-using gegl copy
-using gegl copy
diff --git a/src/main/resources/assets/notenoughupdates/official-wiki.css b/src/main/resources/assets/notenoughupdates/official-wiki.css
new file mode 100644
index 00000000..a9f82a32
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/official-wiki.css
@@ -0,0 +1 @@
+.client-js .mw-dismissable-notice { display: none}.mw-dismissable-notice-close { visibility: hidden}.sitedir-ltr .mw-dismissable-notice-close { float: right}.sitedir-rtl .mw-dismissable-notice-close { float: left}.sitedir-ltr .mw-dismissable-notice-body { margin: .5em 20% .5em 5em}.sitedir-rtl .mw-dismissable-notice-body { margin: .5em 5em .5em 20%}.hlist dl,.hlist ol,.hlist ul { margin: 0; padding: 0}.hlist dl dl,.hlist ol dl,.hlist ul dl,.hlist dl ol,.hlist ol ol,.hlist ul ol,.hlist dl ul,.hlist ol ul,.hlist ul ul { display: inline}.hlist dd,.hlist dt,.hlist li { margin: 0; display: inline}ul.hlist li,.hlist>ul li,.hlist>dl li { display: inline-block; margin-right: 8px}.hlist-separated li:after { content: '•'!important; padding-left: 8px; font-size: 1em; line-height: 1}.hlist-separated :last-child:after { content: none!important}.mw-ui-button { background-color: #f8f9fa; color: #202122; display: inline-block; -moz-box-sizing: border-box; box-sizing: border-box; border: 1px solid #a2a9b1; border-radius: 2px; cursor: pointer; vertical-align: middle; font-family: inherit; font-size: 1em; font-weight: 700; line-height: 1.28571429em; text-align: center; -webkit-appearance: none}.mw-ui-button:not(.mw-ui-icon-element) { min-height: 32px; min-width: 4em; max-width: 28.75em; margin: 0; padding: 5px 12px}.mw-ui-button:not(:disabled) { -webkit-transition: background-color 100ms,color 100ms,border-color 100ms,box-shadow 100ms; transition: background-color 100ms,color 100ms,border-color 100ms,box-shadow 100ms}.mw-ui-button:not(:disabled):visited { color: #202122}.mw-ui-button:not(:disabled):hover { background-color: #fff; color: #404244; border-color: #a2a9b1}.mw-ui-button:not(:disabled):focus { color: #202122; border-color: #36c; box-shadow: inset 0 0 0 1px #36c,inset 0 0 0 2px #fff; outline-width: 0}.mw-ui-button:not(:disabled):focus::-moz-focus-inner { border-color: transparent; padding: 0}.mw-ui-button:not(:disabled):active,.mw-ui-button:not(:disabled).is-on { background-color: #c8ccd1; color: #000; border-color: #72777d; box-shadow: none}.mw-ui-button:disabled { background-color: #c8ccd1; color: #fff; border-color: #c8ccd1; cursor: default}.mw-ui-button.mw-ui-icon-element:not(.mw-ui-icon-with-label-desktop) { color: transparent!important}.mw-ui-button.mw-ui-icon-element:not(.mw-ui-icon-with-label-desktop) span { display: block; position: absolute!important; clip: rect(1px,1px,1px,1px); width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; overflow: hidden}@media all and (max-width: 1000px) { .mw-ui-button.mw-ui-icon-element.mw-ui-icon-with-label-desktop { color:transparent!important } .mw-ui-button.mw-ui-icon-element span { display: block; position: absolute!important; clip: rect(1px,1px,1px,1px); width: 1px; height: 1px; margin: -1px; border: 0; padding: 0; overflow: hidden }}.mw-ui-button.mw-ui-quiet,.mw-ui-button.mw-ui-quiet.mw-ui-progressive,.mw-ui-button.mw-ui-quiet.mw-ui-destructive { background-color: transparent; color: #202122; border-color: transparent; font-weight: 700}.mw-ui-button.mw-ui-quiet:not(.mw-ui-icon-element),.mw-ui-button.mw-ui-quiet.mw-ui-progressive:not(.mw-ui-icon-element),.mw-ui-button.mw-ui-quiet.mw-ui-destructive:not(.mw-ui-icon-element) { min-height: 32px}input[type=checkbox]:hover+.mw-ui-button.mw-ui-quiet,input[type=checkbox]:hover+.mw-ui-button.mw-ui-quiet.mw-ui-progressive,input[type=checkbox]:hover+.mw-ui-button.mw-ui-quiet.mw-ui-destructive,.mw-ui-button.mw-ui-quiet:hover,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:hover,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:hover { background-color: rgba(0,24,73,.02745098); color: #202122; border-color: transparent}input[type=checkbox]:focus+.mw-ui-button.mw-ui-quiet,input[type=checkbox]:focus+.mw-ui-button.mw-ui-quiet.mw-ui-progressive,input[type=checkbox]:focus+.mw-ui-button.mw-ui-quiet.mw-ui-destructive,.mw-ui-button.mw-ui-quiet:focus,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:focus,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:focus { color: #202122; border-color: #36c; box-shadow: inset 0 0 0 1px #36c,inset 0 0 0 2px #fff}input[type=checkbox]:active+.mw-ui-button.mw-ui-quiet,input[type=checkbox]:active+.mw-ui-button.mw-ui-quiet.mw-ui-progressive,input[type=checkbox]:active+.mw-ui-button.mw-ui-quiet.mw-ui-destructive,.mw-ui-button.mw-ui-quiet:active,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:active,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:active { background-color: rgba(0,36,73,.08235294); color: #000; border-color: #72777d; box-shadow: none}.mw-ui-button.mw-ui-quiet:disabled,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:disabled,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:disabled,.mw-ui-button.mw-ui-quiet:disabled:hover,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:disabled:hover,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:disabled:hover,.mw-ui-button.mw-ui-quiet:disabled:active,.mw-ui-button.mw-ui-quiet.mw-ui-progressive:disabled:active,.mw-ui-button.mw-ui-quiet.mw-ui-destructive:disabled:active { background-color: transparent; color: #72777d; border-color: transparent}.mw-ui-button.mw-ui-progressive:not(:disabled) { background-color: #36c; color: #fff; border-color: #36c}.mw-ui-button.mw-ui-progressive:not(:disabled):hover { background-color: #447ff5; border-color: #447ff5}.mw-ui-button.mw-ui-progressive:not(:disabled):focus { box-shadow: inset 0 0 0 1px #36c,inset 0 0 0 2px #fff}.mw-ui-button.mw-ui-progressive:not(:disabled):active,.mw-ui-button.mw-ui-progressive:not(:disabled).is-on { background-color: #2a4b8d; border-color: #2a4b8d; box-shadow: none}.mw-ui-button.mw-ui-progressive:disabled { background-color: #c8ccd1; color: #fff; border-color: #c8ccd1}.mw-ui-button.mw-ui-progressive.mw-ui-quiet { color: #36c; background-color: transparent; border-color: transparent}input[type=checkbox]:hover+.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:hover { background-color: rgba(52,123,255,.2); border-color: transparent; color: #447ff5}input[type=checkbox]:focus+.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:focus { color: #36c; border-color: #36c}input[type=checkbox]:active+.mw-ui-button.mw-ui-progressive.mw-ui-quiet,.mw-ui-button.mw-ui-progressive.mw-ui-quiet:active { color: #fff; background-color: #2a4b8d; border-color: #2a4b8d}.mw-ui-button.mw-ui-destructive:not(:disabled) { background-color: #d33; color: #fff; border-color: #d33}.mw-ui-button.mw-ui-destructive:not(:disabled):hover { background-color: #ff4242; border-color: #ff4242}.mw-ui-button.mw-ui-destructive:not(:disabled):focus { box-shadow: inset 0 0 0 1px #d33,inset 0 0 0 2px #fff}.mw-ui-button.mw-ui-destructive:not(:disabled):active,.mw-ui-button.mw-ui-destructive:not(:disabled).is-on { background-color: #b32424; border-color: #b32424; box-shadow: none}.mw-ui-button.mw-ui-destructive:disabled { background-color: #c8ccd1; color: #fff; border-color: #c8ccd1}.mw-ui-button.mw-ui-destructive.mw-ui-quiet { color: #d33; background-color: transparent; border-color: transparent}input[type=checkbox]:hover+.mw-ui-button.mw-ui-destructive.mw-ui-quiet,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:hover { background-color: rgba(209,29,19,.2); border-color: transparent; color: #ff4242}input[type=checkbox]:focus+.mw-ui-button.mw-ui-destructive.mw-ui-quiet,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:focus { color: #d33; border-color: #d33}input[type=checkbox]:active+.mw-ui-button.mw-ui-destructive.mw-ui-quiet,.mw-ui-button.mw-ui-destructive.mw-ui-quiet:active { color: #fff; background-color: #b32424; border-color: #b32424}.mw-ui-button.mw-ui-big { font-size: 1.3em}.mw-ui-button.mw-ui-block { display: block; width: 100%; margin-left: auto; margin-right: auto}a.mw-ui-button { text-decoration: none}a.mw-ui-button:hover,a.mw-ui-button:focus { text-decoration: none}.mw-ui-button-group>* { min-width: 48px; border-radius: 0; float: left}.mw-ui-button-group>*:first-child { border-top-left-radius: 2px; border-bottom-left-radius: 2px}.mw-ui-button-group>*:not(:first-child) { border-left: 0}.mw-ui-button-group>*:last-child { border-top-right-radius: 2px; border-bottom-right-radius: 2px}.mw-ui-button-group .is-on .button { cursor: default}.mw-ui-icon { font-size: initial; position: relative; display: inline-block; box-sizing: content-box!important; width: 1.25em; height: 1.25em; min-width: 1.25em; min-height: 1.25em; flex-basis: 1.25em; vertical-align: middle; line-height: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; -moz-appearance: none; -webkit-appearance: none; background-color: transparent; border: 0; margin: 0; padding: 0}.mw-ui-icon:before { content: ''; display: block; width: 100%; height: 100%; min-width: 1.25em; min-height: 1.25em; background-repeat: no-repeat; background-size: 1.25em 1.25em; background-position: center}.mw-ui-icon-flush-top { margin-top: -.75em}.mw-ui-icon-flush-left { margin-left: -.75em}.mw-ui-icon-flush-right { margin-right: -.75em}.mw-ui-icon-element { border-radius: 2px; padding: .75em; -webkit-transition: background-color 100ms; transition: background-color 100ms; color: transparent}.mw-ui-icon-element:focus,.mw-ui-icon-element:active,.mw-ui-icon-element:visited { color: transparent}.mw-ui-icon-element:active { background-color: rgba(0,0,0,.03)}@media(hover: hover) { .mw-ui-icon-element:not(.disabled):hover { background-color:rgba(0,0,0,.03) }}.mw-ui-icon-small { width: 1em; height: 1em; min-width: 1em; min-height: 1em; flex-basis: 1em; line-height: 1em}.mw-ui-icon-small:before { content: ''; display: block; width: 100%; height: 100%; min-width: 1em; min-height: 1em; background-repeat: no-repeat; background-size: 1em 1em; background-position: center}.mw-ui-icon-small.mw-ui-icon-element { padding: .5625em}.mw-ui-icon-small.mw-ui-icon-flush-left { margin-left: -.5625em}.mw-ui-icon-small.mw-ui-icon-flush-right { margin-right: -.5625em}.mw-ui-icon-small.mw-ui-icon-before:before { min-width: 1em; min-height: 1em; margin-right: .5625em}.mw-ui-icon-before { width: auto; max-width: 100%}.mw-ui-icon-before:before { display: inline-block; font-size: initial; width: auto; min-width: 1.25em; min-height: 1.25em; margin-right: 8px; vertical-align: middle}.mw-ui-icon-before span { vertical-align: middle}@media all and (min-width: 1000px) { .mw-ui-icon-with-label-desktop { color:#54595d; width: auto; line-height: inherit; flex-basis: auto } .mw-ui-icon-with-label-desktop:hover,.mw-ui-icon-with-label-desktop:focus,.mw-ui-icon-with-label-desktop:active,.mw-ui-icon-with-label-desktop:visited { color: #54595d; text-decoration: none } .mw-ui-icon-with-label-desktop:before { width: auto; display: inline-block; margin-right: 8px; vertical-align: text-bottom }}.minerva__tab-container { white-space: nowrap; overflow-x: auto}.minerva__tab-container .minerva__tab { font-size: .85em; margin: 0 10px 0 0; color: #54595d; font-weight: 700; padding-bottom: 6px; display: inline-block}.minerva__tab-container .minerva__tab:visited,.minerva__tab-container .minerva__tab:hover,.minerva__tab-container .minerva__tab:active,.minerva__tab-container .minerva__tab.new,.minerva__tab-container .minerva__tab.new:visited,.minerva__tab-container .minerva__tab.new:active,.minerva__tab-container .minerva__tab.new:hover { color: #54595d; text-decoration: none}.minerva__tab-container .minerva__tab:last-child { margin-right: 0}.minerva__tab-container .minerva__tab.selected { border-bottom: 2px solid #54595d}.toggle-list__list--drop-down { -webkit-transform: translateY(-8px); -ms-transform: translateY(-8px); transform: translateY(-8px); -webkit-tap-highlight-color: transparent}.minerva-animations-ready .toggle-list__list--drop-down { -webkit-transition: opacity 100ms ease-in-out,-webkit-tap-highlight-color 0s ease-in-out,transform 100ms ease-in-out,visibility 100ms ease-in-out; transition: opacity 100ms ease-in-out,-webkit-tap-highlight-color 0s ease-in-out,transform 100ms ease-in-out,visibility 100ms ease-in-out}.toggle-list__checkbox:checked~.toggle-list__list--drop-down { -webkit-transform: translateY(0); -ms-transform: translateY(0); transform: translateY(0)}.toggle-list-item { display: block; padding: .75em .875em}.toggle-list-item:hover { background: #eaecf0}.toggle-list-item__anchor { display: block; line-height: 1}.toggle-list-item__anchor:hover { text-decoration: none}.toggle-list-item__anchor:visited,.toggle-list-item__anchor:active { color: #54595d}.toggle-list-item__icon { vertical-align: middle}.toggle-list-item__label { text-align: left; color: #54595d; font-weight: 700; white-space: nowrap; vertical-align: middle; font-size: .875em}.minerva-user-menu-list { top: 100%; right: -.75em; min-width: 200px; border-radius: 2px}.minerva--history-page-action-enabled .page-actions-menu__list-item { flex-basis: auto}.minerva--history-page-action-enabled .page-actions-menu__list-item:first-child { flex-grow: 0}.page-actions-overflow-list { top: 100%; right: -.75em; border-radius: 2px}.mw-ui-icon-minerva-ellipsis:before { -webkit-transform: rotate(90deg); -ms-transform: rotate(90deg); transform: rotate(90deg)}@media screen { @counter-style meetei { system: numeric; symbols: '\ABF0''\ABF1''\ABF2''\ABF3''\ABF4''\ABF5''\ABF6''\ABF7''\ABF8''\ABF9'; suffix: ') ' } @counter-style santali { system: numeric; symbols: '\1C50''\1C51''\1C52''\1C53''\1C54''\1C55''\1C56''\1C57''\1C58''\1C59' } ol:lang(azb) li,ol:lang(bcc) li,ol:lang(bgn) li,ol:lang(bqi) li,ol:lang(fa) li,ol:lang(glk) li,ol:lang(kk-arab) li,ol:lang(lrc) li,ol:lang(luz) li,ol:lang(mzn) li { list-style-type: persian } ol:lang(ckb) li,ol:lang(sdh) li { list-style-type: arabic-indic } ol:lang(hi) li,ol:lang(mai) li,ol:lang(mr) li,ol:lang(ne) li { list-style-type: devanagari } ol:lang(as) li,ol:lang(bn) li { list-style-type: bengali } ol:lang(mni) li { list-style-type: meetei } ol:lang(or) li { list-style-type: oriya } ol:lang(sat) li { list-style-type: santali }}div,span,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,ins,em,img,small,strike,strong,sub,sup,tt,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,input,button,select,audio,video { margin: 0; padding: 0; border: 0; font: inherit; font-size: 100%; vertical-align: baseline; background: 0 0}table,caption,tbody,tfoot,thead,tr,th,td { font-size: 100%}caption { font-weight: 700}button { border: 0; background-color: transparent; cursor: pointer}input { line-height: normal}ul { list-style: none}table { border-collapse: collapse}html,body { height: 100%}html { font-size: 100%; -webkit-text-size-adjust: none}body { background-color: transparent; color: #202122; margin: 0}main { display: block}.mw-body { border-top: 1px solid transparent; padding-bottom: 32px}.overlay-enabled,.mw-body { background-color: transparent}.header-container { border-bottom: 1px solid #c8ccd1; padding: 0 16px}.header-container.header-chrome { background-color: #eaecf0; border: 0; box-shadow: inset 0 -1px 3px rgba(0,0,0,.08)}.navigation-drawer--loading,#footer-info-lastmod { display: none}.header { display: table; width: 100%; border-spacing: 0; border-collapse: collapse; height: 3.375em; white-space: nowrap; border-top: 1px solid #c8ccd1; margin-top: -1px}.header>div,.header>.navigation-drawer { position: relative; vertical-align: middle; display: table-cell}.header>div a { display: block}.header .branding-box { width: auto; opacity: .66}.header .branding-box h1,.header .branding-box a { margin-left: 5px; font-size: 1em; text-decoration: none; color: #202122}.header .branding-box h1 span,.header .branding-box a span { line-height: 1; font-size: inherit}.header .branding-box h1 img,.header .branding-box a img { vertical-align: middle}.header .branding-box h1>*,.header .branding-box a>* { float: left}.header .branding-box h1 sup,.header .branding-box a sup { color: #54595d; display: none}.beta .header .branding-box h1 sup,.beta .header .branding-box a sup { display: initial}.header>.header-title { vertical-align: middle}#searchInput { cursor: text}.search-box,.header .search-box { display: none; width: auto}.search-box .search { background-color: #fff; background-position: left .5em center; background-repeat: no-repeat; background-size: 1.125em; -webkit-appearance: none; width: 100%; margin-top: 0; height: 2.25em; border: 1px solid #fff; border-radius: 2px; padding: 7px 0 7px 2.0625em; box-shadow: 0 1px 1px rgba(0,0,0,.05); outline: 0; -webkit-transition: border-color 250ms,box-shadow 250ms; transition: border-color 250ms,box-shadow 250ms}.client-nojs .search-box .search:focus,.search-overlay .search-box .search:focus { border-color: #36c; box-shadow: inset 0 0 0 1px #36c,0 1px 1px rgba(0,0,0,.05)}input.search::-webkit-search-decoration,input.search::-webkit-search-cancel-button,input.search::-webkit-search-results-button,input.search::-webkit-search-results-decoration { display: none}.content h2 { clear: left}.content .collapsible-heading .edit-page { visibility: hidden}.content .collapsible-heading.open-block .edit-page { visibility: visible}.content .mw-parser-output>h2,.content .section-heading { border-bottom: 1px solid #eaecf0; margin-bottom: .5em}.content .mw-parser-output>h1,.content .mw-parser-output>h2,.content .mw-parser-output>h3,.content .mw-parser-output>h4,.content .mw-parser-output>h5,.content .section-heading,.content .in-block { display: table}.content .mw-parser-output>h1 .mw-headline,.content .mw-parser-output>h2 .mw-headline,.content .mw-parser-output>h3 .mw-headline,.content .mw-parser-output>h4 .mw-headline,.content .mw-parser-output>h5 .mw-headline,.content .section-heading .mw-headline,.content .in-block .mw-headline { width: 100%}.content .mw-parser-output>h1>span,.content .mw-parser-output>h2>span,.content .mw-parser-output>h3>span,.content .mw-parser-output>h4>span,.content .mw-parser-output>h5>span,.content .section-heading>span,.content .in-block>span { display: table-cell; vertical-align: middle}.content .mw-parser-output>h1>.mw-editsection>.mw-ui-icon-element,.content .mw-parser-output>h2>.mw-editsection>.mw-ui-icon-element,.content .mw-parser-output>h3>.mw-editsection>.mw-ui-icon-element,.content .mw-parser-output>h4>.mw-editsection>.mw-ui-icon-element,.content .mw-parser-output>h5>.mw-editsection>.mw-ui-icon-element,.content .section-heading>.mw-editsection>.mw-ui-icon-element,.content .in-block>.mw-editsection>.mw-ui-icon-element { margin-top: -.75em; margin-bottom: -.75em}.client-nojs .section-heading .indicator { display: none}#page-secondary-actions { clear: both}#page-secondary-actions a { margin: 10px 2px 2px 0}#bodyContent .panel .content,.overlay .content-header,.overlay .panel,.page-list.side-list .list-thumb,.page-list li,.topic-title-list li,.site-link-list li,.drawer,.messagebox,.errorbox,.successbox,.warningbox,.list-header,.mw-revision { padding-left: 16px; padding-right: 16px}.talk-overlay .comment .comment-content,.image-list,.pre-content,#mw-content-text>form>.oo-ui-fieldLayout>.oo-ui-fieldLayout-body,#mw-content-text>form>.oo-ui-widget,.content,.post-content { margin: 0 16px}.minerva__subtitle { margin-top: 10px; margin-bottom: 10px}.minerva__subtitle:empty { margin: 0}@media all and (min-width: 720px) { .page-summary-list,.topic-title-list,.site-link-list,.overlay .panel,.list-header { padding-left:3.35em; padding-right: 3.35em }}.heading-holder { padding: 20px 0 0; position: relative}.heading-holder .tagline { color: #54595d; font-size: .85em}.page-heading { margin-bottom: 12px}.mw-ui-icon-element.disabled,.language-selector.disabled { cursor: default; opacity: .25}#page-actions { position: relative}.page-actions-menu { -moz-box-sizing: border-box; box-sizing: border-box; border-top: 1px solid #eaecf0; border-bottom: 1px solid #c8ccd1; margin-top: -1px}.page-actions-menu__list { display: flex; height: 3em; justify-content: space-between}.page-actions-menu__list-item { display: flex; justify-content: flex-end; align-items: center; min-width: 0; overflow: hidden}.page-actions-menu__list-item>a { font-weight: 500}.page-actions-menu__list-item li>*:hover { box-shadow: none}.page-actions-menu__list-item:first-child { flex-grow: 1; justify-content: flex-start; margin-left: -8px}.page-actions-menu__list-item:last-child { margin-right: -8px}.client-nojs .watch-this-article { visibility: hidden}.client-nojs .is-authenticated .watch-this-article { visibility: visible}@media all and (max-width: 320px - 1) { .client-nojs #page-actions { display:none } .client-nojs #section_0 { border: 0 }}.minerva-user-navigation { display: flex; min-width: 7em; min-height: 3.375em; height: 100%; width: 100%; align-items: center; justify-content: flex-end; position: relative}.minerva-user-navigation>*:last-child { margin-right: -.75em}.view-border-box *,.view-border-box { -moz-box-sizing: border-box; box-sizing: border-box}.client-js .mw-redirectedfrom,.printfooter,.jsonly { display: none}.client-js .jsonly { display: inherit}.hidden { display: none!important}#mw-mf-viewport { position: relative; height: 100%}#mw-mf-page-center { width: 100%; min-height: 100%; position: relative; background-color: #eaecf0}.content { position: relative; z-index: 0}.minerva-footer { border-top: solid 1px #c8ccd1; overflow: auto; padding-bottom: 6px}.client-nojs footer .indicator,.client-nojs .mw-footer .indicator { display: none}footer .hlist li:after,.mw-footer .hlist li:after { color: #36c}footer>.post-content,.mw-footer>.post-content { overflow: auto; margin-top: 42px}footer>.post-content>*,.mw-footer>.post-content>* { margin-bottom: 9px}footer>.post-content>h2,.mw-footer>.post-content>h2 { border-bottom: solid 1px #c8ccd1; padding-bottom: 10px; margin-top: 42px; font-size: 1em; font-weight: 700}footer>.post-content>h2:first-child,.mw-footer>.post-content>h2:first-child { margin-top: 0}footer>.post-content .hlist,.mw-footer>.post-content .hlist,footer>.post-content .license,.mw-footer>.post-content .license { font-size: .875em}.last-modified-bar { border-bottom: solid 1px #c8ccd1; background-color: #eaecf0; color: #72777d; padding-top: .75em; padding-bottom: .75em; font-size: .875em; -webkit-transition: background-color 250ms,color 250ms; transition: background-color 250ms,color 250ms}.last-modified-bar a,.last-modified-bar a:visited { color: #54595d}.last-modified-bar a:nth-child(1),.last-modified-bar a:visited:nth-child(1) { font-weight: 700}.last-modified-bar a.external { background-image: none; padding-right: 0}.last-modified-bar__content { align-items: center; display: -ms-flexbox; display: flex}.last-modified-bar__text { padding-right: 3.5em; padding-left: .75em; line-height: 1.65; vertical-align: middle; flex-grow: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap}@media(max-width: 720px) { .last-modified-bar__text { padding-right:1em }}@media print { .noprint,.banner-container,.header,.minerva__tab-container,.page-actions-menu,.post-content { display: none } h1,h2,h3,h4,h5,h6 { page-break-after: avoid } table,figure,img { page-break-inside: avoid } img { max-width: 100% } img.image-lazy-loaded { -webkit-animation: none!important; animation: none!important }}@media print and (max-device-width: 720px) { @page { margin:50px 0 } html { padding: 0 50px } .header-container,.header-container.header-chrome { background: #fff; box-shadow: none!important } .header { border-top: 0; display: block; height: auto; padding: 0 16px } .header .branding-box { padding-left: 0!important } .header .branding-box sup { display: none!important } .header>nav,.header>div { display: none!important } .header>.branding-box { height: auto; display: block!important; padding: 0 0 51px 50px } .header>.branding-box h1 { font-size: inherit } .header>.branding-box h1>* { float: none } .header>.branding-box h1 img { height: 41px; width: auto; vertical-align: inherit } .hatnote,.pre-content #page-actions { display: none } .pre-content { display: block; padding: 51px 0 35px } .pre-content h1 { font-size: 70px; font-weight: 400; font-style: italic; font-stretch: normal; line-height: normal; letter-spacing: normal; text-align: left; color: #000 } .pre-content .tagline { font-size: 36px } .mw-body>.content { padding-top: 55px; position: relative } .mw-body>.content:before { top: 0 } .thumbinner { width: auto!important } .thumbinner>a { width: 100% } .thumb { position: relative; padding: 58px 0!important; text-align: left; margin: 0!important } .thumb:after { bottom: 30px } .thumb:after,.mw-body>.content:before { position: absolute; left: 0; content: ''; display: block; width: 55px; height: 2px; background: #999 } .thumbcaption { margin-top: 23px!important; width: 100%; font-style: italic; font-size: 28px } [class|=mw-content] { font-size: 36px } [class|=mw-content] a { text-decoration: underline; color: #202122 } [class|=mw-content] blockquote { color: #54595d; padding: 5px 39px; font-style: italic } [class|=mw-content] .section-heading { border-bottom: 0; padding-bottom: 0; margin-bottom: 16px } [class|=mw-content] h2 { font-size: 48px } [class|=mw-content] h3 { font-size: 40px; margin-bottom: 13px } [class|=mw-content] h4,[class|=mw-content] h5,[class|=mw-content] h6 { font-size: 36px; margin-bottom: 12px } [class|=mw-content] .wikitable { font-size: 16px } [class|=mw-content] .infobox { font-size: 30px } .references .mw-cite-backlink { display: none } .references .reference-text { font-style: italic } .references a { text-decoration: none } .references .external.text { background-image: none } .printfooter { display: block; padding-top: 108px; font-size: 30px } #mw-mf-page-center>footer { border-top: solid 4px #000; padding-top: 23px; background: #fff!important } #mw-mf-page-center>footer .mw-ui-icon:before { display: none!important } #mw-mf-page-center>footer .last-modified-bar { background: 0 0!important; border: 0!important } #mw-mf-page-center>footer .last-modifier-tagline { font-size: 36px; padding-top: 0!important; padding-bottom: 16px!important } #mw-mf-page-center>footer .last-modified-bar,#mw-mf-page-center>footer .last-modified-bar a { font-weight: 700!important; color: #000!important } #mw-mf-page-center>footer .post-content { margin-top: 15px!important; display: block } #mw-mf-page-center>footer .post-content .hlist,#mw-mf-page-center>footer .post-content h2 { display: none } #mw-mf-page-center>footer .post-content .license a,#mw-mf-page-center>footer .post-content .license { font-size: 30px; color: #999; font-weight: 400 }}@font-face { font-family: raleway; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCFPrEHJA.woff2) format('woff2'); unicode-range: U+0460-052F,U+1C80-1C88,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face { font-family: raleway; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCMPrEHJA.woff2) format('woff2'); unicode-range: U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face { font-family: raleway; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCHPrEHJA.woff2) format('woff2'); unicode-range: U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+1EA0-1EF9,U+20AB}@font-face { font-family: raleway; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCGPrEHJA.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: raleway; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrE.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face { font-family: neuton; font-style: italic; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBRrPtMoH62xUZCyrg2Wi_FBw.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: neuton; font-style: italic; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBRrPtMoH62xUZCyrg4Wi8.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face { font-family: neuton; font-style: normal; font-weight: 200; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKAKkvcwr4Pro.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: neuton; font-style: normal; font-weight: 200; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKAKkvfQr4.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face { font-family: neuton; font-style: normal; font-weight: 300; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKZKovcwr4Pro.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: neuton; font-style: normal; font-weight: 300; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKZKovfQr4.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face { font-family: neuton; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBTrPtMoH62xUZCwYg6Qis.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: neuton; font-style: normal; font-weight: 400; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBTrPtMoH62xUZCz4g6.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face { font-family: neuton; font-style: normal; font-weight: 700; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKdK0vcwr4Pro.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: neuton; font-style: normal; font-weight: 700; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKdK0vfQr4.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face { font-family: neuton; font-style: normal; font-weight: 800; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKaK4vcwr4Pro.woff2) format('woff2'); unicode-range: U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face { font-family: neuton; font-style: normal; font-weight: 800; font-display: swap; src: url(https://fonts.gstatic.com/s/neuton/v16/UMBQrPtMoH62xUZKaK4vfQr4.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@media screen and (min-width: 1000px) { .header { max-width:1250px!important }}.banner-container,.header,.page-header-bar,.overlay-header,.content,.overlay-content,.content-unstyled,.pre-content,.post-content,.last-modified-bar,#mw-content-text>form { max-width: 1250px!important}.page-Main_Page .page-heading,.page-Main_Page .pre-content { display: none!important}.page-Main_Page pre { display: none}.page-Main_Page .blocks-list { display: flex; flex-wrap: wrap; justify-content: space-evenly; list-style: none; column-gap: 20px; row-gap: 20px; padding: 0; margin: 0}.page-Main_Page .blocks-item { box-sizing: border-box; color: #ffc376; display: flex; flex: 1 0 180px; text-align: center; margin: 0!important; border: 1px solid #ecebeb; border-radius: 8px; box-shadow: 0 2px 15px rgba(175,175,175,.2); flex-flow: wrap; position: relative}.page-Main_Page .blocks-item:hover { box-shadow: 0 2px 15px rgba(231,135,27,.4)!important; cursor: pointer; top: -2px}.page-Main_Page .blocks-item>a { color: #ffc376; padding: 0 10px 15px; display: flex; flex-direction: column; flex: 1; justify-content: center; border-radius: inherit; text-decoration: none; background-color: transparent}.page-Main_Page .block-icon { background-position: top center; background-repeat: no-repeat; background-size: contain; height: 140px; margin: 0; transition: all .1s ease-in-out}.page-Main_Page .blocks-item-title { margin: 0; font-size: 22px; color: #ffc376}.page-Main_Page .blocks-item-description:not(:empty) { margin-top: 10px}.page-Main_Page .blocks-item-description { font-weight: 300; margin: 0; color: #1a1a1a}.page-Main_Page .block-icon:before { content: ""; display: block; position: relative}.page-Main_Page .blocks-item#block-accessories>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/accessories.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/accessories.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/accessories.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/accessories.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/accessories.png) 2x)}.page-Main_Page .blocks-item#block-accessories>a>.block-icon:before,.page-Main_Page .blocks-item#block-accessories:hover>a>.block-icon,.page-Main_Page .blocks-item#block-accessories>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/accessories.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/accessories.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/accessories.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/accessories.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/accessories.ro.png) 2x)}.page-Main_Page .blocks-item#block-armor>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/armor.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/armor.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/armor.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/armor.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/armor.png) 2x)}.page-Main_Page .blocks-item#block-armor>a>.block-icon:before,.page-Main_Page .blocks-item#block-armor:hover>a>.block-icon,.page-Main_Page .blocks-item#block-armor>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/armor.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/armor.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/armor.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/armor.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/armor.ro.png) 2x)}.page-Main_Page .blocks-item#block-collections>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/collections.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/collections.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/collections.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/collections.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/collections.png) 2x)}.page-Main_Page .blocks-item#block-collections>a>.block-icon:before,.page-Main_Page .blocks-item#block-collections:hover>a>.block-icon,.page-Main_Page .blocks-item#block-collections>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/collections.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/collections.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/collections.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/collections.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/collections.ro.png) 2x)}.page-Main_Page .blocks-item#block-hub>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/hub.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/hub.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/hub.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/hub.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/hub.png) 2x)}.page-Main_Page .blocks-item#block-hub>a>.block-icon:before,.page-Main_Page .blocks-item#block-hub:hover>a>.block-icon,.page-Main_Page .blocks-item#block-hub>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/hub.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/hub.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/hub.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/hub.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/hub.ro.png) 2x)}.page-Main_Page .blocks-item#block-fairysouls>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/fairysouls.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/fairysouls.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/fairysouls.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/fairysouls.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/fairysouls.png) 2x)}.page-Main_Page .blocks-item#block-fairysouls>a>.block-icon:before,.page-Main_Page .blocks-item#block-fairysouls:hover>a>.block-icon,.page-Main_Page .blocks-item#block-fairysouls>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/fairysouls.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/fairysouls.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/fairysouls.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/fairysouls.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/fairysouls.ro.png) 2x)}.page-Main_Page .blocks-item#block-island>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/island.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/island.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/island.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/island.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/island.png) 2x)}.page-Main_Page .blocks-item#block-island>a>.block-icon:before,.page-Main_Page .blocks-item#block-island:hover>a>.block-icon,.page-Main_Page .blocks-item#block-island>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/island.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/island.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/island.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/island.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/island.ro.png) 2x)}.page-Main_Page .blocks-item#block-locations>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/locations.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/locations.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/locations.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/locations.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/locations.png) 2x)}.page-Main_Page .blocks-item#block-locations>a>.block-icon:before,.page-Main_Page .blocks-item#block-locations:hover>a>.block-icon,.page-Main_Page .blocks-item#block-locations>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/locations.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/locations.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/locations.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/locations.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/locations.ro.png) 2x)}.page-Main_Page .blocks-item#block-minions>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/minions.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/minions.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/minions.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/minions.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/minions.png) 2x)}.page-Main_Page .blocks-item#block-minions>a>.block-icon:before,.page-Main_Page .blocks-item#block-minions:hover>a>.block-icon,.page-Main_Page .blocks-item#block-minions>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/minions.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/minions.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/minions.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/minions.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/minions.ro.png) 2x)}.page-Main_Page .blocks-item#block-pets>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/pets.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/pets.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/pets.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/pets.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/pets.png) 2x)}.page-Main_Page .blocks-item#block-pets>a>.block-icon:before,.page-Main_Page .blocks-item#block-pets:hover>a>.block-icon,.page-Main_Page .blocks-item#block-pets>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/pets.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/pets.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/pets.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/pets.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/pets.ro.png) 2x)}.page-Main_Page .blocks-item#block-reforging>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/reforging.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/reforging.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/reforging.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/reforging.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/reforging.png) 2x)}.page-Main_Page .blocks-item#block-reforging>a>.block-icon:before,.page-Main_Page .blocks-item#block-reforging:hover>a>.block-icon,.page-Main_Page .blocks-item#block-reforging>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/reforging.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/reforging.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/reforging.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/reforging.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/reforging.ro.png) 2x)}.page-Main_Page .blocks-item#block-skills>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/skills.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/skills.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/skills.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/skills.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/skills.png) 2x)}.page-Main_Page .blocks-item#block-skills>a>.block-icon:before,.page-Main_Page .blocks-item#block-skills:hover>a>.block-icon,.page-Main_Page .blocks-item#block-skills>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/skills.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/skills.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/skills.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/skills.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/skills.ro.png) 2x)}.page-Main_Page .blocks-item#block-stats>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/stats.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/stats.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/stats.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/stats.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/stats.png) 2x)}.page-Main_Page .blocks-item#block-stats>a>.block-icon:before,.page-Main_Page .blocks-item#block-stats:hover>a>.block-icon,.page-Main_Page .blocks-item#block-stats>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/stats.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/stats.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/stats.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/stats.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/stats.ro.png) 2x)}.page-Main_Page .blocks-item#block-weapons>a>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/weapons.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/weapons.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/weapons.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/weapons.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/weapons.png) 2x)}.page-Main_Page .blocks-item#block-weapons>a>.block-icon:before,.page-Main_Page .blocks-item#block-weapons:hover>a>.block-icon,.page-Main_Page .blocks-item#block-weapons>a:focus>.block-icon { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/low-res/weapons.ro.png); background-image: image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/weapons.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/weapons.ro.png) 2x); background-image: -webkit-image-set(url(https://wiki.hypixel.net/images/hypixel/icons/low-res/weapons.ro.png) 1x,url(https://wiki.hypixel.net/images/hypixel/icons/hi-res/weapons.ro.png) 2x)}.page-Main_Page #wrapper { display: flex; flex-direction: row; column-gap: 50px; row-gap: 50px; justify-content: space-between}.page-Main_Page #wrapper #content { display: flex; flex-direction: column; row-gap: 50px}.page-Main_Page #wrapper #content #introduction { display: flex; flex-direction: row; column-gap: 25px; row-gap: 25px; align-content: center}.page-Main_Page #wrapper #content #introduction #welcome { margin: .5em 0}.page-Main_Page #wrapper #content #introduction .blocks-item { margin: 0!important}.page-Main_Page #wrapper #content #statistics .stats-list { display: flex; flex-wrap: wrap; list-style: none; justify-content: space-evenly; padding: 0; row-gap: 25px}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item { margin: 0}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-icon { background-position: center; background-size: contain; background-repeat: no-repeat; height: 55px; width: 55px; display: inline-block; position: relative; vertical-align: middle}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-icon.stats-icon-edits { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/edits.png)}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-icon.stats-icon-pages { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/pages.png)}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-icon.stats-icon-files { background-image: url(https://wiki.hypixel.net/images/hypixel/icons/files.png)}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-item-text { vertical-align: middle; display: inline-flex; position: relative; flex-direction: column; flex-wrap: nowrap; justify-content: center; align-content: center; margin: 0 15px}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-item-text span:first-child { font-size: 20px}.page-Main_Page #wrapper #content #statistics .stats-list .stats-item .stats-item-text span:nth-child(2) { font-size: 16px}.page-Main_Page #wrapper #content #other-game-content ul { columns: 200px auto}.page-Main_Page #wrapper #content .content-heading { height: 50px; background-color: #1f1f1f; border: 1px solid #333; border-image: url(https://wiki.hypixel.net/images/hypixel/borders/classic_border.png) 1000 1000 repeat!important; border-image-width: 35px!important; border-image-outset: 2px!important; margin: 0 0 1em; font-size: 20px; display: flex; justify-content: center; align-items: center}.page-Main_Page #wrapper #sidebar { display: flex; flex-direction: column; row-gap: 50px}.page-Main_Page #wrapper #sidebar .sidebar-heading { text-align: center; font-size: 20px}.page-Main_Page #wrapper #sidebar .sidebar-content { display: flex; flex-direction: column; flex-wrap: nowrap; row-gap: 15px; background-color: #1f1f1f; padding: 20px; border-radius: 3px; border: 1px solid #333; border-image: url(https://wiki.hypixel.net/images/hypixel/borders/square_border.png) 500 500 repeat; border-image-width: 35px!important; border-image-outset: 2px!important}.page-Main_Page #wrapper #sidebar #clock { display: none}.page-Main_Page #wrapper #sidebar #clock p { text-align: center; margin: 0}.page-Main_Page #wrapper #sidebar #clock #clock-time { font-size: 2em}.page-Main_Page #wrapper #sidebar #clock #clock-date { font-size: 1em}@media(max-width: 1000px) { #wrapper { flex-wrap:wrap }}@media(max-width: 720px) { #introduction { flex-wrap:wrap; justify-content: center } .stats-list { flex-direction: column; align-content: center }}.mw-ui-button.mw-ui-progressive { background-color: #e7871b; color: #fff; border: 1px solid #e7871b}.oo-ui-panelLayout-framed { background-color: #eaecf0!important; border-radius: 4px; border: none!important}.oo-ui-dropdownInputWidget.oo-ui-widget-enabled { background-color: transparent}ul.mw-contributions-list li { min-height: 0!important}ul.special li { min-height: 0!important}body { color: transparent; background-color: transparent; font-family: Raleway,helvetica,serif!important}#content h1,#content h2,#content h3 { font-family: Neuton,Raleway,helvetica,serif!important}html,#mw-mf-page-center,#mw-script-doc,#content,.navbox,.navbox-subgroup,.overlay.search-overlay { background-color: #fff!important}.overlay.search-overlay { background-color: #fff!important}.overlay.search-overlay .search-box { display: block!important; position: relative!important}a.external { background-image: none!important; padding-right: 0!important}.mw-body h2.list-header { margin-top: 16px}.page-heading>h1 { font-size: 1.7em!important; font-weight: 400!important; line-height: 1.3; word-wrap: break-word; word-break: break-word}.list-header { background-color: transparent; color: inherit}#toc ul { list-style: decimal}#mw-toc-heading::before { background-image: url(data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgZm9jdXNhYmxlPSJmYWxzZSIgZGF0YS1wcmVmaXg9ImZhcyIgZGF0YS1pY29uPSJsaXN0IiBjbGFzcz0ic3ZnLWlubGluZS0tZmEgZmEtbGlzdCBmYS13LTE2IiByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNGRkYiIGQ9Ik04MCAzNjhIMTZhMTYgMTYgMCAwIDAtMTYgMTZ2NjRhMTYgMTYgMCAwIDAgMTYgMTZoNjRhMTYgMTYgMCAwIDAgMTYtMTZ2LTY0YTE2IDE2IDAgMCAwLTE2LTE2em0wLTMyMEgxNkExNiAxNiAwIDAgMCAwIDY0djY0YTE2IDE2IDAgMCAwIDE2IDE2aDY0YTE2IDE2IDAgMCAwIDE2LTE2VjY0YTE2IDE2IDAgMCAwLTE2LTE2em0wIDE2MEgxNmExNiAxNiAwIDAgMC0xNiAxNnY2NGExNiAxNiAwIDAgMCAxNiAxNmg2NGExNiAxNiAwIDAgMCAxNi0xNnYtNjRhMTYgMTYgMCAwIDAtMTYtMTZ6bTQxNiAxNzZIMTc2YTE2IDE2IDAgMCAwLTE2IDE2djMyYTE2IDE2IDAgMCAwIDE2IDE2aDMyMGExNiAxNiAwIDAgMCAxNi0xNnYtMzJhMTYgMTYgMCAwIDAtMTYtMTZ6bTAtMzIwSDE3NmExNiAxNiAwIDAgMC0xNiAxNnYzMmExNiAxNiAwIDAgMCAxNiAxNmgzMjBhMTYgMTYgMCAwIDAgMTYtMTZWODBhMTYgMTYgMCAwIDAtMTYtMTZ6bTAgMTYwSDE3NmExNiAxNiAwIDAgMC0xNiAxNnYzMmExNiAxNiAwIDAgMCAxNiAxNmgzMjBhMTYgMTYgMCAwIDAgMTYtMTZ2LTMyYTE2IDE2IDAgMCAwLTE2LTE2eiI+PC9wYXRoPjwvc3ZnPg==); content: ""; float: left; height: 14px; left: -14px; position: relative; top: 5px; width: 14px}#footer-company { padding: 0 50px 0 0}#footer-links { display: flex; flex: 1; flex-direction: column; flex-wrap: wrap; font-size: 15px; max-height: 120px}#footer-links>li { padding: 4px 10px}#footer-logo { max-height: 64px}#footer-socials { font-size: 16px; vertical-align: top; color: gray; display: block; padding: 0 4px}#footer-socials .fab { min-width: 18px; text-align: center; vertical-align: middle}#footer-socials a:hover { color: gray!important}#footer-socials a:hover>.fa-discord { color: #7289da}#footer-socials a:hover>.fa-facebook { color: #4267b2}#footer-socials a:hover>.fa-instagram { color: #405de6}#footer-socials a:hover>.fa-tiktok { color: #000}#footer-socials a:hover>.fa-twitter { color: #1da1f2}#footer-socials a:hover>.fa-youtube { color: red}#mw-content-text>form { width: 100%!important}.branding-box { background: url(https://wiki.hypixel.net/images/hypixel-full.png) no-repeat; background-origin: content-box; background-size: contain; background-position: center; opacity: 1!important; padding: 10px 0; cursor: pointer; height: 100%}.branding-box>a { height: 100%; width: 100%}.branding-box>a>span { color: transparent}.client-nojs .search-box .search:focus { border: none; box-shadow: none}.search-overlay .search-box .search:focus { border: none; box-shadow: none}.toggle-list__toggle,#mw-mf-main-menu-button { border: none; box-shadow: none; outline: none!important}.footer { background-image: linear-gradient(to bottom,rgba(26,26,26,0.92),#1a1a1a),url(https://wiki.hypixel.net/images/artwork.png); background-position: center; background-repeat: no-repeat; background-size: cover; border-top: 1px solid #ddd; color: #fff; margin-top: 60px; padding: 30px 0; user-select: none}.footer a { color: gray!important; text-decoration: none!important; transition: .12s ease-in-out}.footer a:hover { color: #fff!important}.footer-copyright { color: gray; display: block; padding: 0 4px}.footer-inner { display: flex; flex-wrap: wrap; justify-content: space-between; margin: 0 auto; max-width: 1160px; padding: 0!important; width: 65%!important}.header { height: 71px!important; user-select: none}.header-chrome:before { background-image: radial-gradient(farthest-side at top,rgba(255,255,255,0.5),#ffffff),url(https://wiki.hypixel.net/images/artwork.png)!important; background-position: center; background-repeat: no-repeat; background-size: cover; content: ""; height: 72px; left: 0; max-width: 100%!important; position: absolute; width: 100%!important}.last-modified-bar { margin: auto; width: 90%; background-color: #eaecf0!important; border-radius: 4px}.minerva__tab.selected { border-bottom: 2px solid #e7871b!important}.mw-editform .editOptions { margin-top: 20px}.mw-ui-icon-element.cancel { height: 44px; margin: 10px; padding: 0; vertical-align: middle; width: 44px}.mw-ui-icon-element:not(.disabled):hover { background-color: rgba(0,0,0,.1)}.overlay-footer-container { display: none}.overlay.search-overlay.visible { animation-duration: .1s!important}.minerva__tab-container { display: none}.page-actions-menu,#filetoc,.warningbox { border-radius: 4px; margin-bottom: 16px; padding: 0 20px; background-color: #eaecf0; border: 1px solid #c8ccd1}.warningbox { padding: 10px 25px!important}.warningbox,#mw-clearyourcache { margin-bottom: 16px!important}.search { -webkit-appearance: none!important; background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&format=original&skin=minerva&version=1qbws); background-position: left .8em center!important; background-size: 18px!important; border: 1px solid #fff!important; border-radius: 6px!important; box-shadow: 0 0 10px #bbb!important; box-sizing: border-box!important; color: #666!important; font-family: BlinkMacSystemFont,segoe ui,helvetica,Arial,sans-serif!important; font-size: 14px!important; height: 40px!important; line-height: 1.15!important; max-width: 380px; padding-left: 40px!important; padding-right: 20px!important; transition: border .12s ease-in-out!important; width: 100%!important}.search:focus { outline: 1px solid #ffc376!important}.search-box .search { border-radius: 4px}.content kbd { border-radius: 4px}.content samp { border-radius: 4px}.content code { border-radius: 4px}.content pre { border-radius: 4px}footer { border: none!important}fieldset { margin: 10px 0}#mw-mf-page-left { box-shadow: 0 5px 17px 0 rgba(0,0,0,.24),0 0 1px #a2a9b1!important; position: absolute!important; height: max-content; border-radius: 3px; -webkit-transition: opacity 100ms ease-in-out,-webkit-tap-highlight-color 0s ease-in-out,transform 100ms ease-in-out,visibility 100ms ease-in-out!important; transition: opacity 100ms ease-in-out,-webkit-tap-highlight-color 0s ease-in-out,transform 100ms ease-in-out,visibility 100ms ease-in-out!important; top: 45px!important; left: -12px!important; transform: translate(0,-10px)!important}#mw-mf-page-left li { border: none!important}#mw-mf-page-left li:hover { background-color: #eaecf0!important}#mw-mf-page-left ul { padding-bottom: 0!important}#mw-mf-page-left ul li a { color: #54595d!important}#mw-mf-page-left ul li a:hover { box-shadow: none!important}form.search-box { display: block; width: 100%}input { outline: none}#main-menu-input:checked~#mw-mf-page-left { transform: translate(0,0)!important}.hlist { display: none}.last-modified-bar.active { background-color: #218e47!important}.wikitable>tr>th,.wikitable>tr>td,.wikitable>*>tr>th,.wikitable>*>tr>td { padding: .25em .55em!important}.suggestions { border-radius: 6px!important}.suggestions-result,.suggestions-special { padding: .5em 1em!important}.suggestions-results,.suggestions-special { border-color: #ccc!important}kbd,samp,code,pre,.page-actions-menu,#filetoc,.warningbox,.last-modified-bar { border: 1px solid #333; border-image: url(https://wiki.hypixel.net/images/hypixel/borders/classic_border.png) 1000 1000 repeat!important; border-image-width: 35px!important; border-image-outset: 2px!important}@media only screen { .oo-ui-tabOptionWidget { color: #fff!important } .oo-ui-tabOptionWidget.oo-ui-optionWidget-selected { background-color: #212121 } .suggestions-results,.suggestions-special { background-color: #1f1f1f!important; border-color: #333!important } .suggestions-results .special-label,.suggestions-special .special-label { color: #ccc!important } .suggestions-results .suggestions-result,.suggestions-special .suggestions-result,.suggestions-results .special-query,.suggestions-special .special-query { color: #fff!important } .search { color: #ccc!important } html,body,#mw-mf-page-center,#mw-script-doc,#content,.navbox,.navbox-subgroup,.overlay.search-overlay,.oo-ui-tabSelectWidget-framed,.oo-ui-tagMultiselectWidget-handle,.mw-prefs-buttons,.mw-scribunto-message,.mw-scribunto-console-fieldset,.mw-history-compareselectedversions { background-color: transparent!important; color: #fff } .mw-rcfilters-ui-watchlistTopSectionWidget-separator { border-color: #212121!important } .mw-rcfilters-ui-filterTagMultiselectWidget-wrapper-content-title,.mw-rcfilters-ui-filterTagMultiselectWidget-emptyFilters { color: #fff!important } .oo-ui-tabSelectWidget-framed { border-bottom-color: transparent } .oo-ui-tagMultiselectWidget-handle,.oo-ui-buttonGroupWidget,.oo-ui-dropdownWidget-handle,.oo-ui-optionWidget,.oo-ui-selectWidget,.oo-ui-optionWidget-selected { background-color: #1a1a1a!important; color: #fff!important; border-color: #212121!important } .oo-ui-optionWidget-highlighted { background-color: #212121!important } .oo-ui-optionWidget-selected { background-color: #1f1f1f!important } input,select,.oo-ui-buttonElement-button,#mw-scribunto-input,.diff-context { color: #fff!important; background-color: #1f1f1f!important; border: 1px solid #333!important } legend { color: #aaa } .content .mw-parser-output>h2 { border-bottom: 2px solid #333 } .content .mw-parser-output>h3 { border-bottom: 1px solid #333; margin-bottom: .5em } .content .section-heading { border-bottom: 1px solid #aaa } .content kbd,.content samp,.content code,.content pre,.content .toc,.content .infobox { background-color: #1f1f1f!important; border-color: #333!important } .content .infobox td { border-color: #333!important } .infobox tr { color: #fff!important } table.wikitable>tr>th,table.wikitable>tr>td { background-color: #212121; border-color: #333!important } table.wikitable>tr>th { background-color: #2b2b2b } table.wikitable>tr:nth-child(odd)>td { background: #2b2b2b } table.wikitable>*>tr>th,table.wikitable>*>tr>td { background-color: #212121; border-color: #333!important } table.wikitable>*>tr>th { background-color: #2b2b2b } table.wikitable>*>tr:nth-child(odd)>td { background: #2b2b2b } .mw-datatable>tr>th,.mw_metadata>tr>th,.mw-datatable>tr>td,.mw_metadata>tr>td { background-color: #212121!important; border-color: #333!important } .mw-datatable>tr>th,.mw_metadata>tr>th { background-color: #2b2b2b!important } .mw-datatable>*>tr>th,.mw_metadata>*>tr>th,.mw-datatable>*>tr>td,.mw_metadata>*>tr>td { background-color: #212121!important; border-color: #333!important } .mw-datatable>*>tr>th,.mw_metadata>*>tr>th { background-color: #2b2b2b!important } .footer { background-image: linear-gradient(to bottom,rgba(26,26,26,0.85),#1a1a1a),url(https://wiki.hypixel.net/images/artwork.png); border-top: 1px solid #1a1a1a } .header-chrome:before { background-image: radial-gradient(farthest-side at top,rgba(26,26,26,0.5),#1a1a1a),url(https://wiki.hypixel.net/images/artwork.png)!important } .oo-ui-iconElement-icon,.oo-ui-indicatorElement-indicator { filter: invert(1) hue-rotate(180deg) brightness(1.2) } .mw-ui-icon:not(.mw-ui-icon-wikimedia-history-invert):before { filter: invert(1) hue-rotate(180deg) brightness(1.2) } .mw-ui-icon:not(.mw-ui-icon-mf-expand-invert):before { filter: invert(1) hue-rotate(180deg) brightness(1.2) } .last-modified-bar { background-color: #1f1f1f!important } .last-modified-bar .last-modified-bar__text { color: #fff!important } .oo-ui-panelLayout-framed { background-color: #1f1f1f!important } .minerva__tab { color: #aaa!important } .mw-ui-icon-with-label-desktop:hover,.mw-ui-icon-with-label-desktop:focus,.mw-ui-icon-with-label-desktop:active,.mw-ui-icon-with-label-desktop:visited { color: #aaa!important } .page-heading>h1,.page-heading>.tagline { color: #fff!important } .toggle-list__list { color: #fff!important; background-color: #1f1f1f!important; box-shadow: 0 5px 17px 0 rgba(0,0,0,.24),0 0 1px #000!important; border: 1px solid #333 } .search { box-shadow: 0 0 10px #1f1f1f!important } .search,.page-actions-menu,#filetoc,.warningbox { background-color: #1f1f1f!important; border-color: #333!important } .toggle-list-item:hover { background: #000; color: #fff } .blocks-item-description,.mw-mf-user { color: #fff!important } .blocks-item { box-shadow: 0 2px 15px rgba(35,35,35,.5)!important; border: 1px solid #333!important; background-color: #212121 } .mw-ui-button { background-color: #1f1f1f!important; border: 1px solid #333!important; color: #fff!important } .mw-ui-button:hover { background-color: #212121!important } .mw-history-undo a,.mw-rollback-link a { background-color: #1f1f1f!important; border: 1px solid #333!important; color: #fff!important } .mw-history-undo a:hover,.mw-rollback-link a:hover { background-color: #212121!important } .toggle-list-item__label { color: #aaa!important } .page-list .info,.page-list .component { color: #aaa!important } .page-list li { border-color: #333!important } .topic-title-list .info,.topic-title-list .component { color: #aaa!important } .topic-title-list li { border-color: #333!important } .site-link-list .info,.site-link-list .component { color: #aaa!important } .site-link-list li { border-color: #333!important } .page-list.side-list .list-thumb { color: #aaa!important } .topic-title-list.side-list .list-thumb { color: #aaa!important } .site-link-list.side-list .list-thumb { color: #aaa!important } ul.mw-contributions-list li { border-color: #1f1f1f!important } ul.special li { border-color: #1f1f1f!important } .ns-special .content-header { border-color: #1f1f1f!important } .mw-prefs-buttons { border-color: #1f1f1f!important } #mw-mf-page-left { box-shadow: 0 5px 17px 0 rgba(0,0,0,.24),0 0 1px #000!important } #mw-mf-page-left ul li { background-color: #1f1f1f!important; color: #fff!important } #mw-mf-page-left ul li a { color: #aaa!important } #mw-mf-page-left li:hover { background-color: #000!important } .mw-ui-icon-element:not(.disabled):hover { background-color: rgba(0,0,0,.4) }}@media only screen and (min-width: 720px) { .header .branding-box { width:auto!important; min-width: 82px } .overlay.search-overlay .overlay-title { padding-left: 236px!important; width: 380px!important } #page-actions a { color: #fff!important } #page-actions label { color: #fff!important }}@media only screen and (max-width: 720px) { #footer-company { padding:0 0 30px; text-align: center; width: 100% } #footer-links { max-height: 100%; text-align: center } .header-chrome:before { background-image: linear-gradient(to bottom,rgba(255,255,255,0.5),#ffffff),url(https://wiki.hypixel.net/images/artwork.png)!important; height: 170px!important } .last-modified-bar { margin: 0 16px } .header-chrome:before { background-image: linear-gradient(to bottom,rgba(26,26,26,0.5),#1a1a1a),url(https://wiki.hypixel.net/images/artwork.png)!important }}@media only screen and (min-width: 1000px) { .footer-inner { padding:0; width: 90% }}@media only screen and (max-width: 1000px) { #footer-links { max-width:100% } .footer-inner { padding: 0 5%!important; width: calc(90%)!important }}.infobox { border: 15px solid #232445!important; border-image: url(https://wiki.hypixel.net/images/hypixel/borders/square_border.png) 1000 1000 repeat!important; border-image-width: 100px!important; border-image-outset: 2px!important; border-collapse: separate!important}.infobox { background-color: #f2f2f2; border-collapse: collapse; clear: both; display: table!important; float: right; margin: 0!important; margin-left: 20px!important; width: 320px; margin-bottom: 15px!important; table-layout: fixed}.infobox table { border-collapse: inherit!important}.infobox img { display: block; margin: 20px auto; max-width: 150px; height: auto}.infobox td { border-top: 1px solid #c7c7c7; padding: 2px 8px; text-align: right}.infobox td:first-of-type { font-weight: 700; text-align: left}.infobox td:last-child { float: right; width: 100%; text-align: right}.infobox tr:first-of-type>th { font-size: 16px; font-weight: 700; padding: 10px 0; text-align: center}.infobox.minor { border-image-width: 0 100px 100px 100px!important; border-width: 0 15px 15px!important; margin-top: -15px!important}.infobox tr:first-of-type>td { border-top: none}.mw-parser-output .infobox:last-of-type { margin-bottom: 15px}span.color-divine,span.color-light_blue,span.color-aqua { color: #5ff!important}span.color-black { color: #000!important}span.color-rare,span.color-blue { color: #55f!important}span.color-dark_aqua { color: #0aa!important}span.color-dark_blue { color: #00a!important}span.color-dark_gray { color: #555!important}span.color-dark_green { color: #0a0!important}span.color-epic,span.color-dark_purple { color: #a0a!important}span.color-dark_red { color: #a00!important}span.color-legendary,span.color-orange,span.color-gold { color: #fa0!important}span.color-gray { color: #aaa!important}span.color-uncommon,span.color-green { color: #5f5!important}span.color-pink,span.color-mythic,span.color-light_purple { color: #f5f!important}span.color-supreme,span.color-special,span.color-very-special,span.color-red { color: #f55!important}span.color-common,span.color-white { color: #fff!important}span.color-yellow { color: #ff5!important}.tabber__header__prev:after,.tabber__header__next:after { filter: invert(1)}:not(.infobox) .tabber__tab--active { background-color: rgba(51,102,204,.2)}:not(.infobox) .tabber__panel,:not(.infobox) .tabber__header { background-color: #1f1f1f; border: 1px solid #333}:not(.infobox) .tabber__panel { padding: 1em!important}:not(.infobox) .tabber__panel h1,:not(.infobox) .tabber__panel h2,:not(.infobox) .tabber__panel h3 { margin-top: 0}.diff-addedline .diffchange { background: #0083ff}.codeEditor-status { color: #000!important}#toctogglecheckbox:not(:checked)+.toctitle { border-bottom: 1px solid #333; margin-bottom: 10px}a.new { color: #d33!important}.contributionscores { width: 100%}.contributionscores td { text-align: center!important}.contributionscores .header { display: table-row}.contributionscores .content { width: auto}.wikiEditor-ui-toolbar { background-color: #1f1f1f!important}.wikiEditor-ui-toolbar .label:after { filter: invert(1) hue-rotate(180deg) brightness(1.2)}.wikiEditor-ui-toolbar .tabs .tab a::before { filter: invert(1) hue-rotate(180deg) brightness(1.2)}.wikiEditor-ui .wikiEditor-ui-view { border: 1px solid #54595d}.wikiEditor-ui-toolbar { box-shadow: 0 10px 9px 0 rgba(0,0,0,.1)}.wikiEditor-ui-toolbar .sections .section { border-top: none}.wikiEditor-ui-toolbar .group { border-right: none; border-left: none}.tabber__panel { overflow: visible}:not(.tabber__panel--active).tabber__panel { display: none}.tabber__section { height: auto!important; overflow: visible}.infobox td { font-size: 13px}.minecraft-inventory td { font-size: 15px!important}.content { padding: 0}.tabber__tab--active,.tabber__tab--active:visited { box-shadow: inset 0 -2px 0 0 #ffc376; border-width: 0 1px; background-color: rgba(255,195,118,.1)!important; font-weight: 700}.tabber__tab--active a:active,.tabber__tab a:visited { color: #ffc376!important}.tabber__tab:hover { box-shadow: inset 0 -2px 0 0 #ffc376; color: #ffc376; filter: brightness(1.5)}.tabber__tab a:active,.tabber__tab a:visited { color: #bdbcb9!important}.tabber__tabs { box-shadow: none!important}.tabber__tabs a:first-of-type { border-left: none}.tabber__tab { color: #36c; line-height: 30px; font-weight: 400}.tabber { margin-bottom: 5px}#mw-mf-page-left ul { list-style-type: none; padding-left: 0}#mw-mf-page-left li { margin-bottom: 0}#mw-mf-page-left ul li a { color: #aaa!important}#mw-mf-main-menu-button:hover+#mw-mf-page-left,#mw-mf-page-left:hover { visibility: visible}.mw-hypixel-right ul { padding-left: 0}.mw-hypixel-right li { margin-bottom: 0}.mw-hypixel-right a { text-decoration: none}table.mw-collapsible :first-child tr:first-child th:last-child::before { color: #ffc376!important}.infobox.minor img,.remove-img-span img { display: inline!important; margin: 0!important}.infobox.minor tr:first-of-type>th { padding: 7px; border-bottom: 1px solid #333!important}.infobox.minor tr:nth-of-type(2)>td { border-top: none}.occupants-minor,.resources-minor { text-align: left!important; font-weight: 400; padding: 5px 0 0!important}.occupants-minor:first-of-type,.resources-minor:first-of-type { border-right: 1px solid #333!important}.occupants-minor li,.resources-minor li,.materials-minor li { margin-bottom: 0!important}.occupants-minor ul,.resources-minor ul,.materials-minor ul { list-style: none!important; padding: 7px!important; font-weight: 400!important}.color-wheel-minor { border-radius: 50px; border-style: solid; border-width: 30px; height: 0; width: 0; transform: rotate(45deg)}.loot-drops-minor li { list-style-type: none; margin-bottom: 0}.gemstone-slot-minor { text-align: center!important; padding: 5px}.upgrades-low-minor { text-align: center!important; font-weight: 400!important; border-right: 1px solid #333!important}.upgrades-right-minor { padding: 2px!important; padding-top: 5px!important; text-align: center!important}.upgrades-text-minor { font-size: 15px!important; font-weight: 700!important}.attributes-minor { text-align: center!important; font-weight: 400!important; border-right: 1px #333 solid!important}.attributes-text-minor { font-size: 13px!important; font-weight: 700!important}.container-navbox { max-width: 100%; height: auto; padding: 6px; font-size: 15px; background-color: #1f1f1f; border: 1px solid #c8ccd1; border-color: #333!important; border-image: url(https://wiki.hypixel.net/images/hypixel/borders/classic_border.png) 1000 1000 repeat!important; border-image-width: 35px!important; border-image-outset: 2px!important; clear: both}.container-navbox-header { width: auto; height: 35px; padding: 10px; border-bottom: 2px solid #333; text-align: center; display: flex; flex-direction: row; align-items: center; justify-content: space-between; font-size: 18px; vertical-align: middle}.container-navbox-header p { margin: 0!important}.container-navbox-section { max-width: 100%; height: auto; border-bottom: 2px solid #333; display: flex; flex-direction: row; background-color: #1f1f1f; column-gap: 5px}.container-navbox-section:last-child { border-bottom: none}.container-navbox-group-header { width: 200px; max-height: 100%; padding: 1em; display: flex; align-items: center; background-color: #1f1f1f; font-weight: 700; white-space: pre-wrap; column-gap: 10px}.container-navbox-group { width: 100%; padding: 15px 1em}.container-navbox-group ul { columns: 220px auto}.container-navbox-group ul li { margin-bottom: 5px}.dropdown:hover .dropdown-content { visibility: visible; opacity: 1}blockquote { font-family: Raleway,helvetica,serif!important}.cata-image-loot-tabber * .tabber__tabs a::before { content: ""; width: 35px; height: 45px; background-position: center; background-repeat: no-repeat; background-size: cover}.cata-image-loot-tabber * .tabber__tabs a:nth-child(1)::before { background-image: url(https://wiki.hypixel.net/images/a/a8/SkyBlock_furniture_wood_chest_plus.png)}.cata-image-loot-tabber * .tabber__tabs a:nth-child(2)::before { background-image: url(https://wiki.hypixel.net/images/b/be/SkyBlock_furniture_gold_chest_plus.png)}.cata-image-loot-tabber * .tabber__tabs a:nth-child(3)::before { background-image: url(https://wiki.hypixel.net/images/e/e9/SkyBlock_furniture_diamond_chest_plus.png)}.cata-image-loot-tabber * .tabber__tabs a:nth-child(4)::before { background-image: url(https://wiki.hypixel.net/images/8/82/SkyBlock_furniture_emerald_chest_plus.png)}.cata-image-loot-tabber * .tabber__tabs a:nth-child(5)::before { background-image: url(https://wiki.hypixel.net/images/b/be/SkyBlock_furniture_ender_chest_plus.png)}.cata-image-loot-tabber * .tabber__tabs a:nth-child(6)::before { background-image: url(https://wiki.hypixel.net/images/b/be/SkyBlock_furniture_ender_chest_plus.png)}.boss-quote-table-quote { font-family: sans,serif; font-size: 40px; font-weight: 700; color: #f55; padding: 16px 10px; line-height: .5}.toc>ul { margin: 0 5em 0 32px!important}.toctogglecheckbox~ul { display: none}.toctogglecheckbox:not(:checked)~ul { display: block}.dialogue-headine { padding: .5em 0; line-height: 1.3; word-wrap: break-word; word-break: break-word; font-weight: 700}.content code { padding: .1em .4em}code { border-image: none!important}.mw-parser-output { display: inline-block; width: 100%; max-width: 100%}@media(min-width: 1000px) { .header-container.header-chrome { position:fixed; z-index: 2; width: 100%; top: 0; padding: 0!important } .header-container.header-chrome:before { box-shadow: 0 0 20px 10px #1a1a1a } #mw-mf-page-center,#mw-mf-page-center::before { top: 100px!important } .minerva-user-menu-list { top: 60px }}@media(max-width: 1000px) { .hypixel-site-navigation .toggle-list__toggle { padding-left:0!important; padding-right: 0!important } #hypixel-site-navigation-wrapper { padding: 0 .75em }}@media(max-width: 720px) { .header { flex-wrap:wrap!important; height: auto!important; justify-content: space-around!important } #hypixel-site-navigation-wrapper { order: 3; flex-wrap: wrap!important; row-gap: 15px; justify-content: space-around } #hypixel-site-navigation-wrapper .toggle-list__list { left: 0!important; width: 100%!important } .branding-box { width: 80px; height: 40px } .search-box { width: 100%!important; left: 0!important }}.main-menu-mask { display: none!important}#hypixel-site-navigation-wrapper { display: flex; flex-wrap: nowrap}.hypixel-site-navigation { color: #fff!important; text-shadow: 1px 1px rgba(0,0,0,.5)}.hypixel-site-navigation a { color: inherit!important}.hypixel-site-navigation .toggle-list__toggle { padding: .75em}.hypixel-site-navigation .toggle-list__toggle:hover { background-color: rgba(0,0,0,.4)}.hypixel-site-navigation .toggle-list__list { top: 100%; min-width: 200px}.hypixel-site-navigation .toggle-list__list .toggle-list-item .toggle-list-item__anchor { min-height: 20px}.toggle-list__list,.minerva-user-menu-list { border-radius: 3px}.minerva-user-navigation { width: auto!important; min-width: revert!important}.header { display: flex; justify-content: space-between; align-content: center; align-items: center; flex-direction: row; flex-wrap: nowrap}.hypixel-site-navigation>label::after { content: ""; background-image: linear-gradient(transparent,transparent),url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+ZXhwYW5kPC90aXRsZT48ZyBmaWxsPSIjYTJhOWIxIj48cGF0aCBkPSJNMTcuNSA0Ljc1bC03LjUgNy41LTcuNS03LjVMMSA2LjI1bDkgOSA5LTl6Ii8+PC9nPjwvc3ZnPg==); display: inline-block; vertical-align: middle; min-width: 1em; min-height: 1em; padding: 0 0 0 20px; background-repeat: no-repeat; background-size: 1em 1em; background-position: center}#mw-mf-page-left ul li a span,.toggle-list-item__label { color: #fff!important}.mw-ui-icon-wikimedia-flag-ltr-base20:before { background-image: url(https://wiki.hypixel.net/resources/lib/ooui/themes/wikimediaui/images/icons/flag-ltr.svg)}.mw-ui-icon-wikimedia-articleRedirect-ltr-base20:before { background-image: url(https://wiki.hypixel.net/resources/lib/ooui/themes/wikimediaui/images/icons/articleRedirect-ltr.svg)}@media(max-width: 720px) { table.infobox { display:table!important } table.wikitable { display: block!important }}table.infobox { display: revert!important}.infobox ul { list-style: none}#userloginForm .mw-userlogin-rememberme { display: block!important}.mw-hp-tree { color: #5f5; margin-left: 20px}.mw-hp-tree li { margin-bottom: 0; list-style-type: disc}.mw-hp-tree li::marker { color: #fff}.mw-hp-tree ul:first-of-type { margin-top: 6px}.mw-hp-tree ul:last-of-type { margin-bottom: 6px}.mw-hp-tree-container { margin-left: 5px}.mw-hp-tree-text::after { content: "Expand"; color: #ba91ff; display: inline-block}.mw-hp-tree-text-down::after { content: "Collapse"; color: #7698ff; display: inline-block}.mw-hp-tree-anchor { cursor: pointer; user-select: none}.mw-hp-tree-nested { display: none}.mw-hp-tree-active { display: block}.mw-display-qrcode { border: 2px solid #fff}.mw-overlays-container .search-overlay { top: 71px}.mw-overlays-container .search-overlay .search-content,.mw-overlays-container .search-overlay .results { margin-left: 0!important}.mw-overlays-container .search-overlay .search-content { z-index: 4; position: relative; border: none!important}.mw-overlays-container .search-overlay .overlay-content { padding-top: 0!important; z-index: 3}.mw-overlays-container .search-overlay .overlay-header { flex-wrap: nowrap!important}.mw-overlays-container .search-overlay .overlay-title { padding-right: 15px}.mw-overlays-container .search-overlay .search { max-width: unset!important}.mw-overlays-container .search-overlay .clear { right: 5px!important}.mw-overlays-container .search-overlay .results { position: relative; box-shadow: none!important; background: 0 0!important}.mw-overlays-container .search-overlay .results ul>li { color: #fff; background: #1f1f1f; border: 1px solid #333!important; border-radius: 6px; margin: 5px 0; box-shadow: 0 0 10px #1f1f1f!important}.mw-overlays-container .search-overlay .results .list-thumb { background-color: #212121; border-radius: 6px}.mw-overlays-container .search-overlay .results .page-summary h2,.mw-overlays-container .search-overlay .results .page-summary h3 { color: #fff}@media(min-width: 720px) { .overlay-content { padding-left:236px!important } .overlay-header-container { z-index: 4!important } .search-content,.results { width: 380px!important }}@media(max-width: 720px) { div.overlay-header-container { position:relative!important; top: -71px!important } .overlay-content { padding: 0 15px } .search-content,.results { width: 100%!important }}table.sortable .headerSort { padding-right: 21px!important; position: relative}table.sortable .headerSort:after { background-image: inherit; content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-repeat: no-repeat; background-position: center right; filter: invert(100%); pointer-events: none}.warningbox>p { color: #fff; margin: .5em 0}.suggestions-special { border-radius: 6px}.mw-dismissable-notice { background-color: #1f1f1f; border-radius: 8px; border: 1px solid #333; border-image-width: 35px!important; border-image-outset: 2px!important}.mw-dismissable-notice { position: fixed; display: block; bottom: 25px; z-index: 6; width: 100%; max-width: 92%!important; box-shadow: 0 -5px 30px 20px rgba(0,0,0,.3); margin: 0!important; left: 50%; transform: translateX(-50%)}.mw-dismissable-notice-body { padding: 20px; margin: 0!important}.mw-dismissable-notice-close { padding: 20px}.banner-container { position: relative}.warningbox { color: #fff!important}#content { position: relative; z-index: 1; background-color: transparent!important}div#mw-mf-page-center::before { content: ""; position: fixed; top: 0; bottom: 0; right: 0; height: 100%; width: 100%; background-image: linear-gradient(#1a1a1a,transparent),url(https://wiki.hypixel.net/images/hypixel/background.png); background-image: linear-gradient(#1a1a1a,transparent),image-set(url(https://wiki.hypixel.net/images/hypixel/background.png) 1x,url(https://wiki.hypixel.net/images/hypixel/background-large.png) 2x); background-attachment: fixed; background-color: #1a1a1a; background-position: center; background-repeat: no-repeat; background-size: cover; opacity: .075; z-index: 0; pointer-events: none}.page-Main_Page #wrapper #content { background: 0 0!important}.last-modified-bar,.footer { position: relative}.last-modified-bar a,.last-modified-bar a:visited { color: #fff}.overlay { z-index: 2!important}.mwe-math-element { overflow: auto; display: block}#page-secondary-actions { display: none}.loot-drops-minor li { margin-bottom: 0!important}.warningbox { color: #fff}.warningbox>p { margin: .5em 0!important; font-size: 17px}.toctitle>.mw-ui-icon-minerva-listBullet { display: none}.infobox img { max-width: 100%!important}.hp-loottable td { border: 2px solid #1a1a1a!important}.hp-loottable td:last-child { color: #5f5}.is-affected-by-mf { outline: dotted 3px transparent; outline-offset: -1px; outline-color: #5ff}.is-affected-by-pl { outline: dotted 3px transparent; outline-offset: -1px; outline-color: #f5f}.is-affected-by-mf.is-affected-by-pl { outline-color: #b591b7!important}.cata-image-loot-tabber * .tabber__tabs a:nth-child(1)::before { background-image: url(https://wiki.hypixel.net/images/b/b9/SkyBlock_furniture_dungeon_wood_reward_chest.png); height: 65px}.cata-image-loot-tabber * .tabber__tabs a:nth-child(2)::before { background-image: url(https://wiki.hypixel.net/images/8/85/SkyBlock_furniture_dungeon_gold_reward_chest.png); height: 65px}.cata-image-loot-tabber * .tabber__tabs a:nth-child(3)::before { background-image: url(https://wiki.hypixel.net/images/9/98/SkyBlock_furniture_dungeon_diamond_reward_chest.png); height: 65px; width: 40px}.cata-image-loot-tabber * .tabber__tabs a:nth-child(4)::before { background-image: url(https://wiki.hypixel.net/images/e/e4/SkyBlock_furniture_dungeon_emerald_reward_chest.png); height: 65px; width: 40px}.cata-image-loot-tabber * .tabber__tabs a:nth-child(5)::before { background-image: url(https://wiki.hypixel.net/images/4/40/SkyBlock_furniture_dungeon_obsidian_reward_chest.png); height: 65px; width: 50px}.cata-image-loot-tabber * .tabber__tabs a:nth-child(6)::before { background-image: url(https://wiki.hypixel.net/images/8/87/SkyBlock_furniture_dungeon_bedrock_reward_chest.png); height: 65px; width: 55px}.diff-deletedline .diffchange { background: #988e78!important}.hide { display: none}.page-notif-box { border: 2px solid #333!important; border-left-width: 10px!important; border-radius: 6px; border-collapse: separate!important; width: 75%; background-color: #1f1f1f!important; box-shadow: 0 0 10px #1f1f1f!important; display: flex; margin: auto!important; color: #fff; font-weight: 700; margin-top: 25px!important; margin-bottom: 25px!important}.page-notif-box tr>td { border: none; padding: .25em .9em}.page-notif-box img { max-width: revert!important; flex-shrink: 0}.page-notif-box-updating,.page-notif-box-changed { border-color: #e7871b!important}.page-notif-box-no-obtain,.page-notif-box-cannot-obtain { border-color: #e30000!important}.page-notif-box-alpha { border-color: #0d6f67!important}.hp-input { height: 35px; width: 100%; border: none!important}.dungeon-calc-container td,.loot-calc-container td { border: 2px solid #1a1a1a}.dungeon-calc-button,.loot-calc-button { cursor: pointer; vertical-align: bottom; background-color: #3f7dfb!important; transition-duration: .35s; padding: 5px!important}.dungeon-calc-button:hover,.loot-calc-button:hover { background-color: #5e93fe!important}.hp-loottable td:last-child { color: #5f5}.dungeon-loottable td:last-child { color: #5f5}.listspacing li { margin-bottom: 0!important}.listspacing li:last-child { margin-bottom: 1em!important}.listdisplay li { display: inline!important}.categoryboxcontainer { max-width: 100%; height: 35px; background-color: #1f1f1f; border: 1px solid #333; padding: 3px; font-size: 15px; clear: both}.categoryboxcontainer li { display: inline-block; padding-left: 5px; padding-right: 5px; line-height: 35px}.categoryboxcontainer li:first-child { padding-left: 0; border-left: none}.categoryboxcontainer li:nth-child(2) { border-left: none}.categoryboxcontainer li:empty { display: none}.tooltiptemp { position: relative!important; display: inline-block!important; text-decoration: underline dotted; cursor: help}.tooltiptemp .tooltiptexttemp { visibility: hidden; width: 240px; background-color: #000; color: #fff; text-align: center; border: 1px #333 solid; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1; bottom: 100%!important; left: 50%!important; margin-left: -120px!important; opacity: 0; transition: opacity 1s}.tooltiptemp .tooltiptexttemp::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -5px; border-width: 5px; border-style: solid; border-color: #000 transparent transparent transparent}.tooltiptemp:hover .tooltiptexttemp { visibility: visible; opacity: 1}.tooltiptemp p { margin: 0}.raw-mctooltip { position: relative!important; display: inline-block!important; font-weight: 400}.raw-mctooltip:hover .raw-mctooltiptext { display: inline}.raw-mctooltiptext { display: none; font-family: minecraft,helvetica,serif; margin: 0}.content .mw-parser-output>h2 { padding: .25em 0; font-size: 1.8em; margin-top: 35px}.content .mw-parser-output>h2,.content .mw-parser-output>h3 { text-transform: uppercase; font-weight: 400}.heading-holder { padding: 0!important}.mw-body-content blockquote { background-color: #212121; border-radius: 6px; border: 1px solid #333!important; border-left-width: 5px!important; display: table}.tabber__tab { font-weight: 400!important; column-gap: 10px}.tabber__header .tabber__tab:not(.tabber__tab--active) { color: #fff}.mw-collapsible-toggle { padding-left: 5px}.tabber__header,.tabber__section,.tabber__panel { scroll-snap-type: none!important; overscroll-behavior: none!important; scroll-snap-align: none!important; overflow: hidden!important}.mw-userlogin-help { display: none}@media(min-width: 720px) { .header .branding-box { max-height:55px }}@font-face { font-family: minecraft; src: url(https://wiki.hypixel.net/fonts/minecraft.woff) format("woff")}.minecraft-inventory { -moz-user-select: none; -ms-user-select: none; -webkit-user-select: none; background-color: #c6c6c6; border: 4px solid; border-color: #fff #555 #555 #fff; border-radius: 4px; box-shadow: 0 0 0 1px #000; color: #404040; display: inline-block; font-family: minecraft,serif; font-size: 15px; font-weight: 400; padding: 2px 6px 6px; user-select: none; margin: 10px 0}.minecraft-inventory table { border-collapse: separate; margin: 0!important}.minecraft-inventory td { background: #8b8b8b no-repeat center center/32px 32px; border: 2px solid; border-color: #373737 #fff #fff #373737; box-sizing: border-box; padding: 0; position: relative; width: 36px}.minecraft-inventory td>.external { background: 0 0; padding: 0}.minecraft-inventory td>a:hover { text-decoration: none}.minecraft-inventory td:hover:after { background: #fff; content: ""; float: left; height: 100%; left: 0; opacity: .5; pointer-events: none; position: absolute; top: 0; width: 100%}.minecraft-inventory td:hover .mctooltip { display: block}.minecraft-inventory>span { padding: 2px}.minecraft-inventory tr { height: 36px}.minecraft-inventory .enchanted::before { content: ""; height: 32px; left: 0; position: absolute; top: 0; width: 32px; background-image: url(https://wiki.hypixel.net/images/minecraft/glint.webp); mix-blend-mode: color-dodge}.minecraft-inventory .enchanted::after { content: ""; height: 32px; left: 0; position: absolute; top: 0; width: 32px; background-image: url(https://wiki.hypixel.net/images/minecraft/item-spritesheet_cutout.png); background-position: inherit}.minecraft-inventory .amount { margin: 0; position: relative; z-index: 999}.minecraft-inventory .sbsprite { background-repeat: no-repeat; color: #fff; direction: rtl; display: block; text-shadow: 2px 2px #3f3f3f; background-image: url(https://wiki.hypixel.net/images/skyblock/item-spritesheet.png); height: 22px; line-height: 44px; margin: 0 5px; text-indent: -8px; width: 22px}.minecraft-inventory .mcsprite { background-repeat: no-repeat; color: #fff; direction: rtl; display: block; text-shadow: 2px 2px #3f3f3f; background-image: url(https://wiki.hypixel.net/images/minecraft/item-spritesheet.png); height: 32px; line-height: 54px; text-indent: -2px; width: 32px}.minecraft-inventory .sbpet { background-repeat: no-repeat; color: #fff; direction: rtl; display: block; text-shadow: 2px 2px #3f3f3f; background-image: url(https://wiki.hypixel.net/images/skyblock/pet-spritesheet.png); height: 22px; line-height: 44px; margin: 0 6px; text-indent: -8px; width: 20px}.mctooltip { background: rgba(16,0,16,.93); border: 2px solid; border-image: linear-gradient(to bottom,rgba(80,0,255,0.31),rgba(40,0,127,0.31)); border-image-slice: 1; border-radius: 4px; box-shadow: 0 0 0 2px rgba(16,0,16,.93); display: none; line-height: 18px; margin-left: 15px; margin-top: -30px; padding: 4px 4px 3px; position: fixed; text-indent: initial; text-shadow: 2px 2px #3f3f3f; z-index: 9999}.mctooltip>span { direction: ltr; display: block; white-space: nowrap; text-align: left}.mctooltip>span:nth-child(1):not(:last-child) { padding-bottom: 5px}.mctooltip>span:nth-child(n+2) { float: left}.mctooltip>span:nth-child(n+2):not(:last-child) { padding-right: 4px}.mctooltip>span.inline { display: inline-block!important}.mctooltip .rarity-divine { color: #5ff}.mctooltip .rarity-rare { color: #55f; text-shadow: 2px 2px #15153f}.mctooltip .rarity-epic { color: #a0a; text-shadow: 2px 2px #2a002a}.mctooltip .rarity-supreme { color: #a00; text-shadow: 2px 2px #2a0000}.mctooltip .rarity-legendary { color: #fa0; text-shadow: 2px 2px #2a2a00}.mctooltip .rarity-uncommon { color: #5f5; text-shadow: 2px 2px #153f15}.mctooltip .rarity-mythic { color: #f5f; text-shadow: 2px 2px #3f153f}.mctooltip .rarity-veryspecial { color: #f55; text-shadow: 2px 2px #3f1515}.mctooltip .rarity-special { color: #f55; text-shadow: 2px 2px #3f1515}.mctooltip .color-aqua { text-shadow: 2px 2px #153f3f}.mctooltip .color-black { text-shadow: 2px 2px #000}.mctooltip .color-blue { text-shadow: 2px 2px #15153f}.mctooltip .color-dark_aqua { text-shadow: 2px 2px #002a2a}.mctooltip .color-dark_blue { text-shadow: 2px 2px #00002a}.mctooltip .color-dark_gray { text-shadow: 2px 2px #151515}.mctooltip .color-dark_green { text-shadow: 2px 2px #002a00}.mctooltip .color-dark_purple { text-shadow: 2px 2px #2a002a}.mctooltip .color-dark_red { text-shadow: 2px 2px #2a0000}.mctooltip .color-gold { text-shadow: 2px 2px #2a2a00}.mctooltip .color-gray { text-shadow: 2px 2px #2a2a2a}.mctooltip .color-green { text-shadow: 2px 2px #153f15}.mctooltip .color-light_purple { text-shadow: 2px 2px #3f153f}.mctooltip .color-red { text-shadow: 2px 2px #3f1515}.mctooltip .color-white { text-shadow: 2px 2px #3f3f3f}.mctooltip .color-yellow { text-shadow: 2px 2px #3f3f15}.color-aqua { color: #5ff}.color-black { color: #000}.color-blue { color: #55f}.color-dark_aqua { color: #0aa}.color-dark_blue { color: #00a}.color-dark_gray { color: #555}.color-dark_green { color: #0a0}.color-dark_purple { color: #a0a}.color-dark_red { color: #a00}.color-gold { color: #fa0}.color-gray { color: #aaa}.color-green { color: #5f5}.color-light_purple { color: #f5f}.color-red { color: #f55}.color-white { color: #fff}.color-yellow { color: #ff5}.mcentity { background-image: url(https://wiki.hypixel.net/images/minecraft/entity-spritesheet.png); height: 16px; width: 16px}.mcblock { background-image: url(https://wiki.hypixel.net/images/minecraft/block-spritesheet.png); height: 16px; width: 16px}.sbspray { background-image: url(https://wiki.hypixel.net/images/skyblock/spray-spritesheet.png); height: 128px; width: 128px}.sbnpc { background-image: url(https://wiki.hypixel.net/images/skyblock/npc-spritesheet.png); height: 120px; width: 270px}.sbnpc-_56ms { background-position: 0 0}.sbnpc-adventurer { background-position: -120px 0}.sbnpc-agents { background-position: -240px 0}.sbnpc-anita { background-position: -360px 0}.sbnpc-archeologist { background-position: -480px 0}.sbnpc-armorsmith { background-position: -600px 0}.sbnpc-arthur { background-position: -720px 0}.sbnpc-artist { background-position: -840px 0}.sbnpc-artist_2 { background-position: -960px 0}.sbnpc-auction_agent_0 { background-position: -1080px 0}.sbnpc-auction_agent_1 { background-position: -1200px 0}.sbnpc-auction_agent_2 { background-position: -1320px 0}.sbnpc-auction_agent_3 { background-position: -1440px 0}.sbnpc-auction_master { background-position: -1560px 0}.sbnpc-baker { background-position: -1680px 0}.sbnpc-banker { background-position: -1800px 0}.sbnpc-bartender { background-position: -1920px 0}.sbnpc-bazaar { background-position: -2040px 0}.sbnpc-bazaar_assistant { background-position: -2160px 0}.sbnpc-beekeeper { background-position: -2280px 0}.sbnpc-bestiary { background-position: -2400px 0}.sbnpc-beth { background-position: -2520px 0}.sbnpc-blue_shark { background-position: -2640px 0}.sbnpc-bodyguard_1 { background-position: -2760px 0}.sbnpc-bodyguard_2 { background-position: 0 -270px}.sbnpc-bonzo { background-position: -120px -270px}.sbnpc-bonzo_summon_0 { background-position: -240px -270px}.sbnpc-bonzo_summon_1 { background-position: -360px -270px}.sbnpc-bonzo_summon_2 { background-position: -480px -270px}.sbnpc-bonzo_undead { background-position: -600px -270px}.sbnpc-builder { background-position: -720px -270px}.sbnpc-candidate { background-position: -840px -270px}.sbnpc-cannibal_undead { background-position: -960px -270px}.sbnpc-carpenter { background-position: -1080px -270px}.sbnpc-catacombs_blacksmith { background-position: -1200px -270px}.sbnpc-century_simon { background-position: -1320px -270px}.sbnpc-charlie { background-position: -1440px -270px}.sbnpc-clerk_election { background-position: -1560px -270px}.sbnpc-community_shop { background-position: -1680px -270px}.sbnpc-crypt_dreadlord { background-position: -1800px -270px}.sbnpc-crypt_souleater { background-position: -1920px -270px}.sbnpc-crystal_sentry { background-position: -2040px -270px}.sbnpc-dante_grey { background-position: -2160px -270px}.sbnpc-dante_statue { background-position: -2280px -270px}.sbnpc-default_lost_adventurer { background-position: -2400px -270px}.sbnpc-derp_candidate { background-position: -2520px -270px}.sbnpc-diamond_guy { background-position: -2640px -270px}.sbnpc-dictator { background-position: -2760px -270px}.sbnpc-dirt_guy { background-position: 0 -540px}.sbnpc-donpireso { background-position: -120px -540px}.sbnpc-duncan { background-position: -240px -540px}.sbnpc-dungeons_candidate { background-position: -360px -540px}.sbnpc-dungeons_hub_selector { background-position: -480px -540px}.sbnpc-dusk { background-position: -600px -540px}.sbnpc-dwarf_banker { background-position: -720px -540px}.sbnpc-dwarf_citizen_female_5 { background-position: -840px -540px}.sbnpc-dwarf_citizen_female_6 { background-position: -960px -540px}.sbnpc-dwarf_citizen_female_7 { background-position: -1080px -540px}.sbnpc-dwarf_citizen_male_1 { background-position: -1200px -540px}.sbnpc-dwarf_citizen_male_2 { background-position: -1320px -540px}.sbnpc-dwarf_citizen_male_3 { background-position: -1440px -540px}.sbnpc-dwarf_citizen_male_4 { background-position: -1560px -540px}.sbnpc-dwarf_council_female_5 { background-position: -1680px -540px}.sbnpc-dwarf_council_female_6 { background-position: -1800px -540px}.sbnpc-dwarf_council_female_7 { background-position: -1920px -540px}.sbnpc-dwarf_council_female_8 { background-position: -2040px -540px}.sbnpc-dwarf_council_male_1 { background-position: -2160px -540px}.sbnpc-dwarf_council_male_2 { background-position: -2280px -540px}.sbnpc-dwarf_council_male_3 { background-position: -2400px -540px}.sbnpc-dwarf_council_male_4 { background-position: -2520px -540px}.sbnpc-dwarf_militia_1 { background-position: -2640px -540px}.sbnpc-dwarf_militia_2 { background-position: -2760px -540px}.sbnpc-dwarf_militia_3 { background-position: 0 -810px}.sbnpc-dwarf_militia_4 { background-position: -120px -810px}.sbnpc-dwarf_militia_5 { background-position: -240px -810px}.sbnpc-dwarf_militia_6 { background-position: -360px -810px}.sbnpc-dwarf_royalguard_female_5 { background-position: -480px -810px}.sbnpc-dwarf_royalguard_female_6 { background-position: -600px -810px}.sbnpc-dwarf_royalguard_female_7 { background-position: -720px -810px}.sbnpc-dwarf_royalguard_female_8 { background-position: -840px -810px}.sbnpc-dwarf_royalguard_male_1 { background-position: -960px -810px}.sbnpc-dwarf_royalguard_male_2 { background-position: -1080px -810px}.sbnpc-dwarf_royalguard_male_3 { background-position: -1200px -810px}.sbnpc-dwarf_royalguard_male_4 { background-position: -1320px -810px}.sbnpc-economist_candidate { background-position: -1440px -810px}.sbnpc-elle { background-position: -1560px -810px}.sbnpc-emissary_female_1 { background-position: -1680px -810px}.sbnpc-emissary_female_2 { background-position: -1800px -810px}.sbnpc-emissary_female_3 { background-position: -1920px -810px}.sbnpc-emissary_male_1 { background-position: -2040px -810px}.sbnpc-emissary_male_2 { background-position: -2160px -810px}.sbnpc-emissary_male_3 { background-position: -2280px -810px}.sbnpc-end_dealer { background-position: -2400px -810px}.sbnpc-enderman_liquid_hot_magma { background-position: -2520px -810px}.sbnpc-enraged_revenant_horror { background-position: -2640px -810px}.sbnpc-entity_liquid_hot_magma { background-position: -2760px -810px}.sbnpc-event_master { background-position: 0 -1080px}.sbnpc-events_candidate { background-position: -120px -1080px}.sbnpc-fairy { background-position: -240px -1080px}.sbnpc-farm_merchant { background-position: -360px -1080px}.sbnpc-farmer { background-position: -480px -1080px}.sbnpc-farmer_jon { background-position: -600px -1080px}.sbnpc-fire_guy { background-position: -720px -1080px}.sbnpc-fish_merchant { background-position: -840px -1080px}.sbnpc-fisherman { background-position: -960px -1080px}.sbnpc-fishing_candidate { background-position: -1080px -1080px}.sbnpc-flamer_undead { background-position: -1200px -1080px}.sbnpc-forger { background-position: -1320px -1080px}.sbnpc-frank_undead { background-position: -1440px -1080px}.sbnpc-friendly_hiker { background-position: -1560px -1080px}.sbnpc-frost_undead { background-position: -1680px -1080px}.sbnpc-frosty { background-position: -1800px -1080px}.sbnpc-frozen_lost_adventurer { background-position: -1920px -1080px}.sbnpc-furry_e_boy { background-position: -2040px -1080px}.sbnpc-gatekeeper { background-position: -2160px -1080px}.sbnpc-giant_undead { background-position: -2280px -1080px}.sbnpc-goblin { background-position: -2400px -1080px}.sbnpc-goblin_armor_1 { background-position: -2520px -1080px}.sbnpc-goblin_armor_2 { background-position: -2640px -1080px}.sbnpc-goblin_armor_3 { background-position: -2760px -1080px}.sbnpc-goblin_armor_4 { background-position: 0 -1350px}.sbnpc-goblin_king_1 { background-position: -120px -1350px}.sbnpc-goblin_murderlover { background-position: -240px -1350px}.sbnpc-goblin_naked_1 { background-position: -360px -1350px}.sbnpc-goblin_naked_2 { background-position: -480px -1350px}.sbnpc-goblin_naked_3 { background-position: -600px -1350px}.sbnpc-goblin_naked_4 { background-position: -720px -1350px}.sbnpc-goblin_naked_5 { background-position: -840px -1350px}.sbnpc-gold_forger { background-position: -960px -1350px}.sbnpc-goon { background-position: -1080px -1350px}.sbnpc-grandma_wolf { background-position: -1200px -1350px}.sbnpc-great_white_shark { background-position: -1320px -1350px}.sbnpc-guber { background-position: -1440px -1350px}.sbnpc-guildford { background-position: -1560px -1350px}.sbnpc-gulliver { background-position: -1680px -1350px}.sbnpc-gustave { background-position: -1800px -1350px}.sbnpc-haymitch { background-position: -1920px -1350px}.sbnpc-hephaestus { background-position: -2040px -1350px}.sbnpc-holy_lost_adventurer { background-position: -2160px -1350px}.sbnpc-hub_selector { background-position: -2280px -1350px}.sbnpc-hungry_hiker { background-position: -2400px -1350px}.sbnpc-hunter_ava { background-position: -2520px -1350px}.sbnpc-ice_fisherman { background-position: -2640px -1350px}.sbnpc-iron_forger { background-position: -2760px -1350px}.sbnpc-jacob { background-position: 0 -1620px}.sbnpc-jake { background-position: -120px -1620px}.sbnpc-juliette { background-position: -240px -1620px}.sbnpc-kessie { background-position: -360px -1620px}.sbnpc-king_midas { background-position: -480px -1620px}.sbnpc-lapis_miner { background-position: -600px -1620px}.sbnpc-lazy_miner { background-position: -720px -1620px}.sbnpc-leech_undead { background-position: -840px -1620px}.sbnpc-lift_operator { background-position: -960px -1620px}.sbnpc-liquid_hot_magma { background-position: -1080px -1620px}.sbnpc-livid { background-position: -1200px -1620px}.sbnpc-livid_undead { background-position: -1320px -1620px}.sbnpc-lonely_philosopher { background-position: -1440px -1620px}.sbnpc-lumber_merchant { background-position: -1560px -1620px}.sbnpc-lumberjack { background-position: -1680px -1620px}.sbnpc-mason { background-position: -1800px -1620px}.sbnpc-master_tactician { background-position: -1920px -1620px}.sbnpc-mayhem_main { background-position: -2040px -1620px}.sbnpc-mayor { background-position: -2160px -1620px}.sbnpc-melancholic_viking { background-position: -2280px -1620px}.sbnpc-melody { background-position: -2400px -1620px}.sbnpc-mine_merchant { background-position: -2520px -1620px}.sbnpc-mining_candidate { background-position: -2640px -1620px}.sbnpc-minos_champion { background-position: -2760px -1620px}.sbnpc-minos_inquisitor { background-position: 0 -1890px}.sbnpc-minotaur { background-position: -120px -1890px}.sbnpc-mort { background-position: -240px -1890px}.sbnpc-mr_dead_undead { background-position: -360px -1890px}.sbnpc-mute_undead { background-position: -480px -1890px}.sbnpc-nitroholic { background-position: -600px -1890px}.sbnpc-nurse_shark { background-position: -720px -1890px}.sbnpc-old_man_garry { background-position: -840px -1890px}.sbnpc-ooze_undead { background-position: -960px -1890px}.sbnpc-ophelia { background-position: -1080px -1890px}.sbnpc-oringo { background-position: -1200px -1890px}.sbnpc-parasite_undead { background-position: -1320px -1890px}.sbnpc-pat { background-position: -1440px -1890px}.sbnpc-personal_bank_upgrader { background-position: -1560px -1890px}.sbnpc-pet_collector { background-position: -1680px -1890px}.sbnpc-pet_sitter { background-position: -1800px -1890px}.sbnpc-pets_candidate { background-position: -1920px -1890px}.sbnpc-placeholder_candidate { background-position: -2040px -1890px}.sbnpc-player_jerry { background-position: -2160px -1890px}.sbnpc-potato_king { background-position: -2280px -1890px}.sbnpc-professor { background-position: -2400px -1890px}.sbnpc-psycho_undead { background-position: -2520px -1890px}.sbnpc-putrid_undead { background-position: -2640px -1890px}.sbnpc-puzzler { background-position: -2760px -1890px}.sbnpc-rainmaker { background-position: 0 -2160px}.sbnpc-reaper_undead { background-position: -120px -2160px}.sbnpc-redstone_engineer { background-position: -240px -2160px}.sbnpc-refraction { background-position: -360px -2160px}.sbnpc-relenter { background-position: -480px -2160px}.sbnpc-revenant_horror { background-position: -600px -2160px}.sbnpc-revoker_undead { background-position: -720px -2160px}.sbnpc-rick { background-position: -840px -2160px}.sbnpc-romero_final { background-position: -960px -2160px}.sbnpc-romero_normal { background-position: -1080px -2160px}.sbnpc-sadan { background-position: -1200px -2160px}.sbnpc-salesman_christmas { background-position: -1320px -2160px}.sbnpc-salesman_easter { background-position: -1440px -2160px}.sbnpc-salesman_generic { background-position: -1560px -2160px}.sbnpc-salesman_halloween { background-position: -1680px -2160px}.sbnpc-salesman_summer { background-position: -1800px -2160px}.sbnpc-scarf_archer { background-position: -1920px -2160px}.sbnpc-scarf_mage { background-position: -2040px -2160px}.sbnpc-scarf_priest { background-position: -2160px -2160px}.sbnpc-scarf_undead { background-position: -2280px -2160px}.sbnpc-scarf_warrior { background-position: -2400px -2160px}.sbnpc-scoop { background-position: -2520px -2160px}.sbnpc-scorpius { background-position: -2640px -2160px}.sbnpc-shadow_assassin { background-position: -2760px -2160px}.sbnpc-shady_bartender { background-position: 0 -2430px}.sbnpc-shady_cousin { background-position: -120px -2430px}.sbnpc-shaggy { background-position: -240px -2430px}.sbnpc-shepherd { background-position: -360px -2430px}.sbnpc-simon_hat { background-position: -480px -2430px}.sbnpc-sirius { background-position: -600px -2430px}.sbnpc-skeletor_prime { background-position: -720px -2430px}.sbnpc-skull_undead { background-position: -840px -2430px}.sbnpc-slayer { background-position: -960px -2430px}.sbnpc-slayer_candidate { background-position: -1080px -2430px}.sbnpc-snowmaker { background-position: -1200px -2430px}.sbnpc-spirit_bear { background-position: -1320px -2430px}.sbnpc-spooky { background-position: -1440px -2430px}.sbnpc-st_jerry { background-position: -1560px -2430px}.sbnpc-sylent { background-position: -1680px -2430px}.sbnpc-tailor_assistant { background-position: -1800px -2430px}.sbnpc-tailor_owner { background-position: -1920px -2430px}.sbnpc-tammy { background-position: -2040px -2430px}.sbnpc-tear_undead { background-position: -2160px -2430px}.sbnpc-technoblade { background-position: -2280px -2430px}.sbnpc-terracotta { background-position: -2400px -2430px}.sbnpc-terry { background-position: -2520px -2430px}.sbnpc-thirty_virus { background-position: -2640px -2430px}.sbnpc-tiger_shark { background-position: -2760px -2430px}.sbnpc-timedeo { background-position: -2880px 0}.sbnpc-tomioka { background-position: -2880px -270px}.sbnpc-tony { background-position: -2880px -540px}.sbnpc-treasure_horder { background-position: -2880px -810px}.sbnpc-treasure_hunter { background-position: -2880px -1080px}.sbnpc-trevor { background-position: -2880px -1350px}.sbnpc-trinity { background-position: -2880px -1620px}.sbnpc-unstable_lost_adventurer { background-position: -2880px -1890px}.sbnpc-vader_undead { background-position: -2880px -2160px}.sbnpc-vinny { background-position: -2880px -2430px}.sbnpc-walker_undead { background-position: 0 -2700px}.sbnpc-walter { background-position: -120px -2700px}.sbnpc-weaponsmith { background-position: -240px -2700px}.sbnpc-weirdo_0 { background-position: -360px -2700px}.sbnpc-weirdo_1 { background-position: -480px -2700px}.sbnpc-weirdo_2 { background-position: -600px -2700px}.sbnpc-winona { background-position: -720px -2700px}.sbnpc-winter_banker { background-position: -840px -2700px}.sbnpc-wizard { background-position: -960px -2700px}.sbnpc-wizard_candidate { background-position: -1080px -2700px}.sbnpc-wizard_quest { background-position: -1200px -2700px}.sbnpc-wolf_shaman { background-position: -1320px -2700px}.sbnpc-wool_weaver { background-position: -1440px -2700px}.sbnpc-young_lost_adventurer { background-position: -1560px -2700px}.sbnpc-zog { background-position: -1680px -2700px}.sbnpc-zombie_commander { background-position: -1800px -2700px}.sbsprite-cobblestone_generator_10 { background-position: 0 0}.sbsprite-cobblestone_generator_11 { background-position: -22px 0}.sbsprite-danger_3_portal { background-position: -44px 0}.sbsprite-resource_regenerator_crystal { background-position: -66px 0}.sbsprite-sugar_cane_generator_12 { background-position: -88px 0}.sbsprite-cobblestone_generator_12 { background-position: -110px 0}.sbsprite-sugar_cane_generator_11 { background-position: -132px 0}.sbsprite-sugar_cane_generator_10 { background-position: -154px 0}.sbsprite-small_shelves { background-position: -176px 0}.sbsprite-bingo_talisman { background-position: -198px 0}.sbsprite-red_scarf { background-position: -220px 0}.sbsprite-wither_helmet { background-position: -242px 0}.sbsprite-glowstone_generator_11 { background-position: -264px 0}.sbsprite-glowstone_generator_10 { background-position: -286px 0}.sbsprite-fast_travel_crypt { background-position: -308px 0}.sbsprite-present_personality { background-position: -330px 0}.sbsprite-extra_large_gemstone_sack { background-position: -352px 0}.sbsprite-gold_bonzo_head { background-position: -374px 0}.sbsprite-shadow_assassin_mauve { background-position: -396px 0}.sbsprite-ender_artifact { background-position: -418px 0}.sbsprite-sheep_generator_1 { background-position: -440px 0}.sbsprite-beach_chair_plus { background-position: -462px 0}.sbsprite-sheep_generator_2 { background-position: -484px 0}.sbsprite-sheep_generator_3 { background-position: -506px 0}.sbsprite-sheep_generator_4 { background-position: -528px 0}.sbsprite-sheep_generator_5 { background-position: -550px 0}.sbsprite-sheep_generator_6 { background-position: -572px 0}.sbsprite-frozen_spider { background-position: -594px 0}.sbsprite-sheep_generator_7 { background-position: -616px 0}.sbsprite-sheep_generator_8 { background-position: -638px 0}.sbsprite-sheep_generator_9 { background-position: -660px 0}.sbsprite-nether_wart_island_crystal { background-position: -682px 0}.sbsprite-medium_fishing_sack { background-position: -704px 0}.sbsprite-gold_generator_9 { background-position: -726px 0}.sbsprite-gold_generator_7 { background-position: -748px 0}.sbsprite-gold_generator_8 { background-position: -770px 0}.sbsprite-gold_generator_5 { background-position: -792px 0}.sbsprite-penguin_10 { background-position: -814px 0}.sbsprite-diver_helmet { background-position: -836px 0}.sbsprite-gold_generator_6 { background-position: -858px 0}.sbsprite-penguin_11 { background-position: -880px 0}.sbsprite-gold_generator_3 { background-position: -902px 0}.sbsprite-gold_generator_4 { background-position: -924px 0}.sbsprite-pet_skin_sheep_purple { background-position: -946px 0}.sbsprite-gold_generator_1 { background-position: -968px 0}.sbsprite-gold_generator_2 { background-position: -990px 0}.sbsprite-jar_of_pickles { background-position: -1012px 0}.sbsprite-griffin_upgrade_stone_legendary { background-position: -1034px 0}.sbsprite-pet_skin_sheep_orange { background-position: 0 -22px}.sbsprite-talisman { background-position: -22px -22px}.sbsprite-jungle_generator_7 { background-position: -44px -22px}.sbsprite-jungle_generator_6 { background-position: -66px -22px}.sbsprite-tutti_frutti_poison { background-position: -88px -22px}.sbsprite-fishing_generator_11 { background-position: -110px -22px}.sbsprite-jungle_generator_9 { background-position: -132px -22px}.sbsprite-fishing_generator_10 { background-position: -154px -22px}.sbsprite-jungle_generator_8 { background-position: -176px -22px}.sbsprite-jungle_generator_3 { background-position: -198px -22px}.sbsprite-witch_mask { background-position: -220px -22px}.sbsprite-yellow { background-position: -242px -22px}.sbsprite-jungle_generator_2 { background-position: -264px -22px}.sbsprite-jungle_generator_5 { background-position: -286px -22px}.sbsprite-jungle_generator_4 { background-position: -308px -22px}.sbsprite-bat_person_artifact { background-position: -330px -22px}.sbsprite-cocoa_generator_11 { background-position: -352px -22px}.sbsprite-cocoa_generator_12 { background-position: -374px -22px}.sbsprite-jungle_generator_1 { background-position: -396px -22px}.sbsprite-cocoa_generator_10 { background-position: -418px -22px}.sbsprite-beheaded_horror { background-position: -440px -22px}.sbsprite-clay_generator_6 { background-position: -462px -22px}.sbsprite-clay_generator_7 { background-position: -484px -22px}.sbsprite-clay_generator_8 { background-position: -506px -22px}.sbsprite-clay_generator_9 { background-position: -528px -22px}.sbsprite-clay_generator_2 { background-position: -550px -22px}.sbsprite-clay_generator_3 { background-position: -572px -22px}.sbsprite-clay_generator_4 { background-position: -594px -22px}.sbsprite-clay_generator_5 { background-position: -616px -22px}.sbsprite-gold_livid_head { background-position: -638px -22px}.sbsprite-clay_generator_1 { background-position: -660px -22px}.sbsprite-medium_slayer_sack { background-position: -682px -22px}.sbsprite-pet_skin_wither { background-position: -704px -22px}.sbsprite-pink_frosted_donut_3 { background-position: -726px -22px}.sbsprite-pink_frosted_donut_2 { background-position: -748px -22px}.sbsprite-pink_frosted_donut_5 { background-position: -770px -22px}.sbsprite-garland { background-position: -792px -22px}.sbsprite-pink_frosted_donut_4 { background-position: -814px -22px}.sbsprite-pink_frosted_donut_7 { background-position: -836px -22px}.sbsprite-pink_frosted_donut_6 { background-position: -858px -22px}.sbsprite-pink_frosted_donut_9 { background-position: -880px -22px}.sbsprite-pink_frosted_donut_8 { background-position: -902px -22px}.sbsprite-rune_jerry { background-position: -924px -22px}.sbsprite-feather_ring { background-position: -946px -22px}.sbsprite-perfect_forge { background-position: -968px -22px}.sbsprite-bingo_relic { background-position: -990px -22px}.sbsprite-revenant_catalyst { background-position: -1012px -22px}.sbsprite-sun_2 { background-position: -1034px -22px}.sbsprite-sun_1 { background-position: 0 -44px}.sbsprite-pet_skin_tiger_twilight { background-position: -22px -44px}.sbsprite-blessing_of_life { background-position: -44px -44px}.sbsprite-plasma { background-position: -66px -44px}.sbsprite-carrot_patch { background-position: -88px -44px}.sbsprite-pink_frosted_donut_1 { background-position: -110px -44px}.sbsprite-bestiary_the_park { background-position: -132px -44px}.sbsprite-end_stone_10 { background-position: -154px -44px}.sbsprite-end_stone_11 { background-position: -176px -44px}.sbsprite-griffin_upgrade_stone_epic { background-position: -198px -44px}.sbsprite-iron_generator_10 { background-position: -220px -44px}.sbsprite-pet_skin_rock_embarrassed { background-position: -242px -44px}.sbsprite-fast_travel_barn { background-position: -264px -44px}.sbsprite-iron_generator_11 { background-position: -286px -44px}.sbsprite-iron_generator_12 { background-position: -308px -44px}.sbsprite-large_runes_sack { background-position: -330px -44px}.sbsprite-rune_redstone { background-position: -352px -44px}.sbsprite-horseman_candle { background-position: -374px -44px}.sbsprite-tepid_green_tea { background-position: -396px -44px}.sbsprite-large_agronomy_sack { background-position: -418px -44px}.sbsprite-wise_shimmer { background-position: -440px -44px}.sbsprite-maxor_the_fish { background-position: -462px -44px}.sbsprite-revenant_generator_4 { background-position: -484px -44px}.sbsprite-revenant_generator_5 { background-position: -506px -44px}.sbsprite-revenant_generator_6 { background-position: -528px -44px}.sbsprite-revenant_generator_7 { background-position: -550px -44px}.sbsprite-revenant_generator_1 { background-position: -572px -44px}.sbsprite-revenant_generator_2 { background-position: -594px -44px}.sbsprite-epoch_cake_orange { background-position: -616px -44px}.sbsprite-revenant_generator_3 { background-position: -638px -44px}.sbsprite-large_gemstone_sack { background-position: -660px -44px}.sbsprite-mender_crown { background-position: -682px -44px}.sbsprite-mummy_10 { background-position: -704px -44px}.sbsprite-revenant_generator_8 { background-position: -726px -44px}.sbsprite-revenant_generator_9 { background-position: -748px -44px}.sbsprite-mummy_11 { background-position: -770px -44px}.sbsprite-hard_stone_generator_9 { background-position: -792px -44px}.sbsprite-hard_stone_generator_8 { background-position: -814px -44px}.sbsprite-hard_stone_generator_7 { background-position: -836px -44px}.sbsprite-hard_stone_generator_6 { background-position: -858px -44px}.sbsprite-hard_stone_generator_5 { background-position: -880px -44px}.sbsprite-hard_stone_generator_4 { background-position: -902px -44px}.sbsprite-medium_talisman_bag { background-position: -924px -44px}.sbsprite-hard_stone_generator_3 { background-position: -946px -44px}.sbsprite-black_small_backpack { background-position: -968px -44px}.sbsprite-hard_stone_generator_2 { background-position: -990px -44px}.sbsprite-harp { background-position: -1012px -44px}.sbsprite-hard_stone_generator_1 { background-position: -1034px -44px}.sbsprite-pet_skin_sheep_green { background-position: 0 -66px}.sbsprite-magma_cube_generator_10 { background-position: -22px -66px}.sbsprite-fishing_crystal { background-position: -44px -66px}.sbsprite-magma_cube_generator_11 { background-position: -66px -66px}.sbsprite-rough_amber_gem { background-position: -88px -66px}.sbsprite-oak_generator_5 { background-position: -110px -66px}.sbsprite-oak_generator_4 { background-position: -132px -66px}.sbsprite-oak_generator_3 { background-position: -154px -66px}.sbsprite-oak_generator_2 { background-position: -176px -66px}.sbsprite-red_claw_ring { background-position: -198px -66px}.sbsprite-oak_generator_9 { background-position: -220px -66px}.sbsprite-oak_generator_8 { background-position: -242px -66px}.sbsprite-purple_small_backpack { background-position: -264px -66px}.sbsprite-oak_generator_7 { background-position: -286px -66px}.sbsprite-oak_generator_6 { background-position: -308px -66px}.sbsprite-picnic_set { background-position: -330px -66px}.sbsprite-oak_generator_1 { background-position: -352px -66px}.sbsprite-pet_skin_sheep_neon_red { background-position: -374px -66px}.sbsprite-hot_stuff { background-position: -396px -66px}.sbsprite-skeleton_generator_11 { background-position: -418px -66px}.sbsprite-skeleton_generator_10 { background-position: -440px -66px}.sbsprite-mayor_jerry { background-position: -462px -66px}.sbsprite-generals_armor_of_the_resistance_helmet { background-position: -484px -66px}.sbsprite-recall_potion { background-position: -506px -66px}.sbsprite-portable_builder { background-position: -528px -66px}.sbsprite-rune_ice { background-position: -550px -66px}.sbsprite-zombie_brain_mixin { background-position: -572px -66px}.sbsprite-pet_skin_rabbit_aquamarine { background-position: -594px -66px}.sbsprite-rune_music { background-position: -616px -66px}.sbsprite-magnetic_talisman { background-position: -638px -66px}.sbsprite-light_grey_jumbo_backpack { background-position: -660px -66px}.sbsprite-onyx { background-position: -682px -66px}.sbsprite-rune_fire { background-position: -704px -66px}.sbsprite-pet_skin_sheep_black { background-position: -726px -66px}.sbsprite-ice_fireplace { background-position: -748px -66px}.sbsprite-sun_personality { background-position: -770px -66px}.sbsprite-pet { background-position: -792px -66px}.sbsprite-melon_2 { background-position: -814px -66px}.sbsprite-melon_3 { background-position: -836px -66px}.sbsprite-epoch_cake_purple { background-position: -858px -66px}.sbsprite-melon_1 { background-position: -880px -66px}.sbsprite-krampus_helmet { background-position: -902px -66px}.sbsprite-coffee_table { background-position: -924px -66px}.sbsprite-necromancer_lord_helmet { background-position: -946px -66px}.sbsprite-melon_8 { background-position: -968px -66px}.sbsprite-blue_ice_hunk { background-position: -990px -66px}.sbsprite-divan_helmet { background-position: -1012px -66px}.sbsprite-melon_9 { background-position: -1034px -66px}.sbsprite-melon_6 { background-position: 0 -88px}.sbsprite-melon_7 { background-position: -22px -88px}.sbsprite-melon_4 { background-position: -44px -88px}.sbsprite-melon_5 { background-position: -66px -88px}.sbsprite-blue_candy { background-position: -88px -88px}.sbsprite-squid_hat { background-position: -110px -88px}.sbsprite-dungeon_green_support_orb { background-position: -132px -88px}.sbsprite-coin_diamond_3 { background-position: -154px -88px}.sbsprite-pink { background-position: -176px -88px}.sbsprite-coin_diamond_2 { background-position: -198px -88px}.sbsprite-repelling_candle { background-position: -220px -88px}.sbsprite-enderman_generator_11 { background-position: -242px -88px}.sbsprite-power_artifact { background-position: -264px -88px}.sbsprite-enderman_generator_10 { background-position: -286px -88px}.sbsprite-amethyst_crystal { background-position: -308px -88px}.sbsprite-crimson_essence { background-position: -330px -88px}.sbsprite-blue_small_backpack { background-position: -352px -88px}.sbsprite-grey_jumbo_backpack { background-position: -374px -88px}.sbsprite-wither_essence { background-position: -396px -88px}.sbsprite-brown_jumbo_backpack { background-position: -418px -88px}.sbsprite-archer_dungeon_ability_1 { background-position: -440px -88px}.sbsprite-crochet_tiger_plushie { background-position: -462px -88px}.sbsprite-final_destination_helmet { background-position: -484px -88px}.sbsprite-luxurious_spool { background-position: -506px -88px}.sbsprite-auto_recombobulator { background-position: -528px -88px}.sbsprite-killer_11 { background-position: -550px -88px}.sbsprite-spooky_bait { background-position: -572px -88px}.sbsprite-killer_10 { background-position: -594px -88px}.sbsprite-fast_travel_howl { background-position: -616px -88px}.sbsprite-etherwarp_conduit { background-position: -638px -88px}.sbsprite-forest_island_crystal { background-position: -660px -88px}.sbsprite-spirit_mask { background-position: -682px -88px}.sbsprite-sacks { background-position: -704px -88px}.sbsprite-obsidian_generator_10 { background-position: -726px -88px}.sbsprite-chicken_generator_10 { background-position: -748px -88px}.sbsprite-chicken_generator_12 { background-position: -770px -88px}.sbsprite-wood_singularity { background-position: -792px -88px}.sbsprite-chicken_generator_11 { background-position: -814px -88px}.sbsprite-sun_6 { background-position: -836px -88px}.sbsprite-builder_melon { background-position: -858px -88px}.sbsprite-santa_1 { background-position: -880px -88px}.sbsprite-sun_5 { background-position: -902px -88px}.sbsprite-dirt_bottle { background-position: -924px -88px}.sbsprite-sun_4 { background-position: -946px -88px}.sbsprite-handy_blood_chalice { background-position: -968px -88px}.sbsprite-sun_3 { background-position: -990px -88px}.sbsprite-sun_9 { background-position: -1012px -88px}.sbsprite-superior_fragment { background-position: -1034px -88px}.sbsprite-sun_8 { background-position: 0 -110px}.sbsprite-sun_7 { background-position: -22px -110px}.sbsprite-your_essence { background-position: -44px -110px}.sbsprite-pink_greater_backpack { background-position: -66px -110px}.sbsprite-unstable_fragment { background-position: -88px -110px}.sbsprite-obsidian_generator_11 { background-position: -110px -110px}.sbsprite-obsidian_generator_12 { background-position: -132px -110px}.sbsprite-perfect_sapphire_gem { background-position: -154px -110px}.sbsprite-gravel_generator_11 { background-position: -176px -110px}.sbsprite-gravel_generator_10 { background-position: -198px -110px}.sbsprite-candy_corn { background-position: -220px -110px}.sbsprite-mineral_talisman { background-position: -242px -110px}.sbsprite-divan_alloy { background-position: -264px -110px}.sbsprite-moil_log { background-position: -286px -110px}.sbsprite-super_magic_mushroom_soup { background-position: -308px -110px}.sbsprite-easter_basket { background-position: -330px -110px}.sbsprite-hunter_talisman { background-position: -352px -110px}.sbsprite-medium_potion_bag { background-position: -374px -110px}.sbsprite-pet_skin_megalodon_bullhead { background-position: -396px -110px}.sbsprite-broken_piggy_bank { background-position: -418px -110px}.sbsprite-mayor_technoblade { background-position: -440px -110px}.sbsprite-farming_talisman { background-position: -462px -110px}.sbsprite-flawed_sapphire_gem { background-position: -484px -110px}.sbsprite-light_blue_large_backpack { background-position: -506px -110px}.sbsprite-kindred { background-position: -528px -110px}.sbsprite-pocket_espresso_machine { background-position: -550px -110px}.sbsprite-overflux_power_orb { background-position: -572px -110px}.sbsprite-potato_spreading { background-position: -594px -110px}.sbsprite-acacia_generator_11 { background-position: -616px -110px}.sbsprite-birch_generator_6 { background-position: -638px -110px}.sbsprite-acacia_generator_10 { background-position: -660px -110px}.sbsprite-birch_generator_5 { background-position: -682px -110px}.sbsprite-birch_generator_4 { background-position: -704px -110px}.sbsprite-birch_generator_3 { background-position: -726px -110px}.sbsprite-holy_dragon_helmet { background-position: -748px -110px}.sbsprite-basketball_personality { background-position: -770px -110px}.sbsprite-birch_generator_9 { background-position: -792px -110px}.sbsprite-birch_generator_8 { background-position: -814px -110px}.sbsprite-birch_generator_7 { background-position: -836px -110px}.sbsprite-birch_generator_2 { background-position: -858px -110px}.sbsprite-birch_generator_1 { background-position: -880px -110px}.sbsprite-anubis { background-position: -902px -110px}.sbsprite-santa_8 { background-position: -924px -110px}.sbsprite-santa_9 { background-position: -946px -110px}.sbsprite-santa_6 { background-position: -968px -110px}.sbsprite-santa_7 { background-position: -990px -110px}.sbsprite-santa_4 { background-position: -1012px -110px}.sbsprite-candy_talisman { background-position: -1034px -110px}.sbsprite-santa_5 { background-position: 0 -132px}.sbsprite-santa_2 { background-position: -22px -132px}.sbsprite-santa_3 { background-position: -44px -132px}.sbsprite-small_combat_sack { background-position: -66px -132px}.sbsprite-speed_racer { background-position: -88px -132px}.sbsprite-pet_skin_parrot_blue_macaw { background-position: -110px -132px}.sbsprite-red_large_backpack { background-position: -132px -132px}.sbsprite-sea_archer_helmet { background-position: -154px -132px}.sbsprite-happy_mask { background-position: -176px -132px}.sbsprite-blue_large_backpack { background-position: -198px -132px}.sbsprite-enderman_generator_4 { background-position: -220px -132px}.sbsprite-enderman_generator_3 { background-position: -242px -132px}.sbsprite-enderman_generator_2 { background-position: -264px -132px}.sbsprite-enderman_generator_1 { background-position: -286px -132px}.sbsprite-enderman_generator_8 { background-position: -308px -132px}.sbsprite-enderman_generator_7 { background-position: -330px -132px}.sbsprite-enderman_generator_6 { background-position: -352px -132px}.sbsprite-enderman_generator_5 { background-position: -374px -132px}.sbsprite-green_candy { background-position: -396px -132px}.sbsprite-bestiary_milestone { background-position: -418px -132px}.sbsprite-colossal_exp_bottle_upgrade { background-position: -440px -132px}.sbsprite-sun_11 { background-position: -462px -132px}.sbsprite-sun_10 { background-position: -484px -132px}.sbsprite-vampire_witch_mask { background-position: -506px -132px}.sbsprite-pet_skin_sheep_yellow { background-position: -528px -132px}.sbsprite-bank_upgrade_palatial { background-position: -550px -132px}.sbsprite-flawed_ruby_gem { background-position: -572px -132px}.sbsprite-redstone_generator_9 { background-position: -594px -132px}.sbsprite-redstone_generator_7 { background-position: -616px -132px}.sbsprite-redstone_generator_8 { background-position: -638px -132px}.sbsprite-arachne_fragment { background-position: -660px -132px}.sbsprite-spider_generator_10 { background-position: -682px -132px}.sbsprite-spider_generator_11 { background-position: -704px -132px}.sbsprite-epoch_cake_red { background-position: -726px -132px}.sbsprite-orange_jumbo_backpack { background-position: -748px -132px}.sbsprite-giant_the_fish { background-position: -770px -132px}.sbsprite-minnow_bait { background-position: -792px -132px}.sbsprite-enderman_generator_9 { background-position: -814px -132px}.sbsprite-mastiff_puppy { background-position: -836px -132px}.sbsprite-talisman_enrichment_critical_damage { background-position: -858px -132px}.sbsprite-fast_travel_forge { background-position: -880px -132px}.sbsprite-goblin_omelette { background-position: -902px -132px}.sbsprite-builder_ancient_fruit { background-position: -924px -132px}.sbsprite-master_skull_tier_10 { background-position: -946px -132px}.sbsprite-hardened_wood { background-position: -968px -132px}.sbsprite-large_winter_sack { background-position: -990px -132px}.sbsprite-talisman_enrichment_intelligence { background-position: -1012px -132px}.sbsprite-snow_snowglobe { background-position: -1034px -132px}.sbsprite-summoning_eye { background-position: 0 -154px}.sbsprite-cavespider_generator_10 { background-position: -22px -154px}.sbsprite-clownfish_10 { background-position: -44px -154px}.sbsprite-cavespider_generator_11 { background-position: -66px -154px}.sbsprite-revenant_generator_12 { background-position: -88px -154px}.sbsprite-clownfish_11 { background-position: -110px -154px}.sbsprite-revenant_generator_11 { background-position: -132px -154px}.sbsprite-revenant_generator_10 { background-position: -154px -154px}.sbsprite-red_small_backpack { background-position: -176px -154px}.sbsprite-soulflow { background-position: -198px -154px}.sbsprite-farming_fortune { background-position: -220px -154px}.sbsprite-dungeon_stone_berserk { background-position: -242px -154px}.sbsprite-green_greater_backpack { background-position: -264px -154px}.sbsprite-mastiff_helmet { background-position: -286px -154px}.sbsprite-purple { background-position: -308px -154px}.sbsprite-skeleton_generator_7 { background-position: -330px -154px}.sbsprite-skeleton_generator_6 { background-position: -352px -154px}.sbsprite-skeleton_generator_9 { background-position: -374px -154px}.sbsprite-skeleton_generator_8 { background-position: -396px -154px}.sbsprite-speed_ring { background-position: -418px -154px}.sbsprite-skeleton_generator_3 { background-position: -440px -154px}.sbsprite-rabbit_hutch { background-position: -462px -154px}.sbsprite-skeleton_generator_2 { background-position: -484px -154px}.sbsprite-skeleton_generator_5 { background-position: -506px -154px}.sbsprite-minion_storage_expander { background-position: -528px -154px}.sbsprite-skeleton_generator_4 { background-position: -550px -154px}.sbsprite-werewolf_helmet { background-position: -572px -154px}.sbsprite-light_blue_small_backpack { background-position: -594px -154px}.sbsprite-skeleton_generator_1 { background-position: -616px -154px}.sbsprite-lapis_chest { background-position: -638px -154px}.sbsprite-healing_talisman { background-position: -660px -154px}.sbsprite-magma_cube_head { background-position: -682px -154px}.sbsprite-shadow_goggles { background-position: -704px -154px}.sbsprite-ice_generator_11 { background-position: -726px -154px}.sbsprite-fine_jasper_gem { background-position: -748px -154px}.sbsprite-candy_artifact { background-position: -770px -154px}.sbsprite-pet_skin_dragon_neon_blue { background-position: -792px -154px}.sbsprite-fast_travel_desert { background-position: -814px -154px}.sbsprite-rune_end { background-position: -836px -154px}.sbsprite-old_shimmer { background-position: -858px -154px}.sbsprite-skyblock_bench { background-position: -880px -154px}.sbsprite-hay_bale { background-position: -902px -154px}.sbsprite-crit_chance { background-position: -924px -154px}.sbsprite-dungeon_stone { background-position: -946px -154px}.sbsprite-artifact_potion_affinity { background-position: -968px -154px}.sbsprite-yoggie { background-position: -990px -154px}.sbsprite-starred_adaptive_helmet { background-position: -1012px -154px}.sbsprite-foraging_3_portal { background-position: -1034px -154px}.sbsprite-pet_skin_dragon_neon_red { background-position: 0 -176px}.sbsprite-ditto_skull { background-position: -22px -176px}.sbsprite-pig_generator_6 { background-position: -44px -176px}.sbsprite-redstone_generator_1 { background-position: -66px -176px}.sbsprite-pig_generator_5 { background-position: -88px -176px}.sbsprite-redstone_generator_2 { background-position: -110px -176px}.sbsprite-pig_generator_8 { background-position: -132px -176px}.sbsprite-pig_generator_7 { background-position: -154px -176px}.sbsprite-flawless_amethyst_gem { background-position: -176px -176px}.sbsprite-redstone_generator_5 { background-position: -198px -176px}.sbsprite-wither_catalyst { background-position: -220px -176px}.sbsprite-pig_generator_9 { background-position: -242px -176px}.sbsprite-redstone_generator_6 { background-position: -264px -176px}.sbsprite-cyan_jumbo_backpack { background-position: -286px -176px}.sbsprite-redstone_generator_3 { background-position: -308px -176px}.sbsprite-redstone_generator_4 { background-position: -330px -176px}.sbsprite-ice_generator_10 { background-position: -352px -176px}.sbsprite-pig_generator_2 { background-position: -374px -176px}.sbsprite-builder_lettuce { background-position: -396px -176px}.sbsprite-first_master_star { background-position: -418px -176px}.sbsprite-pig_generator_1 { background-position: -440px -176px}.sbsprite-pig_generator_4 { background-position: -462px -176px}.sbsprite-green_medium_backpack { background-position: -484px -176px}.sbsprite-pig_generator_3 { background-position: -506px -176px}.sbsprite-sugar_cane_generator_9 { background-position: -528px -176px}.sbsprite-greater_backpack { background-position: -550px -176px}.sbsprite-sugar_cane_generator_6 { background-position: -572px -176px}.sbsprite-sugar_cane_generator_5 { background-position: -594px -176px}.sbsprite-pet_skin_sheep_neon_blue { background-position: -616px -176px}.sbsprite-sugar_cane_generator_8 { background-position: -638px -176px}.sbsprite-sugar_cane_generator_7 { background-position: -660px -176px}.sbsprite-sugar_cane_generator_2 { background-position: -682px -176px}.sbsprite-sugar_cane_generator_1 { background-position: -704px -176px}.sbsprite-cauldron { background-position: -726px -176px}.sbsprite-sugar_cane_generator_4 { background-position: -748px -176px}.sbsprite-sugar_cane_generator_3 { background-position: -770px -176px}.sbsprite-wheat_island_crystal { background-position: -792px -176px}.sbsprite-boss_collection_scarf { background-position: -814px -176px}.sbsprite-deep_sea_orb { background-position: -836px -176px}.sbsprite-pet_skin_elephant_red { background-position: -858px -176px}.sbsprite-pink_large_backpack { background-position: -880px -176px}.sbsprite-gemstone_collection { background-position: -902px -176px}.sbsprite-carpentry_bench { background-position: -924px -176px}.sbsprite-pet_skin_wolf_henzo_doggo { background-position: -946px -176px}.sbsprite-sloth_11 { background-position: -968px -176px}.sbsprite-sloth_10 { background-position: -990px -176px}.sbsprite-vampire_mask { background-position: -1012px -176px}.sbsprite-reindeer_personality { background-position: -1034px -176px}.sbsprite-minos_hunter_helmet { background-position: 0 -198px}.sbsprite-catacombs_2 { background-position: -22px -198px}.sbsprite-catacombs_3 { background-position: -44px -198px}.sbsprite-catacombs_1 { background-position: -66px -198px}.sbsprite-catacombs_6 { background-position: -88px -198px}.sbsprite-small_runes_sack { background-position: -110px -198px}.sbsprite-catacombs_4 { background-position: -132px -198px}.sbsprite-catacombs_5 { background-position: -154px -198px}.sbsprite-clownfish_hat { background-position: -176px -198px}.sbsprite-fine_topaz_gem { background-position: -198px -198px}.sbsprite-beastmaster_crest_uncommon { background-position: -220px -198px}.sbsprite-superlite_motor { background-position: -242px -198px}.sbsprite-red_greater_backpack { background-position: -264px -198px}.sbsprite-hunter_ring { background-position: -286px -198px}.sbsprite-necromancer_brooch { background-position: -308px -198px}.sbsprite-spooky_shard { background-position: -330px -198px}.sbsprite-grey_medium_backpack { background-position: -352px -198px}.sbsprite-diamond_chest { background-position: -374px -198px}.sbsprite-slime_hat { background-position: -396px -198px}.sbsprite-hermit_crab_2 { background-position: -418px -198px}.sbsprite-enderman_cortex_rewriter { background-position: -440px -198px}.sbsprite-hermit_crab_1 { background-position: -462px -198px}.sbsprite-carrot_generator_11 { background-position: -484px -198px}.sbsprite-carrot_generator_12 { background-position: -506px -198px}.sbsprite-mushroom_generator_4 { background-position: -528px -198px}.sbsprite-carrot_generator_10 { background-position: -550px -198px}.sbsprite-mushroom_generator_3 { background-position: -572px -198px}.sbsprite-mushroom_generator_6 { background-position: -594px -198px}.sbsprite-mushroom_generator_5 { background-position: -616px -198px}.sbsprite-mushroom_generator_8 { background-position: -638px -198px}.sbsprite-mushroom_generator_7 { background-position: -660px -198px}.sbsprite-mushroom_generator_9 { background-position: -682px -198px}.sbsprite-diamond_professor_head { background-position: -704px -198px}.sbsprite-large_foraging_sack { background-position: -726px -198px}.sbsprite-robotron_reflector { background-position: -748px -198px}.sbsprite-wish_ultimate { background-position: -770px -198px}.sbsprite-tessellated_ender_pearl { background-position: -792px -198px}.sbsprite-pet_skin_sheep_red { background-position: -814px -198px}.sbsprite-spirit_decoy { background-position: -836px -198px}.sbsprite-stacked_pumpkins { background-position: -858px -198px}.sbsprite-medium_runes_sack { background-position: -880px -198px}.sbsprite-mushroom_generator_2 { background-position: -902px -198px}.sbsprite-young_dragon_helmet { background-position: -924px -198px}.sbsprite-mushroom_generator_1 { background-position: -946px -198px}.sbsprite-hermit_crab_6 { background-position: -968px -198px}.sbsprite-gravity_talisman { background-position: -990px -198px}.sbsprite-hermit_crab_5 { background-position: -1012px -198px}.sbsprite-hermit_crab_4 { background-position: -1034px -198px}.sbsprite-hermit_crab_3 { background-position: 0 -220px}.sbsprite-melon_10 { background-position: -22px -220px}.sbsprite-party_time_event { background-position: -44px -220px}.sbsprite-grinch_10 { background-position: -66px -220px}.sbsprite-melon_11 { background-position: -88px -220px}.sbsprite-hermit_crab_9 { background-position: -110px -220px}.sbsprite-hermit_crab_8 { background-position: -132px -220px}.sbsprite-grinch_11 { background-position: -154px -220px}.sbsprite-hermit_crab_7 { background-position: -176px -220px}.sbsprite-flower_generator_10 { background-position: -198px -220px}.sbsprite-race_giant_mushroom { background-position: -220px -220px}.sbsprite-flower_generator_11 { background-position: -242px -220px}.sbsprite-flower_generator_12 { background-position: -264px -220px}.sbsprite-redstone_chest { background-position: -286px -220px}.sbsprite-undead_catalyst { background-position: -308px -220px}.sbsprite-master_skull_tier_7 { background-position: -330px -220px}.sbsprite-reindeer_9 { background-position: -352px -220px}.sbsprite-master_skull_tier_6 { background-position: -374px -220px}.sbsprite-rune_slimy { background-position: -396px -220px}.sbsprite-master_skull_tier_9 { background-position: -418px -220px}.sbsprite-medium_shelves { background-position: -440px -220px}.sbsprite-master_skull_tier_8 { background-position: -462px -220px}.sbsprite-plasmaflux_power_orb { background-position: -484px -220px}.sbsprite-adaptive_helmet { background-position: -506px -220px}.sbsprite-pet_skin_endermite_radiant { background-position: -528px -220px}.sbsprite-master_skull_tier_1 { background-position: -550px -220px}.sbsprite-master_skull_tier_3 { background-position: -572px -220px}.sbsprite-oil_barrel { background-position: -594px -220px}.sbsprite-master_skull_tier_2 { background-position: -616px -220px}.sbsprite-master_skull_tier_5 { background-position: -638px -220px}.sbsprite-master_skull_tier_4 { background-position: -660px -220px}.sbsprite-pet_skin_guardian { background-position: -682px -220px}.sbsprite-flawless_jade_gem { background-position: -704px -220px}.sbsprite-survivor_cube { background-position: -726px -220px}.sbsprite-undead_2 { background-position: -748px -220px}.sbsprite-undead_3 { background-position: -770px -220px}.sbsprite-undead_4 { background-position: -792px -220px}.sbsprite-undead_5 { background-position: -814px -220px}.sbsprite-undead_6 { background-position: -836px -220px}.sbsprite-undead_7 { background-position: -858px -220px}.sbsprite-undead_8 { background-position: -880px -220px}.sbsprite-undead_9 { background-position: -902px -220px}.sbsprite-enchanted_book_bundle_vicious { background-position: -924px -220px}.sbsprite-endstone_chest { background-position: -946px -220px}.sbsprite-titanium_fuel_tank { background-position: -968px -220px}.sbsprite-golden_ball { background-position: -990px -220px}.sbsprite-undead_1 { background-position: -1012px -220px}.sbsprite-happy_emoji_5 { background-position: -1034px -220px}.sbsprite-reindeer_1 { background-position: 0 -242px}.sbsprite-warden_heart { background-position: -22px -242px}.sbsprite-happy_emoji_4 { background-position: -44px -242px}.sbsprite-reindeer_2 { background-position: -66px -242px}.sbsprite-happy_emoji_7 { background-position: -88px -242px}.sbsprite-reindeer_3 { background-position: -110px -242px}.sbsprite-happy_emoji_6 { background-position: -132px -242px}.sbsprite-kalhuiki_mask { background-position: -154px -242px}.sbsprite-reindeer_4 { background-position: -176px -242px}.sbsprite-happy_emoji_1 { background-position: -198px -242px}.sbsprite-reindeer_5 { background-position: -220px -242px}.sbsprite-reindeer_6 { background-position: -242px -242px}.sbsprite-happy_emoji_3 { background-position: -264px -242px}.sbsprite-reindeer_7 { background-position: -286px -242px}.sbsprite-happy_emoji_2 { background-position: -308px -242px}.sbsprite-reindeer_8 { background-position: -330px -242px}.sbsprite-happy_emoji_9 { background-position: -352px -242px}.sbsprite-festive_skeleton_personality { background-position: -374px -242px}.sbsprite-happy_emoji_8 { background-position: -396px -242px}.sbsprite-mimic_fragment { background-position: -418px -242px}.sbsprite-pet_skin_parrot_gold_macaw { background-position: -440px -242px}.sbsprite-mithril_drill_engine { background-position: -462px -242px}.sbsprite-titan_helmet { background-position: -484px -242px}.sbsprite-warden_helmet { background-position: -506px -242px}.sbsprite-nether_wart_pouch { background-position: -528px -242px}.sbsprite-red_nose { background-position: -550px -242px}.sbsprite-emerald_generator_12 { background-position: -572px -242px}.sbsprite-farming_1_portal { background-position: -594px -242px}.sbsprite-pet_skin_horse_zombie { background-position: -616px -242px}.sbsprite-devour_ring { background-position: -638px -242px}.sbsprite-mining_1_portal { background-position: -660px -242px}.sbsprite-builder_lilac_fruit { background-position: -682px -242px}.sbsprite-diamond_livid_head { background-position: -704px -242px}.sbsprite-fast_travel_dungeon_hub { background-position: -726px -242px}.sbsprite-emerald_generator_10 { background-position: -748px -242px}.sbsprite-emerald_generator_11 { background-position: -770px -242px}.sbsprite-bestiary_catacombs { background-position: -792px -242px}.sbsprite-fine_amber_gem { background-position: -814px -242px}.sbsprite-beach_ball_personality { background-position: -836px -242px}.sbsprite-cow_generator_11 { background-position: -858px -242px}.sbsprite-cow_generator_12 { background-position: -880px -242px}.sbsprite-mummy_personality { background-position: -902px -242px}.sbsprite-rune_wet { background-position: -924px -242px}.sbsprite-jumbo_backpack_upgrade { background-position: -946px -242px}.sbsprite-shadow_assassin_admiral { background-position: -968px -242px}.sbsprite-beating_heart { background-position: -990px -242px}.sbsprite-giant_tooth { background-position: -1012px -242px}.sbsprite-black_large_backpack { background-position: -1034px -242px}.sbsprite-corleonite { background-position: 0 -264px}.sbsprite-magma_cube_generator_1 { background-position: -22px -264px}.sbsprite-magma_cube_generator_5 { background-position: -44px -264px}.sbsprite-gold_candy { background-position: -66px -264px}.sbsprite-magma_cube_generator_4 { background-position: -88px -264px}.sbsprite-magma_cube_generator_3 { background-position: -110px -264px}.sbsprite-magma_cube_generator_2 { background-position: -132px -264px}.sbsprite-magma_cube_generator_9 { background-position: -154px -264px}.sbsprite-dining_table { background-position: -176px -264px}.sbsprite-magma_cube_generator_8 { background-position: -198px -264px}.sbsprite-magma_cube_generator_7 { background-position: -220px -264px}.sbsprite-magma_cube_generator_6 { background-position: -242px -264px}.sbsprite-sadan_brooch { background-position: -264px -264px}.sbsprite-birch_generator_11 { background-position: -286px -264px}.sbsprite-birch_generator_10 { background-position: -308px -264px}.sbsprite-strong_dragon_helmet { background-position: -330px -264px}.sbsprite-greater_enchanted_chest_upgrade { background-position: -352px -264px}.sbsprite-pink_frosted_donut_11 { background-position: -374px -264px}.sbsprite-molten_cube { background-position: -396px -264px}.sbsprite-pink_frosted_donut_10 { background-position: -418px -264px}.sbsprite-ultimate_carrot_candy_upgrade { background-position: -440px -264px}.sbsprite-old_baby { background-position: -462px -264px}.sbsprite-coin_lapis { background-position: -484px -264px}.sbsprite-superior_shimmer { background-position: -506px -264px}.sbsprite-diver_fragment { background-position: -528px -264px}.sbsprite-blue_greater_backpack { background-position: -550px -264px}.sbsprite-piggy_bank { background-position: -572px -264px}.sbsprite-flawed_jade_gem { background-position: -594px -264px}.sbsprite-dungeon_boss_key { background-position: -616px -264px}.sbsprite-spider_catalyst { background-position: -638px -264px}.sbsprite-shark_scale_helmet { background-position: -660px -264px}.sbsprite-ghost_book { background-position: -682px -264px}.sbsprite-titanium_alloy { background-position: -704px -264px}.sbsprite-pet_skin_enderman_slayer { background-position: -726px -264px}.sbsprite-hegemony_artifact { background-position: -748px -264px}.sbsprite-potion_affinity_talisman { background-position: -770px -264px}.sbsprite-trick_or_treat_bag { background-position: -792px -264px}.sbsprite-fake_gold_ring { background-position: -814px -264px}.sbsprite-dr_paper { background-position: -836px -264px}.sbsprite-fuel_tank { background-position: -858px -264px}.sbsprite-rough_amethyst_gem { background-position: -880px -264px}.sbsprite-flawless_sapphire_gem { background-position: -902px -264px}.sbsprite-pink_small_backpack { background-position: -924px -264px}.sbsprite-cow_generator_10 { background-position: -946px -264px}.sbsprite-mithril_infusion { background-position: -968px -264px}.sbsprite-beastmaster_crest_common { background-position: -990px -264px}.sbsprite-shiny_relic { background-position: -1012px -264px}.sbsprite-concentrated_stone { background-position: -1034px -264px}.sbsprite-sloth_personality { background-position: 0 -286px}.sbsprite-stocking { background-position: -22px -286px}.sbsprite-egg_pile { background-position: -44px -286px}.sbsprite-blessing_of_wisdom { background-position: -66px -286px}.sbsprite-happy_snowman { background-position: -88px -286px}.sbsprite-gingerbread_10 { background-position: -110px -286px}.sbsprite-gingerbread_11 { background-position: -132px -286px}.sbsprite-diamond_generator_11 { background-position: -154px -286px}.sbsprite-diamond_generator_10 { background-position: -176px -286px}.sbsprite-medium_backpack { background-position: -198px -286px}.sbsprite-rune_white_spiral { background-position: -220px -286px}.sbsprite-diamond_generator_12 { background-position: -242px -286px}.sbsprite-blacksmith_plus { background-position: -264px -286px}.sbsprite-light_blue_greater_backpack { background-position: -286px -286px}.sbsprite-watcher_eye { background-position: -308px -286px}.sbsprite-pet_skin_silverfish { background-position: -330px -286px}.sbsprite-rough_ruby_gem { background-position: -352px -286px}.sbsprite-fine_amethyst_gem { background-position: -374px -286px}.sbsprite-flawed_topaz_gem { background-position: -396px -286px}.sbsprite-spirit_bone { background-position: -418px -286px}.sbsprite-snow_blaster { background-position: -440px -286px}.sbsprite-unknown_item { background-position: -462px -286px}.sbsprite-spider_essence { background-position: -484px -286px}.sbsprite-light_bait { background-position: -506px -286px}.sbsprite-beastmaster_crest_legendary { background-position: -528px -286px}.sbsprite-mayor_diana { background-position: -550px -286px}.sbsprite-enchanted_jack_o_lantern { background-position: -572px -286px}.sbsprite-medium_foraging_sack { background-position: -594px -286px}.sbsprite-emerald_chest { background-position: -616px -286px}.sbsprite-carrot_generator_6 { background-position: -638px -286px}.sbsprite-reindeer_11 { background-position: -660px -286px}.sbsprite-carrot_generator_7 { background-position: -682px -286px}.sbsprite-reindeer_10 { background-position: -704px -286px}.sbsprite-carrot_generator_4 { background-position: -726px -286px}.sbsprite-carrot_generator_5 { background-position: -748px -286px}.sbsprite-carrot_generator_2 { background-position: -770px -286px}.sbsprite-carrot_generator_3 { background-position: -792px -286px}.sbsprite-carrot_generator_1 { background-position: -814px -286px}.sbsprite-carrot_generator_8 { background-position: -836px -286px}.sbsprite-dragon_scale { background-position: -858px -286px}.sbsprite-carrot_generator_9 { background-position: -880px -286px}.sbsprite-protector_dragon_helmet { background-position: -902px -286px}.sbsprite-rune_hearts { background-position: -924px -286px}.sbsprite-pet_skin_sheep_magenta { background-position: -946px -286px}.sbsprite-shadow_assassin_helmet { background-position: -968px -286px}.sbsprite-gemstone_gauntlet_gold { background-position: -990px -286px}.sbsprite-lucky_dice { background-position: -1012px -286px}.sbsprite-wolf_ring { background-position: -1034px -286px}.sbsprite-haunt_ability { background-position: 0 -308px}.sbsprite-undead_essence { background-position: -22px -308px}.sbsprite-bitter_ice_tea { background-position: -44px -308px}.sbsprite-beastmaster_crest_rare { background-position: -66px -308px}.sbsprite-enchanted_titanium { background-position: -88px -308px}.sbsprite-red_claw_talisman { background-position: -110px -308px}.sbsprite-intimidation_talisman { background-position: -132px -308px}.sbsprite-ice_bait { background-position: -154px -308px}.sbsprite-empty_soda_can { background-position: -176px -308px}.sbsprite-jerry_candy { background-position: -198px -308px}.sbsprite-ghast_generator_3 { background-position: -220px -308px}.sbsprite-fancy_flower_pot { background-position: -242px -308px}.sbsprite-ghast_generator_2 { background-position: -264px -308px}.sbsprite-cyan_greater_backpack { background-position: -286px -308px}.sbsprite-ghast_generator_5 { background-position: -308px -308px}.sbsprite-ghast_generator_4 { background-position: -330px -308px}.sbsprite-ghast_generator_7 { background-position: -352px -308px}.sbsprite-cold_ones { background-position: -374px -308px}.sbsprite-ghast_generator_6 { background-position: -396px -308px}.sbsprite-mega_jerry_lure { background-position: -418px -308px}.sbsprite-ghast_generator_9 { background-position: -440px -308px}.sbsprite-rune_smokey { background-position: -462px -308px}.sbsprite-ghast_generator_8 { background-position: -484px -308px}.sbsprite-healer_dungeon_ability_2 { background-position: -506px -308px}.sbsprite-healer_dungeon_ability_3 { background-position: -528px -308px}.sbsprite-ghast_generator_1 { background-position: -550px -308px}.sbsprite-brown_medium_backpack { background-position: -572px -308px}.sbsprite-healer_dungeon_ability_1 { background-position: -594px -308px}.sbsprite-ice_cream_2 { background-position: -616px -308px}.sbsprite-ice_cream_1 { background-position: -638px -308px}.sbsprite-ice_cream_4 { background-position: -660px -308px}.sbsprite-ice_cream_3 { background-position: -682px -308px}.sbsprite-ice_cream_6 { background-position: -704px -308px}.sbsprite-ice_cream_5 { background-position: -726px -308px}.sbsprite-ice_cream_8 { background-position: -748px -308px}.sbsprite-ice_cream_7 { background-position: -770px -308px}.sbsprite-ice_cream_9 { background-position: -792px -308px}.sbsprite-ice_cream_10 { background-position: -814px -308px}.sbsprite-ice_cream_11 { background-position: -836px -308px}.sbsprite-coin_iron { background-position: -858px -308px}.sbsprite-chewed_gum { background-position: -880px -308px}.sbsprite-training_weights { background-position: -902px -308px}.sbsprite-orange_large_backpack { background-position: -924px -308px}.sbsprite-campfire_talisman_24 { background-position: -946px -308px}.sbsprite-campfire_talisman_25 { background-position: -968px -308px}.sbsprite-campfire_talisman_26 { background-position: -990px -308px}.sbsprite-campfire_talisman_27 { background-position: -1012px -308px}.sbsprite-campfire_talisman_28 { background-position: -1034px -308px}.sbsprite-campfire_talisman_29 { background-position: 0 -330px}.sbsprite-candle_table { background-position: -22px -330px}.sbsprite-jingle_bells { background-position: -44px -330px}.sbsprite-lynx_talisman { background-position: -66px -330px}.sbsprite-campfire_talisman_20 { background-position: -88px -330px}.sbsprite-campfire_talisman_21 { background-position: -110px -330px}.sbsprite-campfire_talisman_22 { background-position: -132px -330px}.sbsprite-campfire_talisman_23 { background-position: -154px -330px}.sbsprite-perfect_ruby_gem { background-position: -176px -330px}.sbsprite-pet_skin_megalodon_baby { background-position: -198px -330px}.sbsprite-jungle_amulet { background-position: -220px -330px}.sbsprite-reaper_mask { background-position: -242px -330px}.sbsprite-enchanting_plus { background-position: -264px -330px}.sbsprite-catacombs_expert_ring { background-position: -286px -330px}.sbsprite-ice_knight_statue { background-position: -308px -330px}.sbsprite-bits_talisman { background-position: -330px -330px}.sbsprite-dark_orb { background-position: -352px -330px}.sbsprite-blessing_of_power { background-position: -374px -330px}.sbsprite-beastmaster_crest_epic { background-position: -396px -330px}.sbsprite-bulky_stone { background-position: -418px -330px}.sbsprite-yellow_small_backpack { background-position: -440px -330px}.sbsprite-small_potion_bag { background-position: -462px -330px}.sbsprite-green_jumbo_backpack { background-position: -484px -330px}.sbsprite-zombie_heart { background-position: -506px -330px}.sbsprite-pet_skin_black_cat_ivory { background-position: -528px -330px}.sbsprite-titanium_relic { background-position: -550px -330px}.sbsprite-fast_travel_jungle { background-position: -572px -330px}.sbsprite-pet_skin_rabbit { background-position: -594px -330px}.sbsprite-enderman_mask { background-position: -616px -330px}.sbsprite-perfect_amethyst_gem { background-position: -638px -330px}.sbsprite-boss_collection_sadan { background-position: -660px -330px}.sbsprite-blessing_of_stone { background-position: -682px -330px}.sbsprite-master_catacombs_pass_0 { background-position: -704px -330px}.sbsprite-snowman { background-position: -726px -330px}.sbsprite-candy_the_fish { background-position: -748px -330px}.sbsprite-gold_chest { background-position: -770px -330px}.sbsprite-master_catacombs_pass_6 { background-position: -792px -330px}.sbsprite-master_catacombs_pass_5 { background-position: -814px -330px}.sbsprite-master_catacombs_pass_8 { background-position: -836px -330px}.sbsprite-master_catacombs_pass_7 { background-position: -858px -330px}.sbsprite-master_catacombs_pass_2 { background-position: -880px -330px}.sbsprite-master_catacombs_pass_1 { background-position: -902px -330px}.sbsprite-master_catacombs_pass_4 { background-position: -924px -330px}.sbsprite-master_catacombs_pass_3 { background-position: -946px -330px}.sbsprite-candy_bowl { background-position: -968px -330px}.sbsprite-large_talisman_bag { background-position: -990px -330px}.sbsprite-secret_dungeon_redstone_key { background-position: -1012px -330px}.sbsprite-knockoff_cola { background-position: -1034px -330px}.sbsprite-grinch_2 { background-position: 0 -352px}.sbsprite-grinch_3 { background-position: -22px -352px}.sbsprite-grinch_4 { background-position: -44px -352px}.sbsprite-personal_bank_item { background-position: -66px -352px}.sbsprite-grinch_5 { background-position: -88px -352px}.sbsprite-grinch_6 { background-position: -110px -352px}.sbsprite-blessing_of_time { background-position: -132px -352px}.sbsprite-grinch_7 { background-position: -154px -352px}.sbsprite-grinch_8 { background-position: -176px -352px}.sbsprite-grinch_9 { background-position: -198px -352px}.sbsprite-crit_damage { background-position: -220px -352px}.sbsprite-grinch_1 { background-position: -242px -352px}.sbsprite-bunny_4 { background-position: -264px -352px}.sbsprite-bunny_3 { background-position: -286px -352px}.sbsprite-the_watchers_head { background-position: -308px -352px}.sbsprite-bunny_2 { background-position: -330px -352px}.sbsprite-bunny_1 { background-position: -352px -352px}.sbsprite-bunny_8 { background-position: -374px -352px}.sbsprite-bunny_7 { background-position: -396px -352px}.sbsprite-master_catacombs_pass_9 { background-position: -418px -352px}.sbsprite-bat_person_helmet { background-position: -440px -352px}.sbsprite-bunny_6 { background-position: -462px -352px}.sbsprite-bunny_5 { background-position: -484px -352px}.sbsprite-refined_amber { background-position: -506px -352px}.sbsprite-pet_skin_rock_derp { background-position: -528px -352px}.sbsprite-pet_skin_sheep_gray { background-position: -550px -352px}.sbsprite-flawed_amber_gem { background-position: -572px -352px}.sbsprite-pumpkin_11 { background-position: -594px -352px}.sbsprite-pumpkin_10 { background-position: -616px -352px}.sbsprite-white_small_backpack { background-position: -638px -352px}.sbsprite-blaze_hat { background-position: -660px -352px}.sbsprite-woodcutting_crystal { background-position: -682px -352px}.sbsprite-bunny_9 { background-position: -704px -352px}.sbsprite-roofed_forest_island { background-position: -726px -352px}.sbsprite-campfire_talisman_13 { background-position: -748px -352px}.sbsprite-campfire_talisman_14 { background-position: -770px -352px}.sbsprite-rune_lava { background-position: -792px -352px}.sbsprite-campfire_talisman_15 { background-position: -814px -352px}.sbsprite-campfire_talisman_16 { background-position: -836px -352px}.sbsprite-campfire_talisman_17 { background-position: -858px -352px}.sbsprite-campfire_talisman_18 { background-position: -880px -352px}.sbsprite-golden_dante_statue { background-position: -902px -352px}.sbsprite-campfire_talisman_19 { background-position: -924px -352px}.sbsprite-foraging_4_portal { background-position: -946px -352px}.sbsprite-new_year_cake_bag { background-position: -968px -352px}.sbsprite-santa_personality { background-position: -990px -352px}.sbsprite-campfire_talisman_10 { background-position: -1012px -352px}.sbsprite-campfire_talisman_11 { background-position: -1034px -352px}.sbsprite-campfire_talisman_12 { background-position: 0 -374px}.sbsprite-jerry_stone { background-position: -22px -374px}.sbsprite-cyclops_personality { background-position: -44px -374px}.sbsprite-desert_island_crystal { background-position: -66px -374px}.sbsprite-happy_emoji_personality { background-position: -88px -374px}.sbsprite-rough_sapphire_gem { background-position: -110px -374px}.sbsprite-fallen_star_hat { background-position: -132px -374px}.sbsprite-blaze_generator_10 { background-position: -154px -374px}.sbsprite-blaze_generator_11 { background-position: -176px -374px}.sbsprite-goblin_omelette_blue_cheese { background-position: -198px -374px}.sbsprite-treasure_artifact { background-position: -220px -374px}.sbsprite-hermit_crab_personality { background-position: -242px -374px}.sbsprite-orange { background-position: -264px -374px}.sbsprite-pond_island { background-position: -286px -374px}.sbsprite-fast_travel_void { background-position: -308px -374px}.sbsprite-transmission_tuner { background-position: -330px -374px}.sbsprite-bestiary_the_end { background-position: -352px -374px}.sbsprite-danger_1_portal { background-position: -374px -374px}.sbsprite-pink_jumbo_backpack { background-position: -396px -374px}.sbsprite-sea_walker_helmet { background-position: -418px -374px}.sbsprite-wise_fragment { background-position: -440px -374px}.sbsprite-jerry_talisman_golden { background-position: -462px -374px}.sbsprite-superior_baby { background-position: -484px -374px}.sbsprite-flower_bed { background-position: -506px -374px}.sbsprite-cactus_generator_1 { background-position: -528px -374px}.sbsprite-endstone_geode { background-position: -550px -374px}.sbsprite-holy_baby { background-position: -572px -374px}.sbsprite-cactus_generator_3 { background-position: -594px -374px}.sbsprite-cactus_generator_2 { background-position: -616px -374px}.sbsprite-cactus_generator_5 { background-position: -638px -374px}.sbsprite-cactus_generator_4 { background-position: -660px -374px}.sbsprite-cactus_generator_7 { background-position: -682px -374px}.sbsprite-cactus_generator_6 { background-position: -704px -374px}.sbsprite-cactus_generator_9 { background-position: -726px -374px}.sbsprite-protector_shimmer { background-position: -748px -374px}.sbsprite-cactus_generator_8 { background-position: -770px -374px}.sbsprite-rune_sparkling { background-position: -792px -374px}.sbsprite-bingo_ring { background-position: -814px -374px}.sbsprite-griffin_upgrade_stone_rare { background-position: -836px -374px}.sbsprite-chick_nest { background-position: -858px -374px}.sbsprite-solved_prism { background-position: -880px -374px}.sbsprite-king_talisman { background-position: -902px -374px}.sbsprite-treasure_ring { background-position: -924px -374px}.sbsprite-black_medium_backpack { background-position: -946px -374px}.sbsprite-surfboard { background-position: -968px -374px}.sbsprite-mithril_fuel_tank { background-position: -990px -374px}.sbsprite-fast_travel_home { background-position: -1012px -374px}.sbsprite-water_trough { background-position: -1034px -374px}.sbsprite-mayor_dante { background-position: 0 -396px}.sbsprite-cheese_fuel { background-position: -22px -396px}.sbsprite-pet_skin_lion_lioness { background-position: -44px -396px}.sbsprite-pink_bunny_personality { background-position: -66px -396px}.sbsprite-goldor_the_fish { background-position: -88px -396px}.sbsprite-speed_wither_helmet { background-position: -110px -396px}.sbsprite-pink_medium_backpack { background-position: -132px -396px}.sbsprite-mayor_derpy { background-position: -154px -396px}.sbsprite-talisman_enrichment_health { background-position: -176px -396px}.sbsprite-enderpack { background-position: -198px -396px}.sbsprite-pet_skin_rock_thinking { background-position: -220px -396px}.sbsprite-soul_fragment { background-position: -242px -396px}.sbsprite-skyblock_chair { background-position: -264px -396px}.sbsprite-mayor_paul { background-position: -286px -396px}.sbsprite-autopet_rules_2 { background-position: -308px -396px}.sbsprite-bat_talisman { background-position: -330px -396px}.sbsprite-killer_4 { background-position: -352px -396px}.sbsprite-killer_5 { background-position: -374px -396px}.sbsprite-killer_6 { background-position: -396px -396px}.sbsprite-killer_7 { background-position: -418px -396px}.sbsprite-killer_8 { background-position: -440px -396px}.sbsprite-killer_9 { background-position: -462px -396px}.sbsprite-builder_appalled_pumpkin { background-position: -484px -396px}.sbsprite-holy_shimmer { background-position: -506px -396px}.sbsprite-royal_pigeon { background-position: -528px -396px}.sbsprite-life_preserver { background-position: -550px -396px}.sbsprite-killer_1 { background-position: -572px -396px}.sbsprite-killer_2 { background-position: -594px -396px}.sbsprite-killer_3 { background-position: -616px -396px}.sbsprite-pet_skin_rock_cool { background-position: -638px -396px}.sbsprite-dingy { background-position: -660px -396px}.sbsprite-intimidation_ring { background-position: -682px -396px}.sbsprite-easter_egg_6 { background-position: -704px -396px}.sbsprite-builder_kiwi { background-position: -726px -396px}.sbsprite-easter_egg_5 { background-position: -748px -396px}.sbsprite-easter_egg_4 { background-position: -770px -396px}.sbsprite-rough_jade_gem { background-position: -792px -396px}.sbsprite-easter_egg_3 { background-position: -814px -396px}.sbsprite-easter_egg_2 { background-position: -836px -396px}.sbsprite-easter_egg_1 { background-position: -858px -396px}.sbsprite-snow_generator_11 { background-position: -880px -396px}.sbsprite-snow_generator_10 { background-position: -902px -396px}.sbsprite-easter_egg_9 { background-position: -924px -396px}.sbsprite-easter_egg_8 { background-position: -946px -396px}.sbsprite-easter_egg_7 { background-position: -968px -396px}.sbsprite-medium_gemstone_sack { background-position: -990px -396px}.sbsprite-large_enchanted_agronomy_sack { background-position: -1012px -396px}.sbsprite-blessed_fruit { background-position: -1034px -396px}.sbsprite-dungeon_stone_archer { background-position: 0 -418px}.sbsprite-arrow_swapper { background-position: -22px -418px}.sbsprite-snow_cannon { background-position: -44px -418px}.sbsprite-jerry_box_mega { background-position: -66px -418px}.sbsprite-pet_skin_sheep_brown { background-position: -88px -418px}.sbsprite-brewing_plus { background-position: -110px -418px}.sbsprite-mayor_barry { background-position: -132px -418px}.sbsprite-bat_ring { background-position: -154px -418px}.sbsprite-candle_arch { background-position: -176px -418px}.sbsprite-mithril_plate { background-position: -198px -418px}.sbsprite-carrot_bait { background-position: -220px -418px}.sbsprite-speed_artifact { background-position: -242px -418px}.sbsprite-salmon_hat { background-position: -264px -418px}.sbsprite-mini_sandcastle { background-position: -286px -418px}.sbsprite-scavenger_talisman { background-position: -308px -418px}.sbsprite-fast_travel_kuudra { background-position: -330px -418px}.sbsprite-foraging_fortune { background-position: -352px -418px}.sbsprite-bunny_personality { background-position: -374px -418px}.sbsprite-sandcastle_personality { background-position: -396px -418px}.sbsprite-undead_11 { background-position: -418px -418px}.sbsprite-magenta_jumbo_backpack { background-position: -440px -418px}.sbsprite-undead_10 { background-position: -462px -418px}.sbsprite-diamond_necron_head { background-position: -484px -418px}.sbsprite-wet_pumpkin { background-position: -506px -418px}.sbsprite-gemstone_gauntlet { background-position: -528px -418px}.sbsprite-cobblestone_generator_9 { background-position: -550px -418px}.sbsprite-cobblestone_generator_8 { background-position: -572px -418px}.sbsprite-iron_generator_1 { background-position: -594px -418px}.sbsprite-cobblestone_generator_7 { background-position: -616px -418px}.sbsprite-control_switch { background-position: -638px -418px}.sbsprite-iron_generator_2 { background-position: -660px -418px}.sbsprite-cobblestone_generator_6 { background-position: -682px -418px}.sbsprite-pumpkin_bomb { background-position: -704px -418px}.sbsprite-cobblestone_generator_5 { background-position: -726px -418px}.sbsprite-cobblestone_generator_4 { background-position: -748px -418px}.sbsprite-dwarven_tankard { background-position: -770px -418px}.sbsprite-jerry_talisman_purple { background-position: -792px -418px}.sbsprite-cobblestone_generator_3 { background-position: -814px -418px}.sbsprite-cobblestone_generator_2 { background-position: -836px -418px}.sbsprite-reindeer_plush { background-position: -858px -418px}.sbsprite-cobblestone_generator_1 { background-position: -880px -418px}.sbsprite-big_xtree { background-position: -902px -418px}.sbsprite-farming_island { background-position: -924px -418px}.sbsprite-rune_endersnake { background-position: -946px -418px}.sbsprite-rune { background-position: -968px -418px}.sbsprite-sweet_flesh { background-position: -990px -418px}.sbsprite-shark_10 { background-position: -1012px -418px}.sbsprite-shark_12 { background-position: -1034px -418px}.sbsprite-viking_tear { background-position: 0 -440px}.sbsprite-shark_11 { background-position: -22px -440px}.sbsprite-iron_generator_7 { background-position: -44px -440px}.sbsprite-iron_generator_8 { background-position: -66px -440px}.sbsprite-iron_generator_9 { background-position: -88px -440px}.sbsprite-beacon_skull { background-position: -110px -440px}.sbsprite-coin_gold_2 { background-position: -132px -440px}.sbsprite-iron_generator_3 { background-position: -154px -440px}.sbsprite-iron_generator_4 { background-position: -176px -440px}.sbsprite-sea_creature_ring { background-position: -198px -440px}.sbsprite-iron_generator_5 { background-position: -220px -440px}.sbsprite-iron_generator_6 { background-position: -242px -440px}.sbsprite-nether_warts_generator_7 { background-position: -264px -440px}.sbsprite-nether_warts_generator_8 { background-position: -286px -440px}.sbsprite-nether_warts_generator_9 { background-position: -308px -440px}.sbsprite-nether_warts_generator_3 { background-position: -330px -440px}.sbsprite-wolf_fur_mixin { background-position: -352px -440px}.sbsprite-mayor_marina { background-position: -374px -440px}.sbsprite-candy_ring { background-position: -396px -440px}.sbsprite-nether_warts_generator_4 { background-position: -418px -440px}.sbsprite-nether_warts_generator_5 { background-position: -440px -440px}.sbsprite-nether_warts_generator_6 { background-position: -462px -440px}.sbsprite-large_backpack { background-position: -484px -440px}.sbsprite-fine_sapphire_gem { background-position: -506px -440px}.sbsprite-nether_warts_generator_1 { background-position: -528px -440px}.sbsprite-nether_warts_generator_2 { background-position: -550px -440px}.sbsprite-griffin_upgrade_stone_uncommon { background-position: -572px -440px}.sbsprite-grey_greater_backpack { background-position: -594px -440px}.sbsprite-shiny_orb { background-position: -616px -440px}.sbsprite-large_enchanted_husbandry_sack { background-position: -638px -440px}.sbsprite-milk_cookies { background-position: -660px -440px}.sbsprite-spider_artifact { background-position: -682px -440px}.sbsprite-green_gift { background-position: -704px -440px}.sbsprite-fast_travel_park { background-position: -726px -440px}.sbsprite-jungle_heart { background-position: -748px -440px}.sbsprite-toil_log { background-position: -770px -440px}.sbsprite-absolute_ender_pearl { background-position: -792px -440px}.sbsprite-catacombs_pass_10 { background-position: -814px -440px}.sbsprite-protector_fragment { background-position: -836px -440px}.sbsprite-ice_generator_1 { background-position: -858px -440px}.sbsprite-ice_generator_2 { background-position: -880px -440px}.sbsprite-old_fragment { background-position: -902px -440px}.sbsprite-ice_generator_3 { background-position: -924px -440px}.sbsprite-traveling_zoo { background-position: -946px -440px}.sbsprite-ice_generator_4 { background-position: -968px -440px}.sbsprite-ice_generator_5 { background-position: -990px -440px}.sbsprite-ice_generator_6 { background-position: -1012px -440px}.sbsprite-ice_generator_7 { background-position: -1034px -440px}.sbsprite-ice_generator_8 { background-position: 0 -462px}.sbsprite-ice_generator_9 { background-position: -22px -462px}.sbsprite-lady_bug_personality { background-position: -44px -462px}.sbsprite-pet_skin_rock_laugh { background-position: -66px -462px}.sbsprite-experimentation_table { background-position: -88px -462px}.sbsprite-titanium_ore { background-position: -110px -462px}.sbsprite-blue_medium_backpack { background-position: -132px -462px}.sbsprite-ice_sofa { background-position: -154px -462px}.sbsprite-rune_lightning { background-position: -176px -462px}.sbsprite-tarantula_talisman { background-position: -198px -462px}.sbsprite-mayor_aatrox { background-position: -220px -462px}.sbsprite-race_crystal_core { background-position: -242px -462px}.sbsprite-black_cat_plush { background-position: -264px -462px}.sbsprite-small_agronomy_sack { background-position: -286px -462px}.sbsprite-magenta_greater_backpack { background-position: -308px -462px}.sbsprite-pet_skin_sheep_light_gray { background-position: -330px -462px}.sbsprite-diamond_scarf_head { background-position: -352px -462px}.sbsprite-hay_bed { background-position: -374px -462px}.sbsprite-talisman_enrichment_sea_creature_chance { background-position: -396px -462px}.sbsprite-strong_shimmer { background-position: -418px -462px}.sbsprite-shady_ring { background-position: -440px -462px}.sbsprite-dante_talisman { background-position: -462px -462px}.sbsprite-pink_bunny_1 { background-position: -484px -462px}.sbsprite-black_greater_backpack { background-position: -506px -462px}.sbsprite-builder_cactus { background-position: -528px -462px}.sbsprite-magenta_small_backpack { background-position: -550px -462px}.sbsprite-talisman_enrichment_defense { background-position: -572px -462px}.sbsprite-pink_bunny_3 { background-position: -594px -462px}.sbsprite-talisman_enrichment_magic_find { background-position: -616px -462px}.sbsprite-pink_bunny_2 { background-position: -638px -462px}.sbsprite-pink_bunny_5 { background-position: -660px -462px}.sbsprite-pink_bunny_4 { background-position: -682px -462px}.sbsprite-salmon_opal { background-position: -704px -462px}.sbsprite-pink_bunny_7 { background-position: -726px -462px}.sbsprite-pink_bunny_6 { background-position: -748px -462px}.sbsprite-pink_bunny_9 { background-position: -770px -462px}.sbsprite-pink_bunny_8 { background-position: -792px -462px}.sbsprite-refined_mithril { background-position: -814px -462px}.sbsprite-happy_emoji_10 { background-position: -836px -462px}.sbsprite-happy_emoji_11 { background-position: -858px -462px}.sbsprite-mine_talisman { background-position: -880px -462px}.sbsprite-old_dragon_helmet { background-position: -902px -462px}.sbsprite-boss_collection_livid { background-position: -924px -462px}.sbsprite-green_small_backpack { background-position: -946px -462px}.sbsprite-rune_bite { background-position: -968px -462px}.sbsprite-jungle_generator_11 { background-position: -990px -462px}.sbsprite-mega_luck { background-position: -1012px -462px}.sbsprite-jungle_generator_10 { background-position: -1034px -462px}.sbsprite-pet_skin_chicken_baby_chick { background-position: 0 -484px}.sbsprite-pile_of_cash { background-position: -22px -484px}.sbsprite-dungeoneering { background-position: -44px -484px}.sbsprite-base_griffin_upgrade_stone { background-position: -66px -484px}.sbsprite-red_tent { background-position: -88px -484px}.sbsprite-dungeon_red_support_orb { background-position: -110px -484px}.sbsprite-fast_travel_nether { background-position: -132px -484px}.sbsprite-night_vision_charm { background-position: -154px -484px}.sbsprite-zombie_grave { background-position: -176px -484px}.sbsprite-fish_bait { background-position: -198px -484px}.sbsprite-ice_lolly_personality { background-position: -220px -484px}.sbsprite-grizzly_paw { background-position: -242px -484px}.sbsprite-large_potion_bag { background-position: -264px -484px}.sbsprite-poorly_wrapped_rock { background-position: -286px -484px}.sbsprite-drill_engine { background-position: -308px -484px}.sbsprite-dark_oak_generator_10 { background-position: -330px -484px}.sbsprite-dungeon_normal_key { background-position: -352px -484px}.sbsprite-dark_oak_generator_11 { background-position: -374px -484px}.sbsprite-unstable_shimmer { background-position: -396px -484px}.sbsprite-green_egg { background-position: -418px -484px}.sbsprite-rough_topaz_gem { background-position: -440px -484px}.sbsprite-mana_flux_power_orb { background-position: -462px -484px}.sbsprite-amber_material { background-position: -484px -484px}.sbsprite-grinch_personality { background-position: -506px -484px}.sbsprite-fast_travel_crystals { background-position: -528px -484px}.sbsprite-lapis_generator_2 { background-position: -550px -484px}.sbsprite-lapis_generator_3 { background-position: -572px -484px}.sbsprite-rune_sack { background-position: -594px -484px}.sbsprite-lapis_generator_4 { background-position: -616px -484px}.sbsprite-tightly_tied_hay_bale { background-position: -638px -484px}.sbsprite-beach_ball { background-position: -660px -484px}.sbsprite-lapis_generator_5 { background-position: -682px -484px}.sbsprite-lapis_generator_10 { background-position: -704px -484px}.sbsprite-lapis_generator_12 { background-position: -726px -484px}.sbsprite-light_grey_large_backpack { background-position: -748px -484px}.sbsprite-lapis_generator_1 { background-position: -770px -484px}.sbsprite-lapis_generator_11 { background-position: -792px -484px}.sbsprite-pet_item_quick_claw { background-position: -814px -484px}.sbsprite-basketball_9 { background-position: -836px -484px}.sbsprite-deck_chair { background-position: -858px -484px}.sbsprite-lady_bug_9 { background-position: -880px -484px}.sbsprite-basketball_8 { background-position: -902px -484px}.sbsprite-lady_bug_8 { background-position: -924px -484px}.sbsprite-basketball_7 { background-position: -946px -484px}.sbsprite-basketball_6 { background-position: -968px -484px}.sbsprite-rune_pestilence { background-position: -990px -484px}.sbsprite-basketball_5 { background-position: -1012px -484px}.sbsprite-mithril_generator_12 { background-position: -1034px -484px}.sbsprite-sea_creature_talisman { background-position: 0 -506px}.sbsprite-basketball_4 { background-position: -22px -506px}.sbsprite-mithril_generator_11 { background-position: -44px -506px}.sbsprite-basketball_3 { background-position: -66px -506px}.sbsprite-mithril_generator_10 { background-position: -88px -506px}.sbsprite-basketball_2 { background-position: -110px -506px}.sbsprite-blue_egg { background-position: -132px -506px}.sbsprite-basketball_1 { background-position: -154px -506px}.sbsprite-lady_bug_1 { background-position: -176px -506px}.sbsprite-emerald_ring { background-position: -198px -506px}.sbsprite-lady_bug_3 { background-position: -220px -506px}.sbsprite-lady_bug_2 { background-position: -242px -506px}.sbsprite-lady_bug_5 { background-position: -264px -506px}.sbsprite-lapis_generator_6 { background-position: -286px -506px}.sbsprite-epoch_cake_green { background-position: -308px -506px}.sbsprite-lady_bug_4 { background-position: -330px -506px}.sbsprite-lapis_generator_7 { background-position: -352px -506px}.sbsprite-medium_husbandry_sack { background-position: -374px -506px}.sbsprite-bunny_11 { background-position: -396px -506px}.sbsprite-lady_bug_7 { background-position: -418px -506px}.sbsprite-lapis_generator_8 { background-position: -440px -506px}.sbsprite-bunny_10 { background-position: -462px -506px}.sbsprite-candy_relic { background-position: -484px -506px}.sbsprite-lady_bug_6 { background-position: -506px -506px}.sbsprite-lapis_generator_9 { background-position: -528px -506px}.sbsprite-red_jumbo_backpack { background-position: -550px -506px}.sbsprite-holy_fragment { background-position: -572px -506px}.sbsprite-ice_cream_personality { background-position: -594px -506px}.sbsprite-dungeon_blue_support_orb { background-position: -616px -506px}.sbsprite-blaze_generator_4 { background-position: -638px -506px}.sbsprite-blaze_generator_3 { background-position: -660px -506px}.sbsprite-blaze_generator_2 { background-position: -682px -506px}.sbsprite-blaze_generator_1 { background-position: -704px -506px}.sbsprite-blaze_generator_8 { background-position: -726px -506px}.sbsprite-blaze_generator_7 { background-position: -748px -506px}.sbsprite-pet_skin_whale_orca { background-position: -770px -506px}.sbsprite-blaze_generator_6 { background-position: -792px -506px}.sbsprite-blaze_generator_5 { background-position: -814px -506px}.sbsprite-deadgehog_helmet { background-position: -836px -506px}.sbsprite-volta { background-position: -858px -506px}.sbsprite-blaze_generator_9 { background-position: -880px -506px}.sbsprite-frozen_chicken { background-position: -902px -506px}.sbsprite-pet_skin_dragon_neon_purple { background-position: -924px -506px}.sbsprite-cavespider_generator_6 { background-position: -946px -506px}.sbsprite-cavespider_generator_5 { background-position: -968px -506px}.sbsprite-rune_gem { background-position: -990px -506px}.sbsprite-cavespider_generator_8 { background-position: -1012px -506px}.sbsprite-cavespider_generator_7 { background-position: -1034px -506px}.sbsprite-cavespider_generator_2 { background-position: 0 -528px}.sbsprite-cavespider_generator_1 { background-position: -22px -528px}.sbsprite-cavespider_generator_4 { background-position: -44px -528px}.sbsprite-jerry_talisman_blue { background-position: -66px -528px}.sbsprite-cavespider_generator_3 { background-position: -88px -528px}.sbsprite-speed_talisman { background-position: -110px -528px}.sbsprite-mummy_1 { background-position: -132px -528px}.sbsprite-rabbit_hat { background-position: -154px -528px}.sbsprite-bat_person_ring { background-position: -176px -528px}.sbsprite-mummy_3 { background-position: -198px -528px}.sbsprite-cavespider_generator_9 { background-position: -220px -528px}.sbsprite-mummy_2 { background-position: -242px -528px}.sbsprite-mummy_5 { background-position: -264px -528px}.sbsprite-strong_baby { background-position: -286px -528px}.sbsprite-mummy_4 { background-position: -308px -528px}.sbsprite-mummy_7 { background-position: -330px -528px}.sbsprite-mummy_6 { background-position: -352px -528px}.sbsprite-spooky_helmet { background-position: -374px -528px}.sbsprite-dining_chair { background-position: -396px -528px}.sbsprite-mummy_9 { background-position: -418px -528px}.sbsprite-mummy_8 { background-position: -440px -528px}.sbsprite-ender_relic { background-position: -462px -528px}.sbsprite-flawed_jasper_gem { background-position: -484px -528px}.sbsprite-cactus_generator_10 { background-position: -506px -528px}.sbsprite-pet_skin_silverfish_fossilized { background-position: -528px -528px}.sbsprite-cactus_generator_11 { background-position: -550px -528px}.sbsprite-cactus_generator_12 { background-position: -572px -528px}.sbsprite-dark_goggles { background-position: -594px -528px}.sbsprite-starred_bonzo_mask { background-position: -616px -528px}.sbsprite-pigs_foot { background-position: -638px -528px}.sbsprite-gemstone_mixture { background-position: -660px -528px}.sbsprite-tarantula_black_widow { background-position: -682px -528px}.sbsprite-builder_berry_bush { background-position: -704px -528px}.sbsprite-chicken_head { background-position: -726px -528px}.sbsprite-pet_skin_elephant_purple { background-position: -748px -528px}.sbsprite-cow_head { background-position: -770px -528px}.sbsprite-witch_broomstick { background-position: -792px -528px}.sbsprite-pet_skin_monkey_gorilla { background-position: -814px -528px}.sbsprite-grey_large_backpack { background-position: -836px -528px}.sbsprite-pet_skin_sheep_neon_green { background-position: -858px -528px}.sbsprite-magic_mushroom_soup { background-position: -880px -528px}.sbsprite-petrified_starfall { background-position: -902px -528px}.sbsprite-spruce_generator_9 { background-position: -924px -528px}.sbsprite-second_master_star { background-position: -946px -528px}.sbsprite-sled { background-position: -968px -528px}.sbsprite-spruce_generator_1 { background-position: -990px -528px}.sbsprite-voidling_generator_2 { background-position: -1012px -528px}.sbsprite-red { background-position: -1034px -528px}.sbsprite-spirit_wing { background-position: 0 -550px}.sbsprite-spruce_generator_2 { background-position: -22px -550px}.sbsprite-voidling_generator_1 { background-position: -44px -550px}.sbsprite-spruce_generator_3 { background-position: -66px -550px}.sbsprite-voidling_generator_4 { background-position: -88px -550px}.sbsprite-spruce_generator_4 { background-position: -110px -550px}.sbsprite-voidling_generator_3 { background-position: -132px -550px}.sbsprite-spruce_generator_5 { background-position: -154px -550px}.sbsprite-voidling_generator_6 { background-position: -176px -550px}.sbsprite-spruce_generator_6 { background-position: -198px -550px}.sbsprite-voidling_generator_5 { background-position: -220px -550px}.sbsprite-spruce_generator_7 { background-position: -242px -550px}.sbsprite-voidling_generator_8 { background-position: -264px -550px}.sbsprite-spruce_generator_8 { background-position: -286px -550px}.sbsprite-voidling_generator_7 { background-position: -308px -550px}.sbsprite-voidling_generator_9 { background-position: -330px -550px}.sbsprite-magenta_large_backpack { background-position: -352px -550px}.sbsprite-fast_travel_end { background-position: -374px -550px}.sbsprite-cow_generator_8 { background-position: -396px -550px}.sbsprite-cow_generator_9 { background-position: -418px -550px}.sbsprite-present_1 { background-position: -440px -550px}.sbsprite-topaz_crystal { background-position: -462px -550px}.sbsprite-bestiary_private_island { background-position: -484px -550px}.sbsprite-present_2 { background-position: -506px -550px}.sbsprite-present_3 { background-position: -528px -550px}.sbsprite-cow_generator_1 { background-position: -550px -550px}.sbsprite-cow_generator_2 { background-position: -572px -550px}.sbsprite-dragon_horn { background-position: -594px -550px}.sbsprite-bat_artifact { background-position: -616px -550px}.sbsprite-cow_generator_3 { background-position: -638px -550px}.sbsprite-cow_generator_4 { background-position: -660px -550px}.sbsprite-cow_generator_5 { background-position: -682px -550px}.sbsprite-cow_generator_6 { background-position: -704px -550px}.sbsprite-cow_generator_7 { background-position: -726px -550px}.sbsprite-goblin_omelette_pesto { background-position: -748px -550px}.sbsprite-farming_2_portal { background-position: -770px -550px}.sbsprite-village_talisman { background-position: -792px -550px}.sbsprite-cheetah_talisman { background-position: -814px -550px}.sbsprite-mining_2_portal { background-position: -836px -550px}.sbsprite-present_8 { background-position: -858px -550px}.sbsprite-wood_talisman { background-position: -880px -550px}.sbsprite-present_9 { background-position: -902px -550px}.sbsprite-present_4 { background-position: -924px -550px}.sbsprite-present_5 { background-position: -946px -550px}.sbsprite-present_6 { background-position: -968px -550px}.sbsprite-present_7 { background-position: -990px -550px}.sbsprite-healing_ring { background-position: -1012px -550px}.sbsprite-titanium_artifact { background-position: -1034px -550px}.sbsprite-penguin_1 { background-position: 0 -572px}.sbsprite-penguin_2 { background-position: -22px -572px}.sbsprite-ruby_crystal { background-position: -44px -572px}.sbsprite-tiki_torch { background-position: -66px -572px}.sbsprite-wheat_generator_10 { background-position: -88px -572px}.sbsprite-emerald_generator_8 { background-position: -110px -572px}.sbsprite-wheat_generator_12 { background-position: -132px -572px}.sbsprite-emerald_generator_7 { background-position: -154px -572px}.sbsprite-wheat_generator_11 { background-position: -176px -572px}.sbsprite-scarecrow { background-position: -198px -572px}.sbsprite-emerald_generator_9 { background-position: -220px -572px}.sbsprite-emerald_generator_4 { background-position: -242px -572px}.sbsprite-emerald_generator_3 { background-position: -264px -572px}.sbsprite-emerald_generator_6 { background-position: -286px -572px}.sbsprite-emerald_generator_5 { background-position: -308px -572px}.sbsprite-pet_skin_elephant_monochrome { background-position: -330px -572px}.sbsprite-emerald_generator_2 { background-position: -352px -572px}.sbsprite-emerald_generator_1 { background-position: -374px -572px}.sbsprite-flawless_topaz_gem { background-position: -396px -572px}.sbsprite-raw_soulflow { background-position: -418px -572px}.sbsprite-large_enchanted_mining_sack { background-position: -440px -572px}.sbsprite-gold_scarf_head { background-position: -462px -572px}.sbsprite-orange_medium_backpack { background-position: -484px -572px}.sbsprite-fine_jade_gem { background-position: -506px -572px}.sbsprite-white_gift { background-position: -528px -572px}.sbsprite-goblin_omelette_sunny_side { background-position: -550px -572px}.sbsprite-builder_brown_mushroom { background-position: -572px -572px}.sbsprite-giant_flesh { background-position: -594px -572px}.sbsprite-jumbo_backpack { background-position: -616px -572px}.sbsprite-eternal_flame_ring { background-position: -638px -572px}.sbsprite-wrapped_gift_for_juliette { background-position: -660px -572px}.sbsprite-enchanted_book_bundle_counter_strike { background-position: -682px -572px}.sbsprite-pet_item_toy_jerry { background-position: -704px -572px}.sbsprite-golden_plate { background-position: -726px -572px}.sbsprite-penguin_5 { background-position: -748px -572px}.sbsprite-grandfather_clock { background-position: -770px -572px}.sbsprite-penguin_6 { background-position: -792px -572px}.sbsprite-penguin_3 { background-position: -814px -572px}.sbsprite-pet_skin_elephant_orange { background-position: -836px -572px}.sbsprite-fast_travel_museum { background-position: -858px -572px}.sbsprite-penguin_4 { background-position: -880px -572px}.sbsprite-penguin_9 { background-position: -902px -572px}.sbsprite-penguin_7 { background-position: -924px -572px}.sbsprite-penguin_8 { background-position: -946px -572px}.sbsprite-light_grey_medium_backpack { background-position: -968px -572px}.sbsprite-blue_jumbo_backpack { background-position: -990px -572px}.sbsprite-cyan_small_backpack { background-position: -1012px -572px}.sbsprite-jade_crystal { background-position: -1034px -572px}.sbsprite-large_dungeon_sack { background-position: 0 -594px}.sbsprite-summoning_ring { background-position: -22px -594px}.sbsprite-dragon_essence { background-position: -44px -594px}.sbsprite-basket_of_seeds { background-position: -66px -594px}.sbsprite-bunny_jerry { background-position: -88px -594px}.sbsprite-perfect_jade_gem { background-position: -110px -594px}.sbsprite-spray_can { background-position: -132px -594px}.sbsprite-campfire_talisman_4 { background-position: -154px -594px}.sbsprite-campfire_talisman_5 { background-position: -176px -594px}.sbsprite-campfire_talisman_2 { background-position: -198px -594px}.sbsprite-campfire_talisman_3 { background-position: -220px -594px}.sbsprite-remnant_of_the_eye { background-position: -242px -594px}.sbsprite-campfire_talisman_1 { background-position: -264px -594px}.sbsprite-talisman_enrichment_critical_chance { background-position: -286px -594px}.sbsprite-ghast_head { background-position: -308px -594px}.sbsprite-white_greater_backpack { background-position: -330px -594px}.sbsprite-mayor_diaz { background-position: -352px -594px}.sbsprite-campfire_talisman_8 { background-position: -374px -594px}.sbsprite-campfire_talisman_9 { background-position: -396px -594px}.sbsprite-jaderald { background-position: -418px -594px}.sbsprite-campfire_talisman_6 { background-position: -440px -594px}.sbsprite-gold_thorn_head { background-position: -462px -594px}.sbsprite-campfire_talisman_7 { background-position: -484px -594px}.sbsprite-dark_bait { background-position: -506px -594px}.sbsprite-game_annihilator { background-position: -528px -594px}.sbsprite-purple_greater_backpack { background-position: -550px -594px}.sbsprite-bestiary_deep_caverns { background-position: -572px -594px}.sbsprite-foraging_5_portal { background-position: -594px -594px}.sbsprite-wolf_talisman { background-position: -616px -594px}.sbsprite-gold_professor_head { background-position: -638px -594px}.sbsprite-pet_skin_sheep_light_blue { background-position: -660px -594px}.sbsprite-ice_lolly_4 { background-position: -682px -594px}.sbsprite-basketball_10 { background-position: -704px -594px}.sbsprite-ice_lolly_3 { background-position: -726px -594px}.sbsprite-mineral_helmet { background-position: -748px -594px}.sbsprite-basketball_11 { background-position: -770px -594px}.sbsprite-ice_lolly_2 { background-position: -792px -594px}.sbsprite-basketball_12 { background-position: -814px -594px}.sbsprite-ice_lolly_1 { background-position: -836px -594px}.sbsprite-rock_candy { background-position: -858px -594px}.sbsprite-ice_lolly_8 { background-position: -880px -594px}.sbsprite-tarantula_generator_2 { background-position: -902px -594px}.sbsprite-ice_lolly_7 { background-position: -924px -594px}.sbsprite-tarantula_generator_1 { background-position: -946px -594px}.sbsprite-ice_lolly_6 { background-position: -968px -594px}.sbsprite-ice_lolly_5 { background-position: -990px -594px}.sbsprite-purple_egg { background-position: -1012px -594px}.sbsprite-ice_lolly_9 { background-position: -1034px -594px}.sbsprite-tarantula_generator_9 { background-position: 0 -616px}.sbsprite-tarantula_generator_8 { background-position: -22px -616px}.sbsprite-tarantula_generator_7 { background-position: -44px -616px}.sbsprite-tarantula_generator_6 { background-position: -66px -616px}.sbsprite-tarantula_generator_5 { background-position: -88px -616px}.sbsprite-tarantula_generator_4 { background-position: -110px -616px}.sbsprite-tarantula_generator_3 { background-position: -132px -616px}.sbsprite-hypixel_castle { background-position: -154px -616px}.sbsprite-rune_golden { background-position: -176px -616px}.sbsprite-wheat_generator_9 { background-position: -198px -616px}.sbsprite-ftx_3070 { background-position: -220px -616px}.sbsprite-wheat_generator_8 { background-position: -242px -616px}.sbsprite-wheat_generator_5 { background-position: -264px -616px}.sbsprite-wheat_generator_4 { background-position: -286px -616px}.sbsprite-builder_corn { background-position: -308px -616px}.sbsprite-cheap_coffee { background-position: -330px -616px}.sbsprite-wheat_generator_7 { background-position: -352px -616px}.sbsprite-wheat_generator_6 { background-position: -374px -616px}.sbsprite-mushroom_generator_11 { background-position: -396px -616px}.sbsprite-wheat_generator_1 { background-position: -418px -616px}.sbsprite-mushroom_generator_10 { background-position: -440px -616px}.sbsprite-ender_plus { background-position: -462px -616px}.sbsprite-wheat_generator_3 { background-position: -484px -616px}.sbsprite-wheat_generator_2 { background-position: -506px -616px}.sbsprite-voidling_generator_10 { background-position: -528px -616px}.sbsprite-voidling_generator_11 { background-position: -550px -616px}.sbsprite-mushroom_generator_12 { background-position: -572px -616px}.sbsprite-personal_bonus { background-position: -594px -616px}.sbsprite-flawless_amber_gem { background-position: -616px -616px}.sbsprite-rune_darkness_within { background-position: -638px -616px}.sbsprite-bag_of_cash { background-position: -660px -616px}.sbsprite-pet_skin_hound_beagle { background-position: -682px -616px}.sbsprite-pufferfish_hat { background-position: -704px -616px}.sbsprite-lime_greater_backpack { background-position: -726px -616px}.sbsprite-food_trough { background-position: -748px -616px}.sbsprite-pet_skin_yeti_grown_up { background-position: -770px -616px}.sbsprite-slime_generator_10 { background-position: -792px -616px}.sbsprite-undead_personality { background-position: -814px -616px}.sbsprite-slime_generator_11 { background-position: -836px -616px}.sbsprite-nether_wart_island { background-position: -858px -616px}.sbsprite-gravel_generator_5 { background-position: -880px -616px}.sbsprite-gravel_generator_4 { background-position: -902px -616px}.sbsprite-gravel_generator_7 { background-position: -924px -616px}.sbsprite-gravel_generator_6 { background-position: -946px -616px}.sbsprite-gravel_generator_9 { background-position: -968px -616px}.sbsprite-gravel_generator_8 { background-position: -990px -616px}.sbsprite-shiny_shard { background-position: -1012px -616px}.sbsprite-pet_skin_rabbit_rose { background-position: -1034px -616px}.sbsprite-quiver { background-position: 0 -638px}.sbsprite-rune_snake { background-position: -22px -638px}.sbsprite-bonzo_mask { background-position: -44px -638px}.sbsprite-fast_travel { background-position: -66px -638px}.sbsprite-treasurite { background-position: -88px -638px}.sbsprite-chicken_coop { background-position: -110px -638px}.sbsprite-end_portal_fumes_mixin { background-position: -132px -638px}.sbsprite-crafting_plus { background-position: -154px -638px}.sbsprite-gravel_generator_1 { background-position: -176px -638px}.sbsprite-gravel_generator_3 { background-position: -198px -638px}.sbsprite-gravel_generator_2 { background-position: -220px -638px}.sbsprite-easter_egg_11 { background-position: -242px -638px}.sbsprite-easter_egg_10 { background-position: -264px -638px}.sbsprite-protein_bar { background-position: -286px -638px}.sbsprite-hard_stone_generator_10 { background-position: -308px -638px}.sbsprite-coin_gold { background-position: -330px -638px}.sbsprite-light_blue_jumbo_backpack { background-position: -352px -638px}.sbsprite-hard_stone_generator_12 { background-position: -374px -638px}.sbsprite-hard_stone_generator_11 { background-position: -396px -638px}.sbsprite-rune_blood { background-position: -418px -638px}.sbsprite-raggedy_shark_tooth_necklace { background-position: -440px -638px}.sbsprite-pure_mithril { background-position: -462px -638px}.sbsprite-coin_emerald { background-position: -484px -638px}.sbsprite-pet_skin_black_cat_onyx { background-position: -506px -638px}.sbsprite-easter_egg_12 { background-position: -528px -638px}.sbsprite-emperor_head { background-position: -550px -638px}.sbsprite-power_wither_helmet { background-position: -572px -638px}.sbsprite-bee_11 { background-position: -594px -638px}.sbsprite-bee_10 { background-position: -616px -638px}.sbsprite-pet_skin_wolf { background-position: -638px -638px}.sbsprite-pumpkin_4 { background-position: -660px -638px}.sbsprite-pumpkin_3 { background-position: -682px -638px}.sbsprite-pumpkin_6 { background-position: -704px -638px}.sbsprite-fine_ruby_gem { background-position: -726px -638px}.sbsprite-pumpkin_5 { background-position: -748px -638px}.sbsprite-pumpkin_2 { background-position: -770px -638px}.sbsprite-electron_transmitter { background-position: -792px -638px}.sbsprite-pumpkin_1 { background-position: -814px -638px}.sbsprite-gingerbread_house { background-position: -836px -638px}.sbsprite-bee_1 { background-position: -858px -638px}.sbsprite-large_mining_sack { background-position: -880px -638px}.sbsprite-bee_2 { background-position: -902px -638px}.sbsprite-bee_3 { background-position: -924px -638px}.sbsprite-bee_4 { background-position: -946px -638px}.sbsprite-midas_jewel { background-position: -968px -638px}.sbsprite-unstable_dragon_helmet { background-position: -990px -638px}.sbsprite-vaccine_talisman { background-position: -1012px -638px}.sbsprite-whale_bait { background-position: -1034px -638px}.sbsprite-bee_9 { background-position: 0 -660px}.sbsprite-bee_5 { background-position: -22px -660px}.sbsprite-booster_cookie_box { background-position: -44px -660px}.sbsprite-perfect_topaz_gem { background-position: -66px -660px}.sbsprite-bee_6 { background-position: -88px -660px}.sbsprite-bee_7 { background-position: -110px -660px}.sbsprite-bee_8 { background-position: -132px -660px}.sbsprite-elvish_helmet { background-position: -154px -660px}.sbsprite-pumpkin_8 { background-position: -176px -660px}.sbsprite-light_grey_greater_backpack { background-position: -198px -660px}.sbsprite-pumpkin_7 { background-position: -220px -660px}.sbsprite-pumpkin_9 { background-position: -242px -660px}.sbsprite-best_weapon_rack { background-position: -264px -660px}.sbsprite-washed_up_souvenir { background-position: -286px -660px}.sbsprite-coin_diamond { background-position: -308px -660px}.sbsprite-builder_pink_berry { background-position: -330px -660px}.sbsprite-clownfish_personality { background-position: -352px -660px}.sbsprite-easter_egg_personality { background-position: -374px -660px}.sbsprite-jerry_talisman_green { background-position: -396px -660px}.sbsprite-spiked_atrocity { background-position: -418px -660px}.sbsprite-flower_generator_8 { background-position: -440px -660px}.sbsprite-flower_generator_9 { background-position: -462px -660px}.sbsprite-farmer_orb { background-position: -484px -660px}.sbsprite-flower_generator_4 { background-position: -506px -660px}.sbsprite-crypt_skull_key { background-position: -528px -660px}.sbsprite-flower_generator_5 { background-position: -550px -660px}.sbsprite-flower_generator_6 { background-position: -572px -660px}.sbsprite-flower_generator_7 { background-position: -594px -660px}.sbsprite-flower_generator_1 { background-position: -616px -660px}.sbsprite-flower_generator_2 { background-position: -638px -660px}.sbsprite-nutcracker { background-position: -660px -660px}.sbsprite-flower_generator_3 { background-position: -682px -660px}.sbsprite-scarf_studies { background-position: -704px -660px}.sbsprite-builder_apple { background-position: -726px -660px}.sbsprite-skyblock_table { background-position: -748px -660px}.sbsprite-sleeping_eye { background-position: -770px -660px}.sbsprite-spider_generator_1 { background-position: -792px -660px}.sbsprite-pet_skin_elephant_blue { background-position: -814px -660px}.sbsprite-spider_generator_2 { background-position: -836px -660px}.sbsprite-spider_generator_3 { background-position: -858px -660px}.sbsprite-shark_bait { background-position: -880px -660px}.sbsprite-spider_generator_4 { background-position: -902px -660px}.sbsprite-spider_generator_5 { background-position: -924px -660px}.sbsprite-black { background-position: -946px -660px}.sbsprite-sapphire_polished_drill_engine { background-position: -968px -660px}.sbsprite-cocoa_generator_1 { background-position: -990px -660px}.sbsprite-cocoa_generator_7 { background-position: -1012px -660px}.sbsprite-cocoa_generator_6 { background-position: -1034px -660px}.sbsprite-rune_snow { background-position: 0 -682px}.sbsprite-cocoa_generator_9 { background-position: -22px -682px}.sbsprite-cocoa_generator_8 { background-position: -44px -682px}.sbsprite-cocoa_generator_3 { background-position: -66px -682px}.sbsprite-cocoa_generator_2 { background-position: -88px -682px}.sbsprite-cocoa_generator_5 { background-position: -110px -682px}.sbsprite-cocoa_generator_4 { background-position: -132px -682px}.sbsprite-spider_generator_6 { background-position: -154px -682px}.sbsprite-spider_generator_7 { background-position: -176px -682px}.sbsprite-spider_generator_8 { background-position: -198px -682px}.sbsprite-spider_generator_9 { background-position: -220px -682px}.sbsprite-brown_large_backpack { background-position: -242px -682px}.sbsprite-flower_maelstrom { background-position: -264px -682px}.sbsprite-pumpkin_generator_12 { background-position: -286px -682px}.sbsprite-coal_generator_9 { background-position: -308px -682px}.sbsprite-diamond_thorn_head { background-position: -330px -682px}.sbsprite-ender_stone_generator_11 { background-position: -352px -682px}.sbsprite-coal_generator_8 { background-position: -374px -682px}.sbsprite-ender_stone_generator_10 { background-position: -396px -682px}.sbsprite-coal_generator_7 { background-position: -418px -682px}.sbsprite-jerry_box_blue { background-position: -440px -682px}.sbsprite-coal_generator_6 { background-position: -462px -682px}.sbsprite-coal_generator_5 { background-position: -484px -682px}.sbsprite-pumpkin_generator_11 { background-position: -506px -682px}.sbsprite-coal_generator_4 { background-position: -528px -682px}.sbsprite-pumpkin_generator_10 { background-position: -550px -682px}.sbsprite-talisman_of_space { background-position: -572px -682px}.sbsprite-talisman_enrichment_strength { background-position: -594px -682px}.sbsprite-white_jumbo_backpack { background-position: -616px -682px}.sbsprite-full_fairy_control { background-position: -638px -682px}.sbsprite-quartz_generator_9 { background-position: -660px -682px}.sbsprite-rune_wake { background-position: -682px -682px}.sbsprite-quartz_generator_8 { background-position: -704px -682px}.sbsprite-festive_jerry_personality { background-position: -726px -682px}.sbsprite-quartz_generator_5 { background-position: -748px -682px}.sbsprite-builder_berry { background-position: -770px -682px}.sbsprite-quartz_generator_4 { background-position: -792px -682px}.sbsprite-quartz_generator_7 { background-position: -814px -682px}.sbsprite-quartz_generator_6 { background-position: -836px -682px}.sbsprite-quartz_generator_1 { background-position: -858px -682px}.sbsprite-quartz_generator_3 { background-position: -880px -682px}.sbsprite-quartz_generator_2 { background-position: -902px -682px}.sbsprite-bingo_heirloom { background-position: -924px -682px}.sbsprite-dwarf_turtle_shelmet { background-position: -946px -682px}.sbsprite-wolf_paw { background-position: -968px -682px}.sbsprite-jasper_crystal { background-position: -990px -682px}.sbsprite-party_hat_crab { background-position: -1012px -682px}.sbsprite-feather_artifact { background-position: -1034px -682px}.sbsprite-coal_generator_3 { background-position: 0 -704px}.sbsprite-coal_generator_2 { background-position: -22px -704px}.sbsprite-coal_generator_1 { background-position: -44px -704px}.sbsprite-fast_travel_gold { background-position: -66px -704px}.sbsprite-crystal_hollows_crystals { background-position: -88px -704px}.sbsprite-mining_island { background-position: -110px -704px}.sbsprite-flawless_jasper_gem { background-position: -132px -704px}.sbsprite-halloween_candles { background-position: -154px -704px}.sbsprite-ascension_rope { background-position: -176px -704px}.sbsprite-brown_small_backpack { background-position: -198px -704px}.sbsprite-diver_puffer { background-position: -220px -704px}.sbsprite-melon_generator_10 { background-position: -242px -704px}.sbsprite-melon_generator_12 { background-position: -264px -704px}.sbsprite-melon_generator_11 { background-position: -286px -704px}.sbsprite-desert_island { background-position: -308px -704px}.sbsprite-green { background-position: -330px -704px}.sbsprite-crystallized_heart { background-position: -352px -704px}.sbsprite-sinful_dice { background-position: -374px -704px}.sbsprite-soulflow_supercell { background-position: -396px -704px}.sbsprite-sea_creature_artifact { background-position: -418px -704px}.sbsprite-grey_small_backpack { background-position: -440px -704px}.sbsprite-aatrox_batphone { background-position: -462px -704px}.sbsprite-clay_generator_10 { background-position: -484px -704px}.sbsprite-clay_generator_11 { background-position: -506px -704px}.sbsprite-end_stone_personality { background-position: -528px -704px}.sbsprite-builder_banana_bunch { background-position: -550px -704px}.sbsprite-danger_2_portal { background-position: -572px -704px}.sbsprite-mayor_scorpius { background-position: -594px -704px}.sbsprite-voodoo { background-position: -616px -704px}.sbsprite-jerry_box_purple { background-position: -638px -704px}.sbsprite-wither_artifact { background-position: -660px -704px}.sbsprite-skull_chest { background-position: -682px -704px}.sbsprite-pet_skin_elephant_pink { background-position: -704px -704px}.sbsprite-oak_generator_10 { background-position: -726px -704px}.sbsprite-slime_generator_1 { background-position: -748px -704px}.sbsprite-slime_generator_2 { background-position: -770px -704px}.sbsprite-frozen_blaze_icicle { background-position: -792px -704px}.sbsprite-oak_generator_11 { background-position: -814px -704px}.sbsprite-slime_generator_5 { background-position: -836px -704px}.sbsprite-slime_generator_6 { background-position: -858px -704px}.sbsprite-slime_generator_3 { background-position: -880px -704px}.sbsprite-slime_generator_4 { background-position: -902px -704px}.sbsprite-slime_generator_9 { background-position: -924px -704px}.sbsprite-slime_generator_7 { background-position: -946px -704px}.sbsprite-slime_generator_8 { background-position: -968px -704px}.sbsprite-dungeon_golden_key { background-position: -990px -704px}.sbsprite-mender_fedora { background-position: -1012px -704px}.sbsprite-pet_skin_rock_smile { background-position: -1034px -704px}.sbsprite-builder_orange { background-position: 0 -726px}.sbsprite-ghast_generator_10 { background-position: -22px -726px}.sbsprite-beach_chair { background-position: -44px -726px}.sbsprite-ghast_generator_11 { background-position: -66px -726px}.sbsprite-boss { background-position: -88px -726px}.sbsprite-race_precursor_ruins { background-position: -110px -726px}.sbsprite-perfectly_cut_fuel_tank { background-position: -132px -726px}.sbsprite-ice_essence { background-position: -154px -726px}.sbsprite-jerry_box_green { background-position: -176px -726px}.sbsprite-fireplace { background-position: -198px -726px}.sbsprite-moldy_bread { background-position: -220px -726px}.sbsprite-pet_skin_tiger_saber_tooth { background-position: -242px -726px}.sbsprite-obsidian_generator_5 { background-position: -264px -726px}.sbsprite-obsidian_generator_4 { background-position: -286px -726px}.sbsprite-obsidian_generator_7 { background-position: -308px -726px}.sbsprite-obsidian_generator_6 { background-position: -330px -726px}.sbsprite-obsidian_generator_1 { background-position: -352px -726px}.sbsprite-obsidian_generator_3 { background-position: -374px -726px}.sbsprite-foraging_1_portal { background-position: -396px -726px}.sbsprite-obsidian_generator_2 { background-position: -418px -726px}.sbsprite-dungeon_stone_tank { background-position: -440px -726px}.sbsprite-obsidian_generator_9 { background-position: -462px -726px}.sbsprite-obsidian_generator_8 { background-position: -484px -726px}.sbsprite-pet_skin_sheep_light_green { background-position: -506px -726px}.sbsprite-decayed_bat { background-position: -528px -726px}.sbsprite-pet_skin_squid_glow { background-position: -550px -726px}.sbsprite-potato_generator_4 { background-position: -572px -726px}.sbsprite-potato_generator_5 { background-position: -594px -726px}.sbsprite-potato_generator_12 { background-position: -616px -726px}.sbsprite-potato_generator_6 { background-position: -638px -726px}.sbsprite-potato_generator_11 { background-position: -660px -726px}.sbsprite-potato_generator_7 { background-position: -682px -726px}.sbsprite-potato_generator_10 { background-position: -704px -726px}.sbsprite-potato_generator_8 { background-position: -726px -726px}.sbsprite-potato_generator_9 { background-position: -748px -726px}.sbsprite-slayer_energy_drink { background-position: -770px -726px}.sbsprite-arachne_keeper_fragment { background-position: -792px -726px}.sbsprite-cat_talisman { background-position: -814px -726px}.sbsprite-large_slayer_sack { background-position: -836px -726px}.sbsprite-rune_rainbow { background-position: -858px -726px}.sbsprite-potato_generator_1 { background-position: -880px -726px}.sbsprite-potato_generator_2 { background-position: -902px -726px}.sbsprite-potato_generator_3 { background-position: -924px -726px}.sbsprite-lime_large_backpack { background-position: -946px -726px}.sbsprite-bestiary_spiders_den { background-position: -968px -726px}.sbsprite-ruby_polished_drill_engine { background-position: -990px -726px}.sbsprite-yellow_jumbo_backpack { background-position: -1012px -726px}.sbsprite-pet_skin_dolphin_snubnose { background-position: -1034px -726px}.sbsprite-spider_egg_mixin { background-position: 0 -748px}.sbsprite-pet_skin_dragon_pastel { background-position: -22px -748px}.sbsprite-honed_shark_tooth_necklace { background-position: -44px -748px}.sbsprite-bob_omb { background-position: -66px -748px}.sbsprite-dungeon_wizard_crystal { background-position: -88px -748px}.sbsprite-barn_island { background-position: -110px -748px}.sbsprite-weapon_rack { background-position: -132px -748px}.sbsprite-shadow_assassin_crimson { background-position: -154px -748px}.sbsprite-small_talisman_bag { background-position: -176px -748px}.sbsprite-medium_combat_sack { background-position: -198px -748px}.sbsprite-bonzo_statue { background-position: -220px -748px}.sbsprite-zombie_artifact { background-position: -242px -748px}.sbsprite-cheese_hunter { background-position: -264px -748px}.sbsprite-hologram { background-position: -286px -748px}.sbsprite-ultrasequencer { background-position: -308px -748px}.sbsprite-wise_dragon_helmet { background-position: -330px -748px}.sbsprite-cyan_medium_backpack { background-position: -352px -748px}.sbsprite-light_grey_small_backpack { background-position: -374px -748px}.sbsprite-catacombs_pass_5 { background-position: -396px -748px}.sbsprite-catacombs_pass_4 { background-position: -418px -748px}.sbsprite-catacombs_pass_3 { background-position: -440px -748px}.sbsprite-magma_bucket_upgrade { background-position: -462px -748px}.sbsprite-catacombs_pass_2 { background-position: -484px -748px}.sbsprite-coin_redstone { background-position: -506px -748px}.sbsprite-catacombs_pass_1 { background-position: -528px -748px}.sbsprite-hermit_crab_10 { background-position: -550px -748px}.sbsprite-catacombs_pass_0 { background-position: -572px -748px}.sbsprite-hermit_crab_11 { background-position: -594px -748px}.sbsprite-dungeon_stone_mage { background-position: -616px -748px}.sbsprite-gingerbread_personality { background-position: -638px -748px}.sbsprite-titanium_drill_engine { background-position: -660px -748px}.sbsprite-catacombs_pass_9 { background-position: -682px -748px}.sbsprite-fast_travel_dragontail { background-position: -704px -748px}.sbsprite-catacombs_pass_8 { background-position: -726px -748px}.sbsprite-catacombs_pass_7 { background-position: -748px -748px}.sbsprite-reaper_spirit { background-position: -770px -748px}.sbsprite-catacombs_pass_6 { background-position: -792px -748px}.sbsprite-armor_of_the_resistance_helmet { background-position: -814px -748px}.sbsprite-orange_small_backpack { background-position: -836px -748px}.sbsprite-bait_ring { background-position: -858px -748px}.sbsprite-luck_talisman { background-position: -880px -748px}.sbsprite-beach_ball_11 { background-position: -902px -748px}.sbsprite-beach_ball_10 { background-position: -924px -748px}.sbsprite-shark_personality { background-position: -946px -748px}.sbsprite-coal_generator_11 { background-position: -968px -748px}.sbsprite-coal_generator_12 { background-position: -990px -748px}.sbsprite-fourth_master_star { background-position: -1012px -748px}.sbsprite-water_hydra_head { background-position: -1034px -748px}.sbsprite-coal_generator_10 { background-position: 0 -770px}.sbsprite-ice_dinner_table { background-position: -22px -770px}.sbsprite-talisman_enrichment_attack_speed { background-position: -44px -770px}.sbsprite-gemstone_fuel_tank { background-position: -66px -770px}.sbsprite-green_large_backpack { background-position: -88px -770px}.sbsprite-fairy_wings_charm { background-position: -110px -770px}.sbsprite-rare_diamond { background-position: -132px -770px}.sbsprite-bunny { background-position: -154px -770px}.sbsprite-storm_the_fish { background-position: -176px -770px}.sbsprite-penguin_personality { background-position: -198px -770px}.sbsprite-shark_1 { background-position: -220px -770px}.sbsprite-shard_of_the_shredded { background-position: -242px -770px}.sbsprite-shark_2 { background-position: -264px -770px}.sbsprite-sheep_generator_11 { background-position: -286px -770px}.sbsprite-diamonite { background-position: -308px -770px}.sbsprite-prehistoric_egg { background-position: -330px -770px}.sbsprite-shark_3 { background-position: -352px -770px}.sbsprite-sheep_generator_12 { background-position: -374px -770px}.sbsprite-shark_4 { background-position: -396px -770px}.sbsprite-shark_5 { background-position: -418px -770px}.sbsprite-shark_6 { background-position: -440px -770px}.sbsprite-shark_7 { background-position: -462px -770px}.sbsprite-shark_8 { background-position: -484px -770px}.sbsprite-shark_9 { background-position: -506px -770px}.sbsprite-bbq { background-position: -528px -770px}.sbsprite-pet_skin_sheep_white { background-position: -550px -770px}.sbsprite-sheep_generator_10 { background-position: -572px -770px}.sbsprite-rune_spirit { background-position: -594px -770px}.sbsprite-aote_stone { background-position: -616px -770px}.sbsprite-french_bread { background-position: -638px -770px}.sbsprite-ember_helmet { background-position: -660px -770px}.sbsprite-large_bed { background-position: -682px -770px}.sbsprite-builder_bush { background-position: -704px -770px}.sbsprite-talisman_enrichment_ferocity { background-position: -726px -770px}.sbsprite-fire_talisman { background-position: -748px -770px}.sbsprite-purple_candy { background-position: -770px -770px}.sbsprite-spider_talisman { background-position: -792px -770px}.sbsprite-intimidation_artifact { background-position: -814px -770px}.sbsprite-large_candy_sack { background-position: -836px -770px}.sbsprite-present_10 { background-position: -858px -770px}.sbsprite-present_11 { background-position: -880px -770px}.sbsprite-beach_ball_9 { background-position: -902px -770px}.sbsprite-tarantula_generator_10 { background-position: -924px -770px}.sbsprite-beach_ball_8 { background-position: -946px -770px}.sbsprite-gold_sadan_head { background-position: -968px -770px}.sbsprite-tarantula_generator_11 { background-position: -990px -770px}.sbsprite-large_enchanted_foraging_sack { background-position: -1012px -770px}.sbsprite-warrior_dungeon_ability_1 { background-position: -1034px -770px}.sbsprite-beach_ball_5 { background-position: 0 -792px}.sbsprite-beach_ball_4 { background-position: -22px -792px}.sbsprite-beach_ball_7 { background-position: -44px -792px}.sbsprite-cracked_piggy_bank { background-position: -66px -792px}.sbsprite-beach_ball_6 { background-position: -88px -792px}.sbsprite-ice_lolly_11 { background-position: -110px -792px}.sbsprite-ice_lolly_10 { background-position: -132px -792px}.sbsprite-razor_sharp_shark_tooth_necklace { background-position: -154px -792px}.sbsprite-farm_crystal { background-position: -176px -792px}.sbsprite-bank_upgrade_luxurious { background-position: -198px -792px}.sbsprite-large_fishing_sack { background-position: -220px -792px}.sbsprite-lime_small_backpack { background-position: -242px -792px}.sbsprite-portable_wool_weaver { background-position: -264px -792px}.sbsprite-beach_ball_1 { background-position: -286px -792px}.sbsprite-beach_ball_3 { background-position: -308px -792px}.sbsprite-beach_ball_2 { background-position: -330px -792px}.sbsprite-revive_stone_orb { background-position: -352px -792px}.sbsprite-fish_hat { background-position: -374px -792px}.sbsprite-skull_personality { background-position: -396px -792px}.sbsprite-builder_onion { background-position: -418px -792px}.sbsprite-melon_generator_3 { background-position: -440px -792px}.sbsprite-zombie_generator_9 { background-position: -462px -792px}.sbsprite-melon_generator_2 { background-position: -484px -792px}.sbsprite-melon_generator_1 { background-position: -506px -792px}.sbsprite-melon_generator_7 { background-position: -528px -792px}.sbsprite-zombie_generator_5 { background-position: -550px -792px}.sbsprite-melon_generator_6 { background-position: -572px -792px}.sbsprite-zombie_generator_6 { background-position: -594px -792px}.sbsprite-melon_generator_5 { background-position: -616px -792px}.sbsprite-zombie_generator_7 { background-position: -638px -792px}.sbsprite-melon_generator_4 { background-position: -660px -792px}.sbsprite-zombie_generator_8 { background-position: -682px -792px}.sbsprite-zombie_generator_1 { background-position: -704px -792px}.sbsprite-zombie_generator_2 { background-position: -726px -792px}.sbsprite-optical_lens { background-position: -748px -792px}.sbsprite-zombie_generator_3 { background-position: -770px -792px}.sbsprite-zombie_generator_4 { background-position: -792px -792px}.sbsprite-beach_umbrella { background-position: -814px -792px}.sbsprite-diamond_atom { background-position: -836px -792px}.sbsprite-coin_talisman { background-position: -858px -792px}.sbsprite-nether_island { background-position: -880px -792px}.sbsprite-rune_couture { background-position: -902px -792px}.sbsprite-fish_affinity_talisman { background-position: -924px -792px}.sbsprite-wedding_ring_4 { background-position: -946px -792px}.sbsprite-wedding_ring_5 { background-position: -968px -792px}.sbsprite-wedding_ring_6 { background-position: -990px -792px}.sbsprite-wedding_ring_7 { background-position: -1012px -792px}.sbsprite-wedding_ring_8 { background-position: -1034px -792px}.sbsprite-large_enchanted_combat_sack { background-position: 0 -814px}.sbsprite-wedding_ring_9 { background-position: -22px -814px}.sbsprite-rune_clouds { background-position: -44px -814px}.sbsprite-perfect_amber_gem { background-position: -66px -814px}.sbsprite-precursor_gear { background-position: -88px -814px}.sbsprite-wedding_ring_2 { background-position: -110px -814px}.sbsprite-wedding_ring_3 { background-position: -132px -814px}.sbsprite-rune_enchant { background-position: -154px -814px}.sbsprite-god_potion { background-position: -176px -814px}.sbsprite-rune_magical { background-position: -198px -814px}.sbsprite-pet_skin_monkey_golden { background-position: -220px -814px}.sbsprite-spiked_bait { background-position: -242px -814px}.sbsprite-ghost_11 { background-position: -264px -814px}.sbsprite-perfect_jasper_gem { background-position: -286px -814px}.sbsprite-quartz_generator_11 { background-position: -308px -814px}.sbsprite-sandcastle_1 { background-position: -330px -814px}.sbsprite-sandcastle_2 { background-position: -352px -814px}.sbsprite-pet_skin_sheep_pink { background-position: -374px -814px}.sbsprite-premium_flesh { background-position: -396px -814px}.sbsprite-sandcastle_5 { background-position: -418px -814px}.sbsprite-blessed_bait { background-position: -440px -814px}.sbsprite-sandcastle_6 { background-position: -462px -814px}.sbsprite-sandcastle_3 { background-position: -484px -814px}.sbsprite-sandcastle_4 { background-position: -506px -814px}.sbsprite-wise_wither_helmet { background-position: -528px -814px}.sbsprite-sandcastle_9 { background-position: -550px -814px}.sbsprite-quartz_generator_10 { background-position: -572px -814px}.sbsprite-sandcastle_7 { background-position: -594px -814px}.sbsprite-sandcastle_8 { background-position: -616px -814px}.sbsprite-mayor_cole { background-position: -638px -814px}.sbsprite-fifth_master_star { background-position: -660px -814px}.sbsprite-ghost_10 { background-position: -682px -814px}.sbsprite-young_shimmer { background-position: -704px -814px}.sbsprite-minion_chair { background-position: -726px -814px}.sbsprite-pig_mask { background-position: -748px -814px}.sbsprite-hyper_catalyst_upgrade { background-position: -770px -814px}.sbsprite-potion { background-position: -792px -814px}.sbsprite-exceedingly_rare_ender_artifact_upgrader { background-position: -814px -814px}.sbsprite-refined_titanium { background-position: -836px -814px}.sbsprite-sharp_shark_tooth_necklace { background-position: -858px -814px}.sbsprite-wreath { background-position: -880px -814px}.sbsprite-melon_generator_9 { background-position: -902px -814px}.sbsprite-melon_generator_8 { background-position: -924px -814px}.sbsprite-epoch_cake_pink { background-position: -946px -814px}.sbsprite-dungeon_stone_healer { background-position: -968px -814px}.sbsprite-young_baby { background-position: -990px -814px}.sbsprite-presents { background-position: -1012px -814px}.sbsprite-dark_oak_generator_5 { background-position: -1034px -814px}.sbsprite-dark_oak_generator_6 { background-position: 0 -836px}.sbsprite-large_enchanted_fishing_sack { background-position: -22px -836px}.sbsprite-radiant_power_orb { background-position: -44px -836px}.sbsprite-dark_oak_generator_3 { background-position: -66px -836px}.sbsprite-large_husbandry_sack { background-position: -88px -836px}.sbsprite-dark_oak_generator_4 { background-position: -110px -836px}.sbsprite-dark_oak_generator_9 { background-position: -132px -836px}.sbsprite-dark_oak_generator_7 { background-position: -154px -836px}.sbsprite-dark_oak_generator_8 { background-position: -176px -836px}.sbsprite-dark_oak_generator_1 { background-position: -198px -836px}.sbsprite-dark_oak_generator_2 { background-position: -220px -836px}.sbsprite-illusion_glass { background-position: -242px -836px}.sbsprite-iron_chest { background-position: -264px -836px}.sbsprite-festive_zombie_personality { background-position: -286px -836px}.sbsprite-frozen_blaze_helmet { background-position: -308px -836px}.sbsprite-fast_travel_nest { background-position: -330px -836px}.sbsprite-brown_greater_backpack { background-position: -352px -836px}.sbsprite-red_gift { background-position: -374px -836px}.sbsprite-builder_lemon { background-position: -396px -836px}.sbsprite-rune_hot { background-position: -418px -836px}.sbsprite-small_mining_sack { background-position: -440px -836px}.sbsprite-pet_skin_jerry_green_elf { background-position: -462px -836px}.sbsprite-amber_polished_drill_engine { background-position: -484px -836px}.sbsprite-pedestal { background-position: -506px -836px}.sbsprite-red_claw_artifact { background-position: -528px -836px}.sbsprite-zombie_generator_11 { background-position: -550px -836px}.sbsprite-zombie_generator_10 { background-position: -572px -836px}.sbsprite-wither_relic { background-position: -594px -836px}.sbsprite-spider_hat { background-position: -616px -836px}.sbsprite-sludge_juice { background-position: -638px -836px}.sbsprite-precursor_eye { background-position: -660px -836px}.sbsprite-fast_travel_scarleton { background-position: -682px -836px}.sbsprite-connect_four { background-position: -704px -836px}.sbsprite-sloth_3 { background-position: -726px -836px}.sbsprite-sloth_4 { background-position: -748px -836px}.sbsprite-pet_skin_enderman { background-position: -770px -836px}.sbsprite-sloth_1 { background-position: -792px -836px}.sbsprite-sloth_2 { background-position: -814px -836px}.sbsprite-rabbit_generator_9 { background-position: -836px -836px}.sbsprite-builder_chesto_berry { background-position: -858px -836px}.sbsprite-rabbit_generator_4 { background-position: -880px -836px}.sbsprite-sloth_7 { background-position: -902px -836px}.sbsprite-rabbit_generator_3 { background-position: -924px -836px}.sbsprite-sloth_8 { background-position: -946px -836px}.sbsprite-rabbit_generator_2 { background-position: -968px -836px}.sbsprite-sloth_5 { background-position: -990px -836px}.sbsprite-rabbit_generator_1 { background-position: -1012px -836px}.sbsprite-sloth_6 { background-position: -1034px -836px}.sbsprite-rabbit_generator_8 { background-position: 0 -858px}.sbsprite-lantern { background-position: -22px -858px}.sbsprite-rabbit_generator_7 { background-position: -44px -858px}.sbsprite-rabbit_generator_6 { background-position: -66px -858px}.sbsprite-sloth_9 { background-position: -88px -858px}.sbsprite-rabbit_generator_5 { background-position: -110px -858px}.sbsprite-clownfish_8 { background-position: -132px -858px}.sbsprite-clownfish_9 { background-position: -154px -858px}.sbsprite-clownfish_6 { background-position: -176px -858px}.sbsprite-clownfish_7 { background-position: -198px -858px}.sbsprite-clownfish_4 { background-position: -220px -858px}.sbsprite-clownfish_5 { background-position: -242px -858px}.sbsprite-mender_helmet { background-position: -264px -858px}.sbsprite-clownfish_2 { background-position: -286px -858px}.sbsprite-clownfish_3 { background-position: -308px -858px}.sbsprite-enderman_hat { background-position: -330px -858px}.sbsprite-superior_dragon_helmet { background-position: -352px -858px}.sbsprite-clownfish_1 { background-position: -374px -858px}.sbsprite-reset_heart_of_the_mountain { background-position: -396px -858px}.sbsprite-lapis_crystal { background-position: -418px -858px}.sbsprite-purple_jumbo_backpack { background-position: -440px -858px}.sbsprite-purple_large_backpack { background-position: -462px -858px}.sbsprite-dragon_claw { background-position: -484px -858px}.sbsprite-potato_talisman { background-position: -506px -858px}.sbsprite-nether_warts_generator_12 { background-position: -528px -858px}.sbsprite-nether_warts_generator_11 { background-position: -550px -858px}.sbsprite-nether_warts_generator_10 { background-position: -572px -858px}.sbsprite-yellow_medium_backpack { background-position: -594px -858px}.sbsprite-acacia_generator_9 { background-position: -616px -858px}.sbsprite-arachne_crystal { background-position: -638px -858px}.sbsprite-acacia_generator_8 { background-position: -660px -858px}.sbsprite-acacia_generator_7 { background-position: -682px -858px}.sbsprite-helix { background-position: -704px -858px}.sbsprite-acacia_generator_6 { background-position: -726px -858px}.sbsprite-mutant_nether_stalk { background-position: -748px -858px}.sbsprite-acacia_generator_5 { background-position: -770px -858px}.sbsprite-acacia_generator_4 { background-position: -792px -858px}.sbsprite-acacia_generator_3 { background-position: -814px -858px}.sbsprite-acacia_generator_2 { background-position: -836px -858px}.sbsprite-acacia_generator_1 { background-position: -858px -858px}.sbsprite-orange_greater_backpack { background-position: -880px -858px}.sbsprite-boss_collection_professor { background-position: -902px -858px}.sbsprite-soulflow_engine { background-position: -924px -858px}.sbsprite-armor_showcase { background-position: -946px -858px}.sbsprite-gingerbread_2 { background-position: -968px -858px}.sbsprite-gingerbread_1 { background-position: -990px -858px}.sbsprite-gingerbread_6 { background-position: -1012px -858px}.sbsprite-gingerbread_5 { background-position: -1034px -858px}.sbsprite-gingerbread_4 { background-position: 0 -880px}.sbsprite-small_backpack { background-position: -22px -880px}.sbsprite-gingerbread_3 { background-position: -44px -880px}.sbsprite-gingerbread_9 { background-position: -66px -880px}.sbsprite-gingerbread_8 { background-position: -88px -880px}.sbsprite-gingerbread_7 { background-position: -110px -880px}.sbsprite-small_fishing_sack { background-position: -132px -880px}.sbsprite-fast_travel_castle { background-position: -154px -880px}.sbsprite-glacite_jewel { background-position: -176px -880px}.sbsprite-medium_agronomy_sack { background-position: -198px -880px}.sbsprite-mining_fortune { background-position: -220px -880px}.sbsprite-pet_item_spooky_cupcake { background-position: -242px -880px}.sbsprite-red_medium_backpack { background-position: -264px -880px}.sbsprite-third_master_star { background-position: -286px -880px}.sbsprite-pet_skin_phoenix_ice { background-position: -308px -880px}.sbsprite-golem_hat { background-position: -330px -880px}.sbsprite-ghost_personality { background-position: -352px -880px}.sbsprite-epoch_cake_yellow { background-position: -374px -880px}.sbsprite-creeper_generator_11 { background-position: -396px -880px}.sbsprite-creeper_generator_10 { background-position: -418px -880px}.sbsprite-magenta_medium_backpack { background-position: -440px -880px}.sbsprite-pet_skin_elephant_green { background-position: -462px -880px}.sbsprite-soulflow_pile { background-position: -484px -880px}.sbsprite-pumpkin_personality { background-position: -506px -880px}.sbsprite-small_slayer_sack { background-position: -528px -880px}.sbsprite-poisoned_candle { background-position: -550px -880px}.sbsprite-bestiary_crimson_isle { background-position: -572px -880px}.sbsprite-ring_potion_affinity { background-position: -594px -880px}.sbsprite-rock_gemstone { background-position: -616px -880px}.sbsprite-blood_god_crest { background-position: -638px -880px}.sbsprite-judgement_core { background-position: -660px -880px}.sbsprite-rune_tidal { background-position: -682px -880px}.sbsprite-lava_talisman { background-position: -704px -880px}.sbsprite-revived_heart { background-position: -726px -880px}.sbsprite-killer_personality { background-position: -748px -880px}.sbsprite-snow_suit_helmet { background-position: -770px -880px}.sbsprite-blobfish_hat { background-position: -792px -880px}.sbsprite-stool { background-position: -814px -880px}.sbsprite-builder_blue_corn { background-position: -836px -880px}.sbsprite-pulpous_orange_juice { background-position: -858px -880px}.sbsprite-fast_travel_drag { background-position: -880px -880px}.sbsprite-tank_dungeon_ability_2 { background-position: -902px -880px}.sbsprite-tank_dungeon_ability_1 { background-position: -924px -880px}.sbsprite-treasure_talisman { background-position: -946px -880px}.sbsprite-bookcase { background-position: -968px -880px}.sbsprite-skeletor_helmet { background-position: -990px -880px}.sbsprite-unstable_baby { background-position: -1012px -880px}.sbsprite-large_combat_sack { background-position: -1034px -880px}.sbsprite-minos_relic { background-position: 0 -902px}.sbsprite-pet_item_bubblegum { background-position: -22px -902px}.sbsprite-small_xtree { background-position: -44px -902px}.sbsprite-epoch_cake_aqua { background-position: -66px -902px}.sbsprite-wither_blood { background-position: -88px -902px}.sbsprite-egg_hunt { background-position: -110px -902px}.sbsprite-rune_fire_spiral { background-position: -132px -902px}.sbsprite-wither_goggles { background-position: -154px -902px}.sbsprite-egg_stack { background-position: -176px -902px}.sbsprite-mummy_candle { background-position: -198px -902px}.sbsprite-enchanted_book_bundle_big_brain { background-position: -220px -902px}.sbsprite-builder_beetroot { background-position: -242px -902px}.sbsprite-rabbit_generator_11 { background-position: -264px -902px}.sbsprite-rabbit_generator_10 { background-position: -286px -902px}.sbsprite-rabbit_generator_12 { background-position: -308px -902px}.sbsprite-rotten_apple { background-position: -330px -902px}.sbsprite-etherwarp_merger { background-position: -352px -902px}.sbsprite-redstone_generator_11 { background-position: -374px -902px}.sbsprite-redstone_generator_10 { background-position: -396px -902px}.sbsprite-protector_baby { background-position: -418px -902px}.sbsprite-fast_travel_deep { background-position: -440px -902px}.sbsprite-polished_pumpkin { background-position: -462px -902px}.sbsprite-redstone_generator_12 { background-position: -484px -902px}.sbsprite-tic_tac_toe { background-position: -506px -902px}.sbsprite-foraging_2_portal { background-position: -528px -902px}.sbsprite-recombobulator_3000 { background-position: -550px -902px}.sbsprite-sand_generator_7 { background-position: -572px -902px}.sbsprite-sand_generator_8 { background-position: -594px -902px}.sbsprite-sand_generator_9 { background-position: -616px -902px}.sbsprite-scarecrow_personality { background-position: -638px -902px}.sbsprite-pet_skin_sheep_aqua { background-position: -660px -902px}.sbsprite-skull_10 { background-position: -682px -902px}.sbsprite-melon_personality { background-position: -704px -902px}.sbsprite-skull_11 { background-position: -726px -902px}.sbsprite-flawed_amethyst_gem { background-position: -748px -902px}.sbsprite-revive_stone { background-position: -770px -902px}.sbsprite-creeper_generator_9 { background-position: -792px -902px}.sbsprite-creeper_generator_8 { background-position: -814px -902px}.sbsprite-potato_basket { background-position: -836px -902px}.sbsprite-diamond_essence { background-position: -858px -902px}.sbsprite-creeper_generator_7 { background-position: -880px -902px}.sbsprite-creeper_generator_6 { background-position: -902px -902px}.sbsprite-creeper_generator_5 { background-position: -924px -902px}.sbsprite-creeper_generator_4 { background-position: -946px -902px}.sbsprite-creeper_generator_3 { background-position: -968px -902px}.sbsprite-creeper_generator_2 { background-position: -990px -902px}.sbsprite-sand_generator_1 { background-position: -1012px -902px}.sbsprite-creeper_generator_1 { background-position: -1034px -902px}.sbsprite-sand_generator_2 { background-position: 0 -924px}.sbsprite-sand_generator_3 { background-position: -22px -924px}.sbsprite-sand_generator_4 { background-position: -44px -924px}.sbsprite-sand_generator_5 { background-position: -66px -924px}.sbsprite-jerry_box_golden { background-position: -88px -924px}.sbsprite-sand_generator_6 { background-position: -110px -924px}.sbsprite-seal_of_the_family { background-position: -132px -924px}.sbsprite-gemstone_chamber { background-position: -154px -924px}.sbsprite-aqua { background-position: -176px -924px}.sbsprite-ice_hunk { background-position: -198px -924px}.sbsprite-crystal_ball { background-position: -220px -924px}.sbsprite-ice_chair { background-position: -242px -924px}.sbsprite-sandcastle_11 { background-position: -264px -924px}.sbsprite-sandcastle_10 { background-position: -286px -924px}.sbsprite-furnace_plus { background-position: -308px -924px}.sbsprite-pig_generator_12 { background-position: -330px -924px}.sbsprite-pig_generator_11 { background-position: -352px -924px}.sbsprite-pig_generator_10 { background-position: -374px -924px}.sbsprite-nether_artifact { background-position: -396px -924px}.sbsprite-chicken_generator_1 { background-position: -418px -924px}.sbsprite-sniper_helmet { background-position: -440px -924px}.sbsprite-chicken_generator_4 { background-position: -462px -924px}.sbsprite-chicken_generator_5 { background-position: -484px -924px}.sbsprite-heat_core { background-position: -506px -924px}.sbsprite-chicken_generator_2 { background-position: -528px -924px}.sbsprite-wishing_compass { background-position: -550px -924px}.sbsprite-chicken_generator_3 { background-position: -572px -924px}.sbsprite-desk { background-position: -594px -924px}.sbsprite-white_large_backpack { background-position: -616px -924px}.sbsprite-hub_portal { background-position: -638px -924px}.sbsprite-spruce_generator_10 { background-position: -660px -924px}.sbsprite-spruce_generator_11 { background-position: -682px -924px}.sbsprite-chicken_generator_8 { background-position: -704px -924px}.sbsprite-mithril_generator_9 { background-position: -726px -924px}.sbsprite-scarf_thesis { background-position: -748px -924px}.sbsprite-chicken_generator_9 { background-position: -770px -924px}.sbsprite-mithril_generator_8 { background-position: -792px -924px}.sbsprite-fast_travel_da { background-position: -814px -924px}.sbsprite-chicken_generator_6 { background-position: -836px -924px}.sbsprite-mithril_generator_7 { background-position: -858px -924px}.sbsprite-zombie_ring { background-position: -880px -924px}.sbsprite-chicken_generator_7 { background-position: -902px -924px}.sbsprite-mithril_generator_6 { background-position: -924px -924px}.sbsprite-wood_chest { background-position: -946px -924px}.sbsprite-glowstone_generator_8 { background-position: -968px -924px}.sbsprite-mithril_generator_1 { background-position: -990px -924px}.sbsprite-pink_bunny_12 { background-position: -1012px -924px}.sbsprite-purple_medium_backpack { background-position: -1034px -924px}.sbsprite-glowstone_generator_7 { background-position: 0 -946px}.sbsprite-pink_bunny_11 { background-position: -22px -946px}.sbsprite-pink_bunny_10 { background-position: -44px -946px}.sbsprite-glowstone_generator_9 { background-position: -66px -946px}.sbsprite-glowstone_generator_4 { background-position: -88px -946px}.sbsprite-mithril_generator_5 { background-position: -110px -946px}.sbsprite-glowstone_generator_3 { background-position: -132px -946px}.sbsprite-mithril_generator_4 { background-position: -154px -946px}.sbsprite-glowstone_generator_6 { background-position: -176px -946px}.sbsprite-mithril_generator_3 { background-position: -198px -946px}.sbsprite-glowstone_generator_5 { background-position: -220px -946px}.sbsprite-mithril_generator_2 { background-position: -242px -946px}.sbsprite-very_official_yellow_rock { background-position: -264px -946px}.sbsprite-bat_person_talisman { background-position: -286px -946px}.sbsprite-cyan_large_backpack { background-position: -308px -946px}.sbsprite-fairy_soul { background-position: -330px -946px}.sbsprite-ghost_8 { background-position: -352px -946px}.sbsprite-ghost_9 { background-position: -374px -946px}.sbsprite-power_talisman { background-position: -396px -946px}.sbsprite-ghost_4 { background-position: -418px -946px}.sbsprite-decent_coffee { background-position: -440px -946px}.sbsprite-ghost_5 { background-position: -462px -946px}.sbsprite-ember_fragment { background-position: -484px -946px}.sbsprite-ghost_6 { background-position: -506px -946px}.sbsprite-ghost_7 { background-position: -528px -946px}.sbsprite-dull_shark_tooth_necklace { background-position: -550px -946px}.sbsprite-ghost_1 { background-position: -572px -946px}.sbsprite-ghost_2 { background-position: -594px -946px}.sbsprite-ghost_3 { background-position: -616px -946px}.sbsprite-gold_gift { background-position: -638px -946px}.sbsprite-tank_wither_helmet { background-position: -660px -946px}.sbsprite-spider_ring { background-position: -682px -946px}.sbsprite-santa_10 { background-position: -704px -946px}.sbsprite-santa_11 { background-position: -726px -946px}.sbsprite-yellow_greater_backpack { background-position: -748px -946px}.sbsprite-sapphire_crystal { background-position: -770px -946px}.sbsprite-mayor_foxy { background-position: -792px -946px}.sbsprite-starred_shadow_assassin_helmet { background-position: -814px -946px}.sbsprite-god_potion_2 { background-position: -836px -946px}.sbsprite-goblin_helmet { background-position: -858px -946px}.sbsprite-diamond_generator_5 { background-position: -880px -946px}.sbsprite-lesser_orb_of_healing { background-position: -902px -946px}.sbsprite-diamond_generator_6 { background-position: -924px -946px}.sbsprite-diamond_generator_3 { background-position: -946px -946px}.sbsprite-pet_skin_jerry_red_elf { background-position: -968px -946px}.sbsprite-diamond_generator_4 { background-position: -990px -946px}.sbsprite-lady_bug_10 { background-position: -1012px -946px}.sbsprite-diamond_generator_1 { background-position: -1034px -946px}.sbsprite-star_decorations { background-position: 0 -968px}.sbsprite-diamond_generator_2 { background-position: -22px -968px}.sbsprite-bingo_artifact { background-position: -44px -968px}.sbsprite-diamond_generator_9 { background-position: -66px -968px}.sbsprite-lady_bug_11 { background-position: -88px -968px}.sbsprite-diamond_generator_7 { background-position: -110px -968px}.sbsprite-diamond_generator_8 { background-position: -132px -968px}.sbsprite-heart_of_the_mountain { background-position: -154px -968px}.sbsprite-glowstone_generator_2 { background-position: -176px -968px}.sbsprite-glowstone_generator_1 { background-position: -198px -968px}.sbsprite-pink_donut_personality { background-position: -220px -968px}.sbsprite-artifact_of_space { background-position: -242px -968px}.sbsprite-lesser_soulflow_engine { background-position: -264px -968px}.sbsprite-mithril_crystal { background-position: -286px -968px}.sbsprite-young_fragment { background-position: -308px -968px}.sbsprite-master_catacombs_pass_10 { background-position: -330px -968px}.sbsprite-flying_bats { background-position: -352px -968px}.sbsprite-light_blue_medium_backpack { background-position: -374px -968px}.sbsprite-fast_travel_hub { background-position: -396px -968px}.sbsprite-pumpkin_generator_2 { background-position: -418px -968px}.sbsprite-pumpkin_generator_1 { background-position: -440px -968px}.sbsprite-pumpkin_generator_4 { background-position: -462px -968px}.sbsprite-end_helmet { background-position: -484px -968px}.sbsprite-pumpkin_generator_3 { background-position: -506px -968px}.sbsprite-pumpkin_generator_6 { background-position: -528px -968px}.sbsprite-titanium_talisman { background-position: -550px -968px}.sbsprite-pumpkin_generator_5 { background-position: -572px -968px}.sbsprite-reaper_gem { background-position: -594px -968px}.sbsprite-rune_zap { background-position: -616px -968px}.sbsprite-pumpkin_generator_8 { background-position: -638px -968px}.sbsprite-pumpkin_generator_7 { background-position: -660px -968px}.sbsprite-pumpkin_generator_9 { background-position: -682px -968px}.sbsprite-crooked_artifact { background-position: -704px -968px}.sbsprite-haste_ring { background-position: -726px -968px}.sbsprite-soulflow_battery { background-position: -748px -968px}.sbsprite-medium_mining_sack { background-position: -770px -968px}.sbsprite-skull_1 { background-position: -792px -968px}.sbsprite-coffin { background-position: -814px -968px}.sbsprite-chest_shelves { background-position: -836px -968px}.sbsprite-power_ring { background-position: -858px -968px}.sbsprite-white_medium_backpack { background-position: -880px -968px}.sbsprite-divan_fragment { background-position: -902px -968px}.sbsprite-skull_8 { background-position: -924px -968px}.sbsprite-gold_essence { background-position: -946px -968px}.sbsprite-skull_9 { background-position: -968px -968px}.sbsprite-skull_6 { background-position: -990px -968px}.sbsprite-skull_7 { background-position: -1012px -968px}.sbsprite-skull_4 { background-position: -1034px -968px}.sbsprite-skull_5 { background-position: 0 -990px}.sbsprite-skull_2 { background-position: -22px -990px}.sbsprite-skull_3 { background-position: -44px -990px}.sbsprite-black_jumbo_backpack { background-position: -66px -990px}.sbsprite-fast_travel_mines { background-position: -88px -990px}.sbsprite-skull_vase { background-position: -110px -990px}.sbsprite-fishing_generator_8 { background-position: -132px -990px}.sbsprite-fishing_generator_7 { background-position: -154px -990px}.sbsprite-fishing_generator_6 { background-position: -176px -990px}.sbsprite-fishing_generator_5 { background-position: -198px -990px}.sbsprite-fishing_generator_4 { background-position: -220px -990px}.sbsprite-lime_jumbo_backpack { background-position: -242px -990px}.sbsprite-fishing_generator_3 { background-position: -264px -990px}.sbsprite-fishing_generator_2 { background-position: -286px -990px}.sbsprite-fishing_generator_1 { background-position: -308px -990px}.sbsprite-fishing_generator_9 { background-position: -330px -990px}.sbsprite-yellow_large_backpack { background-position: -352px -990px}.sbsprite-amber_crystal { background-position: -374px -990px}.sbsprite-suspicious_vial { background-position: -396px -990px}.sbsprite-campfire { background-position: -418px -990px}.sbsprite-snow_generator_4 { background-position: -440px -990px}.sbsprite-snow_generator_5 { background-position: -462px -990px}.sbsprite-ring_of_space { background-position: -484px -990px}.sbsprite-snow_generator_6 { background-position: -506px -990px}.sbsprite-talisman_enrichment_walk_speed { background-position: -528px -990px}.sbsprite-snow_generator_7 { background-position: -550px -990px}.sbsprite-snow_generator_1 { background-position: -572px -990px}.sbsprite-snow_generator_2 { background-position: -594px -990px}.sbsprite-snow_generator_3 { background-position: -616px -990px}.sbsprite-lime_medium_backpack { background-position: -638px -990px}.sbsprite-end_stone_1 { background-position: -660px -990px}.sbsprite-strong_fragment { background-position: -682px -990px}.sbsprite-small_foraging_sack { background-position: -704px -990px}.sbsprite-synthetic_heart { background-position: -726px -990px}.sbsprite-end_stone_4 { background-position: -748px -990px}.sbsprite-diamond_sadan_head { background-position: -770px -990px}.sbsprite-end_stone_5 { background-position: -792px -990px}.sbsprite-end_stone_2 { background-position: -814px -990px}.sbsprite-end_stone_3 { background-position: -836px -990px}.sbsprite-diamond_bonzo_head { background-position: -858px -990px}.sbsprite-end_stone_8 { background-position: -880px -990px}.sbsprite-end_stone_9 { background-position: -902px -990px}.sbsprite-end_stone_6 { background-position: -924px -990px}.sbsprite-end_stone_7 { background-position: -946px -990px}.sbsprite-snow_generator_8 { background-position: -968px -990px}.sbsprite-snow_generator_9 { background-position: -990px -990px}.sbsprite-ender_stone_generator_4 { background-position: -1012px -990px}.sbsprite-epoch_cake_blue { background-position: -1034px -990px}.sbsprite-sand_generator_10 { background-position: 0 -1012px}.sbsprite-ender_stone_generator_3 { background-position: -22px -1012px}.sbsprite-sand_generator_11 { background-position: -44px -1012px}.sbsprite-ender_stone_generator_2 { background-position: -66px -1012px}.sbsprite-ender_stone_generator_1 { background-position: -88px -1012px}.sbsprite-pet_skin_sheep_neon_yellow { background-position: -110px -1012px}.sbsprite-fast_travel_spider { background-position: -132px -1012px}.sbsprite-pet_skin_sheep_blue { background-position: -154px -1012px}.sbsprite-epoch_cake_black { background-position: -176px -1012px}.sbsprite-wise_baby { background-position: -198px -1012px}.sbsprite-chronomatron { background-position: -220px -1012px}.sbsprite-scarf_grimoire { background-position: -242px -1012px}.sbsprite-bestiary_hub { background-position: -264px -1012px}.sbsprite-ender_stone_generator_9 { background-position: -286px -1012px}.sbsprite-ender_stone_generator_8 { background-position: -308px -1012px}.sbsprite-ender_stone_generator_7 { background-position: -330px -1012px}.sbsprite-ender_stone_generator_6 { background-position: -352px -1012px}.sbsprite-ender_stone_generator_5 { background-position: -374px -1012px}.sbsprite-small_gemstone_sack { background-position: -396px -1012px}.sbsprite-flawless_ruby_gem { background-position: -418px -1012px}.sbsprite-gold_necron_head { background-position: -440px -1012px}.sbsprite-small_husbandry_sack { background-position: -462px -1012px}.sbsprite-reaper_orb { background-position: -484px -1012px}.sbsprite-blaze_helmet { background-position: -506px -1012px}.sbsprite-bee_personality { background-position: -528px -1012px}.sbsprite-fishing { background-position: -550px -1012px}.sbsprite-titanium_ring { background-position: -572px -1012px}.sbsprite-lime { background-position: -594px -1012px}.sbsprite-feather_talisman { background-position: -616px -1012px}.sbsprite-rough_jasper_gem { background-position: -638px -1012px}.sbsprite-goblin_omelette_spicy { background-position: -660px -1012px}.sbsprite-gold_generator_11 { background-position: -682px -1012px}.sbsprite-gold_generator_10 { background-position: -704px -1012px}.sbsprite-gold_generator_12 { background-position: -726px -1012px}.sbpet-sheep_green { background-position: 0 0}.sbpet-sheep_yellow { background-position: -20px 0}.sbpet-bal { background-position: -40px 0}.sbpet-grandma_wolf { background-position: -60px 0}.sbpet-sheep_orange { background-position: -80px 0}.sbpet-sheep_red { background-position: -100px 0}.sbpet-bat { background-position: -120px 0}.sbpet-elephant_red { background-position: -140px 0}.sbpet-rabbit { background-position: -160px 0}.sbpet-megalodon_baby { background-position: -180px 0}.sbpet-silverfish { background-position: -200px 0}.sbpet-ghoul { background-position: -220px 0}.sbpet-pigman { background-position: 0 -22px}.sbpet-elephant_orange { background-position: -20px -22px}.sbpet-jerry { background-position: -40px -22px}.sbpet-sheep_neon_yellow { background-position: -60px -22px}.sbpet-rat { background-position: -80px -22px}.sbpet-tiger { background-position: -100px -22px}.sbpet-lion { background-position: -120px -22px}.sbpet-horse { background-position: -140px -22px}.sbpet-sheep_neon_green { background-position: -160px -22px}.sbpet-giraffe { background-position: -180px -22px}.sbpet-black_cat_ivory { background-position: -200px -22px}.sbpet-golden_dragon { background-position: -220px -22px}.sbpet-rock_derp { background-position: 0 -44px}.sbpet-parrot { background-position: -20px -44px}.sbpet-sheep_blue { background-position: -40px -44px}.sbpet-monkey_golden { background-position: -60px -44px}.sbpet-jellyfish { background-position: -80px -44px}.sbpet-horse_zombie { background-position: -100px -44px}.sbpet-sheep_purple { background-position: -120px -44px}.sbpet-elephant_purple { background-position: -140px -44px}.sbpet-endermite_radiant { background-position: -160px -44px}.sbpet-rock { background-position: -180px -44px}.sbpet-default { background-position: -200px -44px}.sbpet-blaze { background-position: -220px -44px}.sbpet-endermite { background-position: 0 -66px}.sbpet-megalodon_bullhead { background-position: -20px -66px}.sbpet-hound_beagle { background-position: -40px -66px}.sbpet-zombie { background-position: -60px -66px}.sbpet-guardian { background-position: -80px -66px}.sbpet-scatha { background-position: -100px -66px}.sbpet-wolf { background-position: -120px -66px}.sbpet-rabbit_aquamarine { background-position: -140px -66px}.sbpet-spirit { background-position: -160px -66px}.sbpet-hound { background-position: -180px -66px}.sbpet-dragon_neon_purple { background-position: -200px -66px}.sbpet-tiger_twilight { background-position: -220px -66px}.sbpet-sheep_light_green { background-position: 0 -88px}.sbpet-monkey_gorilla { background-position: -20px -88px}.sbpet-spider { background-position: -40px -88px}.sbpet-mithril_golem { background-position: -60px -88px}.sbpet-dolphin_snubnose { background-position: -80px -88px}.sbpet-snowman { background-position: -100px -88px}.sbpet-bee { background-position: -120px -88px}.sbpet-monkey { background-position: -140px -88px}.sbpet-jerry_red_elf { background-position: -160px -88px}.sbpet-elephant_pink { background-position: -180px -88px}.sbpet-sheep_brown { background-position: -200px -88px}.sbpet-magma_cube { background-position: -220px -88px}.sbpet-pig { background-position: 0 -110px}.sbpet-blue_whale { background-position: -20px -110px}.sbpet-skeleton { background-position: -40px -110px}.sbpet-phoenix_ice { background-position: -60px -110px}.sbpet-ammonite { background-position: -80px -110px}.sbpet-elephant_green { background-position: -100px -110px}.sbpet-armadillo { background-position: -120px -110px}.sbpet-dolphin { background-position: -140px -110px}.sbpet-turtle { background-position: -160px -110px}.sbpet-dragon_neon_red { background-position: -180px -110px}.sbpet-tiger_saber_tooth { background-position: -200px -110px}.sbpet-wither_skeleton { background-position: -220px -110px}.sbpet-parrot_blue_macaw { background-position: 0 -132px}.sbpet-ocelot { background-position: -20px -132px}.sbpet-sheep_light_gray { background-position: -40px -132px}.sbpet-elephant_blue { background-position: -60px -132px}.sbpet-chicken_baby_chick { background-position: -80px -132px}.sbpet-rock_thinking { background-position: -100px -132px}.sbpet-enderman_slayer { background-position: -120px -132px}.sbpet-ender_dragon { background-position: -140px -132px}.sbpet-rabbit_rose { background-position: -160px -132px}.sbpet-sheep_white { background-position: -180px -132px}.sbpet-silverfish_fossilized { background-position: -200px -132px}.sbpet-squid { background-position: -220px -132px}.sbpet-sheep_light_blue { background-position: 0 -154px}.sbpet-elephant { background-position: -20px -154px}.sbpet-golden_dragon_egg { background-position: -40px -154px}.sbpet-enderman { background-position: -60px -154px}.sbpet-chicken { background-position: -80px -154px}.sbpet-parrot_gold_macaw { background-position: -100px -154px}.sbpet-sheep_gray { background-position: -120px -154px}.sbpet-rock_cool { background-position: -140px -154px}.sbpet-rock_laugh { background-position: -160px -154px}.sbpet-sheep_black { background-position: -180px -154px}.sbpet-sheep_neon_blue { background-position: -200px -154px}.sbpet-rock_embarrassed { background-position: -220px -154px}.sbpet-dragon_neon_blue { background-position: 0 -176px}.sbpet-sheep { background-position: -20px -176px}.sbpet-baby_yeti { background-position: -40px -176px}.sbpet-sheep_aqua { background-position: -60px -176px}.sbpet-sheep_pink { background-position: -80px -176px}.sbpet-elephant_monochrome { background-position: -100px -176px}.sbpet-wolf_henzo_doggo { background-position: -120px -176px}.sbpet-squid_glow { background-position: -140px -176px}.sbpet-flying_fish { background-position: -160px -176px}.sbpet-griffin { background-position: -180px -176px}.sbpet-jerry_green_elf { background-position: -200px -176px}.sbpet-dragon_pastel { background-position: -220px -176px}.sbpet-sheep_neon_red { background-position: 0 -198px}.sbpet-sheep_magenta { background-position: -20px -198px}.sbpet-skeleton_horse { background-position: -40px -198px}.sbpet-megalodon { background-position: -60px -198px}.sbpet-lion_lioness { background-position: -80px -198px}.sbpet-tarantula { background-position: -100px -198px}.sbpet-yeti_grown_up { background-position: -120px -198px}.sbpet-phoenix { background-position: -140px -198px}.sbpet-golem { background-position: -160px -198px}.sbpet-black_cat { background-position: -180px -198px}.sbpet-whale_orca { background-position: -200px -198px}.sbpet-rock_smile { background-position: -220px -198px}.sbpet-wither { background-position: 0 -220px}.sbpet-black_cat_onyx { background-position: -20px -220px}.sbspray-AngryTurkey { background-position: 0 0}.sbspray-AnotherDimension { background-position: -128px 0}.sbspray-BlueArrowE { background-position: -256px 0}.sbspray-BlueArrowN { background-position: -384px 0}.sbspray-BlueArrowNE { background-position: -512px 0}.sbspray-BlueArrowNW { background-position: -640px 0}.sbspray-BlueArrowS { background-position: -768px 0}.sbspray-BlueArrowSE { background-position: -896px 0}.sbspray-BlueArrowSW { background-position: -1024px 0}.sbspray-BlueArrowW { background-position: -1152px 0}.sbspray-Bonzo { background-position: 0 -128px}.sbspray-Boom { background-position: -128px -128px}.sbspray-BunnyGG { background-position: -256px -128px}.sbspray-ChestGlow { background-position: -384px -128px}.sbspray-Chill { background-position: -512px -128px}.sbspray-Chimney { background-position: -640px -128px}.sbspray-ChocolateFeast { background-position: -768px -128px}.sbspray-ChristmasTree { background-position: -896px -128px}.sbspray-Coconut { background-position: -1024px -128px}.sbspray-Creeper { background-position: -1152px -128px}.sbspray-EasterBasket { background-position: 0 -256px}.sbspray-EasterCreeper { background-position: -128px -256px}.sbspray-EasterEggs { background-position: -256px -256px}.sbspray-Eek { background-position: -384px -256px}.sbspray-EggHunt { background-position: -512px -256px}.sbspray-EggSurprise { background-position: -640px -256px}.sbspray-Faboolous { background-position: -768px -256px}.sbspray-FarmingArrowE { background-position: -896px -256px}.sbspray-FarmingArrowN { background-position: -1024px -256px}.sbspray-FarmingArrowS { background-position: -1152px -256px}.sbspray-FarmingArrowW { background-position: 0 -384px}.sbspray-FoundU { background-position: -128px -384px}.sbspray-Garlic { background-position: -256px -384px}.sbspray-GenericArmor { background-position: -384px -384px}.sbspray-GenericBooks { background-position: -512px -384px}.sbspray-GenericFishing { background-position: -640px -384px}.sbspray-GenericMob { background-position: -768px -384px}.sbspray-GenericOres { background-position: -896px -384px}.sbspray-GenericPotions { background-position: -1024px -384px}.sbspray-GenericWeapons { background-position: -1152px -384px}.sbspray-GoldenEgg { background-position: 0 -512px}.sbspray-Heart { background-position: -128px -512px}.sbspray-Hypixel { background-position: -256px -512px}.sbspray-HypixelDark { background-position: -384px -512px}.sbspray-IceCream { background-position: -512px -512px}.sbspray-Kite { background-position: -640px -512px}.sbspray-LetUsIn { background-position: -768px -512px}.sbspray-Lifebelt { background-position: -896px -512px}.sbspray-MinionAnimals { background-position: -1024px -512px}.sbspray-MinionFarming { background-position: -1152px -512px}.sbspray-MinionForaging { background-position: 0 -640px}.sbspray-MinionMining { background-position: -128px -640px}.sbspray-MinionMisc { background-position: -256px -640px}.sbspray-MinionMonsters { background-position: -384px -640px}.sbspray-OnFire { background-position: -512px -640px}.sbspray-Porkchop { background-position: -640px -640px}.sbspray-PortalArrowE { background-position: -768px -640px}.sbspray-PortalArrowN { background-position: -896px -640px}.sbspray-PortalArrowS { background-position: -1024px -640px}.sbspray-PortalArrowW { background-position: -1152px -640px}.sbspray-Presents { background-position: 0 -768px}.sbspray-Puffer { background-position: -128px -768px}.sbspray-PuppySurprise { background-position: -256px -768px}.sbspray-RabbitCostume { background-position: -384px -768px}.sbspray-RedArrowE { background-position: -512px -768px}.sbspray-RedArrowN { background-position: -640px -768px}.sbspray-RedArrowNE { background-position: -768px -768px}.sbspray-RedArrowNW { background-position: -896px -768px}.sbspray-RedArrowS { background-position: -1024px -768px}.sbspray-RedArrowSE { background-position: -1152px -768px}.sbspray-RedArrowSW { background-position: 0 -896px}.sbspray-RedArrowW { background-position: -128px -896px}.sbspray-SandCastleH { background-position: -256px -896px}.sbspray-Sandcastle { background-position: -384px -896px}.sbspray-SantaJerry { background-position: -512px -896px}.sbspray-SantaSlips { background-position: -640px -896px}.sbspray-Sign { background-position: -768px -896px}.sbspray-SkyBlockChristmas { background-position: -896px -896px}.sbspray-SniperSnowball { background-position: -1024px -896px}.sbspray-Snowball { background-position: -1152px -896px}.sbspray-StorageArrowE { background-position: 0 -1024px}.sbspray-StorageArrowN { background-position: -128px -1024px}.sbspray-StorageArrowS { background-position: -256px -1024px}.sbspray-StorageArrowW { background-position: -384px -1024px}.sbspray-Surfing { background-position: -512px -1024px}.sbspray-TheWrongEggs { background-position: -640px -1024px}.sbspray-Trap { background-position: -768px -1024px}.sbspray-TrickOrTreat { background-position: -896px -1024px}.sbspray-UndeadJerry { background-position: -1024px -1024px}.sbspray-Volleyball { background-position: -1152px -1024px}.sbspray-Watcher { background-position: 0 -1152px}.sbspray-Whoosh { background-position: -128px -1152px}.sbspray-WitchPlease { background-position: -256px -1152px}.sbspray-Wreath { background-position: -384px -1152px}.sbspray-YellowArrowE { background-position: -512px -1152px}.sbspray-YellowArrowN { background-position: -640px -1152px}.sbspray-YellowArrowNE { background-position: -768px -1152px}.sbspray-YellowArrowNW { background-position: -896px -1152px}.sbspray-YellowArrowS { background-position: -1024px -1152px}.sbspray-YellowArrowSE { background-position: -1152px -1152px}.sbspray-YellowArrowSW { background-position: -1280px 0}.sbspray-YellowArrowW { background-position: -1280px -128px}.mcsprite-acacia_boat { background-position: 0 0}.mcsprite-acacia_button { background-position: -32px 0}.mcsprite-acacia_door { background-position: -64px 0}.mcsprite-acacia_fence { background-position: -96px 0}.mcsprite-acacia_fence_gate { background-position: -128px 0}.mcsprite-acacia_leaves { background-position: -160px 0}.mcsprite-acacia_log { background-position: -192px 0}.mcsprite-acacia_planks { background-position: -224px 0}.mcsprite-acacia_pressure_plate { background-position: -256px 0}.mcsprite-acacia_sapling { background-position: -288px 0}.mcsprite-acacia_sign { background-position: -320px 0}.mcsprite-acacia_slab { background-position: -352px 0}.mcsprite-acacia_stairs { background-position: -384px 0}.mcsprite-acacia_trapdoor { background-position: -416px 0}.mcsprite-acacia_wood { background-position: -448px 0}.mcsprite-acacia_wood_button { background-position: -480px 0}.mcsprite-acacia_wood_door { background-position: -512px 0}.mcsprite-acacia_wood_fence { background-position: -544px 0}.mcsprite-acacia_wood_fence_gate { background-position: -576px 0}.mcsprite-acacia_wood_planks { background-position: -608px 0}.mcsprite-acacia_wood_pressure_plate { background-position: -640px 0}.mcsprite-acacia_wood_sign { background-position: -672px 0}.mcsprite-acacia_wood_slab { background-position: -704px 0}.mcsprite-acacia_wood_stairs { background-position: -736px 0}.mcsprite-acacia_wood_trapdoor { background-position: -768px 0}.mcsprite-activator_rail { background-position: -800px 0}.mcsprite-adult_carrots { background-position: -832px 0}.mcsprite-adult_nether_warts { background-position: -864px 0}.mcsprite-adult_potatoes { background-position: -896px 0}.mcsprite-adult_wheat_crops { background-position: -928px 0}.mcsprite-air { background-position: -960px 0}.mcsprite-allium { background-position: -992px 0}.mcsprite-amethyst_cluster { background-position: -1024px 0}.mcsprite-amethyst_shard { background-position: -1056px 0}.mcsprite-ancient_debris { background-position: -1088px 0}.mcsprite-andesite { background-position: -1120px 0}.mcsprite-andesite_slab { background-position: -1152px 0}.mcsprite-andesite_stairs { background-position: -1184px 0}.mcsprite-andesite_wall { background-position: -1216px 0}.mcsprite-anvil { background-position: -1248px 0}.mcsprite-apple { background-position: 0 -32px}.mcsprite-armor_stand { background-position: -32px -32px}.mcsprite-arrow { background-position: -64px -32px}.mcsprite-arrow_loaded_crossbow { background-position: -96px -32px}.mcsprite-arrow_of_decay { background-position: -128px -32px}.mcsprite-arrow_of_fire_resistance { background-position: -160px -32px}.mcsprite-arrow_of_harming { background-position: -192px -32px}.mcsprite-arrow_of_healing { background-position: -224px -32px}.mcsprite-arrow_of_invisibility { background-position: -256px -32px}.mcsprite-arrow_of_leaping { background-position: -288px -32px}.mcsprite-arrow_of_luck { background-position: -320px -32px}.mcsprite-arrow_of_night_vision { background-position: -352px -32px}.mcsprite-arrow_of_poison { background-position: -384px -32px}.mcsprite-arrow_of_regeneration { background-position: -416px -32px}.mcsprite-arrow_of_slow_falling { background-position: -448px -32px}.mcsprite-arrow_of_slowness { background-position: -480px -32px}.mcsprite-arrow_of_splashing { background-position: -512px -32px}.mcsprite-arrow_of_strength { background-position: -544px -32px}.mcsprite-arrow_of_swiftness { background-position: -576px -32px}.mcsprite-arrow_of_the_turtle_master { background-position: -608px -32px}.mcsprite-arrow_of_water_breathing { background-position: -640px -32px}.mcsprite-arrow_of_weakness { background-position: -672px -32px}.mcsprite-awkward_lingering_potion { background-position: -704px -32px}.mcsprite-awkward_potion { background-position: -736px -32px}.mcsprite-awkward_splash_potion { background-position: -768px -32px}.mcsprite-axolotl_spawn_egg { background-position: -800px -32px}.mcsprite-azalea { background-position: -832px -32px}.mcsprite-azalea_leaves { background-position: -864px -32px}.mcsprite-azure_bluet { background-position: -896px -32px}.mcsprite-baked_potato { background-position: -928px -32px}.mcsprite-bamboo { background-position: -960px -32px}.mcsprite-banner { background-position: -992px -32px}.mcsprite-barrel { background-position: -1024px -32px}.mcsprite-barrier { background-position: -1056px -32px}.mcsprite-basalt { background-position: -1088px -32px}.mcsprite-bat_spawn_egg { background-position: -1120px -32px}.mcsprite-beacon { background-position: -1152px -32px}.mcsprite-bedrock { background-position: -1184px -32px}.mcsprite-bee_nest { background-position: -1216px -32px}.mcsprite-bee_spawn_egg { background-position: -1248px -32px}.mcsprite-beehive { background-position: 0 -64px}.mcsprite-beetroot { background-position: -32px -64px}.mcsprite-beetroot_seeds { background-position: -64px -64px}.mcsprite-beetroot_soup { background-position: -96px -64px}.mcsprite-beetroots { background-position: -128px -64px}.mcsprite-bell { background-position: -160px -64px}.mcsprite-big_dripleaf { background-position: -192px -64px}.mcsprite-birch_boat { background-position: -224px -64px}.mcsprite-birch_button { background-position: -256px -64px}.mcsprite-birch_door { background-position: -288px -64px}.mcsprite-birch_fence { background-position: -320px -64px}.mcsprite-birch_fence_gate { background-position: -352px -64px}.mcsprite-birch_leaves { background-position: -384px -64px}.mcsprite-birch_log { background-position: -416px -64px}.mcsprite-birch_planks { background-position: -448px -64px}.mcsprite-birch_pressure_plate { background-position: -480px -64px}.mcsprite-birch_sapling { background-position: -512px -64px}.mcsprite-birch_sign { background-position: -544px -64px}.mcsprite-birch_slab { background-position: -576px -64px}.mcsprite-birch_stairs { background-position: -608px -64px}.mcsprite-birch_trapdoor { background-position: -640px -64px}.mcsprite-birch_wood { background-position: -672px -64px}.mcsprite-birch_wood_button { background-position: -704px -64px}.mcsprite-birch_wood_door { background-position: -736px -64px}.mcsprite-birch_wood_fence { background-position: -768px -64px}.mcsprite-birch_wood_fence_gate { background-position: -800px -64px}.mcsprite-birch_wood_planks { background-position: -832px -64px}.mcsprite-birch_wood_pressure_plate { background-position: -864px -64px}.mcsprite-birch_wood_sign { background-position: -896px -64px}.mcsprite-birch_wood_slab { background-position: -928px -64px}.mcsprite-birch_wood_stairs { background-position: -960px -64px}.mcsprite-birch_wood_trapdoor { background-position: -992px -64px}.mcsprite-black_banner { background-position: -1024px -64px}.mcsprite-black_bed { background-position: -1056px -64px}.mcsprite-black_bed_lce { background-position: -1088px -64px}.mcsprite-black_candle { background-position: -1120px -64px}.mcsprite-black_carpet { background-position: -1152px -64px}.mcsprite-black_concrete { background-position: -1184px -64px}.mcsprite-black_concrete_powder { background-position: -1216px -64px}.mcsprite-black_dye { background-position: -1248px -64px}.mcsprite-black_firework_star { background-position: 0 -96px}.mcsprite-black_glazed_terracotta { background-position: -32px -96px}.mcsprite-black_shield { background-position: -64px -96px}.mcsprite-black_shulker_box { background-position: -96px -96px}.mcsprite-black_stained_glass { background-position: -128px -96px}.mcsprite-black_stained_glass_pane { background-position: -160px -96px}.mcsprite-black_terracotta { background-position: -192px -96px}.mcsprite-black_wool { background-position: -224px -96px}.mcsprite-blackstone { background-position: -256px -96px}.mcsprite-blackstone_slab { background-position: -288px -96px}.mcsprite-blackstone_stairs { background-position: -320px -96px}.mcsprite-blackstone_wall { background-position: -352px -96px}.mcsprite-blast_furnace { background-position: -384px -96px}.mcsprite-blaze_powder { background-position: -416px -96px}.mcsprite-blaze_rod { background-position: -448px -96px}.mcsprite-blaze_spawn_egg { background-position: -480px -96px}.mcsprite-block_of_amethyst { background-position: -512px -96px}.mcsprite-block_of_coal { background-position: -544px -96px}.mcsprite-block_of_copper { background-position: -576px -96px}.mcsprite-block_of_diamond { background-position: -608px -96px}.mcsprite-block_of_emerald { background-position: -640px -96px}.mcsprite-block_of_gold { background-position: -672px -96px}.mcsprite-block_of_iron { background-position: -704px -96px}.mcsprite-block_of_lapis_lazuli { background-position: -736px -96px}.mcsprite-block_of_netherite { background-position: -768px -96px}.mcsprite-block_of_quartz { background-position: -800px -96px}.mcsprite-block_of_raw_copper { background-position: -832px -96px}.mcsprite-block_of_raw_gold { background-position: -864px -96px}.mcsprite-block_of_raw_iron { background-position: -896px -96px}.mcsprite-block_of_redstone { background-position: -928px -96px}.mcsprite-blue_banner { background-position: -960px -96px}.mcsprite-blue_bed { background-position: -992px -96px}.mcsprite-blue_bed_lce { background-position: -1024px -96px}.mcsprite-blue_candle { background-position: -1056px -96px}.mcsprite-blue_carpet { background-position: -1088px -96px}.mcsprite-blue_concrete { background-position: -1120px -96px}.mcsprite-blue_concrete_powder { background-position: -1152px -96px}.mcsprite-blue_dye { background-position: -1184px -96px}.mcsprite-blue_firework_star { background-position: -1216px -96px}.mcsprite-blue_glazed_terracotta { background-position: -1248px -96px}.mcsprite-blue_ice { background-position: 0 -128px}.mcsprite-blue_orchid { background-position: -32px -128px}.mcsprite-blue_shield { background-position: -64px -128px}.mcsprite-blue_shulker_box { background-position: -96px -128px}.mcsprite-blue_stained_glass { background-position: -128px -128px}.mcsprite-blue_stained_glass_pane { background-position: -160px -128px}.mcsprite-blue_terracotta { background-position: -192px -128px}.mcsprite-blue_wool { background-position: -224px -128px}.mcsprite-bone { background-position: -256px -128px}.mcsprite-bone_block { background-position: -288px -128px}.mcsprite-bone_meal { background-position: -320px -128px}.mcsprite-book { background-position: -352px -128px}.mcsprite-book_and_quill { background-position: -384px -128px}.mcsprite-bookshelf { background-position: -416px -128px}.mcsprite-bottle_o_enchanting { background-position: -448px -128px}.mcsprite-bow { background-position: -480px -128px}.mcsprite-bowl { background-position: -512px -128px}.mcsprite-brain_coral { background-position: -544px -128px}.mcsprite-brain_coral_block { background-position: -576px -128px}.mcsprite-brain_coral_fan { background-position: -608px -128px}.mcsprite-bread { background-position: -640px -128px}.mcsprite-brewing_stand { background-position: -672px -128px}.mcsprite-brick { background-position: -704px -128px}.mcsprite-brick_slab { background-position: -736px -128px}.mcsprite-brick_slab_old { background-position: -768px -128px}.mcsprite-brick_stairs { background-position: -800px -128px}.mcsprite-brick_wall { background-position: -832px -128px}.mcsprite-bricks { background-position: -864px -128px}.mcsprite-bricks_old { background-position: -896px -128px}.mcsprite-broken_anvil { background-position: -928px -128px}.mcsprite-broken_elytra { background-position: -960px -128px}.mcsprite-brown_banner { background-position: -992px -128px}.mcsprite-brown_bed { background-position: -1024px -128px}.mcsprite-brown_bed_lce { background-position: -1056px -128px}.mcsprite-brown_candle { background-position: -1088px -128px}.mcsprite-brown_carpet { background-position: -1120px -128px}.mcsprite-brown_concrete { background-position: -1152px -128px}.mcsprite-brown_concrete_powder { background-position: -1184px -128px}.mcsprite-brown_dye { background-position: -1216px -128px}.mcsprite-brown_firework_star { background-position: -1248px -128px}.mcsprite-brown_glazed_terracotta { background-position: 0 -160px}.mcsprite-brown_mushroom { background-position: -32px -160px}.mcsprite-brown_mushroom_block { background-position: -64px -160px}.mcsprite-brown_shield { background-position: -96px -160px}.mcsprite-brown_shulker_box { background-position: -128px -160px}.mcsprite-brown_stained_glass { background-position: -160px -160px}.mcsprite-brown_stained_glass_pane { background-position: -192px -160px}.mcsprite-brown_terracotta { background-position: -224px -160px}.mcsprite-brown_wool { background-position: -256px -160px}.mcsprite-bubble_column { background-position: -288px -160px}.mcsprite-bubble_coral { background-position: -320px -160px}.mcsprite-bubble_coral_block { background-position: -352px -160px}.mcsprite-bubble_coral_fan { background-position: -384px -160px}.mcsprite-bucket { background-position: -416px -160px}.mcsprite-bucket_of_axolotl { background-position: -448px -160px}.mcsprite-bucket_of_cod { background-position: -480px -160px}.mcsprite-bucket_of_pufferfish { background-position: -512px -160px}.mcsprite-bucket_of_salmon { background-position: -544px -160px}.mcsprite-bucket_of_tropical_fish { background-position: -576px -160px}.mcsprite-budding_amethyst { background-position: -608px -160px}.mcsprite-bundle { background-position: -640px -160px}.mcsprite-buried_treasure_map { background-position: -672px -160px}.mcsprite-cactus { background-position: -704px -160px}.mcsprite-cactus_green { background-position: -736px -160px}.mcsprite-cake { background-position: -768px -160px}.mcsprite-calcite { background-position: -800px -160px}.mcsprite-campfire { background-position: -832px -160px}.mcsprite-candle { background-position: -864px -160px}.mcsprite-carrot { background-position: -896px -160px}.mcsprite-carrot_on_a_stick { background-position: -928px -160px}.mcsprite-cartography_table { background-position: -960px -160px}.mcsprite-carved_pumpkin { background-position: -992px -160px}.mcsprite-cast_fishing_rod { background-position: -1024px -160px}.mcsprite-cat_spawn_egg { background-position: -1056px -160px}.mcsprite-cauldron { background-position: -1088px -160px}.mcsprite-cave_air { background-position: -1120px -160px}.mcsprite-cave_spider_spawn_egg { background-position: -1152px -160px}.mcsprite-chain { background-position: -1184px -160px}.mcsprite-chainmail_boots { background-position: -1216px -160px}.mcsprite-chainmail_chestplate { background-position: -1248px -160px}.mcsprite-chainmail_helmet { background-position: 0 -192px}.mcsprite-chainmail_leggings { background-position: -32px -192px}.mcsprite-charcoal { background-position: -64px -192px}.mcsprite-chest { background-position: -96px -192px}.mcsprite-chicken_spawn_egg { background-position: -128px -192px}.mcsprite-chipped_anvil { background-position: -160px -192px}.mcsprite-chiseled_deepslate { background-position: -192px -192px}.mcsprite-chiseled_nether_bricks { background-position: -224px -192px}.mcsprite-chiseled_polished_blackstone { background-position: -256px -192px}.mcsprite-chiseled_quartz_block { background-position: -288px -192px}.mcsprite-chiseled_red_sandstone { background-position: -320px -192px}.mcsprite-chiseled_sandstone { background-position: -352px -192px}.mcsprite-chiseled_stone_bricks { background-position: -384px -192px}.mcsprite-chiseled_stone_bricks_monster_egg { background-position: -416px -192px}.mcsprite-chorus_flower { background-position: -448px -192px}.mcsprite-chorus_fruit { background-position: -480px -192px}.mcsprite-chorus_plant { background-position: -512px -192px}.mcsprite-clay { background-position: -544px -192px}.mcsprite-clay_ball { background-position: -576px -192px}.mcsprite-clock { background-position: -608px -192px}.mcsprite-clownfish { background-position: -640px -192px}.mcsprite-coal { background-position: -672px -192px}.mcsprite-coal_ore { background-position: -704px -192px}.mcsprite-coarse_dirt { background-position: -736px -192px}.mcsprite-cobbled_deepslate { background-position: -768px -192px}.mcsprite-cobbled_deepslate_slab { background-position: -800px -192px}.mcsprite-cobbled_deepslate_stairs { background-position: -832px -192px}.mcsprite-cobbled_deepslate_wall { background-position: -864px -192px}.mcsprite-cobblestone { background-position: -896px -192px}.mcsprite-cobblestone_monster_egg { background-position: -928px -192px}.mcsprite-cobblestone_slab { background-position: -960px -192px}.mcsprite-cobblestone_stairs { background-position: -992px -192px}.mcsprite-cobblestone_wall { background-position: -1024px -192px}.mcsprite-cobweb { background-position: -1056px -192px}.mcsprite-cocoa_beans { background-position: -1088px -192px}.mcsprite-cod_spawn_egg { background-position: -1120px -192px}.mcsprite-command_block { background-position: -1152px -192px}.mcsprite-compass { background-position: -1184px -192px}.mcsprite-composter { background-position: -1216px -192px}.mcsprite-conduit { background-position: -1248px -192px}.mcsprite-cooked_beef { background-position: 0 -224px}.mcsprite-cooked_chicken { background-position: -32px -224px}.mcsprite-cooked_cod { background-position: -64px -224px}.mcsprite-cooked_fish { background-position: -96px -224px}.mcsprite-cooked_mutton { background-position: -128px -224px}.mcsprite-cooked_porkchop { background-position: -160px -224px}.mcsprite-cooked_rabbit { background-position: -192px -224px}.mcsprite-cooked_salmon { background-position: -224px -224px}.mcsprite-cookie { background-position: -256px -224px}.mcsprite-copper_block { background-position: -288px -224px}.mcsprite-copper_ingot { background-position: -320px -224px}.mcsprite-copper_ore { background-position: -352px -224px}.mcsprite-cornflower { background-position: -384px -224px}.mcsprite-cow_spawn_egg { background-position: -416px -224px}.mcsprite-cracked_deepslate_bricks { background-position: -448px -224px}.mcsprite-cracked_deepslate_tiles { background-position: -480px -224px}.mcsprite-cracked_nether_bricks { background-position: -512px -224px}.mcsprite-cracked_polished_blackstone_bricks { background-position: -544px -224px}.mcsprite-cracked_stone_bricks { background-position: -576px -224px}.mcsprite-cracked_stone_bricks_monster_egg { background-position: -608px -224px}.mcsprite-crafting_table { background-position: -640px -224px}.mcsprite-creeper_head { background-position: -672px -224px}.mcsprite-creeper_spawn_egg { background-position: -704px -224px}.mcsprite-crimson_button { background-position: -736px -224px}.mcsprite-crimson_door { background-position: -768px -224px}.mcsprite-crimson_fence { background-position: -800px -224px}.mcsprite-crimson_fence_gate { background-position: -832px -224px}.mcsprite-crimson_fungus { background-position: -864px -224px}.mcsprite-crimson_hyphae { background-position: -896px -224px}.mcsprite-crimson_nylium { background-position: -928px -224px}.mcsprite-crimson_planks { background-position: -960px -224px}.mcsprite-crimson_pressure_plate { background-position: -992px -224px}.mcsprite-crimson_roots { background-position: -1024px -224px}.mcsprite-crimson_sign { background-position: -1056px -224px}.mcsprite-crimson_slab { background-position: -1088px -224px}.mcsprite-crimson_stairs { background-position: -1120px -224px}.mcsprite-crimson_stem { background-position: -1152px -224px}.mcsprite-crimson_trapdoor { background-position: -1184px -224px}.mcsprite-crossbow { background-position: -1216px -224px}.mcsprite-crying_obsidian { background-position: -1248px -224px}.mcsprite-cut_copper { background-position: 0 -256px}.mcsprite-cut_copper_block { background-position: -32px -256px}.mcsprite-cut_copper_slab { background-position: -64px -256px}.mcsprite-cut_copper_stairs { background-position: -96px -256px}.mcsprite-cut_red_sandstone { background-position: -128px -256px}.mcsprite-cut_red_sandstone_slab { background-position: -160px -256px}.mcsprite-cut_sandstone { background-position: -192px -256px}.mcsprite-cut_sandstone_slab { background-position: -224px -256px}.mcsprite-cyan_banner { background-position: -256px -256px}.mcsprite-cyan_bed { background-position: -288px -256px}.mcsprite-cyan_bed_lce { background-position: -320px -256px}.mcsprite-cyan_candle { background-position: -352px -256px}.mcsprite-cyan_carpet { background-position: -384px -256px}.mcsprite-cyan_concrete { background-position: -416px -256px}.mcsprite-cyan_concrete_powder { background-position: -448px -256px}.mcsprite-cyan_dye { background-position: -480px -256px}.mcsprite-cyan_firework_star { background-position: -512px -256px}.mcsprite-cyan_glazed_terracotta { background-position: -544px -256px}.mcsprite-cyan_shield { background-position: -576px -256px}.mcsprite-cyan_shulker_box { background-position: -608px -256px}.mcsprite-cyan_stained_glass { background-position: -640px -256px}.mcsprite-cyan_stained_glass_pane { background-position: -672px -256px}.mcsprite-cyan_terracotta { background-position: -704px -256px}.mcsprite-cyan_wool { background-position: -736px -256px}.mcsprite-dandelion { background-position: -768px -256px}.mcsprite-dandelion_yellow { background-position: -800px -256px}.mcsprite-dark_oak_boat { background-position: -832px -256px}.mcsprite-dark_oak_button { background-position: -864px -256px}.mcsprite-dark_oak_door { background-position: -896px -256px}.mcsprite-dark_oak_fence { background-position: -928px -256px}.mcsprite-dark_oak_fence_gate { background-position: -960px -256px}.mcsprite-dark_oak_leaves { background-position: -992px -256px}.mcsprite-dark_oak_log { background-position: -1024px -256px}.mcsprite-dark_oak_planks { background-position: -1056px -256px}.mcsprite-dark_oak_pressure_plate { background-position: -1088px -256px}.mcsprite-dark_oak_sapling { background-position: -1120px -256px}.mcsprite-dark_oak_sign { background-position: -1152px -256px}.mcsprite-dark_oak_slab { background-position: -1184px -256px}.mcsprite-dark_oak_stairs { background-position: -1216px -256px}.mcsprite-dark_oak_trapdoor { background-position: -1248px -256px}.mcsprite-dark_oak_wood { background-position: 0 -288px}.mcsprite-dark_oak_wood_button { background-position: -32px -288px}.mcsprite-dark_oak_wood_door { background-position: -64px -288px}.mcsprite-dark_oak_wood_fence { background-position: -96px -288px}.mcsprite-dark_oak_wood_fence_gate { background-position: -128px -288px}.mcsprite-dark_oak_wood_planks { background-position: -160px -288px}.mcsprite-dark_oak_wood_pressure_plate { background-position: -192px -288px}.mcsprite-dark_oak_wood_sign { background-position: -224px -288px}.mcsprite-dark_oak_wood_slab { background-position: -256px -288px}.mcsprite-dark_oak_wood_stairs { background-position: -288px -288px}.mcsprite-dark_oak_wood_trapdoor { background-position: -320px -288px}.mcsprite-dark_prismarine { background-position: -352px -288px}.mcsprite-dark_prismarine_slab { background-position: -384px -288px}.mcsprite-dark_prismarine_stairs { background-position: -416px -288px}.mcsprite-daylight_detector { background-position: -448px -288px}.mcsprite-daylight_sensor { background-position: -480px -288px}.mcsprite-dead_brain_coral { background-position: -512px -288px}.mcsprite-dead_brain_coral_block { background-position: -544px -288px}.mcsprite-dead_brain_coral_fan { background-position: -576px -288px}.mcsprite-dead_bubble_coral { background-position: -608px -288px}.mcsprite-dead_bubble_coral_block { background-position: -640px -288px}.mcsprite-dead_bubble_coral_fan { background-position: -672px -288px}.mcsprite-dead_bush { background-position: -704px -288px}.mcsprite-dead_fire_coral { background-position: -736px -288px}.mcsprite-dead_fire_coral_block { background-position: -768px -288px}.mcsprite-dead_fire_coral_fan { background-position: -800px -288px}.mcsprite-dead_horn_coral { background-position: -832px -288px}.mcsprite-dead_horn_coral_block { background-position: -864px -288px}.mcsprite-dead_horn_coral_fan { background-position: -896px -288px}.mcsprite-dead_tube_coral { background-position: -928px -288px}.mcsprite-dead_tube_coral_block { background-position: -960px -288px}.mcsprite-dead_tube_coral_fan { background-position: -992px -288px}.mcsprite-debug_stick { background-position: -1024px -288px}.mcsprite-deepslate { background-position: -1056px -288px}.mcsprite-deepslate_brick_slab { background-position: -1088px -288px}.mcsprite-deepslate_brick_stairs { background-position: -1120px -288px}.mcsprite-deepslate_brick_wall { background-position: -1152px -288px}.mcsprite-deepslate_bricks { background-position: -1184px -288px}.mcsprite-deepslate_coal_ore { background-position: -1216px -288px}.mcsprite-deepslate_copper_ore { background-position: -1248px -288px}.mcsprite-deepslate_diamond_ore { background-position: 0 -320px}.mcsprite-deepslate_emerald_ore { background-position: -32px -320px}.mcsprite-deepslate_gold_ore { background-position: -64px -320px}.mcsprite-deepslate_iron_ore { background-position: -96px -320px}.mcsprite-deepslate_lapis_lazuli_ore { background-position: -128px -320px}.mcsprite-deepslate_redstone_ore { background-position: -160px -320px}.mcsprite-deepslate_tile_slab { background-position: -192px -320px}.mcsprite-deepslate_tile_stairs { background-position: -224px -320px}.mcsprite-deepslate_tile_wall { background-position: -256px -320px}.mcsprite-deepslate_tiles { background-position: -288px -320px}.mcsprite-detector_rail { background-position: -320px -320px}.mcsprite-diamond { background-position: -352px -320px}.mcsprite-diamond_axe { background-position: -384px -320px}.mcsprite-diamond_boots { background-position: -416px -320px}.mcsprite-diamond_chestplate { background-position: -448px -320px}.mcsprite-diamond_helmet { background-position: -480px -320px}.mcsprite-diamond_hoe { background-position: -512px -320px}.mcsprite-diamond_horse_armor { background-position: -544px -320px}.mcsprite-diamond_leggings { background-position: -576px -320px}.mcsprite-diamond_ore { background-position: -608px -320px}.mcsprite-diamond_pickaxe { background-position: -640px -320px}.mcsprite-diamond_shovel { background-position: -672px -320px}.mcsprite-diamond_sword { background-position: -704px -320px}.mcsprite-diorite { background-position: -736px -320px}.mcsprite-diorite_slab { background-position: -768px -320px}.mcsprite-diorite_stairs { background-position: -800px -320px}.mcsprite-diorite_wall { background-position: -832px -320px}.mcsprite-dirt { background-position: -864px -320px}.mcsprite-dirt_path { background-position: -896px -320px}.mcsprite-dispenser { background-position: -928px -320px}.mcsprite-dolphin_spawn_egg { background-position: -960px -320px}.mcsprite-donkey_spawn_egg { background-position: -992px -320px}.mcsprite-double_smooth_stone_slab { background-position: -1024px -320px}.mcsprite-dragon_egg { background-position: -1056px -320px}.mcsprite-dragon_head { background-position: -1088px -320px}.mcsprite-dragons_breath { background-position: -1120px -320px}.mcsprite-dried_kelp { background-position: -1152px -320px}.mcsprite-dried_kelp_block { background-position: -1184px -320px}.mcsprite-dripstone_block { background-position: -1216px -320px}.mcsprite-dropper { background-position: -1248px -320px}.mcsprite-drowned_spawn_egg { background-position: 0 -352px}.mcsprite-egg { background-position: -32px -352px}.mcsprite-elder_guardian_spawn_egg { background-position: -64px -352px}.mcsprite-elytra { background-position: -96px -352px}.mcsprite-emerald { background-position: -128px -352px}.mcsprite-emerald_ore { background-position: -160px -352px}.mcsprite-empty_locator_map { background-position: -192px -352px}.mcsprite-empty_map { background-position: -224px -352px}.mcsprite-enchanted_apple { background-position: -256px -352px}.mcsprite-enchanted_book { background-position: -288px -352px}.mcsprite-enchanted_golden_apple { background-position: -320px -352px}.mcsprite-enchanting_table { background-position: -352px -352px}.mcsprite-enchantment_table { background-position: -384px -352px}.mcsprite-end_crystal { background-position: -416px -352px}.mcsprite-end_gateway { background-position: -448px -352px}.mcsprite-end_portal { background-position: -480px -352px}.mcsprite-end_portal_frame { background-position: -512px -352px}.mcsprite-end_rod { background-position: -544px -352px}.mcsprite-end_stone { background-position: -576px -352px}.mcsprite-end_stone_brick_slab { background-position: -608px -352px}.mcsprite-end_stone_brick_stairs { background-position: -640px -352px}.mcsprite-end_stone_brick_wall { background-position: -672px -352px}.mcsprite-end_stone_bricks { background-position: -704px -352px}.mcsprite-ender_chest { background-position: -736px -352px}.mcsprite-ender_pearl { background-position: -768px -352px}.mcsprite-enderman_spawn_egg { background-position: -800px -352px}.mcsprite-endermite_spawn_egg { background-position: -832px -352px}.mcsprite-evoker_spawn_egg { background-position: -864px -352px}.mcsprite-exposed_copper { background-position: -896px -352px}.mcsprite-exposed_copper_block { background-position: -928px -352px}.mcsprite-exposed_cut_copper { background-position: -960px -352px}.mcsprite-exposed_cut_copper_block { background-position: -992px -352px}.mcsprite-exposed_cut_copper_slab { background-position: -1024px -352px}.mcsprite-exposed_cut_copper_stairs { background-position: -1056px -352px}.mcsprite-eye_of_ender { background-position: -1088px -352px}.mcsprite-farmland { background-position: -1120px -352px}.mcsprite-feather { background-position: -1152px -352px}.mcsprite-fermented_spider_eye { background-position: -1184px -352px}.mcsprite-fern { background-position: -1216px -352px}.mcsprite-filled_bundle { background-position: -1248px -352px}.mcsprite-fire_charge { background-position: 0 -384px}.mcsprite-fire_coral { background-position: -32px -384px}.mcsprite-fire_coral_block { background-position: -64px -384px}.mcsprite-fire_coral_fan { background-position: -96px -384px}.mcsprite-firework_loaded_crossbow { background-position: -128px -384px}.mcsprite-firework_rocket { background-position: -160px -384px}.mcsprite-firework_star { background-position: -192px -384px}.mcsprite-fishing_rod { background-position: -224px -384px}.mcsprite-fletching_table { background-position: -256px -384px}.mcsprite-flint { background-position: -288px -384px}.mcsprite-flint_and_steel { background-position: -320px -384px}.mcsprite-flower_pot { background-position: -352px -384px}.mcsprite-flowering_azalea { background-position: -384px -384px}.mcsprite-flowering_azalea_leaves { background-position: -416px -384px}.mcsprite-flowing_lava { background-position: -448px -384px}.mcsprite-flowing_water { background-position: -480px -384px}.mcsprite-fox_spawn_egg { background-position: -512px -384px}.mcsprite-frosted_ice { background-position: -544px -384px}.mcsprite-furnace { background-position: -576px -384px}.mcsprite-ghast_spawn_egg { background-position: -608px -384px}.mcsprite-ghast_tear { background-position: -640px -384px}.mcsprite-gilded_blackstone { background-position: -672px -384px}.mcsprite-glass { background-position: -704px -384px}.mcsprite-glass_bottle { background-position: -736px -384px}.mcsprite-glass_pane { background-position: -768px -384px}.mcsprite-glistering_melon { background-position: -800px -384px}.mcsprite-glistering_melon_slice { background-position: -832px -384px}.mcsprite-glow_berries { background-position: -864px -384px}.mcsprite-glow_ink_sac { background-position: -896px -384px}.mcsprite-glow_item_frame { background-position: -928px -384px}.mcsprite-glow_lichen { background-position: -960px -384px}.mcsprite-glow_squid_spawn_egg { background-position: -992px -384px}.mcsprite-glowstone { background-position: -1024px -384px}.mcsprite-glowstone_dust { background-position: -1056px -384px}.mcsprite-goat_horn { background-position: -1088px -384px}.mcsprite-goat_spawn_egg { background-position: -1120px -384px}.mcsprite-gold_ingot { background-position: -1152px -384px}.mcsprite-gold_nugget { background-position: -1184px -384px}.mcsprite-gold_ore { background-position: -1216px -384px}.mcsprite-golden_apple { background-position: -1248px -384px}.mcsprite-golden_axe { background-position: 0 -416px}.mcsprite-golden_boots { background-position: -32px -416px}.mcsprite-golden_carrot { background-position: -64px -416px}.mcsprite-golden_chestplate { background-position: -96px -416px}.mcsprite-golden_helmet { background-position: -128px -416px}.mcsprite-golden_hoe { background-position: -160px -416px}.mcsprite-golden_horse_armor { background-position: -192px -416px}.mcsprite-golden_leggings { background-position: -224px -416px}.mcsprite-golden_pickaxe { background-position: -256px -416px}.mcsprite-golden_shovel { background-position: -288px -416px}.mcsprite-golden_sword { background-position: -320px -416px}.mcsprite-granite { background-position: -352px -416px}.mcsprite-granite_slab { background-position: -384px -416px}.mcsprite-granite_stairs { background-position: -416px -416px}.mcsprite-granite_wall { background-position: -448px -416px}.mcsprite-grass { background-position: -480px -416px}.mcsprite-grass_block { background-position: -512px -416px}.mcsprite-grass_path { background-position: -544px -416px}.mcsprite-gravel { background-position: -576px -416px}.mcsprite-gray_banner { background-position: -608px -416px}.mcsprite-gray_bed { background-position: -640px -416px}.mcsprite-gray_bed_lce { background-position: -672px -416px}.mcsprite-gray_candle { background-position: -704px -416px}.mcsprite-gray_carpet { background-position: -736px -416px}.mcsprite-gray_concrete { background-position: -768px -416px}.mcsprite-gray_concrete_powder { background-position: -800px -416px}.mcsprite-gray_dye { background-position: -832px -416px}.mcsprite-gray_firework_star { background-position: -864px -416px}.mcsprite-gray_glazed_terracotta { background-position: -896px -416px}.mcsprite-gray_shield { background-position: -928px -416px}.mcsprite-gray_shulker_box { background-position: -960px -416px}.mcsprite-gray_stained_glass { background-position: -992px -416px}.mcsprite-gray_stained_glass_pane { background-position: -1024px -416px}.mcsprite-gray_terracotta { background-position: -1056px -416px}.mcsprite-gray_wool { background-position: -1088px -416px}.mcsprite-green_banner { background-position: -1120px -416px}.mcsprite-green_bed { background-position: -1152px -416px}.mcsprite-green_bed_lce { background-position: -1184px -416px}.mcsprite-green_candle { background-position: -1216px -416px}.mcsprite-green_carpet { background-position: -1248px -416px}.mcsprite-green_concrete { background-position: 0 -448px}.mcsprite-green_concrete_powder { background-position: -32px -448px}.mcsprite-green_dye { background-position: -64px -448px}.mcsprite-green_firework_star { background-position: -96px -448px}.mcsprite-green_glazed_terracotta { background-position: -128px -448px}.mcsprite-green_shield { background-position: -160px -448px}.mcsprite-green_shulker_box { background-position: -192px -448px}.mcsprite-green_stained_glass { background-position: -224px -448px}.mcsprite-green_stained_glass_pane { background-position: -256px -448px}.mcsprite-green_terracotta { background-position: -288px -448px}.mcsprite-green_wool { background-position: -320px -448px}.mcsprite-grindstone { background-position: -352px -448px}.mcsprite-guardian_spawn_egg { background-position: -384px -448px}.mcsprite-gunpowder { background-position: -416px -448px}.mcsprite-half_filled_bundle { background-position: -448px -448px}.mcsprite-hanging_roots { background-position: -480px -448px}.mcsprite-hay_bale { background-position: -512px -448px}.mcsprite-head { background-position: -544px -448px}.mcsprite-heart_of_the_sea { background-position: -576px -448px}.mcsprite-heavy_weighted_pressure_plate { background-position: -608px -448px}.mcsprite-hoglin_spawn_egg { background-position: -640px -448px}.mcsprite-honey_block { background-position: -672px -448px}.mcsprite-honey_bottle { background-position: -704px -448px}.mcsprite-honeycomb { background-position: -736px -448px}.mcsprite-honeycomb_block { background-position: -768px -448px}.mcsprite-hopper { background-position: -800px -448px}.mcsprite-horn_coral { background-position: -832px -448px}.mcsprite-horn_coral_block { background-position: -864px -448px}.mcsprite-horn_coral_fan { background-position: -896px -448px}.mcsprite-horse_spawn_egg { background-position: -928px -448px}.mcsprite-husk_spawn_egg { background-position: -960px -448px}.mcsprite-ice { background-position: -992px -448px}.mcsprite-infested_chiseled_stone_bricks { background-position: -1024px -448px}.mcsprite-infested_cobblestone { background-position: -1056px -448px}.mcsprite-infested_cracked_stone_bricks { background-position: -1088px -448px}.mcsprite-infested_deepslate { background-position: -1120px -448px}.mcsprite-infested_mossy_stone_bricks { background-position: -1152px -448px}.mcsprite-infested_stone { background-position: -1184px -448px}.mcsprite-infested_stone_bricks { background-position: -1216px -448px}.mcsprite-ink_sac { background-position: -1248px -448px}.mcsprite-inverted_daylight_detector { background-position: 0 -480px}.mcsprite-inverted_daylight_sensor { background-position: -32px -480px}.mcsprite-invisible_bedrock { background-position: -64px -480px}.mcsprite-iron_axe { background-position: -96px -480px}.mcsprite-iron_bars { background-position: -128px -480px}.mcsprite-iron_boots { background-position: -160px -480px}.mcsprite-iron_chestplate { background-position: -192px -480px}.mcsprite-iron_door { background-position: -224px -480px}.mcsprite-iron_helmet { background-position: -256px -480px}.mcsprite-iron_hoe { background-position: -288px -480px}.mcsprite-iron_horse_armor { background-position: -320px -480px}.mcsprite-iron_ingot { background-position: -352px -480px}.mcsprite-iron_leggings { background-position: -384px -480px}.mcsprite-iron_nugget { background-position: -416px -480px}.mcsprite-iron_ore { background-position: -448px -480px}.mcsprite-iron_pickaxe { background-position: -480px -480px}.mcsprite-iron_shovel { background-position: -512px -480px}.mcsprite-iron_sword { background-position: -544px -480px}.mcsprite-iron_trapdoor { background-position: -576px -480px}.mcsprite-item_frame { background-position: -608px -480px}.mcsprite-jack_olantern { background-position: -640px -480px}.mcsprite-jigsaw { background-position: -672px -480px}.mcsprite-jigsaw_block { background-position: -704px -480px}.mcsprite-jukebox { background-position: -736px -480px}.mcsprite-jungle_boat { background-position: -768px -480px}.mcsprite-jungle_button { background-position: -800px -480px}.mcsprite-jungle_door { background-position: -832px -480px}.mcsprite-jungle_fence { background-position: -864px -480px}.mcsprite-jungle_fence_gate { background-position: -896px -480px}.mcsprite-jungle_leaves { background-position: -928px -480px}.mcsprite-jungle_log { background-position: -960px -480px}.mcsprite-jungle_planks { background-position: -992px -480px}.mcsprite-jungle_pressure_plate { background-position: -1024px -480px}.mcsprite-jungle_sapling { background-position: -1056px -480px}.mcsprite-jungle_sign { background-position: -1088px -480px}.mcsprite-jungle_slab { background-position: -1120px -480px}.mcsprite-jungle_stairs { background-position: -1152px -480px}.mcsprite-jungle_trapdoor { background-position: -1184px -480px}.mcsprite-jungle_wood { background-position: -1216px -480px}.mcsprite-jungle_wood_button { background-position: -1248px -480px}.mcsprite-jungle_wood_door { background-position: 0 -512px}.mcsprite-jungle_wood_fence { background-position: -32px -512px}.mcsprite-jungle_wood_fence_gate { background-position: -64px -512px}.mcsprite-jungle_wood_planks { background-position: -96px -512px}.mcsprite-jungle_wood_pressure_plate { background-position: -128px -512px}.mcsprite-jungle_wood_sign { background-position: -160px -512px}.mcsprite-jungle_wood_slab { background-position: -192px -512px}.mcsprite-jungle_wood_stairs { background-position: -224px -512px}.mcsprite-jungle_wood_trapdoor { background-position: -256px -512px}.mcsprite-kelp { background-position: -288px -512px}.mcsprite-knowledge_book { background-position: -320px -512px}.mcsprite-ladder { background-position: -352px -512px}.mcsprite-lantern { background-position: -384px -512px}.mcsprite-lapis_lazuli { background-position: -416px -512px}.mcsprite-lapis_lazuli_block { background-position: -448px -512px}.mcsprite-lapis_lazuli_ore { background-position: -480px -512px}.mcsprite-large_amethyst_bud { background-position: -512px -512px}.mcsprite-large_fern { background-position: -544px -512px}.mcsprite-lava { background-position: -576px -512px}.mcsprite-lava_bucket { background-position: -608px -512px}.mcsprite-lead { background-position: -640px -512px}.mcsprite-leather { background-position: -672px -512px}.mcsprite-leather_boots { background-position: -704px -512px}.mcsprite-leather_boots_black { background-position: -736px -512px}.mcsprite-leather_boots_blue { background-position: -768px -512px}.mcsprite-leather_boots_cyan { background-position: -800px -512px}.mcsprite-leather_boots_gray { background-position: -832px -512px}.mcsprite-leather_boots_green { background-position: -864px -512px}.mcsprite-leather_boots_light_blue { background-position: -896px -512px}.mcsprite-leather_boots_light_gray { background-position: -928px -512px}.mcsprite-leather_boots_lime { background-position: -960px -512px}.mcsprite-leather_boots_magenta { background-position: -992px -512px}.mcsprite-leather_boots_orange { background-position: -1024px -512px}.mcsprite-leather_boots_pink { background-position: -1056px -512px}.mcsprite-leather_boots_purple { background-position: -1088px -512px}.mcsprite-leather_boots_red { background-position: -1120px -512px}.mcsprite-leather_boots_white { background-position: -1152px -512px}.mcsprite-leather_boots_yellow { background-position: -1184px -512px}.mcsprite-leather_cap { background-position: -1216px -512px}.mcsprite-leather_cap_black { background-position: -1248px -512px}.mcsprite-leather_cap_blue { background-position: 0 -544px}.mcsprite-leather_cap_cyan { background-position: -32px -544px}.mcsprite-leather_cap_gray { background-position: -64px -544px}.mcsprite-leather_cap_green { background-position: -96px -544px}.mcsprite-leather_cap_light_blue { background-position: -128px -544px}.mcsprite-leather_cap_light_gray { background-position: -160px -544px}.mcsprite-leather_cap_lime { background-position: -192px -544px}.mcsprite-leather_cap_magenta { background-position: -224px -544px}.mcsprite-leather_cap_orange { background-position: -256px -544px}.mcsprite-leather_cap_pink { background-position: -288px -544px}.mcsprite-leather_cap_purple { background-position: -320px -544px}.mcsprite-leather_cap_red { background-position: -352px -544px}.mcsprite-leather_cap_white { background-position: -384px -544px}.mcsprite-leather_cap_yellow { background-position: -416px -544px}.mcsprite-leather_horse_armor { background-position: -448px -544px}.mcsprite-leather_pants { background-position: -480px -544px}.mcsprite-leather_pants_black { background-position: -512px -544px}.mcsprite-leather_pants_blue { background-position: -544px -544px}.mcsprite-leather_pants_cyan { background-position: -576px -544px}.mcsprite-leather_pants_gray { background-position: -608px -544px}.mcsprite-leather_pants_green { background-position: -640px -544px}.mcsprite-leather_pants_light_blue { background-position: -672px -544px}.mcsprite-leather_pants_light_gray { background-position: -704px -544px}.mcsprite-leather_pants_lime { background-position: -736px -544px}.mcsprite-leather_pants_magenta { background-position: -768px -544px}.mcsprite-leather_pants_orange { background-position: -800px -544px}.mcsprite-leather_pants_pink { background-position: -832px -544px}.mcsprite-leather_pants_purple { background-position: -864px -544px}.mcsprite-leather_pants_red { background-position: -896px -544px}.mcsprite-leather_pants_white { background-position: -928px -544px}.mcsprite-leather_pants_yellow { background-position: -960px -544px}.mcsprite-leather_tunic { background-position: -992px -544px}.mcsprite-leather_tunic_black { background-position: -1024px -544px}.mcsprite-leather_tunic_blue { background-position: -1056px -544px}.mcsprite-leather_tunic_cyan { background-position: -1088px -544px}.mcsprite-leather_tunic_gray { background-position: -1120px -544px}.mcsprite-leather_tunic_green { background-position: -1152px -544px}.mcsprite-leather_tunic_light_blue { background-position: -1184px -544px}.mcsprite-leather_tunic_light_gray { background-position: -1216px -544px}.mcsprite-leather_tunic_lime { background-position: -1248px -544px}.mcsprite-leather_tunic_magenta { background-position: 0 -576px}.mcsprite-leather_tunic_orange { background-position: -32px -576px}.mcsprite-leather_tunic_pink { background-position: -64px -576px}.mcsprite-leather_tunic_purple { background-position: -96px -576px}.mcsprite-leather_tunic_red { background-position: -128px -576px}.mcsprite-leather_tunic_white { background-position: -160px -576px}.mcsprite-leather_tunic_yellow { background-position: -192px -576px}.mcsprite-lectern { background-position: -224px -576px}.mcsprite-lever { background-position: -256px -576px}.mcsprite-light_blue_banner { background-position: -288px -576px}.mcsprite-light_blue_bed { background-position: -320px -576px}.mcsprite-light_blue_bed_lce { background-position: -352px -576px}.mcsprite-light_blue_candle { background-position: -384px -576px}.mcsprite-light_blue_carpet { background-position: -416px -576px}.mcsprite-light_blue_concrete { background-position: -448px -576px}.mcsprite-light_blue_concrete_powder { background-position: -480px -576px}.mcsprite-light_blue_dye { background-position: -512px -576px}.mcsprite-light_blue_firework_star { background-position: -544px -576px}.mcsprite-light_blue_glazed_terracotta { background-position: -576px -576px}.mcsprite-light_blue_shield { background-position: -608px -576px}.mcsprite-light_blue_shulker_box { background-position: -640px -576px}.mcsprite-light_blue_stained_glass { background-position: -672px -576px}.mcsprite-light_blue_stained_glass_pane { background-position: -704px -576px}.mcsprite-light_blue_terracotta { background-position: -736px -576px}.mcsprite-light_blue_wool { background-position: -768px -576px}.mcsprite-light_gray_banner { background-position: -800px -576px}.mcsprite-light_gray_bed { background-position: -832px -576px}.mcsprite-light_gray_bed_lce { background-position: -864px -576px}.mcsprite-light_gray_candle { background-position: -896px -576px}.mcsprite-light_gray_carpet { background-position: -928px -576px}.mcsprite-light_gray_concrete { background-position: -960px -576px}.mcsprite-light_gray_concrete_powder { background-position: -992px -576px}.mcsprite-light_gray_dye { background-position: -1024px -576px}.mcsprite-light_gray_firework_star { background-position: -1056px -576px}.mcsprite-light_gray_glazed_terracotta { background-position: -1088px -576px}.mcsprite-light_gray_shield { background-position: -1120px -576px}.mcsprite-light_gray_shulker_box { background-position: -1152px -576px}.mcsprite-light_gray_stained_glass { background-position: -1184px -576px}.mcsprite-light_gray_stained_glass_pane { background-position: -1216px -576px}.mcsprite-light_gray_terracotta { background-position: -1248px -576px}.mcsprite-light_gray_wool { background-position: 0 -608px}.mcsprite-light_negative { background-position: -32px -608px}.mcsprite-light_weighted_pressure_plate { background-position: -64px -608px}.mcsprite-lightning_rod { background-position: -96px -608px}.mcsprite-lilac { background-position: -128px -608px}.mcsprite-lily_of_the_valley { background-position: -160px -608px}.mcsprite-lily_pad { background-position: -192px -608px}.mcsprite-lime_banner { background-position: -224px -608px}.mcsprite-lime_bed { background-position: -256px -608px}.mcsprite-lime_bed_lce { background-position: -288px -608px}.mcsprite-lime_candle { background-position: -320px -608px}.mcsprite-lime_carpet { background-position: -352px -608px}.mcsprite-lime_concrete { background-position: -384px -608px}.mcsprite-lime_concrete_powder { background-position: -416px -608px}.mcsprite-lime_dye { background-position: -448px -608px}.mcsprite-lime_firework_star { background-position: -480px -608px}.mcsprite-lime_glazed_terracotta { background-position: -512px -608px}.mcsprite-lime_shield { background-position: -544px -608px}.mcsprite-lime_shulker_box { background-position: -576px -608px}.mcsprite-lime_stained_glass { background-position: -608px -608px}.mcsprite-lime_stained_glass_pane { background-position: -640px -608px}.mcsprite-lime_terracotta { background-position: -672px -608px}.mcsprite-lime_wool { background-position: -704px -608px}.mcsprite-lingering_potion_of_decay { background-position: -736px -608px}.mcsprite-lingering_potion_of_fire_resistance { background-position: -768px -608px}.mcsprite-lingering_potion_of_harming { background-position: -800px -608px}.mcsprite-lingering_potion_of_healing { background-position: -832px -608px}.mcsprite-lingering_potion_of_invisibility { background-position: -864px -608px}.mcsprite-lingering_potion_of_leaping { background-position: -896px -608px}.mcsprite-lingering_potion_of_levitation { background-position: -928px -608px}.mcsprite-lingering_potion_of_luck { background-position: -960px -608px}.mcsprite-lingering_potion_of_night_vision { background-position: -992px -608px}.mcsprite-lingering_potion_of_poison { background-position: -1024px -608px}.mcsprite-lingering_potion_of_regeneration { background-position: -1056px -608px}.mcsprite-lingering_potion_of_slow_falling { background-position: -1088px -608px}.mcsprite-lingering_potion_of_slowness { background-position: -1120px -608px}.mcsprite-lingering_potion_of_strength { background-position: -1152px -608px}.mcsprite-lingering_potion_of_swiftness { background-position: -1184px -608px}.mcsprite-lingering_potion_of_the_turtle_master { background-position: -1216px -608px}.mcsprite-lingering_potion_of_water_breathing { background-position: -1248px -608px}.mcsprite-lingering_potion_of_weakness { background-position: 0 -640px}.mcsprite-lingering_water_bottle { background-position: -32px -640px}.mcsprite-llama_spawn_egg { background-position: -64px -640px}.mcsprite-locked_map { background-position: -96px -640px}.mcsprite-lodestone { background-position: -128px -640px}.mcsprite-loom { background-position: -160px -640px}.mcsprite-magenta_banner { background-position: -192px -640px}.mcsprite-magenta_bed { background-position: -224px -640px}.mcsprite-magenta_bed_lce { background-position: -256px -640px}.mcsprite-magenta_candle { background-position: -288px -640px}.mcsprite-magenta_carpet { background-position: -320px -640px}.mcsprite-magenta_concrete { background-position: -352px -640px}.mcsprite-magenta_concrete_powder { background-position: -384px -640px}.mcsprite-magenta_dye { background-position: -416px -640px}.mcsprite-magenta_firework_star { background-position: -448px -640px}.mcsprite-magenta_glazed_terracotta { background-position: -480px -640px}.mcsprite-magenta_shield { background-position: -512px -640px}.mcsprite-magenta_shulker_box { background-position: -544px -640px}.mcsprite-magenta_stained_glass { background-position: -576px -640px}.mcsprite-magenta_stained_glass_pane { background-position: -608px -640px}.mcsprite-magenta_terracotta { background-position: -640px -640px}.mcsprite-magenta_wool { background-position: -672px -640px}.mcsprite-magma_cream { background-position: -704px -640px}.mcsprite-magma_cube_spawn_egg { background-position: -736px -640px}.mcsprite-map { background-position: -768px -640px}.mcsprite-medium_amethyst_bud { background-position: -800px -640px}.mcsprite-melon { background-position: -832px -640px}.mcsprite-melon_seeds { background-position: -864px -640px}.mcsprite-melon_slice { background-position: -896px -640px}.mcsprite-mhf_alex { background-position: -928px -640px}.mcsprite-mhf_arrowdown { background-position: -960px -640px}.mcsprite-mhf_arrowleft { background-position: -992px -640px}.mcsprite-mhf_arrowright { background-position: -1024px -640px}.mcsprite-mhf_arrowup { background-position: -1056px -640px}.mcsprite-mhf_blaze { background-position: -1088px -640px}.mcsprite-mhf_cactus { background-position: -1120px -640px}.mcsprite-mhf_cake { background-position: -1152px -640px}.mcsprite-mhf_cavespider { background-position: -1184px -640px}.mcsprite-mhf_chest { background-position: -1216px -640px}.mcsprite-mhf_chicken { background-position: -1248px -640px}.mcsprite-mhf_coconutb { background-position: 0 -672px}.mcsprite-mhf_coconutg { background-position: -32px -672px}.mcsprite-mhf_cow { background-position: -64px -672px}.mcsprite-mhf_creeper { background-position: -96px -672px}.mcsprite-mhf_enderman { background-position: -128px -672px}.mcsprite-mhf_exclamation { background-position: -160px -672px}.mcsprite-mhf_ghast { background-position: -192px -672px}.mcsprite-mhf_golem { background-position: -224px -672px}.mcsprite-mhf_herobrine { background-position: -256px -672px}.mcsprite-mhf_lavaslime { background-position: -288px -672px}.mcsprite-mhf_melon { background-position: -320px -672px}.mcsprite-mhf_mushroomcow { background-position: -352px -672px}.mcsprite-mhf_oaklog { background-position: -384px -672px}.mcsprite-mhf_ocelot { background-position: -416px -672px}.mcsprite-mhf_pig { background-position: -448px -672px}.mcsprite-mhf_pigzombie { background-position: -480px -672px}.mcsprite-mhf_present1 { background-position: -512px -672px}.mcsprite-mhf_present2 { background-position: -544px -672px}.mcsprite-mhf_pumpkin { background-position: -576px -672px}.mcsprite-mhf_question { background-position: -608px -672px}.mcsprite-mhf_sheep { background-position: -640px -672px}.mcsprite-mhf_skeleton { background-position: -672px -672px}.mcsprite-mhf_slime { background-position: -704px -672px}.mcsprite-mhf_spider { background-position: -736px -672px}.mcsprite-mhf_squid { background-position: -768px -672px}.mcsprite-mhf_steve { background-position: -800px -672px}.mcsprite-mhf_tnt { background-position: -832px -672px}.mcsprite-mhf_tnt2 { background-position: -864px -672px}.mcsprite-mhf_villager { background-position: -896px -672px}.mcsprite-mhf_wskeleton { background-position: -928px -672px}.mcsprite-mhf_zombie { background-position: -960px -672px}.mcsprite-milk_bucket { background-position: -992px -672px}.mcsprite-minecart { background-position: -1024px -672px}.mcsprite-minecart_with_chest { background-position: -1056px -672px}.mcsprite-minecart_with_command_block { background-position: -1088px -672px}.mcsprite-minecart_with_furnace { background-position: -1120px -672px}.mcsprite-minecart_with_hopper { background-position: -1152px -672px}.mcsprite-minecart_with_tnt { background-position: -1184px -672px}.mcsprite-monster_spawner { background-position: -1216px -672px}.mcsprite-mooshroom_spawn_egg { background-position: -1248px -672px}.mcsprite-moss_block { background-position: 0 -704px}.mcsprite-moss_carpet { background-position: -32px -704px}.mcsprite-moss_stone { background-position: -64px -704px}.mcsprite-mossy_cobblestone { background-position: -96px -704px}.mcsprite-mossy_cobblestone_slab { background-position: -128px -704px}.mcsprite-mossy_cobblestone_stairs { background-position: -160px -704px}.mcsprite-mossy_cobblestone_wall { background-position: -192px -704px}.mcsprite-mossy_stone_brick_slab { background-position: -224px -704px}.mcsprite-mossy_stone_brick_stairs { background-position: -256px -704px}.mcsprite-mossy_stone_brick_wall { background-position: -288px -704px}.mcsprite-mossy_stone_bricks { background-position: -320px -704px}.mcsprite-mossy_stone_bricks_monster_egg { background-position: -352px -704px}.mcsprite-mule_spawn_egg { background-position: -384px -704px}.mcsprite-mundane_lingering_potion { background-position: -416px -704px}.mcsprite-mundane_potion { background-position: -448px -704px}.mcsprite-mundane_splash_potion { background-position: -480px -704px}.mcsprite-mushroom_stem { background-position: -512px -704px}.mcsprite-mushroom_stew { background-position: -544px -704px}.mcsprite-music_disc_11 { background-position: -576px -704px}.mcsprite-music_disc_13 { background-position: -608px -704px}.mcsprite-music_disc_blocks { background-position: -640px -704px}.mcsprite-music_disc_cat { background-position: -672px -704px}.mcsprite-music_disc_chirp { background-position: -704px -704px}.mcsprite-music_disc_far { background-position: -736px -704px}.mcsprite-music_disc_mall { background-position: -768px -704px}.mcsprite-music_disc_mellohi { background-position: -800px -704px}.mcsprite-music_disc_pigstep { background-position: -832px -704px}.mcsprite-music_disc_stal { background-position: -864px -704px}.mcsprite-music_disc_strad { background-position: -896px -704px}.mcsprite-music_disc_wait { background-position: -928px -704px}.mcsprite-music_disc_ward { background-position: -960px -704px}.mcsprite-mycelium { background-position: -992px -704px}.mcsprite-name_tag { background-position: -1024px -704px}.mcsprite-nautilus_shell { background-position: -1056px -704px}.mcsprite-nether_brick { background-position: -1088px -704px}.mcsprite-nether_brick_block { background-position: -1120px -704px}.mcsprite-nether_brick_fence { background-position: -1152px -704px}.mcsprite-nether_brick_slab { background-position: -1184px -704px}.mcsprite-nether_brick_stairs { background-position: -1216px -704px}.mcsprite-nether_brick_wall { background-position: -1248px -704px}.mcsprite-nether_bricks { background-position: 0 -736px}.mcsprite-nether_gold_ore { background-position: -32px -736px}.mcsprite-nether_quartz { background-position: -64px -736px}.mcsprite-nether_quartz_ore { background-position: -96px -736px}.mcsprite-nether_sprouts { background-position: -128px -736px}.mcsprite-nether_sprouts_old { background-position: -160px -736px}.mcsprite-nether_star { background-position: -192px -736px}.mcsprite-nether_wart { background-position: -224px -736px}.mcsprite-nether_wart_block { background-position: -256px -736px}.mcsprite-netherite_axe { background-position: -288px -736px}.mcsprite-netherite_boots { background-position: -320px -736px}.mcsprite-netherite_chestplate { background-position: -352px -736px}.mcsprite-netherite_helmet { background-position: -384px -736px}.mcsprite-netherite_hoe { background-position: -416px -736px}.mcsprite-netherite_ingot { background-position: -448px -736px}.mcsprite-netherite_leggings { background-position: -480px -736px}.mcsprite-netherite_pickaxe { background-position: -512px -736px}.mcsprite-netherite_scrap { background-position: -544px -736px}.mcsprite-netherite_shovel { background-position: -576px -736px}.mcsprite-netherite_sword { background-position: -608px -736px}.mcsprite-netherrack { background-position: -640px -736px}.mcsprite-note_block { background-position: -672px -736px}.mcsprite-oak_boat { background-position: -704px -736px}.mcsprite-oak_button { background-position: -736px -736px}.mcsprite-oak_door { background-position: -768px -736px}.mcsprite-oak_fence { background-position: -800px -736px}.mcsprite-oak_fence_gate { background-position: -832px -736px}.mcsprite-oak_leaves { background-position: -864px -736px}.mcsprite-oak_log { background-position: -896px -736px}.mcsprite-oak_planks { background-position: -928px -736px}.mcsprite-oak_pressure_plate { background-position: -960px -736px}.mcsprite-oak_sapling { background-position: -992px -736px}.mcsprite-oak_sign { background-position: -1024px -736px}.mcsprite-oak_slab { background-position: -1056px -736px}.mcsprite-oak_stairs { background-position: -1088px -736px}.mcsprite-oak_trapdoor { background-position: -1120px -736px}.mcsprite-oak_wood { background-position: -1152px -736px}.mcsprite-oak_wood_button { background-position: -1184px -736px}.mcsprite-oak_wood_door { background-position: -1216px -736px}.mcsprite-oak_wood_fence { background-position: -1248px -736px}.mcsprite-oak_wood_fence_gate { background-position: 0 -768px}.mcsprite-oak_wood_planks { background-position: -32px -768px}.mcsprite-oak_wood_pressure_plate { background-position: -64px -768px}.mcsprite-oak_wood_sign { background-position: -96px -768px}.mcsprite-oak_wood_slab { background-position: -128px -768px}.mcsprite-oak_wood_stairs { background-position: -160px -768px}.mcsprite-oak_wood_trapdoor { background-position: -192px -768px}.mcsprite-observer { background-position: -224px -768px}.mcsprite-obsidian { background-position: -256px -768px}.mcsprite-ocean_explorer_map { background-position: -288px -768px}.mcsprite-ocelot_spawn_egg { background-position: -320px -768px}.mcsprite-ominous_shield { background-position: -352px -768px}.mcsprite-orange_banner { background-position: -384px -768px}.mcsprite-orange_bed { background-position: -416px -768px}.mcsprite-orange_bed_lce { background-position: -448px -768px}.mcsprite-orange_candle { background-position: -480px -768px}.mcsprite-orange_carpet { background-position: -512px -768px}.mcsprite-orange_concrete { background-position: -544px -768px}.mcsprite-orange_concrete_powder { background-position: -576px -768px}.mcsprite-orange_dye { background-position: -608px -768px}.mcsprite-orange_firework_star { background-position: -640px -768px}.mcsprite-orange_glazed_terracotta { background-position: -672px -768px}.mcsprite-orange_shield { background-position: -704px -768px}.mcsprite-orange_shulker_box { background-position: -736px -768px}.mcsprite-orange_stained_glass { background-position: -768px -768px}.mcsprite-orange_stained_glass_pane { background-position: -800px -768px}.mcsprite-orange_terracotta { background-position: -832px -768px}.mcsprite-orange_tulip { background-position: -864px -768px}.mcsprite-orange_wool { background-position: -896px -768px}.mcsprite-oxeye_daisy { background-position: -928px -768px}.mcsprite-oxidized_copper { background-position: -960px -768px}.mcsprite-oxidized_copper_block { background-position: -992px -768px}.mcsprite-oxidized_cut_copper { background-position: -1024px -768px}.mcsprite-oxidized_cut_copper_block { background-position: -1056px -768px}.mcsprite-oxidized_cut_copper_slab { background-position: -1088px -768px}.mcsprite-oxidized_cut_copper_stairs { background-position: -1120px -768px}.mcsprite-packed_ice { background-position: -1152px -768px}.mcsprite-painting { background-position: -1184px -768px}.mcsprite-panda_spawn_egg { background-position: -1216px -768px}.mcsprite-paper { background-position: -1248px -768px}.mcsprite-parrot_spawn_egg { background-position: 0 -800px}.mcsprite-peony { background-position: -32px -800px}.mcsprite-petrified_oak_slab { background-position: -64px -800px}.mcsprite-phantom_membrane { background-position: -96px -800px}.mcsprite-phantom_spawn_egg { background-position: -128px -800px}.mcsprite-pig_spawn_egg { background-position: -160px -800px}.mcsprite-piglin_brute_spawn_egg { background-position: -192px -800px}.mcsprite-piglin_spawn_egg { background-position: -224px -800px}.mcsprite-pillager_spawn_egg { background-position: -256px -800px}.mcsprite-pink_banner { background-position: -288px -800px}.mcsprite-pink_bed { background-position: -320px -800px}.mcsprite-pink_bed_lce { background-position: -352px -800px}.mcsprite-pink_candle { background-position: -384px -800px}.mcsprite-pink_carpet { background-position: -416px -800px}.mcsprite-pink_concrete { background-position: -448px -800px}.mcsprite-pink_concrete_powder { background-position: -480px -800px}.mcsprite-pink_dye { background-position: -512px -800px}.mcsprite-pink_firework_star { background-position: -544px -800px}.mcsprite-pink_glazed_terracotta { background-position: -576px -800px}.mcsprite-pink_shield { background-position: -608px -800px}.mcsprite-pink_shulker_box { background-position: -640px -800px}.mcsprite-pink_stained_glass { background-position: -672px -800px}.mcsprite-pink_stained_glass_pane { background-position: -704px -800px}.mcsprite-pink_terracotta { background-position: -736px -800px}.mcsprite-pink_tulip { background-position: -768px -800px}.mcsprite-pink_wool { background-position: -800px -800px}.mcsprite-piston { background-position: -832px -800px}.mcsprite-player_head { background-position: -864px -800px}.mcsprite-podzol { background-position: -896px -800px}.mcsprite-pointed_dripstone { background-position: -928px -800px}.mcsprite-poisonous_potato { background-position: -960px -800px}.mcsprite-polar_bear_spawn_egg { background-position: -992px -800px}.mcsprite-polished_andesite { background-position: -1024px -800px}.mcsprite-polished_andesite_slab { background-position: -1056px -800px}.mcsprite-polished_andesite_stairs { background-position: -1088px -800px}.mcsprite-polished_basalt { background-position: -1120px -800px}.mcsprite-polished_blackstone { background-position: -1152px -800px}.mcsprite-polished_blackstone_brick_slab { background-position: -1184px -800px}.mcsprite-polished_blackstone_brick_stairs { background-position: -1216px -800px}.mcsprite-polished_blackstone_brick_wall { background-position: -1248px -800px}.mcsprite-polished_blackstone_bricks { background-position: 0 -832px}.mcsprite-polished_blackstone_button { background-position: -32px -832px}.mcsprite-polished_blackstone_pressure_plate { background-position: -64px -832px}.mcsprite-polished_blackstone_slab { background-position: -96px -832px}.mcsprite-polished_blackstone_stairs { background-position: -128px -832px}.mcsprite-polished_blackstone_wall { background-position: -160px -832px}.mcsprite-polished_deepslate { background-position: -192px -832px}.mcsprite-polished_deepslate_slab { background-position: -224px -832px}.mcsprite-polished_deepslate_stairs { background-position: -256px -832px}.mcsprite-polished_deepslate_wall { background-position: -288px -832px}.mcsprite-polished_diorite { background-position: -320px -832px}.mcsprite-polished_diorite_slab { background-position: -352px -832px}.mcsprite-polished_diorite_stairs { background-position: -384px -832px}.mcsprite-polished_granite { background-position: -416px -832px}.mcsprite-polished_granite_slab { background-position: -448px -832px}.mcsprite-polished_granite_stairs { background-position: -480px -832px}.mcsprite-popped_chorus_fruit { background-position: -512px -832px}.mcsprite-poppy { background-position: -544px -832px}.mcsprite-portal { background-position: -576px -832px}.mcsprite-potato { background-position: -608px -832px}.mcsprite-potion_of_decay { background-position: -640px -832px}.mcsprite-potion_of_fire_resistance { background-position: -672px -832px}.mcsprite-potion_of_harming { background-position: -704px -832px}.mcsprite-potion_of_healing { background-position: -736px -832px}.mcsprite-potion_of_invisibility { background-position: -768px -832px}.mcsprite-potion_of_leaping { background-position: -800px -832px}.mcsprite-potion_of_levitation { background-position: -832px -832px}.mcsprite-potion_of_luck { background-position: -864px -832px}.mcsprite-potion_of_night_vision { background-position: -896px -832px}.mcsprite-potion_of_poison { background-position: -928px -832px}.mcsprite-potion_of_regeneration { background-position: -960px -832px}.mcsprite-potion_of_slow_falling { background-position: -992px -832px}.mcsprite-potion_of_slowness { background-position: -1024px -832px}.mcsprite-potion_of_strength { background-position: -1056px -832px}.mcsprite-potion_of_swiftness { background-position: -1088px -832px}.mcsprite-potion_of_the_turtle_master { background-position: -1120px -832px}.mcsprite-potion_of_water_breathing { background-position: -1152px -832px}.mcsprite-potion_of_weakness { background-position: -1184px -832px}.mcsprite-powder_snow { background-position: -1216px -832px}.mcsprite-powder_snow_bucket { background-position: -1248px -832px}.mcsprite-powered_rail { background-position: 0 -864px}.mcsprite-prismarine { background-position: -32px -864px}.mcsprite-prismarine_brick_slab { background-position: -64px -864px}.mcsprite-prismarine_brick_stairs { background-position: -96px -864px}.mcsprite-prismarine_brick_stairs_old { background-position: -128px -864px}.mcsprite-prismarine_bricks { background-position: -160px -864px}.mcsprite-prismarine_bricks_slab { background-position: -192px -864px}.mcsprite-prismarine_crystals { background-position: -224px -864px}.mcsprite-prismarine_shard { background-position: -256px -864px}.mcsprite-prismarine_wall { background-position: -288px -864px}.mcsprite-pufferfish { background-position: -320px -864px}.mcsprite-pufferfish_spawn_egg { background-position: -352px -864px}.mcsprite-pumpkin { background-position: -384px -864px}.mcsprite-pumpkin_pie { background-position: -416px -864px}.mcsprite-pumpkin_seeds { background-position: -448px -864px}.mcsprite-purple_banner { background-position: -480px -864px}.mcsprite-purple_bed { background-position: -512px -864px}.mcsprite-purple_bed_lce { background-position: -544px -864px}.mcsprite-purple_candle { background-position: -576px -864px}.mcsprite-purple_carpet { background-position: -608px -864px}.mcsprite-purple_concrete { background-position: -640px -864px}.mcsprite-purple_concrete_powder { background-position: -672px -864px}.mcsprite-purple_dye { background-position: -704px -864px}.mcsprite-purple_firework_star { background-position: -736px -864px}.mcsprite-purple_glazed_terracotta { background-position: -768px -864px}.mcsprite-purple_shield { background-position: -800px -864px}.mcsprite-purple_shulker_box { background-position: -832px -864px}.mcsprite-purple_stained_glass { background-position: -864px -864px}.mcsprite-purple_stained_glass_pane { background-position: -896px -864px}.mcsprite-purple_terracotta { background-position: -928px -864px}.mcsprite-purple_wool { background-position: -960px -864px}.mcsprite-purpur_block { background-position: -992px -864px}.mcsprite-purpur_pillar { background-position: -1024px -864px}.mcsprite-purpur_slab { background-position: -1056px -864px}.mcsprite-purpur_stairs { background-position: -1088px -864px}.mcsprite-quartz_bricks { background-position: -1120px -864px}.mcsprite-quartz_pillar { background-position: -1152px -864px}.mcsprite-quartz_slab { background-position: -1184px -864px}.mcsprite-quartz_stairs { background-position: -1216px -864px}.mcsprite-rabbit_hide { background-position: -1248px -864px}.mcsprite-rabbit_spawn_egg { background-position: 0 -896px}.mcsprite-rabbit_stew { background-position: -32px -896px}.mcsprite-rabbits_foot { background-position: -64px -896px}.mcsprite-rail { background-position: -96px -896px}.mcsprite-ravager_spawn_egg { background-position: -128px -896px}.mcsprite-raw_beef { background-position: -160px -896px}.mcsprite-raw_chicken { background-position: -192px -896px}.mcsprite-raw_cod { background-position: -224px -896px}.mcsprite-raw_copper { background-position: -256px -896px}.mcsprite-raw_fish { background-position: -288px -896px}.mcsprite-raw_gold { background-position: -320px -896px}.mcsprite-raw_iron { background-position: -352px -896px}.mcsprite-raw_mutton { background-position: -384px -896px}.mcsprite-raw_porkchop { background-position: -416px -896px}.mcsprite-raw_rabbit { background-position: -448px -896px}.mcsprite-raw_salmon { background-position: -480px -896px}.mcsprite-red_banner { background-position: -512px -896px}.mcsprite-red_bed { background-position: -544px -896px}.mcsprite-red_bed_lce { background-position: -576px -896px}.mcsprite-red_candle { background-position: -608px -896px}.mcsprite-red_carpet { background-position: -640px -896px}.mcsprite-red_concrete { background-position: -672px -896px}.mcsprite-red_concrete_powder { background-position: -704px -896px}.mcsprite-red_dye { background-position: -736px -896px}.mcsprite-red_firework_star { background-position: -768px -896px}.mcsprite-red_glazed_terracotta { background-position: -800px -896px}.mcsprite-red_mushroom { background-position: -832px -896px}.mcsprite-red_mushroom_block { background-position: -864px -896px}.mcsprite-red_nether_brick_slab { background-position: -896px -896px}.mcsprite-red_nether_brick_stairs { background-position: -928px -896px}.mcsprite-red_nether_brick_wall { background-position: -960px -896px}.mcsprite-red_nether_bricks { background-position: -992px -896px}.mcsprite-red_sand { background-position: -1024px -896px}.mcsprite-red_sandstone { background-position: -1056px -896px}.mcsprite-red_sandstone_slab { background-position: -1088px -896px}.mcsprite-red_sandstone_stairs { background-position: -1120px -896px}.mcsprite-red_sandstone_wall { background-position: -1152px -896px}.mcsprite-red_shield { background-position: -1184px -896px}.mcsprite-red_shulker_box { background-position: -1216px -896px}.mcsprite-red_stained_glass { background-position: -1248px -896px}.mcsprite-red_stained_glass_pane { background-position: 0 -928px}.mcsprite-red_terracotta { background-position: -32px -928px}.mcsprite-red_tulip { background-position: -64px -928px}.mcsprite-red_wool { background-position: -96px -928px}.mcsprite-redstone { background-position: -128px -928px}.mcsprite-redstone_comparator { background-position: -160px -928px}.mcsprite-redstone_dust { background-position: -192px -928px}.mcsprite-redstone_lamp { background-position: -224px -928px}.mcsprite-redstone_ore { background-position: -256px -928px}.mcsprite-redstone_repeater { background-position: -288px -928px}.mcsprite-redstone_torch { background-position: -320px -928px}.mcsprite-respawn_anchor { background-position: -352px -928px}.mcsprite-rooted_dirt { background-position: -384px -928px}.mcsprite-rose_bush { background-position: -416px -928px}.mcsprite-rose_red { background-position: -448px -928px}.mcsprite-rotten_flesh { background-position: -480px -928px}.mcsprite-saddle { background-position: -512px -928px}.mcsprite-salmon_spawn_egg { background-position: -544px -928px}.mcsprite-sand { background-position: -576px -928px}.mcsprite-sandstone { background-position: -608px -928px}.mcsprite-sandstone_slab { background-position: -640px -928px}.mcsprite-sandstone_stairs { background-position: -672px -928px}.mcsprite-sandstone_wall { background-position: -704px -928px}.mcsprite-scaffolding { background-position: -736px -928px}.mcsprite-sculk_sensor { background-position: -768px -928px}.mcsprite-scute { background-position: -800px -928px}.mcsprite-sea_lantern { background-position: -832px -928px}.mcsprite-sea_pickle { background-position: -864px -928px}.mcsprite-seagrass { background-position: -896px -928px}.mcsprite-seeds { background-position: -928px -928px}.mcsprite-shears { background-position: -960px -928px}.mcsprite-sheep_spawn_egg { background-position: -992px -928px}.mcsprite-shield { background-position: -1024px -928px}.mcsprite-shroomlight { background-position: -1056px -928px}.mcsprite-shrub_lce { background-position: -1088px -928px}.mcsprite-shulker_box { background-position: -1120px -928px}.mcsprite-shulker_shell { background-position: -1152px -928px}.mcsprite-shulker_spawn_egg { background-position: -1184px -928px}.mcsprite-silverfish_spawn_egg { background-position: -1216px -928px}.mcsprite-skeleton_horse_spawn_egg { background-position: -1248px -928px}.mcsprite-skeleton_skull { background-position: 0 -960px}.mcsprite-skeleton_spawn_egg { background-position: -32px -960px}.mcsprite-slime_block { background-position: -64px -960px}.mcsprite-slime_spawn_egg { background-position: -96px -960px}.mcsprite-slimeball { background-position: -128px -960px}.mcsprite-small_amethyst_bud { background-position: -160px -960px}.mcsprite-small_dripleaf { background-position: -192px -960px}.mcsprite-smithing_table { background-position: -224px -960px}.mcsprite-smoker { background-position: -256px -960px}.mcsprite-smooth_basalt { background-position: -288px -960px}.mcsprite-smooth_quartz { background-position: -320px -960px}.mcsprite-smooth_quartz_block { background-position: -352px -960px}.mcsprite-smooth_quartz_slab { background-position: -384px -960px}.mcsprite-smooth_quartz_stairs { background-position: -416px -960px}.mcsprite-smooth_red_sandstone { background-position: -448px -960px}.mcsprite-smooth_red_sandstone_slab { background-position: -480px -960px}.mcsprite-smooth_red_sandstone_stairs { background-position: -512px -960px}.mcsprite-smooth_sandstone { background-position: -544px -960px}.mcsprite-smooth_sandstone_slab { background-position: -576px -960px}.mcsprite-smooth_sandstone_stairs { background-position: -608px -960px}.mcsprite-smooth_stone { background-position: -640px -960px}.mcsprite-smooth_stone_bricks { background-position: -672px -960px}.mcsprite-smooth_stone_slab { background-position: -704px -960px}.mcsprite-snow { background-position: -736px -960px}.mcsprite-snow_block { background-position: -768px -960px}.mcsprite-snowball { background-position: -800px -960px}.mcsprite-soul_campfire { background-position: -832px -960px}.mcsprite-soul_lantern { background-position: -864px -960px}.mcsprite-soul_sand { background-position: -896px -960px}.mcsprite-soul_soil { background-position: -928px -960px}.mcsprite-soul_torch { background-position: -960px -960px}.mcsprite-spawn_agent { background-position: -992px -960px}.mcsprite-spawn_bat { background-position: -1024px -960px}.mcsprite-spawn_bee { background-position: -1056px -960px}.mcsprite-spawn_blaze { background-position: -1088px -960px}.mcsprite-spawn_cat { background-position: -1120px -960px}.mcsprite-spawn_cave_spider { background-position: -1152px -960px}.mcsprite-spawn_chicken { background-position: -1184px -960px}.mcsprite-spawn_cod { background-position: -1216px -960px}.mcsprite-spawn_cow { background-position: -1248px -960px}.mcsprite-spawn_creeper { background-position: 0 -992px}.mcsprite-spawn_dolphin { background-position: -32px -992px}.mcsprite-spawn_donkey { background-position: -64px -992px}.mcsprite-spawn_drowned { background-position: -96px -992px}.mcsprite-spawn_elder_guardian { background-position: -128px -992px}.mcsprite-spawn_enderman { background-position: -160px -992px}.mcsprite-spawn_endermite { background-position: -192px -992px}.mcsprite-spawn_evoker { background-position: -224px -992px}.mcsprite-spawn_fox { background-position: -256px -992px}.mcsprite-spawn_ghast { background-position: -288px -992px}.mcsprite-spawn_goat { background-position: -320px -992px}.mcsprite-spawn_guardian { background-position: -352px -992px}.mcsprite-spawn_horse { background-position: -384px -992px}.mcsprite-spawn_husk { background-position: -416px -992px}.mcsprite-spawn_llama { background-position: -448px -992px}.mcsprite-spawn_magma_cube { background-position: -480px -992px}.mcsprite-spawn_mask { background-position: -512px -992px}.mcsprite-spawn_mooshroom { background-position: -544px -992px}.mcsprite-spawn_mule { background-position: -576px -992px}.mcsprite-spawn_npc { background-position: -608px -992px}.mcsprite-spawn_ocelot { background-position: -640px -992px}.mcsprite-spawn_panda { background-position: -672px -992px}.mcsprite-spawn_parrot { background-position: -704px -992px}.mcsprite-spawn_phantom { background-position: -736px -992px}.mcsprite-spawn_pig { background-position: -768px -992px}.mcsprite-spawn_pillager { background-position: -800px -992px}.mcsprite-spawn_polar_bear { background-position: -832px -992px}.mcsprite-spawn_pufferfish { background-position: -864px -992px}.mcsprite-spawn_rabbit { background-position: -896px -992px}.mcsprite-spawn_ravager { background-position: -928px -992px}.mcsprite-spawn_salmon { background-position: -960px -992px}.mcsprite-spawn_sheep { background-position: -992px -992px}.mcsprite-spawn_shulker { background-position: -1024px -992px}.mcsprite-spawn_silverfish { background-position: -1056px -992px}.mcsprite-spawn_skeleton { background-position: -1088px -992px}.mcsprite-spawn_skeleton_horse { background-position: -1120px -992px}.mcsprite-spawn_slime { background-position: -1152px -992px}.mcsprite-spawn_spider { background-position: -1184px -992px}.mcsprite-spawn_squid { background-position: -1216px -992px}.mcsprite-spawn_stray { background-position: -1248px -992px}.mcsprite-spawn_strider { background-position: 0 -1024px}.mcsprite-spawn_trader_llama { background-position: -32px -1024px}.mcsprite-spawn_tropical_fish { background-position: -64px -1024px}.mcsprite-spawn_turtle { background-position: -96px -1024px}.mcsprite-spawn_vex { background-position: -128px -1024px}.mcsprite-spawn_villager { background-position: -160px -1024px}.mcsprite-spawn_vindicator { background-position: -192px -1024px}.mcsprite-spawn_wandering_trader { background-position: -224px -1024px}.mcsprite-spawn_witch { background-position: -256px -1024px}.mcsprite-spawn_wither_skeleton { background-position: -288px -1024px}.mcsprite-spawn_wolf { background-position: -320px -1024px}.mcsprite-spawn_zoglin { background-position: -352px -1024px}.mcsprite-spawn_zombie { background-position: -384px -1024px}.mcsprite-spawn_zombie_horse { background-position: -416px -1024px}.mcsprite-spawn_zombie_pigman { background-position: -448px -1024px}.mcsprite-spawn_zombie_villager { background-position: -480px -1024px}.mcsprite-spawner { background-position: -512px -1024px}.mcsprite-spectral_arrow { background-position: -544px -1024px}.mcsprite-spider_eye { background-position: -576px -1024px}.mcsprite-spider_spawn_egg { background-position: -608px -1024px}.mcsprite-splash_mundane_potion { background-position: -640px -1024px}.mcsprite-splash_potion_of_decay { background-position: -672px -1024px}.mcsprite-splash_potion_of_fire_resistance { background-position: -704px -1024px}.mcsprite-splash_potion_of_harming { background-position: -736px -1024px}.mcsprite-splash_potion_of_healing { background-position: -768px -1024px}.mcsprite-splash_potion_of_invisibility { background-position: -800px -1024px}.mcsprite-splash_potion_of_leaping { background-position: -832px -1024px}.mcsprite-splash_potion_of_levitation { background-position: -864px -1024px}.mcsprite-splash_potion_of_luck { background-position: -896px -1024px}.mcsprite-splash_potion_of_night_vision { background-position: -928px -1024px}.mcsprite-splash_potion_of_poison { background-position: -960px -1024px}.mcsprite-splash_potion_of_regeneration { background-position: -992px -1024px}.mcsprite-splash_potion_of_slow_falling { background-position: -1024px -1024px}.mcsprite-splash_potion_of_slowness { background-position: -1056px -1024px}.mcsprite-splash_potion_of_strength { background-position: -1088px -1024px}.mcsprite-splash_potion_of_swiftness { background-position: -1120px -1024px}.mcsprite-splash_potion_of_the_turtle_master { background-position: -1152px -1024px}.mcsprite-splash_potion_of_water_breathing { background-position: -1184px -1024px}.mcsprite-splash_potion_of_weakness { background-position: -1216px -1024px}.mcsprite-splash_water_bottle { background-position: -1248px -1024px}.mcsprite-sponge { background-position: 0 -1056px}.mcsprite-spore_blossom { background-position: -32px -1056px}.mcsprite-spruce_boat { background-position: -64px -1056px}.mcsprite-spruce_button { background-position: -96px -1056px}.mcsprite-spruce_door { background-position: -128px -1056px}.mcsprite-spruce_fence { background-position: -160px -1056px}.mcsprite-spruce_fence_gate { background-position: -192px -1056px}.mcsprite-spruce_leaves { background-position: -224px -1056px}.mcsprite-spruce_log { background-position: -256px -1056px}.mcsprite-spruce_planks { background-position: -288px -1056px}.mcsprite-spruce_pressure_plate { background-position: -320px -1056px}.mcsprite-spruce_sapling { background-position: -352px -1056px}.mcsprite-spruce_sign { background-position: -384px -1056px}.mcsprite-spruce_slab { background-position: -416px -1056px}.mcsprite-spruce_stairs { background-position: -448px -1056px}.mcsprite-spruce_trapdoor { background-position: -480px -1056px}.mcsprite-spruce_wood { background-position: -512px -1056px}.mcsprite-spruce_wood_button { background-position: -544px -1056px}.mcsprite-spruce_wood_door { background-position: -576px -1056px}.mcsprite-spruce_wood_fence { background-position: -608px -1056px}.mcsprite-spruce_wood_fence_gate { background-position: -640px -1056px}.mcsprite-spruce_wood_planks { background-position: -672px -1056px}.mcsprite-spruce_wood_pressure_plate { background-position: -704px -1056px}.mcsprite-spruce_wood_sign { background-position: -736px -1056px}.mcsprite-spruce_wood_slab { background-position: -768px -1056px}.mcsprite-spruce_wood_stairs { background-position: -800px -1056px}.mcsprite-spruce_wood_trapdoor { background-position: -832px -1056px}.mcsprite-spyglass { background-position: -864px -1056px}.mcsprite-squid_spawn_egg { background-position: -896px -1056px}.mcsprite-steak { background-position: -928px -1056px}.mcsprite-stick { background-position: -960px -1056px}.mcsprite-sticky_piston { background-position: -992px -1056px}.mcsprite-stone { background-position: -1024px -1056px}.mcsprite-stone_axe { background-position: -1056px -1056px}.mcsprite-stone_brick_slab { background-position: -1088px -1056px}.mcsprite-stone_brick_stairs { background-position: -1120px -1056px}.mcsprite-stone_brick_wall { background-position: -1152px -1056px}.mcsprite-stone_bricks { background-position: -1184px -1056px}.mcsprite-stone_bricks_monster_egg { background-position: -1216px -1056px}.mcsprite-stone_button { background-position: -1248px -1056px}.mcsprite-stone_hoe { background-position: 0 -1088px}.mcsprite-stone_monster_egg { background-position: -32px -1088px}.mcsprite-stone_pickaxe { background-position: -64px -1088px}.mcsprite-stone_pressure_plate { background-position: -96px -1088px}.mcsprite-stone_shovel { background-position: -128px -1088px}.mcsprite-stone_slab { background-position: -160px -1088px}.mcsprite-stone_stairs { background-position: -192px -1088px}.mcsprite-stone_sword { background-position: -224px -1088px}.mcsprite-stray_spawn_egg { background-position: -256px -1088px}.mcsprite-strider_spawn_egg { background-position: -288px -1088px}.mcsprite-string { background-position: -320px -1088px}.mcsprite-stripped_acacia_log { background-position: -352px -1088px}.mcsprite-stripped_acacia_wood { background-position: -384px -1088px}.mcsprite-stripped_birch_log { background-position: -416px -1088px}.mcsprite-stripped_birch_wood { background-position: -448px -1088px}.mcsprite-stripped_crimson_hyphae { background-position: -480px -1088px}.mcsprite-stripped_crimson_stem { background-position: -512px -1088px}.mcsprite-stripped_dark_oak_log { background-position: -544px -1088px}.mcsprite-stripped_dark_oak_wood { background-position: -576px -1088px}.mcsprite-stripped_jungle_log { background-position: -608px -1088px}.mcsprite-stripped_jungle_wood { background-position: -640px -1088px}.mcsprite-stripped_oak_log { background-position: -672px -1088px}.mcsprite-stripped_oak_wood { background-position: -704px -1088px}.mcsprite-stripped_spruce_log { background-position: -736px -1088px}.mcsprite-stripped_spruce_wood { background-position: -768px -1088px}.mcsprite-stripped_warped_hyphae { background-position: -800px -1088px}.mcsprite-stripped_warped_stem { background-position: -832px -1088px}.mcsprite-structure_block { background-position: -864px -1088px}.mcsprite-structure_void { background-position: -896px -1088px}.mcsprite-sugar { background-position: -928px -1088px}.mcsprite-sugar_cane { background-position: -960px -1088px}.mcsprite-sunflower { background-position: -992px -1088px}.mcsprite-suspicious_stew { background-position: -1024px -1088px}.mcsprite-sweet_berries { background-position: -1056px -1088px}.mcsprite-tall_grass { background-position: -1088px -1088px}.mcsprite-target { background-position: -1120px -1088px}.mcsprite-terracotta { background-position: -1152px -1088px}.mcsprite-thick_lingering_potion { background-position: -1184px -1088px}.mcsprite-thick_potion { background-position: -1216px -1088px}.mcsprite-thick_splash_potion { background-position: -1248px -1088px}.mcsprite-tinted_glass { background-position: 0 -1120px}.mcsprite-tipped_arrow { background-position: -32px -1120px}.mcsprite-tnt { background-position: -64px -1120px}.mcsprite-top_snow { background-position: -96px -1120px}.mcsprite-torch { background-position: -128px -1120px}.mcsprite-totem_of_undying { background-position: -160px -1120px}.mcsprite-trader_llama_spawn_egg { background-position: -192px -1120px}.mcsprite-trapped_chest { background-position: -224px -1120px}.mcsprite-treasure_map { background-position: -256px -1120px}.mcsprite-trident { background-position: -288px -1120px}.mcsprite-tripwire_hook { background-position: -320px -1120px}.mcsprite-tropical_fish { background-position: -352px -1120px}.mcsprite-tropical_fish_spawn_egg { background-position: -384px -1120px}.mcsprite-tube_coral { background-position: -416px -1120px}.mcsprite-tube_coral_block { background-position: -448px -1120px}.mcsprite-tube_coral_fan { background-position: -480px -1120px}.mcsprite-tuff { background-position: -512px -1120px}.mcsprite-turtle_egg { background-position: -544px -1120px}.mcsprite-turtle_helmet { background-position: -576px -1120px}.mcsprite-turtle_shell { background-position: -608px -1120px}.mcsprite-turtle_spawn_egg { background-position: -640px -1120px}.mcsprite-twisting_vines { background-position: -672px -1120px}.mcsprite-uncraftable_lingering_potion { background-position: -704px -1120px}.mcsprite-uncraftable_potion { background-position: -736px -1120px}.mcsprite-uncraftable_splash_potion { background-position: -768px -1120px}.mcsprite-uncraftable_tipped_arrow { background-position: -800px -1120px}.mcsprite-vex_spawn_egg { background-position: -832px -1120px}.mcsprite-villager_spawn_egg { background-position: -864px -1120px}.mcsprite-vindicator_spawn_egg { background-position: -896px -1120px}.mcsprite-vines { background-position: -928px -1120px}.mcsprite-void_air { background-position: -960px -1120px}.mcsprite-wandering_trader_spawn_egg { background-position: -992px -1120px}.mcsprite-warped_button { background-position: -1024px -1120px}.mcsprite-warped_door { background-position: -1056px -1120px}.mcsprite-warped_fence { background-position: -1088px -1120px}.mcsprite-warped_fence_gate { background-position: -1120px -1120px}.mcsprite-warped_fungus { background-position: -1152px -1120px}.mcsprite-warped_fungus_on_a_stick { background-position: -1184px -1120px}.mcsprite-warped_hyphae { background-position: -1216px -1120px}.mcsprite-warped_nylium { background-position: -1248px -1120px}.mcsprite-warped_planks { background-position: 0 -1152px}.mcsprite-warped_pressure_plate { background-position: -32px -1152px}.mcsprite-warped_roots { background-position: -64px -1152px}.mcsprite-warped_sign { background-position: -96px -1152px}.mcsprite-warped_slab { background-position: -128px -1152px}.mcsprite-warped_stairs { background-position: -160px -1152px}.mcsprite-warped_stem { background-position: -192px -1152px}.mcsprite-warped_trapdoor { background-position: -224px -1152px}.mcsprite-warped_wart_block { background-position: -256px -1152px}.mcsprite-water { background-position: -288px -1152px}.mcsprite-water_bottle { background-position: -320px -1152px}.mcsprite-water_bucket { background-position: -352px -1152px}.mcsprite-waxed_block_of_copper { background-position: -384px -1152px}.mcsprite-waxed_copper { background-position: -416px -1152px}.mcsprite-waxed_copper_block { background-position: -448px -1152px}.mcsprite-waxed_cut_copper { background-position: -480px -1152px}.mcsprite-waxed_cut_copper_block { background-position: -512px -1152px}.mcsprite-waxed_cut_copper_slab { background-position: -544px -1152px}.mcsprite-waxed_cut_copper_stairs { background-position: -576px -1152px}.mcsprite-waxed_exposed_copper { background-position: -608px -1152px}.mcsprite-waxed_exposed_copper_block { background-position: -640px -1152px}.mcsprite-waxed_exposed_cut_copper { background-position: -672px -1152px}.mcsprite-waxed_exposed_cut_copper_block { background-position: -704px -1152px}.mcsprite-waxed_exposed_cut_copper_slab { background-position: -736px -1152px}.mcsprite-waxed_exposed_cut_copper_stairs { background-position: -768px -1152px}.mcsprite-waxed_oxidized_copper { background-position: -800px -1152px}.mcsprite-waxed_oxidized_copper_block { background-position: -832px -1152px}.mcsprite-waxed_oxidized_cut_copper { background-position: -864px -1152px}.mcsprite-waxed_oxidized_cut_copper_block { background-position: -896px -1152px}.mcsprite-waxed_oxidized_cut_copper_slab { background-position: -928px -1152px}.mcsprite-waxed_oxidized_cut_copper_stairs { background-position: -960px -1152px}.mcsprite-waxed_weathered_copper { background-position: -992px -1152px}.mcsprite-waxed_weathered_copper_block { background-position: -1024px -1152px}.mcsprite-waxed_weathered_cut_copper { background-position: -1056px -1152px}.mcsprite-waxed_weathered_cut_copper_block { background-position: -1088px -1152px}.mcsprite-waxed_weathered_cut_copper_slab { background-position: -1120px -1152px}.mcsprite-waxed_weathered_cut_copper_stairs { background-position: -1152px -1152px}.mcsprite-weathered_copper { background-position: -1184px -1152px}.mcsprite-weathered_copper_block { background-position: -1216px -1152px}.mcsprite-weathered_cut_copper { background-position: -1248px -1152px}.mcsprite-weathered_cut_copper_block { background-position: 0 -1184px}.mcsprite-weathered_cut_copper_slab { background-position: -32px -1184px}.mcsprite-weathered_cut_copper_stairs { background-position: -64px -1184px}.mcsprite-weeping_vines { background-position: -96px -1184px}.mcsprite-wet_sponge { background-position: -128px -1184px}.mcsprite-wheat { background-position: -160px -1184px}.mcsprite-wheat_seeds { background-position: -192px -1184px}.mcsprite-white_banner { background-position: -224px -1184px}.mcsprite-white_bed { background-position: -256px -1184px}.mcsprite-white_bed_lce { background-position: -288px -1184px}.mcsprite-white_candle { background-position: -320px -1184px}.mcsprite-white_carpet { background-position: -352px -1184px}.mcsprite-white_concrete { background-position: -384px -1184px}.mcsprite-white_concrete_powder { background-position: -416px -1184px}.mcsprite-white_dye { background-position: -448px -1184px}.mcsprite-white_firework_star { background-position: -480px -1184px}.mcsprite-white_glazed_terracotta { background-position: -512px -1184px}.mcsprite-white_shield { background-position: -544px -1184px}.mcsprite-white_shulker_box { background-position: -576px -1184px}.mcsprite-white_stained_glass { background-position: -608px -1184px}.mcsprite-white_stained_glass_pane { background-position: -640px -1184px}.mcsprite-white_terracotta { background-position: -672px -1184px}.mcsprite-white_tulip { background-position: -704px -1184px}.mcsprite-white_wool { background-position: -736px -1184px}.mcsprite-witch_spawn_egg { background-position: -768px -1184px}.mcsprite-wither_rose { background-position: -800px -1184px}.mcsprite-wither_skeleton_skull { background-position: -832px -1184px}.mcsprite-wither_skeleton_spawn_egg { background-position: -864px -1184px}.mcsprite-wolf_spawn_egg { background-position: -896px -1184px}.mcsprite-wooden_axe { background-position: -928px -1184px}.mcsprite-wooden_hoe { background-position: -960px -1184px}.mcsprite-wooden_pickaxe { background-position: -992px -1184px}.mcsprite-wooden_shovel { background-position: -1024px -1184px}.mcsprite-wooden_slab { background-position: -1056px -1184px}.mcsprite-wooden_sword { background-position: -1088px -1184px}.mcsprite-woodland_explorer_map { background-position: -1120px -1184px}.mcsprite-written_book { background-position: -1152px -1184px}.mcsprite-yellow_banner { background-position: -1184px -1184px}.mcsprite-yellow_bed { background-position: -1216px -1184px}.mcsprite-yellow_bed_lce { background-position: -1248px -1184px}.mcsprite-yellow_candle { background-position: 0 -1216px}.mcsprite-yellow_carpet { background-position: -32px -1216px}.mcsprite-yellow_concrete { background-position: -64px -1216px}.mcsprite-yellow_concrete_powder { background-position: -96px -1216px}.mcsprite-yellow_dye { background-position: -128px -1216px}.mcsprite-yellow_firework_star { background-position: -160px -1216px}.mcsprite-yellow_glazed_terracotta { background-position: -192px -1216px}.mcsprite-yellow_shield { background-position: -224px -1216px}.mcsprite-yellow_shulker_box { background-position: -256px -1216px}.mcsprite-yellow_stained_glass { background-position: -288px -1216px}.mcsprite-yellow_stained_glass_pane { background-position: -320px -1216px}.mcsprite-yellow_terracotta { background-position: -352px -1216px}.mcsprite-yellow_wool { background-position: -384px -1216px}.mcsprite-zoglin_spawn_egg { background-position: -416px -1216px}.mcsprite-zombie_head { background-position: -448px -1216px}.mcsprite-zombie_horse_spawn_egg { background-position: -480px -1216px}.mcsprite-zombie_pigman_spawn_egg { background-position: -512px -1216px}.mcsprite-zombie_spawn_egg { background-position: -544px -1216px}.mcsprite-zombie_villager_spawn_egg { background-position: -576px -1216px}.mcsprite-zombified_piglin_spawn_egg { background-position: -608px -1216px}.toc { display: none; position: relative; margin: 1em 0; padding: .2em .5em; background-color: #f8f9fa; border: solid 1px #eaecf0; box-sizing: border-box}.toctogglecheckbox~ul { visibility: hidden; height: 0}.toctogglecheckbox:not(:checked)~ul { visibility: visible; padding-bottom: 20px; height: auto}.toctitle { padding: 0 25px 0 32px}.toctitle .mw-ui-icon { position: absolute; left: 0}.toctitle .toctogglespan+.mw-ui-icon { top: 8px; right: 0; left: auto}.toctogglelabel { cursor: pointer; position: absolute; left: 0; top: 0; right: 0; height: 50px; z-index: 1}.client-js .toc .toctitle { visibility: hidden; background-position: right center; font-weight: 700; border-bottom: 0}.client-js .toc .toctitle h2 { display: inline-block; font-family: -apple-system,blinkmacsystemfont,segoe ui,roboto,lato,helvetica,arial,sans-serif; font-size: 1.125em; vertical-align: middle}.client-js .toc .tocnumber { display: none}.client-js .toc>ul { margin: 0 22.85714286em 0 32px; padding-left: 0; font-size: .875em}.client-js .toc ul { list-style: none}@media screen and (min-width: 720px) { .client-js .toc { display:table } .client-js .toc .toctitle { visibility: visible }}body { font-family: -apple-system,blinkmacsystemfont,segoe ui,roboto,lato,helvetica,arial,sans-serif; line-height: 1.4; -webkit-tap-highlight-color: rgba(0,0,0,.2); overflow-y: scroll}.content { line-height: 1.65; word-wrap: break-word}.content .center { width: 100%; text-align: center}.content .center>*,.content .center .thumb { margin-left: auto; margin-right: auto}@media all and (max-width: 320px - 1) { html { font-size:80% } .content { margin: 0 12px }}.nomobile { display: none!important}@supports(font: -apple-system-body) { html { font:-apple-system-body } body { font-size: 94.11764706% } @media all and (max-width: 320px - 1) { body { font-size:75.29411765% } }}.content figure,.content .thumb { margin: .6em 0}.content figure .thumbinner,.content .thumb .thumbinner { margin: 0 auto; max-width: 100%!important}.content figcaption,.content .thumbcaption { margin: .5em 0 0; font-size: .8125em; line-height: 1.5; padding: 0!important; color: #54595d}.content .thumbcaption { width: auto!important}.content .mw-image-border,.content .thumbborder { border: 1px solid #c8ccd1}.content .magnify { display: none}.content img { vertical-align: middle}.content .floatright { clear: right; float: right; margin: 0 0 .6em .6em}.content .floatleft { clear: left; float: left; margin: 0 .6em .6em 0}.content a>img,.content noscript>img { max-width: 100%!important; height: auto!important}.content .noresize { max-width: 100%; overflow-x: auto}.content .noresize a>img { max-width: none!important}h1 { font-size: 1.7em}h2 { font-size: 1.5em}h3 { font-size: 1.2em; font-weight: 700}h4 { font-weight: 700}.pre-content h1,.content h1,.content h2 { font-family: linux libertine,helvetica,georgia,times,serif}.pre-content h1,.content h1,.content h2,h3,h4,h5,h6 { line-height: 1.3; word-wrap: break-word; word-break: break-word}.content h2,.content h3,.content h4,.content h5,.content h6 { padding: .5em 0}.content p+h3 { margin-top: 1.5em}.content {}.content ol { padding-left: 2.25em}.content ul { list-style-type: disc; padding-left: 1em}.content ul>li>ul { list-style-type: circle}.content ul>li>ul>li>ul { list-style-type: square}.content ol ol,.content ul ol,.content ol ul,.content ul ul { margin-left: 1em}.content li { margin-bottom: 10px}.content li:last-child { margin-bottom: inherit}dl { margin-left: 1em}dl dt { font-weight: 700}dl dd { display: block; overflow: auto}body.mw-hide-empty-elt .mw-empty-elt { display: none}a:not([href]) { color: #3f7dfb; cursor: pointer}a { color: #3f7dfb; text-decoration: none}a:visited { color: #ba91ff}a:active { color: #986be5}a:hover { text-decoration: underline}a.new,a.new:visited,a.new:hover { color: #d33}a.new>*,a.new:visited>*,a.new:hover>* { color: #d33}a.external { background-size: 10px; background-repeat: no-repeat; background-position: center right; padding-right: 13px}.return-link { display: block; font-size: .875em; margin-top: 1.5em}.plainlinks a { background: 0 0!important; padding: 0!important}.content p { margin: .5em 0 1em}.content hr { background-color: #a2a9b1; height: 1px; border: 0}.content kbd,.content samp,.content code,.content pre { font-family: menlo,consolas,liberation mono,courier new,monospace; border: solid 1px #c8ccd1; white-space: pre-wrap}.content code { padding: .2em .5em}.content pre { padding: 1em}b,strong { font-weight: 700}blockquote { border-left: 3px solid #c8ccd1; padding: 8px 24px 8px 32px; font-family: linux libertine,helvetica,georgia,times,serif; font-size: 1.1em}blockquote>:first-child { margin-top: 0}blockquote>:last-child { margin-bottom: 0}blockquote>:only-child { margin-top: 0; margin-bottom: 0}em,i { font-style: italic}sup { vertical-align: super}sub { vertical-align: sub}sub,sup,.content .mw-ref { font-size: .75em; line-height: 1}@media all and (max-width: 720px) { .content table { display:block; width: 100%!important; box-sizing: border-box } .content table.wikitable { border: 0 } .content caption { display: block }}.content table { margin: 1em 0; overflow: auto; overflow-y: hidden; overflow-x: auto}.content table caption { text-align: left}.wikitable { border: 1px solid #54595d; border-color: rgba(84,89,93,.3)}.wikitable>tr>th,.wikitable>tr>td,.wikitable>*>tr>th,.wikitable>*>tr>td { border: 1px solid #54595d; border-color: rgba(84,89,93,.3); padding: .2em}.wikitable>tr>th,.wikitable>*>tr>th { background-color: #eaecf0}@media screen and (min-width: 720px) { .client-js #searchIcon { display:none } .header .branding-box { width: 10.0625em } .header .search-box { display: table-cell; width: auto } .header .search-box .search { width: 23.4375em } .pre-content,#mw-content-text>form,.content,.post-content { max-width: 993.3px; margin: 0 3.35em } .content figure,.content .thumb { max-width: 704px } .content figure.mw-halign-left,.content .thumb.mw-halign-left,.content figure.tleft,.content .thumb.tleft { float: left; clear: left; margin-right: 1.4em } .content figure.mw-default-size,.content .thumb.mw-default-size,.content figure.mw-halign-right,.content .thumb.mw-halign-right,.content figure.tright,.content .thumb.tright { float: right; clear: right; margin-left: 1.4em } .content table caption { background: inherit } .content table tbody { display: table-row-group } .last-modified-bar { background-color: transparent; padding-left: 0; padding-right: 0; font-size: 1em }}@media screen and (min-width: 1000px) { .banner-container,.header,.page-header-bar,.overlay-header,.content,.overlay-content,.content-unstyled,.pre-content,.post-content,#mw-content-text>form { margin-left:auto; margin-right: auto; width: 90%; max-width: 993.3px } .header { max-width: 995.3px }}toast.mw-notification-type-error,.mw-notification.mw-notification-type-error { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=toast.mw-notification-type-error%2C.mw-notification.mw-notification-type-error&format=rasterized&skin=minerva&version=qhhuv); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=toast.mw-notification-type-error%2C.mw-notification.mw-notification-type-error&format=original&skin=minerva&version=qhhuv)}toast.mw-notification-type-error,.mw-notification.mw-notification-type-error--reference { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=toast.mw-notification-type-error%2C.mw-notification.mw-notification-type-error&variant=reference&format=rasterized&skin=minerva&version=qhhuv); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=toast.mw-notification-type-error%2C.mw-notification.mw-notification-type-error&variant=reference&format=original&skin=minerva&version=qhhuv)}a.external { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=a.external&format=rasterized&lang=en&skin=minerva&version=qhhuv); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=a.external&format=original&lang=en&skin=minerva&version=qhhuv)}a.external--reference { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=a.external&variant=reference&format=rasterized&lang=en&skin=minerva&version=qhhuv); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.content.styles.images&image=a.external&variant=reference&format=original&lang=en&skin=minerva&version=qhhuv)}.mw-ui-icon-wikimedia-history-base20:before,.mw-ui-background-icon-history { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=history&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=history&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-history-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=history&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=history&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-history-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=history&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=history&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-language-base20:before,.mw-ui-background-icon-language { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=language&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=language&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-language-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=language&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=language&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-language-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=language&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=language&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-edit-base20:before,.mw-ui-background-icon-edit { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=edit&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=edit&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-edit-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=edit&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=edit&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-edit-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=edit&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=edit&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-editLock-base20:before,.mw-ui-background-icon-editLock { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=editLock&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=editLock&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-editLock-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=editLock&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=editLock&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-editLock-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=editLock&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=editLock&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-search-base20:before,.mw-ui-background-icon-search { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-search-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-search-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=search&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-menu-base20:before,.mw-ui-background-icon-menu { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=menu&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=menu&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-menu-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=menu&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=menu&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-menu-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=menu&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=menu&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-star-base20:before,.mw-ui-background-icon-star { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=star&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=star&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-star-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=star&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=star&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-star-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=star&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=star&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-halfStar-base20:before,.mw-ui-background-icon-halfStar { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=halfStar&format=rasterized&lang=en&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=halfStar&format=original&lang=en&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-halfStar-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=halfStar&variant=invert&format=rasterized&lang=en&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=halfStar&variant=invert&format=original&lang=en&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-halfStar-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=halfStar&variant=progressive&format=rasterized&lang=en&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=halfStar&variant=progressive&format=original&lang=en&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-unStar-base20:before,.mw-ui-background-icon-unStar { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=unStar&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=unStar&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-unStar-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=unStar&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=unStar&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-unStar-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=unStar&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=unStar&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-userAvatar-base20:before,.mw-ui-background-icon-userAvatar { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=userAvatar&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=userAvatar&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-userAvatar-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=userAvatar&variant=invert&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=userAvatar&variant=invert&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-wikimedia-userAvatar-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=userAvatar&variant=progressive&format=rasterized&skin=minerva&version=4y50j); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.icons.wikimedia&image=userAvatar&variant=progressive&format=original&skin=minerva&version=4y50j)}.mw-ui-icon-minerva-speechBubbles:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.advanced.icons&image=speechBubbles&format=rasterized&lang=en&skin=minerva&version=jhnt0); background-image: linear-gradient(transparent,transparent),url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+c3BlZWNoIGJ1YmJsZXM8L3RpdGxlPjxnIGZpbGw9IiM1NDU5NWQiPjxwYXRoIGQ9Ik0xNyA0djdhMiAyIDAgMDEtMiAySDR2MWEyIDIgMCAwMDIgMmgxMGw0IDRWNmEyIDIgMCAwMC0yLTJ6TTYgMTBIMHY2eiIvPjxyZWN0IHdpZHRoPSIxNiIgaGVpZ2h0PSIxMiIgcng9IjIiLz48L2c+PC9zdmc+)}.mw-ui-icon-minerva-specialPages:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.advanced.icons&image=specialPages&format=rasterized&lang=en&skin=minerva&version=jhnt0); background-image: linear-gradient(transparent,transparent),url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+c3BlY2lhbCBwYWdlczwvdGl0bGU+PGcgZmlsbD0iIzU0NTk1ZCI+PHBhdGggZD0iTTcgMGEyIDIgMCAwMC0yIDJoOWEyIDIgMCAwMTIgMnYxMmEyIDIgMCAwMDItMlYyYTIgMiAwIDAwLTItMnoiLz48cGF0aCBkPSJNMTMgMjBINGEyIDIgMCAwMS0yLTJWNWEyIDIgMCAwMTItMmg5YTIgMiAwIDAxMiAydjEzYTIgMiAwIDAxLTIgMnptLTYuNS0zLjVsLjQxLTEuMDlMOCAxNWwtMS4wOS0uNDEtLjQxLTEuMDktLjQxIDEuMDlMNSAxNWwxLjA5LjQxLjQxIDEuMDl6bTIuOTgyLS45NDlsLjk1Mi0yLjU2MSAyLjUzLS45NjQtMi41My0uOTY0TDkuNDgyIDguNWwtLjk1MiAyLjU2Mi0yLjUzLjk2NCAyLjUzLjk2NC45NTIgMi41NjF6TTYgMTAuNWwuNTQ3LTEuNDUzTDggOC41bC0xLjQ1My0uNTQ3TDYgNi41bC0uNTQ3IDEuNDUzTDQgOC41bDEuNDUzLjU0N0w2IDEwLjV6Ii8+PC9nPjwvc3ZnPg==)}.mw-ui-icon-minerva-recentChanges:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.advanced.icons&image=recentChanges&format=rasterized&lang=en&skin=minerva&version=jhnt0); background-image: linear-gradient(transparent,transparent),url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+cmVjZW50IGNoYW5nZXM8L3RpdGxlPjxnIGZpbGw9IiM1NDU5NWQiPjxjaXJjbGUgY3g9IjIiIGN5PSI0IiByPSIyIi8+PGNpcmNsZSBjeD0iMiIgY3k9IjEwIiByPSIyIi8+PGNpcmNsZSBjeD0iMiIgY3k9IjE2IiByPSIyIi8+PHBhdGggZD0iTTYgM2gxMXYySDZ6bTAgNmg2djJINnptMCA2aDJ2Mkg2em0xMi43Ni0zLjExbDEuMDc4LTEuMTEyYS41NTYuNTU2IDAgMDAwLS43ODNsLTEuODU1LTEuODMzYS41NTYuNTU2IDAgMDAtLjc4MyAwbC0xLjA5IDEuMDc3IDIuNjUgMi42NXptLTMuMjI3LTIuMDYyTDEwIDE1LjM2MVYxOGgyLjYzOWw1LjUzMy01LjUzM3oiLz48L2c+PC9zdmc+)}.mw-ui-icon-minerva-die:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=die&format=rasterized&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=die&format=original&skin=minerva&version=17p52)}.mw-ui-icon-minerva-heart:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=heart&format=rasterized&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=heart&format=original&skin=minerva&version=17p52)}.mw-ui-icon-minerva-home:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=home&format=rasterized&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=home&format=original&skin=minerva&version=17p52)}.mw-ui-icon-minerva-logIn:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=logIn&format=rasterized&lang=en&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=logIn&format=original&lang=en&skin=minerva&version=17p52)}.mw-ui-icon-minerva-logOut:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=logOut&format=rasterized&lang=en&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=logOut&format=original&lang=en&skin=minerva&version=17p52)}.mw-ui-icon-minerva-settings:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=settings&format=rasterized&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=settings&format=original&skin=minerva&version=17p52)}.mw-ui-icon-minerva-mapPin:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=mapPin&format=rasterized&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=mapPin&format=original&skin=minerva&version=17p52)}.mw-ui-icon-minerva-unStar:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=unStar&format=rasterized&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=unStar&format=original&skin=minerva&version=17p52)}.mw-ui-icon-minerva-userContributions:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=userContributions&format=rasterized&lang=en&skin=minerva&version=17p52); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.mainMenu.icons&image=userContributions&format=original&lang=en&skin=minerva&version=17p52)}#mw-mf-page-left { position: fixed; top: 0; left: 0; bottom: 0; min-width: 275px; visibility: hidden; max-width: 80%; z-index: 2; overflow-y: auto; background-color: #eaecf0; -webkit-transform: translate(-100%,0); -ms-transform: translate(-100%,0); transform: translate(-100%,0)}@media screen and (min-width: 720px) { #mw-mf-page-left { min-width:320px }}#mw-mf-page-left ul { padding-bottom: 22px}.main-menu-mask { position: fixed; top: 0; left: 0; right: 0; opacity: 0; bottom: 0; background: rgba(0,0,0,.8); z-index: 1; visibility: hidden}#main-menu-input:checked~.main-menu-mask { visibility: visible; opacity: .5}#main-menu-input:checked~#mw-mf-page-left { visibility: visible; box-shadow: 1px 0 8px 0 rgba(0,0,0,.35); -webkit-transform: translate(0,0); -ms-transform: translate(0,0); transform: translate(0,0)}.minerva-animations-ready #mw-mf-page-left { -webkit-transition: opacity 250ms ease-in-out,visibility 250ms ease-in-out,transform 250ms ease-in-out; transition: opacity 250ms ease-in-out,visibility 250ms ease-in-out,transform 250ms ease-in-out}.minerva-animations-ready .main-menu-mask { -webkit-transition: opacity 100ms ease-in-out,visibility 0ms linear 100ms; transition: opacity 100ms ease-in-out,visibility 0ms linear 100ms}.minerva-animations-ready #main-menu-input:checked~.main-menu-mask { -webkit-transition: opacity 100ms ease-in-out; transition: opacity 100ms ease-in-out}.navigation-full-screen #mw-mf-page-left { max-width: none; -webkit-transform: none; -ms-transform: none; transform: none}.hotfix-T264376 .main-menu-mask { display: none}.hotfix-T264376 #main-menu-input:checked~.main-menu-mask { display: block}#mw-mf-page-left .secondary-action { border: 0; font-size: 16px; position: absolute; right: 0; top: 0; bottom: 0; border-left: 1px solid #a2a9b1; color: transparent}#mw-mf-page-left .primary-action { margin-right: 3.5em}#mw-mf-page-left ul:first-child li:first-child { border-top: 0}#mw-mf-page-left ul li { background-color: #fff; position: relative; border-top: 1px solid #eaecf0; margin-top: -1px}#mw-mf-page-left ul li:first-child { border-top: 0}#mw-mf-page-left ul li a { color: #54595d; display: block; max-width: 100%; padding: 12px 10px 12px 15px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap}#mw-mf-page-left ul li a.secondary-action { padding-left: 10px}#mw-mf-page-left ul li a:hover { box-shadow: inset 4px 0 0 0 #36c; text-decoration: none}#mw-mf-page-left ul li a span { font-size: .875em; font-weight: 700; vertical-align: middle}#mw-mf-page-left ul.hlist li { background-color: transparent; border: 0; margin: 0; font-size: .75em}#mw-mf-page-left ul.hlist li:after { content: none}#mw-mf-page-left ul.hlist li a { color: #36c; padding: .7em 12px}#mw-mf-page-left ul.hlist li a:hover { background-color: transparent; box-shadow: none}.notifications-overlay { visibility: visible}.notifications-overlay.navigation-drawer { display: block; width: auto; right: 0; box-shadow: -5px 0 0 0 rgba(0,0,0,.35); -webkit-transform: translate(100%,0); -ms-transform: translate(100%,0); transform: translate(100%,0); -webkit-transition: transform 250ms ease-in-out; transition: transform 250ms ease-in-out}.notifications-overlay.navigation-drawer.visible { -webkit-transform: translate(0,0); -ms-transform: translate(0,0); transform: translate(0,0)}@media all and (min-width: 720px) { .notifications-overlay.navigation-drawer { left:40% } .notifications-overlay.navigation-drawer .overlay-header { margin: 0; width: 100%; max-width: none } .notifications-overlay.navigation-drawer .overlay-header .cancel { left: 0 }}.toggle-list__checkbox { position: absolute; z-index: -1; opacity: 0}.toggle-list__toggle { display: inline-block; cursor: pointer}.toggle-list__checkbox:focus+.toggle-list__toggle { outline: dotted 1px; outline: auto #447ff5}.toggle-list__checkbox:checked+.toggle-list__toggle { outline: 0; background: rgba(1,1,1,.1)}.touch-events .toggle-list__checkbox:focus+.toggle-list__toggle { outline: 0}.toggle-list__list { background: #fff; position: absolute; overflow-y: auto; z-index: 2; box-shadow: 0 5px 17px 0 rgba(0,0,0,.24),0 0 1px #a2a9b1; visibility: hidden; opacity: 0}.toggle-list__checkbox:checked~.toggle-list__list { visibility: visible; opacity: 1}.mw-ui-icon-minerva-articleRedirect:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=articleRedirect&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=articleRedirect&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-articleRedirect,.mw-ui-icon-articleRedirect-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=articleRedirect&variant=invert&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=articleRedirect&variant=invert&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-articleRedirect,.mw-ui-icon-articleRedirect-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=articleRedirect&variant=progressive&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=articleRedirect&variant=progressive&format=original&lang=en&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-infoFilled:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=infoFilled&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=infoFilled&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-infoFilled,.mw-ui-icon-infoFilled-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=infoFilled&variant=invert&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=infoFilled&variant=invert&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-infoFilled,.mw-ui-icon-infoFilled-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=infoFilled&variant=progressive&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=infoFilled&variant=progressive&format=original&lang=en&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-quotes:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=quotes&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=quotes&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-quotes,.mw-ui-icon-quotes-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=quotes&variant=invert&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=quotes&variant=invert&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-quotes,.mw-ui-icon-quotes-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=quotes&variant=progressive&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=quotes&variant=progressive&format=original&lang=en&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-link:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=link&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=link&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-link,.mw-ui-icon-link-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=link&variant=invert&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=link&variant=invert&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-link,.mw-ui-icon-link-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=link&variant=progressive&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=link&variant=progressive&format=original&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-listBullet:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=listBullet&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=listBullet&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-listBullet,.mw-ui-icon-listBullet-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=listBullet&variant=invert&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=listBullet&variant=invert&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-listBullet,.mw-ui-icon-listBullet-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=listBullet&variant=progressive&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=listBullet&variant=progressive&format=original&lang=en&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-ellipsis:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=ellipsis&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=ellipsis&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-ellipsis,.mw-ui-icon-ellipsis-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=ellipsis&variant=invert&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=ellipsis&variant=invert&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-ellipsis,.mw-ui-icon-ellipsis-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=ellipsis&variant=progressive&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=ellipsis&variant=progressive&format=original&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-userAvatar:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatar&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatar&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-userAvatar,.mw-ui-icon-userAvatar-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatar&variant=invert&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatar&variant=invert&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-userAvatar,.mw-ui-icon-userAvatar-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatar&variant=progressive&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatar&variant=progressive&format=original&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-userAvatarOutline:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatarOutline&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatarOutline&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-userAvatarOutline,.mw-ui-icon-userAvatarOutline-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatarOutline&variant=invert&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatarOutline&variant=invert&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-userAvatarOutline,.mw-ui-icon-userAvatarOutline-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatarOutline&variant=progressive&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userAvatarOutline&variant=progressive&format=original&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-userGroup:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userGroup&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userGroup&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-userGroup,.mw-ui-icon-userGroup-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userGroup&variant=invert&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userGroup&variant=invert&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-userGroup,.mw-ui-icon-userGroup-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userGroup&variant=progressive&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userGroup&variant=progressive&format=original&lang=en&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-userTalk:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userTalk&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userTalk&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-userTalk,.mw-ui-icon-userTalk-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userTalk&variant=invert&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userTalk&variant=invert&format=original&lang=en&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-userTalk,.mw-ui-icon-userTalk-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userTalk&variant=progressive&format=rasterized&lang=en&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=userTalk&variant=progressive&format=original&lang=en&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-logoWikidata:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=logoWikidata&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=logoWikidata&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-invert.oo-ui-icon-logoWikidata,.mw-ui-icon-logoWikidata-invert:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=logoWikidata&variant=invert&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=logoWikidata&variant=invert&format=original&skin=minerva&version=bdzvr)}.oo-ui-image-progressive.oo-ui-icon-logoWikidata,.mw-ui-icon-logoWikidata-progressive:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=logoWikidata&variant=progressive&format=rasterized&skin=minerva&version=bdzvr); background-image: linear-gradient(transparent,transparent),url(https://wiki.hypixel.net/load.php?modules=skins.minerva.overflow.icons&image=logoWikidata&variant=progressive&format=original&skin=minerva&version=bdzvr)}.mw-ui-icon-minerva-markup:before { background-image: url(https://wiki.hypixel.net/load.php?modules=skins.minerva.personalMenu.icons&image=markup&format=rasterized&skin=minerva&version=1j2d9); background-image: linear-gradient(transparent,transparent),url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj48dGl0bGU+bWFya3VwPC90aXRsZT48ZyBmaWxsPSIjNTQ1OTVkIj48cGF0aCBkPSJNNi41IDMuNUwwIDEwbDEuNSAxLjUgNSA1TDggMTVsLTUtNSA1LTV6bTcgMEwxMiA1bDUgNS01IDUgMS41IDEuNUwyMCAxMHoiLz48L2c+PC9zdmc+)}div#mw-content-text { position: absolute;}body { text-rendering: optimizeLegibility; text-rendering: geometricPrecision}
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpg
deleted file mode 100644
index 0bfb0d2e..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_0.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpg
deleted file mode 100644
index b4890bc5..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_1.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpg
deleted file mode 100644
index ea7da9aa..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_2.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpg
deleted file mode 100644
index 92013d1a..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_3.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpg
deleted file mode 100644
index 2e3da992..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_4.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpg
deleted file mode 100644
index 95398c35..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_day/panorama_5.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpg
deleted file mode 100644
index 837a2928..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_0.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpg
deleted file mode 100644
index 6f988421..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_1.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpg
deleted file mode 100644
index 0c664062..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_2.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpg
deleted file mode 100644
index 278d92f1..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_3.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpg
deleted file mode 100644
index f9205c52..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_4.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpg
deleted file mode 100644
index 5ca08bf9..00000000
--- a/src/main/resources/assets/notenoughupdates/panoramas/combat_2_night/panorama_5.jpg
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_0.jpg b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_0.jpg
new file mode 100644
index 00000000..efbef9ed
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_0.jpg
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_1.jpg b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_1.jpg
new file mode 100644
index 00000000..7f895802
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_1.jpg
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_2.jpg b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_2.jpg
new file mode 100644
index 00000000..db925a2f
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_2.jpg
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_3.jpg b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_3.jpg
new file mode 100644
index 00000000..7dbe0246
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_3.jpg
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_4.jpg b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_4.jpg
new file mode 100644
index 00000000..78b97952
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_4.jpg
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_5.jpg b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_5.jpg
new file mode 100644
index 00000000..e8f64665
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/panoramas/crimson_isle/panorama_5.jpg
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/prev.png b/src/main/resources/assets/notenoughupdates/prev.png
deleted file mode 100644
index a4ec7743..00000000
--- a/src/main/resources/assets/notenoughupdates/prev.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/prev.xcf b/src/main/resources/assets/notenoughupdates/prev.xcf
deleted file mode 100644
index e9fecc61..00000000
--- a/src/main/resources/assets/notenoughupdates/prev.xcf
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/prev_unhovered.png b/src/main/resources/assets/notenoughupdates/prev_unhovered.png
deleted file mode 100644
index f4340fee..00000000
--- a/src/main/resources/assets/notenoughupdates/prev_unhovered.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_basic.png b/src/main/resources/assets/notenoughupdates/pv_basic.png
index 227bad5a..4d5236f5 100644
--- a/src/main/resources/assets/notenoughupdates/pv_basic.png
+++ b/src/main/resources/assets/notenoughupdates/pv_basic.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_bestiary_tab.png b/src/main/resources/assets/notenoughupdates/pv_bestiary_tab.png
new file mode 100644
index 00000000..620c156b
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/pv_bestiary_tab.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_bingo_tab.png b/src/main/resources/assets/notenoughupdates/pv_bingo_tab.png
new file mode 100644
index 00000000..135035cf
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/pv_bingo_tab.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_cata.png b/src/main/resources/assets/notenoughupdates/pv_cata.png
deleted file mode 100644
index 46b676e1..00000000
--- a/src/main/resources/assets/notenoughupdates/pv_cata.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_invs.png b/src/main/resources/assets/notenoughupdates/pv_invs.png
index 881078d2..46c7b0e9 100644
--- a/src/main/resources/assets/notenoughupdates/pv_invs.png
+++ b/src/main/resources/assets/notenoughupdates/pv_invs.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/pv_trophy_fish_tab.png b/src/main/resources/assets/notenoughupdates/pv_trophy_fish_tab.png
new file mode 100644
index 00000000..d42446c1
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/pv_trophy_fish_tab.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/radial_circle_off.png b/src/main/resources/assets/notenoughupdates/radial_circle_off.png
deleted file mode 100644
index 300cbcfb..00000000
--- a/src/main/resources/assets/notenoughupdates/radial_circle_off.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/radial_circle_on.png b/src/main/resources/assets/notenoughupdates/radial_circle_on.png
deleted file mode 100644
index 4d5cc862..00000000
--- a/src/main/resources/assets/notenoughupdates/radial_circle_on.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/radial_square_off.png b/src/main/resources/assets/notenoughupdates/radial_square_off.png
deleted file mode 100644
index 97fbf27e..00000000
--- a/src/main/resources/assets/notenoughupdates/radial_square_off.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/radial_square_on.png b/src/main/resources/assets/notenoughupdates/radial_square_on.png
deleted file mode 100644
index 5116df80..00000000
--- a/src/main/resources/assets/notenoughupdates/radial_square_on.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/setting_border.png b/src/main/resources/assets/notenoughupdates/setting_border.png
deleted file mode 100644
index e5dff747..00000000
--- a/src/main/resources/assets/notenoughupdates/setting_border.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.frag b/src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.frag
new file mode 100644
index 00000000..8985e717
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.frag
@@ -0,0 +1,54 @@
+#version 130
+
+uniform sampler2D textureIn;
+uniform int something;
+uniform vec2 dvdPosition;
+
+//Algorithm by sam hocevar
+vec3 rgb2hsv(vec3 c) {
+ vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
+ vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
+ vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
+
+ float d = q.x - min(q.w, q.y);
+ float e = 1.0e-10;
+ return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
+}
+
+//Algorithm by hughsk
+vec3 hsv2rgb(vec3 c) {
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
+ return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
+}
+void main() {
+ vec2 diskUv = vec2(1, 634) / 1024;
+ vec2 diskSize = vec2(162, 78) / 1024;
+ float renderScale = 0.5;
+ vec2 renderSize = diskSize * renderScale;
+ vec2 positionTopLeft = dvdPosition / 1024;
+ vec2 positionBottomRight = positionTopLeft + renderSize;
+ vec4 texture = texture2D(textureIn, gl_TexCoord[0].st);
+ // vec4 texture = vec4(1.0, 0.0, 1.0, 1.0);
+ vec2 offset = gl_TexCoord[0].st - positionTopLeft;
+
+ if (0 <= offset.x && offset.x < renderSize.x && 0 <= offset.y && offset.y < renderSize.y) {
+ vec4 diskTexture = texture2D(textureIn, diskUv + offset / renderScale);
+ // vec4 diskTexture = vec4(1.0, 0.0, 0.0, 1.0);
+ if (diskTexture.w > 0.5) {
+ vec3 hehe = rgb2hsv(diskTexture.xyz);
+
+ float otherHue = float(something) / 255.0;
+ if (otherHue > 1){
+ hehe.x = 1;
+ } else if (otherHue < 0){
+ hehe.x = 0;
+ } else {
+ hehe.x = otherHue;
+ }
+
+ texture = vec4(hsv2rgb(hehe), 1.0);
+ }
+ }
+ gl_FragColor = texture;
+}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.vert b/src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.vert
new file mode 100644
index 00000000..d2bc8e19
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/shaders/capes/screensaver/screensaver.vert
@@ -0,0 +1,6 @@
+#version 120
+
+void main() {
+ gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/blur.json b/src/main/resources/assets/notenoughupdates/shaders/program/blur.json
index 9da3c2e8..01c0578d 100644
--- a/src/main/resources/assets/notenoughupdates/shaders/program/blur.json
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/blur.json
@@ -1,21 +1,85 @@
{
- "blend": {
- "func": "add",
- "srcrgb": "srcalpha",
- "dstrgb": "1-srcalpha"
+ "blend": {
+ "func": "add",
+ "srcrgb": "srcalpha",
+ "dstrgb": "1-srcalpha"
+ },
+ "vertex": "sobel",
+ "fragment": "blur2",
+ "attributes": [
+ "Position"
+ ],
+ "samplers": [
+ {
+ "name": "DiffuseSampler"
+ }
+ ],
+ "uniforms": [
+ {
+ "name": "ProjMat",
+ "type": "matrix4x4",
+ "count": 16,
+ "values": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
},
- "vertex": "sobel",
- "fragment": "blur2",
- "attributes": [ "Position" ],
- "samplers": [
- { "name": "DiffuseSampler" }
- ],
- "uniforms": [
- { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
- { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
- { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
- { "name": "BlurDir", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
- { "name": "Radius", "type": "float", "count": 1, "values": [ 5.0 ] },
- { "name": "AlphaMult", "type": "float", "count": 1, "values": [ 1.0 ] }
- ]
+ {
+ "name": "InSize",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "OutSize",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "BlurDir",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "Radius",
+ "type": "float",
+ "count": 1,
+ "values": [
+ 5.0
+ ]
+ },
+ {
+ "name": "AlphaMult",
+ "type": "float",
+ "count": 1,
+ "values": [
+ 1.0
+ ]
+ }
+ ]
}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json
index bb41ffd5..a8a3fc79 100644
--- a/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/dungeonmap.json
@@ -6,14 +6,63 @@
},
"vertex": "dungeonmap",
"fragment": "dungeonmap",
- "attributes": [ "Position" ],
+ "attributes": [
+ "Position"
+ ],
"samplers": [
- { "name": "DiffuseSampler" }
+ {
+ "name": "DiffuseSampler"
+ }
],
"uniforms": [
- { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
- { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
- { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] },
- { "name": "radiusSq", "type": "float", "count": 1, "values": [ 1.0 ] }
+ {
+ "name": "ProjMat",
+ "type": "matrix4x4",
+ "count": 16,
+ "values": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "OutSize",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "InSize",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "radiusSq",
+ "type": "float",
+ "count": 1,
+ "values": [
+ 1.0
+ ]
+ }
]
}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json b/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json
index 048ceb9f..2878f3ed 100644
--- a/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/grayscale.json
@@ -6,12 +6,46 @@
},
"vertex": "blit",
"fragment": "grayscale",
- "attributes": [ "Position" ],
+ "attributes": [
+ "Position"
+ ],
"samplers": [
- { "name": "DiffuseSampler" }
+ {
+ "name": "DiffuseSampler"
+ }
],
"uniforms": [
- { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
- { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }
+ {
+ "name": "ProjMat",
+ "type": "matrix4x4",
+ "count": 16,
+ "values": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "OutSize",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ }
]
}
diff --git a/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json b/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json
index 653764fb..3bd50d8b 100644
--- a/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json
+++ b/src/main/resources/assets/notenoughupdates/shaders/program/setrgbtoalpha.json
@@ -6,12 +6,46 @@
},
"vertex": "blit",
"fragment": "setrgbtoalpha",
- "attributes": [ "Position" ],
+ "attributes": [
+ "Position"
+ ],
"samplers": [
- { "name": "DiffuseSampler" }
+ {
+ "name": "DiffuseSampler"
+ }
],
"uniforms": [
- { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] },
- { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }
+ {
+ "name": "ProjMat",
+ "type": "matrix4x4",
+ "count": 16,
+ "values": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "name": "OutSize",
+ "type": "float",
+ "count": 2,
+ "values": [
+ 1.0,
+ 1.0
+ ]
+ }
]
}
diff --git a/src/main/resources/assets/notenoughupdates/slider_off.png b/src/main/resources/assets/notenoughupdates/slider_off.png
deleted file mode 100644
index 0f514c41..00000000
--- a/src/main/resources/assets/notenoughupdates/slider_off.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/slider_on.png b/src/main/resources/assets/notenoughupdates/slider_on.png
deleted file mode 100644
index 8d2d6680..00000000
--- a/src/main/resources/assets/notenoughupdates/slider_on.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/sounds.json b/src/main/resources/assets/notenoughupdates/sounds.json
index 6d827876..5a3b5528 100644
--- a/src/main/resources/assets/notenoughupdates/sounds.json
+++ b/src/main/resources/assets/notenoughupdates/sounds.json
@@ -71,7 +71,6 @@
}
]
},
-
"titanium.break": {
"category": "block",
"sounds": [
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstoneamberbreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstoneamberbreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstoneamberbreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstoneamberbreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstoneamethystbreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstoneamethystbreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstoneamethystbreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstoneamethystbreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstonejadebreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstonejadebreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstonejadebreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstonejadebreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstonejasperbreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstonejasperbreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstonejasperbreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstonejasperbreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstonerubybreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstonerubybreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstonerubybreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstonerubybreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstonesapphirebreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstonesapphirebreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstonesapphirebreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstonesapphirebreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/gemstonetopazbreak.json b/src/main/resources/assets/notenoughupdates/sounds/gemstonetopazbreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/gemstonetopazbreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/gemstonetopazbreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/mithrilbreak.json b/src/main/resources/assets/notenoughupdates/sounds/mithrilbreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/mithrilbreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/mithrilbreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/sounds/titaniumbreak.json b/src/main/resources/assets/notenoughupdates/sounds/titaniumbreak.json
index b02ee0c7..e46a3897 100644
--- a/src/main/resources/assets/notenoughupdates/sounds/titaniumbreak.json
+++ b/src/main/resources/assets/notenoughupdates/sounds/titaniumbreak.json
@@ -1 +1,3 @@
-{ "debouncer": 20 }
+{
+ "debouncer": 20
+}
diff --git a/src/main/resources/assets/notenoughupdates/supersecretassets/lunar.png b/src/main/resources/assets/notenoughupdates/supersecretassets/lunar.png
new file mode 100644
index 00000000..7de98284
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/supersecretassets/lunar.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.png
new file mode 100644
index 00000000..5a5fa825
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/crafting_table_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.png b/src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.png
new file mode 100644
index 00000000..18085170
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/entity_viewer.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.png b/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.png
deleted file mode 100644
index 2c3d2eb1..00000000
--- a/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.png
new file mode 100644
index 00000000..cdd8b0f1
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/forge_recipe_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/item_shop_recipe.png b/src/main/resources/assets/notenoughupdates/textures/gui/item_shop_recipe.png
new file mode 100644
index 00000000..e78c0f44
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/item_shop_recipe.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.png
new file mode 100644
index 00000000..facd6d6c
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/mob_loot_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/navigation.png b/src/main/resources/assets/notenoughupdates/textures/gui/navigation.png
new file mode 100644
index 00000000..628f3a47
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/navigation.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/tab.png b/src/main/resources/assets/notenoughupdates/textures/gui/tab.png
new file mode 100644
index 00000000..91d317ca
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/tab.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.png b/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.png
deleted file mode 100644
index 42b6241c..00000000
--- a/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe.png
+++ /dev/null
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.png b/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.png
new file mode 100644
index 00000000..8cb89bae
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/textures/gui/villager_recipe_tall.png
Binary files differ
diff --git a/src/main/resources/assets/notenoughupdates/trophy_profit.png b/src/main/resources/assets/notenoughupdates/trophy_profit.png
new file mode 100644
index 00000000..2965f1dc
--- /dev/null
+++ b/src/main/resources/assets/notenoughupdates/trophy_profit.png
Binary files differ
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
new file mode 100644
index 00000000..0123ad91
--- /dev/null
+++ b/src/main/resources/fabric.mod.json
@@ -0,0 +1,10 @@
+{
+ "id": "notenoughupdates",
+ "version": "${version}",
+ "schemaVersion": 1,
+ "entrypoints": {
+ "main": [
+ "io.github.moulberry.notenoughupdates.envcheck.FabricEntrypoint"
+ ]
+ }
+}
diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info
index d20efafe..70f63a48 100644
--- a/src/main/resources/mcmod.info
+++ b/src/main/resources/mcmod.info
@@ -1,16 +1,18 @@
[
-{
- "modid": "notenoughupdates",
- "name": "NotEnoughUpdates",
- "description": "Mod that shows recipes and useful info for Hypixel's Skyblock gamemode.",
- "version": "${version}",
- "mcversion": "${mcversion}",
- "url": "https://github.com/Moulberry/NotEnoughUpdates/",
- "updateUrl": "https://github.com/Moulberry/NotEnoughUpdates/releases",
- "authorList": ["Moulberry"],
- "credits": "",
- "logoFile": "",
- "screenshots": [],
- "dependencies": []
-}
+ {
+ "modid": "notenoughupdates",
+ "name": "NotEnoughUpdates",
+ "description": "Mod that shows recipes and useful info for Hypixel's Skyblock gamemode.",
+ "version": "${version}",
+ "mcversion": "${mcversion}",
+ "url": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/",
+ "updateUrl": "https://github.com/NotEnoughUpdates/NotEnoughUpdates/releases",
+ "authorList": [
+ "Moulberry"
+ ],
+ "credits": "",
+ "logoFile": "",
+ "screenshots": [],
+ "dependencies": []
+ }
]
diff --git a/src/main/resources/mixins.notenoughupdates.json b/src/main/resources/mixins.notenoughupdates.json
index a566ee2e..ed1ba55a 100644
--- a/src/main/resources/mixins.notenoughupdates.json
+++ b/src/main/resources/mixins.notenoughupdates.json
@@ -1,43 +1,56 @@
{
"package": "io.github.moulberry.notenoughupdates.mixins",
"refmap": "mixins.notenoughupdates.refmap.json",
+ "minVersion": "0.7",
+ "plugin": "io.github.moulberry.notenoughupdates.envcheck.NEUMixinConfigPlugin",
"compatibilityLevel": "JAVA_8",
"mixins": [
- "MixinAbstractClientPlayer",
- "MixinContainer",
- "MixinEffectRenderer",
- "MixinEntity",
- "MixinEntityAgeable",
- "MixinEntityPlayer",
- "MixinEntityPlayerSP",
- "MixinEntityRenderer",
- "MixinGuiChest",
- "MixinGuiContainer",
- "MixinGuiIngame",
- "MixinGuiInventory",
- "MixinGuiScreen",
- "MixinInventoryEffectRenderer",
- "MixinInventoryPlayer",
- "MixinItemCameraTransforms",
- "MixinItemRenderer",
- "MixinItemStack",
- "MixinLayerArmorBase",
- "MixinLayerCustomHead",
- "MixinMinecraft",
- "MixinMouseHelper",
- "MixinNetHandlerPlayClient",
- "MixinPlayerControllerMP",
- "MixinRender",
- "MixinRendererLivingEntity",
- "MixinRenderFish",
- "MixinRenderGlobal",
- "MixinRenderItem",
- "MixinRenderList",
- "MixinTextureManager",
- "MixinTileEntitySkullRenderer",
- "MixinTileEntitySpecialRenderer",
- "MixinVboRenderList",
- "MixinWorld",
- "MixinWorldClient"
+ "AccessorEntityAgeable",
+ "AccessorEntityArmorStand",
+ "AccessorGuiPlayerTabOverlay",
+ "MixinAbstractClientPlayer",
+ "MixinContainer",
+ "MixinEffectRenderer",
+ "MixinEntity",
+ "MixinEntityAgeable",
+ "MixinEntityHorse",
+ "MixinEntityPlayer",
+ "MixinEntityPlayerSP",
+ "MixinEntityRenderer",
+ "MixinEntitySkeleton",
+ "MixinGuiChest",
+ "MixinGuiContainer",
+ "MixinGuiIngame",
+ "MixinGuiInventory",
+ "MixinGuiScreen",
+ "MixinInventoryEffectRenderer",
+ "MixinInventoryPlayer",
+ "MixinItemCameraTransforms",
+ "MixinItemRenderer",
+ "MixinItemStack",
+ "MixinLayerArmorBase",
+ "MixinLayerCustomHead",
+ "MixinMinecraft",
+ "MixinMouseHelper",
+ "MixinNetHandlerPlayClient",
+ "MixinPlayerControllerMP",
+ "MixinRender",
+ "MixinRendererLivingEntity",
+ "MixinRenderFish",
+ "MixinRenderGlobal",
+ "MixinRenderItem",
+ "MixinRenderList",
+ "MixinTextureManager",
+ "MixinTileEntitySkullRenderer",
+ "MixinTileEntitySpecialRenderer",
+ "MixinVboRenderList",
+ "MixinWorld",
+ "MixinWorldClient"
+ ],
+ "client": [
+ "AccessorGuiContainer",
+ "AccessorGuiEditSign",
+ "AccessorMinecraft",
+ "MixinGuiEditSign"
]
}
diff --git a/src/main/resources/moulberry.key b/src/main/resources/moulberry.key
new file mode 100644
index 00000000..5a7a3307
--- /dev/null
+++ b/src/main/resources/moulberry.key
Binary files differ
diff --git a/src/main/resources/neukeystore.jks b/src/main/resources/neukeystore.jks
new file mode 100644
index 00000000..3a5a23b6
--- /dev/null
+++ b/src/main/resources/neukeystore.jks
Binary files differ
diff --git a/src/main/resources/neukeystore.txt b/src/main/resources/neukeystore.txt
new file mode 100644
index 00000000..5616f69b
--- /dev/null
+++ b/src/main/resources/neukeystore.txt
@@ -0,0 +1,17 @@
+neukeystore.jks
+===============
+
+This file should only ever be handled by a `keytool` binary from jdk 1.8u51 or below, as to be compatible with old java versions.
+
+The password to the keystore is `neuneu` and it contains every certificate from jdk 1.8u51 and the Let's Encrypt root CAs.
+
+Example for adding a new certificate:
+
+ ~/.jdks/jdk1.8.0_51/bin/keytool -keystore neukeystore.jks -storepass neuneu -alias ISRGROOTX1 -import -file isrgrootx1.der
+
+Please keep a list of added aliases below:
+
+ - ISRGROOTX1 (Let's Encrypt)
+ - ISRGROOTX2 (Let's Encrypt)
+
+
diff --git a/src/main/resources/notenoughupdates_at.cfg b/src/main/resources/notenoughupdates_at.cfg
deleted file mode 100644
index c3fb5dbc..00000000
--- a/src/main/resources/notenoughupdates_at.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-public net.minecraft.client.gui.inventory.GuiContainer field_146999_f #xSize
-public net.minecraft.client.gui.inventory.GuiContainer field_147000_g #ySize
-public net.minecraft.client.gui.inventory.GuiContainer field_147003_i #guiLeft
-public net.minecraft.client.gui.inventory.GuiContainer field_147009_r #guiTop
-public net.minecraft.client.gui.inventory.GuiContainer func_146975_c(II)Lnet/minecraft/inventory/Slot; #guiTop
-public net.minecraft.client.gui.inventory.GuiEditSign field_146848_f #tileSign
-public net.minecraft.client.gui.inventory.GuiContainer func_146977_a(Lnet/minecraft/inventory/Slot;)V #drawSlot
-public net.minecraft.client.gui.inventory.GuiContainer func_146981_a(Lnet/minecraft/inventory/Slot;II)Z #isMouseOverSlot
-public net.minecraft.client.renderer.RenderGlobal field_72755_R #renderInfos
-public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation
-public net.minecraft.client.renderer.RenderGlobal$ContainerLocalRenderInformation field_178036_a #renderChunk \ No newline at end of file
diff --git a/src/test/java/io/github/moulberry/notenoughupdates/core/util/Vec3ComparableTest.java b/src/test/java/io/github/moulberry/notenoughupdates/core/util/Vec3ComparableTest.java
new file mode 100644
index 00000000..12645152
--- /dev/null
+++ b/src/test/java/io/github/moulberry/notenoughupdates/core/util/Vec3ComparableTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.core.util;
+
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class Vec3ComparableTest {
+ @Test
+ void equals_false_when_null() {
+ // Arrange
+ Vec3Comparable vec3c = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ boolean areEqual = vec3c.equals(null);
+
+ // Assert
+ assertFalse(areEqual);
+ }
+
+ @Test
+ void equals_true_when_same_object() {
+ // Arrange
+ Vec3Comparable vec3c = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ boolean areEqual = vec3c.equals(vec3c);
+
+ // Assert
+ assertTrue(areEqual);
+ }
+
+ @Test
+ void equals_true_when_same_value() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c2 = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ boolean areEqual = vec3c1.equals(vec3c2);
+
+ // Assert
+ assertTrue(areEqual);
+ }
+
+ @Test
+ void equals_false_when_vec3_equals() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3 vec3c2 = new Vec3(1.0, 2.0, 3.0);
+
+ // Act
+ boolean areEqual = vec3c1.equals(vec3c2);
+
+ // Assert
+ assertFalse(areEqual);
+ }
+
+ @Test
+ void equals_false_when_different_object_type() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ BlockPos blockPos = new BlockPos(1.0, 2.0, 3.0);
+
+ // Act
+ boolean areEqual = vec3c1.equals(blockPos);
+
+ // Assert
+ assertFalse(areEqual);
+ }
+
+ @Test
+ void equals_false_when_different_value() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c2 = new Vec3Comparable(3.0, 2.0, 1.0);
+
+ // Act
+ boolean areEqual = vec3c1.equals(vec3c2);
+
+ // Assert
+ assertFalse(areEqual);
+ }
+
+ @Test
+ void hashCode_same_when_same_value() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c2 = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ double vec3c1Hash = vec3c1.hashCode();
+ double vec3c2Hash = vec3c2.hashCode();
+
+ // Assert
+ assertEquals(vec3c1Hash, vec3c2Hash);
+ }
+
+ @Test
+ void hashCode_different_when_different_value() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c2 = new Vec3Comparable(3.0, 2.0, 1.0);
+
+ // Act
+ double vec3c1Hash = vec3c1.hashCode();
+ double vec3c2Hash = vec3c2.hashCode();
+
+ // Assert
+ assertNotEquals(vec3c1Hash, vec3c2Hash);
+ }
+
+ @Test
+ void compareTo_zero_when_equal() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c2 = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ int result = vec3c1.compareTo(vec3c2);
+
+ // Assert
+ assertEquals(0, result);
+ }
+
+ @Test
+ void compareTo_negative_when_lower() {
+ // Arrange
+ Vec3Comparable vec3c1 = new Vec3Comparable(0.0, 2.0, 3.0);
+ Vec3Comparable vec3c2 = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ int result = vec3c1.compareTo(vec3c2);
+
+ // Assert
+ assertTrue(result < 0);
+ }
+
+ @Test
+ void compareTo_positive_when_x_y_or_z_is_higher() {
+ // Arrange
+ Vec3Comparable vec3c1x = new Vec3Comparable(2.0, 2.0, 3.0);
+ Vec3Comparable vec3c2x = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c1y = new Vec3Comparable(1.0, 3.0, 3.0);
+ Vec3Comparable vec3c2y = new Vec3Comparable(1.0, 2.0, 3.0);
+ Vec3Comparable vec3c1z = new Vec3Comparable(1.0, 2.0, 4.0);
+ Vec3Comparable vec3c2z = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act
+ int resultX = vec3c1x.compareTo(vec3c2x);
+ int resultY = vec3c1y.compareTo(vec3c2y);
+ int resultZ = vec3c1z.compareTo(vec3c2z);
+
+ // Assert
+ assertTrue(resultX > 0);
+ assertTrue(resultY > 0);
+ assertTrue(resultZ > 0);
+ }
+
+ @Test
+ void compareTo_throws_on_null() {
+ // Arrange
+ Vec3Comparable vec3c = new Vec3Comparable(1.0, 2.0, 3.0);
+
+ // Act & Assert
+ Assertions.assertThrows(NullPointerException.class, () -> {
+ vec3c.compareTo(null);
+ });
+ }
+
+ @Test
+ void signumEquals_is_true_when_all_signums_match() {
+ Vec3Comparable first = new Vec3Comparable(-1.0, 1.0, 0);
+ Vec3 second = new Vec3(-1.0, 1.0, 0);
+ Assertions.assertTrue(first.signumEquals(second));
+ }
+
+ @Test
+ void signumEquals_is_false_when_any_signum_differs() {
+ Vec3Comparable first = new Vec3Comparable(-1.0, 1.0, 0);
+ Vec3 second = new Vec3(-1.0, 1.0, 1.0);
+ Vec3 third = new Vec3(-1.0, -1.0, 0);
+ Vec3 fourth = new Vec3(1.0, 1.0, 1.0);
+ Assertions.assertFalse(first.signumEquals(second));
+ Assertions.assertFalse(first.signumEquals(third));
+ Assertions.assertFalse(first.signumEquals(fourth));
+ }
+}
diff --git a/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolverTest.java b/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolverTest.java
new file mode 100644
index 00000000..123f5bf3
--- /dev/null
+++ b/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalMetalDetectorSolverTest.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalMetalDetectorSolver.SolutionState;
+import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
+import net.minecraft.util.BlockPos;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+
+class CrystalMetalDetectorSolverTest {
+ class Location {
+ double distance;
+ Vec3Comparable playerPosition;
+ SolutionState expectedState;
+ boolean centerKnown;
+
+ public Location(
+ double distance,
+ Vec3Comparable playerPosition,
+ SolutionState expectedState,
+ boolean centerKnown
+ ) {
+ this.distance = distance;
+ this.playerPosition = playerPosition;
+ this.expectedState = expectedState;
+ this.centerKnown = centerKnown;
+ }
+ }
+
+ class Solution {
+ ArrayList<Location> locations = new ArrayList<>();
+ BlockPos center = BlockPos.ORIGIN;
+ BlockPos expectedSolution = BlockPos.ORIGIN;
+ }
+
+ @BeforeEach
+ void setUp() {
+ CrystalMetalDetectorSolver.initWorld();
+ CrystalMetalDetectorSolver.treasureAllowedPredicate = blockPos -> true;
+ NEUDebugLogger.logMethod = CrystalMetalDetectorSolverTest::neuDebugLog;
+ NEUDebugLogger.allFlagsEnabled = true;
+ }
+
+ private void findPossibleSolutionsTwice(Location loc, boolean centerNewlyDiscovered) {
+ // Each location has to be received twice to be valid
+ CrystalMetalDetectorSolver.findPossibleSolutions(loc.distance, loc.playerPosition, centerNewlyDiscovered);
+ CrystalMetalDetectorSolver.findPossibleSolutions(loc.distance, loc.playerPosition, false);
+ }
+
+ private void checkSolution(Solution solution) {
+ boolean centerSet = false;
+ int index = 0;
+ for (Location loc : solution.locations) {
+ if (loc.centerKnown && !centerSet && !solution.center.equals(BlockPos.ORIGIN)) {
+ CrystalMetalDetectorSolver.setMinesCenter(solution.center);
+ centerSet = true;
+ findPossibleSolutionsTwice(loc, true);
+ } else {
+ findPossibleSolutionsTwice(loc, false);
+ }
+ Assertions.assertEquals(
+ loc.expectedState,
+ CrystalMetalDetectorSolver.currentState,
+ "Location index " + index
+ );
+ index++;
+ }
+
+ Assertions.assertEquals(solution.expectedSolution, CrystalMetalDetectorSolver.getSolution());
+ }
+
+ @Test
+ void findPossibleSolutions_single_location_sample_is_ignored() {
+ Location location = new Location(
+ 37.3,
+ new Vec3Comparable(779.1057116115207, 70.5, 502.2997937667801),
+ SolutionState.MULTIPLE,
+ false
+ );
+
+ CrystalMetalDetectorSolver.findPossibleSolutions(location.distance, location.playerPosition, false);
+ Assertions.assertEquals(SolutionState.NOT_STARTED, CrystalMetalDetectorSolver.previousState,
+ "Previous state"
+ );
+ Assertions.assertEquals(SolutionState.NOT_STARTED, CrystalMetalDetectorSolver.currentState,
+ "Current state"
+ );
+ }
+
+ @Test
+ void findPossibleSolutions_currentState_becomes_previousState() {
+ Location location = new Location(
+ 37.3,
+ new Vec3Comparable(779.1057116115207, 70.5, 502.2997937667801),
+ SolutionState.MULTIPLE,
+ false
+ );
+
+ findPossibleSolutionsTwice(location, false);
+ Assertions.assertEquals(SolutionState.NOT_STARTED, CrystalMetalDetectorSolver.previousState,
+ "Previous state"
+ );
+ Assertions.assertEquals(location.expectedState, CrystalMetalDetectorSolver.currentState,
+ "Current state"
+ );
+ }
+
+ @Test
+ void findPossibleSolutions_state_is_invalid_when_solution_and_distance_mismatch() {
+ Solution solution = new Solution();
+ solution.center = new BlockPos(736, 88, 547);
+ solution.expectedSolution = new BlockPos(722, 67, 590);
+ solution.locations.add(new Location(
+ 67.5,
+ new Vec3Comparable(757.8235166144441, 68.0, 532.8037800566217),
+ SolutionState.FOUND_KNOWN,
+ true
+ ));
+ // slightly different player position with invalid distance
+ solution.locations.add(new Location(
+ 4.0,
+ new Vec3Comparable(757.8235166144441, 69.0, 532.8037800566217),
+ SolutionState.INVALID,
+ true
+ ));
+ checkSolution(solution);
+ }
+
+ @Test
+ void findPossibleSolutions_state_is_failed_when_second_location_eliminates_all_blocks() {
+ Solution solution = new Solution();
+ solution.center = new BlockPos(736, 88, 547);
+ solution.locations.add(new Location(
+ 29.4,
+ new Vec3Comparable(721.5979761606153, 68.0, 590.9056839507032),
+ SolutionState.MULTIPLE_KNOWN,
+ true
+ ));
+ solution.locations.add(new Location(
+ 4.0, // actual distance should be 38.2
+ new Vec3Comparable(711.858759313838, 67.0, 590.3583935310772),
+ SolutionState.FAILED,
+ true
+ ));
+ checkSolution(solution);
+ }
+
+ @Test
+ void findPossibleSolutions_state_is_found_known_when_center_found_after_location() {
+ Solution solution = new Solution();
+ solution.center = new BlockPos(736, 88, 547);
+ solution.locations.add(new Location(
+ 67.5,
+ new Vec3Comparable(757.8235166144441, 68.0, 532.8037800566217),
+ SolutionState.MULTIPLE,
+ false
+ ));
+ checkSolution(solution);
+
+ solution.locations.get(0).centerKnown = true;
+ solution.locations.get(0).expectedState = SolutionState.FOUND_KNOWN;
+ solution.expectedSolution = new BlockPos(722, 67, 590);
+ checkSolution(solution);
+ }
+
+ @Test
+ void findPossibleSolutions_state_is_found_when_single_known_location() {
+ Solution solution = new Solution();
+ solution.center = new BlockPos(736, 88, 547);
+ solution.expectedSolution = new BlockPos(722, 67, 590);
+ solution.locations.add(new Location(
+ 67.5,
+ new Vec3Comparable(757.8235166144441, 68.0, 532.8037800566217),
+ SolutionState.FOUND_KNOWN,
+ true
+ ));
+ checkSolution(solution);
+ }
+
+ @Test
+ void findPossibleSolutions_states_are_correct_using_multiple_locations_with_unknown_center() {
+ Solution solution = new Solution();
+ solution.locations.add(new Location(
+ 37.3,
+ new Vec3Comparable(779.1057116115207, 70.5, 502.2997937667801),
+ SolutionState.MULTIPLE,
+ false
+ ));
+ solution.locations.add(new Location(
+ 34.8,
+ new Vec3Comparable(782.6999999880791, 71.0, 508.69999998807907),
+ SolutionState.FOUND,
+ false
+ ));
+ solution.expectedSolution = new BlockPos(758, 67, 533);
+
+ checkSolution(solution);
+ }
+
+ @Test
+ void findPossibleSolutions_states_are_correct_when_multiple_known_locations_found() {
+ Solution solution = new Solution();
+
+ // First, validate that the solution doesn't work without the center
+ solution.locations.add(new Location(
+ 29.4,
+ new Vec3Comparable(721.5979761606153, 68.0, 590.9056839507032),
+ SolutionState.MULTIPLE,
+ false
+ ));
+ solution.locations.add(new Location(
+ 38.2,
+ new Vec3Comparable(711.858759313838, 67.0, 590.3583935310772),
+ SolutionState.MULTIPLE,
+ false
+ ));
+ checkSolution(solution);
+
+ // Now validate that the solution works with the center
+ CrystalMetalDetectorSolver.resetSolution(false);
+ solution.locations.get(0).expectedState = SolutionState.MULTIPLE_KNOWN;
+ solution.locations.get(0).centerKnown = true;
+ solution.locations.get(1).expectedState = SolutionState.FOUND_KNOWN;
+ solution.locations.get(1).centerKnown = true;
+ solution.expectedSolution = new BlockPos(748, 66, 578);
+ solution.center = new BlockPos(736, 88, 547);
+ checkSolution(solution);
+ }
+
+ private static void neuDebugLog(String message) {
+ System.out.println(message);
+ }
+}
diff --git a/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java b/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java
new file mode 100644
index 00000000..5cf5fa90
--- /dev/null
+++ b/src/test/java/io/github/moulberry/notenoughupdates/miscfeatures/CrystalWishingCompassSolverTest.java
@@ -0,0 +1,1393 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.miscfeatures;
+
+import io.github.moulberry.notenoughupdates.core.util.Vec3Comparable;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.CompassTarget;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.HandleCompassResult;
+import io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.SolverState;
+import io.github.moulberry.notenoughupdates.util.NEUDebugLogger;
+import net.minecraft.util.BlockPos;
+import net.minecraft.util.Vec3;
+import net.minecraft.util.Vec3i;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+
+import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.ALL_PARTICLES_MAX_MILLIS;
+import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.Crystal;
+import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.HollowsZone;
+import static io.github.moulberry.notenoughupdates.miscfeatures.CrystalWishingCompassSolver.getInstance;
+
+class CrystalWishingCompassSolverTest {
+ private static final CrystalWishingCompassSolver solver = getInstance();
+ long systemTimeMillis;
+ private final long DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE = 500L;
+ private final int CH_LOWEST_VALID_Y = 30;
+
+ private final CompassUse minesOfDivanCompassUse1 = new CompassUse(
+ 1647528732979L,
+ new BlockPos(754, 137, 239),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(754.358459, 138.536407, 239.200928), 137),
+ new ParticleSpawn(new Vec3Comparable(754.315735, 138.444351, 239.690521), 45),
+ new ParticleSpawn(new Vec3Comparable(754.272278, 138.352051, 240.180008), 51),
+ new ParticleSpawn(new Vec3Comparable(754.228760, 138.259750, 240.669479), 49),
+ new ParticleSpawn(new Vec3Comparable(754.185303, 138.167435, 241.158966), 57),
+ new ParticleSpawn(new Vec3Comparable(754.141846, 138.075134, 241.648438), 50),
+ new ParticleSpawn(new Vec3Comparable(754.098328, 137.982819, 242.137909), 51),
+ new ParticleSpawn(new Vec3Comparable(754.054871, 137.890518, 242.627396), 57),
+ new ParticleSpawn(new Vec3Comparable(754.011353, 137.798203, 243.116867), 44),
+ new ParticleSpawn(new Vec3Comparable(753.967896, 137.705887, 243.606354), 59),
+ new ParticleSpawn(new Vec3Comparable(753.924438, 137.613586, 244.095825), 35),
+ new ParticleSpawn(new Vec3Comparable(753.880920, 137.521271, 244.585297), 48),
+ new ParticleSpawn(new Vec3Comparable(753.837463, 137.428970, 245.074783), 70),
+ new ParticleSpawn(new Vec3Comparable(753.793945, 137.336655, 245.564255), 33),
+ new ParticleSpawn(new Vec3Comparable(753.750488, 137.244354, 246.053741), 55),
+ new ParticleSpawn(new Vec3Comparable(753.707031, 137.152039, 246.543213), 42),
+ new ParticleSpawn(new Vec3Comparable(753.663513, 137.059738, 247.032700), 56),
+ new ParticleSpawn(new Vec3Comparable(753.620056, 136.967422, 247.522171), 48),
+ new ParticleSpawn(new Vec3Comparable(753.576538, 136.875122, 248.011642), 56),
+ new ParticleSpawn(new Vec3Comparable(754.333618, 138.527710, 239.197800), 55)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.NEED_SECOND_COMPASS
+ );
+
+ private final CompassUse minesOfDivanCompassUse2 = new CompassUse(
+ DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
+ new BlockPos(760, 134, 266),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(759.686951, 135.524994, 266.190704), 129),
+ new ParticleSpawn(new Vec3Comparable(759.625183, 135.427887, 266.677277), 69),
+ new ParticleSpawn(new Vec3Comparable(759.561707, 135.330704, 267.163635), 31),
+ new ParticleSpawn(new Vec3Comparable(759.498230, 135.233536, 267.649963), 115),
+ new ParticleSpawn(new Vec3Comparable(759.434753, 135.136368, 268.136322), 0),
+ new ParticleSpawn(new Vec3Comparable(759.371277, 135.039200, 268.622650), 46),
+ new ParticleSpawn(new Vec3Comparable(759.307800, 134.942017, 269.109009), 49),
+ new ParticleSpawn(new Vec3Comparable(759.244324, 134.844849, 269.595337), 59),
+ new ParticleSpawn(new Vec3Comparable(759.180847, 134.747681, 270.081696), 45),
+ new ParticleSpawn(new Vec3Comparable(759.117371, 134.650513, 270.568024), 39),
+ new ParticleSpawn(new Vec3Comparable(759.053894, 134.553329, 271.054352), 67),
+ new ParticleSpawn(new Vec3Comparable(758.990356, 134.456161, 271.540710), 49),
+ new ParticleSpawn(new Vec3Comparable(758.926880, 134.358994, 272.027039), 32),
+ new ParticleSpawn(new Vec3Comparable(758.863403, 134.261826, 272.513397), 61),
+ new ParticleSpawn(new Vec3Comparable(758.799927, 134.164642, 272.999725), 44),
+ new ParticleSpawn(new Vec3Comparable(758.736450, 134.067474, 273.486084), 48),
+ new ParticleSpawn(new Vec3Comparable(758.672974, 133.970306, 273.972412), 57),
+ new ParticleSpawn(new Vec3Comparable(758.609497, 133.873138, 274.458740), 55),
+ new ParticleSpawn(new Vec3Comparable(758.546021, 133.775955, 274.945099), 59),
+ new ParticleSpawn(new Vec3Comparable(758.482544, 133.678787, 275.431427), 38),
+ new ParticleSpawn(new Vec3Comparable(759.636658, 135.522827, 266.186371), 0)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.SOLVED
+ );
+
+ Vec3i minesOfDivanSolution = new Vec3i(735, 98, 451);
+
+ private final CompassUse goblinHoldoutCompassUse1 = new CompassUse(
+ 1647776326763L,
+ new BlockPos(454, 87, 776),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(454.171722, 88.616852, 775.807190), 188),
+ new ParticleSpawn(new Vec3Comparable(454.010315, 88.613464, 775.333984), 44),
+ new ParticleSpawn(new Vec3Comparable(453.849243, 88.610069, 774.860657), 61),
+ new ParticleSpawn(new Vec3Comparable(453.688141, 88.606674, 774.387329), 51),
+ new ParticleSpawn(new Vec3Comparable(453.527069, 88.603271, 773.914001), 40),
+ new ParticleSpawn(new Vec3Comparable(453.365997, 88.599876, 773.440674), 57),
+ new ParticleSpawn(new Vec3Comparable(453.204926, 88.596481, 772.967346), 45),
+ new ParticleSpawn(new Vec3Comparable(453.043854, 88.593086, 772.494019), 49),
+ new ParticleSpawn(new Vec3Comparable(452.882782, 88.589691, 772.020691), 46),
+ new ParticleSpawn(new Vec3Comparable(452.721710, 88.586288, 771.547302), 65),
+ new ParticleSpawn(new Vec3Comparable(452.560638, 88.582893, 771.073975), 43),
+ new ParticleSpawn(new Vec3Comparable(452.399567, 88.579498, 770.600647), 50),
+ new ParticleSpawn(new Vec3Comparable(452.238495, 88.576103, 770.127319), 48),
+ new ParticleSpawn(new Vec3Comparable(452.077423, 88.572701, 769.653992), 47),
+ new ParticleSpawn(new Vec3Comparable(451.916351, 88.569305, 769.180664), 60),
+ new ParticleSpawn(new Vec3Comparable(451.755280, 88.565910, 768.707336), 40),
+ new ParticleSpawn(new Vec3Comparable(451.594208, 88.562515, 768.234009), 69),
+ new ParticleSpawn(new Vec3Comparable(451.433136, 88.559120, 767.760681), 40),
+ new ParticleSpawn(new Vec3Comparable(451.272064, 88.555717, 767.287354), 42),
+ new ParticleSpawn(new Vec3Comparable(454.183441, 88.616600, 775.803040), 54)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.NEED_SECOND_COMPASS
+ );
+
+ private final CompassUse goblinHoldoutCompassUse2 = new CompassUse(
+ DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
+ new BlockPos(439, 85, 777),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(439.068848, 86.624870, 776.043701), 136),
+ new ParticleSpawn(new Vec3Comparable(438.936066, 86.625786, 775.561646), 46),
+ new ParticleSpawn(new Vec3Comparable(438.804352, 86.626595, 775.079346), 65),
+ new ParticleSpawn(new Vec3Comparable(438.672699, 86.627396, 774.596985), 40),
+ new ParticleSpawn(new Vec3Comparable(438.541016, 86.628197, 774.114624), 51),
+ new ParticleSpawn(new Vec3Comparable(438.409332, 86.628998, 773.632263), 50),
+ new ParticleSpawn(new Vec3Comparable(438.277679, 86.629799, 773.149902), 50),
+ new ParticleSpawn(new Vec3Comparable(438.145996, 86.630608, 772.667603), 56),
+ new ParticleSpawn(new Vec3Comparable(438.014343, 86.631409, 772.185242), 40),
+ new ParticleSpawn(new Vec3Comparable(437.882660, 86.632210, 771.702881), 65),
+ new ParticleSpawn(new Vec3Comparable(437.751007, 86.633011, 771.220520), 45),
+ new ParticleSpawn(new Vec3Comparable(437.619324, 86.633812, 770.738159), 42),
+ new ParticleSpawn(new Vec3Comparable(437.487671, 86.634613, 770.255798), 60),
+ new ParticleSpawn(new Vec3Comparable(437.355988, 86.635414, 769.773499), 51),
+ new ParticleSpawn(new Vec3Comparable(437.224335, 86.636215, 769.291138), 44),
+ new ParticleSpawn(new Vec3Comparable(437.092651, 86.637024, 768.808777), 56),
+ new ParticleSpawn(new Vec3Comparable(436.960999, 86.637825, 768.326416), 56),
+ new ParticleSpawn(new Vec3Comparable(436.829315, 86.638626, 767.844055), 40),
+ new ParticleSpawn(new Vec3Comparable(436.697632, 86.639427, 767.361694), 50),
+ new ParticleSpawn(new Vec3Comparable(436.565979, 86.640228, 766.879395), 46),
+ new ParticleSpawn(new Vec3Comparable(439.108551, 86.620811, 776.031067), 0)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.SOLVED
+ );
+
+ Vec3i goblinHoldoutKingSolution = new Vec3i(377, 87, 550);
+ Vec3i goblinHoldoutQueenSolution = new Vec3i(322, 139, 769);
+
+ private final CompassUse precursorCityCompassUse1 = new CompassUse(
+ 1647744920365L,
+ new BlockPos(570, 120, 565),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(570.428955, 121.630745, 565.674500), 192),
+ new ParticleSpawn(new Vec3Comparable(570.572998, 121.642563, 566.153137), 52),
+ new ParticleSpawn(new Vec3Comparable(570.714233, 121.654442, 566.632629), 45),
+ new ParticleSpawn(new Vec3Comparable(570.855286, 121.666321, 567.112183), 51),
+ new ParticleSpawn(new Vec3Comparable(570.996338, 121.678200, 567.591736), 0),
+ new ParticleSpawn(new Vec3Comparable(571.137390, 121.690079, 568.071289), 111),
+ new ParticleSpawn(new Vec3Comparable(571.278442, 121.701958, 568.550781), 38),
+ new ParticleSpawn(new Vec3Comparable(571.419495, 121.713844, 569.030334), 51),
+ new ParticleSpawn(new Vec3Comparable(571.560547, 121.725723, 569.509888), 49),
+ new ParticleSpawn(new Vec3Comparable(571.701599, 121.737602, 569.989441), 0),
+ new ParticleSpawn(new Vec3Comparable(571.842651, 121.749481, 570.468994), 101),
+ new ParticleSpawn(new Vec3Comparable(571.983704, 121.761360, 570.948547), 53),
+ new ParticleSpawn(new Vec3Comparable(572.124756, 121.773239, 571.428101), 47),
+ new ParticleSpawn(new Vec3Comparable(572.265747, 121.785118, 571.907654), 49),
+ new ParticleSpawn(new Vec3Comparable(572.406799, 121.796997, 572.387207), 49),
+ new ParticleSpawn(new Vec3Comparable(572.547852, 121.808876, 572.866699), 51),
+ new ParticleSpawn(new Vec3Comparable(572.688904, 121.820755, 573.346252), 57),
+ new ParticleSpawn(new Vec3Comparable(572.829956, 121.832634, 573.825806), 42),
+ new ParticleSpawn(new Vec3Comparable(572.971008, 121.844513, 574.305359), 50),
+ new ParticleSpawn(new Vec3Comparable(573.112061, 121.856392, 574.784912), 52),
+ new ParticleSpawn(new Vec3Comparable(570.372192, 121.631874, 565.694946), 0)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.NEED_SECOND_COMPASS
+ );
+
+ private final CompassUse precursorCityCompassUse2 = new CompassUse(
+ DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
+ new BlockPos(591, 136, 579),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(590.847961, 137.589584, 579.776672), 192),
+ new ParticleSpawn(new Vec3Comparable(590.918945, 137.528259, 580.267761), 50),
+ new ParticleSpawn(new Vec3Comparable(590.985229, 137.465118, 580.759338), 56),
+ new ParticleSpawn(new Vec3Comparable(591.051147, 137.401855, 581.250916), 47),
+ new ParticleSpawn(new Vec3Comparable(591.117126, 137.338593, 581.742493), 47),
+ new ParticleSpawn(new Vec3Comparable(591.183044, 137.275330, 582.234070), 49),
+ new ParticleSpawn(new Vec3Comparable(591.249023, 137.212067, 582.725647), 60),
+ new ParticleSpawn(new Vec3Comparable(591.314941, 137.148804, 583.217224), 55),
+ new ParticleSpawn(new Vec3Comparable(591.380920, 137.085541, 583.708801), 47),
+ new ParticleSpawn(new Vec3Comparable(591.446838, 137.022263, 584.200378), 50),
+ new ParticleSpawn(new Vec3Comparable(591.512817, 136.959000, 584.691956), 39),
+ new ParticleSpawn(new Vec3Comparable(591.578735, 136.895737, 585.183533), 53),
+ new ParticleSpawn(new Vec3Comparable(591.644714, 136.832474, 585.675110), 53),
+ new ParticleSpawn(new Vec3Comparable(591.710632, 136.769211, 586.166687), 45),
+ new ParticleSpawn(new Vec3Comparable(591.776611, 136.705948, 586.658264), 79),
+ new ParticleSpawn(new Vec3Comparable(591.842529, 136.642685, 587.149841), 20),
+ new ParticleSpawn(new Vec3Comparable(591.908508, 136.579407, 587.641418), 62),
+ new ParticleSpawn(new Vec3Comparable(591.974426, 136.516144, 588.132996), 48),
+ new ParticleSpawn(new Vec3Comparable(592.040344, 136.452881, 588.624573), 40),
+ new ParticleSpawn(new Vec3Comparable(592.106323, 136.389618, 589.116150), 51),
+ new ParticleSpawn(new Vec3Comparable(590.766357, 137.556885, 579.791565), 0)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.SOLVED
+ );
+
+ Vec3i precursorCitySolution = new Vec3i(604, 124, 681);
+
+ private final CompassUse jungleCompassUse1 = new CompassUse(
+ 1647744980313L,
+ new BlockPos(454, 122, 459),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(453.954895, 122.958122, 458.687866), 141),
+ new ParticleSpawn(new Vec3Comparable(453.515991, 122.760010, 458.553314), 59),
+ new ParticleSpawn(new Vec3Comparable(453.078156, 122.560112, 458.417877), 41),
+ new ParticleSpawn(new Vec3Comparable(452.640381, 122.360123, 458.282349), 50),
+ new ParticleSpawn(new Vec3Comparable(452.202606, 122.160133, 458.146851), 66),
+ new ParticleSpawn(new Vec3Comparable(451.764832, 121.960136, 458.011353), 35),
+ new ParticleSpawn(new Vec3Comparable(451.327057, 121.760147, 457.875854), 49),
+ new ParticleSpawn(new Vec3Comparable(450.889313, 121.560150, 457.740356), 50),
+ new ParticleSpawn(new Vec3Comparable(450.451538, 121.360161, 457.604858), 49),
+ new ParticleSpawn(new Vec3Comparable(450.013763, 121.160172, 457.469330), 51),
+ new ParticleSpawn(new Vec3Comparable(449.575989, 120.960175, 457.333832), 59),
+ new ParticleSpawn(new Vec3Comparable(449.138214, 120.760185, 457.198334), 41),
+ new ParticleSpawn(new Vec3Comparable(448.700439, 120.560196, 457.062836), 55),
+ new ParticleSpawn(new Vec3Comparable(448.262695, 120.360199, 456.927338), 50),
+ new ParticleSpawn(new Vec3Comparable(447.824921, 120.160210, 456.791840), 49),
+ new ParticleSpawn(new Vec3Comparable(447.387146, 119.960213, 456.656311), 53),
+ new ParticleSpawn(new Vec3Comparable(446.949371, 119.760223, 456.520813), 43),
+ new ParticleSpawn(new Vec3Comparable(446.511597, 119.560234, 456.385315), 51),
+ new ParticleSpawn(new Vec3Comparable(446.073853, 119.360237, 456.249817), 49),
+ new ParticleSpawn(new Vec3Comparable(445.636078, 119.160248, 456.114319), 56),
+ new ParticleSpawn(new Vec3Comparable(453.975647, 122.920158, 458.668488), 0)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.NEED_SECOND_COMPASS
+ );
+
+ private final CompassUse jungleCompassUse2 = new CompassUse(
+ DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
+ new BlockPos(438, 126, 468),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(437.701721, 127.395279, 467.455048), 139),
+ new ParticleSpawn(new Vec3Comparable(437.297852, 127.161415, 467.275604), 35),
+ new ParticleSpawn(new Vec3Comparable(436.895813, 126.927208, 467.092529), 68),
+ new ParticleSpawn(new Vec3Comparable(436.493896, 126.692986, 466.909241), 41),
+ new ParticleSpawn(new Vec3Comparable(436.091980, 126.458763, 466.725952), 54),
+ new ParticleSpawn(new Vec3Comparable(435.690033, 126.224533, 466.542664), 39),
+ new ParticleSpawn(new Vec3Comparable(435.288116, 125.990311, 466.359375), 52),
+ new ParticleSpawn(new Vec3Comparable(434.886200, 125.756088, 466.176086), 66),
+ new ParticleSpawn(new Vec3Comparable(434.484283, 125.521866, 465.992767), 40),
+ new ParticleSpawn(new Vec3Comparable(434.082367, 125.287636, 465.809479), 41),
+ new ParticleSpawn(new Vec3Comparable(433.680420, 125.053413, 465.626190), 50),
+ new ParticleSpawn(new Vec3Comparable(433.278503, 124.819191, 465.442902), 59),
+ new ParticleSpawn(new Vec3Comparable(432.876587, 124.584969, 465.259613), 54),
+ new ParticleSpawn(new Vec3Comparable(432.474670, 124.350746, 465.076294), 38),
+ new ParticleSpawn(new Vec3Comparable(432.072723, 124.116516, 464.893005), 63),
+ new ParticleSpawn(new Vec3Comparable(431.670807, 123.882294, 464.709717), 36),
+ new ParticleSpawn(new Vec3Comparable(431.268890, 123.648071, 464.526428), 64),
+ new ParticleSpawn(new Vec3Comparable(430.866974, 123.413849, 464.343140), 48),
+ new ParticleSpawn(new Vec3Comparable(430.465057, 123.179619, 464.159821), 53),
+ new ParticleSpawn(new Vec3Comparable(430.063110, 122.945396, 463.976532), 46),
+ new ParticleSpawn(new Vec3Comparable(437.732666, 127.385803, 467.381592), 1)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.SOLVED
+ );
+
+ Vec3i jungleSolution = new Vec3i(343, 72, 424);
+ Vec3i jungleSolutionTempleDoor = new Vec3i(
+ jungleSolution.getX() - 57,
+ jungleSolution.getY() + 36,
+ jungleSolution.getZ() - 21
+ );
+
+ private final CompassUse magmaCompassUse1 = new CompassUse(
+ 1647745029814L,
+ new BlockPos(462, 58, 550),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(462.226898, 59.614380, 550.032654), 160),
+ new ParticleSpawn(new Vec3Comparable(462.693848, 59.609089, 549.853943), 47),
+ new ParticleSpawn(new Vec3Comparable(463.160706, 59.603809, 549.674988), 48),
+ new ParticleSpawn(new Vec3Comparable(463.627533, 59.598526, 549.496033), 136),
+ new ParticleSpawn(new Vec3Comparable(464.094391, 59.593246, 549.317017), 0),
+ new ParticleSpawn(new Vec3Comparable(464.561218, 59.587963, 549.138062), 0),
+ new ParticleSpawn(new Vec3Comparable(465.028076, 59.582684, 548.959106), 53),
+ new ParticleSpawn(new Vec3Comparable(465.494904, 59.577400, 548.780090), 48),
+ new ParticleSpawn(new Vec3Comparable(465.961761, 59.572117, 548.601135), 55),
+ new ParticleSpawn(new Vec3Comparable(466.428589, 59.566837, 548.422180), 47),
+ new ParticleSpawn(new Vec3Comparable(466.895416, 59.561554, 548.243164), 46),
+ new ParticleSpawn(new Vec3Comparable(467.362274, 59.556274, 548.064209), 53),
+ new ParticleSpawn(new Vec3Comparable(467.829102, 59.550991, 547.885254), 50),
+ new ParticleSpawn(new Vec3Comparable(468.295959, 59.545712, 547.706238), 54),
+ new ParticleSpawn(new Vec3Comparable(468.762787, 59.540428, 547.527283), 52),
+ new ParticleSpawn(new Vec3Comparable(469.229645, 59.535145, 547.348328), 105),
+ new ParticleSpawn(new Vec3Comparable(469.696472, 59.529865, 547.169312), 1),
+ new ParticleSpawn(new Vec3Comparable(470.163300, 59.524582, 546.990356), 51),
+ new ParticleSpawn(new Vec3Comparable(470.630157, 59.519302, 546.811401), 40),
+ new ParticleSpawn(new Vec3Comparable(471.096985, 59.514019, 546.632385), 49),
+ new ParticleSpawn(new Vec3Comparable(462.221954, 59.614719, 550.019165), 0)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.NEED_SECOND_COMPASS
+ );
+
+ private final CompassUse magmaCompassUse2 = new CompassUse(
+ DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
+ new BlockPos(449, 53, 556),
+ new ArrayList<>(Arrays.asList(
+ new ParticleSpawn(new Vec3Comparable(449.120911, 54.624340, 556.108948), 204),
+ new ParticleSpawn(new Vec3Comparable(449.587433, 54.627399, 555.929138), 102),
+ new ParticleSpawn(new Vec3Comparable(450.053741, 54.630432, 555.748657), 0),
+ new ParticleSpawn(new Vec3Comparable(450.520020, 54.633465, 555.568237), 62),
+ new ParticleSpawn(new Vec3Comparable(450.986298, 54.636497, 555.387756), 38),
+ new ParticleSpawn(new Vec3Comparable(451.452606, 54.639530, 555.207275), 48),
+ new ParticleSpawn(new Vec3Comparable(451.918884, 54.642563, 555.026794), 63),
+ new ParticleSpawn(new Vec3Comparable(452.385162, 54.645596, 554.846375), 52),
+ new ParticleSpawn(new Vec3Comparable(452.851471, 54.648628, 554.665894), 35),
+ new ParticleSpawn(new Vec3Comparable(453.317749, 54.651661, 554.485413), 53),
+ new ParticleSpawn(new Vec3Comparable(453.784027, 54.654694, 554.304993), 54),
+ new ParticleSpawn(new Vec3Comparable(454.250305, 54.657726, 554.124512), 50),
+ new ParticleSpawn(new Vec3Comparable(454.716614, 54.660759, 553.944031), 55),
+ new ParticleSpawn(new Vec3Comparable(455.182892, 54.663792, 553.763550), 49),
+ new ParticleSpawn(new Vec3Comparable(455.649170, 54.666824, 553.583130), 41),
+ new ParticleSpawn(new Vec3Comparable(456.115479, 54.669857, 553.402649), 48),
+ new ParticleSpawn(new Vec3Comparable(456.581757, 54.672890, 553.222168), 54),
+ new ParticleSpawn(new Vec3Comparable(457.048035, 54.675922, 553.041687), 45),
+ new ParticleSpawn(new Vec3Comparable(457.514313, 54.678959, 552.861267), 55),
+ new ParticleSpawn(new Vec3Comparable(449.110443, 54.623035, 556.079163), 49)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.SOLVED
+ );
+
+ Vec3i magmaSolution = new Vec3i(737, 56, 444);
+
+ Vec3Comparable kingOdawaMinesOrNucleusCoordsInRemnants = new Vec3Comparable(566, 100, 566);
+ Vec3Comparable queenKingOdawaOrCityNucleusCoordsInMithrilDeposits = new Vec3Comparable(566, 130, 466);
+ Vec3Comparable odawaSolution = new Vec3Comparable(349, 110, 390);
+
+ private final CompassUse nucleusCompass = new CompassUse(
+ 1647745029814L,
+ new BlockPos(512, 106, 512),
+ null,
+ HandleCompassResult.PLAYER_IN_NUCLEUS,
+ SolverState.NOT_STARTED
+ );
+
+ private void resetSolverState() {
+ solver.initWorld();
+ systemTimeMillis = 0;
+ solver.currentTimeMillis = () -> (systemTimeMillis);
+ // These must be overridden for all test cases or an exception will be thrown when
+ // data that is only present when running in the context of Minecraft is accessed.
+ solver.keyInInventory = () -> false;
+ solver.kingsScentPresent = () -> false;
+ solver.foundCrystals = () -> EnumSet.noneOf(Crystal.class);
+ }
+
+ @BeforeEach
+ void setUp() {
+ NEUDebugLogger.logMethod = CrystalWishingCompassSolverTest::neuDebugLog;
+ NEUDebugLogger.allFlagsEnabled = true;
+ resetSolverState();
+ }
+
+ private void checkSolution(Solution solution) {
+ int index = 0;
+ for (CompassUse compassUse : solution.compassUses) {
+ systemTimeMillis += compassUse.timeIncrementMillis;
+ HandleCompassResult handleCompassResult = solver.handleCompassUse(compassUse.playerPos);
+ Assertions.assertEquals(
+ compassUse.expectedHandleCompassUseResult,
+ handleCompassResult,
+ "CompassUse index " + index
+ );
+
+ for (ParticleSpawn particle : compassUse.particles) {
+ systemTimeMillis += particle.timeIncrementMillis;
+ solver.solveUsingParticle(
+ particle.spawnLocation.xCoord,
+ particle.spawnLocation.yCoord,
+ particle.spawnLocation.zCoord,
+ systemTimeMillis
+ );
+ }
+
+ Assertions.assertEquals(
+ compassUse.expectedSolverState,
+ solver.getSolverState(),
+ "CompassUse index " + index
+ );
+ if (compassUse.expectedSolverState == SolverState.SOLVED) {
+ Assertions.assertEquals(
+ solution.expectedSolutionCoords,
+ solver.getSolutionCoords()
+ );
+ }
+
+ index++;
+ }
+ }
+
+ @Test
+ void first_compass_without_particles_sets_solver_state_to_processing_first_use() {
+ // Arrange
+ CompassUse compassUse = new CompassUse(minesOfDivanCompassUse1);
+ compassUse.particles.clear();
+ compassUse.expectedSolverState = SolverState.PROCESSING_FIRST_USE;
+
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(compassUse)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void new_compass_resets_processing_first_use_state_after_timeout() {
+ // Arrange
+ CompassUse processingFirstUseCompassUse = new CompassUse(minesOfDivanCompassUse1);
+ processingFirstUseCompassUse.particles.clear();
+ processingFirstUseCompassUse.expectedSolverState = SolverState.PROCESSING_FIRST_USE;
+ Solution processingFirstUseSolution = new Solution(
+ new ArrayList<>(Collections.singletonList(processingFirstUseCompassUse)),
+ Vec3i.NULL_VECTOR
+ );
+ checkSolution(processingFirstUseSolution);
+ Assertions.assertEquals(SolverState.PROCESSING_FIRST_USE, solver.getSolverState());
+
+ CompassUse resetStateCompassUse = new CompassUse(jungleCompassUse1);
+ resetStateCompassUse.timeIncrementMillis = ALL_PARTICLES_MAX_MILLIS + 1;
+ resetStateCompassUse.expectedHandleCompassUseResult = HandleCompassResult.NO_PARTICLES_FOR_PREVIOUS_COMPASS;
+ resetStateCompassUse.expectedSolverState = SolverState.FAILED_TIMEOUT_NO_REPEATING;
+ Solution goodSolution = new Solution(
+ new ArrayList<>(Collections.singletonList(resetStateCompassUse)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(goodSolution);
+ }
+
+ @Test
+ void first_compass_with_repeating_particles_sets_state_to_need_second_compass() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void first_compass_in_nucleus_sets_state_to_player_in_nucleus() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(nucleusCompass)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void use_while_handling_previous_returns_still_processing_first_use() {
+ // Arrange
+ CompassUse compassUse1 = new CompassUse(
+ 1647528732979L,
+ new BlockPos(754, 137, 239),
+ new ArrayList<>(Collections.singletonList(
+ new ParticleSpawn(new Vec3Comparable(754.358459, 138.536407, 239.200928), 137)
+ )),
+ HandleCompassResult.SUCCESS,
+ SolverState.PROCESSING_FIRST_USE
+ );
+
+ // STILL_PROCESSING_FIRST_USE is expected instead of LOCATION_TOO_CLOSE since the solver
+ // isn't ready for the second compass use, which includes the location check
+ CompassUse compassUse2 = new CompassUse(compassUse1);
+ compassUse2.expectedHandleCompassUseResult = HandleCompassResult.STILL_PROCESSING_PRIOR_USE;
+ compassUse2.timeIncrementMillis = 500;
+
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(compassUse1, compassUse2)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void missing_repeating_particles_sets_state_to_failed_timeout_no_repeating() {
+ // Arrange
+ CompassUse compassUse = new CompassUse(minesOfDivanCompassUse1);
+ compassUse.particles.remove(compassUse.particles.size() - 1);
+ compassUse.particles.get(compassUse.particles.size() - 1).timeIncrementMillis += ALL_PARTICLES_MAX_MILLIS;
+ compassUse.expectedSolverState = SolverState.FAILED_TIMEOUT_NO_REPEATING;
+
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(compassUse)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void compasses_too_close_returns_location_too_close_and_solver_state_is_still_need_second_compass() {
+ // Arrange
+ CompassUse secondCompassUse = new CompassUse(
+ DELAY_AFTER_FIRST_COMPASS_LAST_PARTICLE,
+ minesOfDivanCompassUse1.playerPos.add(2, 2, 2),
+ null,
+ HandleCompassResult.LOCATION_TOO_CLOSE,
+ SolverState.NEED_SECOND_COMPASS
+ );
+
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, secondCompassUse)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void second_compass_sets_solver_state_to_processing_second_use() {
+ // Arrange
+ CompassUse secondCompassUse = new CompassUse(minesOfDivanCompassUse2);
+ secondCompassUse.expectedSolverState = SolverState.PROCESSING_SECOND_USE;
+ secondCompassUse.particles.clear();
+
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
+ minesOfDivanSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void second_compass_with_repeating_particles_sets_state_to_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
+ minesOfDivanSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void particles_from_first_compass_are_ignored_by_second_compass() {
+ // Arrange
+ CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2);
+ compassUse2.particles.add(0, minesOfDivanCompassUse1.particles.get(0));
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, compassUse2)),
+ minesOfDivanSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ private void execInvalidParticlesInvalidSolution() {
+ // Arrange
+ CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2);
+
+ // reverse the direction of the particles, moving the repeat particle
+ // to "new" end
+ compassUse2.particles.remove(compassUse2.particles.size() - 1);
+ Collections.reverse(compassUse2.particles);
+ // add a new repeat particle
+ compassUse2.particles.add(new ParticleSpawn(compassUse2.particles.get(0)));
+
+ // Adjust the player position
+ compassUse2.playerPos = new BlockPos(compassUse2.particles.get(0).spawnLocation);
+ compassUse2.expectedSolverState = SolverState.FAILED_INVALID_SOLUTION;
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, compassUse2)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void second_compass_with_inverted_particles_sets_state_to_invalid_solution() {
+ // Arrange, Act, and Assert
+ execInvalidParticlesInvalidSolution();
+ }
+
+ @Test
+ void solution_outside_hollows_sets_state_to_invalid_solution() {
+ // Arrange
+ CompassUse compassUse1 = new CompassUse(minesOfDivanCompassUse1);
+ CompassUse compassUse2 = new CompassUse(minesOfDivanCompassUse2);
+ double invalidYOffset = -(minesOfDivanSolution.getY() - (CH_LOWEST_VALID_Y - 1));
+ Vec3 offset = new Vec3(0.0, invalidYOffset, 0.0);
+
+ compassUse1.playerPos = compassUse1.playerPos.add(offset.xCoord, offset.yCoord, offset.zCoord);
+ for (ParticleSpawn particle : compassUse1.particles) {
+ particle.spawnLocation = particle.spawnLocation.add(offset);
+ }
+
+ compassUse2.playerPos = compassUse2.playerPos.add(offset.xCoord, offset.yCoord, offset.zCoord);
+ for (ParticleSpawn particle : compassUse2.particles) {
+ particle.spawnLocation = particle.spawnLocation.add(offset);
+ }
+ compassUse2.expectedSolverState = SolverState.FAILED_INVALID_SOLUTION;
+
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(compassUse1, compassUse2)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void second_solution_can_be_solved_after_state_is_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
+ minesOfDivanSolution
+ );
+ checkSolution(solution);
+
+ Solution solution2 = new Solution(
+ new ArrayList<>(Arrays.asList(precursorCityCompassUse1, precursorCityCompassUse2)),
+ precursorCitySolution
+ );
+
+ // Act & Assert
+ checkSolution(solution2);
+ }
+
+ @Test
+ void second_solution_can_be_solved_after_state_is_failed() {
+ // Arrange
+ execInvalidParticlesInvalidSolution();
+ Assertions.assertEquals(solver.getSolverState(), SolverState.FAILED_INVALID_SOLUTION);
+
+ Solution solution2 = new Solution(
+ new ArrayList<>(Arrays.asList(precursorCityCompassUse1, precursorCityCompassUse2)),
+ precursorCitySolution
+ );
+
+ // Act & Assert
+ checkSolution(solution2);
+ }
+
+ @Test
+ void distant_particles_are_ignored() {
+ // Arrange
+ CompassUse compassUse = new CompassUse(minesOfDivanCompassUse1);
+ compassUse.particles.get(2).spawnLocation.addVector(100.0, 100.0, 100.0);
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void possible_targets_includes_queen_and_excludes_king_when_kings_scent_is_present() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+ solver.kingsScentPresent = () -> true;
+
+ // Act
+ checkSolution(solution);
+ EnumSet<CompassTarget> targets = solver.getPossibleTargets();
+
+ // Assert
+ Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_QUEEN));
+ Assertions.assertFalse(targets.contains(CompassTarget.GOBLIN_KING));
+ }
+
+ @Test
+ void possible_targets_excludes_king_and_includes_queen_when_kings_scent_is_not_present() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+ solver.kingsScentPresent = () -> false;
+
+ // Act
+ checkSolution(solution);
+ EnumSet<CompassTarget> targets = solver.getPossibleTargets();
+
+ // Assert
+ Assertions.assertFalse(targets.contains(CompassTarget.GOBLIN_QUEEN));
+ Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_KING));
+ }
+
+ @Test
+ void possible_targets_excludes_odawa_and_includes_temple_when_key_in_inventory() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(jungleCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+ solver.keyInInventory = () -> true;
+
+ // Act
+ checkSolution(solution);
+ EnumSet<CompassTarget> targets = solver.getPossibleTargets();
+
+ // Assert
+ Assertions.assertFalse(targets.contains(CompassTarget.ODAWA));
+ Assertions.assertTrue(targets.contains(CompassTarget.JUNGLE_TEMPLE));
+ }
+
+ @Test
+ void possible_targets_includes_odawa_and_excludes_temple_when_key_not_in_inventory() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(jungleCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+ solver.keyInInventory = () -> false;
+
+ // Act
+ checkSolution(solution);
+ EnumSet<CompassTarget> targets = solver.getPossibleTargets();
+
+ // Assert
+ Assertions.assertTrue(targets.contains(CompassTarget.ODAWA));
+ Assertions.assertFalse(targets.contains(CompassTarget.JUNGLE_TEMPLE));
+ }
+
+ @Test
+ void possible_targets_contains_all_valid_targets_when_all_crystals_missing() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(precursorCityCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+ solver.foundCrystals = () -> EnumSet.noneOf(Crystal.class);
+ solver.keyInInventory = () -> false;
+ solver.kingsScentPresent = () -> false;
+
+ // Act
+ checkSolution(solution);
+ EnumSet<CompassTarget> targets = solver.getPossibleTargets();
+
+ // Assert
+ Assertions.assertTrue(targets.contains(CompassTarget.CRYSTAL_NUCLEUS));
+ Assertions.assertTrue(targets.contains(CompassTarget.ODAWA));
+ Assertions.assertTrue(targets.contains(CompassTarget.MINES_OF_DIVAN));
+ Assertions.assertTrue(targets.contains(CompassTarget.GOBLIN_KING));
+ Assertions.assertTrue(targets.contains(CompassTarget.PRECURSOR_CITY));
+ Assertions.assertTrue(targets.contains(CompassTarget.BAL));
+ // No key or king's scent, so these should be false
+ Assertions.assertFalse(targets.contains(CompassTarget.JUNGLE_TEMPLE));
+ Assertions.assertFalse(targets.contains(CompassTarget.GOBLIN_QUEEN));
+ }
+
+ private void CheckExcludedTargetsForCrystals(
+ CompassUse compassUseToExecute,
+ ArrayList<CompassTarget> excludedTargets,
+ EnumSet<Crystal> foundCrystals
+ ) {
+ // Arrange
+ EnumSet<CompassTarget> targets;
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(compassUseToExecute)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act
+ checkSolution(solution);
+ targets = solver.getPossibleTargets();
+ boolean targetFound = false;
+ for (CompassTarget target : excludedTargets) {
+ if (targets.contains(target)) {
+ targetFound = true;
+ break;
+ }
+ }
+ Assertions.assertTrue(targetFound);
+
+ resetSolverState();
+ solver.foundCrystals = () -> foundCrystals;
+ checkSolution(solution);
+ targets = solver.getPossibleTargets();
+
+ // Assert
+ for (CompassTarget target : excludedTargets) {
+ Assertions.assertFalse(targets.contains(target));
+ }
+ }
+
+ @Test
+ void possible_targets_excludes_king_and_queen_when_amber_crystal_found() {
+ // Arrange
+ ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Arrays.asList(
+ CompassTarget.GOBLIN_KING,
+ CompassTarget.GOBLIN_QUEEN
+ ));
+
+ // Act & Assert
+ CheckExcludedTargetsForCrystals(goblinHoldoutCompassUse1, excludedTargets, EnumSet.of(Crystal.AMBER));
+ }
+
+ @Test
+ void possible_targets_excludes_odawa_and_temple_when_amethyst_crystal_found() {
+ // Arrange
+ ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Arrays.asList(
+ CompassTarget.ODAWA,
+ CompassTarget.JUNGLE_TEMPLE
+ ));
+
+ // Act & Assert
+ CheckExcludedTargetsForCrystals(jungleCompassUse1, excludedTargets, EnumSet.of(Crystal.AMETHYST));
+ }
+
+ @Test
+ void possible_targets_excludes_mines_when_jade_crystal_found() {
+ // Arrange
+ ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Collections.singletonList(
+ CompassTarget.MINES_OF_DIVAN));
+
+ // Act & Assert
+ CheckExcludedTargetsForCrystals(minesOfDivanCompassUse1, excludedTargets, EnumSet.of(Crystal.JADE));
+ }
+
+ @Test
+ void possible_targets_excludes_city_when_sapphire_crystal_found() {
+ // Arrange
+ ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Collections.singletonList(
+ CompassTarget.PRECURSOR_CITY));
+
+ // Act & Assert
+ CheckExcludedTargetsForCrystals(precursorCityCompassUse1, excludedTargets, EnumSet.of(Crystal.SAPPHIRE));
+ }
+
+ @Test
+ void possible_targets_excludes_bal_when_topaz_crystal_found() {
+ // Arrange
+ ArrayList<CompassTarget> excludedTargets = new ArrayList<>(Collections.singletonList(
+ CompassTarget.BAL));
+
+ // Act & Assert
+ CheckExcludedTargetsForCrystals(magmaCompassUse1, excludedTargets, EnumSet.of(Crystal.TOPAZ));
+ }
+
+ @Test
+ void solver_resets_when_possible_targets_change_based_on_found_crystals() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act
+ checkSolution(solution);
+ systemTimeMillis += minesOfDivanCompassUse2.timeIncrementMillis;
+ solver.foundCrystals = () -> EnumSet.of(Crystal.JADE);
+ HandleCompassResult handleCompassResult = solver.handleCompassUse(minesOfDivanCompassUse2.playerPos);
+
+ // Assert
+ Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult);
+ Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState());
+ }
+
+ @Test
+ void solver_resets_when_player_location_changes_zones() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(minesOfDivanCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act
+ checkSolution(solution);
+ systemTimeMillis += minesOfDivanCompassUse2.timeIncrementMillis;
+ BlockPos newLocation = minesOfDivanCompassUse2.playerPos.add(-400, 0, 0);
+ HandleCompassResult handleCompassResult = solver.handleCompassUse(newLocation);
+
+ // Assert
+ Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult);
+ Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState());
+ }
+
+ @Test
+ void solver_resets_based_on_jungle_key_presence() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(jungleCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act
+ solver.keyInInventory = () -> false;
+ checkSolution(solution);
+ systemTimeMillis += jungleCompassUse2.timeIncrementMillis;
+ solver.keyInInventory = () -> true;
+ HandleCompassResult handleCompassResult = solver.handleCompassUse(jungleCompassUse2.playerPos);
+
+ // Assert
+ Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult);
+ Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState());
+ }
+
+ @Test
+ void solver_resets_based_on_kings_scent_presence() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Collections.singletonList(goblinHoldoutCompassUse1)),
+ Vec3i.NULL_VECTOR
+ );
+
+ // Act
+ solver.kingsScentPresent = () -> false;
+ checkSolution(solution);
+ systemTimeMillis += goblinHoldoutCompassUse2.timeIncrementMillis;
+ solver.kingsScentPresent = () -> true;
+ HandleCompassResult handleCompassResult = solver.handleCompassUse(goblinHoldoutCompassUse2.playerPos);
+
+ // Assert
+ Assertions.assertEquals(HandleCompassResult.POSSIBLE_TARGETS_CHANGED, handleCompassResult);
+ Assertions.assertEquals(SolverState.NOT_STARTED, solver.getSolverState());
+ }
+
+ @Test
+ void mines_of_divan_solution_is_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(minesOfDivanCompassUse1, minesOfDivanCompassUse2)),
+ minesOfDivanSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void jungle_temple_solution_with_key_in_inventory_is_solved_successfully_excluding_bal() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(jungleCompassUse1, jungleCompassUse2)),
+ jungleSolutionTempleDoor
+ );
+ solver.keyInInventory = () -> true;
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void jungle_temple_solution_is_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(jungleCompassUse1, jungleCompassUse2)),
+ jungleSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void precursor_city_solution_is_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(precursorCityCompassUse1, precursorCityCompassUse2)),
+ precursorCitySolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void goblin_king_solution_is_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(goblinHoldoutCompassUse1, goblinHoldoutCompassUse2)),
+ goblinHoldoutKingSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ @Test
+ void bal_solution_is_solved() {
+ // Arrange
+ Solution solution = new Solution(
+ new ArrayList<>(Arrays.asList(magmaCompassUse1, magmaCompassUse2)),
+ magmaSolution
+ );
+
+ // Act & Assert
+ checkSolution(solution);
+ }
+
+ EnumSet<CompassTarget> GetSolutionTargetsHelper(
+ HollowsZone compassUsedZone,
+ EnumSet<Crystal> foundCrystals,
+ EnumSet<CompassTarget> possibleTargets,
+ Vec3Comparable solutionCoords,
+ int expectedSolutionCount
+ ) {
+ EnumSet<CompassTarget> solutionTargets =
+ CrystalWishingCompassSolver.getSolutionTargets(
+ compassUsedZone,
+ foundCrystals,
+ possibleTargets,
+ solutionCoords
+ );
+ Assertions.assertEquals(expectedSolutionCount, solutionTargets.size());
+ return solutionTargets;
+ }
+
+ @Test
+ void solutionPossibleTargets_removes_nucleus_when_coords_not_in_nucleus() {
+ // Arrange & Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.MITHRIL_DEPOSITS,
+ EnumSet.noneOf(Crystal.class),
+ EnumSet.allOf(CompassTarget.class),
+ new Vec3Comparable(minesOfDivanSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertFalse(solutionTargets.contains(CompassTarget.CRYSTAL_NUCLEUS));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_jungle_temple_and_bal_from_other_zones_when_overlapping() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.GOBLIN_HOLDOUT,
+ EnumSet.of(Crystal.AMBER),
+ possibleTargets,
+ new Vec3Comparable(202, 72, 513), // upper left of Goblin Holdout
+ 2
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.JUNGLE_TEMPLE));
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_king_odawa_and_mines_of_divan_from_other_zones_when_overlapping() {
+ // Arrange & Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.PRECURSOR_REMNANTS,
+ EnumSet.noneOf(Crystal.class),
+ EnumSet.allOf(CompassTarget.class),
+ kingOdawaMinesOrNucleusCoordsInRemnants,
+ 3
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_KING));
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.MINES_OF_DIVAN));
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.ODAWA));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_city_and_queen_from_other_zones_when_overlapping() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.GOBLIN_KING);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.MITHRIL_DEPOSITS,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ queenKingOdawaOrCityNucleusCoordsInMithrilDeposits,
+ 2
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_QUEEN));
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.PRECURSOR_CITY));
+ }
+
+ @Test
+ void solutionPossibleTargets_excludes_jungle_temple_from_other_zone_when_not_overlapping() {
+ // Arrange
+ Vec3Comparable notOverlapping = new Vec3Comparable(202, 72, 513 + 110); // upper left of Goblin Holdout
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.GOBLIN_HOLDOUT,
+ EnumSet.of(Crystal.AMBER),
+ possibleTargets,
+ notOverlapping,
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL));
+ }
+
+ @Test
+ void solutionPossibleTargets_excludes_king_odawa_and_mines_of_divan_from_other_zones_when_not_overlapping() {
+ // Arrange
+ Vec3Comparable notOverlapping = kingOdawaMinesOrNucleusCoordsInRemnants.addVector(100, 0, 100);
+
+ // Act & Assert
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.PRECURSOR_REMNANTS,
+ EnumSet.noneOf(Crystal.class),
+ EnumSet.allOf(CompassTarget.class),
+ notOverlapping,
+ 0
+ );
+ }
+
+ @Test
+ void solutionPossibleTargets_excludes_city_and_queen_from_other_zones_when_not_overlapping() {
+ // Arrange
+ Vec3Comparable notOverlapping = queenKingOdawaOrCityNucleusCoordsInMithrilDeposits.addVector(100, 0, -100);
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.GOBLIN_KING);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act & Assert
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.MITHRIL_DEPOSITS,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ notOverlapping,
+ 0
+ );
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_king_based_on_y_coordinate() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.GOBLIN_HOLDOUT,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ new Vec3Comparable(goblinHoldoutKingSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_KING));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_odawa_based_on_y_coordinate() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.GOBLIN_KING);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.JUNGLE,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ new Vec3Comparable(odawaSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.ODAWA));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_mines_based_on_y_coordinate() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.MITHRIL_DEPOSITS,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ new Vec3Comparable(minesOfDivanSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.MINES_OF_DIVAN));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_temple_based_on_y_coordinate() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.BAL);
+ possibleTargets.remove(CompassTarget.ODAWA);
+ possibleTargets.remove(CompassTarget.GOBLIN_KING);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.JUNGLE,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ new Vec3Comparable(jungleSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.JUNGLE_TEMPLE));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_queen_based_on_y_coordinate() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.GOBLIN_KING);
+ possibleTargets.remove(CompassTarget.ODAWA);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.GOBLIN_HOLDOUT,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ new Vec3Comparable(goblinHoldoutQueenSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.GOBLIN_QUEEN));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_city_based_on_y_coordinate() {
+ // Arrange
+ EnumSet<CompassTarget> possibleTargets = EnumSet.allOf(CompassTarget.class);
+ possibleTargets.remove(CompassTarget.GOBLIN_KING);
+
+ // Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.PRECURSOR_REMNANTS,
+ EnumSet.noneOf(Crystal.class),
+ possibleTargets,
+ new Vec3Comparable(precursorCitySolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.PRECURSOR_CITY));
+ }
+
+ @Test
+ void solutionPossibleTargets_includes_bal_based_on_y_coordinate() {
+ // Arrange & Act
+ EnumSet<CompassTarget> solutionTargets = GetSolutionTargetsHelper(
+ HollowsZone.MAGMA_FIELDS,
+ EnumSet.noneOf(Crystal.class),
+ EnumSet.allOf(CompassTarget.class),
+ new Vec3Comparable(magmaSolution),
+ 1
+ );
+
+ // Assert
+ Assertions.assertTrue(solutionTargets.contains(CompassTarget.BAL));
+ }
+
+ // Represents a particle spawn, including:
+ // - Milliseconds to increment the "system time" prior to spawn.
+ // - The particle spawn location.
+ static class ParticleSpawn {
+ long timeIncrementMillis;
+ Vec3Comparable spawnLocation;
+
+ ParticleSpawn(Vec3Comparable spawnLocation, long timeIncrementMillis) {
+ this.timeIncrementMillis = timeIncrementMillis;
+ this.spawnLocation = spawnLocation;
+ }
+
+ ParticleSpawn(ParticleSpawn source) {
+ timeIncrementMillis = source.timeIncrementMillis;
+ spawnLocation = new Vec3Comparable(source.spawnLocation);
+ }
+ }
+
+ // Represents a use of the wishing compass, including:
+ // - Milliseconds to increment the "system time" prior to use.
+ // - The player's position when the compass is used.
+ // - The resulting set of particles
+ // - The expected state of the wishing compass solver after this compass is used
+ static class CompassUse {
+ long timeIncrementMillis;
+ BlockPos playerPos;
+ ArrayList<ParticleSpawn> particles;
+ HandleCompassResult expectedHandleCompassUseResult;
+ SolverState expectedSolverState;
+
+ CompassUse(
+ long timeIncrementMillis,
+ BlockPos playerPos,
+ ArrayList<ParticleSpawn> particles,
+ HandleCompassResult expectedHandleCompassUseResult,
+ SolverState expectedState
+ ) {
+ this.timeIncrementMillis = timeIncrementMillis;
+ this.playerPos = playerPos;
+ this.particles = particles != null ? particles : new ArrayList<>();
+ this.expectedHandleCompassUseResult = expectedHandleCompassUseResult;
+ this.expectedSolverState = expectedState;
+ }
+
+ CompassUse(CompassUse source) {
+ this.timeIncrementMillis = source.timeIncrementMillis;
+ this.playerPos = new BlockPos(source.playerPos);
+ this.particles = new ArrayList<>(source.particles);
+ this.expectedHandleCompassUseResult = source.expectedHandleCompassUseResult;
+ this.expectedSolverState = source.expectedSolverState;
+ }
+ }
+
+ static class Solution {
+ ArrayList<CompassUse> compassUses;
+ Vec3i expectedSolutionCoords;
+
+ Solution(ArrayList<CompassUse> compassUses, Vec3i expectedSolutionCoords) {
+ this.compassUses = compassUses;
+ this.expectedSolutionCoords = new Vec3i(
+ expectedSolutionCoords.getX(),
+ expectedSolutionCoords.getY(),
+ expectedSolutionCoords.getZ()
+ );
+ }
+ }
+
+ private static void neuDebugLog(String message) {
+ System.out.println(message);
+ }
+}
diff --git a/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java b/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java
new file mode 100644
index 00000000..66ba5442
--- /dev/null
+++ b/src/test/java/io/github/moulberry/notenoughupdates/util/CalculatorTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+public class CalculatorTest {
+ public static void main(String[] args) throws Calculator.CalculatorException {
+ List<Calculator.Token> lex = Calculator.lex("10k + 3 * 4m");
+ List<Calculator.Token> shunted = Calculator.shuntingYard(lex);
+ for (Calculator.Token rawToken : shunted) {
+ System.out.printf(
+ "%s(%s)",
+ rawToken.type,
+ rawToken.operatorValue == null ? rawToken.numericValue + " * 10 ^ " + rawToken.exponent : rawToken.operatorValue
+ );
+ }
+ System.out.println();
+ BigDecimal evaluate = Calculator.evaluate(shunted);
+ System.out.println("Eval: " + evaluate);
+ }
+
+}
diff --git a/src/test/resources/log4j2-test.xml b/src/test/resources/log4j2-test.xml
new file mode 100644
index 00000000..61ee1966
--- /dev/null
+++ b/src/test/resources/log4j2-test.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+ <Appenders>
+ <Console name="SysOut" target="SYSTEM_OUT">
+ <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %msg{nolookups}%n"/>
+ </Console>
+ </Appenders>
+ <Loggers>
+ <Root level="info">
+ <filters>
+ <MarkerFilter marker="NETWORK_PACKETS" onMatch="DENY" onMismatch="NEUTRAL"/>
+ </filters>
+ <AppenderRef ref="SysOut"/>
+ </Root>
+ </Loggers>
+</Configuration>