From 33dcd99ab3c5fe690495fd043e11979a2549f818 Mon Sep 17 00:00:00 2001 From: Erdragh Date: Fri, 21 Jun 2024 14:18:54 +0200 Subject: [PATCH] Port to Kotlin --- README.md | 1 - build.gradle | 11 +- gradle.properties | 4 + .../java/com/example/examplemod/Config.java | 63 -------- .../com/example/examplemod/ExampleMod.java | 136 ---------------- .../examplemod/mixin/ExampleServerMixin.java | 37 +++++ .../kotlin/com/example/examplemod/Config.kt | 60 +++++++ .../com/example/examplemod/ExampleMod.kt | 146 ++++++++++++++++++ .../resources/META-INF/neoforge.mods.toml | 9 +- src/main/resources/examplemod.mixins.json | 14 ++ 10 files changed, 276 insertions(+), 205 deletions(-) delete mode 100644 src/main/java/com/example/examplemod/Config.java delete mode 100644 src/main/java/com/example/examplemod/ExampleMod.java create mode 100644 src/main/java/com/example/examplemod/mixin/ExampleServerMixin.java create mode 100644 src/main/kotlin/com/example/examplemod/Config.kt create mode 100644 src/main/kotlin/com/example/examplemod/ExampleMod.kt create mode 100644 src/main/resources/examplemod.mixins.json diff --git a/README.md b/README.md index c8ae5cbb..823e22b1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Kotlin MDK This is a fork of NeoForge's MDK that is configured to use Kotlin. The following modifications have been made: -- Gradle's Kotlin DSL for the build scripts - Port existing Java code to Kotlin - Adjust necessary resources for running on Kotlin (i.e. depend on KFF) - Added an example Mixin to emphasize that Mixins should only be written in Java diff --git a/build.gradle b/build.gradle index 37d0dbc2..3bd6e6c6 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ plugins { id 'idea' id 'maven-publish' id 'net.neoforged.gradle.userdev' version '7.0.142' + id "org.jetbrains.kotlin.jvm" version ("2.0.0") } tasks.named('wrapper', Wrapper).configure { @@ -20,6 +21,10 @@ group = mod_group_id repositories { mavenLocal() + maven { + name = "Kotlin for Forge" + setUrl("https://thedarkcolour.github.io/KotlinForForge/") + } } base { @@ -97,6 +102,8 @@ dependencies { // And its provides the option to then use net.minecraft as the group, and one of; client, server or joined as the module name, plus the game version as version. // For all intends and purposes: You can treat this dependency as if it is a normal library you would use. implementation "net.neoforged:neoforge:${neo_version}" + // Since Kotlin is its own JVM language with its own standard library, a custom language loader needs to be used, i.e. KFF + implementation("thedarkcolour:kotlinforforge-neoforge:$kff_version") // Example optional mod dependency with JEI // The JEI API is declared for compile time use, while the full JEI artifact is used at runtime @@ -131,6 +138,8 @@ tasks.withType(ProcessResources).configureEach { minecraft_version_range: minecraft_version_range, neo_version : neo_version, neo_version_range : neo_version_range, + kff_version : kff_version, + kff_version_range : kff_version_range, loader_version_range : loader_version_range, mod_id : mod_id, mod_name : mod_name, @@ -141,7 +150,7 @@ tasks.withType(ProcessResources).configureEach { ] inputs.properties replaceProperties - filesMatching(['META-INF/neoforge.mods.toml']) { + filesMatching(['META-INF/neoforge.mods.toml', "*.mixins.json"]) { expand replaceProperties } } diff --git a/gradle.properties b/gradle.properties index 82bac1ab..2aaa721a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,6 +22,10 @@ neo_version_range=[21.0.0-beta,) # The loader version range can only use the major version of FML as bounds loader_version_range=[4,) +# KFF +kff_version=5.3.0 +kff_version_range=[5.3,) + ## Mod Properties # The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} diff --git a/src/main/java/com/example/examplemod/Config.java b/src/main/java/com/example/examplemod/Config.java deleted file mode 100644 index d70d1eba..00000000 --- a/src/main/java/com/example/examplemod/Config.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.example.examplemod; - -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.fml.event.config.ModConfigEvent; -import net.neoforged.neoforge.common.ModConfigSpec; - -// An example config class. This is not required, but it's a good idea to have one to keep your config organized. -// Demonstrates how to use Neo's config APIs -@EventBusSubscriber(modid = ExampleMod.MODID, bus = EventBusSubscriber.Bus.MOD) -public class Config -{ - private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder(); - - private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER - .comment("Whether to log the dirt block on common setup") - .define("logDirtBlock", true); - - private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER - .comment("A magic number") - .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); - - public static final ModConfigSpec.ConfigValue MAGIC_NUMBER_INTRODUCTION = BUILDER - .comment("What you want the introduction message to be for the magic number") - .define("magicNumberIntroduction", "The magic number is... "); - - // a list of strings that are treated as resource locations for items - private static final ModConfigSpec.ConfigValue> ITEM_STRINGS = BUILDER - .comment("A list of items to log on common setup.") - .defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName); - - static final ModConfigSpec SPEC = BUILDER.build(); - - public static boolean logDirtBlock; - public static int magicNumber; - public static String magicNumberIntroduction; - public static Set items; - - private static boolean validateItemName(final Object obj) - { - return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName)); - } - - @SubscribeEvent - static void onLoad(final ModConfigEvent event) - { - logDirtBlock = LOG_DIRT_BLOCK.get(); - magicNumber = MAGIC_NUMBER.get(); - magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get(); - - // convert the list of strings into a set of items - items = ITEM_STRINGS.get().stream() - .map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName))) - .collect(Collectors.toSet()); - } -} diff --git a/src/main/java/com/example/examplemod/ExampleMod.java b/src/main/java/com/example/examplemod/ExampleMod.java deleted file mode 100644 index 835a48dd..00000000 --- a/src/main/java/com/example/examplemod/ExampleMod.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.example.examplemod; - -import org.slf4j.Logger; - -import com.mojang.logging.LogUtils; - -import net.minecraft.client.Minecraft; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; -import net.minecraft.world.food.FoodProperties; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.CreativeModeTabs; -import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.MapColor; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.ModContainer; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.fml.common.Mod; -import net.neoforged.fml.config.ModConfig; -import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; -import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.event.server.ServerStartingEvent; -import net.neoforged.neoforge.registries.DeferredBlock; -import net.neoforged.neoforge.registries.DeferredHolder; -import net.neoforged.neoforge.registries.DeferredItem; -import net.neoforged.neoforge.registries.DeferredRegister; - -// The value here should match an entry in the META-INF/neoforge.mods.toml file -@Mod(ExampleMod.MODID) -public class ExampleMod -{ - // Define mod id in a common place for everything to reference - public static final String MODID = "examplemod"; - // Directly reference a slf4j logger - private static final Logger LOGGER = LogUtils.getLogger(); - // Create a Deferred Register to hold Blocks which will all be registered under the "examplemod" namespace - public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(MODID); - // Create a Deferred Register to hold Items which will all be registered under the "examplemod" namespace - public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID); - // Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "examplemod" namespace - public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID); - - // Creates a new Block with the id "examplemod:example_block", combining the namespace and path - public static final DeferredBlock EXAMPLE_BLOCK = BLOCKS.registerSimpleBlock("example_block", BlockBehaviour.Properties.of().mapColor(MapColor.STONE)); - // Creates a new BlockItem with the id "examplemod:example_block", combining the namespace and path - public static final DeferredItem EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem("example_block", EXAMPLE_BLOCK); - - // Creates a new food item with the id "examplemod:example_id", nutrition 1 and saturation 2 - public static final DeferredItem EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item", new Item.Properties().food(new FoodProperties.Builder() - .alwaysEdible().nutrition(1).saturationModifier(2f).build())); - - // Creates a creative tab with the id "examplemod:example_tab" for the example item, that is placed after the combat tab - public static final DeferredHolder EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder() - .title(Component.translatable("itemGroup.examplemod")) //The language key for the title of your CreativeModeTab - .withTabsBefore(CreativeModeTabs.COMBAT) - .icon(() -> EXAMPLE_ITEM.get().getDefaultInstance()) - .displayItems((parameters, output) -> { - output.accept(EXAMPLE_ITEM.get()); // Add the example item to the tab. For your own tabs, this method is preferred over the event - }).build()); - - // The constructor for the mod class is the first code that is run when your mod is loaded. - // FML will recognize some parameter types like IEventBus or ModContainer and pass them in automatically. - public ExampleMod(IEventBus modEventBus, ModContainer modContainer) - { - // Register the commonSetup method for modloading - modEventBus.addListener(this::commonSetup); - - // Register the Deferred Register to the mod event bus so blocks get registered - BLOCKS.register(modEventBus); - // Register the Deferred Register to the mod event bus so items get registered - ITEMS.register(modEventBus); - // Register the Deferred Register to the mod event bus so tabs get registered - CREATIVE_MODE_TABS.register(modEventBus); - - // Register ourselves for server and other game events we are interested in. - // Note that this is necessary if and only if we want *this* class (ExampleMod) to respond directly to events. - // Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below. - NeoForge.EVENT_BUS.register(this); - - // Register the item to a creative tab - modEventBus.addListener(this::addCreative); - - // Register our mod's ModConfigSpec so that FML can create and load the config file for us - modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC); - } - - private void commonSetup(final FMLCommonSetupEvent event) - { - // Some common setup code - LOGGER.info("HELLO FROM COMMON SETUP"); - - if (Config.logDirtBlock) - LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT)); - - LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber); - - Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString())); - } - - // Add the example block item to the building blocks tab - private void addCreative(BuildCreativeModeTabContentsEvent event) - { - if (event.getTabKey() == CreativeModeTabs.BUILDING_BLOCKS) - event.accept(EXAMPLE_BLOCK_ITEM); - } - - // You can use SubscribeEvent and let the Event Bus discover methods to call - @SubscribeEvent - public void onServerStarting(ServerStartingEvent event) - { - // Do something when the server starts - LOGGER.info("HELLO from server starting"); - } - - // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent - @EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) - public static class ClientModEvents - { - @SubscribeEvent - public static void onClientSetup(FMLClientSetupEvent event) - { - // Some client setup code - LOGGER.info("HELLO FROM CLIENT SETUP"); - LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName()); - } - } -} diff --git a/src/main/java/com/example/examplemod/mixin/ExampleServerMixin.java b/src/main/java/com/example/examplemod/mixin/ExampleServerMixin.java new file mode 100644 index 00000000..d602d7e3 --- /dev/null +++ b/src/main/java/com/example/examplemod/mixin/ExampleServerMixin.java @@ -0,0 +1,37 @@ +package com.example.examplemod.mixin; + +import com.mojang.logging.LogUtils; +import net.minecraft.commands.CommandSource; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ServerInfo; +import net.minecraft.server.TickTask; +import net.minecraft.util.thread.ReentrantBlockableEventLoop; +import net.minecraft.world.level.chunk.storage.ChunkIOErrorReporter; +import org.slf4j.Logger; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +// Example Mixin to demonstrate that Mixins should be written in Java. +// It is _technically_ possible to write them in Kotlin but only if you understand +// how the Kotlin compiler works internally and what bytecode it produces and are fully +// aware of that at all times. The general advice is: JUST USE JAVA FOR MIXINS + +// Marked as abstract so all the extends and implements clauses don't need to be "followed". +// Those clauses are added to get easy access to things without needing to @Shadow them. +@Mixin(MinecraftServer.class) +public abstract class ExampleServerMixin extends ReentrantBlockableEventLoop implements ServerInfo, ChunkIOErrorReporter, CommandSource, AutoCloseable { + + private final Logger LOGGER = LogUtils.getLogger(); + + // Constructor of a Mixin gets ignored + public ExampleServerMixin(String pName) { + super(pName); + } + + @Inject(method = "runServer", at = @At("HEAD")) + public void examplemod$runServer(CallbackInfo ci) { + LOGGER.info("Example Mixin ran from server startup"); + } +} diff --git a/src/main/kotlin/com/example/examplemod/Config.kt b/src/main/kotlin/com/example/examplemod/Config.kt new file mode 100644 index 00000000..0a28ad51 --- /dev/null +++ b/src/main/kotlin/com/example/examplemod/Config.kt @@ -0,0 +1,60 @@ +package com.example.examplemod + +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.Item +import net.neoforged.bus.api.SubscribeEvent +import net.neoforged.fml.common.EventBusSubscriber +import net.neoforged.fml.event.config.ModConfigEvent +import net.neoforged.neoforge.common.ModConfigSpec +import java.util.stream.Collectors + +// An example config class. This is not required, but it's a good idea to have one to keep your config organized. +// Demonstrates how to use Neo's config APIs +@EventBusSubscriber(modid = ExampleMod.MODID, bus = EventBusSubscriber.Bus.MOD) +object Config { + private val BUILDER: ModConfigSpec.Builder = ModConfigSpec.Builder() + + private val LOG_DIRT_BLOCK: ModConfigSpec.BooleanValue = + BUILDER.comment("Whether to log the dirt block on common setup").define("logDirtBlock", true) + + private val MAGIC_NUMBER: ModConfigSpec.IntValue = + BUILDER.comment("A magic number").defineInRange("magicNumber", 42, 0, Int.MAX_VALUE) + + val MAGIC_NUMBER_INTRODUCTION: ModConfigSpec.ConfigValue = + BUILDER.comment("What you want the introduction message to be for the magic number") + .define("magicNumberIntroduction", "The magic number is... ") + + // a list of strings that are treated as resource locations for items + private val ITEM_STRINGS: ModConfigSpec.ConfigValue> = + BUILDER.comment("A list of items to log on common setup.").defineListAllowEmpty( + "items", + listOf("minecraft:iron_ingot"), + ::validateItemName + ) + + val SPEC: ModConfigSpec = BUILDER.build() + + var logDirtBlock: Boolean = false + var magicNumber: Int = 0 + lateinit var magicNumberIntroduction: String + lateinit var items: Set + + private fun validateItemName(obj: Any): Boolean { + return obj is String && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(obj)) + } + + @SubscribeEvent + fun onLoad(event: ModConfigEvent) { + logDirtBlock = LOG_DIRT_BLOCK.get() + magicNumber = MAGIC_NUMBER.get() + magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get() + + // convert the list of strings into a set of items + items = ITEM_STRINGS.get().stream().map { itemName: String? -> + BuiltInRegistries.ITEM[ResourceLocation.parse( + itemName + )] + }.collect(Collectors.toSet()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/example/examplemod/ExampleMod.kt b/src/main/kotlin/com/example/examplemod/ExampleMod.kt new file mode 100644 index 00000000..11dc4aa1 --- /dev/null +++ b/src/main/kotlin/com/example/examplemod/ExampleMod.kt @@ -0,0 +1,146 @@ +package com.example.examplemod + +import com.mojang.logging.LogUtils +import net.minecraft.client.Minecraft +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.core.registries.Registries +import net.minecraft.network.chat.Component +import net.minecraft.world.food.FoodProperties +import net.minecraft.world.item.BlockItem +import net.minecraft.world.item.CreativeModeTab +import net.minecraft.world.item.CreativeModeTab.ItemDisplayParameters +import net.minecraft.world.item.CreativeModeTabs +import net.minecraft.world.item.Item +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.state.BlockBehaviour +import net.minecraft.world.level.material.MapColor +import net.neoforged.api.distmarker.Dist +import net.neoforged.bus.api.IEventBus +import net.neoforged.bus.api.SubscribeEvent +import net.neoforged.fml.ModContainer +import net.neoforged.fml.common.EventBusSubscriber +import net.neoforged.fml.common.Mod +import net.neoforged.fml.config.ModConfig +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent +import net.neoforged.neoforge.common.NeoForge +import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent +import net.neoforged.neoforge.event.server.ServerStartingEvent +import net.neoforged.neoforge.registries.DeferredBlock +import net.neoforged.neoforge.registries.DeferredHolder +import net.neoforged.neoforge.registries.DeferredItem +import net.neoforged.neoforge.registries.DeferredRegister +import java.util.function.Consumer +import java.util.function.Supplier + +// The value here should match an entry in the META-INF/neoforge.mods.toml file +@Mod(ExampleMod.MODID) +class ExampleMod { + companion object { + // Define mod id in a common place for everything to reference + const val MODID = "examplemod" + // Directly reference a slf4j logger + private val LOGGER = LogUtils.getLogger(); + + // Create a Deferred Register to hold Blocks which will all be registered under the "examplemod" namespace + val BLOCKS: DeferredRegister.Blocks = DeferredRegister.createBlocks( + MODID + ) + // Create a Deferred Register to hold Items which will all be registered under the "examplemod" namespace + val ITEMS: DeferredRegister.Items = DeferredRegister.createItems( + MODID + ) + // Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "examplemod" namespace + val CREATIVE_MODE_TABS: DeferredRegister = + DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID) + + // Creates a new Block with the id "examplemod:example_block", combining the namespace and path + val EXAMPLE_BLOCK: DeferredBlock = + BLOCKS.registerSimpleBlock("example_block", BlockBehaviour.Properties.of().mapColor(MapColor.STONE)) + // Creates a new BlockItem with the id "examplemod:example_block", combining the namespace and path + val EXAMPLE_BLOCK_ITEM: DeferredItem = ITEMS.registerSimpleBlockItem("example_block", EXAMPLE_BLOCK) + + // Creates a new food item with the id "examplemod:example_id", nutrition 1 and saturation 2 + val EXAMPLE_ITEM: DeferredItem = ITEMS.registerSimpleItem( + "example_item", Item.Properties().food( + FoodProperties.Builder() + .alwaysEdible().nutrition(1).saturationModifier(2f).build() + ) + ) + + // Creates a creative tab with the id "examplemod:example_tab" for the example item, that is placed after the combat tab + val EXAMPLE_TAB: DeferredHolder = CREATIVE_MODE_TABS.register("example_tab", + Supplier { + CreativeModeTab.builder() + .title(Component.translatable("itemGroup.examplemod")) //The language key for the title of your CreativeModeTab + .withTabsBefore(CreativeModeTabs.COMBAT) + .icon { EXAMPLE_ITEM.get().defaultInstance } + .displayItems { parameters: ItemDisplayParameters?, output: CreativeModeTab.Output -> + output.accept(EXAMPLE_ITEM.get()) // Add the example item to the tab. For your own tabs, this method is preferred over the event + }.build() + }) + + // You can use EventBusSubscriber to automatically register all static methods in the class annotated with @SubscribeEvent + @EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD, value = [Dist.CLIENT]) + object ClientModEvents { + @SubscribeEvent + fun onClientSetup(event: FMLClientSetupEvent?) { + // Some client setup code + LOGGER.info("HELLO FROM CLIENT SETUP") + LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().user.name) + } + } + } + + constructor(modEventBus: IEventBus, modContainer: ModContainer) { + // Register the commonSetup method for modloading + modEventBus.addListener(::commonSetup) + + // Register the Deferred Register to the mod event bus so blocks get registered + BLOCKS.register(modEventBus) + // Register the Deferred Register to the mod event bus so items get registered + ITEMS.register(modEventBus) + // Register the Deferred Register to the mod event bus so tabs get registered + CREATIVE_MODE_TABS.register(modEventBus) + + // Register ourselves for server and other game events we are interested in. + // Note that this is necessary if and only if we want *this* class (ExampleMod) to respond directly to events. + // Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below. + NeoForge.EVENT_BUS.register(this) + + // Register the item to a creative tab + modEventBus.addListener(::addCreative) + + // Register our mod's ModConfigSpec so that FML can create and load the config file for us + modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC) + } + + private fun commonSetup(event: FMLCommonSetupEvent) { + // Some common setup code + LOGGER.info("HELLO FROM COMMON SETUP") + + if (Config.logDirtBlock) LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT)) + + LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber) + + Config.items.forEach(Consumer { item: Item -> + LOGGER.info( + "ITEM >> {}", + item.toString() + ) + }) + } + + // Add the example block item to the building blocks tab + private fun addCreative(event: BuildCreativeModeTabContentsEvent) { + if (event.tabKey === CreativeModeTabs.BUILDING_BLOCKS) event.accept(EXAMPLE_BLOCK_ITEM) + } + + // You can use SubscribeEvent and let the Event Bus discover methods to call + @SubscribeEvent + fun onServerStarting(event: ServerStartingEvent) { + // Do something when the server starts + LOGGER.info("HELLO from server starting") + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/neoforge.mods.toml b/src/main/resources/META-INF/neoforge.mods.toml index 1b9f6e99..f62400d2 100644 --- a/src/main/resources/META-INF/neoforge.mods.toml +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -4,10 +4,11 @@ # 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="javafml" #mandatory +modLoader="kotlinforforge" #mandatory # A version range to match for said mod loader - for regular FML @Mod it will be the FML version. This is currently 2. -loaderVersion="${loader_version_range}" #mandatory +# For Kotlin this is currently 5.3 +loaderVersion="${kff_version_range}" #mandatory # The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. # Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. @@ -47,8 +48,8 @@ authors="${mod_authors}" #optional description='''${mod_description}''' # The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. -#[[mixins]] -#config="${mod_id}.mixins.json" +[[mixins]] +config="${mod_id}.mixins.json" # The [[accessTransformers]] block allows you to declare where your AT file is. # If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg diff --git a/src/main/resources/examplemod.mixins.json b/src/main/resources/examplemod.mixins.json new file mode 100644 index 00000000..8af46138 --- /dev/null +++ b/src/main/resources/examplemod.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.example.examplemod.mixin", + "compatibilityLevel": "JAVA_17", + "refmap": "${mod_id}.refmap.json", + "server": [ + "ExampleServerMixin" + ], + "client": [], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file