From 2cc508fd38842ebb1764327e1cd15ce37818df10 Mon Sep 17 00:00:00 2001 From: autaut03 Date: Tue, 12 Feb 2019 21:20:49 +0200 Subject: [PATCH] Rewrite for 1.13 (wip) --- .../forgelin/preloader/ForgelinPlugin.java | 37 ------ .../forgelin/preloader/ForgelinSetup.java | 28 ----- .../forgelin/FMLKotlinModContainer.kt | 108 ++++++++++++++++++ .../forgelin/FMLKotlinModLanguageProvider.kt | 37 ++++++ .../forgelin/FMLKotlinModLoadingContext.kt | 31 +++++ .../forgelin/FMLKotlinModTarget.kt | 27 +++++ .../net/shadowfacts/forgelin/Forgelin.kt | 23 +--- .../ForgelinAutomaticEventSubscriber.kt | 12 +- .../net/shadowfacts/forgelin/KotlinAdapter.kt | 41 ------- src/main/resources/META-INF/mods.toml | 52 +++++++++ ...rge.forgespi.language.IModLanguageProvider | 1 + src/main/resources/mcmod.info | 14 --- src/main/resources/pack.mcmeta | 7 ++ .../forgelin/AutomaticKtSubscriberTest.kt | 26 ----- .../net/shadowfacts/forgelin/ForgelinTest.kt | 50 ++++++++ src/test/resources/META-INF/mods.toml | 32 ++++++ src/test/resources/pack.mcmeta | 7 ++ 17 files changed, 360 insertions(+), 173 deletions(-) delete mode 100644 src/main/java/net/shadowfacts/forgelin/preloader/ForgelinPlugin.java delete mode 100644 src/main/java/net/shadowfacts/forgelin/preloader/ForgelinSetup.java create mode 100644 src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModContainer.kt create mode 100644 src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLanguageProvider.kt create mode 100644 src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLoadingContext.kt create mode 100644 src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModTarget.kt delete mode 100644 src/main/kotlin/net/shadowfacts/forgelin/KotlinAdapter.kt create mode 100644 src/main/resources/META-INF/mods.toml create mode 100644 src/main/resources/META-INF/services/net.minecraftforge.forgespi.language.IModLanguageProvider delete mode 100644 src/main/resources/mcmod.info create mode 100644 src/main/resources/pack.mcmeta delete mode 100644 src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt create mode 100644 src/test/kotlin/net/shadowfacts/forgelin/ForgelinTest.kt create mode 100644 src/test/resources/META-INF/mods.toml create mode 100644 src/test/resources/pack.mcmeta diff --git a/src/main/java/net/shadowfacts/forgelin/preloader/ForgelinPlugin.java b/src/main/java/net/shadowfacts/forgelin/preloader/ForgelinPlugin.java deleted file mode 100644 index 164c397..0000000 --- a/src/main/java/net/shadowfacts/forgelin/preloader/ForgelinPlugin.java +++ /dev/null @@ -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 data) { - - } - - @Override - public String getAccessTransformerClass() { - return null; - } - -} diff --git a/src/main/java/net/shadowfacts/forgelin/preloader/ForgelinSetup.java b/src/main/java/net/shadowfacts/forgelin/preloader/ForgelinSetup.java deleted file mode 100644 index b437ba8..0000000 --- a/src/main/java/net/shadowfacts/forgelin/preloader/ForgelinSetup.java +++ /dev/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 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; - } - -} diff --git a/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModContainer.kt b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModContainer.kt new file mode 100644 index 0000000..e958e31 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModContainer.kt @@ -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 { 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 = Consumer {} + + private fun onEventFailed(iEventBus: IEventBus, event: Event, iEventListeners: Array, 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 +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLanguageProvider.kt b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLanguageProvider.kt new file mode 100644 index 0000000..31cccfc --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLanguageProvider.kt @@ -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 { + 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 { it.modId }, java.util.function.Function.identity())) + scanResult.addLanguageLoader(modTargetMap) + } + } + + override fun ?> consumeLifecycleEvent(consumeEvent: Supplier?) {} +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLoadingContext.kt b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLoadingContext.kt new file mode 100644 index 0000000..7acb5c5 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModLoadingContext.kt @@ -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 registerExtensionPoint(point: ExtensionPoint, extension: Supplier) { + 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)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModTarget.kt b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModTarget.kt new file mode 100644 index 0000000..587685b --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/forgelin/FMLKotlinModTarget.kt @@ -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 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 + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt b/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt index bd0b201..518577a 100644 --- a/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt +++ b/src/main/kotlin/net/shadowfacts/forgelin/Forgelin.kt @@ -1,25 +1,6 @@ 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.FMLPreInitializationEvent -/** - * @author shadowfacts - */ -@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) - } - } -} +@Mod("forgelin") +object Forgelin \ No newline at end of file diff --git a/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt b/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt index 41cce73..4fce18a 100644 --- a/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt +++ b/src/main/kotlin/net/shadowfacts/forgelin/ForgelinAutomaticEventSubscriber.kt @@ -1,7 +1,7 @@ package net.shadowfacts.forgelin 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.Mod 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.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 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 DEFAULT_SUBSCRIPTION_SIDES = EnumSet.allOf(Side::class.java) private val LOGGER = LogManager.getLogger(ForgelinAutomaticEventSubscriber::class.java) private val unregistered = mutableSetOf>() @@ -34,8 +34,8 @@ object ForgelinAutomaticEventSubscriber { 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) + if (containedMod.annotationInfo["modLanguageAdapter"] != FMLKotlinModLanguageProvider::class.qualifiedName) { + LOGGER.debug("Skipping @EventBusSubscriber injection for {} since it does not use FMLKotlinModLanguageProvider", containedModId) continue } @@ -108,5 +108,5 @@ object ForgelinAutomaticEventSubscriber { return targetSides } return DEFAULT_SUBSCRIPTION_SIDES - } + }*/ } diff --git a/src/main/kotlin/net/shadowfacts/forgelin/KotlinAdapter.kt b/src/main/kotlin/net/shadowfacts/forgelin/KotlinAdapter.kt deleted file mode 100644 index 8b4239e..0000000 --- a/src/main/kotlin/net/shadowfacts/forgelin/KotlinAdapter.kt +++ /dev/null @@ -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 - } - -} \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..b5a4730 --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -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 +#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" \ No newline at end of file diff --git a/src/main/resources/META-INF/services/net.minecraftforge.forgespi.language.IModLanguageProvider b/src/main/resources/META-INF/services/net.minecraftforge.forgespi.language.IModLanguageProvider new file mode 100644 index 0000000..a2fef47 --- /dev/null +++ b/src/main/resources/META-INF/services/net.minecraftforge.forgespi.language.IModLanguageProvider @@ -0,0 +1 @@ +net.shadowfacts.forgelin.FMLKotlinModLanguageProvider \ No newline at end of file diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info deleted file mode 100644 index 804751d..0000000 --- a/src/main/resources/mcmod.info +++ /dev/null @@ -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": [] - } -] \ No newline at end of file diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..626cff5 --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "Forgelin resources", + "pack_format": 4, + "_comment": "Without this file, Forge crashes on startup." + } +} \ No newline at end of file diff --git a/src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt b/src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt deleted file mode 100644 index 6cfcc1d..0000000 --- a/src/test/kotlin/net/shadowfacts/forgelin/AutomaticKtSubscriberTest.kt +++ /dev/null @@ -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") - } - } -} diff --git a/src/test/kotlin/net/shadowfacts/forgelin/ForgelinTest.kt b/src/test/kotlin/net/shadowfacts/forgelin/ForgelinTest.kt new file mode 100644 index 0000000..5b3d4bc --- /dev/null +++ b/src/test/kotlin/net/shadowfacts/forgelin/ForgelinTest.kt @@ -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 { 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") + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml new file mode 100644 index 0000000..c1dc33f --- /dev/null +++ b/src/test/resources/META-INF/mods.toml @@ -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" \ No newline at end of file diff --git a/src/test/resources/pack.mcmeta b/src/test/resources/pack.mcmeta new file mode 100644 index 0000000..71be97f --- /dev/null +++ b/src/test/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "Forgelin test resources", + "pack_format": 4, + "_comment": "Without this file, Forge crashes on startup." + } +} \ No newline at end of file