Rewrite for 1.13 (wip)
This commit is contained in:
parent
22eb8db077
commit
2cc508fd38
|
@ -1,37 +0,0 @@
|
||||||
package net.shadowfacts.forgelin.preloader;
|
|
||||||
|
|
||||||
import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
public class ForgelinPlugin implements IFMLLoadingPlugin {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getASMTransformerClass() {
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModContainerClass() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSetupClass() {
|
|
||||||
return "net.shadowfacts.forgelin.preloader.ForgelinSetup";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectData(Map<String, Object> data) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAccessTransformerClass() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package net.shadowfacts.forgelin.preloader;
|
|
||||||
|
|
||||||
import net.minecraftforge.fml.relauncher.IFMLCallHook;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
public class ForgelinSetup implements IFMLCallHook {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void injectData(Map<String, Object> data) {
|
|
||||||
ClassLoader loader = (ClassLoader)data.get("classLoader");
|
|
||||||
try {
|
|
||||||
loader.loadClass("net.shadowfacts.forgelin.KotlinAdapter");
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
// this should never happen
|
|
||||||
throw new RuntimeException("Couldn't find Forgelin langague adapter, this shouldn't be happening", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Void call() throws Exception {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
package net.shadowfacts.forgelin
|
||||||
|
|
||||||
|
import net.minecraftforge.eventbus.EventBusErrorMessage
|
||||||
|
import net.minecraftforge.eventbus.api.Event
|
||||||
|
import net.minecraftforge.eventbus.api.IEventBus
|
||||||
|
import net.minecraftforge.eventbus.api.IEventExceptionHandler
|
||||||
|
import net.minecraftforge.eventbus.api.IEventListener
|
||||||
|
import net.minecraftforge.fml.*
|
||||||
|
import net.minecraftforge.fml.Logging.LOADING
|
||||||
|
import net.minecraftforge.fml.config.ModConfig
|
||||||
|
import net.minecraftforge.forgespi.language.IModInfo
|
||||||
|
import net.minecraftforge.forgespi.language.ModFileScanData
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import java.util.*
|
||||||
|
import java.util.function.Consumer
|
||||||
|
|
||||||
|
class FMLKotlinModContainer(
|
||||||
|
private val info: IModInfo,
|
||||||
|
private val className: String,
|
||||||
|
private val modClassLoader: ClassLoader,
|
||||||
|
private val scanResults: ModFileScanData
|
||||||
|
) : ModContainer(info) {
|
||||||
|
private val log = LogManager.getLogger()
|
||||||
|
|
||||||
|
val eventBus: IEventBus
|
||||||
|
private var mod: Any? = null
|
||||||
|
private val modClass: Class<*>
|
||||||
|
|
||||||
|
init {
|
||||||
|
log.debug(LOADING, "Creating FMLModContainer instance for {} with classLoader {} & {}", className, modClassLoader, javaClass.classLoader)
|
||||||
|
triggerMap[ModLoadingStage.CONSTRUCT] = dummy().andThen(::beforeEvent).andThen(::constructMod).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.CREATE_REGISTRIES] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.LOAD_REGISTRIES] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.COMMON_SETUP] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.SIDED_SETUP] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.ENQUEUE_IMC] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.PROCESS_IMC] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
triggerMap[ModLoadingStage.COMPLETE] = dummy().andThen(::beforeEvent).andThen(::fireEvent).andThen(::afterEvent)
|
||||||
|
eventBus = IEventBus.create(::onEventFailed)
|
||||||
|
configHandler = Optional.of<Consumer<ModConfig.ModConfigEvent>>(Consumer { event -> eventBus.post(event) })
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Here, we won't init the class, meaning static {} blocks (init {} in kotlin) won't get triggered
|
||||||
|
// but we will still have to do it later, on CONSTRUCT phase.
|
||||||
|
modClass = Class.forName(className, false, modClassLoader)
|
||||||
|
log.debug(LOADING, "Loaded modclass {} with {}", modClass.name, modClass.classLoader)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
log.error(LOADING, "Failed to load class {}", className, e)
|
||||||
|
throw ModLoadingException(info, ModLoadingStage.CONSTRUCT, "fml.modloading.failedtoloadmodclass", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dummy(): Consumer<LifecycleEventProvider.LifecycleEvent> = Consumer {}
|
||||||
|
|
||||||
|
private fun onEventFailed(iEventBus: IEventBus, event: Event, iEventListeners: Array<IEventListener>, i: Int, throwable: Throwable) {
|
||||||
|
log.error(EventBusErrorMessage(event, i, iEventListeners, throwable))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun beforeEvent(lifecycleEvent: LifecycleEventProvider.LifecycleEvent) {
|
||||||
|
FMLKotlinModLoadingContext.get().activeContainer = this
|
||||||
|
ModThreadContext.get().activeContainer = this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun fireEvent(lifecycleEvent: LifecycleEventProvider.LifecycleEvent) {
|
||||||
|
val event = lifecycleEvent.getOrBuildEvent(this)
|
||||||
|
log.debug(LOADING, "Firing event for modid {} : {}", this.getModId(), event)
|
||||||
|
try {
|
||||||
|
eventBus.post(event)
|
||||||
|
log.debug(LOADING, "Fired event for modid {} : {}", this.getModId(), event)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
log.error(LOADING, "Caught exception during event {} dispatch for modid {}", event, this.getModId(), e)
|
||||||
|
throw ModLoadingException(modInfo, lifecycleEvent.fromStage(), "fml.modloading.errorduringevent", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun afterEvent(lifecycleEvent: LifecycleEventProvider.LifecycleEvent) {
|
||||||
|
ModThreadContext.get().activeContainer = null
|
||||||
|
FMLKotlinModLoadingContext.get().activeContainer = null
|
||||||
|
if (currentState == ModLoadingStage.ERROR) {
|
||||||
|
log.error(LOADING, "An error occurred while dispatching event {} to {}", lifecycleEvent.fromStage(), getModId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun constructMod(event: LifecycleEventProvider.LifecycleEvent) {
|
||||||
|
try {
|
||||||
|
log.debug(LOADING, "Loading mod instance {} of type {}", getModId(), modClass.name)
|
||||||
|
// Now we can load the class, so that static {} block gets called
|
||||||
|
Class.forName(className)
|
||||||
|
// Then we check whether it's a kotlin object and return it, or if not we create a new instance of kotlin class.
|
||||||
|
this.mod = modClass.kotlin.objectInstance ?: modClass.newInstance()
|
||||||
|
log.debug(LOADING, "Loaded mod instance {} of type {}", getModId(), modClass.name)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
log.error(LOADING, "Failed to create mod instance. ModID: {}, class {}", getModId(), modClass.name, e)
|
||||||
|
throw ModLoadingException(modInfo, event.fromStage(), "fml.modloading.failedtoloadmod", e, modClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
log.debug(LOADING, "Completed Automatic event subscribers for {}", getModId())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun matches(mod: Any): Boolean = mod === this.mod
|
||||||
|
|
||||||
|
override fun getMod(): Any? = mod
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package net.shadowfacts.forgelin
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.Logging.SCAN
|
||||||
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLanguageProvider
|
||||||
|
import net.minecraftforge.forgespi.language.ILifecycleEvent
|
||||||
|
import net.minecraftforge.forgespi.language.IModLanguageProvider
|
||||||
|
import net.minecraftforge.forgespi.language.ModFileScanData
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import java.util.function.Supplier
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forge {@link ILanguageAdapter} for Kotlin
|
||||||
|
* Usage: Set the {@code modLanguageAdapter} field in your {@code @Mod} annotation to {@code net.shadowfacts.forgelin.FMLKotlinModLanguageProvider}
|
||||||
|
* @author shadowfacts
|
||||||
|
*/
|
||||||
|
class FMLKotlinModLanguageProvider : IModLanguageProvider {
|
||||||
|
private val log = LogManager.getLogger()
|
||||||
|
|
||||||
|
override fun name(): String {
|
||||||
|
return "kotlinfml"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFileVisitor(): Consumer<ModFileScanData> {
|
||||||
|
return Consumer { scanResult ->
|
||||||
|
val modTargetMap = scanResult.annotations.stream()
|
||||||
|
.filter { ad -> ad.annotationType == FMLJavaModLanguageProvider.MODANNOTATION }
|
||||||
|
.peek { ad -> log.debug(SCAN, "Found @Mod class {} with id {}", ad.classType.className, ad.annotationData["value"]) }
|
||||||
|
.map { ad -> FMLKotlinModTarget(ad.classType.className, ad.annotationData["value"] as String) }
|
||||||
|
.collect(Collectors.toMap(java.util.function.Function<FMLKotlinModTarget, String> { it.modId }, java.util.function.Function.identity<FMLKotlinModTarget>()))
|
||||||
|
scanResult.addLanguageLoader(modTargetMap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <R : ILifecycleEvent<R>?> consumeLifecycleEvent(consumeEvent: Supplier<R>?) {}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package net.shadowfacts.forgelin
|
||||||
|
|
||||||
|
import net.minecraftforge.common.ForgeConfigSpec
|
||||||
|
import net.minecraftforge.eventbus.api.IEventBus
|
||||||
|
import net.minecraftforge.fml.ExtensionPoint
|
||||||
|
import net.minecraftforge.fml.config.ModConfig
|
||||||
|
import java.util.function.Supplier
|
||||||
|
|
||||||
|
object FMLKotlinModLoadingContext {
|
||||||
|
private val context = ThreadLocal.withInitial { FMLKotlinModLoadingContext }
|
||||||
|
var activeContainer: FMLKotlinModContainer? = null
|
||||||
|
|
||||||
|
val modEventBus: IEventBus
|
||||||
|
get() = activeContainer!!.eventBus
|
||||||
|
|
||||||
|
fun get(): FMLKotlinModLoadingContext {
|
||||||
|
return context.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> registerExtensionPoint(point: ExtensionPoint<T>, extension: Supplier<T>) {
|
||||||
|
activeContainer!!.registerExtensionPoint(point, extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerConfig(type: ModConfig.Type, spec: ForgeConfigSpec) {
|
||||||
|
activeContainer!!.addConfig(ModConfig(type, spec, activeContainer!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun registerConfig(type: ModConfig.Type, spec: ForgeConfigSpec, fileName: String) {
|
||||||
|
activeContainer!!.addConfig(ModConfig(type, spec, activeContainer, fileName))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package net.shadowfacts.forgelin
|
||||||
|
|
||||||
|
import net.minecraftforge.fml.Logging.LOADING
|
||||||
|
import net.minecraftforge.forgespi.language.IModInfo
|
||||||
|
import net.minecraftforge.forgespi.language.IModLanguageProvider
|
||||||
|
import net.minecraftforge.forgespi.language.ModFileScanData
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
|
||||||
|
class FMLKotlinModTarget(private val className: String, val modId: String) : IModLanguageProvider.IModLanguageLoader {
|
||||||
|
private val log = LogManager.getLogger()
|
||||||
|
|
||||||
|
override fun <T> loadMod(info: IModInfo, modClassLoader: ClassLoader, modFileScanResults: ModFileScanData): T {
|
||||||
|
// This language class is loaded in the system level classloader - before the game even starts
|
||||||
|
// So we must treat container construction as an arms length operation, and load the container
|
||||||
|
// in the classloader of the game - the context classloader is appropriate here.
|
||||||
|
try {
|
||||||
|
val fmlContainer = Class.forName("net.shadowfacts.forgelin.FMLKotlinModContainer", true, Thread.currentThread().contextClassLoader)
|
||||||
|
log.debug(LOADING, "Loading FMLKotlinModContainer from classloader {} - got {}", Thread.currentThread().contextClassLoader, fmlContainer.classLoader)
|
||||||
|
val constructor = fmlContainer.getConstructor(IModInfo::class.java, String::class.java, ClassLoader::class.java, ModFileScanData::class.java)
|
||||||
|
return constructor.newInstance(info, className, modClassLoader, modFileScanResults) as T
|
||||||
|
} catch (e: ReflectiveOperationException) {
|
||||||
|
log.fatal(LOADING, "Unable to load FMLKotlinModContainer, wut?", e)
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,6 @@
|
||||||
package net.shadowfacts.forgelin
|
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
|
||||||
import net.minecraftforge.fml.common.Mod.EventHandler
|
|
||||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
|
|
||||||
|
|
||||||
/**
|
@Mod("forgelin")
|
||||||
* @author shadowfacts
|
object Forgelin
|
||||||
*/
|
|
||||||
@Mod(modid = Forgelin.MOD_ID, name = Forgelin.NAME, version = Forgelin.VERSION, acceptableRemoteVersions = "*", acceptedMinecraftVersions = "*", modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter")
|
|
||||||
object Forgelin {
|
|
||||||
|
|
||||||
const val MOD_ID = "forgelin"
|
|
||||||
const val NAME = "Forgelin"
|
|
||||||
const val VERSION = "@VERSION@"
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onPreInit(event: FMLPreInitializationEvent) {
|
|
||||||
Loader.instance().modList.forEach {
|
|
||||||
ForgelinAutomaticEventSubscriber.subscribeAutomatic(it, event.asmData, FMLCommonHandler.instance().side)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
package net.shadowfacts.forgelin
|
package net.shadowfacts.forgelin
|
||||||
|
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import net.minecraftforge.fml.common.Loader
|
/*import net.minecraftforge.fml.common.Loader
|
||||||
import net.minecraftforge.fml.common.LoaderException
|
import net.minecraftforge.fml.common.LoaderException
|
||||||
import net.minecraftforge.fml.common.Mod
|
import net.minecraftforge.fml.common.Mod
|
||||||
import net.minecraftforge.fml.common.ModContainer
|
import net.minecraftforge.fml.common.ModContainer
|
||||||
|
@ -9,14 +9,14 @@ 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.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.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)
|
||||||
|
|
||||||
private val unregistered = mutableSetOf<Class<*>>()
|
private val unregistered = mutableSetOf<Class<*>>()
|
||||||
|
@ -34,8 +34,8 @@ object ForgelinAutomaticEventSubscriber {
|
||||||
|
|
||||||
for (containedMod in containedMods) {
|
for (containedMod in containedMods) {
|
||||||
val containedModId = containedMod.annotationInfo["modid"] as String
|
val containedModId = containedMod.annotationInfo["modid"] as String
|
||||||
if (containedMod.annotationInfo["modLanguageAdapter"] != KotlinAdapter::class.qualifiedName) {
|
if (containedMod.annotationInfo["modLanguageAdapter"] != FMLKotlinModLanguageProvider::class.qualifiedName) {
|
||||||
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it does not use KotlinAdapter", containedModId)
|
LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it does not use FMLKotlinModLanguageProvider", containedModId)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,5 +108,5 @@ object ForgelinAutomaticEventSubscriber {
|
||||||
return targetSides
|
return targetSides
|
||||||
}
|
}
|
||||||
return DEFAULT_SUBSCRIPTION_SIDES
|
return DEFAULT_SUBSCRIPTION_SIDES
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
package net.shadowfacts.forgelin
|
|
||||||
|
|
||||||
import net.minecraftforge.fml.common.FMLModContainer
|
|
||||||
import net.minecraftforge.fml.common.ILanguageAdapter
|
|
||||||
import net.minecraftforge.fml.common.ModContainer
|
|
||||||
import net.minecraftforge.fml.relauncher.Side
|
|
||||||
import org.apache.logging.log4j.LogManager
|
|
||||||
import java.lang.reflect.Field
|
|
||||||
import java.lang.reflect.Method
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Forge {@link ILanguageAdapter} for Kotlin
|
|
||||||
* Usage: Set the {@code modLanguageAdapter} field in your {@code @Mod} annotation to {@code net.shadowfacts.forgelin.KotlinAdapter}
|
|
||||||
* @author shadowfacts
|
|
||||||
*/
|
|
||||||
class KotlinAdapter : ILanguageAdapter {
|
|
||||||
|
|
||||||
private val log = LogManager.getLogger("KotlinAdapter")
|
|
||||||
|
|
||||||
override fun supportsStatics(): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setProxy(target: Field, proxyTarget: Class<*>, proxy: Any) {
|
|
||||||
log.debug("Setting proxy: ${target.declaringClass.simpleName}.${target.name} -> $proxy")
|
|
||||||
|
|
||||||
// objectInstance is not null if it's a Kotlin object, so set the value on the object
|
|
||||||
// if it is null, set the value on the static field
|
|
||||||
target.set(proxyTarget.kotlin.objectInstance, proxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getNewInstance(container: FMLModContainer, objectClass: Class<*>, classLoader: ClassLoader, factoryMarkedAnnotation: Method?): Any {
|
|
||||||
log.debug("FML has asked for ${objectClass.simpleName} to be constructed")
|
|
||||||
return objectClass.kotlin.objectInstance ?: objectClass.newInstance()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setInternalProxies(mod: ModContainer?, side: Side?, loader: ClassLoader?) {
|
|
||||||
// Nothing to do; FML's got this covered for Kotlin
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
# This is an example mods.toml file. It contains the data relating to the loading mods.
|
||||||
|
# There are several mandatory fields (#mandatory), and many more that are optional (#optional).
|
||||||
|
# The overall format is standard TOML format, v0.5.0.
|
||||||
|
# Note that there are a couple of TOML lists in this file.
|
||||||
|
# Find more information on toml format here: https://github.com/toml-lang/toml
|
||||||
|
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
|
||||||
|
modLoader="kotlinfml" #mandatory
|
||||||
|
# A version range to match for said mod loader - for regular FML @Mod it will be the forge version
|
||||||
|
loaderVersion="[24,)" #mandatory (24 is current forge version)
|
||||||
|
# A URL to refer people to when problems occur with this mod
|
||||||
|
issueTrackerURL="https://github.com/shadowfacts/Forgelin/issues" #optional
|
||||||
|
# A URL for the "homepage" for this mod, displayed in the mod UI
|
||||||
|
displayURL="https://github.com/shadowfacts/Forgelin" #optional
|
||||||
|
# A file name (in the root of the mod JAR) containing a logo for display
|
||||||
|
logoFile="examplemod.png" #optional
|
||||||
|
# A text field displayed in the mod UI
|
||||||
|
credits="Emberwalker, for the original Forgelin" #optional
|
||||||
|
# A text field displayed in the mod UI
|
||||||
|
authors="shadowfacts" #optional
|
||||||
|
# A list of mods - how many allowed here is determined by the individual mod loader
|
||||||
|
[[mods]] #mandatory
|
||||||
|
# The modid of the mod
|
||||||
|
modId="forgelin" #mandatory
|
||||||
|
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
|
||||||
|
version="${file.jarVersion}" #mandatory
|
||||||
|
# A display name for the mod
|
||||||
|
displayName="Shadowfacts' Forgelin" #mandatory
|
||||||
|
# A URL to query for updates for this mod. See the JSON update specification <here>
|
||||||
|
#updateJSONURL="" #optional
|
||||||
|
# The description text for the mod (multi line!) (#mandatory)
|
||||||
|
description='''
|
||||||
|
Kotlin provider for Forge.
|
||||||
|
'''
|
||||||
|
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
|
||||||
|
[[dependencies.forgelin]] #optional
|
||||||
|
# the modid of the dependency
|
||||||
|
modId="forge" #mandatory
|
||||||
|
# Does this dependency have to exist - if not, ordering below must be specified
|
||||||
|
mandatory=true #mandatory
|
||||||
|
# The version range of the dependency
|
||||||
|
versionRange="[24,)" #mandatory
|
||||||
|
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
|
||||||
|
ordering="NONE"
|
||||||
|
# Side this dependency is applied on - BOTH, CLIENT or SERVER
|
||||||
|
side="BOTH"
|
||||||
|
# Here's another dependency
|
||||||
|
[[dependencies.forgelin]]
|
||||||
|
modId="minecraft"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[1.13]"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
|
@ -0,0 +1 @@
|
||||||
|
net.shadowfacts.forgelin.FMLKotlinModLanguageProvider
|
|
@ -1,14 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"modid": "forgelin",
|
|
||||||
"name": "Shadowfacts' Forgelin",
|
|
||||||
"version": "$version",
|
|
||||||
"mcversion": "$mcversion",
|
|
||||||
"description": "Kotlin helper library for Forge.",
|
|
||||||
"credits": "Emberwalker, for the original Forgelin",
|
|
||||||
"url": "https://github.com/shadowfacts/Forgelin",
|
|
||||||
"updateUrl": "",
|
|
||||||
"authorList": [ "shadowfacts" ],
|
|
||||||
"screenshots": []
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Forgelin resources",
|
||||||
|
"pack_format": 4,
|
||||||
|
"_comment": "Without this file, Forge crashes on startup."
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,26 +0,0 @@
|
||||||
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
|
|
||||||
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}")
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
@SubscribeEvent
|
|
||||||
fun onRightClickItem(event: PlayerInteractEvent.RightClickItem) {
|
|
||||||
println("Right click item")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package net.shadowfacts.forgelin
|
||||||
|
|
||||||
|
import net.minecraftforge.event.entity.EntityJoinWorldEvent
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent
|
||||||
|
import net.minecraftforge.fml.common.Mod
|
||||||
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
|
||||||
|
import org.apache.logging.log4j.LogManager
|
||||||
|
import org.apache.logging.log4j.Logger
|
||||||
|
|
||||||
|
@Mod("forgelin_test")
|
||||||
|
object ForgelinTest {
|
||||||
|
val logger: Logger = LogManager.getLogger()
|
||||||
|
|
||||||
|
init {
|
||||||
|
// You either need to specify generic type explicitly and use a consumer
|
||||||
|
FMLKotlinModLoadingContext.get().modEventBus.addListener<FMLCommonSetupEvent> { setup(it) }
|
||||||
|
// use a consumer with parameter types specified
|
||||||
|
FMLKotlinModLoadingContext.get().modEventBus.addListener { event: FMLCommonSetupEvent -> setup2(event) }
|
||||||
|
// or just register whole object and mark needed method with SubscribeEvent annotations.
|
||||||
|
FMLKotlinModLoadingContext.get().modEventBus.register(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setup(event: FMLCommonSetupEvent) {
|
||||||
|
logger.info("HELLO from setup")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setup2(event: FMLCommonSetupEvent) {
|
||||||
|
logger.info("HELLO from setup2")
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
modLoader="kotlinfml"
|
||||||
|
loaderVersion="[24,)"
|
||||||
|
issueTrackerURL="https://github.com/shadowfacts/Forgelin/issues"
|
||||||
|
displayURL="https://github.com/shadowfacts/Forgelin"
|
||||||
|
logoFile="examplemod.png"
|
||||||
|
credits="Emberwalker, for the original Forgelin"
|
||||||
|
authors="shadowfacts"
|
||||||
|
|
||||||
|
[[mods]]
|
||||||
|
modId="forgelin_test"
|
||||||
|
version="${file.jarVersion}"
|
||||||
|
displayName="Shadowfacts' Forgelin Test"
|
||||||
|
|
||||||
|
[[dependencies.forgelin_test]]
|
||||||
|
modId="forge"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[24,)"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.forgelin_test]]
|
||||||
|
modId="minecraft"
|
||||||
|
mandatory=true
|
||||||
|
versionRange="[1.13]"
|
||||||
|
ordering="NONE"
|
||||||
|
side="BOTH"
|
||||||
|
|
||||||
|
[[dependencies.forgelin_test]]
|
||||||
|
modId="forgelin"
|
||||||
|
mandatory=true
|
||||||
|
ordering="AFTER"
|
||||||
|
side="BOTH"
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"pack": {
|
||||||
|
"description": "Forgelin test resources",
|
||||||
|
"pack_format": 4,
|
||||||
|
"_comment": "Without this file, Forge crashes on startup."
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue