diff --git a/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt b/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt index 95e39d1f73a7..aa930adb1dc0 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/SkillAPI.kt @@ -28,8 +28,8 @@ import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.NumberUtil.formatLong import at.hannibal2.skyhanni.utils.NumberUtil.formatLongOrUserError import at.hannibal2.skyhanni.utils.NumberUtil.romanToDecimalIfNecessary +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.StringUtils.matchMatcher import at.hannibal2.skyhanni.utils.StringUtils.removeColor import at.hannibal2.skyhanni.utils.TabListData import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt index 8228ae025274..93c7d3407235 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigUpdaterMigrator.kt @@ -12,7 +12,7 @@ import com.google.gson.JsonPrimitive object ConfigUpdaterMigrator { val logger = LorenzLogger("ConfigMigration") - const val CONFIG_VERSION = 62 + const val CONFIG_VERSION = 63 fun JsonElement.at(chain: List, init: Boolean): JsonElement? { if (chain.isEmpty()) return this if (this !is JsonObject) return null diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java index 4293dd168f8b..8e0941d30198 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/ChunkedStatsConfig.java @@ -1,6 +1,6 @@ package at.hannibal2.skyhanni.config.features.gui.customscoreboard; -import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStat; +import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStatsLine; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider; @@ -17,7 +17,7 @@ public class ChunkedStatsConfig { desc = "Select the stats you want to display chunked on the scoreboard." ) @ConfigEditorDraggableList - public List chunkedStats = new ArrayList<>(ChunkedStat.getEntries()); + public List chunkedStats = new ArrayList<>(ChunkedStatsLine.getEntries()); @Expose @ConfigOption( 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 index 38a749f35029..944b44cd4a86 100644 --- 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 @@ -2,7 +2,8 @@ import at.hannibal2.skyhanni.config.FeatureToggle; import at.hannibal2.skyhanni.config.core.config.Position; -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardElement; +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard; +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardConfigElement; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.Accordion; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; @@ -28,17 +29,14 @@ public class CustomScoreboardConfig { @Expose @ConfigOption( name = "Appearance", - desc = "Drag text to change the appearance of the advanced scoreboard." // supporting both custom & advanced search + desc = "Drag text to change the appearance of the advanced scoreboard." ) - @ConfigEditorDraggableList() - public List scoreboardEntries = new ArrayList<>(ScoreboardElement.defaultOption); + @ConfigEditorDraggableList + public Property> scoreboardEntries = Property.of(new ArrayList<>(ScoreboardConfigElement.defaultOptions)); @ConfigOption(name = "Reset Appearance", desc = "Reset the appearance of the advanced scoreboard.") @ConfigEditorButton(buttonText = "Reset") - public Runnable reset = () -> { - scoreboardEntries.clear(); - scoreboardEntries.addAll(ScoreboardElement.defaultOption); - }; + public Runnable reset = CustomScoreboard::resetAppearance; @Expose @ConfigOption(name = "Display Options", desc = "") @@ -56,7 +54,11 @@ public class CustomScoreboardConfig { public InformationFilteringConfig informationFiltering = new InformationFilteringConfig(); @Expose - @ConfigOption(name = "Unknown Lines warning", desc = "Give a chat warning when unknown lines are found in the scoreboard.") + @ConfigOption( + name = "Unknown Lines warning", + desc = "Give a chat warning when unknown lines are found in the scoreboard." + + "\n§cReporting these in the Discord Server are very important, so we can know what lines are missing." + ) @ConfigEditorBoolean public boolean unknownLinesWarning = 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 index 2f0eb502e509..39d8c09bfd7a 100644 --- 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 @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.config.features.gui.customscoreboard; import at.hannibal2.skyhanni.config.FeatureToggle; +import at.hannibal2.skyhanni.utils.RenderUtils; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.Accordion; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; @@ -51,7 +52,6 @@ public class DisplayConfig { @Accordion public TitleAndFooterConfig titleAndFooter = new TitleAndFooterConfig(); - @Expose @ConfigOption(name = "Hide Vanilla Scoreboard", desc = "Hide the vanilla scoreboard.\n" + "§cMods that add their own scoreboard will not be affected by this setting!") @@ -145,8 +145,16 @@ public String toString() { public int lineSpacing = 10; @Expose - @ConfigOption(name = "Cache Scoreboard on Island Switch", - desc = "Will stop the Scoreboard from updating while switching islands.\nRemoves the shaking when loading data.") + @ConfigOption(name = "Text Alignment", desc = "Will align the text to the left, center or right, while not overriding certain lines, like title or footer.") + @ConfigEditorDropdown + public RenderUtils.HorizontalAlignment textAlignment = RenderUtils.HorizontalAlignment.LEFT; + + @Expose + @ConfigOption( + name = "Cache Scoreboard on Island Switch", + desc = "Will stop the Scoreboard from updating while switching islands.\n" + + "Removes the shaking when loading data." + ) @ConfigEditorBoolean public boolean cacheScoreboardOnIslandSwitch = false; } diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/EventsConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/EventsConfig.java index e2663bf55c29..b091c8e90fee 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/EventsConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/gui/customscoreboard/EventsConfig.java @@ -1,11 +1,12 @@ package at.hannibal2.skyhanni.config.features.gui.customscoreboard; -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardEvent; +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardConfigEventElement; import com.google.gson.annotations.Expose; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorButton; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDraggableList; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; +import io.github.notenoughupdates.moulconfig.observer.Property; import java.util.ArrayList; import java.util.List; @@ -18,13 +19,15 @@ public class EventsConfig { desc = "Drag your list to select the priority of each event." ) @ConfigEditorDraggableList() - public List eventEntries = new ArrayList<>(ScoreboardEvent.defaultOption); + public Property> eventEntries = Property.of(new ArrayList<>(ScoreboardConfigEventElement.defaultOption)); @ConfigOption(name = "Reset Events Priority", desc = "Reset the priority of all events.") @ConfigEditorButton(buttonText = "Reset") + // TODO move into kotlin public Runnable reset = () -> { - eventEntries.clear(); - eventEntries.addAll(ScoreboardEvent.defaultOption); + eventEntries.get().clear(); + eventEntries.get().addAll(ScoreboardConfigEventElement.defaultOption); + eventEntries.notifyObservers(); }; @Expose 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 index 670e9b16b7f5..5a553369f37c 100644 --- 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 @@ -11,7 +11,7 @@ public class PartyConfig { @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 + maxValue = 25, minStep = 1 ) public Property maxPartyList = Property.of(4); @@ -21,4 +21,9 @@ public class PartyConfig { "If disabled, it will only show in Dungeon Hub, Crimson Isle & Kuudra.") @ConfigEditorBoolean public boolean showPartyEverywhere = false; + + @Expose + @ConfigOption(name = "Show Party Leader", desc = "Show the party leader in the party list.") + @ConfigEditorBoolean + public boolean showPartyLeader = true; } 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 index 1c3bb4304509..aae9fe026376 100644 --- 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 @@ -6,21 +6,19 @@ import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorDropdown; import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorText; import io.github.notenoughupdates.moulconfig.annotations.ConfigOption; -import io.github.notenoughupdates.moulconfig.observer.Property; public class TitleAndFooterConfig { @Expose - @ConfigOption(name = "Title and Footer Alignment", desc = "Align the title and footer in the scoreboard.") + @ConfigOption(name = "Title Alignment", desc = "Align the title in the scoreboard.") @ConfigEditorDropdown - // TODO rename to "horizontalAlignment" or "alignment" - public RenderUtils.HorizontalAlignment alignTitleAndFooter = RenderUtils.HorizontalAlignment.CENTER; + public RenderUtils.HorizontalAlignment alignTitle = RenderUtils.HorizontalAlignment.CENTER; @Expose @ConfigOption(name = "Custom Title", desc = "What should be displayed as the title of the scoreboard." + - "\nUse & for colors." + + "\nUse && for colors." + "\nUse \"\\n\" for new line.") @ConfigEditorText - public Property customTitle = Property.of("&6&lSKYBLOCK"); + public String customTitle = "&&6&&lSKYBLOCK"; @Expose @ConfigOption(name = "Use Custom Title", desc = "Use a custom title instead of the default Hypixel title.") @@ -32,10 +30,22 @@ public class TitleAndFooterConfig { @ConfigEditorBoolean public boolean useCustomTitleOutsideSkyBlock = false; + @Expose + @ConfigOption(name = "Footer Alignment", desc = "Align the footer in the scoreboard.") + @ConfigEditorDropdown + public RenderUtils.HorizontalAlignment alignFooter = RenderUtils.HorizontalAlignment.LEFT; + @Expose @ConfigOption(name = "Custom Footer", desc = "What should be displayed as the footer of the scoreboard." + - "\nUse & for colors." + + "\nUse && for colors." + + "\nUse \"\\n\" for new line.") + @ConfigEditorText + public String customFooter = "&&ewww.hypixel.net"; + + @Expose + @ConfigOption(name = "Custom Alpha Footer", desc = "What should be displayed as the footer of the scoreboard when on the Alpha Server." + + "\nUse && for colors." + "\nUse \"\\n\" for new line.") @ConfigEditorText - public Property customFooter = Property.of("&ewww.hypixel.net"); + public String customAlphaFooter = "&&ealpha.hypixel.net"; } diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index 3707d10af0a7..20ed572765d5 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -485,12 +485,12 @@ object HypixelData { } private fun checkIsland(event: WidgetUpdateEvent) { - val islandType: IslandType + val newIsland: IslandType val foundIsland: String if (event.isClear()) { TabListData.fullyLoaded = false - islandType = IslandType.NONE + newIsland = IslandType.NONE foundIsland = "" } else { @@ -498,19 +498,21 @@ object HypixelData { // Can not use color coding, because of the color effect (§f§lSKYB§6§lL§e§lOCK§A§L GUEST) val guesting = guestPattern.matches(ScoreboardData.objectiveTitle.removeColor()) foundIsland = TabWidget.AREA.matchMatcherFirstLine { group("island").removeColor() } ?: "" - islandType = getIslandType(foundIsland, guesting) + newIsland = getIslandType(foundIsland, guesting) } // TODO don't send events when one of the arguments is none, at least when not on sb anymore - if (skyBlockIsland != islandType) { - IslandChangeEvent(islandType, skyBlockIsland).postAndCatch() - if (islandType == IslandType.UNKNOWN) { + if (skyBlockIsland != newIsland) { + val oldIsland = skyBlockIsland + skyBlockIsland = newIsland + IslandChangeEvent(newIsland, oldIsland).postAndCatch() + + if (newIsland == IslandType.UNKNOWN) { ChatUtils.debug("Unknown island detected: '$foundIsland'") loggerIslandChange.log("Unknown: '$foundIsland'") } else { - loggerIslandChange.log(islandType.name) + loggerIslandChange.log(newIsland.name) } - skyBlockIsland = islandType if (TabListData.fullyLoaded) { TabWidget.reSendEvents() } diff --git a/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt index 776a7c808103..5fd644818903 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MaxwellAPI.kt @@ -6,7 +6,7 @@ import at.hannibal2.skyhanni.events.LorenzChatEvent import at.hannibal2.skyhanni.events.RepositoryReloadEvent import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardElement +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardConfigElement import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils @@ -135,14 +135,11 @@ object MaxwellAPI { chatPowerPattern.tryReadPower(message) chatPowerUnlockedPattern.tryReadPower(message) - tuningAutoAssignedPattern.matchMatcher(event.message) { - if (tunings.isNullOrEmpty()) return - val tuningsInScoreboard = ScoreboardElement.TUNING in CustomScoreboard.config.scoreboardEntries - if (tuningsInScoreboard) { - ChatUtils.chat( - "Talk to Maxwell and open the Tuning Page again to update the tuning data in scoreboard.", - ) - } + if (!tuningAutoAssignedPattern.matches(event.message)) return + if (tunings.isNullOrEmpty()) return + with(CustomScoreboard.config) { + if (!enabled.get() || ScoreboardConfigElement.TUNING !in scoreboardEntries.get()) return + ChatUtils.chat("Talk to Maxwell and open the Tuning Page again to update the tuning data in scoreboard.") } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt index 54d186ae52c3..fbe304098299 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/MiningAPI.kt @@ -14,7 +14,6 @@ import at.hannibal2.skyhanni.events.ServerBlockChangeEvent import at.hannibal2.skyhanni.events.mining.OreMinedEvent import at.hannibal2.skyhanni.events.player.PlayerDeathEvent import at.hannibal2.skyhanni.events.skyblock.ScoreboardAreaChangeEvent -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern import at.hannibal2.skyhanni.features.mining.OreBlock import at.hannibal2.skyhanni.features.mining.isTitanium import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule @@ -46,12 +45,20 @@ object MiningAPI { private val glaciteAreaPattern by group.pattern("area.glacite", "Glacite Tunnels|Great Glacite Lake") private val dwarvenBaseCampPattern by group.pattern("area.basecamp", "Dwarven Base Camp") - // TODO add regex test + // TODO add regex tests private val coldResetPattern by group.pattern( "cold.reset", "§6The warmth of the campfire reduced your §r§b❄ Cold §r§6to §r§a0§r§6!|§c ☠ §r§7You froze to death§r§7\\.", ) + /** + * REGEX-TEST: Cold: §b-1❄ + */ + val coldPattern by group.pattern( + "cold", + "(?:§.)*Cold: §.(?-?\\d+)❄", + ) + private val pickbobulusGroup = group.group("pickobulus") /** @@ -150,11 +157,15 @@ object MiningAPI { IslandType.SPIDER_DEN, ) + fun inAdvancedMiningIsland() = inAnyIsland(IslandType.DWARVEN_MINES, IslandType.CRYSTAL_HOLLOWS, IslandType.MINESHAFT) + + fun inMiningIsland() = inAdvancedMiningIsland() || inAnyIsland(IslandType.GOLD_MINES, IslandType.DEEP_CAVERNS) + fun inColdIsland() = inAnyIsland(IslandType.DWARVEN_MINES, IslandType.MINESHAFT) @SubscribeEvent fun onScoreboardChange(event: ScoreboardUpdateEvent) { - val newCold = ScoreboardPattern.coldPattern.firstMatcher(event.scoreboard) { + val newCold = coldPattern.firstMatcher(event.scoreboard) { group("cold").toInt().absoluteValue } ?: return diff --git a/src/main/java/at/hannibal2/skyhanni/data/WinterAPI.kt b/src/main/java/at/hannibal2/skyhanni/data/WinterAPI.kt index 9e3a7a9e6ea9..4b430b9c55a6 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/WinterAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/WinterAPI.kt @@ -1,9 +1,12 @@ package at.hannibal2.skyhanni.data +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland import at.hannibal2.skyhanni.utils.TimeUtils import java.time.Month object WinterAPI { + fun inWorkshop() = IslandType.WINTER.isInIsland() + fun isDecember() = TimeUtils.getCurrentLocalDate().month == Month.DECEMBER } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt index e5939c3f758d..7a57de667dd1 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt @@ -95,7 +95,7 @@ enum class TabWidget( ), EVENT( // language=RegExp - "(?:§.)*Event: (?:§.)*(?.*)", + "(?:§.)*Event: (?(?:§.)*)(?.*)", ), SKILLS( // language=RegExp diff --git a/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt b/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt index af1dd8430186..8b9ff035e662 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt @@ -1,11 +1,26 @@ package at.hannibal2.skyhanni.features.combat +import at.hannibal2.skyhanni.data.IslandType import at.hannibal2.skyhanni.data.ScoreboardData -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule -import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland +import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern @SkyHanniModule object SpidersDenAPI { - fun isAtTopOfNest(): Boolean = ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.broodmotherPattern.matches(it) } + + private val repoGroup = RepoPattern.group("combat.spidersden") + + /** + * REGEX-TEST: §4Broodmother§7: §6Soon + */ + val broodmotherPattern by repoGroup.pattern( + "broodmother", + "§4Broodmother§7: §[e64](?:Slain|Dormant|Soon|Awakening|Imminent|Alive!)", + ) + + fun inSpidersDen() = IslandType.SPIDER_DEN.isInIsland() + + fun isAtTopOfNest() = inSpidersDen() && broodmotherPattern.anyMatches(ScoreboardData.sidebarLinesFormatted) } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStat.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStatsLine.kt similarity index 52% rename from src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStat.kt rename to src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStatsLine.kt index 4acfcb81db57..57000be68b86 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStat.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ChunkedStatsLine.kt @@ -4,67 +4,86 @@ import at.hannibal2.skyhanni.data.MiningAPI import at.hannibal2.skyhanni.data.PurseAPI import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.chunkedConfig import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.informationFilteringConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.formatNum +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.formatNumber import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBank import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBits +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsAvailable import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsLine -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsToClaim import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getCopper import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getGems import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getHeat import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getMotes import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getNorthStars +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementBank +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementBits +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementCold +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementCopper +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementGems +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementHeat +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementMotes +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementNorthStars +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementPurse private val hideEmptyLines get() = informationFilteringConfig.hideEmptyLines -enum class ChunkedStat( +enum class ChunkedStatsLine( private val displayPair: () -> String, - val showWhen: () -> Boolean, + private val showWhen: () -> Boolean, + private val showIsland: () -> Boolean, private val configLine: String, ) { PURSE( - displayPair = { "§6${PurseAPI.currentPurse.formatNum()}" }, - showWhen = { !(hideEmptyLines && PurseAPI.currentPurse.toInt() == 0) && ScoreboardElement.PURSE.showWhen() }, + displayPair = { "§6${formatNumber(PurseAPI.currentPurse)}" }, + showWhen = { !(hideEmptyLines && PurseAPI.currentPurse.toInt() == 0) && ScoreboardElementPurse.showWhen() }, + showIsland = { ScoreboardElementPurse.showIsland() }, configLine = "§6Purse", ), MOTES( displayPair = { "§b${getMotes()}" }, - showWhen = { !(hideEmptyLines && getMotes() == "0") && ScoreboardElement.MOTES.showWhen() }, + showWhen = { !(hideEmptyLines && getMotes() == "0") && ScoreboardElementMotes.showWhen() }, + showIsland = { ScoreboardElementMotes.showIsland() }, configLine = "§dMotes", ), BANK( displayPair = { "§6${getBank()}" }, - showWhen = { !(hideEmptyLines && (getBank() == "0" || getBank() == "0§7 / §60")) && ScoreboardElement.BANK.showWhen() }, + showWhen = { !(hideEmptyLines && (getBank() == "0" || getBank() == "0§7 / §60")) && ScoreboardElementBank.showWhen() }, + showIsland = { ScoreboardElementBank.showIsland() }, configLine = "§6Bank", ), BITS( displayPair = { getBitsLine() }, - showWhen = { !(hideEmptyLines && getBits() == "0" && getBitsToClaim() == "0") && ScoreboardElement.BITS.showWhen() }, + showWhen = { !(hideEmptyLines && getBits() == "0" && getBitsAvailable() == "0") && ScoreboardElementBits.showWhen() }, + showIsland = { ScoreboardElementBits.showIsland() }, configLine = "§bBits", ), COPPER( displayPair = { "§c${getCopper()}" }, - showWhen = { !(hideEmptyLines && getCopper() == "0") && ScoreboardElement.COPPER.showWhen() }, + showWhen = { !(hideEmptyLines && getCopper() == "0") && ScoreboardElementCopper.showWhen() }, + showIsland = { ScoreboardElementCopper.showIsland() }, configLine = "§cCopper", ), GEMS( displayPair = { "§a${getGems()}" }, - showWhen = { !(hideEmptyLines && getGems() == "0") && ScoreboardElement.GEMS.showWhen() }, + showWhen = { !(hideEmptyLines && getGems() == "0") && ScoreboardElementGems.showWhen() }, + showIsland = { ScoreboardElementGems.showIsland() }, configLine = "§aGems", ), HEAT( displayPair = { "§c${getHeat()}" }, - showWhen = { !(hideEmptyLines && getHeat() == "§c♨ 0") && ScoreboardElement.HEAT.showWhen() }, + showWhen = { !(hideEmptyLines && getHeat() == "§c♨ 0") && ScoreboardElementHeat.showWhen() }, + showIsland = { ScoreboardElementHeat.showIsland() }, configLine = "§cHeat", ), COLD( displayPair = { "§b${MiningAPI.cold}❄" }, - showWhen = { !(hideEmptyLines && MiningAPI.cold == 0) && ScoreboardElement.COLD.showWhen() }, + showWhen = { !(hideEmptyLines && MiningAPI.cold == 0) && ScoreboardElementCold.showWhen() }, + showIsland = { ScoreboardElementCold.showIsland() }, configLine = "§bCold", ), NORTH_STARS( displayPair = { "§d${getNorthStars()}" }, - showWhen = { !(hideEmptyLines && getNorthStars() == "0") && ScoreboardElement.NORTH_STARS.showWhen() }, + showWhen = { !(hideEmptyLines && getNorthStars() == "0") && ScoreboardElementNorthStars.showWhen() }, + showIsland = { ScoreboardElementNorthStars.showIsland() }, configLine = "§dNorth Stars", ), ; @@ -72,10 +91,22 @@ enum class ChunkedStat( override fun toString() = configLine companion object { - fun getChunkedStats() = chunkedConfig.chunkedStats.mapNotNull { - it.takeIf { it.showWhen() }?.displayPair?.invoke() + + private var currentIslandStats = listOf() + + fun getChunkedStats() = buildList { + currentIslandStats.forEach { stat -> + if (stat.showWhen()) { + add(stat.displayPair.invoke()) + } + } } - fun shouldShowChunkedStats() = chunkedConfig.chunkedStats.any { it.showWhen() } + fun shouldShowChunkedStats() = currentIslandStats.any { it.showWhen() } + + fun showChunkedStatsIsland(): Boolean { + currentIslandStats = chunkedConfig.chunkedStats.filter { it.showIsland() } + return currentIslandStats.isNotEmpty() + } } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt index 4a86519c374e..14f311aad281 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboard.kt @@ -1,28 +1,33 @@ -// -// TODO LIST -// V2 RELEASE -// - Bank API (actually maybe not, I like the current design) -// - countdown events like fishing festival + fiesta when its not on tablist -// - improve hide coin difference to also work with bits, motes, etc -// - color options in the purse etc lines -// - choose the amount of decimal places in shorten nums -// +/** + * TODO LIST + * - Bank API (actually maybe not, I like the current design) + * - countdown events like fishing festival + fiesta when its not on tablist + * - improve hide coin difference to also work with bits, motes, etc + * - color options in the purse etc lines + * - choose the amount of decimal places in shorten nums + * - heavily optimize elements and events by only updating them when absolutely needed + */ package at.hannibal2.skyhanni.features.gui.customscoreboard import at.hannibal2.skyhanni.SkyHanniMod -import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator import at.hannibal2.skyhanni.config.enums.OutsideSbFeature import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.events.ConfigLoadEvent import at.hannibal2.skyhanni.events.DebugDataCollectEvent import at.hannibal2.skyhanni.events.GuiPositionMovedEvent import at.hannibal2.skyhanni.events.GuiRenderEvent +import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.ScoreboardUpdateEvent +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardLine.Companion.align +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElement +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementTitle +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEvent import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.takeIfNotEmpty import at.hannibal2.skyhanni.utils.ConditionalUtils import at.hannibal2.skyhanni.utils.DelayedRun.runDelayed import at.hannibal2.skyhanni.utils.LorenzUtils @@ -34,21 +39,22 @@ import at.hannibal2.skyhanni.utils.SimpleTimeMark.Companion.fromNow import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase import at.hannibal2.skyhanni.utils.TabListData import at.hannibal2.skyhanni.utils.renderables.Renderable -import com.google.gson.JsonArray -import com.google.gson.JsonPrimitive import net.minecraftforge.client.GuiIngameForge import net.minecraftforge.client.event.RenderGameOverlayEvent import net.minecraftforge.fml.common.eventhandler.SubscribeEvent import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds -typealias ScoreboardElementType = Pair - @SkyHanniModule object CustomScoreboard { - private var display = emptyList() - private var cache = emptyList() + private var display: Renderable? = null + private var cache: Renderable? = null + + private var currentIslandEntries = listOf() + var currentIslandEvents = listOf() + private set + private const val GUI_NAME = "Custom Scoreboard" private var nextScoreboardUpdate = SimpleTimeMark.farFuture() @@ -56,25 +62,16 @@ object CustomScoreboard { @SubscribeEvent fun onRenderOverlay(event: GuiRenderEvent.GuiOverlayRenderEvent) { if (!isEnabled()) return - if (display.isEmpty()) return + display ?: return val render = - if (LorenzUtils.inSkyBlock && !TabListData.fullyLoaded && displayConfig.cacheScoreboardOnIslandSwitch && cache.isNotEmpty()) { - cache - } else { - display - } - - val textRenderable = Renderable.verticalContainer( - render.map { Renderable.string(it.first, horizontalAlign = it.second) }, - displayConfig.lineSpacing - 10, - horizontalAlign = HorizontalAlignment.CENTER, - verticalAlign = VerticalAlignment.CENTER, - ) + if (LorenzUtils.inSkyBlock && !TabListData.fullyLoaded && displayConfig.cacheScoreboardOnIslandSwitch && cache != null) cache + else display - val finalRenderable = RenderBackground.addBackground(textRenderable) + render ?: return - RenderBackground.updatePosition(finalRenderable) + // We want to update the background every time, so we can have a smooth transition when using chroma as the color + val finalRenderable = RenderBackground.addBackground(render) config.position.renderRenderable(finalRenderable, posLabel = GUI_NAME) } @@ -110,9 +107,9 @@ object CustomScoreboard { if (dirty || nextScoreboardUpdate.isInPast()) { nextScoreboardUpdate = 250.milliseconds.fromNow() dirty = false - display = createLines().removeEmptyLinesFromEdges() + display = createLines().removeEmptyLinesFromEdges().createRenderable() if (TabListData.fullyLoaded) { - cache = display.toList() + cache = display } } @@ -144,53 +141,47 @@ object CustomScoreboard { } private fun addAllNonSkyBlockLines() = buildList { - addAll(ScoreboardElement.TITLE.getVisiblePair()) - addAll(ScoreboardData.sidebarLinesFormatted.map { it to HorizontalAlignment.LEFT }) + addAll(ScoreboardElementTitle.getLines()) + addAll(ScoreboardData.sidebarLinesFormatted.map { it.align() }) } private fun addDefaultSkyBlockLines() = buildList { - add(ScoreboardData.objectiveTitle to displayConfig.titleAndFooter.alignTitleAndFooter) - addAll(ScoreboardData.sidebarLinesFormatted.map { it to HorizontalAlignment.LEFT }) + add(ScoreboardData.objectiveTitle align displayConfig.titleAndFooter.alignTitle) + addAll(ScoreboardData.sidebarLinesFormatted.map { it.align() }) } - private fun addCustomSkyBlockLines() = buildList { - for (element in config.scoreboardEntries) { - val lines = element.getVisiblePair() + private fun addCustomSkyBlockLines() = buildList { + for (element in currentIslandEntries) { + val lines = element.getLines() if (lines.isEmpty()) continue if ( informationFilteringConfig.hideConsecutiveEmptyLines && - lines.first().first == "" && - lastOrNull()?.first?.isEmpty() == true + lines.first().display.isEmpty() && + lastOrNull()?.display?.isEmpty() == true ) { continue } - if (lines.first().first == "") { - add("" to HorizontalAlignment.LEFT) - continue - } - - if (lines.any { it.first == "" }) { - continue - } - addAll(lines) } } - private fun List.removeEmptyLinesFromEdges(): List { - if (config.informationFiltering.hideEmptyLinesAtTopAndBottom) { - return this - .dropWhile { it.first.isEmpty() } - .dropLastWhile { it.first.isEmpty() } - } - return this - } + private fun List.createRenderable() = Renderable.verticalContainer( + map { Renderable.string(it.display, horizontalAlign = it.alignment) }, + displayConfig.lineSpacing - 10, + horizontalAlign = HorizontalAlignment.CENTER, + verticalAlign = VerticalAlignment.CENTER, + ) + + private fun List.removeEmptyLinesFromEdges(): List = + takeIf { !informationFilteringConfig.hideEmptyLinesAtTopAndBottom } + ?: dropWhile { it.display.isBlank() }.dropLastWhile { it.display.isBlank() } private var dirty = false - // Thank you Apec for showing that the ElementType of the stupid scoreboard is FUCKING HELMET WTF + // The ElementType for the Vanilla Scoreboard is called HELMET + // Thanks to APEC for showing this @SubscribeEvent fun onRenderScoreboard(event: RenderGameOverlayEvent.Post) { if (event.type == RenderGameOverlayEvent.ElementType.HELMET) { @@ -213,6 +204,12 @@ object CustomScoreboard { ) { if (!isHideVanillaScoreboardEnabled()) dirty = true } + ConditionalUtils.onToggle( + config.scoreboardEntries, + eventsConfig.eventEntries, + ) { + updateIslandEntries() + } } @SubscribeEvent @@ -222,6 +219,16 @@ object CustomScoreboard { } } + @SubscribeEvent + fun onIslandChange(event: IslandChangeEvent) { + updateIslandEntries() + } + + private fun updateIslandEntries() { + currentIslandEntries = config.scoreboardEntries.get().map { it.element }.filter { it.showIsland() } + currentIslandEvents = eventsConfig.eventEntries.get().map { it.event }.filter { it.showIsland() } + } + @SubscribeEvent fun onDebugDataCollect(event: DebugDataCollectEvent) { event.title("Custom Scoreboard") @@ -229,117 +236,34 @@ object CustomScoreboard { if (!config.enabled.get()) { add("Custom Scoreboard disabled.") } else { - ScoreboardElement.entries.map { element -> + add("Custom Scoreboard Lines:") + ScoreboardConfigElement.entries.forEach { entry -> add( - "${element.name.firstLetterUppercase()} - " + - "${element.showWhen.invoke()} - " + - "${element.getVisiblePair().map { it.first }}", + " ${entry.name.firstLetterUppercase()} - " + + "island: ${entry.element.showIsland()} - " + + "show: ${entry.element.showWhen()} - " + + "${entry.element.getLines().map { it.display }}", ) } + allUnknownLines.takeIfNotEmpty()?.let { set -> + add("Recent Unknown Lines:") + set.forEach { add(" ${it.line}") } + } } } } + @JvmStatic + fun resetAppearance() { + with(config.scoreboardEntries) { + get().clear() + get().addAll(ScoreboardConfigElement.defaultOptions) + notifyObservers() + } + } + private fun isEnabled() = (LorenzUtils.inSkyBlock || (OutsideSbFeature.CUSTOM_SCOREBOARD.isSelected() && LorenzUtils.onHypixel)) && config.enabled.get() private fun isHideVanillaScoreboardEnabled() = isEnabled() && displayConfig.hideVanillaScoreboard.get() - - @SubscribeEvent - fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { - val prefix = "gui.customScoreboard" - val displayConfigPrefix = "$prefix.displayConfig" - val displayPrefix = "$prefix.display" - - event.move( - 28, - "$prefix.displayConfig.showAllActiveEvents", - "$prefix.displayConfig.eventsConfig.showAllActiveEvents", - ) - - event.move(31, "$displayConfigPrefix.arrowAmountDisplay", "$displayPrefix.arrow.amountDisplay") - event.move(31, "$displayConfigPrefix.colorArrowAmount", "$displayPrefix.arrow.colorArrowAmount") - event.move(31, "$displayConfigPrefix.showMagicalPower", "$displayPrefix.maxwell.showMagicalPower") - event.move(31, "$displayConfigPrefix.compactTuning", "$displayPrefix.maxwell.compactTuning") - event.move(31, "$displayConfigPrefix.tuningAmount", "$displayPrefix.maxwell.tuningAmount") - event.move(31, "$displayConfigPrefix.hideVanillaScoreboard", "$displayPrefix.hideVanillaScoreboard") - event.move(31, "$displayConfigPrefix.displayNumbersFirst", "$displayPrefix.displayNumbersFirst") - event.move(31, "$displayConfigPrefix.showUnclaimedBits", "$displayPrefix.showUnclaimedBits") - event.move(31, "$displayConfigPrefix.showMaxIslandPlayers", "$displayPrefix.showMaxIslandPlayers") - event.move(31, "$displayConfigPrefix.numberFormat", "$displayPrefix.numberFormat") - event.move(31, "$displayConfigPrefix.lineSpacing", "$displayPrefix.lineSpacing") - event.move( - 31, - "$displayConfigPrefix.cacheScoreboardOnIslandSwitch", - "$displayPrefix.cacheScoreboardOnIslandSwitch", - ) - // Categories - event.move(31, "$displayConfigPrefix.alignment", "$displayPrefix.alignment") - event.move(31, "$displayConfigPrefix.titleAndFooter", "$displayPrefix.titleAndFooter") - event.move(31, "$prefix.backgroundConfig", "$prefix.background") - event.move(31, "$prefix.informationFilteringConfig", "$prefix.informationFiltering") - event.move(31, "$displayConfigPrefix.eventsConfig", "$displayPrefix.events") - event.move(31, "$prefix.mayorConfig", "$displayPrefix.mayor") - event.move(31, "$prefix.partyConfig", "$displayPrefix.party") - - event.transform(37, "$displayPrefix.events.eventEntries") { element -> - val array = element.asJsonArray - array.add(JsonPrimitive(ScoreboardEvent.QUEUE.name)) - array - } - event.transform(40, "$displayPrefix.events.eventEntries") { element -> - val jsonArray = element.asJsonArray - val newArray = JsonArray() - - for (jsonElement in jsonArray) { - val stringValue = jsonElement.asString - if (stringValue !in listOf("HOT_DOG_CONTEST", "EFFIGIES")) { - newArray.add(jsonElement) - } - } - - if (jsonArray.any { it.asString in listOf("HOT_DOG_CONTEST", "EFFIGIES") }) { - newArray.add(JsonPrimitive(ScoreboardEvent.RIFT.name)) - } - - newArray - } - - event.move(43, "$displayPrefix.alignment.alignRight", "$displayPrefix.alignment.horizontalAlignment") { - JsonPrimitive( - if (it.asBoolean) { - HorizontalAlignment.RIGHT.name - } else { - HorizontalAlignment.DONT_ALIGN.name - }, - ) - } - event.move(43, "$displayPrefix.alignment.alignCenterVertically", "$displayPrefix.alignment.verticalAlignment") { - JsonPrimitive( - if (it.asBoolean) { - VerticalAlignment.CENTER.name - } else { - VerticalAlignment.DONT_ALIGN.name - }, - ) - } - event.transform(50, "$displayPrefix.events.eventEntries") { element -> - val array = element.asJsonArray - array.add(JsonPrimitive(ScoreboardEvent.ANNIVERSARY.name)) - array.add(JsonPrimitive(ScoreboardEvent.CARNIVAL.name)) - array - } - event.transform(51, "$displayPrefix.events.eventEntries") { element -> - val array = element.asJsonArray - array.add(JsonPrimitive(ScoreboardEvent.NEW_YEAR.name)) - array - } - event.move( - 57, - "$displayPrefix.titleAndFooter.useHypixelTitleAnimation", - "$displayPrefix.titleAndFooter.useCustomTitle", - ) { - JsonPrimitive(!it.asBoolean) - } - } } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardConfigFix.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardConfigFix.kt new file mode 100644 index 000000000000..44dac812764e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardConfigFix.kt @@ -0,0 +1,119 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.config.ConfigUpdaterMigrator +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment +import at.hannibal2.skyhanni.utils.RenderUtils.VerticalAlignment +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonPrimitive +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@SkyHanniModule +object CustomScoreboardConfigFix { + + private const val PREFIX = "gui.customScoreboard" + private const val DISPLAY_PREFIX = "$PREFIX.display" + private const val DISPLAY_CONFIG_PREFIX = "$PREFIX.displayConfig" + private const val EVENTS_CONFIG_KEY = "$DISPLAY_CONFIG_PREFIX.eventsConfig" + private const val ALIGNMENT_KEY = "$DISPLAY_PREFIX.alignment" + private const val TITLE_AND_FOOTER_KEY = "$DISPLAY_PREFIX.titleAndFooter" + private const val EVENT_ENTRIES_KEY = "$DISPLAY_PREFIX.events.eventEntries" + + @SubscribeEvent + fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) { + + event.move(28, "$DISPLAY_CONFIG_PREFIX.showAllActiveEvents", "$EVENTS_CONFIG_KEY.showAllActiveEvents") + + val configPrefixMappings = mapOf( + "$DISPLAY_CONFIG_PREFIX.showAllActiveEvents" to "$EVENTS_CONFIG_KEY.showAllActiveEvents", + "$DISPLAY_CONFIG_PREFIX.arrowAmountDisplay" to "$DISPLAY_PREFIX.arrow.amountDisplay", + "$DISPLAY_CONFIG_PREFIX.colorArrowAmount" to "$DISPLAY_PREFIX.arrow.colorArrowAmount", + "$DISPLAY_CONFIG_PREFIX.showMagicalPower" to "$DISPLAY_PREFIX.maxwell.showMagicalPower", + "$DISPLAY_CONFIG_PREFIX.compactTuning" to "$DISPLAY_PREFIX.maxwell.compactTuning", + "$DISPLAY_CONFIG_PREFIX.tuningAmount" to "$DISPLAY_PREFIX.maxwell.tuningAmount", + "$DISPLAY_CONFIG_PREFIX.hideVanillaScoreboard" to "$DISPLAY_PREFIX.hideVanillaScoreboard", + "$DISPLAY_CONFIG_PREFIX.displayNumbersFirst" to "$DISPLAY_PREFIX.displayNumbersFirst", + "$DISPLAY_CONFIG_PREFIX.showUnclaimedBits" to "$DISPLAY_PREFIX.showUnclaimedBits", + "$DISPLAY_CONFIG_PREFIX.showMaxIslandPlayers" to "$DISPLAY_PREFIX.showMaxIslandPlayers", + "$DISPLAY_CONFIG_PREFIX.numberFormat" to "$DISPLAY_PREFIX.numberFormat", + "$DISPLAY_CONFIG_PREFIX.lineSpacing" to "$DISPLAY_PREFIX.lineSpacing", + "$DISPLAY_CONFIG_PREFIX.cacheScoreboardOnIslandSwitch" to "$DISPLAY_PREFIX.cacheScoreboardOnIslandSwitch", + "$DISPLAY_CONFIG_PREFIX.alignment" to ALIGNMENT_KEY, + "$PREFIX.backgroundConfig" to "$PREFIX.background", + "$PREFIX.informationFilteringConfig" to "$PREFIX.informationFiltering", + EVENTS_CONFIG_KEY to "$DISPLAY_PREFIX.events", + "$PREFIX.mayorConfig" to "$DISPLAY_PREFIX.mayor", + "$PREFIX.partyConfig" to "$DISPLAY_PREFIX.party", + ) + + configPrefixMappings.forEach { (oldKey, newKey) -> + event.move(31, oldKey, newKey) + } + + event.transform(37, EVENT_ENTRIES_KEY) { + it.asJsonArray.apply { + add(JsonPrimitive(ScoreboardConfigEventElement.QUEUE.name)) + } + } + + event.transform(40, EVENT_ENTRIES_KEY) { element -> + replaceElements(element, listOf("HOT_DOG_CONTEST", "EFFIGIES"), ScoreboardConfigEventElement.RIFT.name) + } + + event.move(43, "$ALIGNMENT_KEY.alignRight", "$ALIGNMENT_KEY.horizontalAlignment") { + JsonPrimitive( + if (it.asBoolean) HorizontalAlignment.RIGHT.name + else HorizontalAlignment.DONT_ALIGN.name, + ) + } + event.move(43, "$ALIGNMENT_KEY.alignCenterVertically", "$ALIGNMENT_KEY.verticalAlignment") { + JsonPrimitive( + if (it.asBoolean) VerticalAlignment.CENTER.name + else VerticalAlignment.DONT_ALIGN.name, + ) + } + + event.transform(50, EVENT_ENTRIES_KEY) { + it.asJsonArray.apply { + add(JsonPrimitive(ScoreboardConfigEventElement.ANNIVERSARY.name)) + add(JsonPrimitive(ScoreboardConfigEventElement.CARNIVAL.name)) + } + } + + event.transform(51, EVENT_ENTRIES_KEY) { + it.asJsonArray.apply { + add(JsonPrimitive(ScoreboardConfigEventElement.NEW_YEAR.name)) + } + } + + event.move(57, "$TITLE_AND_FOOTER_KEY.useHypixelTitleAnimation", "$TITLE_AND_FOOTER_KEY.useCustomTitle") { + JsonPrimitive(!it.asBoolean) + } + + event.transform(63, EVENT_ENTRIES_KEY) { element -> + replaceElements(element, listOf("GARDEN_CLEAN_UP", "GARDEN_PASTING"), ScoreboardConfigEventElement.GARDEN.name) + } + listOf("customTitle", "customFooter").forEach { key -> + event.transform(63, "$TITLE_AND_FOOTER_KEY.$key") { + JsonPrimitive(it.asString.replace("&", "&&")) + } + } + listOf("alignTitle", "alignFooter").forEach { key -> + event.move(63, "$TITLE_AND_FOOTER_KEY.alignTitleAndFooter", "$TITLE_AND_FOOTER_KEY.$key") + } + } + + private fun replaceElements(element: JsonElement, oldElements: List, newElement: String): JsonArray { + val jsonArray = element.asJsonArray + val newArray = JsonArray() + + jsonArray.filterNot { it.asString in oldElements }.forEach(newArray::add) + + if (jsonArray.any { it.asString in oldElements }) { + newArray.add(JsonPrimitive(newElement)) + } + + return newArray + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt index 99fdc4f3fcf6..b90c239878ab 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/CustomScoreboardUtils.kt @@ -3,71 +3,87 @@ package at.hannibal2.skyhanni.features.gui.customscoreboard import at.hannibal2.skyhanni.config.features.gui.customscoreboard.DisplayConfig import at.hannibal2.skyhanni.data.BitsAPI import at.hannibal2.skyhanni.data.HypixelData +import at.hannibal2.skyhanni.data.PurseAPI +import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.features.bingo.BingoAPI import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.displayConfig +import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardLine.Companion.align import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators import at.hannibal2.skyhanni.utils.NumberUtil.formatDouble import at.hannibal2.skyhanni.utils.NumberUtil.shortFormat -import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.groupOrNull +import at.hannibal2.skyhanni.utils.RegexUtils.matchGroup import at.hannibal2.skyhanni.utils.StringUtils.removeResets import at.hannibal2.skyhanni.utils.StringUtils.trimWhiteSpace -import at.hannibal2.skyhanni.utils.TabListData import java.util.regex.Pattern object CustomScoreboardUtils { - internal fun getGroupFromPattern(list: List, pattern: Pattern, group: String) = list.map { - it.removeResets().trimWhiteSpace() - }.firstNotNullOfOrNull { line -> - pattern.matchMatcher(line) { - group(group) + private fun getGroup(pattern: Pattern, list: List, group: String) = + list.map { it.removeResets().trimWhiteSpace() }.firstNotNullOfOrNull { line -> + pattern.matchGroup(line, group) } - } fun getProfileTypeSymbol() = when { HypixelData.ironman -> "§7♲ " HypixelData.stranded -> "§a☀ " HypixelData.bingo -> ScoreboardData.sidebarLinesFormatted.firstNotNullOfOrNull { - BingoAPI.getIconFromScoreboard(it)?.plus(" ") + BingoAPI.getIconFromScoreboard(it)?.plus(" ") // TODO: add bingo rank to bingo api } ?: "§e❤ " else -> "§e" } - // TODO change to a non extended function - internal fun Number.formatNum(): String = when (displayConfig.numberFormat) { - DisplayConfig.NumberFormat.SHORT -> this.shortFormat() - DisplayConfig.NumberFormat.LONG -> this.addSeparators() + internal fun formatNumber(number: Number): String = when (displayConfig.numberFormat) { + DisplayConfig.NumberFormat.SHORT -> number.shortFormat() + DisplayConfig.NumberFormat.LONG -> number.addSeparators() else -> "0" } - internal fun String.formatNum() = this.formatDouble().formatNum() + internal fun formatStringNum(string: String) = formatNumber(string.formatDouble()) + + internal fun getMotes() = getGroup(ScoreboardPattern.motesPattern, getSbLines(), "motes") ?: "0" + + internal fun getSoulflow() = TabWidget.SOULFLOW.matchMatcherFirstLine { group("amount") } ?: "0" - internal fun getMotes() = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.motesPattern, "motes") - internal fun getBank() = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.bankPattern, "bank") + internal fun getPurseEarned() = getGroup(PurseAPI.coinsPattern, getSbLines(), "earned")?.let { " §7(§e+$it§7)§6" } - internal fun getBits() = BitsAPI.bits.coerceAtLeast(0).formatNum() + internal fun getBank() = TabWidget.BANK.matchMatcherFirstLine { + group("amount") + (groupOrNull("personal")?.let { " §7/ §6$it" } ?: "") + } ?: "0" - internal fun getBitsToClaim() = BitsAPI.bitsAvailable.coerceAtLeast(0).formatNum() + internal fun getBits() = formatNumber(BitsAPI.bits.coerceAtLeast(0)) + + internal fun getBitsAvailable() = formatNumber(BitsAPI.bitsAvailable.coerceAtLeast(0)) internal fun getBitsLine() = if (displayConfig.showUnclaimedBits) { - "§b${getBits()}§7/§b${getBitsToClaim()}" - } else { - "§b${getBits()}" - } + "§b${getBits()}§7/§b${getBitsAvailable()}" + } else "§b${getBits()}" - internal fun getCopper() = - getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.copperPattern, "copper") + internal fun getCopper() = getGroup(ScoreboardPattern.copperPattern, getSbLines(), "copper") ?: "0" - internal fun getGems() = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.gemsPattern, "gems") + internal fun getGems() = TabWidget.GEMS.matchMatcherFirstLine { group("gems") } ?: "0" - internal fun getHeat() = - getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.heatPattern, "heat") + internal fun getHeat() = getGroup(ScoreboardPattern.heatPattern, getSbLines(), "heat") - internal fun getNorthStars() = - getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.northstarsPattern, "northstars") + internal fun getNorthStars() = getGroup(ScoreboardPattern.northstarsPattern, getSbLines(), "northStars") ?: "0" + internal fun getTimeSymbol() = getGroup(ScoreboardPattern.timePattern, getSbLines(), "symbol") ?: "" + + internal fun getTablistEvent() = TabWidget.EVENT.matchMatcherFirstLine { groupOrNull("color") + group("event") } + + internal fun getElementsFromAny(element: Any?): List = when (element) { + null -> listOf() + is List<*> -> element.mapNotNull { it?.toScoreboardElement() } + else -> listOfNotNull(element.toScoreboardElement()) + } + + private fun Any.toScoreboardElement(): ScoreboardLine? = when (this) { + is String -> this.align() + is ScoreboardLine -> this + else -> null + } - class UndetectedScoreboardLines(message: String) : Exception(message) + internal fun getSbLines() = ScoreboardData.sidebarLinesFormatted } diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardConfigElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardConfigElement.kt new file mode 100644 index 000000000000..9d9dcb378617 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardConfigElement.kt @@ -0,0 +1,125 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElement +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementBank +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementBits +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementChunkedStats +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementCold +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementCookie +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementCopper +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementDate +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementEmptyLine +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementEvents +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementFooter +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementGems +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementHeat +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementIsland +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementLobbyCode +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementLocation +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementMayor +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementMotes +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementNorthStars +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementObjective +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementParty +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementPlayerAmount +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementPowder +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementPower +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementProfile +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementPurse +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementQuiver +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementSlayer +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementSoulflow +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementTime +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementTitle +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementTuning +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementUnknown +import at.hannibal2.skyhanni.features.gui.customscoreboard.elements.ScoreboardElementVisiting + +// TODO once the config can support dynamic lists, remove this enum +enum class ScoreboardConfigElement(val element: ScoreboardElement) { + TITLE(ScoreboardElementTitle), + PROFILE(ScoreboardElementProfile), + PURSE(ScoreboardElementPurse), + MOTES(ScoreboardElementMotes), + BANK(ScoreboardElementBank), + BITS(ScoreboardElementBits), + COPPER(ScoreboardElementCopper), + GEMS(ScoreboardElementGems), + HEAT(ScoreboardElementHeat), + COLD(ScoreboardElementCold), + NORTH_STARS(ScoreboardElementNorthStars), + CHUNKED_STATS(ScoreboardElementChunkedStats), + SOULFLOW(ScoreboardElementSoulflow), + ISLAND(ScoreboardElementIsland), + LOCATION(ScoreboardElementLocation), + PLAYER_AMOUNT(ScoreboardElementPlayerAmount), + VISITING(ScoreboardElementVisiting), + DATE(ScoreboardElementDate), + TIME(ScoreboardElementTime), + LOBBY_CODE(ScoreboardElementLobbyCode), + POWER(ScoreboardElementPower), + TUNING(ScoreboardElementTuning), + COOKIE(ScoreboardElementCookie), + OBJECTIVE(ScoreboardElementObjective), + SLAYER(ScoreboardElementSlayer), + QUIVER(ScoreboardElementQuiver), + POWDER(ScoreboardElementPowder), + EVENTS(ScoreboardElementEvents), + MAYOR(ScoreboardElementMayor), + PARTY(ScoreboardElementParty), + FOOTER(ScoreboardElementFooter), + EXTRA(ScoreboardElementUnknown), + EMPTY_LINE(ScoreboardElementEmptyLine), + EMPTY_LINE2(ScoreboardElementEmptyLine), + EMPTY_LINE3(ScoreboardElementEmptyLine), + EMPTY_LINE4(ScoreboardElementEmptyLine), + EMPTY_LINE5(ScoreboardElementEmptyLine), + EMPTY_LINE6(ScoreboardElementEmptyLine), + EMPTY_LINE7(ScoreboardElementEmptyLine), + EMPTY_LINE8(ScoreboardElementEmptyLine), + EMPTY_LINE9(ScoreboardElementEmptyLine), + EMPTY_LINE10(ScoreboardElementEmptyLine), + ; + + override fun toString() = element.configLine + + companion object { + @JvmField + val defaultOptions = listOf( + TITLE, + PROFILE, + PURSE, + BANK, + MOTES, + BITS, + COPPER, + GEMS, + NORTH_STARS, + HEAT, + COLD, + EMPTY_LINE, + ISLAND, + LOCATION, + LOBBY_CODE, + PLAYER_AMOUNT, + VISITING, + EMPTY_LINE2, + DATE, + TIME, + EVENTS, + COOKIE, + EMPTY_LINE3, + QUIVER, + POWER, + TUNING, + EMPTY_LINE4, + OBJECTIVE, + SLAYER, + POWDER, + MAYOR, + PARTY, + FOOTER, + EXTRA, + ) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardConfigEventElement.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardConfigEventElement.kt new file mode 100644 index 000000000000..aff6013465aa --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardConfigEventElement.kt @@ -0,0 +1,98 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventActiveTablist +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventAnniversary +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventBroodmother +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventCarnival +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventDamage +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventDarkAuction +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventDojo +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventDungeons +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventEssence +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventFlightDuration +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventGarden +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventJacobContest +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventJacobMedals +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventKuudra +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventMagmaBoss +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventMining +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventNewYear +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventQueue +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventRedstone +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventRift +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEvent +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventServerClose +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventSpooky +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventStartingSoonTablist +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventTrapper +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventVoting +import at.hannibal2.skyhanni.features.gui.customscoreboard.events.ScoreboardEventWinter + +/** + * This enum contains all the lines that either are events or other lines that are so rare/not often seen that they + * don't fit in the normal [ScoreboardConfigElement] enum. + * + * We for example have the [ScoreboardEventVoting] Event, while this is clearly not an event, I don't consider them as normal lines + * because they are visible for a maximum of like 1 minute every 5 days and ~12 hours. + */ + +enum class ScoreboardConfigEventElement(val event: ScoreboardEvent) { + VOTING(ScoreboardEventVoting), + SERVER_CLOSE(ScoreboardEventServerClose), + DUNGEONS(ScoreboardEventDungeons), + KUUDRA(ScoreboardEventKuudra), + DOJO(ScoreboardEventDojo), + DARK_AUCTION(ScoreboardEventDarkAuction), + JACOB_CONTEST(ScoreboardEventJacobContest), + JACOB_MEDALS(ScoreboardEventJacobMedals), + TRAPPER(ScoreboardEventTrapper), + GARDEN(ScoreboardEventGarden), + FLIGHT_DURATION(ScoreboardEventFlightDuration), + WINTER(ScoreboardEventWinter), + NEW_YEAR(ScoreboardEventNewYear), + SPOOKY(ScoreboardEventSpooky), + BROODMOTHER(ScoreboardEventBroodmother), + MINING_EVENTS(ScoreboardEventMining), + DAMAGE(ScoreboardEventDamage), + MAGMA_BOSS(ScoreboardEventMagmaBoss), + CARNIVAL(ScoreboardEventCarnival), + RIFT(ScoreboardEventRift), + ESSENCE(ScoreboardEventEssence), + QUEUE(ScoreboardEventQueue), + ANNIVERSARY(ScoreboardEventAnniversary), + ACTIVE_TABLIST_EVENTS(ScoreboardEventActiveTablist), + STARTING_SOON_TABLIST_EVENTS(ScoreboardEventStartingSoonTablist), + REDSTONE(ScoreboardEventRedstone), + ; + + override fun toString() = event.configLine + + companion object { + @JvmField + val defaultOption = listOf( + VOTING, + SERVER_CLOSE, + DUNGEONS, + KUUDRA, + DOJO, + DARK_AUCTION, + JACOB_CONTEST, + JACOB_MEDALS, + TRAPPER, + GARDEN, + FLIGHT_DURATION, + NEW_YEAR, + WINTER, + SPOOKY, + BROODMOTHER, + MINING_EVENTS, + DAMAGE, + MAGMA_BOSS, + CARNIVAL, + RIFT, + ESSENCE, + ACTIVE_TABLIST_EVENTS, + REDSTONE, + ) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt deleted file mode 100644 index f20479b65e44..000000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt +++ /dev/null @@ -1,863 +0,0 @@ -package at.hannibal2.skyhanni.features.gui.customscoreboard - -import at.hannibal2.skyhanni.api.HotmAPI -import at.hannibal2.skyhanni.config.features.gui.customscoreboard.ArrowConfig.ArrowAmountDisplay -import at.hannibal2.skyhanni.config.features.gui.customscoreboard.DisplayConfig.PowderDisplay -import at.hannibal2.skyhanni.data.BitsAPI -import at.hannibal2.skyhanni.data.HypixelData -import at.hannibal2.skyhanni.data.HypixelData.getMaxPlayersForCurrentServer -import at.hannibal2.skyhanni.data.HypixelData.getPlayersOnCurrentServer -import at.hannibal2.skyhanni.data.IslandType -import at.hannibal2.skyhanni.data.MaxwellAPI -import at.hannibal2.skyhanni.data.MayorAPI -import at.hannibal2.skyhanni.data.MiningAPI -import at.hannibal2.skyhanni.data.MiningAPI.inGlaciteArea -import at.hannibal2.skyhanni.data.PartyAPI -import at.hannibal2.skyhanni.data.PurseAPI -import at.hannibal2.skyhanni.data.QuiverAPI -import at.hannibal2.skyhanni.data.QuiverAPI.NONE_ARROW_TYPE -import at.hannibal2.skyhanni.data.QuiverAPI.asArrowPercentage -import at.hannibal2.skyhanni.data.ScoreboardData -import at.hannibal2.skyhanni.data.SlayerAPI -import at.hannibal2.skyhanni.features.dungeon.DungeonAPI -import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStat.Companion.getChunkedStats -import at.hannibal2.skyhanni.features.gui.customscoreboard.ChunkedStat.Companion.shouldShowChunkedStats -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.arrowConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.chunkedConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.config -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.displayConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.informationFilteringConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.maxwellConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.mayorConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.partyConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.formatNum -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBank -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getBitsLine -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getCopper -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getGems -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getGroupFromPattern -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getHeat -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getMotes -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils.getNorthStars -import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter -import at.hannibal2.skyhanni.utils.LorenzUtils -import at.hannibal2.skyhanni.utils.LorenzUtils.inAdvancedMiningIsland -import at.hannibal2.skyhanni.utils.LorenzUtils.inAnyIsland -import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators -import at.hannibal2.skyhanni.utils.NumberUtil.percentageColor -import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches -import at.hannibal2.skyhanni.utils.RegexUtils.matches -import at.hannibal2.skyhanni.utils.RenderUtils.HorizontalAlignment -import at.hannibal2.skyhanni.utils.SimpleTimeMark -import at.hannibal2.skyhanni.utils.SkyBlockTime -import at.hannibal2.skyhanni.utils.StringUtils.firstLetterUppercase -import at.hannibal2.skyhanni.utils.StringUtils.pluralize -import at.hannibal2.skyhanni.utils.TabListData -import at.hannibal2.skyhanni.utils.TimeUtils.format -import at.hannibal2.skyhanni.utils.TimeUtils.formatted -import kotlin.time.Duration.Companion.seconds - -internal var allUnknownLines = listOf() -internal var lastRecentAlarmWarning = SimpleTimeMark.farPast() - -internal fun recentUnknownLines() = allUnknownLines.filter { it.lastFound.passedSince() < 3.seconds } - -internal class UnknownLine(val line: String) { - val firstFound = SimpleTimeMark.now() - var lastFound = SimpleTimeMark.now() - var lastWarned = SimpleTimeMark.farPast() -} - -enum class ScoreboardElement( - private val displayPair: () -> List, - val showWhen: () -> Boolean, - private val configLine: String, -) { - TITLE( - ::getTitleDisplayPair, - { true }, - "§6§lSKYBLOCK", - ), - PROFILE( - ::getProfileDisplayPair, - { true }, - "§7♲ Blueberry", - ), - PURSE( - ::getPurseDisplayPair, - ::getPurseShowWhen, - "Purse: §652,763,737", - ), - MOTES( - ::getMotesDisplayPair, - ::getMotesShowWhen, - "Motes: §d64,647", - ), - BANK( - ::getBankDisplayPair, - ::getBankShowWhen, - "Bank: §6249M", - ), - BITS( - ::getBitsDisplayPair, - ::getBitsShowWhen, - "Bits: §b59,264", - ), - COPPER( - ::getCopperDisplayPair, - ::getCopperShowWhen, - "Copper: §c23,495", - ), - GEMS( - ::getGemsDisplayPair, - ::getGemsShowWhen, - "Gems: §a57,873", - ), - HEAT( - ::getHeatDisplayPair, - ::getHeatShowWhen, - "Heat: §c♨ 0", - ), - COLD( - ::getColdDisplayPair, - ::getColdShowWhen, - "Cold: §b0❄", - ), - NORTH_STARS( - ::getNorthStarsDisplayPair, - ::getNorthStarsShowWhen, - "North Stars: §d756", - ), - CHUNKED_STATS( - ::getChunkedStatsDisplayPair, - ::shouldShowChunkedStats, - "§652,763,737 §7| §d64,647 §7| §6249M\n§b59,264 §7| §c23,495 §7| §a57,873\n§c♨ 0 §7| §b0❄ §7| §d756", - ), - SOULFLOW( - ::getSoulflowDisplayPair, - ::getSoulflowDisplayWhen, - "Soulflow: §3761", - ), - EMPTY_LINE( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - ISLAND( - ::getIslandDisplayPair, - { true }, - "§7㋖ §aHub", - ), - LOCATION( - ::getLocationDisplayPair, - { true }, - "§7⏣ §bVillage", - ), - PLAYER_AMOUNT( - ::getPlayerAmountDisplayPair, - { true }, - "§7Players: §a69§7/§a80", - ), - VISITING( - ::getVisitDisplayPair, - ::getVisitShowWhen, - " §a✌ §7(§a1§7/6)", - ), - DATE( - ::getDateDisplayPair, - { true }, - "Late Summer 11th", - ), - TIME( - ::getTimeDisplayPair, - { true }, - "§710:40pm §b☽", - ), - LOBBY_CODE( - ::getLobbyDisplayPair, - { true }, - "§8mega77CK", - ), - POWER( - ::getPowerDisplayPair, - ::getPowerShowWhen, - "Power: §aSighted §7(§61.263§7)", - ), - TUNING( - ::getTuningDisplayPair, - ::getPowerShowWhen, - "Tuning: §c❁34§7, §e⚔20§7, and §9☣7", - ), - COOKIE( - ::getCookieDisplayPair, - ::getCookieShowWhen, - "§dCookie Buff§f: 3d 17h", - ), - EMPTY_LINE2( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - OBJECTIVE( - ::getObjectiveDisplayPair, - ::getObjectiveShowWhen, - "Objective:\n§eStar SkyHanni on Github", - ), - SLAYER( - ::getSlayerDisplayPair, - ::getSlayerShowWhen, - "Slayer Quest\n §7- §cVoidgloom Seraph III\n §7- §e12§7/§c120 §7Kills", - ), - EMPTY_LINE3( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - QUIVER( - ::getQuiverDisplayPair, - ::getQuiverShowWhen, - "Flint Arrow: §f1,234", - ), - POWDER( - ::getPowderDisplayPair, - ::getPowderShowWhen, - "§9§lPowder\n §7- §fMithril: §254,646\n §7- §fGemstone: §d51,234", - ), - EVENTS( - ::getEventsDisplayPair, - ::getEventsShowWhen, - "§7Wide Range of Events\n§7(too much to show all)", - ), - MAYOR( - ::getMayorDisplayPair, - ::getMayorShowWhen, - "§2Diana:\n §7- §eLucky!\n §7- §eMythological Ritual\n §7- §ePet XP Buff", - ), - PARTY( - ::getPartyDisplayPair, - ::getPartyShowWhen, - "§9§lParty (4):\n §7- §fhannibal2\n §7- §fMoulberry\n §7- §fVahvl\n §7- §fSkirtwearer", - ), - FOOTER( - ::getFooterDisplayPair, - { true }, - "§ewww.hypixel.net", - ), - EXTRA( - ::getExtraDisplayPair, - ::getExtraShowWhen, - "§cUnknown lines the mod is not detecting", - ), - EMPTY_LINE4( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - EMPTY_LINE5( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - EMPTY_LINE6( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - EMPTY_LINE7( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - EMPTY_LINE8( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - EMPTY_LINE9( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - EMPTY_LINE10( - ::getEmptyLineDisplayPair, - { true }, - "", - ), - ; - - override fun toString() = configLine - - fun getVisiblePair() = if (isVisible()) getPair() else listOf("" to HorizontalAlignment.LEFT) - - private fun getPair(): List { - return try { - displayPair() - } catch (e: NoSuchElementException) { - listOf("" to HorizontalAlignment.LEFT) - } - } - - private fun isVisible(): Boolean { - if (!informationFilteringConfig.hideIrrelevantLines) return true - return showWhen() - } - - companion object { - // I don't know why, but this field is needed for it to work - @JvmField - val defaultOption = listOf( - TITLE, - PROFILE, - PURSE, - BANK, - MOTES, - BITS, - COPPER, - GEMS, - NORTH_STARS, - HEAT, - COLD, - EMPTY_LINE, - ISLAND, - LOCATION, - LOBBY_CODE, - PLAYER_AMOUNT, - VISITING, - EMPTY_LINE2, - DATE, - TIME, - EVENTS, - COOKIE, - EMPTY_LINE3, - QUIVER, - POWER, - TUNING, - EMPTY_LINE4, - OBJECTIVE, - SLAYER, - POWDER, - MAYOR, - PARTY, - FOOTER, - EXTRA, - ) - } -} - -private fun getTitleDisplayPair(): List { - val alignment = displayConfig.titleAndFooter.alignTitleAndFooter - - if (!LorenzUtils.inSkyBlock && !displayConfig.titleAndFooter.useCustomTitleOutsideSkyBlock) { - return listOf(ScoreboardData.objectiveTitle to alignment) - } - - return if (displayConfig.titleAndFooter.useCustomTitle) { - listOf( - displayConfig.titleAndFooter.customTitle.get().toString() - .replace("&", "§") - .split("\\n") - .map { it to alignment } - ).flatten() - } else { - listOf(ScoreboardData.objectiveTitle to alignment) - } -} - -private fun getProfileDisplayPair() = listOf( - CustomScoreboardUtils.getProfileTypeSymbol() + HypixelData.profileName.firstLetterUppercase() - to HorizontalAlignment.LEFT, -) - -private fun getPurseDisplayPair(): List { - var purse = PurseAPI.currentPurse.formatNum() - - if (!displayConfig.hideCoinsDifference) { - val earned = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, PurseAPI.coinsPattern, "earned") - if (earned != null) purse += " §7(§e+$earned§7)§6" - } - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && purse == "0" -> "" - displayConfig.displayNumbersFirst -> "§6$purse Purse" - else -> "Purse: §6$purse" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getPurseShowWhen() = !inAnyIsland(IslandType.THE_RIFT) - -private fun getMotesDisplayPair(): List { - val motes = getMotes()?.formatNum() ?: "0" - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && motes == "0" -> "" - displayConfig.displayNumbersFirst -> "§d$motes Motes" - else -> "Motes: §d$motes" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getMotesShowWhen() = inAnyIsland(IslandType.THE_RIFT) - -private fun getBankDisplayPair(): List { - val bank = getBank() ?: "0" - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && (bank == "0" || bank == "0§7 / §60") -> "" - displayConfig.displayNumbersFirst -> "§6$bank Bank" - else -> "Bank: §6$bank" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getBankShowWhen() = !inAnyIsland(IslandType.THE_RIFT) - -private fun getBitsDisplayPair(): List { - val bits = BitsAPI.bits.coerceAtLeast(0).formatNum() - val bitsToClaim = if (BitsAPI.bitsAvailable == -1) { - "§cOpen Sbmenu§b" - } else { - BitsAPI.bitsAvailable.coerceAtLeast(0).formatNum() - } - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && bits == "0" && bitsToClaim == "0" -> "" - displayConfig.displayNumbersFirst -> "${getBitsLine()} Bits" - else -> "Bits: ${getBitsLine()}" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getBitsShowWhen() = !HypixelData.bingo && !inAnyIsland(IslandType.CATACOMBS, IslandType.KUUDRA_ARENA) - -private fun getCopperDisplayPair(): List { - val copper = getCopper()?.formatNum() ?: "0" - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && copper == "0" -> "" - displayConfig.displayNumbersFirst -> "§c$copper Copper" - else -> "Copper: §c$copper" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getCopperShowWhen() = inAnyIsland(IslandType.GARDEN) - -private fun getGemsDisplayPair(): List { - val gems = getGems() - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && gems == "0" -> "" - displayConfig.displayNumbersFirst -> "§a$gems Gems" - else -> "Gems: §a$gems" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getGemsShowWhen() = !inAnyIsland(IslandType.THE_RIFT, IslandType.CATACOMBS, IslandType.KUUDRA_ARENA) - -private fun getHeatDisplayPair(): List { - val heat = getHeat() - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && heat == "§c♨ 0" -> "" - displayConfig.displayNumbersFirst -> heat?.let { "$heat Heat" } ?: "§c♨ 0 Heat" - else -> heat?.let { "Heat: $heat" } ?: "§c♨ 0 Heat" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getHeatShowWhen() = inAnyIsland(IslandType.CRYSTAL_HOLLOWS) && - ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.heatPattern.matches(it) } - -private fun getColdDisplayPair(): List { - val cold = -MiningAPI.cold - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && cold == 0 -> "" - displayConfig.displayNumbersFirst -> "§b$cold❄ Cold" - else -> "Cold: §b$cold❄" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getColdShowWhen() = inAnyIsland(IslandType.DWARVEN_MINES, IslandType.MINESHAFT) && - ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.coldPattern.matches(it) } - -private fun getNorthStarsDisplayPair(): List { - val northStars = getNorthStars()?.formatNum() ?: "0" - - return listOf( - when { - informationFilteringConfig.hideEmptyLines && northStars == "0" -> "" - displayConfig.displayNumbersFirst -> "§d$northStars North Stars" - else -> "North Stars: §d$northStars" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getNorthStarsShowWhen() = inAnyIsland(IslandType.WINTER) - -private fun getChunkedStatsDisplayPair(): List = - getChunkedStats() - .chunked(chunkedConfig.maxStatsPerLine) - .map { it.joinToString(" §f| ") to HorizontalAlignment.LEFT } - -private fun getSoulflowDisplayPair(): List { - val soulflow = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.soulflowPattern, "soulflow") - ?.formatNum() ?: "0" - return listOf( - when { - informationFilteringConfig.hideEmptyLines && soulflow == "0" -> "" - displayConfig.displayNumbersFirst -> "§3$soulflow Soulflow" - else -> "Soulflow: §3$soulflow" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getSoulflowDisplayWhen() = !inAnyIsland(IslandType.THE_RIFT) - -private fun getEmptyLineDisplayPair() = listOf("" to HorizontalAlignment.LEFT) - -private fun getIslandDisplayPair() = - listOf("§7㋖ §a" + LorenzUtils.skyBlockIsland.displayName to HorizontalAlignment.LEFT) - -private fun getLocationDisplayPair() = buildList { - HypixelData.skyBlockAreaWithSymbol?.let { add(it to HorizontalAlignment.LEFT) } - - ScoreboardData.sidebarLinesFormatted.firstOrNull { ScoreboardPattern.plotPattern.matches(it) } - ?.let { add(it to HorizontalAlignment.LEFT) } -} - -fun getPlayerAmountDisplayPair() = buildList { - val max = if (displayConfig.showMaxIslandPlayers) { - "§7/§a${getMaxPlayersForCurrentServer()}" - } else { - "" - } - if (displayConfig.displayNumbersFirst) - add("§a${getPlayersOnCurrentServer()}$max Players" to HorizontalAlignment.LEFT) - else - add("§7Players: §a${getPlayersOnCurrentServer()}$max" to HorizontalAlignment.LEFT) -} - -private fun getVisitDisplayPair() = - listOf( - ScoreboardData.sidebarLinesFormatted.first { ScoreboardPattern.visitingPattern.matches(it) } to - HorizontalAlignment.LEFT, - ) - -private fun getVisitShowWhen() = - ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.visitingPattern.matches(it) } - -private fun getDateDisplayPair() = - listOf( - SkyBlockTime.now().formatted(yearElement = false, hoursAndMinutesElement = false) to HorizontalAlignment.LEFT, - ) - -private fun getTimeDisplayPair(): List { - val symbol = - getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.timePattern, "symbol") ?: "" - return listOf( - "§7" + SkyBlockTime.now() - .formatted( - dayAndMonthElement = false, - yearElement = false, - timeFormat24h = config.display.skyblockTime24hFormat, - exactMinutes = config.display.skyblockTimeExactMinutes, - ) + - " $symbol" to HorizontalAlignment.LEFT, - ) -} - -private fun getLobbyDisplayPair(): List { - val lobbyCode = HypixelData.serverId - val roomId = DungeonAPI.getRoomID()?.let { "§8$it" } ?: "" - val lobbyDisplay = lobbyCode?.let { "§8$it $roomId" } ?: "" - return listOf(lobbyDisplay to HorizontalAlignment.LEFT) -} - -private fun getPowerDisplayPair() = listOf( - ( - MaxwellAPI.currentPower?.let { - val mp = if (maxwellConfig.showMagicalPower) "§7(§6${MaxwellAPI.magicalPower?.addSeparators()}§7)" else "" - if (displayConfig.displayNumbersFirst) { - "§a${it.replace(" Power", "")} Power $mp" - } else { - "Power: §a$it $mp" - } - } ?: "§cOpen \"Your Bags\"!" - ) to HorizontalAlignment.LEFT, -) - -private fun getTuningDisplayPair(): List> { - val tunings = MaxwellAPI.tunings ?: return listOf("§cTalk to \"Maxwell\"!" to HorizontalAlignment.LEFT) - if (tunings.isEmpty()) return listOf("§cNo Maxwell Tunings :(" to HorizontalAlignment.LEFT) - - val title = pluralize(tunings.size, "Tuning", "Tunings") - return if (maxwellConfig.compactTuning) { - val tuning = tunings - .take(3) - .joinToString("§7, ") { tuning -> - with(tuning) { - if (displayConfig.displayNumbersFirst) { - "$color$value$icon" - } else { - "$color$icon$value" - } - } - - } - listOf( - if (displayConfig.displayNumbersFirst) { - "$tuning §f$title" - } else { - "$title: $tuning" - } to HorizontalAlignment.LEFT, - ) - } else { - val tuning = tunings - .take(maxwellConfig.tuningAmount.coerceAtLeast(1)) - .map { tuning -> - with(tuning) { - " §7- §f" + if (displayConfig.displayNumbersFirst) { - "$color$value $icon $name" - } else { - "$name: $color$value$icon" - } - } - - }.toTypedArray() - listOf("$title:", *tuning).map { it to HorizontalAlignment.LEFT } - } -} - -private fun getPowerShowWhen() = !inAnyIsland(IslandType.THE_RIFT) - -private fun getCookieDisplayPair() = listOf( - "§dCookie Buff§f: " + ( - BitsAPI.cookieBuffTime?.let { - if (!BitsAPI.hasCookieBuff()) "§cNot Active" else it.timeUntil().format(maxUnits = 2) - } ?: "§cOpen SbMenu!" - ) to HorizontalAlignment.LEFT, -) - -private fun getCookieShowWhen(): Boolean { - if (HypixelData.bingo) return false - return informationFilteringConfig.hideEmptyLines && BitsAPI.hasCookieBuff() -} - -private fun getObjectiveDisplayPair() = buildList { - val formattedLines = ScoreboardData.sidebarLinesFormatted - val objective = formattedLines.firstOrNull { ScoreboardPattern.objectivePattern.matches(it) } - if (objective != null) { - add(objective to HorizontalAlignment.LEFT) - - val secondLine = formattedLines.nextAfter(objective) ?: "" - add(secondLine to HorizontalAlignment.LEFT) - - formattedLines.nextAfter(objective, 2)?.let { - if (ScoreboardPattern.thirdObjectiveLinePattern.matches(it)) add(it to HorizontalAlignment.LEFT) - } - - formattedLines.nextAfter(objective, 3)?.let { - if (ScoreboardPattern.thirdObjectiveLinePattern.matches(it)) add(it to HorizontalAlignment.LEFT) - } - } -} - -private fun getObjectiveShowWhen(): Boolean = - ScoreboardPattern.objectivePattern.anyMatches(ScoreboardData.sidebarLinesFormatted) - -private fun getSlayerDisplayPair(): List = buildList { - add((if (SlayerAPI.hasActiveSlayerQuest()) "Slayer Quest" else "") to HorizontalAlignment.LEFT) - add(" §7- §e${SlayerAPI.latestSlayerCategory.trim()}" to HorizontalAlignment.LEFT) - add(" §7- §e${SlayerAPI.latestSlayerProgress.trim()}" to HorizontalAlignment.LEFT) -} - -private fun getSlayerShowWhen() = - if (informationFilteringConfig.hideIrrelevantLines) SlayerAPI.isInCorrectArea else true - -private fun getQuiverDisplayPair(): List { - if (QuiverAPI.currentArrow == null) - return listOf("§cChange your Arrow once" to HorizontalAlignment.LEFT) - if (QuiverAPI.currentArrow == NONE_ARROW_TYPE) - return listOf("No Arrows selected" to HorizontalAlignment.LEFT) - - val amountString = ( - if (arrowConfig.colorArrowAmount) { - percentageColor( - QuiverAPI.currentAmount.toLong(), - QuiverAPI.MAX_ARROW_AMOUNT.toLong(), - ).getChatColor() - } else "" - ) + if (QuiverAPI.wearingSkeletonMasterChestplate) { - "∞" - } else { - when (arrowConfig.arrowAmountDisplay) { - ArrowAmountDisplay.NUMBER -> QuiverAPI.currentAmount.addSeparators() - ArrowAmountDisplay.PERCENTAGE -> "${QuiverAPI.currentAmount.asArrowPercentage()}%" - else -> QuiverAPI.currentAmount.addSeparators() - } - } - - return listOf( - if (displayConfig.displayNumbersFirst) { - "$amountString ${QuiverAPI.currentArrow?.arrow}s" - } else { - "Arrows: $amountString ${QuiverAPI.currentArrow?.arrow?.replace(" Arrow", "")}" - } to HorizontalAlignment.LEFT, - ) -} - -private fun getQuiverShowWhen(): Boolean { - if (informationFilteringConfig.hideIrrelevantLines && !QuiverAPI.hasBowInInventory()) return false - return !inAnyIsland(IslandType.THE_RIFT) -} - -private fun getPowderDisplayPair() = buildList { - val powderTypes = HotmAPI.PowderType.values() - if (informationFilteringConfig.hideEmptyLines && powderTypes.all { it.getTotal() == 0L }) { - return listOf("" to HorizontalAlignment.LEFT) - } - - add("§9§lPowder" to HorizontalAlignment.LEFT) - - val displayNumbersFirst = displayConfig.displayNumbersFirst - - for (type in powderTypes) { - val name = type.displayName - val color = type.color - val current = type.getCurrent().formatNum() - val total = type.getTotal().formatNum() - - when (displayConfig.powderDisplay) { - PowderDisplay.AVAILABLE -> { - add(" §7- ${if (displayNumbersFirst) "$color$current $name" else "§f$name: $color$current"}" to HorizontalAlignment.LEFT) - } - - PowderDisplay.TOTAL -> { - add(" §7- ${if (displayNumbersFirst) "$color$total $name" else "§f$name: $color$total"}" to HorizontalAlignment.LEFT) - } - - PowderDisplay.BOTH -> { - add( - " §7- ${if (displayNumbersFirst) "$color$current/$total $name" else "§f$name: $color$current/$total"}" - to HorizontalAlignment.LEFT, - ) - } - - null -> {} - } - } -} - -private fun getPowderShowWhen() = inAdvancedMiningIsland() - -private fun getEventsDisplayPair(): List = ScoreboardEvent.getEvent() - .filterNotNull() - .flatMap { it.getLines().map { i -> i to HorizontalAlignment.LEFT } } - .takeIf { it.isNotEmpty() } ?: listOf("" to HorizontalAlignment.LEFT) - - -private fun getEventsShowWhen() = ScoreboardEvent.getEvent().isNotEmpty() - -private fun getMayorDisplayPair() = buildList { - val currentMayorName = MayorAPI.currentMayor?.mayorName?.let { MayorAPI.mayorNameWithColorCode(it) } ?: return@buildList - val timeTillNextMayor = if (mayorConfig.showTimeTillNextMayor) { - "§7 (§e${MayorAPI.nextMayorTimestamp.timeUntil().format(maxUnits = 2)}§7)" - } else { - "" - } - - add((currentMayorName + timeTillNextMayor) to HorizontalAlignment.LEFT) - - if (mayorConfig.showMayorPerks) { - MayorAPI.currentMayor?.activePerks?.forEach { perk -> - add(" §7- §e${perk.perkName}" to HorizontalAlignment.LEFT) - } - } - - if (!mayorConfig.showExtraMayor) return@buildList - addAll(addMinister()) - addAll(addPerkpocalypseMayor()) -} - -private fun addMinister() = buildList { - val ministerName = MayorAPI.currentMinister?.mayorName?.let { MayorAPI.mayorNameWithColorCode(it) } ?: return@buildList - add(ministerName to HorizontalAlignment.LEFT) - - if (mayorConfig.showMayorPerks) { - MayorAPI.currentMinister?.activePerks?.forEach { perk -> - add(" §7- §e${perk.perkName}" to HorizontalAlignment.LEFT) - } - } -} - -private fun addPerkpocalypseMayor() = buildList { - val jerryExtraMayor = MayorAPI.jerryExtraMayor - val extraMayor = jerryExtraMayor.first ?: return@buildList - - val extraMayorName = extraMayor.mayorName.let { MayorAPI.mayorNameWithColorCode(it) } - val extraTimeTillNextMayor = if (mayorConfig.showTimeTillNextMayor) { - "§7 (§6${jerryExtraMayor.second.timeUntil().format(maxUnits = 2)}§7)" - } else { - "" - } - - add((extraMayorName + extraTimeTillNextMayor) to HorizontalAlignment.LEFT) -} - -private fun getMayorShowWhen() = - !inAnyIsland(IslandType.THE_RIFT) && MayorAPI.currentMayor != null - -private fun getPartyDisplayPair() = - if (PartyAPI.partyMembers.isEmpty() && informationFilteringConfig.hideEmptyLines) { - listOf("" to HorizontalAlignment.LEFT) - } else { - val title = - if (PartyAPI.partyMembers.isEmpty()) "§9§lParty" else "§9§lParty (${PartyAPI.partyMembers.size})" - val partyList = PartyAPI.partyMembers - .take(partyConfig.maxPartyList.get()) - .map { - " §7- §f$it" - } - .toTypedArray() - listOf(title, *partyList).map { it to HorizontalAlignment.LEFT } - } - -private fun getPartyShowWhen() = if (DungeonAPI.inDungeon()) { - false // Hidden bc the scoreboard lines already exist -} else { - if (partyConfig.showPartyEverywhere) { - true - } else { - inAnyIsland(IslandType.DUNGEON_HUB, IslandType.KUUDRA_ARENA, IslandType.CRIMSON_ISLE) || inGlaciteArea() - } -} - -private fun getFooterDisplayPair(): List = listOf( - displayConfig.titleAndFooter.customFooter.get().toString() - .replace("&", "§") - .split("\\n") - .map { it to displayConfig.titleAndFooter.alignTitleAndFooter }, -).flatten() - -private fun getExtraDisplayPair(): List { - val lines = recentUnknownLines() - if (lines.isEmpty()) return listOf("" to HorizontalAlignment.LEFT) - - return listOf("§cUndetected Lines:" to HorizontalAlignment.LEFT) + lines.map { - it.line to HorizontalAlignment.LEFT - } -} - -private fun getExtraShowWhen(): Boolean = recentUnknownLines().isNotEmpty() diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt deleted file mode 100644 index 8dd3af9f7aec..000000000000 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt +++ /dev/null @@ -1,576 +0,0 @@ -package at.hannibal2.skyhanni.features.gui.customscoreboard - -import at.hannibal2.skyhanni.data.HypixelData -import at.hannibal2.skyhanni.data.IslandType -import at.hannibal2.skyhanni.data.ScoreboardData -import at.hannibal2.skyhanni.data.model.TabWidget -import at.hannibal2.skyhanni.features.combat.SpidersDenAPI.isAtTopOfNest -import at.hannibal2.skyhanni.features.dungeon.DungeonAPI -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.eventsConfig -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardEvent.VOTING -import at.hannibal2.skyhanni.features.misc.ServerRestartTitle -import at.hannibal2.skyhanni.features.rift.area.stillgorechateau.RiftBloodEffigies -import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter -import at.hannibal2.skyhanni.utils.LorenzUtils.inAdvancedMiningIsland -import at.hannibal2.skyhanni.utils.LorenzUtils.isInIsland -import at.hannibal2.skyhanni.utils.RegexUtils.anyMatches -import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher -import at.hannibal2.skyhanni.utils.RegexUtils.matches -import at.hannibal2.skyhanni.utils.StringUtils.removeColor -import at.hannibal2.skyhanni.utils.StringUtils.removeResets -import at.hannibal2.skyhanni.utils.TabListData -import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern as SbPattern - -/** - * This enum contains all the lines that either are events or other lines that are so rare/not often seen that they - * don't fit in the normal [ScoreboardElement] enum. - * - * We for example have the [VOTING] Event, while this is clearly not an event, I don't consider them as normal lines - * because they are visible for a maximum of like 1 minute every 5 days and ~12 hours. - */ - -private fun getSbLines(): List = ScoreboardData.sidebarLinesFormatted - -enum class ScoreboardEvent( - private val displayLine: () -> List, - private val showWhen: () -> Boolean, - private val configLine: String, -) { - VOTING( - ::getVotingLines, - ::getVotingShowWhen, - "§7(All Voting Lines)", - ), - SERVER_CLOSE( - ::getServerCloseLines, - ::getServerCloseShowWhen, - "§cServer closing soon!", - ), - DUNGEONS( - ::getDungeonsLines, - ::getDungeonsShowWhen, - "§7(All Dungeons Lines)", - ), - KUUDRA( - ::getKuudraLines, - ::getKuudraShowWhen, - "§7(All Kuudra Lines)", - ), - DOJO( - ::getDojoLines, - ::getDojoShowWhen, - "§7(All Dojo Lines)", - ), - DARK_AUCTION( - ::getDarkAuctionLines, - ::getDarkAuctionShowWhen, - "Time Left: §b11\n" + - "Current Item:\n" + - " §5Travel Scroll to Sirius", - ), - JACOB_CONTEST( - ::getJacobContestLines, - ::getJacobContestShowWhen, - "§eJacob's Contest\n" + - "§e○ §fCarrot §a18m17s\n" + - " Collected §e8,264", - ), - JACOB_MEDALS( - ::getJacobMedalsLines, - ::getJacobMedalsShowWhen, - "§6§lGOLD §fmedals: §613\n" + - "§f§lSILVER §fmedals: §f3\n" + - "§c§lBRONZE §fmedals: §c4", - ), - TRAPPER( - ::getTrapperLines, - ::getTrapperShowWhen, - "Pelts: §5711\n" + - "Tracker Mob Location:\n" + - "§bMushroom Gorge", - ), - GARDEN_CLEAN_UP( - ::getGardenCleanUpLines, - ::getGardenCleanUpShowWhen, - "Cleanup: §c12.6%", - ), - GARDEN_PASTING( - ::getGardenPastingLines, - ::getGardenPastingShowWhen, - "§fBarn Pasting§7: §e12.3%", - ), - FLIGHT_DURATION( - ::getFlightDurationLines, - ::getFlightDurationShowWhen, - "Flight Duration: §a10m 0s", - ), - WINTER( - ::getWinterLines, - ::getWinterShowWhen, - "§7(All Winter Event Lines)", - ), - NEW_YEAR( - ::getNewYearLines, - ::getNewYearShowWhen, - "§dNew Year Event!§f 24:25", - ), - SPOOKY( - ::getSpookyLines, - ::getSpookyShowWhen, - "§6Spooky Festival§f 50:54\n" + - "§7Your Candy:\n" + - "§a1 Green§7, §50 Purple §7(§61 §7pts.)", - ), - BROODMOTHER( - ::getBroodmotherLines, - ::isAtTopOfNest, - "§4Broodmother§7: §eDormant", - ), - MINING_EVENTS( - ::getMiningEventsLines, - { inAdvancedMiningIsland() }, - "§7(All Mining Event Lines)", - ), - DAMAGE( - ::getDamageLines, - ::getDamageShowWhen, - "Dragon HP: §a6,180,925 §c❤\n" + - "Your Damage: §c375,298.5", - ), - MAGMA_BOSS( - ::getMagmaBossLines, - ::getMagmaBossShowWhen, - "§7(All Magma Boss Lines)\n" + - "§7Boss: §c0%\n" + - "§7Damage Soaked:\n" + - "§e▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎▎§7▎▎▎▎▎", - ), - CARNIVAL( - ::getCarnivalLines, - ::getCarnivalShowWhen, - "§7(All Carnival Lines)", - ), - RIFT( - ::getRiftLines, - { IslandType.THE_RIFT.isInIsland() }, - "§7(All Rift Lines)", - ), - ESSENCE( - ::getEssenceLines, - ::getEssenceShowWhen, - "Dragon Essence: §d1,285", - ), - QUEUE( - ::getQueueLines, - ::getQueueShowWhen, - "Queued: Glacite Mineshafts\n" + - "Position: §b#45 §fSince: §a00:00", - ), - ACTIVE_TABLIST_EVENTS( - ::getActiveEventLine, - ::getActiveEventShowWhen, - "§7(All Active Tablist Events)\n§dHoppity's Hunt\n §fEnds in: §e26h", - ), - STARTING_SOON_TABLIST_EVENTS( - ::getSoonEventLine, - ::getSoonEventShowWhen, - "§7(All Starting Soon Tablist Events)\n§6Mining Fiesta\n §fStarts in: §e52min", - ), - REDSTONE( - ::getRedstoneLines, - ::getRedstoneShowWhen, - "§e§l⚡ §cRedstone: §e§b7%", - ), - ANNIVERSARY( - ::getAnniversaryLines, - ::getAnniversaryShowWhen, - "§d5th Anniversary§f 167:59:54", - ), - ; - - override fun toString() = configLine - - fun getLines(): List = displayLine() - - companion object { - fun getEvent() = buildList { - if (eventsConfig.showAllActiveEvents) { - for (event in eventsConfig.eventEntries) { - if (event.showWhen()) { - add(event) - } - } - } else { - add(eventsConfig.eventEntries.firstOrNull { it.showWhen() && it.getLines().isNotEmpty() }) - } - } - - // I don't know why, but this field is needed for it to work - @JvmField - val defaultOption = listOf( - VOTING, - SERVER_CLOSE, - DUNGEONS, - KUUDRA, - DOJO, - DARK_AUCTION, - JACOB_CONTEST, - JACOB_MEDALS, - TRAPPER, - GARDEN_CLEAN_UP, - GARDEN_PASTING, - FLIGHT_DURATION, - NEW_YEAR, - WINTER, - SPOOKY, - BROODMOTHER, - MINING_EVENTS, - DAMAGE, - MAGMA_BOSS, - CARNIVAL, - RIFT, - ESSENCE, - ACTIVE_TABLIST_EVENTS, - ) - } -} - -private fun getVotingLines() = buildList { - val sbLines = getSbLines() - - val yearLine = sbLines.firstOrNull { SbPattern.yearVotesPattern.matches(it) } ?: return emptyList() - add(yearLine) - - if (sbLines.nextAfter(yearLine) == "§7Waiting for") { - add("§7Waiting for") - add("§7your vote...") - } else { - if (SbPattern.votesPattern.anyMatches(sbLines)) { - addAll(sbLines.filter { SbPattern.votesPattern.matches(it) }) - } - } -} - -private fun getVotingShowWhen(): Boolean = SbPattern.yearVotesPattern.anyMatches(getSbLines()) - -private fun getServerCloseLines() = buildList { - val matchingLine = getSbLines().first { ServerRestartTitle.restartingGreedyPattern.matches(it) } - add(matchingLine.split("§8")[0]) -} - -private fun getServerCloseShowWhen(): Boolean = ServerRestartTitle.restartingGreedyPattern.anyMatches(getSbLines()) - -private fun getDungeonsLines() = listOf( - SbPattern.m7dragonsPattern, - SbPattern.autoClosingPattern, - SbPattern.startingInPattern, - SbPattern.keysPattern, - SbPattern.timeElapsedPattern, - SbPattern.clearedPattern, - SbPattern.soloPattern, - SbPattern.teammatesPattern, - SbPattern.floor3GuardiansPattern, -).let { patterns -> - // BetterMap adds a random §r at the start, making the line go black - getSbLines().filter { line -> patterns.any { it.matches(line) } }.map { it.removePrefix("§r") } -} - -private fun getDungeonsShowWhen(): Boolean = DungeonAPI.inDungeon() - -private fun getKuudraLines() = listOf( - SbPattern.autoClosingPattern, - SbPattern.startingInPattern, - SbPattern.timeElapsedPattern, - SbPattern.instanceShutdownPattern, - SbPattern.wavePattern, - SbPattern.tokensPattern, - SbPattern.submergesPattern, -) - .mapNotNull { pattern -> - getSbLines().firstOrNull { pattern.matches(it) } - } - -private fun getKuudraShowWhen(): Boolean = IslandType.KUUDRA_ARENA.isInIsland() - -private fun getDojoLines() = listOf( - SbPattern.dojoChallengePattern, - SbPattern.dojoDifficultyPattern, - SbPattern.dojoPointsPattern, - SbPattern.dojoTimePattern, -) - .mapNotNull { pattern -> - getSbLines().firstOrNull { pattern.matches(it) } - } - -private fun getDojoShowWhen(): Boolean = SbPattern.dojoChallengePattern.anyMatches(getSbLines()) - -private fun getDarkAuctionLines() = buildList { - getSbLines().firstOrNull { SbPattern.startingInPattern.matches(it) }?.let { add(it) } - getSbLines().firstOrNull { SbPattern.timeLeftPattern.matches(it) }?.let { add(it) } - - val darkAuctionCurrentItemLine = getSbLines().firstOrNull { SbPattern.darkAuctionCurrentItemPattern.matches(it) } - - if (darkAuctionCurrentItemLine != null) { - add(darkAuctionCurrentItemLine) - getSbLines().nextAfter(darkAuctionCurrentItemLine)?.let { add(it) } - } -} - -private fun getDarkAuctionShowWhen(): Boolean = IslandType.DARK_AUCTION.isInIsland() - -private fun getJacobContestLines() = buildList { - getSbLines().firstOrNull { SbPattern.jacobsContestPattern.matches(it) }?.let { line -> - add(line) - getSbLines().nextAfter(line)?.let { add(it) } - getSbLines().nextAfter(line, 2)?.let { add(it) } - getSbLines().nextAfter(line, 3)?.let { - if (!SbPattern.footerPattern.matches(it)) add(it) - } - } -} - -private fun getJacobContestShowWhen(): Boolean = SbPattern.jacobsContestPattern.anyMatches(getSbLines()) - -private fun getJacobMedalsLines(): List = getSbLines().filter { SbPattern.medalsPattern.matches(it) } - -private fun getJacobMedalsShowWhen(): Boolean = SbPattern.medalsPattern.anyMatches(getSbLines()) - -private fun getTrapperLines() = buildList { - getSbLines().firstOrNull { SbPattern.peltsPattern.matches(it) }?.let { add(it) } - - val trapperMobLocationLine = getSbLines().firstOrNull { SbPattern.mobLocationPattern.matches(it) } - if (trapperMobLocationLine != null) { - add("Tracker Mob Location:") - getSbLines().nextAfter(trapperMobLocationLine)?.let { add(it) } - } -} - -private fun getTrapperShowWhen(): Boolean = - getSbLines().any { SbPattern.peltsPattern.matches(it) || SbPattern.mobLocationPattern.matches(it) } - -private fun getGardenCleanUpLines(): List = - listOf(getSbLines().first { SbPattern.cleanUpPattern.matches(it) }.trim()) - -private fun getGardenCleanUpShowWhen(): Boolean = SbPattern.cleanUpPattern.anyMatches(getSbLines()) - -private fun getGardenPastingLines(): List = - listOf(getSbLines().first { SbPattern.pastingPattern.matches(it) }.trim()) - -private fun getGardenPastingShowWhen(): Boolean = SbPattern.pastingPattern.anyMatches(getSbLines()) - -private fun getFlightDurationLines(): List = - listOf(getSbLines().first { SbPattern.flightDurationPattern.matches(it) }.trim()) - -private fun getFlightDurationShowWhen(): Boolean = SbPattern.flightDurationPattern.anyMatches(getSbLines()) - -private fun getWinterLines() = buildList { - getSbLines().firstOrNull { SbPattern.winterEventStartPattern.matches(it) }?.let { add(it) } - getSbLines().firstOrNull { SbPattern.winterNextWavePattern.matches(it) && !it.endsWith("Soon!") }?.let { add(it) } - getSbLines().firstOrNull { SbPattern.winterWavePattern.matches(it) }?.let { add(it) } - getSbLines().firstOrNull { SbPattern.winterMagmaLeftPattern.matches(it) }?.let { add(it) } - getSbLines().firstOrNull { SbPattern.winterTotalDmgPattern.matches(it) }?.let { add(it) } - getSbLines().firstOrNull { SbPattern.winterCubeDmgPattern.matches(it) }?.let { add(it) } -} - -private fun getWinterShowWhen(): Boolean = getSbLines().any { - SbPattern.winterEventStartPattern.matches(it) || - (SbPattern.winterNextWavePattern.matches(it) && !it.endsWith("Soon!")) || - SbPattern.winterWavePattern.matches(it) -} - -private fun getNewYearLines() = listOf(getSbLines().first { SbPattern.newYearPattern.matches(it) }) - -private fun getNewYearShowWhen(): Boolean = SbPattern.newYearPattern.anyMatches(getSbLines()) - -private fun getSpookyLines() = buildList { - getSbLines().firstOrNull { SbPattern.spookyPattern.matches(it) }?.let { add(it) } // Time - add("§7Your Candy: ") - add( - TabListData.getFooter() - .removeResets() - .split("\n") - .firstOrNull { it.startsWith("§7Your Candy:") } - ?.removePrefix("§7Your Candy:") ?: "§cCandy not found", - ) // Candy -} - -private fun getSpookyShowWhen(): Boolean = getSbLines().any { SbPattern.spookyPattern.matches(it) } - -private fun getTablistEvent(): String? = - TabListData.getTabList().firstOrNull { SbPattern.eventNamePattern.matches(it) } - ?.let { - SbPattern.eventNamePattern.matchMatcher(it) { - group("name") - } - } - -private fun getActiveEventLine(): List { - val currentActiveEvent = getTablistEvent() ?: return emptyList() - - // Some Active Events are better not shown from the tablist, - // but from other locations like the scoreboard - val blockedEvents = listOf("Spooky Festival", "Carnival", "5th SkyBlock Anniversary", "New Year Celebration") - if (blockedEvents.contains(currentActiveEvent.removeColor())) return emptyList() - - val currentActiveEventTime = SbPattern.eventTimeEndsPattern.firstMatcher(TabWidget.EVENT.lines) { - group("time") - } ?: return emptyList() - - return listOf(currentActiveEvent, " Ends in: §e$currentActiveEventTime") -} - -private fun getActiveEventShowWhen(): Boolean = - getTablistEvent() != null && TabListData.getTabList().any { SbPattern.eventTimeEndsPattern.matches(it) } - -private fun getSoonEventLine(): List { - val soonActiveEvent = getTablistEvent() ?: return emptyList() - val soonActiveEventTime = SbPattern.eventTimeStartsPattern.firstMatcher(TabWidget.EVENT.lines) { - group("time") - } ?: return emptyList() - - return listOf(soonActiveEvent, " Starts in: §e$soonActiveEventTime") -} - -private fun getSoonEventShowWhen(): Boolean = - getTablistEvent() != null && TabListData.getTabList().any { SbPattern.eventTimeStartsPattern.matches(it) } - -private fun getBroodmotherLines(): List = - listOf(getSbLines().first { SbPattern.broodmotherPattern.matches(it) }) - -private fun getMiningEventsLines() = buildList { - // Wind - if (getSbLines().any { SbPattern.windCompassPattern.matches(it) } && - getSbLines().any { SbPattern.windCompassArrowPattern.matches(it) } - ) { - add(getSbLines().first { SbPattern.windCompassPattern.matches(it) }) - add("| ${getSbLines().first { SbPattern.windCompassArrowPattern.matches(it) }} §f|") - } - - // Better Together - if (getSbLines().any { SbPattern.nearbyPlayersPattern.matches(it) }) { - add("§dBetter Together") - add(" ${getSbLines().first { SbPattern.nearbyPlayersPattern.matches(it) }}") - } - - // Zone Events - if (getSbLines().any { SbPattern.miningEventPattern.matches(it) } && - getSbLines().any { SbPattern.miningEventZonePattern.matches(it) } - ) { - add(getSbLines().first { SbPattern.miningEventPattern.matches(it) }.removePrefix("Event: ")) - add("in ${getSbLines().first { SbPattern.miningEventZonePattern.matches(it) }.removePrefix("Zone: ")}") - } - - // Zone Events but no Zone Line - if (getSbLines().any { SbPattern.miningEventPattern.matches(it) } && - getSbLines().none { SbPattern.miningEventZonePattern.matches(it) } - ) { - add( - getSbLines().first { SbPattern.miningEventPattern.matches(it) } - .removePrefix("Event: "), - ) - } - - // Mithril Gourmand - if (getSbLines().any { SbPattern.mithrilRemainingPattern.matches(it) } && - getSbLines().any { SbPattern.mithrilYourMithrilPattern.matches(it) } - ) { - add(getSbLines().first { SbPattern.mithrilRemainingPattern.matches(it) }) - add(getSbLines().first { SbPattern.mithrilYourMithrilPattern.matches(it) }) - } - - // Raffle - if (getSbLines().any { SbPattern.raffleTicketsPattern.matches(it) } && - getSbLines().any { SbPattern.rafflePoolPattern.matches(it) } - ) { - add(getSbLines().first { SbPattern.raffleTicketsPattern.matches(it) }) - add(getSbLines().first { SbPattern.rafflePoolPattern.matches(it) }) - } - - // Raid - if (getSbLines().any { SbPattern.yourGoblinKillsPattern.matches(it) } && - getSbLines().any { SbPattern.remainingGoblinPattern.matches(it) } - ) { - add(getSbLines().first { SbPattern.yourGoblinKillsPattern.matches(it) }) - add(getSbLines().first { SbPattern.remainingGoblinPattern.matches(it) }) - } - - // Fortunate Freezing - if (getSbLines().any { SbPattern.fortunateFreezingBonusPattern.matches(it) }) { - add(getSbLines().first { SbPattern.fortunateFreezingBonusPattern.matches(it) }) - } - - // Fossil Dust - if (getSbLines().any { SbPattern.fossilDustPattern.matches(it) }) { - add(getSbLines().first { SbPattern.fossilDustPattern.matches(it) }) - } -} - -private fun getDamageLines(): List = - listOf(getSbLines().first { SbPattern.bossHPPattern.matches(it) }) + - (getSbLines().first { SbPattern.bossDamagePattern.matches(it) }) - -private fun getDamageShowWhen(): Boolean = - getSbLines().any { SbPattern.bossHPPattern.matches(it) } && - getSbLines().any { SbPattern.bossDamagePattern.matches(it) } - -private fun getMagmaBossLines() = getSbLines().filter { line -> - SbPattern.magmaBossPattern.matches(line) || - SbPattern.damageSoakedPattern.matches(line) || - SbPattern.killMagmasPattern.matches(line) || - SbPattern.killMagmasDamagedSoakedBarPattern.matches(line) || - SbPattern.reformingPattern.matches(line) || - SbPattern.bossHealthPattern.matches(line) || - SbPattern.bossHealthBarPattern.matches(line) -} - -private fun getMagmaBossShowWhen(): Boolean = SbPattern.magmaChamberPattern.matches(HypixelData.skyBlockArea) - -private fun getCarnivalLines() = listOf( - SbPattern.carnivalPattern, - SbPattern.carnivalTokensPattern, - SbPattern.carnivalTasksPattern, - SbPattern.timeLeftPattern, - SbPattern.carnivalCatchStreakPattern, - SbPattern.carnivalFruitsPattern, - SbPattern.carnivalAccuracyPattern, - SbPattern.carnivalKillsPattern, - SbPattern.carnivalScorePattern, -) - .mapNotNull { pattern -> - getSbLines().firstOrNull { pattern.matches(it) } - } - -private fun getCarnivalShowWhen() = - listOf(SbPattern.carnivalPattern, SbPattern.carnivalTokensPattern, SbPattern.carnivalTasksPattern).anyMatches(getSbLines()) - -private fun getRiftLines() = getSbLines().filter { line -> - RiftBloodEffigies.heartsPattern.matches(line) || - SbPattern.riftHotdogTitlePattern.matches(line) || - SbPattern.timeLeftPattern.matches(line) || - SbPattern.riftHotdogEatenPattern.matches(line) || - SbPattern.riftAveikxPattern.matches(line) || - SbPattern.riftHayEatenPattern.matches(line) || - SbPattern.cluesPattern.matches(line) || - SbPattern.barryProtestorsQuestlinePattern.matches(line) || - SbPattern.barryProtestorsHandledPattern.matches(line) -} - -private fun getEssenceLines(): List = listOf(getSbLines().first { SbPattern.essencePattern.matches(it) }) - -private fun getEssenceShowWhen(): Boolean = SbPattern.essencePattern.anyMatches(getSbLines()) - -private fun getQueueLines(): List = - listOf(getSbLines().first { SbPattern.queuePattern.matches(it) }) + - (getSbLines().first { SbPattern.queueTierPattern.matches(it) }) + - (getSbLines().first { SbPattern.queuePositionPattern.matches(it) }) - -private fun getQueueShowWhen(): Boolean = SbPattern.queuePattern.anyMatches(getSbLines()) - -private fun getRedstoneLines(): List = listOf(getSbLines().first { SbPattern.redstonePattern.matches(it) }) - -private fun getRedstoneShowWhen(): Boolean = SbPattern.redstonePattern.anyMatches(getSbLines()) - -private fun getAnniversaryLines() = listOf(getSbLines().first { SbPattern.anniversaryPattern.matches(it) }) - -private fun getAnniversaryShowWhen(): Boolean = SbPattern.anniversaryPattern.anyMatches(getSbLines()) diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardLine.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardLine.kt new file mode 100644 index 000000000000..3231f2bdf11b --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardLine.kt @@ -0,0 +1,18 @@ +package at.hannibal2.skyhanni.features.gui.customscoreboard + +import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.displayConfig +import at.hannibal2.skyhanni.utils.RenderUtils + +data class ScoreboardLine( + val display: String, + val alignment: RenderUtils.HorizontalAlignment = DEFAULT_ALIGNMENT, +) { + + companion object { + private val DEFAULT_ALIGNMENT get() = displayConfig.textAlignment + + fun String.align(): ScoreboardLine = ScoreboardLine(this, DEFAULT_ALIGNMENT) + + infix fun String.align(alignment: RenderUtils.HorizontalAlignment): ScoreboardLine = ScoreboardLine(this, alignment) + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt index 5170bd910d2b..259e983f9fd0 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardPattern.kt @@ -9,7 +9,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent object ScoreboardPattern { private val group = RepoPattern.group("features.gui.customscoreboard") - // Stats from the scoreboard + // Lines from the scoreboard private val scoreboardGroup by group.exclusiveGroup("scoreboard") @SubscribeEvent @@ -17,35 +17,33 @@ object ScoreboardPattern { UnknownLinesHandler.remoteOnlyPatterns = scoreboardGroup.getUnusedPatterns().toTypedArray() } - // main scoreboard + // Main scoreboard private val mainSb = scoreboardGroup.group("main") + + //TODO add regex tests val motesPattern by mainSb.pattern( "motes", - "^(§.)*Motes: (§.)*(?[\\d,]+).*$", + "(?:§.)*Motes: (?:§.)*(?[\\d,]+).*", ) val heatPattern by mainSb.pattern( "heat", - "^Heat: (?.*)$", - ) // this line is weird (either text or number), ill leave it as is; it even has different colors? - val coldPattern by mainSb.pattern( - "cold", - "^(?:§.)*Cold: §.(?-?\\d+)❄$", + "Heat: (?.*)", ) val copperPattern by mainSb.pattern( "copper", - "^(§.)*Copper: (§.)*(?[\\d,]+).*$", + "(?:§.)*Copper: (?:§.)*(?[\\d,]+).*", ) val locationPattern by mainSb.pattern( "location", - "^\\s*(?(§7⏣|§5ф) .*)$", + "\\s*(?(?:§7⏣|§5ф) .*)", ) val lobbyCodePattern by mainSb.pattern( "lobbycode", - "^\\s*§.((\\d{2}/\\d{2}/\\d{2})|Server closing: [\\d:]+) §8(?.*)\$", + "\\s*§.(?:\\d{2}/?){3} §8(?.*)", ) val datePattern by mainSb.pattern( "date", - "^\\s*(Late |Early )?(Spring|Summer|Autumn|Winter) \\d{1,2}(st|nd|rd|th)?.*", + "\\s*(?:(?:Late|Early) )?(?:Spring|Summer|Autumn|Winter) \\d+(?:st|nd|rd|th)?.*", ) /** @@ -54,15 +52,15 @@ object ScoreboardPattern { */ val timePattern by mainSb.pattern( "time", - "^\\s*§7\\d{1,2}:\\d{2}(?:am|pm)\\s*(?(§b☽|§e☀|§.⚡|§.☔))?.*$", + "\\s*§7\\d+:\\d+(?:am|pm)\\s*(?§b☽|§e☀|§.⚡|§.☔)?.*", ) val footerPattern by mainSb.pattern( "footer", - "§e(www|alpha).hypixel.net\$", + "§e(?:www|alpha).hypixel.net", ) val yearVotesPattern by mainSb.pattern( "yearvotes", - "(?^§6Year \\d+ Votes\$)", + "§6Year \\d+ Votes", ) /** @@ -75,66 +73,63 @@ object ScoreboardPattern { ) val waitingForVotePattern by mainSb.pattern( "waitingforvote", - "(§7Waiting for|§7your vote\\.\\.\\.)$", + "§7Waiting for|§7your vote\\.\\.\\.", ) val northstarsPattern by mainSb.pattern( "northstars", - "North Stars: §d(?[\\w,]+).*$", + "North Stars: §d(?[\\w,]+).*", ) val profileTypePattern by mainSb.pattern( "profiletype", - "^\\s*(§7♲ §7Ironman|§a☀ §aStranded|§.Ⓑ §.Bingo).*$", - ) - val emptyLinesPattern by mainSb.pattern( - "emptylines", - "^\\s*$", + "\\s*(?:§7♲ §7Ironman|§a☀ §aStranded|§.Ⓑ §.Bingo).*", ) // multi use private val multiUseSb = scoreboardGroup.group("multiuse") val autoClosingPattern by multiUseSb.pattern( "autoclosing", - "(§.)*Auto-closing in: §c(\\d{1,2}:)?\\d{1,2}$", + "(?:§.)*Auto-closing in: §c(?:\\d+:)?\\d+", ) val startingInPattern by multiUseSb.pattern( "startingin", - "(§.)*Starting in: §.(\\d{1,2}:)?\\d{1,2}$", + "(?:§.)*Starting in: §.(?:\\d+:)?\\d+", ) val timeElapsedPattern by multiUseSb.pattern( "timeelapsed", - "(§.)*Time Elapsed: (§.)*(?