From 4352ffb08d4bfffc06adad2a068f375ab9874333 Mon Sep 17 00:00:00 2001 From: J10a1n15 <45315647+j10a1n15@users.noreply.github.com> Date: Tue, 12 Mar 2024 19:59:55 +0100 Subject: Feature: CustomScoreboard (#893) Co-authored-by: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com> Co-authored-by: Thunderblade73 Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt | 16 +- .../java/at/hannibal2/skyhanni/config/Storage.java | 37 ++ .../config/core/config/gui/GuiPositionEditor.kt | 2 + .../skyhanni/config/features/dev/DevConfig.java | 5 + .../skyhanni/config/features/gui/GUIConfig.java | 6 + .../gui/customscoreboard/AlignmentConfig.java | 20 + .../gui/customscoreboard/BackgroundConfig.java | 66 +++ .../customscoreboard/CustomScoreboardConfig.java | 65 +++ .../gui/customscoreboard/DisplayConfig.java | 96 ++++ .../InformationFilteringConfig.java | 23 + .../features/gui/customscoreboard/MayorConfig.java | 17 + .../features/gui/customscoreboard/PartyConfig.java | 23 + .../gui/customscoreboard/TitleAndFooterConfig.java | 32 ++ .../skyhanni/config/features/misc/MiscConfig.java | 2 +- .../java/at/hannibal2/skyhanni/data/ArrowType.kt | 9 + .../java/at/hannibal2/skyhanni/data/BitsAPI.kt | 200 +++++++ .../java/at/hannibal2/skyhanni/data/FameRanks.kt | 26 + .../at/hannibal2/skyhanni/data/GuiEditManager.kt | 15 + .../java/at/hannibal2/skyhanni/data/HypixelData.kt | 3 + .../java/at/hannibal2/skyhanni/data/MaxwellAPI.kt | 152 +++++ .../java/at/hannibal2/skyhanni/data/MayorAPI.kt | 121 ++++ .../at/hannibal2/skyhanni/data/MayorElection.kt | 79 --- src/main/java/at/hannibal2/skyhanni/data/Mayors.kt | 105 ++++ .../java/at/hannibal2/skyhanni/data/PartyAPI.kt | 4 +- .../java/at/hannibal2/skyhanni/data/PurseAPI.kt | 14 +- .../java/at/hannibal2/skyhanni/data/QuiverAPI.kt | 256 +++++++++ .../at/hannibal2/skyhanni/data/ScoreboardData.kt | 18 +- .../java/at/hannibal2/skyhanni/data/SlayerAPI.kt | 2 +- .../data/jsonobjects/repo/ArrowTypeJson.java | 14 + .../data/jsonobjects/repo/FameRankJson.java | 24 + .../skyhanni/data/jsonobjects/repo/ItemsJson.java | 3 + .../data/jsonobjects/repo/MaxwellPowersJson.java | 10 + .../skyhanni/events/GuiPositionMovedEvent.kt | 3 + .../hannibal2/skyhanni/features/bingo/BingoAPI.kt | 2 + .../skyhanni/features/event/diana/DianaAPI.kt | 6 +- .../features/garden/contest/FarmingContestAPI.kt | 2 +- .../features/garden/farming/GardenCropSpeed.kt | 4 +- .../gui/customscoreboard/CustomScoreboard.kt | 130 +++++ .../gui/customscoreboard/CustomScoreboardUtils.kt | 53 ++ .../gui/customscoreboard/RenderBackground.kt | 87 +++ .../gui/customscoreboard/ScoreboardElements.kt | 635 +++++++++++++++++++++ .../gui/customscoreboard/ScoreboardEvents.kt | 498 ++++++++++++++++ .../gui/customscoreboard/ScoreboardPattern.kt | 404 +++++++++++++ .../gui/customscoreboard/UnknownLinesHandler.kt | 156 +++++ .../skyhanni/features/inventory/MaxPurseItems.kt | 4 +- .../hannibal2/skyhanni/features/minion/MinionXp.kt | 4 +- .../skyhanni/features/misc/ServerRestartTitle.kt | 21 +- .../features/misc/compacttablist/TabListReader.kt | 4 +- .../misc/compacttablist/TabListRenderer.kt | 4 +- .../area/stillgorechateau/RiftBloodEffigies.kt | 23 +- .../skyhanni/mixins/hooks/GuiIngameHook.kt | 9 +- .../at/hannibal2/skyhanni/test/DebugCommand.kt | 4 +- .../skyhanni/test/SkyHanniDebugsAndTests.kt | 2 +- .../skyhanni/test/command/ErrorManager.kt | 3 +- .../at/hannibal2/skyhanni/utils/CollectionUtils.kt | 27 + .../at/hannibal2/skyhanni/utils/LorenzUtils.kt | 6 +- .../java/at/hannibal2/skyhanni/utils/NumberUtil.kt | 12 +- .../at/hannibal2/skyhanni/utils/RenderUtils.kt | 61 +- .../at/hannibal2/skyhanni/utils/SimpleTimeMark.kt | 2 + .../at/hannibal2/skyhanni/utils/TabListData.kt | 7 +- .../java/at/hannibal2/skyhanni/utils/TimeUtils.kt | 34 +- .../skyhanni/utils/shader/ShaderManager.kt | 6 +- 62 files changed, 3524 insertions(+), 154 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/AlignmentConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/BackgroundConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomScoreboardConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/InformationFilteringConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/PartyConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/TitleAndFooterConfig.java create mode 100644 src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt delete mode 100644 src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/Mayors.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/QuiverAPI.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/ArrowTypeJson.java create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/FameRankJson.java create mode 100644 src/main/java/at/hannibal2/skyhanni/data/jsonobjects/repo/MaxwellPowersJson.java create mode 100644 src/main/java/at/hannibal2/skyhanni/events/GuiPositionMovedEvent.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/RenderBackground.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvents.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/UnknownLinesHandler.kt (limited to 'src/main/java') diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index 6c05aadbd..d7d68ba78 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -11,12 +11,14 @@ import at.hannibal2.skyhanni.config.SackData import at.hannibal2.skyhanni.config.commands.Commands.init import at.hannibal2.skyhanni.data.ActionBarData import at.hannibal2.skyhanni.data.ActionBarStatsData +import at.hannibal2.skyhanni.data.BitsAPI import at.hannibal2.skyhanni.data.BlockData import at.hannibal2.skyhanni.data.BossbarData import at.hannibal2.skyhanni.data.ChatManager import at.hannibal2.skyhanni.data.CropAccessoryData import at.hannibal2.skyhanni.data.EntityData import at.hannibal2.skyhanni.data.EntityMovementData +import at.hannibal2.skyhanni.data.FameRanks import at.hannibal2.skyhanni.data.FriendAPI import at.hannibal2.skyhanni.data.GardenComposterUpgradesData import at.hannibal2.skyhanni.data.GardenCropMilestones @@ -30,7 +32,8 @@ import at.hannibal2.skyhanni.data.ItemClickData import at.hannibal2.skyhanni.data.ItemRenderBackground import at.hannibal2.skyhanni.data.ItemTipHelper import at.hannibal2.skyhanni.data.LocationFixData -import at.hannibal2.skyhanni.data.MayorElection +import at.hannibal2.skyhanni.data.MaxwellAPI +import at.hannibal2.skyhanni.data.MayorAPI import at.hannibal2.skyhanni.data.MinecraftData import at.hannibal2.skyhanni.data.OtherInventoryData import at.hannibal2.skyhanni.data.OwnInventoryData @@ -38,6 +41,7 @@ import at.hannibal2.skyhanni.data.PartyAPI import at.hannibal2.skyhanni.data.PetAPI import at.hannibal2.skyhanni.data.ProfileStorageData import at.hannibal2.skyhanni.data.PurseAPI +import at.hannibal2.skyhanni.data.QuiverAPI import at.hannibal2.skyhanni.data.RenderData import at.hannibal2.skyhanni.data.SackAPI import at.hannibal2.skyhanni.data.ScoreboardData @@ -284,6 +288,8 @@ import at.hannibal2.skyhanni.features.misc.TpsCounter import at.hannibal2.skyhanni.features.misc.compacttablist.AdvancedPlayerList import at.hannibal2.skyhanni.features.misc.compacttablist.TabListReader import at.hannibal2.skyhanni.features.misc.compacttablist.TabListRenderer +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern import at.hannibal2.skyhanni.features.misc.discordrpc.DiscordRPCManager import at.hannibal2.skyhanni.features.misc.items.AuctionHouseCopyUnderbidPrice import at.hannibal2.skyhanni.features.misc.items.EstimatedItemValue @@ -445,7 +451,6 @@ class SkyHanniMod { loadModule(GetFromSackAPI) loadModule(UpdateManager) loadModule(CropAccessoryData()) - loadModule(MayorElection()) loadModule(GardenComposterUpgradesData()) loadModule(ActionBarStatsData) loadModule(GardenCropMilestoneInventory()) @@ -464,6 +469,7 @@ class SkyHanniMod { loadModule(GardenBestCropTime()) loadModule(ActionBarData) loadModule(TrackerManager) + loadModule(ScoreboardPattern) loadModule(UtilsPatterns) loadModule(PetAPI) loadModule(BossbarData) @@ -485,7 +491,12 @@ class SkyHanniMod { loadModule(RiftAPI) loadModule(SackAPI) loadModule(BingoAPI) + loadModule(FameRanks) loadModule(FishingAPI) + loadModule(MaxwellAPI) + loadModule(QuiverAPI) + loadModule(BitsAPI) + loadModule(MayorAPI) loadModule(SkillAPI) loadModule(IsFishingDetection) loadModule(LorenzUtils) @@ -748,6 +759,7 @@ class SkyHanniMod { loadModule(DungeonFinderFeatures()) loadModule(PabloHelper()) loadModule(FishingBaitWarnings()) + loadModule(CustomScoreboard()) loadModule(RepoPatternManager) loadModule(PestSpawn()) loadModule(PestSpawnTimer) diff --git a/src/main/java/at/hannibal2/skyhanni/config/Storage.java b/src/main/java/at/hannibal2/skyhanni/config/Storage.java index 597d3a7eb..95286550c 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/Storage.java +++ b/src/main/java/at/hannibal2/skyhanni/config/Storage.java @@ -1,5 +1,6 @@ package at.hannibal2.skyhanni.config; +import at.hannibal2.skyhanni.data.FameRank; import at.hannibal2.skyhanni.api.SkillAPI; import at.hannibal2.skyhanni.data.model.ComposterUpgrade; import at.hannibal2.skyhanni.features.bingo.card.goals.BingoGoal; @@ -78,6 +79,9 @@ public class Storage { @Expose public Map players = new HashMap<>(); + @Expose + public String currentFameRank = null; + public static class PlayerSpecific { @Expose @@ -146,6 +150,39 @@ public class Storage { @Expose public String currentPet = ""; + @Expose + public MaxwellPowerStorage maxwell = new MaxwellPowerStorage(); + + public static class MaxwellPowerStorage { + @Expose + public String currentPower = null; + + @Expose + public int magicalPower = -1; + } + + @Expose + public ArrowsStorage arrows = new ArrowsStorage(); + + public static class ArrowsStorage { + @Expose + public String currentArrow = null; + + @Expose + public Map arrowAmount = new HashMap<>(); + } + + @Expose + public BitsStorage bits = new BitsStorage(); + + public static class BitsStorage { + @Expose + public int bits = -1; + + @Expose + public int bitsToClaim = -1; + } + @Expose public Map minions = new HashMap<>(); diff --git a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt index f6765ca2b..88264e994 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/core/config/gui/GuiPositionEditor.kt @@ -19,6 +19,7 @@ package at.hannibal2.skyhanni.config.core.config.gui import at.hannibal2.skyhanni.config.core.config.Position +import at.hannibal2.skyhanni.data.GuiEditManager import at.hannibal2.skyhanni.data.GuiEditManager.Companion.getAbsX import at.hannibal2.skyhanni.data.GuiEditManager.Companion.getAbsY import at.hannibal2.skyhanni.data.GuiEditManager.Companion.getDummySize @@ -216,6 +217,7 @@ class GuiPositionEditor(private val positions: List, private val borde val elementHeight = position.getDummySize(true).y grabbedX += position.moveX(mouseX - grabbedX, elementWidth) grabbedY += position.moveY(mouseY - grabbedY, elementHeight) + GuiEditManager.handleGuiPositionMoved(position.internalName) } } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java index 89170c027..3b5200c39 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/dev/DevConfig.java @@ -44,6 +44,11 @@ public class DevConfig { @ConfigEditorBoolean public boolean worldEdit = false; + @Expose + @ConfigOption(name = "Bow Sound distance", desc = "The distance in blocks where the sound of shooting a bow will be used for the QuiverAPI.") + @ConfigEditorSlider(minValue = 0, maxValue = 50, minStep = 1) + public int bowSoundDistance = 5; + @ConfigOption(name = "Parkour Waypoints", desc = "") @Accordion @Expose diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java index 4eeadf221..10b6cdde1 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/GUIConfig.java @@ -2,9 +2,11 @@ package at.hannibal2.skyhanni.config.features.gui; import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.config.features.gui.customscoreboard.CustomScoreboardConfig; import at.hannibal2.skyhanni.data.GuiEditManager; import com.google.gson.annotations.Expose; import io.github.moulberry.moulconfig.annotations.Accordion; +import io.github.moulberry.moulconfig.annotations.Category; import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; import io.github.moulberry.moulconfig.annotations.ConfigEditorButton; import io.github.moulberry.moulconfig.annotations.ConfigEditorKeybind; @@ -28,6 +30,10 @@ public class GUIConfig { @ConfigEditorSlider(minValue = 0.1F, maxValue = 10, minStep = 0.05F) public float globalScale = 1F; + @Expose + @Category(name = "Custom Scoreboard", desc = "Custom Scoreboard Settings") + public CustomScoreboardConfig customScoreboard = new CustomScoreboardConfig(); + @Expose @ConfigOption(name = "Modify Visual Words", desc = "") @Accordion diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/AlignmentConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/AlignmentConfig.java new file mode 100644 index 000000000..a5a8170f3 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/AlignmentConfig.java @@ -0,0 +1,20 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +public class AlignmentConfig { + // TODO: Switch to Dropdowns with multiple different alignment ways in the future + // Horizontal: Left, Center, Right + // Vertical: Top, Center, Bottom + @Expose + @ConfigOption(name = "Align to the right", desc = "Align the scoreboard to the right side of the screen.") + @ConfigEditorBoolean + public boolean alignRight = true; + + @Expose + @ConfigOption(name = "Align to the center vertically", desc = "Align the scoreboard to the center of the screen vertically.") + @ConfigEditorBoolean + public boolean alignCenterVertically = true; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/BackgroundConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/BackgroundConfig.java new file mode 100644 index 000000000..3b4924511 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/BackgroundConfig.java @@ -0,0 +1,66 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigEditorColour; +import io.github.moulberry.moulconfig.annotations.ConfigEditorInfoText; +import io.github.moulberry.moulconfig.annotations.ConfigEditorSlider; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +public class BackgroundConfig { + @Expose + @ConfigOption( + name = "Enabled", + desc = "Show a background behind the scoreboard." + ) + @ConfigEditorBoolean + public boolean enabled = true; + + @Expose + @ConfigOption( + name = "Background Color", + desc = "The color of the background." + ) + @ConfigEditorColour + public String color = "0:102:0:0:0"; + + @Expose + @ConfigOption( + name = "Background Border Size", + desc = "The size of the border around the background." + ) + @ConfigEditorSlider( + minValue = 0, + maxValue = 20, + minStep = 1 + ) + public int borderSize = 5; + + @Expose + @ConfigOption( + name = "Rounded Corner Smoothness", + desc = "The smoothness of the rounded corners." + ) + @ConfigEditorSlider( + minValue = 0, + maxValue = 30, + minStep = 1 + ) + public int roundedCornerSmoothness = 10; + + @Expose + @ConfigOption( + name = "Use Custom Background Image", + desc = "Put that image into a resource pack, using the path \"skyhanni/scoreboard.png\"." + ) + @ConfigEditorBoolean + public boolean useCustomBackgroundImage = false; + + @Expose + @ConfigOption( + name = "Custom Background", + desc = "Add an image named \"scoreboard.png\" to your texture pack at \"\\assets\\skyhanni\\scoreboard.png.\" Activate the texture pack in Minecraft, then reload the game." + ) + @ConfigEditorInfoText + public String useless; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomScoreboardConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomScoreboardConfig.java new file mode 100644 index 000000000..4941caf5c --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/CustomScoreboardConfig.java @@ -0,0 +1,65 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.config.core.config.Position; +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardElement; +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.Accordion; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigEditorDraggableList; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +import java.util.ArrayList; +import java.util.List; + +public class CustomScoreboardConfig { + @Expose + @ConfigOption( + name = "Enabled", + desc = "Show a custom scoreboard instead of the vanilla one." + ) + @ConfigEditorBoolean + @FeatureToggle + public boolean enabled = false; + + @Expose + @ConfigOption( + name = "Appearance", + desc = "Drag text to change the appearance of the advanced scoreboard." // supporting both custom & advanced search + ) + @ConfigEditorDraggableList() + public List scoreboardEntries = new ArrayList<>(ScoreboardElement.getEntries()); + + @Expose + @ConfigOption(name = "Display Options", desc = "") + @Accordion + public DisplayConfig displayConfig = new DisplayConfig(); + + @Expose + @ConfigOption(name = "Information Filtering", desc = "") + @Accordion + public InformationFilteringConfig informationFilteringConfig = new InformationFilteringConfig(); + + @Expose + @ConfigOption(name = "Background Options", desc = "") + @Accordion + public BackgroundConfig backgroundConfig = new BackgroundConfig(); + + @Expose + @ConfigOption(name = "Party Options", desc = "") + @Accordion + public PartyConfig partyConfig = new PartyConfig(); + + @Expose + @ConfigOption(name = "Mayor Options", desc = "") + @Accordion + public MayorConfig mayorConfig = new MayorConfig(); + + @Expose + @ConfigOption(name = "Unknown Lines warning", desc = "Gives a chat warning when unknown lines are found in the scoreboard.") + @ConfigEditorBoolean + public boolean unknownLinesWarning = true; + + @Expose + public Position position = new Position(10, 80, false, true); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java new file mode 100644 index 000000000..f009533ba --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/DisplayConfig.java @@ -0,0 +1,96 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import at.hannibal2.skyhanni.config.FeatureToggle; +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.Accordion; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigEditorDropdown; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +public class DisplayConfig { + @Expose + @ConfigOption(name = "Hide Vanilla Scoreboard", desc = "Hide the vanilla scoreboard.") + @ConfigEditorBoolean + @FeatureToggle + public boolean hideVanillaScoreboard = true; + + @Expose + @ConfigOption(name = "Display Numbers First", desc = "Determines whether the number or line name displays first. " + + "§eNote: Will not update the preview above!") + @ConfigEditorBoolean + public boolean displayNumbersFirst = false; + + @Expose + @ConfigOption(name = "Show unclaimed bits", desc = "Show the amount of available Bits that can still be claimed.") + @ConfigEditorBoolean + public boolean showUnclaimedBits = false; + + @Expose + @ConfigOption(name = "Show all active events", desc = "Show all active events in the scoreboard instead of one.") + @ConfigEditorBoolean + public boolean showAllActiveEvents = false; + + @Expose + @ConfigOption(name = "Cache Scoreboard on Island Switch", + desc = "Will stop the Scoreboard from updating while switching islands.\nRemoves the shaking when loading data.") + @ConfigEditorBoolean + public boolean cacheScoreboardOnIslandSwitch = false; + + @Expose + @ConfigOption(name = "Number Format", desc = "") + @ConfigEditorDropdown + public NumberFormat numberFormat = NumberFormat.LONG; + + public enum NumberFormat { + LONG("1,234,567"), + SHORT("1.2M"); + + private final String str; + + NumberFormat(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigOption(name = "Arrow Amount Display", desc = "Determines how the arrow amount is displayed.") + @ConfigEditorDropdown + public ArrowAmountDisplay arrowAmountDisplay = ArrowAmountDisplay.NUMBER; + + public enum ArrowAmountDisplay { + NUMBER("Number"), + PERCENTAGE("Percentage"), + ; + + private final String str; + + ArrowAmountDisplay(String str) { + this.str = str; + } + + @Override + public String toString() { + return str; + } + } + + @Expose + @ConfigOption(name = "Color Arrow Amount", desc = "Color the arrow amount based on the percentage.") + @ConfigEditorBoolean + public boolean colorArrowAmount = false; + + @Expose + @ConfigOption(name = "Alignment Options", desc = "") + @Accordion + public AlignmentConfig alignment = new AlignmentConfig(); + + @Expose + @ConfigOption(name = "Title and Footer Options", desc = "") + @Accordion + public TitleAndFooterConfig titleAndFooter = new TitleAndFooterConfig(); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/InformationFilteringConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/InformationFilteringConfig.java new file mode 100644 index 000000000..02a8f83a0 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/InformationFilteringConfig.java @@ -0,0 +1,23 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +public class InformationFilteringConfig { + @Expose + @ConfigOption(name = "Hide lines with no info", desc = "Hide lines that have no info to display, like hiding the party when not being in one.") + @ConfigEditorBoolean + public boolean hideEmptyLines = true; + + @Expose + @ConfigOption(name = "Hide consecutive empty lines", desc = "Hide lines that are empty and have an empty line above them.") + @ConfigEditorBoolean + public boolean hideConsecutiveEmptyLines = true; + + @Expose + @ConfigOption(name = "Hide non relevant info", desc = "Hide lines that are not relevant to the current location." + + "\n§cIt's generally not recommended to turn this off.") + @ConfigEditorBoolean + public boolean hideIrrelevantLines = true; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java new file mode 100644 index 000000000..5a47e5a48 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/MayorConfig.java @@ -0,0 +1,17 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigOption; + +public class MayorConfig { + @Expose + @ConfigOption(name = "Show Mayor Perks", desc = "Show the perks of the current mayor.") + @ConfigEditorBoolean + public boolean showMayorPerks = true; + + @Expose + @ConfigOption(name = "Show Time till next mayor", desc = "Show the time till the next mayor is elected.") + @ConfigEditorBoolean + public boolean showTimeTillNextMayor = true; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/PartyConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/PartyConfig.java new file mode 100644 index 000000000..2850882b7 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/PartyConfig.java @@ -0,0 +1,23 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigEditorSlider; +import io.github.moulberry.moulconfig.annotations.ConfigOption; +import io.github.moulberry.moulconfig.observer.Property; + +public class PartyConfig { + @Expose + @ConfigOption(name = "Max Party List", desc = "Max number of party members to show in the party list (You are not included).") + @ConfigEditorSlider( + minValue = 1, + maxValue = 25, // why do I even set it so high + minStep = 1 + ) + public Property maxPartyList = Property.of(4); + + @Expose + @ConfigOption(name = "Show Party everywhere", desc = "Show the party list everywhere.\nIf disabled, it will only show in Dungeon hub, Crimson Isle & Kuudra.") + @ConfigEditorBoolean + public boolean showPartyEverywhere = false; +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/TitleAndFooterConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/TitleAndFooterConfig.java new file mode 100644 index 000000000..d88115dff --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/TitleAndFooterConfig.java @@ -0,0 +1,32 @@ +package at.hannibal2.skyhanni.config.features.gui.customscoreboard; + +import at.hannibal2.skyhanni.utils.RenderUtils; +import com.google.gson.annotations.Expose; +import io.github.moulberry.moulconfig.annotations.ConfigEditorBoolean; +import io.github.moulberry.moulconfig.annotations.ConfigEditorDropdown; +import io.github.moulberry.moulconfig.annotations.ConfigEditorText; +import io.github.moulberry.moulconfig.annotations.ConfigOption; +import io.github.moulberry.moulconfig.observer.Property; + +public class TitleAndFooterConfig { + @Expose + @ConfigOption(name = "Title and Footer Alignment", desc = "Align the title and footer in the scoreboard.") + @ConfigEditorDropdown + public RenderUtils.HorizontalAlignment alignTitleAndFooter = RenderUtils.HorizontalAlignment.CENTER; + + @Expose + @ConfigOption(name = "Custom Title", desc = "What should be displayed as the title of the scoreboard.\nUse & for colors.") + @ConfigEditorText + public Property customTitle = Property.of("&6&lSKYBLOCK"); + + @Expose + @ConfigOption(name = "Hypixel's Title Animation", desc = "Will overwrite the custom title with Hypixel's title animation." + + "\nWill also include \"COOP\" if you are in a coop.") + @ConfigEditorBoolean + public boolean useHypixelTitleAnimation = false; + + @Expose + @ConfigOption(name = "Custom Footer", desc = "What should be displayed as the footer of the scoreboard.\nUse & for colors.") + @ConfigEditorText + public Property customFooter = Property.of("&ewww.hypixel.net"); +} diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java index 077bd8303..40b078961 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java @@ -137,7 +137,7 @@ public class MiscConfig { public boolean hidePiggyScoreboard = true; @Expose - @ConfigOption(name = "Color Month Names", desc = "Color the month names in the Scoreboard.") + @ConfigOption(name = "Color Month Names", desc = "Color the month names in the Scoreboard.\nAlso applies to the Custom Scoreboard.") @ConfigEditorBoolean @FeatureToggle public boolean colorMonthNames = false; diff --git a/src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt b/src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt new file mode 100644 index 000000000..5ce7dd33f --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/ArrowType.kt @@ -0,0 +1,9 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.utils.NEUInternalName + +data class ArrowType(val arrow: String, val internalName: NEUInternalName) { + override fun toString(): String { + return internalName.asString() + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt new file mode 100644 index 000000000..2802399bf --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/BitsAPI.kt @@ -0,0 +1,200 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.data.FameRanks.getFameRankByNameOrNull +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.ScoreboardChangeEvent +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils.removeResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object BitsAPI { + private val profileStorage get() = ProfileStorageData.profileSpecific?.bits + private val playerStorage get() = SkyHanniMod.feature.storage + + var bits: Int + get() = profileStorage?.bits ?: 0 + private set(value) { + profileStorage?.bits = value + } + var currentFameRank: FameRank? + get() = playerStorage?.currentFameRank?.let { getFameRankByNameOrNull(it) } + private set(value) { + if (value != null) { + playerStorage?.currentFameRank = value.name + } + } + var bitsToClaim: Int + get() = profileStorage?.bitsToClaim ?: 0 + private set(value) { + profileStorage?.bitsToClaim = value + } + + private const val defaultcookiebits = 4800 + + private val bitsDataGroup = RepoPattern.group("data.bits") + + // Scoreboard patterns + val bitsScoreboardPattern by bitsDataGroup.pattern( + "scoreboard", + "^Bits: §b(?[\\d,.]+).*$" + ) + + // Chat patterns + private val bitsChatGroup = bitsDataGroup.group("chat") + + private val bitsFromFameRankUpChatPattern by bitsChatGroup.pattern( + "famerankup", + "§eYou gained §3(?.*) Bits Available §ecompounded from all your §epreviously eaten §6cookies§e! Click here to open §6cookie menu§e!" + ) + + private val boosterCookieAte by bitsChatGroup.pattern( + "boostercookieate", + "§eYou consumed a §6Booster Cookie§e!.*" + ) + + // GUI patterns + private val bitsGuiGroup = bitsDataGroup.group("gui") + + private val bitsAvailableMenuPattern by bitsGuiGroup.pattern( + "availablemenu", + "§7Bits Available: §b(?[\\d,]+)(§3.+)?" + ) + + private val fameRankSbMenuPattern by bitsGuiGroup.pattern( + "sbmenufamerank", + "§7Your rank: §e(?.*)" + ) + + private val fameRankCommunityShopPattern by bitsGuiGroup.pattern( + "communityshopfamerank", + "§7Fame Rank: §e(?.*)" + ) + + private val bitsGuiNamePattern by bitsGuiGroup.pattern( + "mainmenuname", + "^SkyBlock Menu$" + ) + + private val bitsGuiStackPattern by bitsGuiGroup.pattern( + "mainmenustack", + "^§6Booster Cookie$" + ) + + private val fameRankGuiNamePattern by bitsGuiGroup.pattern( + "famerankmenuname", + "^(Community Shop|Booster Cookie)$" + ) + + private val fameRankGuiStackPattern by bitsGuiGroup.pattern( + "famerankmenustack", + "^(§aCommunity Shop|§eFame Rank)$" + ) + + @SubscribeEvent + fun onScoreboardChange(event: ScoreboardChangeEvent) { + if (!isEnabled()) return + for (line in event.newList) { + val message = line.trimWhiteSpace().removeResets() + + bitsScoreboardPattern.matchMatcher(message) { + val amount = group("amount").formatInt() + + if (amount > bits) { + bitsToClaim -= amount - bits + ChatUtils.debug("You have gained §3${amount - bits} Bits §7according to the scoreboard!") + } + bits = amount + + return + } + } + } + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + val message = event.message.trimWhiteSpace().removeResets() + + bitsFromFameRankUpChatPattern.matchMatcher(message) { + val amount = group("amount").formatInt() + bitsToClaim += amount + + return + } + + boosterCookieAte.matchMatcher(message) { + bitsToClaim += (defaultcookiebits * (currentFameRank?.bitsMultiplier ?: return)).toInt() + + return + } + } + + @SubscribeEvent + fun onInventoryFullyLoaded(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + + val stacks = event.inventoryItems + + if (bitsGuiNamePattern.matches(event.inventoryName)) { + val cookieStack = stacks.values.lastOrNull { bitsGuiStackPattern.matches(it.displayName) } ?: return + for (line in cookieStack.getLore()) { + bitsAvailableMenuPattern.matchMatcher(line) { + bitsToClaim = group("toClaim").formatInt() + + return + } + } + return + } + + if (fameRankGuiNamePattern.matches(event.inventoryName)) { + val fameRankStack = stacks.values.lastOrNull { fameRankGuiStackPattern.matches(it.displayName) } ?: return + + line@ for (line in fameRankStack.getLore()) { + fameRankCommunityShopPattern.matchMatcher(line) { + val rank = group("rank") + + currentFameRank = getFameRankByNameOrNull(rank) + ?: return ErrorManager.logErrorWithData( + FameRankNotFoundException(rank), + "FameRank $rank not found", + "Rank" to rank, + "Lore" to fameRankStack.getLore(), + "FameRanks" to FameRanks.fameRanks + ) + + continue@line + } + + fameRankSbMenuPattern.matchMatcher(line) { + val rank = group("rank") + + currentFameRank = getFameRankByNameOrNull(rank) + ?: return ErrorManager.logErrorWithData( + FameRankNotFoundException(rank), + "FameRank $rank not found", + "Rank" to rank, + "Lore" to fameRankStack.getLore(), + "FameRanks" to FameRanks.fameRanks + ) + + continue@line + } + } + } + } + + fun isEnabled() = LorenzUtils.inSkyBlock && profileStorage != null + + class FameRankNotFoundException(rank: String) : Exception("FameRank not found: $rank") +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt b/src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt new file mode 100644 index 000000000..663e2b970 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/FameRanks.kt @@ -0,0 +1,26 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.jsonobjects.repo.FameRankJson +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object FameRanks { + var fameRanks = emptyMap() + private set + + fun getFameRankByNameOrNull(name: String) = fameRanks[name] + + @SubscribeEvent + fun onRepoReload(event: RepositoryReloadEvent) { + val ranks = event.getConstant("FameRank") + fameRanks = ranks.fame_rank.values.map { FameRank(it.name, it.fame_required, it.bits_multiplier, it.votes) } + .associateBy { it.name } + } +} + +data class FameRank( + val name: String, + val fameRequired: Int, + val bitsMultiplier: Double, + val electionVotes: Int +) diff --git a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt index 4fbebe958..ee9a6a23a 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/GuiEditManager.kt @@ -3,8 +3,10 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.core.config.Position import at.hannibal2.skyhanni.config.core.config.gui.GuiPositionEditor +import at.hannibal2.skyhanni.events.GuiPositionMovedEvent import at.hannibal2.skyhanni.events.GuiRenderEvent import at.hannibal2.skyhanni.events.LorenzKeyPressEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.test.SkyHanniDebugsAndTests import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils.isRancherSign @@ -51,11 +53,20 @@ class GuiEditManager { currentPositions.clear() } + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + lastMovedGui?.let { + GuiPositionMovedEvent(it).postAndCatch() + lastMovedGui = null + } + } + companion object { var currentPositions = mutableMapOf() private var latestPositions = mapOf() private var currentBorderSize = mutableMapOf>() + private var lastMovedGui: String? = null @JvmStatic fun add(position: Position, posLabel: String, x: Int, y: Int) { @@ -116,6 +127,10 @@ class GuiEditManager { fun GuiProfileViewer.anyTextBoxFocused() = this.getPropertiesWithType().any { it.focus } + + fun handleGuiPositionMoved(guiName: String) { + lastMovedGui = guiName + } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index b206eb565..c347fcdba 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -300,9 +300,12 @@ class HypixelData { private fun checkIsland() { var newIsland = "" var guesting = false + TabListData.fullyLoaded = false + for (line in TabListData.getTabList()) { islandNamePattern.matchMatcher(line) { newIsland = group("island").removeColor() + TabListData.fullyLoaded = true } if (line == " Status: §r§9Guest") { guesting = true diff --git a/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt new file mode 100644 index 000000000..0f19854f7 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt @@ -0,0 +1,152 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.jsonobjects.repo.MaxwellPowersJson +import at.hannibal2.skyhanni.events.InventoryFullyOpenedEvent +import at.hannibal2.skyhanni.events.LorenzChatEvent +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.ItemUtils.getLore +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.NumberUtil.formatInt +import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher +import at.hannibal2.skyhanni.utils.StringUtils.matches +import at.hannibal2.skyhanni.utils.StringUtils.removeColor +import at.hannibal2.skyhanni.utils.StringUtils.removeResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraft.enchantment.Enchantment +import net.minecraft.enchantment.Enchantment.power +import net.minecraft.item.ItemStack +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +object MaxwellAPI { + + private val storage get() = ProfileStorageData.profileSpecific + + var currentPower: String? + get() = storage?.maxwell?.currentPower + set(value) { + storage?.maxwell?.currentPower = value ?: return + } + var magicalPower: Int? + get() = storage?.maxwell?.magicalPower + set(value) { + storage?.maxwell?.magicalPower = value ?: return + } + + private var powers = mutableListOf() + + private val group = RepoPattern.group("data.maxwell") + private val chatPowerpattern by group.pattern( + "chat.power", + "§eYou selected the §a(?.*) §e(power )?for your §aAccessory Bag§e!" + ) + private val inventoryPowerPattern by group.pattern( + "inventory.power", + "§7Selected Power: §a(?.*)" + ) + private val inventoryMPPattern by group.pattern( + "inventory.magicalpower", + "§7Magical Power: §6(?[\\d,]+)" + ) + private val thaumaturgyGuiPattern by group.pattern( + "gui.thaumaturgy", + "Accessory Bag Thaumaturgy" + ) + private val yourBagsGuiPattern by group.pattern( + "gui.yourbags", + "Your Bags" + ) + private val powerSelectedPattern by group.pattern( + "gui.selectedpower", + "§aPower is selected!" + ) + + @SubscribeEvent + fun onChat(event: LorenzChatEvent) { + if (!isEnabled()) return + val message = event.message.trimWhiteSpace().removeResets() + + chatPowerpattern.matchMatcher(message) { + val power = group("power") + currentPower = getPowerByNameOrNull(power) + ?: return ErrorManager.logErrorWithData( + UnknownMaxwellPower("Unknown power: $power"), + "Unknown power: $power", + "power" to power, + "message" to message + ) + } + } + + @SubscribeEvent + fun onInventoryFullyLoaded(event: InventoryFullyOpenedEvent) { + if (!isEnabled()) return + + if (thaumaturgyGuiPattern.matches(event.inventoryName)) { + val selectedPowerStack = + event.inventoryItems.values.find { + powerSelectedPattern.matches(it.getLore().lastOrNull()) + } ?: return + val displayName = selectedPowerStack.displayName.removeColor() + + currentPower = getPowerByNameOrNull(displayName) + ?: return ErrorManager.logErrorWithData( + UnknownMaxwellPower("Unknown power: $power"), + "Unknown power: $power", + "power" to power, + "displayName" to displayName, + "lore" to selectedPowerStack.getLore() + ) + return + } + + if (yourBagsGuiPattern.matches(event.inventoryName)) { + val stacks = event.inventoryItems + + for (stack in stacks.values) { + processStack(stack) + } + } + } + + private fun processStack(stack: ItemStack) { + for (line in stack.getLore()) { + inventoryMPPattern.matchMatcher(line) { + // MagicalPower is boosted in catacombs + if (IslandType.CATACOMBS.isInIsland()) return@matchMatcher + + val mp = group("mp") + magicalPower = mp.formatInt() + return@matchMatcher + } + + inventoryPowerPattern.matchMatcher(line) { + val power = group("power") + currentPower = getPowerByNameOrNull(power) + ?: return@matchMatcher ErrorManager.logErrorWithData( + UnknownMaxwellPower("Unknown power: ${Enchantment.power}"), + "Unknown power: ${Enchantment.power}", + "power" to Enchantment.power, + "displayName" to stack.displayName, + "lore" to stack.getLore() + ) + return@matchMatcher + } + } + } + + private fun getPowerByNameOrNull(name: String) = powers.find { it == name } + + fun isEnabled() = LorenzUtils.inSkyBlock && storage != null + + // Load powers from repo + @SubscribeEvent + fun onRepoLoad(event: RepositoryReloadEvent) { + val data = event.getConstant("MaxwellPowers") + powers = data.powers + } + + class UnknownMaxwellPower(message: String) : Exception(message) +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt new file mode 100644 index 000000000..bc937a5a2 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/MayorAPI.kt @@ -0,0 +1,121 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.config.ConfigManager +import at.hannibal2.skyhanni.data.Mayor.Companion.setMayorWithActivePerks +import at.hannibal2.skyhanni.data.jsonobjects.local.MayorJson +import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.LorenzTickEvent +import at.hannibal2.skyhanni.utils.APIUtil +import at.hannibal2.skyhanni.utils.CollectionUtils.put +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.SimpleTimeMark +import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.asTimeMark +import io.github.moulberry.notenoughupdates.util.SkyBlockTime +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes + +object MayorAPI { + var lastUpdate = SimpleTimeMark.farPast() + private var dispatcher = Dispatchers.IO + + private var rawMayorData: MayorJson? = null + var candidates = mapOf() + private set + var currentMayor: Mayor? = null + private set + var timeTillNextMayor = Duration.ZERO + private set + + private const val ELECTION_END_MONTH = 3 //Late Spring + private const val ELECTION_END_DAY = 27 + + /** + * @param input: The name of the mayor + * @return: The neu color of the mayor; If no mayor was found, it will return "§cUnknown: §7" + */ + fun mayorNameToColorCode(input: String): String { + return Mayor.getMayorFromName(input).color + } + + /** + * @param input: The name of the mayor + * @return: The neu color of the mayor + the name of the mayor; If no mayor was found, it will return "§cUnknown: §7[input]" + */ + fun mayorNameWithColorCode(input: String) = mayorNameToColorCode(input) + input + + @SubscribeEvent + fun onTick(event: LorenzTickEvent) { + if (!LorenzUtils.onHypixel) return + + if (event.repeatSeconds(2)) { + checkHypixelAPI() + getTimeTillNextMayor() + } + } + + private fun calculateNextMayorTime(): SimpleTimeMark { + var mayorYear = SkyBlockTime.now().year + + // Check if either the month is already over or the day is after 27th in the third month + if (SkyBlockTime.now().month > ELECTION_END_MONTH || (SkyBlockTime.now().day >= ELECTION_END_DAY && SkyBlockTime.now().month == ELECTION_END_MONTH)) { + // If so, the next mayor will be in the next year + mayorYear++ + } + + return SkyBlockTime(mayorYear, ELECTION_END_MONTH, day = ELECTION_END_DAY).asTimeMark() + } + + private fun getTimeTillNextMayor() { + val nextMayorTime = calculateNextMayorTime() + timeTillNextMayor = nextMayorTime - SimpleTimeMark.now() + } + + private fun checkCurrentMayor() { + val nextMayorTime = calculateNextMayorTime() + + // Check if it is still the mayor from the old SkyBlock year + currentMayor = candidates[nextMayorTime.toSkyBlockTime().year - 1]?.let { + // TODO: Once Jerry is active, add the sub mayor perks in here + setMayorWithActivePerks(it.name, it.perks) + } + } + + private fun checkHypixelAPI() { + if (lastUpdate.passedSince() < 20.minutes) return + lastUpdate = SimpleTimeMark.now() + + SkyHanniMod.coroutineScope.launch { + val url = "https://api.hypixel.net/v2/resources/skyblock/election" + val jsonObject = withContext(dispatcher) { APIUtil.getJSONResponse(url) } + rawMayorData = ConfigManager.gson.fromJson(jsonObject, MayorJson::class.java) + val data = rawMayorData ?: return@launch + val map = mutableMapOf() + map put data.mayor.election.getPairs() + data.current?.let { + map put data.current.getPairs() + } + candidates = map + checkCurrentMayor() + } + } + + private fun MayorJson.Election.getPairs() = year + 1 to candidates.bestCandidate() + + private fun List.bestCandidate() = maxBy { it.votes } + + @SubscribeEvent + fun onDebugDataCollect(event: DebugDataCollectEvent) { + event.title("Mayor") + event.addIrrelevant { + add("Current Mayor: ${currentMayor?.name ?: "Unknown"}") + add("Active Perks: ${currentMayor?.activePerks}") + add("Last Update: $lastUpdate (${lastUpdate.passedSince()} ago)") + add("Time Till Next Mayor: $timeTillNextMayor") + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt b/src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt deleted file mode 100644 index e73a6bf14..000000000 --- a/src/main/java/at/hannibal2/skyhanni/data/MayorElection.kt +++ /dev/null @@ -1,79 +0,0 @@ -package at.hannibal2.skyhanni.data - -import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.config.ConfigManager -import at.hannibal2.skyhanni.data.jsonobjects.local.MayorJson -import at.hannibal2.skyhanni.events.LorenzTickEvent -import at.hannibal2.skyhanni.utils.APIUtil -import at.hannibal2.skyhanni.utils.CollectionUtils.put -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.SimpleTimeMark -import io.github.moulberry.notenoughupdates.util.SkyBlockTime -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent -import kotlin.time.Duration.Companion.minutes - -class MayorElection { - - private var lastUpdate = SimpleTimeMark.farPast() - private var dispatcher = Dispatchers.IO - - companion object { - - var rawMayorData: MayorJson? = null - var candidates = mapOf() - var currentCandidate: MayorJson.Candidate? = null - - fun isPerkActive(mayor: String, perk: String) = currentCandidate?.let { currentCandidate -> - currentCandidate.name == mayor && currentCandidate.perks.any { it.name == perk } - } ?: false - } - - @SubscribeEvent - fun onTick(event: LorenzTickEvent) { - if (!LorenzUtils.onHypixel) return - - if (event.repeatSeconds(3)) { - check() - } - } - - private fun check() { - if (lastUpdate.passedSince() < 20.minutes) return - lastUpdate = SimpleTimeMark.now() - - SkyHanniMod.coroutineScope.launch { - val url = "https://api.hypixel.net/v2/resources/skyblock/election" - val jsonObject = withContext(dispatcher) { APIUtil.getJSONResponse(url) } - rawMayorData = ConfigManager.gson.fromJson(jsonObject, MayorJson::class.java) - val data = rawMayorData ?: return@launch - val map = mutableMapOf() - map put data.mayor.election.getPairs() - data.current?.let { - map put data.current.getPairs() - } - candidates = map - checkCurrentMayor() - } - } - - private fun checkCurrentMayor() { - var currentYear = SkyBlockTime.now().year - - // The time in the current SkyBlock year when the election circle will restart - val month = 3 // Late Spring - val nextMayorTime = SkyBlockTime(currentYear, month, day = 27).toMillis() - - // Is it still the mayor from old sb year? - if (nextMayorTime > System.currentTimeMillis()) { - currentYear-- - } - currentCandidate = candidates[currentYear] - } - - private fun MayorJson.Election.getPairs() = year + 1 to candidates.bestCandidate() - - private fun List.bestCandidate() = maxBy { it.votes } -} diff --git a/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt new file mode 100644 index 000000000..cd6205c7a --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/Mayors.kt @@ -0,0 +1,105 @@ +package at.hannibal2.skyhanni.data + +import at.hannibal2.skyhanni.data.jsonobjects.local.MayorJson + +enum class Mayor( + val mayorName: String, + val color: String, + private vararg val perks: Perk, +) { + AATROX("Aatrox", "§3", Perk.SLASHED_PRICING, Perk.SLAYER_XP_BUFF, Perk.PATHFINDER), + COLE("Cole", "§e", Perk.PROSPECTION, Perk.MINING_XP_BUFF, Perk.MINING_FIESTA), + DIANA("Diana", "§2", Perk.LUCKY, Perk.MYTHOLOGICAL_RITUAL, Perk.PET_XP_BUFF), + DIAZ("Diaz", "§6", Perk.BARRIER_STREET, Perk.SHOPPING_SPREE), + FINNEGAN("Finnegan", "§c", Perk.FARMING_SIMULATOR, Perk.PELT_POCALYPSE, Perk.GOATED), + FOXY("Foxy", "§d", Perk.SWEET_TOOTH, Perk.BENEVOLENCE, Perk.EXTRA_EVENT), + MARINA("Marina", "§b", Perk.FISHING_XP_BUFF, Perk.LUCK_OF_THE_SEA, Perk.FISHING_FESTIVAL), + PAUL("Paul", "§c", Perk.MARAUDER, Perk.EZPZ, Perk.BENEDICTION), + + SCORPIUS("Scorpius", "§d", Perk.BRIBE, Perk.DARKER_AUCTIONS), + JERRY("Jerry", "§d", Perk.PERKPOCALYPSE, Perk.STATSPOCALYPSE, Perk.JERRYPOCALYPSE), + DERPY("Derpy", "§d", Perk.TURBO_MINIONS, Perk.AH_CLOSED, Perk.DOUBLE_MOBS_HP, Perk.MOAR_SKILLZ), + + UNKNOWN("Unknown", "§c"), + ; + + val activePerks: MutableList = mutableListOf() + + companion object { + fun getMayorFromName(name: String) = entries.firstOrNull { it.mayorName == name } ?: UNKNOWN + + fun setMayorWithActivePerks(name: String, perks: ArrayList): Mayor { + val mayor = getMayorFromName(name) + + mayor.perks.forEach { it.isActive = false } + mayor.activePerks.clear() + perks.mapNotNull { perk -> Perk.entries.firstOrNull { it.perkName == perk.name } } + .filter { mayor.perks.contains(it) }.forEach { + it.isActive = true + mayor.activePerks.add(it) + } + + return mayor + } + } +} + +enum class Perk(val perkName: String) { + // Aatrox + SLASHED_PRICING("SLASHED Pricing"), + SLAYER_XP_BUFF("Slayer XP Buff"), + PATHFINDER("Pathfinder"), + + // Cole + PROSPECTION("Prospection"), + MINING_XP_BUFF("Mining XP Buff"), + MINING_FIESTA("Mining Fiesta"), + + // Diana + LUCKY("Lucky!"), + MYTHOLOGICAL_RITUAL("Mythological Ritual"), + PET_XP_BUFF("Pet XP Buff"), + + // Diaz + BARRIER_STREET("Barrier Street"), + SHOPPING_SPREE("Shopping Spree"), + + // Finnegan + FARMING_SIMULATOR("Farming Simulator"), + PELT_POCALYPSE("Pelt-pocalypse"), + GOATED("GOATed"), + + // Foxy + SWEET_TOOTH("Sweet Tooth"), + BENEVOLENCE("Benevolence"), + EXTRA_EVENT("Extra Event"), + + // Marina + FISHING_XP_BUFF("Fishing XP Buff"), + LUCK_OF_THE_SEA("Luck of the Sea 2.0"), + FISHING_FESTIVAL("Fishing Festival"), + + // Paul + MARAUDER("Marauder"), + EZPZ("EZPZ"), + BENEDICTION("Benediction"), + + + // Scorpius + BRIBE("Bribe"), + DARKER_AUCTIONS("Darker Auctions"), + + // Jerry + PERKPOCALYPSE("Perkpocalypse"), + STATSPOCALYPSE("Statspocalypse"), + JERRYPOCALYPSE("Jerrypocalypse"), + + // Derpy + TURBO_MINIONS("TURBO MINIONS!!!"), + AH_CLOSED("AH CLOSED!!!"), + DOUBLE_MOBS_HP("DOUBLE MOBS HP!!!"), + MOAR_SKILLZ("MOAR SKILLZ!!!"), + ; + + var isActive = false +} diff --git a/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt index 22fb8e4f8..ace56f67f 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PartyAPI.kt @@ -8,7 +8,7 @@ import at.hannibal2.skyhanni.utils.StringUtils.cleanPlayerName import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.StringUtils.removeResets -import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpaceAndResets +import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.random.Random @@ -94,7 +94,7 @@ object PartyAPI { @SubscribeEvent fun onChat(event: LorenzChatEvent) { - val message = event.message.trimWhiteSpaceAndResets().removeResets() + val message = event.message.trimWhiteSpace().removeResets() // new member joined youJoinedPartyPattern.matchMatcher(message) { diff --git a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt index 90ea15627..f4266f800 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/PurseAPI.kt @@ -4,8 +4,8 @@ import at.hannibal2.skyhanni.events.InventoryCloseEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.PurseChangeCause import at.hannibal2.skyhanni.events.PurseChangeEvent -import at.hannibal2.skyhanni.utils.NumberUtil.formatNumber -import at.hannibal2.skyhanni.utils.NumberUtil.milion +import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble +import at.hannibal2.skyhanni.utils.NumberUtil.million import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern import net.minecraft.client.Minecraft @@ -13,7 +13,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object PurseAPI { private val patternGroup = RepoPattern.group("data.purse") - private val coinsPattern by patternGroup.pattern( + val coinsPattern by patternGroup.pattern( "coins", "(§.)*(Piggy|Purse): §6(?[\\d,.]+)( ?(§.)*\\([+-](?[\\d,.]+)\\)?|.*)?$" ) @@ -22,8 +22,9 @@ object PurseAPI { "Piggy: (?.*)" ) - private var currentPurse = 0.0 private var inventoryCloseTime = 0L + var currentPurse = 0.0 + private set @SubscribeEvent fun onInventoryClose(event: InventoryCloseEvent) { @@ -32,10 +33,9 @@ object PurseAPI { @SubscribeEvent fun onTick(event: LorenzTickEvent) { - for (line in ScoreboardData.sidebarLinesFormatted) {