Compare commits

...

12 Commits

6 changed files with 107 additions and 64 deletions

View File

@ -2,7 +2,7 @@
Fork of [Emberwalker's Forgelin](https://github.com/Emberwalker/Forgelin). Fork of [Emberwalker's Forgelin](https://github.com/Emberwalker/Forgelin).
## Additions ## 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. - Provides a Forge `ILanguageAdapter` for using Kotlin `object` classes as your main mod class.
## Usage ## Usage

View File

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

View File

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

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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

@ -8,72 +8,105 @@ import net.minecraftforge.fml.common.ModContainer
import net.minecraftforge.fml.common.discovery.ASMDataTable import net.minecraftforge.fml.common.discovery.ASMDataTable
import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData import net.minecraftforge.fml.common.discovery.ASMDataTable.ASMData
import net.minecraftforge.fml.common.discovery.asm.ModAnnotation.EnumHolder 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.relauncher.Side
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import java.lang.reflect.Modifier
import java.util.EnumSet import java.util.EnumSet
import kotlin.reflect.full.companionObjectInstance import kotlin.reflect.full.companionObjectInstance
object ForgelinAutomaticEventSubscriber { object ForgelinAutomaticEventSubscriber {
private val DEFAULT_SUBSCRIPTION_SIDES = EnumSet.allOf(Side::class.java) private val DEFAULT_SUBSCRIPTION_SIDES = EnumSet.allOf(Side::class.java)
private val LOGGER = LogManager.getLogger(ForgelinAutomaticEventSubscriber::class.java) private val LOGGER = LogManager.getLogger(ForgelinAutomaticEventSubscriber::class.java)
fun subscribeAutomatic(mod: ModContainer, asm: ASMDataTable, currentSide: Side) { private val unregistered = mutableSetOf<Class<*>>()
LOGGER.debug("Attempting to register Kotlin @EventBusSubscriber objects for {}", mod.modId) 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 containedMods = modAnnotations.get(Mod::class.java.name)
val subscribers = modAnnotations.get(Mod.EventBusSubscriber::class.java.name) val subscribers = modAnnotations.get(Mod.EventBusSubscriber::class.java.name)
.filter { parseTargetSides(it).contains(currentSide) } .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) { for (containedMod in containedMods) {
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it is not for mod {}", subscriber.className, mod.modId) val containedModId = containedMod.annotationInfo["modid"] as String
continue 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 for (subscriber in subscribers) {
val kotlinClass = subscriberClass.kotlin try {
val subscriberInstance = kotlinClass.objectInstance ?: kotlinClass.companionObjectInstance ?: continue 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) if (containedModId != ownerModId) {
MinecraftForge.EVENT_BUS.register(subscriberInstance) LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it is not for mod {}", subscriber.className, containedModId)
LOGGER.debug("Registered @EventBusSubscriber object {}", subscriber.className) continue
} catch (e: Throwable) { }
LOGGER.error("An error occurred trying to load an @EventBusSubscriber object {} for modid {}", mod.modId, e)
}
}
}
private fun parseModId(containedMods: MutableSet<ASMData>, subscriber: ASMData): String? { val subscriberClass = Class.forName(subscriber.className, false, loader) ?: continue
val parsedModId: String? = subscriber.annotationInfo["modid"] as? String val kotlinClass = subscriberClass.kotlin
if (parsedModId.isNullOrEmpty()) { val objectInstance = kotlinClass.objectInstance ?: kotlinClass.companionObjectInstance ?: continue
return parsedModId
}
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> { } catch (e: Throwable) {
val parsedSides: List<EnumHolder>? = subscriber.annotationInfo["value"] as? List<EnumHolder> LOGGER.error("An error occurred trying to load an @EventBusSubscriber object {} for modid {}", mod.modId, e)
if (parsedSides != null) { throw LoaderException(e)
val targetSides = EnumSet.noneOf(Side::class.java) }
for (parsed in parsedSides) { }
targetSides.add(Side.valueOf(parsed.value)) }
} }
return targetSides
} private fun hasObjectEventHandlers(objectInstance: Any): Boolean {
return DEFAULT_SUBSCRIPTION_SIDES 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 package net.shadowfacts.forgelin
import net.minecraftforge.event.entity.player.PlayerInteractEvent
import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock import net.minecraftforge.event.entity.player.PlayerInteractEvent.RightClickBlock
import net.minecraftforge.fml.common.Mod import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.Mod.EventBusSubscriber 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") @Mod(modid = AutomaticKtSubscriberTest.MODID, modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter")
object AutomaticKtSubscriberTest { object AutomaticKtSubscriberTest {
const val MODID = "ktsubtest" const val MODID = "ktsubtest"
@EventBusSubscriber(modid = AutomaticKtSubscriberTest.MODID) @EventBusSubscriber(modid = AutomaticKtSubscriberTest.MODID)
object EventSubscriber { object EventSubscriber {
@SubscribeEvent @SubscribeEvent
fun onRightClickBlock(event: RightClickBlock) { fun onRightClickBlock(event: RightClickBlock) {
println("Automatic KT subscriber: Right click ${event.pos}") println("Automatic KT subscriber: Right click ${event.pos}")
} }
}
@JvmStatic
@SubscribeEvent
fun onRightClickItem(event: PlayerInteractEvent.RightClickItem) {
println("Right click item")
}
}
} }