Skip to content

Commit

Permalink
Port to Kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
Erdragh committed Jun 21, 2024
1 parent 99e727c commit 33dcd99
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 205 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
11 changes: 10 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -20,6 +21,10 @@ group = mod_group_id

repositories {
mavenLocal()
maven {
name = "Kotlin for Forge"
setUrl("https://thedarkcolour.github.io/KotlinForForge/")
}
}

base {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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
}
}
Expand Down
4 changes: 4 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
63 changes: 0 additions & 63 deletions src/main/java/com/example/examplemod/Config.java

This file was deleted.

136 changes: 0 additions & 136 deletions src/main/java/com/example/examplemod/ExampleMod.java

This file was deleted.

37 changes: 37 additions & 0 deletions src/main/java/com/example/examplemod/mixin/ExampleServerMixin.java
Original file line number Diff line number Diff line change
@@ -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<TickTask> 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");
}
}
60 changes: 60 additions & 0 deletions src/main/kotlin/com/example/examplemod/Config.kt
Original file line number Diff line number Diff line change
@@ -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<String> =
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<List<String>> =
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<Item>

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())
}
}
Loading

0 comments on commit 33dcd99

Please sign in to comment.