Automatic event subscriber fixed

This commit is contained in:
autaut03 2019-02-12 22:15:08 +02:00
parent b5b0402d51
commit 1ab90f9cc3
3 changed files with 51 additions and 115 deletions

View File

@ -97,8 +97,7 @@ class FMLKotlinModContainer(
}
log.debug(LOADING, "Injecting Automatic event subscribers for {}", getModId())
AutomaticEventSubscriber.inject(this, this.scanResults, this.modClass.classLoader)
//ForgelinAutomaticEventSubscriber.subscribeAutomatic(FMLKotlinModLoadingContext.get().activeContainer, event.asmData, FMLCommonHandler.instance().side)
ForgelinAutomaticEventSubscriber.inject(this, this.scanResults, this.modClass.classLoader)
log.debug(LOADING, "Completed Automatic event subscribers for {}", getModId())
}

View File

@ -1,112 +1,55 @@
package net.shadowfacts.forgelin
import net.minecraftforge.common.MinecraftForge
/*import net.minecraftforge.fml.common.Loader
import net.minecraftforge.fml.common.LoaderException
import net.minecraftforge.api.distmarker.Dist
import net.minecraftforge.fml.Logging
import net.minecraftforge.fml.ModContainer
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.common.eventhandler.SubscribeEvent
import net.minecraftforge.fml.relauncher.Side*/
import net.minecraftforge.fml.loading.FMLEnvironment
import net.minecraftforge.fml.loading.moddiscovery.ModAnnotation
import net.minecraftforge.forgespi.language.ModFileScanData
import org.apache.logging.log4j.LogManager
import java.lang.reflect.Modifier
import java.util.EnumSet
import kotlin.reflect.full.companionObjectInstance
import org.objectweb.asm.Type
import java.util.*
import java.util.stream.Collectors
object ForgelinAutomaticEventSubscriber {
/*private val DEFAULT_SUBSCRIPTION_SIDES = EnumSet.allOf(Side::class.java)
private val LOGGER = LogManager.getLogger(ForgelinAutomaticEventSubscriber::class.java)
private val AUTO_SUBSCRIBER = Type.getType(Mod.EventBusSubscriber::class.java)
private val unregistered = mutableSetOf<Class<*>>()
private val registered = mutableSetOf<Any>()
private val logger = LogManager.getLogger()
fun subscribeAutomatic(mod: ModContainer, asm: ASMDataTable, currentSide: Side) {
val modAnnotations = asm.getAnnotationsFor(mod) ?: return
fun inject(mod: ModContainer, scanData: ModFileScanData?, loader: ClassLoader) {
if(scanData == null) {
return
}
val containedMods = modAnnotations.get(Mod::class.java.name)
val subscribers = modAnnotations.get(Mod.EventBusSubscriber::class.java.name)
.filter { parseTargetSides(it).contains(currentSide) }
logger.debug(Logging.LOADING, "Attempting to inject @EventBusSubscriber classes into the eventbus for {}", mod.modId)
val targets = scanData.annotations.stream()
.filter { annotationData -> annotationData.annotationType == AUTO_SUBSCRIBER }
.filter { annotationData -> shouldBeRegistered(mod.modId, annotationData) }
.collect(Collectors.toList())
val loader = Loader.instance().modClassLoader
targets.forEach { ad ->
val busTargetHolder = ad.annotationData.getOrDefault("bus", ModAnnotation.EnumHolder(null, "FORGE")) as ModAnnotation.EnumHolder
val busTarget = Mod.EventBusSubscriber.Bus.valueOf(busTargetHolder.value)
try {
logger.debug(Logging.LOADING, "Auto-subscribing {} to {}", ad.classType.className, busTarget)
val className = Class.forName(ad.classType.className, true, loader)
busTarget.bus().get().register(className.kotlin.objectInstance ?: className)
} catch (e: ClassNotFoundException) {
logger.fatal(Logging.LOADING, "Failed to load mod class {} for @EventBusSubscriber annotation", ad.classType, e)
throw e
}
}
}
for (containedMod in containedMods) {
val containedModId = containedMod.annotationInfo["modid"] as String
if (containedMod.annotationInfo["modLanguageAdapter"] != FMLKotlinModLanguageProvider::class.qualifiedName) {
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it does not use FMLKotlinModLanguageProvider", containedModId)
continue
}
private fun shouldBeRegistered(modId: String, ad: ModFileScanData.AnnotationData): Boolean {
val sidesValue = ad.annotationData.getOrDefault("value", Arrays.asList(ModAnnotation.EnumHolder(null, "CLIENT"), ModAnnotation.EnumHolder(null, "DEDICATED_SERVER"))) as List<ModAnnotation.EnumHolder>
val sides = sidesValue.stream()
.map { eh -> Dist.valueOf(eh.value) }
.collect(Collectors.toCollection { EnumSet.noneOf(Dist::class.java) }) as EnumSet<Dist>
val annotationModId = ad.annotationData.getOrDefault("modid", modId) as String
LOGGER.debug("Attempting to register Kotlin @EventBusSubscriber objects for {}", containedModId)
for (subscriber in subscribers) {
try {
val ownerModId = parseModId(containedMods, subscriber)
if (ownerModId.isNullOrEmpty()) {
LOGGER.debug("Could not determine owning mod for @EventBusSubscriber on {} for mod {}", subscriber.className, mod.modId)
continue
}
if (containedModId != ownerModId) {
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it is not for mod {}", subscriber.className, containedModId)
continue
}
val subscriberClass = Class.forName(subscriber.className, false, loader) ?: continue
val kotlinClass = subscriberClass.kotlin
val objectInstance = kotlinClass.objectInstance ?: kotlinClass.companionObjectInstance ?: continue
if (!hasStaticEventHandlers(subscriberClass) && subscriberClass !in unregistered) {
MinecraftForge.EVENT_BUS.unregister(subscriberClass)
unregistered += subscriberClass
LOGGER.debug("Unregistered static @EventBusSubscriber class {}", subscriber.className)
}
if (hasObjectEventHandlers(objectInstance) && objectInstance !in registered) {
MinecraftForge.EVENT_BUS.register(objectInstance)
registered += objectInstance
LOGGER.debug("Registered @EventBusSubscriber object instance {}", 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 hasObjectEventHandlers(objectInstance: Any): Boolean {
return objectInstance.javaClass.methods.any {
!Modifier.isStatic(it.modifiers) && it.isAnnotationPresent(SubscribeEvent::class.java)
}
}
private fun hasStaticEventHandlers(clazz: Class<*>): Boolean {
return clazz.methods.any {
Modifier.isStatic(it.modifiers) && it.isAnnotationPresent(SubscribeEvent::class.java)
}
}
private fun parseModId(containedMods: MutableSet<ASMData>, 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<Side> {
val parsedSides: List<EnumHolder>? = subscriber.annotationInfo["value"] as? List<EnumHolder>
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
}*/
return modId == annotationModId && sides.contains(FMLEnvironment.dist)
}
}

View File

@ -20,6 +20,15 @@ object ForgelinTest {
FMLKotlinModLoadingContext.get().modEventBus.register(this)
}
// You can also use EventBusSubscriber as usual
@Mod.EventBusSubscriber
object EventSubscriber {
@SubscribeEvent
fun testNonStatic(event: EntityJoinWorldEvent) {
logger.info("HELLO from testNonStatic")
}
}
fun setup(event: FMLCommonSetupEvent) {
logger.info("HELLO from setup")
}
@ -32,19 +41,4 @@ object ForgelinTest {
fun setup3(event: FMLCommonSetupEvent) {
logger.info("HELLO from setup3")
}
@Mod.EventBusSubscriber
object EventSubscriber {
// doesn't work
@SubscribeEvent
fun testNonStatic(event: EntityJoinWorldEvent) {
logger.info("HELLO from testNonStatic")
}
@JvmStatic
@SubscribeEvent
fun testStatic(event: EntityJoinWorldEvent) {
logger.info("HELLO from testStatic")
}
}
}