diff options
author | Linnea Gräf <nea@nea.moe> | 2024-01-18 21:39:21 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-18 21:39:21 +0100 |
commit | b8adb961f50d17c02dbccbbb00376a2f728c819b (patch) | |
tree | 5cc607aa60c46f2556d9c7552f20336e362aec91 /src/main/java | |
parent | 1bf29e31e35c4eb1a40fe0a7dfd111955ef48322 (diff) | |
download | skyhanni-b8adb961f50d17c02dbccbbb00376a2f728c819b.tar.gz skyhanni-b8adb961f50d17c02dbccbbb00376a2f728c819b.tar.bz2 skyhanni-b8adb961f50d17c02dbccbbb00376a2f728c819b.zip |
Add hotswap agent support (#910)
Added hotswap detection and reloading all listeners on hotswap. #910
Diffstat (limited to 'src/main/java')
4 files changed, 88 insertions, 0 deletions
diff --git a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt index f7c257706..addfbf1f0 100644 --- a/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt +++ b/src/main/java/at/hannibal2/skyhanni/SkyHanniMod.kt @@ -341,6 +341,7 @@ import at.hannibal2.skyhanni.test.TestExportTools import at.hannibal2.skyhanni.test.TestShowSlotNumber import at.hannibal2.skyhanni.test.WorldEdit import at.hannibal2.skyhanni.test.command.CopyNearbyParticlesCommand +import at.hannibal2.skyhanni.test.hotswap.HotswapSupport import at.hannibal2.skyhanni.utils.EntityOutlineRenderer import at.hannibal2.skyhanni.utils.KeyboardManager import at.hannibal2.skyhanni.utils.LorenzUtils @@ -378,6 +379,8 @@ class SkyHanniMod { fun preInit(event: FMLPreInitializationEvent?) { checkIfNeuIsLoaded() + HotswapSupport.load() + // data loadModule(this) loadModule(ChatManager) diff --git a/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupport.kt b/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupport.kt new file mode 100644 index 000000000..87acab62d --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupport.kt @@ -0,0 +1,22 @@ +package at.hannibal2.skyhanni.test.hotswap + +import java.util.function.Supplier + +object HotswapSupport { + private val isForgeSidePresent = + runCatching { Class.forName("moe.nea.hotswapagentforge.forge.HotswapEvent") }.isSuccess + private val obj = if (isForgeSidePresent) { + Supplier<HotswapSupportHandle?> { HotswapSupportImpl() } + } else { + Supplier<HotswapSupportHandle?> { null } + }.get() + + fun isLoaded(): Boolean { + return obj?.isLoaded() ?: false + } + + fun load() { + obj?.load() + } +} + diff --git a/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportHandle.kt b/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportHandle.kt new file mode 100644 index 000000000..c006753a0 --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportHandle.kt @@ -0,0 +1,6 @@ +package at.hannibal2.skyhanni.test.hotswap + +interface HotswapSupportHandle { + fun load() + fun isLoaded(): Boolean +} diff --git a/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportImpl.kt b/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportImpl.kt new file mode 100644 index 000000000..df74eedbb --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportImpl.kt @@ -0,0 +1,57 @@ +package at.hannibal2.skyhanni.test.hotswap + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.utils.LorenzUtils +import at.hannibal2.skyhanni.utils.LorenzUtils.makeAccessible +import at.hannibal2.skyhanni.utils.LorenzUtils.removeFinal +import moe.nea.hotswapagentforge.forge.ClassDefinitionEvent +import moe.nea.hotswapagentforge.forge.HotswapEvent +import moe.nea.hotswapagentforge.forge.HotswapFinishedEvent +import net.minecraft.client.Minecraft +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +class HotswapSupportImpl : HotswapSupportHandle { + override fun load() { + MinecraftForge.EVENT_BUS.register(this) + println("Hotswap Client in Skyhanni loaded") + } + + @SubscribeEvent + fun onHotswapClass(event: ClassDefinitionEvent.Redefinition) { + val instance = SkyHanniMod.modules.find { it.javaClass.name == event.fullyQualifiedName } + if (instance == null) return + val primaryConstructor = runCatching { instance.javaClass.getDeclaredConstructor() }.getOrNull() + Minecraft.getMinecraft().addScheduledTask(Runnable { + LorenzUtils.chat("Refreshing event subscriptions for module $instance!") + MinecraftForge.EVENT_BUS.unregister(instance) + if (primaryConstructor == null) { + MinecraftForge.EVENT_BUS.register(instance) + } else { + SkyHanniMod.modules.remove(instance) + primaryConstructor.isAccessible = true + val newInstance = primaryConstructor.newInstance() + LorenzUtils.chat("Reconstructing $instance -> $newInstance!") + val instanceField = runCatching { instance.javaClass.getDeclaredField("INSTANCE") }.getOrNull() + ?.takeIf { it.type == instance.javaClass } + ?.makeAccessible() + ?.removeFinal() + if (instanceField != null) { + LorenzUtils.chat("Reinjected static instance $newInstance!") + instanceField.set(null, newInstance) + } + SkyHanniMod.modules.add(newInstance) + MinecraftForge.EVENT_BUS.register(newInstance) + } + }) + } + + @SubscribeEvent + fun onHotswapDetected(event: HotswapFinishedEvent) { + LorenzUtils.chat("Hotswap finished!") + } + + override fun isLoaded(): Boolean { + return HotswapEvent.isReady() + } +} |