summaryrefslogtreecommitdiff
path: root/src/main/java/at/hannibal2/skyhanni/test/hotswap/HotswapSupportImpl.kt
blob: 6e497efcae3e8b277dae9bd78b4ba44894827c5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package at.hannibal2.skyhanni.test.hotswap

import at.hannibal2.skyhanni.SkyHanniMod
import at.hannibal2.skyhanni.utils.ChatUtils
import at.hannibal2.skyhanni.utils.DelayedRun
import at.hannibal2.skyhanni.utils.ReflectionUtils.makeAccessible
import at.hannibal2.skyhanni.utils.ReflectionUtils.removeFinal
import moe.nea.hotswapagentforge.forge.ClassDefinitionEvent
import moe.nea.hotswapagentforge.forge.HotswapEvent
import moe.nea.hotswapagentforge.forge.HotswapFinishedEvent
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 } ?: return
        val primaryConstructor = runCatching { instance.javaClass.getDeclaredConstructor() }.getOrNull()
        DelayedRun.onThread.execute {
            ChatUtils.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()
                ChatUtils.chat("Reconstructing $instance -> $newInstance!")
                val instanceField = runCatching { instance.javaClass.getDeclaredField("INSTANCE") }.getOrNull()
                    ?.takeIf { it.type == instance.javaClass }
                    ?.makeAccessible()
                    ?.removeFinal()
                if (instanceField != null) {
                    ChatUtils.chat("Re-injected static instance $newInstance!")
                    instanceField.set(null, newInstance)
                }
                SkyHanniMod.modules.add(newInstance)
                MinecraftForge.EVENT_BUS.register(newInstance)
            }
        }
    }

    @SubscribeEvent
    fun onHotswapDetected(event: HotswapFinishedEvent) {
        ChatUtils.chat("Hotswap finished!")
    }

    override fun isLoaded(): Boolean {
        return HotswapEvent.isReady()
    }
}