From 697e9e2dd6e5bb1d32e5b330623199099d9750bf Mon Sep 17 00:00:00 2001 From: CalMWolfs <94038482+CalMWolfs@users.noreply.github.com> Date: Sat, 26 Oct 2024 13:16:26 +1100 Subject: [PATCH] Backend: Add in event handler check to SkyHanni Events (#2755) --- .../skyhanni/api/event/EventHandler.kt | 26 ++++++++++++++++--- .../skyhanni/config/ConfigManager.kt | 3 ++- .../hannibal2/skyhanni/utils/ConfigUtils.kt | 3 ++- .../utils/repopatterns/RepoPatternManager.kt | 9 +++---- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt index 63d3e14cfb21..040ecc43c9a7 100644 --- a/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt +++ b/src/main/java/at/hannibal2/skyhanni/api/event/EventHandler.kt @@ -2,12 +2,15 @@ package at.hannibal2.skyhanni.api.event import at.hannibal2.skyhanni.SkyHanniMod import at.hannibal2.skyhanni.data.IslandType +import at.hannibal2.skyhanni.mixins.hooks.getValue +import at.hannibal2.skyhanni.mixins.hooks.setValue import at.hannibal2.skyhanni.test.command.ErrorManager import at.hannibal2.skyhanni.utils.ChatUtils import at.hannibal2.skyhanni.utils.LorenzUtils import at.hannibal2.skyhanni.utils.LorenzUtils.inAnyIsland import at.hannibal2.skyhanni.utils.StringUtils import at.hannibal2.skyhanni.utils.chat.Text +import at.hannibal2.skyhanni.utils.system.PlatformUtils class EventHandler private constructor( val name: String, @@ -21,9 +24,24 @@ class EventHandler private constructor( constructor(event: Class, listeners: List) : this( (event.name.split(".").lastOrNull() ?: event.name).replace("$", "."), listeners.sortedBy { it.options.priority }.toList(), - listeners.any { it.options.receiveCancelled } + listeners.any { it.options.receiveCancelled }, ) + companion object { + private var eventHandlerDepth by object : ThreadLocal() { + override fun initialValue(): Int { + return 0 + } + } + + /** + * Returns true if the current thread is in an event handler. This is because the event handler catches exceptions which means + * that we are free to throw exceptions in the event handler without crashing the game. + * We also return true if we are in a dev environment to alert the developer of any errors effectively. + */ + val isInEventHandler get() = eventHandlerDepth > 0 || PlatformUtils.isDevEnvironment + } + fun post(event: T, onError: ((Throwable) -> Unit)? = null): Boolean { invokeCount++ if (this.listeners.isEmpty()) return false @@ -32,6 +50,7 @@ class EventHandler private constructor( var errors = 0 + eventHandlerDepth++ for (listener in listeners) { if (!shouldInvoke(event, listener)) continue try { @@ -48,13 +67,14 @@ class EventHandler private constructor( } if (event.isCancelled && !canReceiveCancelled) break } + eventHandlerDepth-- if (errors > 3) { val hiddenErrors = errors - 3 ChatUtils.chat( Text.text( - "§c[SkyHanni/${SkyHanniMod.version}] $hiddenErrors more errors in $name are hidden!" - ) + "§c[SkyHanni/${SkyHanniMod.version}] $hiddenErrors more errors in $name are hidden!", + ), ) } return event.isCancelled diff --git a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt index b82d4d8f9909..a534eac89193 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/config/ConfigManager.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.config import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.EventHandler import at.hannibal2.skyhanni.config.core.config.Position import at.hannibal2.skyhanni.config.core.config.PositionList import at.hannibal2.skyhanni.data.jsonobjects.local.FriendsJson @@ -96,7 +97,7 @@ class ConfigManager { try { findPositionLinks(features, mutableSetOf()) } catch (e: Exception) { - if (LorenzEvent.isInGuardedEventHandler) throw e + if (LorenzEvent.isInGuardedEventHandler || EventHandler.isInEventHandler) throw e } } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ConfigUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/ConfigUtils.kt index 94d981d8ef61..bcf8e45b25d4 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/ConfigUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/ConfigUtils.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.utils import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.EventHandler import at.hannibal2.skyhanni.config.ConfigGuiManager import at.hannibal2.skyhanni.config.HasLegacyId import at.hannibal2.skyhanni.events.LorenzEvent @@ -86,7 +87,7 @@ object ConfigUtils { if (tryJumpToEditor(ConfigGuiManager.getEditorInstance())) return // TODO create utils function "crashIfInDevEnv" - if (LorenzEvent.isInGuardedEventHandler) { + if (LorenzEvent.isInGuardedEventHandler || EventHandler.isInEventHandler) { throw Error("can not jump to editor $name") } ErrorManager.logErrorStateWithData( diff --git a/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt b/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt index ad10ba19529d..8bef5061f82d 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/repopatterns/RepoPatternManager.kt @@ -1,6 +1,7 @@ package at.hannibal2.skyhanni.utils.repopatterns import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.api.event.EventHandler import at.hannibal2.skyhanni.api.event.HandleEvent import at.hannibal2.skyhanni.config.ConfigManager import at.hannibal2.skyhanni.config.features.dev.RepoPatternConfig @@ -60,11 +61,6 @@ object RepoPatternManager { private var usedKeys: NavigableMap> = TreeMap() private var wasPreInitialized = false - private val isInDevEnv = try { - Launch.blackboard["fml.deobfuscatedEnvironment"] as Boolean - } catch (_: Exception) { - true - } private val insideTest = Launch.blackboard == null @@ -88,8 +84,9 @@ object RepoPatternManager { * Crash if in a development environment, or if inside a guarded event handler. */ fun crash(reason: String) { - if (isInDevEnv || LorenzEvent.isInGuardedEventHandler) + if (LorenzEvent.isInGuardedEventHandler || EventHandler.isInEventHandler) { throw RuntimeException(reason) + } } /**