Skip to content

Commit

Permalink
Port to Kotlin
Browse files Browse the repository at this point in the history
  • Loading branch information
Erdragh committed Aug 14, 2024
1 parent 3e47fe8 commit 38faca7
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 203 deletions.
10 changes: 10 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'java-library'
id 'maven-publish'
id 'net.neoforged.moddev' version '1.0.17'
id "org.jetbrains.kotlin.jvm" version ("2.0.10")
}

tasks.named('wrapper', Wrapper).configure {
Expand All @@ -18,6 +19,10 @@ group = mod_group_id

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

base {
Expand Down Expand Up @@ -112,6 +117,9 @@ configurations {
}

dependencies {
// 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
// compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
Expand Down Expand Up @@ -143,6 +151,8 @@ var generateModMetadata = tasks.register("generateModMetadata", ProcessResources
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 Down
4 changes: 4 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,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.

36 changes: 36 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,36 @@
package com.example.examplemod.mixin;

import com.example.examplemod.ExampleMod;
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.Shadow;
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 {
// Constructor of a Mixin gets ignored
public ExampleServerMixin(String pName) {
super(pName);
}

@Inject(method = "loadLevel", at = @At("TAIL"))
public void examplemod$loadLevel(CallbackInfo ci) {
System.out.println("Example Mixin ran from server startup (modid: " + ExampleMod.MODID + ")");
}
}
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 38faca7

Please sign in to comment.