Compare commits

...

15 Commits

Author SHA1 Message Date
Shadowfacts 7e582d39ee
Update Kotlin and Coroutines 2019-09-13 16:27:57 -04:00
Shadowfacts 09bd973e77
Fix kotlin-stdlib-jdk7/8 not being shadowed 2019-09-13 16:21:17 -04:00
NikkyAI 85b8fd917b update to 1.3.40 (#60)
* update to 1.3.40-eap

skipped current stable (1.3.31) because of https://youtrack.jetbrains.com/issue/KT-30132

* update to 1.3.40
2019-06-19 15:17:04 -04:00
Shadowfacts 7aa0a3ef37
Bump version 2018-11-24 13:40:33 -05:00
Shadowfacts 1342a6f5a6
Update to Kotlin 1.3.10, Coroutines 1.0.1, and bump version
Closes #48
2018-11-23 21:14:22 -05:00
Shadowfacts b18b818f64
Bump version to 1.8.0 2018-10-30 19:24:05 -04:00
Shadowfacts 90c0276180
Update Kotlin to 1.3.0, Coroutines to 1.0.0
Closes #43
2018-10-30 19:20:59 -04:00
Shadowfacts 583e9d8170
Bump version 2018-06-16 10:34:04 -04:00
Shadowfacts 9809314759
Only attempt to register event handlers for mods that use KotlinAdapter
Closes #41
2018-06-14 19:14:55 -04:00
Shadowfacts 9e8935d4cf
Bump version 2018-06-14 18:25:59 -04:00
Shadowfacts 7b885ea4cd
Convert indents to tabs 2018-06-11 17:22:36 -04:00
Shadowfacts 7cebe692e7
Only unregister static/register object event handlers unless appropriate handler methods are detected 2018-06-11 17:21:43 -04:00
Shadowfacts 26b895b6ce
Bump version 2018-06-10 19:27:52 -04:00
gegy1000 df437491f1 Fix #38 (#39)
Because the automatic subscriber depends on the mod class loader, we need it to run after that has been initialized. That only happens in the construction event, so we have to search at some later stage.
2018-06-10 19:27:26 -04:00
Shadowfacts ecf20f1a76
Don't crash on failed registration
I think Forge is doing something weird with registration event handlers causing ClassNotFoundExceptions

Closes #37
2018-06-09 17:32:39 -04:00
7 changed files with 110 additions and 68 deletions

View File

@ -2,7 +2,7 @@
Fork of [Emberwalker's Forgelin](https://github.com/Emberwalker/Forgelin).
## Additions
- Shades the Kotlin standard library, runtime, and reflect libraries so you don't have to.
- Shades the Kotlin standard library, runtime, coroutines-core, and reflect libraries so you don't have to.
- Provides a Forge `ILanguageAdapter` for using Kotlin `object` classes as your main mod class.
## Usage

View File

@ -57,6 +57,7 @@ repositories {
dependencies {
compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib", version: kotlin_version
compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk7", version: kotlin_version
compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: kotlin_version
compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: kotlin_version
compile group: "org.jetbrains", name: "annotations", version: annotations_version
@ -75,6 +76,8 @@ shadowJar {
classifier = ""
dependencies {
include(dependency("org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"))
include(dependency("org.jetbrains.kotlin:kotlin-stdlib-jdk7:${kotlin_version}"))
include(dependency("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlin_version}"))
include(dependency("org.jetbrains.kotlin:kotlin-reflect:${kotlin_version}"))
include(dependency("org.jetbrains:annotations:${annotations_version}"))
include(dependency("org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutines_version}"))

View File

@ -1,4 +1,4 @@
mod_version = 1.7.0
mod_version = 1.8.4
group = net.shadowfacts
archivesBaseName = Forgelin
@ -6,6 +6,6 @@ mc_version = 1.12.2
mcp_mappings = snapshot_20180609
forge_version = 14.23.4.2705
kotlin_version = 1.2.41
annotations_version = 16.0.2
coroutines_version = 0.23.0
kotlin_version = 1.3.50
annotations_version = 16.0.3
coroutines_version = 1.3.1

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip

View File

@ -4,7 +4,7 @@ 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
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
/**
* @author shadowfacts
@ -17,9 +17,9 @@ object Forgelin {
const val VERSION = "@VERSION@"
@EventHandler
fun onConstruction(event: FMLConstructionEvent) {
fun onPreInit(event: FMLPreInitializationEvent) {
Loader.instance().modList.forEach {
ForgelinAutomaticEventSubscriber.subscribeAutomatic(it, event.asmHarvestedData, FMLCommonHandler.instance().side)
ForgelinAutomaticEventSubscriber.subscribeAutomatic(it, event.asmData, FMLCommonHandler.instance().side)
}
}
}

View File

@ -8,73 +8,105 @@ 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 org.apache.logging.log4j.LogManager
import java.lang.reflect.Modifier
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)
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)
private val unregistered = mutableSetOf<Class<*>>()
private val registered = mutableSetOf<Any>()
val modAnnotations = asm.getAnnotationsFor(mod) ?: return
fun subscribeAutomatic(mod: ModContainer, asm: ASMDataTable, currentSide: Side) {
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 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
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
}
for (containedMod in containedMods) {
val containedModId = containedMod.annotationInfo["modid"] as String
if (containedMod.annotationInfo["modLanguageAdapter"] != KotlinAdapter::class.qualifiedName) {
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it does not use KotlinAdapter", containedModId)
continue
}
LOGGER.debug("Registering @EventBusSubscriber object for {} for mod {}", subscriber.className, mod.modId)
LOGGER.debug("Attempting to register Kotlin @EventBusSubscriber objects for {}", containedModId)
val subscriberClass = Class.forName(subscriber.className, false, loader) ?: continue
val kotlinClass = subscriberClass.kotlin
val subscriberInstance = kotlinClass.objectInstance ?: kotlinClass.companionObjectInstance ?: continue
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
}
MinecraftForge.EVENT_BUS.unregister(subscriberClass)
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)
}
}
}
if (containedModId != ownerModId) {
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it is not for mod {}", subscriber.className, containedModId)
continue
}
private fun parseModId(containedMods: MutableSet<ASMData>, subscriber: ASMData): String? {
val parsedModId: String? = subscriber.annotationInfo["modid"] as? String
if (parsedModId.isNullOrEmpty()) {
return parsedModId
}
val subscriberClass = Class.forName(subscriber.className, false, loader) ?: continue
val kotlinClass = subscriberClass.kotlin
val objectInstance = kotlinClass.objectInstance ?: kotlinClass.companionObjectInstance ?: continue
return ASMDataTable.getOwnerModID(containedMods, subscriber)
}
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)
}
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
}
} 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
}
}

View File

@ -1,5 +1,6 @@
package net.shadowfacts.forgelin
import net.minecraftforge.event.entity.player.PlayerInteractEvent
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.Mod.EventBusSubscriber
@ -7,13 +8,19 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
@Mod(modid = AutomaticKtSubscriberTest.MODID, modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter")
object AutomaticKtSubscriberTest {
const val MODID = "ktsubtest"
const val MODID = "ktsubtest"
@EventBusSubscriber(modid = AutomaticKtSubscriberTest.MODID)
object EventSubscriber {
@SubscribeEvent
fun onRightClickBlock(event: RightClickBlock) {
println("Automatic KT subscriber: Right click ${event.pos}")
}
}
@EventBusSubscriber(modid = AutomaticKtSubscriberTest.MODID)
object EventSubscriber {
@SubscribeEvent
fun onRightClickBlock(event: RightClickBlock) {
println("Automatic KT subscriber: Right click ${event.pos}")
}
@JvmStatic
@SubscribeEvent
fun onRightClickItem(event: PlayerInteractEvent.RightClickItem) {
println("Right click item")
}
}
}