From 438c604d52a88dd4b80aa711d3507dfc397ee1f1 Mon Sep 17 00:00:00 2001 From: gegy1000 Date: Mon, 21 May 2018 15:36:15 +0200 Subject: [PATCH] Object EventBusSubscriber registration (#34) * Object EventBusSubscriber registration * Register from construction and handle companion objects * Rename construction event listener * Syntax changes * Add test mod --- .../net/shadowfacts/forgelin/Forgelin.kt | 12 ++- .../ForgelinAutomaticEventSubscriber.kt | 78 +++++++++++++++++++ .../forgelin/AutomaticKtSubscriberTest.kt | 19 +++++ 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt create mode 100644 src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt diff --git a/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt b/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt index 3b1a69d..19d8849 100644 --- a/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt +++ b/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt @@ -1,6 +1,10 @@ package net.shadowfacts.forgelin +import net.minecraftforge.fml.common.FMLCommonHandler +import net.minecraftforge.fml.common.Loader import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.Mod.EventHandler +import net.minecraftforge.fml.common.event.FMLConstructionEvent /** * @author shadowfacts @@ -12,4 +16,10 @@ object Forgelin { const val NAME = "Forgelin" const val VERSION = "@VERSION@" -} \ No newline at end of file + @EventHandler + fun onConstruction(event: FMLConstructionEvent) { + Loader.instance().modList.forEach { + ForgelinAutomaticEventSubscriber.subscribeAutomatic(it, event.asmHarvestedData, FMLCommonHandler.instance().side) + } + } +} diff --git a/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt b/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt new file mode 100644 index 0000000..a450730 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt @@ -0,0 +1,78 @@ +package net.shadowfacts.forgelin + +import net.minecraftforge.common.MinecraftForge +import net.minecraftforge.fml.common.Loader +import net.minecraftforge.fml.common.LoaderException +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.ModContainer +import net.minecraftforge.fml.common.discovery.ASMDataTable +import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData +import net.minecraftforge.fml.common.discovery.asm.ModAnnotation.EnumHolder +import net.minecraftforge.fml.relauncher.Side +import org.apache.logging.log4j.LogManager +import java.util.EnumSet +import kotlin.reflect.full.companionObjectInstance + +object ForgelinAutomaticEventSubscriber { + private val DEFAULT_SUBSCRIPTION_SIDES = EnumSet.allOf(Side::class.java) + private val LOGGER = LogManager.getLogger(ForgelinAutomaticEventSubscriber::class.java) + + fun subscribeAutomatic(mod: ModContainer, asm: ASMDataTable, currentSide: Side) { + LOGGER.debug("Attempting to register Kotlin @EventBusSubscriber objects for {}", mod.modId) + + val modAnnotations = asm.getAnnotationsFor(mod) ?: return + + val containedMods = modAnnotations.get(Mod::class.java.name) + val subscribers = modAnnotations.get(Mod.EventBusSubscriber::class.java.name) + .filter { parseTargetSides(it).contains(currentSide) } + + val loader = Loader.instance().modClassLoader + + for (subscriber in subscribers) { + try { + val ownerModId = parseModId(containedMods, subscriber) + if (ownerModId.isNullOrEmpty()) { + LOGGER.warn("Could not determine owning mod for @EventBusSubscriber on {} for mod {}", subscriber.className, mod.modId) + continue + } + + if (mod.modId != ownerModId) { + LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it is not for mod {}", subscriber.className, mod.modId) + continue + } + + LOGGER.debug("Registering @EventBusSubscriber object for {} for mod {}", subscriber.className, mod.modId) + + val subscriberClass = Class.forName(subscriber.className, false, loader)?.kotlin ?: continue + val subscriberInstance = subscriberClass.objectInstance ?: subscriberClass.companionObjectInstance ?: continue + + MinecraftForge.EVENT_BUS.register(subscriberInstance) + LOGGER.debug("Registered @EventBusSubscriber object {}", subscriber.className) + } catch (e: Throwable) { + LOGGER.error("An error occurred trying to load an @EventBusSubscriber object {} for modid {}", mod.modId, e) + throw LoaderException(e) + } + } + } + + private fun parseModId(containedMods: MutableSet, subscriber: ASMData): String? { + val parsedModId: String? = subscriber.annotationInfo["modid"] as? String + if (parsedModId.isNullOrEmpty()) { + return parsedModId + } + + return ASMDataTable.getOwnerModID(containedMods, subscriber) + } + + private fun parseTargetSides(subscriber: ASMData): EnumSet { + val parsedSides: List? = subscriber.annotationInfo["value"] as? List + if (parsedSides != null) { + val targetSides = EnumSet.noneOf(Side::class.java) + for (parsed in parsedSides) { + targetSides.add(Side.valueOf(parsed.value)) + } + return targetSides + } + return DEFAULT_SUBSCRIPTION_SIDES + } +} diff --git a/src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt b/src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt new file mode 100644 index 0000000..6b7c308 --- /dev/null +++ b/src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt @@ -0,0 +1,19 @@ +package net.shadowfacts.forgelin + +import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock +import net.minecraftforge.fml.common.Mod +import net.minecraftforge.fml.common.Mod.EventBusSubscriber +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent + +@Mod(modid = AutomaticKtSubscriberTest.MODID, modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter") +object AutomaticKtSubscriberTest { + const val MODID = "ktsubtest" + + @EventBusSubscriber(modid = AutomaticKtSubscriberTest.MODID) + object EventSubscriber { + @SubscribeEvent + fun onRightClickBlock(event: RightClickBlock) { + println("Automatic KT subscriber: Right click ${event.pos}") + } + } +}