From df1bff9338410828ec566f28483dee0938463165 Mon Sep 17 00:00:00 2001 From: hannibal2 <24389977+hannibal002@users.noreply.github.com> Date: Sun, 6 Oct 2024 10:54:42 +0200 Subject: [PATCH] Improvement: Working on scoreboard errors again (#2672) Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com> --- .../skyhanni/features/combat/SpidersDenAPI.kt | 5 +- .../gui/customscoreboard/CustomScoreboard.kt | 18 ++--- .../customscoreboard/CustomScoreboardUtils.kt | 11 +-- .../customscoreboard/ScoreboardElements.kt | 69 +++++++------------ .../gui/customscoreboard/ScoreboardEvent.kt | 3 +- .../customscoreboard/UnknownLinesHandler.kt | 60 +++++++++++++--- 6 files changed, 88 insertions(+), 78 deletions(-) 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 7986c55e9d3a..af1dd8430186 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/combat/SpidersDenAPI.kt @@ -1,12 +1,11 @@ package at.hannibal2.skyhanni.features.combat -import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard +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 @SkyHanniModule object SpidersDenAPI { - private fun getSbLines(): List = CustomScoreboard.activeLines - fun isAtTopOfNest(): Boolean = getSbLines().any { ScoreboardPattern.broodmotherPattern.matches(it) } + fun isAtTopOfNest(): Boolean = ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.broodmotherPattern.matches(it) } } 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 c9fb4b15f821..8a1d7b50de45 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 @@ -50,11 +50,6 @@ object CustomScoreboard { private var cache = emptyList() private const val GUI_NAME = "Custom Scoreboard" - // Cached scoreboard data, only update after no change for 300ms - var activeLines = emptyList() - - // Most recent scoreboard state, not in use until cached - private var mostRecentLines = emptyList() private var lastScoreboardUpdate = SimpleTimeMark.farFuture() @SubscribeEvent @@ -115,14 +110,13 @@ object CustomScoreboard { // We want to update the scoreboard as soon as we have new data, not 5 ticks delayed var dirty = false - if (lastScoreboardUpdate.passedSince() > 300.milliseconds) { - activeLines = mostRecentLines + if (lastScoreboardUpdate.passedSince() > 250.milliseconds) { lastScoreboardUpdate = SimpleTimeMark.farFuture() dirty = true } // Creating the lines - if (event.isMod(5) || dirty) { + if (dirty) { display = createLines().removeEmptyLinesFromEdges() if (TabListData.fullyLoaded) { cache = display.toList() @@ -135,7 +129,6 @@ object CustomScoreboard { @SubscribeEvent fun onScoreboardChange(event: ScoreboardUpdateEvent) { - mostRecentLines = event.scoreboard lastScoreboardUpdate = SimpleTimeMark.now() } @@ -160,12 +153,12 @@ object CustomScoreboard { private fun addAllNonSkyBlockLines() = buildList { addAll(ScoreboardElement.TITLE.getVisiblePair()) - addAll(activeLines.map { it to HorizontalAlignment.LEFT }) + addAll(ScoreboardData.sidebarLinesFormatted.map { it to HorizontalAlignment.LEFT }) } private fun addDefaultSkyBlockLines() = buildList { add(ScoreboardData.objectiveTitle to displayConfig.titleAndFooter.alignTitleAndFooter) - addAll(activeLines.map { it to HorizontalAlignment.LEFT }) + addAll(ScoreboardData.sidebarLinesFormatted.map { it to HorizontalAlignment.LEFT }) } private fun addCustomSkyBlockLines() = buildList { @@ -175,7 +168,8 @@ object CustomScoreboard { if ( informationFilteringConfig.hideConsecutiveEmptyLines && - lines.first().first == "" && lastOrNull()?.first?.isEmpty() == true + lines.first().first == "" && + lastOrNull()?.first?.isEmpty() == true ) { continue } 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 4cfc403c421f..99fdc4f3fcf6 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,6 +3,7 @@ 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.ScoreboardData import at.hannibal2.skyhanni.features.bingo.BingoAPI import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboard.displayConfig import at.hannibal2.skyhanni.utils.NumberUtil.addSeparators @@ -27,7 +28,7 @@ object CustomScoreboardUtils { fun getProfileTypeSymbol() = when { HypixelData.ironman -> "§7♲ " HypixelData.stranded -> "§a☀ " - HypixelData.bingo -> CustomScoreboard.activeLines.firstNotNullOfOrNull { + HypixelData.bingo -> ScoreboardData.sidebarLinesFormatted.firstNotNullOfOrNull { BingoAPI.getIconFromScoreboard(it)?.plus(" ") } ?: "§e❤ " @@ -43,7 +44,7 @@ object CustomScoreboardUtils { internal fun String.formatNum() = this.formatDouble().formatNum() - internal fun getMotes() = getGroupFromPattern(CustomScoreboard.activeLines, ScoreboardPattern.motesPattern, "motes") + internal fun getMotes() = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.motesPattern, "motes") internal fun getBank() = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.bankPattern, "bank") internal fun getBits() = BitsAPI.bits.coerceAtLeast(0).formatNum() @@ -57,15 +58,15 @@ object CustomScoreboardUtils { } internal fun getCopper() = - getGroupFromPattern(CustomScoreboard.activeLines, ScoreboardPattern.copperPattern, "copper") + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.copperPattern, "copper") internal fun getGems() = getGroupFromPattern(TabListData.getTabList(), ScoreboardPattern.gemsPattern, "gems") internal fun getHeat() = - getGroupFromPattern(CustomScoreboard.activeLines, ScoreboardPattern.heatPattern, "heat") + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.heatPattern, "heat") internal fun getNorthStars() = - getGroupFromPattern(CustomScoreboard.activeLines, ScoreboardPattern.northstarsPattern, "northstars") + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.northstarsPattern, "northstars") class UndetectedScoreboardLines(message: String) : Exception(message) 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 index 0289a3c81862..769184077b09 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardElements.kt @@ -39,8 +39,6 @@ import at.hannibal2.skyhanni.features.gui.customscoreboard.CustomScoreboardUtils 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.test.command.ErrorManager -import at.hannibal2.skyhanni.utils.CollectionUtils.editCopy import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.inAdvancedMiningIsland @@ -50,41 +48,25 @@ 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.TimeLimitedSet import at.hannibal2.skyhanni.utils.TimeUtils.format import at.hannibal2.skyhanni.utils.TimeUtils.formatted import kotlin.time.Duration.Companion.seconds -internal var confirmedUnknownLines = listOf() -internal var unconfirmedUnknownLines = listOf() -internal var unknownLinesSet = TimeLimitedSet(1.seconds) { onRemoval(it) } - -private fun onRemoval(line: String) { - if (!LorenzUtils.inSkyBlock) return - if (!unconfirmedUnknownLines.contains(line)) return - if (line !in unconfirmedUnknownLines) return - unconfirmedUnknownLines = unconfirmedUnknownLines.filterNot { it == line } - confirmedUnknownLines = confirmedUnknownLines.editCopy { add(line) } - if (!config.unknownLinesWarning) return - val pluralize = pluralize(confirmedUnknownLines.size, "unknown line", withNumber = true) - val message = "CustomScoreboard detected $pluralize" - ErrorManager.logErrorWithData( - CustomScoreboardUtils.UndetectedScoreboardLines(message), - message, - "Unknown Lines" to confirmedUnknownLines, - "Island" to LorenzUtils.skyBlockIsland, - "Area" to HypixelData.skyBlockArea, - "Full Scoreboard" to CustomScoreboard.activeLines, - noStackTrace = true, - betaOnly = true, - ) -} +internal var allUnknownLines = listOf() +internal var lastRecentAlarmWarning = SimpleTimeMark.farPast() + +internal fun recentUnknownLines() = allUnknownLines.filter { it.lastFound.passedSince() < 3.seconds } -internal var amountOfUnknownLines = 0 +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, @@ -389,7 +371,7 @@ private fun getPurseDisplayPair(): List { var purse = PurseAPI.currentPurse.formatNum() if (!displayConfig.hideCoinsDifference) { - val earned = getGroupFromPattern(CustomScoreboard.activeLines, PurseAPI.coinsPattern, "earned") + val earned = getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, PurseAPI.coinsPattern, "earned") if (earned != null) purse += " §7(§e+$earned§7)§6" } @@ -492,7 +474,7 @@ private fun getHeatDisplayPair(): List { } private fun getHeatShowWhen() = inAnyIsland(IslandType.CRYSTAL_HOLLOWS) && - CustomScoreboard.activeLines.any { ScoreboardPattern.heatPattern.matches(it) } + ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.heatPattern.matches(it) } private fun getColdDisplayPair(): List { val cold = -MiningAPI.cold @@ -507,7 +489,7 @@ private fun getColdDisplayPair(): List { } private fun getColdShowWhen() = inAnyIsland(IslandType.DWARVEN_MINES, IslandType.MINESHAFT) && - CustomScoreboard.activeLines.any { ScoreboardPattern.coldPattern.matches(it) } + ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.coldPattern.matches(it) } private fun getNorthStarsDisplayPair(): List { val northStars = getNorthStars()?.formatNum() ?: "0" @@ -550,7 +532,7 @@ private fun getIslandDisplayPair() = private fun getLocationDisplayPair() = buildList { HypixelData.skyBlockAreaWithSymbol?.let { add(it to HorizontalAlignment.LEFT) } - CustomScoreboard.activeLines.firstOrNull { ScoreboardPattern.plotPattern.matches(it) } + ScoreboardData.sidebarLinesFormatted.firstOrNull { ScoreboardPattern.plotPattern.matches(it) } ?.let { add(it to HorizontalAlignment.LEFT) } } @@ -568,12 +550,12 @@ fun getPlayerAmountDisplayPair() = buildList { private fun getVisitDisplayPair() = listOf( - CustomScoreboard.activeLines.first { ScoreboardPattern.visitingPattern.matches(it) } to + ScoreboardData.sidebarLinesFormatted.first { ScoreboardPattern.visitingPattern.matches(it) } to HorizontalAlignment.LEFT, ) private fun getVisitShowWhen() = - CustomScoreboard.activeLines.any { ScoreboardPattern.visitingPattern.matches(it) } + ScoreboardData.sidebarLinesFormatted.any { ScoreboardPattern.visitingPattern.matches(it) } private fun getDateDisplayPair() = listOf( @@ -582,7 +564,7 @@ private fun getDateDisplayPair() = private fun getTimeDisplayPair(): List { val symbol = - getGroupFromPattern(CustomScoreboard.activeLines, ScoreboardPattern.timePattern, "symbol") ?: "" + getGroupFromPattern(ScoreboardData.sidebarLinesFormatted, ScoreboardPattern.timePattern, "symbol") ?: "" return listOf( "§7" + SkyBlockTime.now() .formatted( @@ -671,7 +653,7 @@ private fun getCookieShowWhen(): Boolean { } private fun getObjectiveDisplayPair() = buildList { - val formattedLines = CustomScoreboard.activeLines + val formattedLines = ScoreboardData.sidebarLinesFormatted val objective = formattedLines.firstOrNull { ScoreboardPattern.objectivePattern.matches(it) } if (objective != null) { add(objective to HorizontalAlignment.LEFT) @@ -690,7 +672,7 @@ private fun getObjectiveDisplayPair() = buildList { } private fun getObjectiveShowWhen(): Boolean = - ScoreboardPattern.objectivePattern.anyMatches(CustomScoreboard.activeLines) + ScoreboardPattern.objectivePattern.anyMatches(ScoreboardData.sidebarLinesFormatted) private fun getSlayerDisplayPair(): List = buildList { add((if (SlayerAPI.hasActiveSlayerQuest()) "Slayer Quest" else "") to HorizontalAlignment.LEFT) @@ -860,15 +842,10 @@ private fun getFooterDisplayPair(): List = listOf( ).flatten() private fun getExtraDisplayPair(): List { - if (unconfirmedUnknownLines.isEmpty()) return listOf("" to HorizontalAlignment.LEFT) - amountOfUnknownLines = unconfirmedUnknownLines.size + val lines = recentUnknownLines() + if (lines.isEmpty()) return listOf("" to HorizontalAlignment.LEFT) - return listOf("§cUndetected Lines:" to HorizontalAlignment.LEFT) + unconfirmedUnknownLines.map { it to HorizontalAlignment.LEFT } + return listOf("§cUndetected Lines:" to HorizontalAlignment.LEFT) + lines.map { it.line to HorizontalAlignment.LEFT } } -private fun getExtraShowWhen(): Boolean { - if (unconfirmedUnknownLines.isEmpty()) { - amountOfUnknownLines = 0 - } - return unconfirmedUnknownLines.isNotEmpty() -} +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 index 6531d5158d75..3d8251dfbb63 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/ScoreboardEvent.kt @@ -2,6 +2,7 @@ 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 @@ -29,7 +30,7 @@ import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern as * because they are visible for a maximum of like 1 minute every 5 days and ~12 hours. */ -private fun getSbLines(): List = CustomScoreboard.activeLines +private fun getSbLines(): List = ScoreboardData.sidebarLinesFormatted enum class ScoreboardEvent( private val displayLine: () -> List, diff --git a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/UnknownLinesHandler.kt b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/UnknownLinesHandler.kt index 38612f29703b..0dff1f4933dd 100644 --- a/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/UnknownLinesHandler.kt +++ b/src/main/java/at/hannibal2/skyhanni/features/gui/customscoreboard/UnknownLinesHandler.kt @@ -1,15 +1,22 @@ package at.hannibal2.skyhanni.features.gui.customscoreboard import at.hannibal2.skyhanni.data.BitsAPI +import at.hannibal2.skyhanni.data.HypixelData import at.hannibal2.skyhanni.data.PurseAPI +import at.hannibal2.skyhanni.data.ScoreboardData import at.hannibal2.skyhanni.features.misc.ServerRestartTitle import at.hannibal2.skyhanni.features.rift.area.stillgorechateau.RiftBloodEffigies +import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils +import at.hannibal2.skyhanni.utils.CollectionUtils.editCopy import at.hannibal2.skyhanni.utils.CollectionUtils.nextAfter import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.RegexUtils.matches +import at.hannibal2.skyhanni.utils.SimpleTimeMark import at.hannibal2.skyhanni.utils.StringUtils.removeResets import java.util.regex.Pattern +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds import at.hannibal2.skyhanni.features.gui.customscoreboard.ScoreboardPattern as SbPattern object UnknownLinesHandler { @@ -133,7 +140,7 @@ object UnknownLinesHandler { private var remoteOnlyPatternsAdded = false fun handleUnknownLines() { - val sidebarLines = CustomScoreboard.activeLines + val sidebarLines = ScoreboardData.sidebarLinesFormatted var unknownLines = sidebarLines.map { it.removeResets() }.filter { it.isNotBlank() }.filter { it.trim().length > 3 } @@ -205,19 +212,50 @@ object UnknownLinesHandler { /* * Handle broken scoreboard lines */ - confirmedUnknownLines = confirmedUnknownLines.filter { it in unknownLines } + if (unknownLines.isEmpty()) return - unknownLines = unknownLines.filter { it !in confirmedUnknownLines } - - unconfirmedUnknownLines = unknownLines - - unknownLines = unknownLines.filter { it !in unknownLinesSet } + for (line in unknownLines) { + val unknownLine = allUnknownLines.firstOrNull { it.line == line } + if (unknownLine == null) { + if (LorenzUtils.inSkyBlock) { + ChatUtils.debug("Unknown Scoreboard line: '$line'") + } + allUnknownLines = allUnknownLines.editCopy { + add(UnknownLine(line)) + } + } else { + unknownLine.lastFound = SimpleTimeMark.now() + val firstFoundSince = unknownLine.firstFound.passedSince() + val lastWarnedSince = unknownLine.lastWarned.passedSince() + if (firstFoundSince > 3.seconds && lastWarnedSince > 30.minutes) { + unknownLine.lastWarned = SimpleTimeMark.now() + warn(line, "same line active for 3 seconds") + continue + } + } + } - unknownLines.forEach { - if (LorenzUtils.inSkyBlock) { - ChatUtils.debug("Unknown Scoreboard line: '$it'") + if (lastRecentAlarmWarning.passedSince() > 30.minutes) { + val recentAlarms = allUnknownLines.filter { it.firstFound.passedSince() < 6.seconds } + if (recentAlarms.size >= 5) { + warn(recentAlarms.first().line, "5 different lines in 5 seconds") } - unknownLinesSet.add(it) } } + + private fun warn(line: String, reason: String) { + ErrorManager.logErrorWithData( + // line inclucded in chat message to not cache a previous message + CustomScoreboardUtils.UndetectedScoreboardLines(line), + "CustomScoreboard detected a unknown line: '$line'", + "Unknown Line" to line, + "reason" to reason, + "Island" to LorenzUtils.skyBlockIsland, + "Area" to HypixelData.skyBlockArea, + "Full Scoreboard" to ScoreboardData.sidebarLinesFormatted, + noStackTrace = true, + betaOnly = true, + ) + + } }