From 0d288498a60718e2a165666ebd69b10aef658833 Mon Sep 17 00:00:00 2001 From: Thunderblade73 <85900443+Thunderblade73@users.noreply.github.com> Date: Mon, 3 Jun 2024 19:38:55 +0200 Subject: Backend: Widget abstractions (#1150) Co-authored-by: Cal --- src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt | 2 + .../java/at/hannibal2/skyhanni/data/HypixelData.kt | 90 +++-- .../at/hannibal2/skyhanni/data/model/TabWidget.kt | 438 +++++++++++++++++++++ .../hannibal2/skyhanni/events/WidgetUpdateEvent.kt | 14 + .../at/hannibal2/skyhanni/utils/TabListData.kt | 6 +- 5 files changed, 503 insertions(+), 47 deletions(-) create mode 100644 src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt create mode 100644 src/main/java/at/hannibal2/skyhanni/events/WidgetUpdateEvent.kt (limited to 'src/main/java') diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index b7e6d7417..a3143ee36 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -64,6 +64,7 @@ import at.hannibal2.skyhanni.data.jsonobjects.local.VisualWordsJson import at.hannibal2.skyhanni.data.mob.MobData import at.hannibal2.skyhanni.data.mob.MobDebug import at.hannibal2.skyhanni.data.mob.MobDetection +import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.data.repo.RepoManager import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.PreInitFinishedEvent @@ -577,6 +578,7 @@ class SkyHanniMod { loadModule(ChatUtils) loadModule(FixedRateTimerManager()) loadModule(ChromaManager) + loadModule(TabWidget) loadModule(HotmData) loadModule(ContributorManager) loadModule(TabComplete) diff --git a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt index 166282582..6f9fdd138 100644 --- a/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt +++ b/src/main/java/at/hannibal2/skyhanni/data/HypixelData.kt @@ -2,6 +2,7 @@ package at.hannibal2.skyhanni.data import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.config.ConfigManager.Companion.gson +import at.hannibal2.skyhanni.data.model.TabWidget import at.hannibal2.skyhanni.events.HypixelJoinEvent import at.hannibal2.skyhanni.events.IslandChangeEvent import at.hannibal2.skyhanni.events.LorenzChatEvent @@ -9,6 +10,7 @@ import at.hannibal2.skyhanni.events.LorenzTickEvent import at.hannibal2.skyhanni.events.LorenzWorldChangeEvent import at.hannibal2.skyhanni.events.ProfileJoinEvent import at.hannibal2.skyhanni.events.TabListUpdateEvent +import at.hannibal2.skyhanni.events.WidgetUpdateEvent import at.hannibal2.skyhanni.features.bingo.BingoAPI import at.hannibal2.skyhanni.features.dungeon.DungeonAPI import at.hannibal2.skyhanni.features.rift.RiftAPI @@ -36,8 +38,7 @@ class HypixelData { private val patternGroup = RepoPattern.group("data.hypixeldata") private val islandNamePattern by patternGroup.pattern( - "islandname", - "(?:§.)*(Area|Dungeon): (?:§.)*(?.*)" + "islandname", "(?:§.)*(Area|Dungeon): (?:§.)*(?.*)" ) private var lastLocRaw = SimpleTimeMark.farPast() @@ -45,51 +46,41 @@ class HypixelData { companion object { private val patternGroup = RepoPattern.group("data.hypixeldata") private val serverIdScoreboardPattern by patternGroup.pattern( - "serverid.scoreboard", - "§7\\d+/\\d+/\\d+ §8(?[mM])(?\\S+).*" + "serverid.scoreboard", "§7\\d+/\\d+/\\d+ §8(?[mM])(?\\S+).*" ) private val serverIdTablistPattern by patternGroup.pattern( - "serverid.tablist", - " Server: §r§8(?\\S+)" + "serverid.tablist", " Server: §r§8(?\\S+)" ) private val lobbyTypePattern by patternGroup.pattern( - "lobbytype", - "(?.*lobby)\\d+" + "lobbytype", "(?.*lobby)\\d+" ) private val playerAmountPattern by patternGroup.pattern( - "playeramount", - "^\\s*(?:§.)+Players (?:§.)+\\((?\\d+)\\)\\s*$" + "playeramount", "^\\s*(?:§.)+Players (?:§.)+\\((?\\d+)\\)\\s*$" ) private val playerAmountCoopPattern by patternGroup.pattern( - "playeramount.coop", - "^\\s*(?:§.)*Coop (?:§.)*\\((?\\d+)\\)\\s*$" + "playeramount.coop", "^\\s*(?:§.)*Coop (?:§.)*\\((?\\d+)\\)\\s*$" ) private val playerAmountGuestingPattern by patternGroup.pattern( - "playeramount.guesting", - "^\\s*(?:§.)*Guests (?:§.)*\\((?\\d+)\\)\\s*$" + "playeramount.guesting", "^\\s*(?:§.)*Guests (?:§.)*\\((?\\d+)\\)\\s*$" ) + /** * REGEX-TEST: §r§b§lParty §r§f(4) */ private val dungeonPartyAmountPattern by patternGroup.pattern( - "playeramount.dungeonparty", - "^\\s*(?:§.)+Party (?:§.)+\\((?\\d+)\\)\\s*$" + "playeramount.dungeonparty", "^\\s*(?:§.)+Party (?:§.)+\\((?\\d+)\\)\\s*$" ) private val soloProfileAmountPattern by patternGroup.pattern( - "solo.profile.amount", - "^\\s*(?:§.)*Island\\s*$" + "solo.profile.amount", "^\\s*(?:§.)*Island\\s*$" ) private val scoreboardVisitingAmoutPattern by patternGroup.pattern( - "scoreboard.visiting.amount", - "\\s+§.✌ §.\\(§.(?\\d+)§./(?\\d+)\\)" + "scoreboard.visiting.amount", "\\s+§.✌ §.\\(§.(?\\d+)§./(?\\d+)\\)" ) private val guestPattern by patternGroup.pattern( - "guesting.scoreboard", - "SKYBLOCK GUEST" + "guesting.scoreboard", "SKYBLOCK GUEST" ) private val scoreboardTitlePattern by patternGroup.pattern( - "scoreboard.title", - "SK[YI]BLOCK(?: CO-OP| GUEST)?" + "scoreboard.title", "SK[YI]BLOCK(?: CO-OP| GUEST)?" ) /** @@ -97,8 +88,7 @@ class HypixelData { * REGEX-TEST: §5ф §dWizard Tower */ private val skyblockAreaPattern by patternGroup.pattern( - "skyblock.area", - "\\s*§(?7⏣|5ф) §(?.)(?.*)" + "skyblock.area", "\\s*§(?7⏣|5ф) §(?.)(?.*)" ) var hypixelLive = false @@ -125,12 +115,7 @@ class HypixelData { // Data from locraw var locrawData: JsonObject? = null private var locraw: MutableMap = mutableMapOf( - "server" to "", - "gametype" to "", - "lobbyname" to "", - "lobbytype" to "", - "mode" to "", - "map" to "" + "server" to "", "gametype" to "", "lobbyname" to "", "lobbytype" to "", "mode" to "", "map" to "" ) val server get() = locraw["server"] ?: "" @@ -158,7 +143,8 @@ class HypixelData { } ErrorManager.logErrorWithData( - Exception("NoServerId"), "Could not find server id", + Exception("NoServerId"), + "Could not find server id", "islandType" to LorenzUtils.skyBlockIsland, "tablist" to TabListData.getTabList(), "scoreboard" to ScoreboardData.sidebarLinesFormatted @@ -302,10 +288,7 @@ class HypixelData { // So, as requested by Hannibal, use locraw from // NEU and have NEU send it. // Remove this when NEU dependency is removed - if (LorenzUtils.onHypixel && - locrawData == null && - lastLocRaw.passedSince() > 15.seconds - ) { + if (LorenzUtils.onHypixel && locrawData == null && lastLocRaw.passedSince() > 15.seconds) { lastLocRaw = SimpleTimeMark.now() thread(start = true) { Thread.sleep(1000) @@ -342,7 +325,6 @@ class HypixelData { val inSkyBlock = checkScoreboard() if (inSkyBlock) { - checkIsland() checkSidebar() checkCurrentServerId() } @@ -351,6 +333,14 @@ class HypixelData { skyBlock = inSkyBlock } + @SubscribeEvent + fun onTabListUpdate(event: WidgetUpdateEvent) { + when (event.widget) { + TabWidget.AREA -> checkIsland(event) + else -> Unit + } + } + private fun checkProfileName() { if (profileName.isNotEmpty()) return @@ -392,18 +382,23 @@ class HypixelData { noTrade = ironman || stranded || bingo } - private fun checkIsland() { - var foundIsland = "" - TabListData.fullyLoaded = false + private fun checkIsland(event: WidgetUpdateEvent) { + val islandType: IslandType + val foundIsland: String + if (event.isClear()) { + + TabListData.fullyLoaded = false + islandType = IslandType.NONE + foundIsland = "" - TabListData.getTabList().matchFirst(islandNamePattern) { - foundIsland = group("island").removeColor() + } else { TabListData.fullyLoaded = true + // 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) } - // 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()) - val islandType = getIslandType(foundIsland, guesting) if (skyBlockIsland != islandType) { IslandChangeEvent(islandType, skyBlockIsland).postAndCatch() if (islandType == IslandType.UNKNOWN) { @@ -413,6 +408,9 @@ class HypixelData { loggerIslandChange.log(islandType.name) } skyBlockIsland = islandType + if (TabListData.fullyLoaded) { + TabWidget.reSendEvents() + } } } diff --git a/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt new file mode 100644 index 000000000..d459e2a9e --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/data/model/TabWidget.kt @@ -0,0 +1,438 @@ +package at.hannibal2.skyhanni.data.model + +import at.hannibal2.skyhanni.events.RepositoryReloadEvent +import at.hannibal2.skyhanni.events.TabListUpdateEvent +import at.hannibal2.skyhanni.events.WidgetUpdateEvent +import at.hannibal2.skyhanni.utils.CollectionUtils.editCopy +import at.hannibal2.skyhanni.utils.CollectionUtils.getOrNull +import at.hannibal2.skyhanni.utils.ConditionalUtils.transformIf +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher +import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern +import net.minecraftforge.fml.common.eventhandler.EventPriority +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import java.util.regex.Matcher +import java.util.regex.Pattern + +private val repoGroup by RepoPattern.exclusiveGroup("tab.widget.enum") + +/** + * This class defines various widgets within the tab list, specifically focusing on the reading of the values. + * Each enum value corresponds to a distinct widget in the tab list, ensuring no overlap between them. + * The general info widget is broken up into multiple smaller ones. + * The class facilitates access to the lines associated with each widget and triggers events when a widget undergoes changes or becomes invisible. + */ +enum class TabWidget( + pattern0: String, +) { + PLAYER_LIST( + // language=RegExp + "(?:§.)*Players (?:§.)*\\(\\d+\\)" + ), + + /** This line holds no information, only here because every widget must be present */ + INFO( + // language=RegExp + "(?:§.)*Info" + ), + AREA( + // language=RegExp + "(?:§.)*(Area|Dungeon): (?:§.)*(?.*)" + ), + SERVER( + // language=RegExp + "Server: (?:§.)*(?.*)" + ), + GEMS( + // language=RegExp + "Gems: (?:§.)*(?.*)" + ), + FAIRY_SOULS( + // language=RegExp + "Fairy Souls: (?:§.)*(?\\d+)(?:§.)*\\/(?:§.)*(?\\d+)" + ), + PROFILE( + // language=RegExp + "(?:§.)*Profile: (?:§.)*(?\\S+).*" + ), + SB_LEVEL( + // language=RegExp + "SB Level(?:§.)*: (?:§.)*\\[(?:§.)*(?\\d+)(?:§.)*\\] (?:§.)*(?\\d+).*" + ), + BANK( + // language=RegExp + "Bank: (?:§.)*(?[^§]+)(?:(?:§.)* \\/ (?:§.)*(?.*))?" + ), + INTEREST( + // language=RegExp + "Interest: (?:§.)*(?