あらまし
- 執筆時点でほぼ最新のKotlin版GradleとForgeGradleプラグインを使って、Minecraft 1.12.2版のForge Modding環境を作った
- ソースコードにJavaとKotlinのファイルを混在して配置できる
- IntelliJでクライアントとサーバーの起動とHotSwapのテストができた
- 成果物の出力関連はノータッチ
- →だめだった
- バージョンをうまく調整するといけそう
背景
手元のプロジェクトをガンガンモダンなGradleに切り替えて、プログラミング言語もJavaからKotlinに移行しているので、
この際なのでついにビルドスクリプトが初期状態でgroovy版Gradleの状態で提供されているMinecraftのModding環境もbuild.gradle.ktsに移行しました。
この記事はその際のメモです。
目標
扱う
- Gradleを更新する
- ビルドスクリプトをKotlin版Gradleに切り替える
- ForgeGradleプラグインを更新する
- ModのソースコードをJava・Kotlin混合状態にする
- IntelliJでコードのホットスワップができるようにする
まだ扱わない
- Javaバージョン指定
- テストコード
- jarの生成
- shadow jarでkotlinの依存関係を含める
- shadow jarの添付ライブラリのパッケージ名を変更する
- CIによる自動ビルド
対象読者
この記事は次の知識がある前提で書かれています。
- デフォルトのGroovy版Gradleを使用したMinecraft Forge Modding
- EclipseでのJavaでの開発経験
この記事は次の知識がない前提で書かれています。
- Kotlin版Gradleを使用したMinecraft Forge Modding
- IntelliJでのHotSwapの利用
環境
- コンパイル対象
- Minecraft 1.12.2
- Minecraft Forge 14.23.5.2855
- Kotlin 1.5.20
- ビルドスクリプト
- Gradle 7.1.1
- ForgeGradle 5.1.11
- 開発環境
- Windows 10
- IntelliJ IDEA 2021.1.3 (Community Edition)
手順
Minecraft ForgeのModding環境のダウンロード
とりあえず問題のForgeのModdingキットを入手します。
2種類のビルドスクリプトを入手して、両方に含まれる情報をマージしたうえでさらにGradleのバージョン移行もするのが目標です。
1.12.2 - 14.23.5.2855
これは構築対象のModding環境です。
forge-1.12.2-14.23.5.2855-mdk.zip
中身はこのような感じです。
1.17.1 - 37.0.9
これは現時点で最新のModding環境です。
これにはモダンなForgeGradleプラグインの扱い方の情報が含まれています。
forge-1.17.1-37.0.9-mdk.zip
中身はこのような感じです。
ビルドに関わるファイル
ビルドに関わる部分は次のものです。
-
gradle---- Gradleラッパーのバージョンごとに固定 -
src---- ソースコードの構成は従来の知識で扱える -
gradle.properties---- GradleのVM設定しか書かれていない -
gradlew---- Gradleラッパーのバージョンごとに固定 -
gradlew.bat---- Gradleラッパーのバージョンごとに固定 -
build.gradle---- 複雑
このうち本当に問題が複雑なのはbuild.gradleのみです。
IntelliJ IDEA Community版のダウンロード
今回はWindows上でIntelliJを使うので、それを用意します。
多分exeでもzipでも同じことができると思います。
【余談】実は当初Android StudioをIntelliJの代用にしていましたが、再コンパイルしてもなぜかLoaded classes are up to date. Nothing to reloadと出るだけでHotSwapが利かず(HotSwapしようとはしているけどなぜか差分が見つからない?)、あれこれキャッシュ破棄などを繰り返している過程で、Community版にしたらいつの間にか効くようになっていました(謎)(TODO)。
参考資料
1.12.2版と最新版でのbuild.gradleの差分のチェック
以下は1.12.2のビルドスクリプトからコメントを省いたものです。
[+]
buildscript {
repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter()
mavenCentral()
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:3.+'
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = '1.0'
group = 'com.yourname.modid'
archivesBaseName = 'modid'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
minecraft {
mappings channel: 'snapshot', version: '20171003-1.12'
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
}
server {
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
}
}
}
dependencies {
minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2855'
}
jar {
manifest {
attributes([
"Specification-Title": "examplemod",
"Specification-Vendor": "examplemodsareus",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "${version}",
"Implementation-Vendor" :"examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
jar.finalizedBy('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file:///${project.projectDir}/mcmodsrepo"
}
}
}
以下は1.17.1のビルドスクリプトからコメントを省いたものです。
[+]
buildscript {
repositories {
maven { url = 'https://maven.minecraftforge.net' }
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = '1.0'
group = 'com.yourname.modid'
archivesBaseName = 'modid'
java.toolchain.languageVersion = JavaLanguageVersion.of(16)
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
mappings channel: 'official', version: '1.17.1'
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
mods {
examplemod {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
mods {
examplemod {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
args '--mod', 'examplemod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
mods {
examplemod {
source sourceSets.main
}
}
}
}
}
sourceSets.main.resources { srcDir 'src/generated/resources' }
repositories {
}
dependencies {
minecraft 'net.minecraftforge:forge:1.17.1-37.0.9'
}
jar {
manifest {
attributes([
"Specification-Title" : "examplemod",
"Specification-Vendor" : "examplemodsareus",
"Specification-Version" : "1",
"Implementation-Title" : project.name,
"Implementation-Version" : project.jar.archiveVersion,
"Implementation-Vendor" : "examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
jar.finalizedBy('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file://${project.projectDir}/mcmodsrepo"
}
}
}
以下は差分です。
Forgeのリポジトリの変更
repositories {
- maven { url = 'https://files.minecraftforge.net/maven' }
- jcenter()
+ maven { url = 'https://maven.minecraftforge.net' }
mavenCentral()
}
ForgeのMavenリポジトリのURLが
https://files.minecraftforge.net/mavenからhttps://maven.minecraftforge.netに変わっています。
古い方にアクセスすると新しい方にリダイレクトされるので、とりあえず新しい方を指定しておけばよいでしょう。
jcenterは非推奨になったので消えました。
ForgeGradleバージョンの更新
dependencies {
- classpath 'net.minecraftforge.gradle:ForgeGradle:3.+'
+ classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true
}
使用するForgeGradleプラグインのバージョンが3.+から5.1.+に変わりました。
今回は5.1.11固定にしたいため、ここは5.1.11にします。
changing: trueは、常に最新版を使いたい場合に指定するようです。
Javaバージョンの指定
-sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
+java.toolchain.languageVersion = JavaLanguageVersion.of(16)
新旧でJavaバージョンが1.8→16に変わっているのと、記法そのものが変わっています。
今回はとりあえず動けばいいので古い方のまま使います。
デバッグ出力の追加
+println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
これはログの出力しかしてないので省きます。
Minecraft Mappingバージョンの更新
- mappings channel: 'snapshot', version: '20171003-1.12'
+ mappings channel: 'official', version: '1.17.1'
これはアルファベットで書かれた難読化・最小化された短い識別子名と、英単語で書かれた可読性のある長い識別子名の対応を記した定義ファイルです。
Forgeのバージョンごとに固定でよいと思うので、古い方を使います。
原文のコメントを読むと、officialの方にはライセンス上の何かがあるっぽいです。
実行構成の更新
runs {
client {
workingDirectory project.file('run')
- property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+ property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
+ mods {
+ examplemod {
+ source sourceSets.main
+ }
+ }
}
server {
- property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
+ workingDirectory project.file('run')
+ property 'forge.logging.markers', 'REGISTRIES'
+ property 'forge.logging.console.level', 'debug'
+ mods {
+ examplemod {
+ source sourceSets.main
+ }
+ }
+ }
+ data {
+ workingDirectory project.file('run')
+ property 'forge.logging.markers', 'REGISTRIES'
property 'forge.logging.console.level', 'debug'
+ args '--mod', 'examplemod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
+ mods {
+ examplemod {
+ source sourceSets.main
+ }
+ }
}
}
変更点は、以下の通りです。
-
forge.logging.markersが変わった -
server側にworkingDirectoryの指定が増えた -
mods節が増えた -
data節が増えた
ロギング関係は実行そのものには影響はないので古い方を使います。
server側のworkingDirectoryの指定は、デフォルトの値を再指定しているだけなので本来は不要のはずですが、折角増えているのでこちらを採用します。
クライアントもサーバーも同じrunディレクトリを指定することができますが、ファイルがごちゃまぜになって面倒だしサーバー側をリセットしたいときにクライアント側もまとめて消えるのが面倒なので別のディレクトリを指定しようと思います。
mods節が増えていますが、よくわからない(TODO)ので古い方に合わせます。
指定しなくても動いたということは1.12.2版のForgeでは必要ない機能である可能性があります。
data節はリソースの自動生成に関するもののようです。
jsonファイルなどを自力で書けば関係ないので丸ごと省きます。
runs節はGradle上からMinecraftアプリケーションの実行を行わない場合(例えばビルドしか行わない場合など)は丸ごと省くことができます。
リソースディレクトリの追加
+sourceSets.main.resources { srcDir 'src/generated/resources' }
自動生成されたリソースのディレクトリ(?)を追加しています。
リソースの自動生成は今回使用しないので省きます。
依存性の変更
+repositories {
+}
+
dependencies {
- minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2855'
+ minecraft 'net.minecraftforge:forge:1.17.1-37.0.9'
}
依存性の変更はForgeバージョンの変更のみです。
古い方を使います。
Jarマニフェストの更新
jar {
manifest { attributes([
"Specification-Title": "examplemod",
"Specification-Vendor": "examplemodsareus",
"Specification-Version": "1",
"Implementation-Title": project.name,
- "Implementation-Version": "${version}",
+ "Implementation-Version": project.jar.archiveVersion,
"Implementation-Vendor" :"examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
Implementation-Versionがversionからproject.jar.archiveVersionを参照するように変わりました。
後者でよいと思います。
アップロード先パスの修正
repositories {
maven {
- url "file:///${project.projectDir}/mcmodsrepo"
+ url "file://${project.projectDir}/mcmodsrepo"
}
}
project.projectDirには絶対パスが入っているため/の個数が余計になることの修正?
後者を使います。
build.gradleのマージ
二つのビルドスクリプトをマージしました。
[+]
buildscript {
repositories {
maven { url = 'https://maven.minecraftforge.net' }
jcenter()
mavenCentral()
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:5.1.11'
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
version = '1.0'
group = 'com.yourname.modid'
archivesBaseName = 'modid'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
minecraft {
mappings channel: 'snapshot', version: '20171003-1.12'
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
}
server {
workingDirectory project.file('runServer')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
}
}
}
dependencies {
minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2855'
}
jar {
manifest {
attributes([
"Specification-Title": "examplemod",
"Specification-Vendor": "examplemodsareus",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": project.jar.archiveVersion,
"Implementation-Vendor" :"examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
jar.finalizedBy('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file://${project.projectDir}/mcmodsrepo"
}
}
}
Gradle Wrapper 7.1.1の入手
以下の記事に従ってgradlewを手に入れ、既存のgradle gradlew gradlew.batを上書きします。
キャッシュの破棄
%HOMEPATH%の下にある.m2と.gradleを削除します。
これによってGradleを次に使用したときに大量の通信が発生します。
プロジェクトディレクトリに.ideaがある場合は、これを削除します。
これによってIntelliJ上で行ったプロジェクトごとの設定が初期化されます。
これはModのコンパイル時にJavaバージョンの異なる環境でコンパイルしたMinecraftがエラーを起こす問題の対策です。
プロジェクトをIntelliJ IDEAで開いてみる
マージ後のbuild.gradleとGradle 7.1.1を使用したプロジェクトは普通に開けました。
ForgeGradleはGradleのバージョンに依存性があります。
古いForgeGradleは古いGradle、新しいForgeGradleは新しいGradleでしか動きません。
クライアントを起動してみる
runClientタスクを実行します。
このタスクはruns節内で定義されたclientに由来するものです。
無事実行できるとチャット内容がIDE上に現れます。
Forge MDKにはデフォルトでサンプルMODが用意されていますが、これがちゃんと動いていることが確認できます。
java.nio.ByteBuffer.flipエラー
当初ここでエラーに遭遇しました。
java.nio.ByteBuffer.flipがどうとか言われる場合は、Minecraftクライアントをビルドした時点でのJavaバージョンとrunClient時に使われるJavaバージョンがあっていません。
ビルドされたMinecraftは%HOMEPATH%\.gradle内に存在するようです。
その場合、次の場所をすべて1.8に統一したあとでIntelliJを閉じてキャッシュを削除し、再び起動を試みます。
ファイル→プロジェクト構成→プロジェクト設定→プロジェクト→プロジェクトSDK = corretto-1.8
ここでWSL版のjavaがリストにある場合がありますが、それを使用すると別のエラーが出ます。
ファイル→設定→ビルド、実行、デプロイ→ビルドツール→Gradle→Gradle JVM = プロジェクト SDK 1.8
ファイル→プロジェクト構成→プロジェクト設定→モジュール→モジュールSDK = プロジェクト SDK
実行構成の編集→(ここに何かある場合はそこ)
Gradleタスクの実行構成にはJavaのバージョンを選択するUIはありませんでした。
build.gradle.ktsへの移行
この時点で新しいGradleで、新しいForgeGradleプラグインで、1.12.2版のForgeで、正常に動作するところまで来ました。
次はビルドスクリプトの言語をGroovyからKotlinに移行する最も大きな仕事です。
Gradleプラグインの指定
build.gradleにおいてGradleプラグインに関係する場所は以下の部分です。
buildscript {
repositories {
maven { url = 'https://maven.minecraftforge.net' }
jcenter()
mavenCentral()
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:5.1.11'
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
問題を簡単にするために、今回は使わないeclipseプラグインとmaven-publishプラグインは外すことにします。
非推奨となったjcenter()リポジトリも除外します。
buildscript {
repositories {
maven { url = 'https://maven.minecraftforge.net' }
mavenCentral()
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:5.1.11'
}
}
apply plugin: 'net.minecraftforge.gradle'
残ったのはForgeGradleのプラグインを使用するためのものだけです。
これはKotlin版Gradleでは次のように書きます。
plugins {
id("net.minecraftforge.gradle")
}
pluginManagement {
repositories {
mavenCentral()
maven("https://files.minecraftforge.net/maven")
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"net.minecraftforge.gradle" -> useModule("net.minecraftforge.gradle:ForgeGradle:5.1.11")
}
}
}
}
build.gradle.kts側には使用するプラグインのID(およびバージョン)のみを記述して、settings.gradle.kts側でプラグインの解決方法を定義します。
plugins節は一つのbuild.gradle.kts内に1個だけ記述できます。
新たなGradleプラグインを追加したい場合は、既存のplugins節に追記します。
【余談】eachPlugin節を記述すると、明示的に解決方法が指定されていないプラグインの解決に失敗するようになります。明示的に解決方法を定義しない場合にデフォルトの解決方法を使用するような記述は不明です(TODO)。
成果物に関する指定
この辺は主にjarファイルを生成する際に関わってくるもので、今回は実行までで妥協するためばっさり省略します。
version = '1.0'
group = 'com.yourname.modid'
archivesBaseName = 'modid'
jar {
manifest {
attributes([
"Specification-Title": "examplemod",
"Specification-Vendor": "examplemodsareus",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": project.jar.archiveVersion,
"Implementation-Vendor" :"examplemodsareus",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
jar.finalizedBy('reobfJar')
publishing {
publications {
mavenJava(MavenPublication) {
artifact jar
}
}
repositories {
maven {
url "file://${project.projectDir}/mcmodsrepo"
}
}
}
Javaバージョンの指定
次の記述は、Kotlin版では次のようにしました。
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
↓
tasks.withType<JavaCompile> {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
options.encoding = "UTF-8"
}
無修飾のsourceCompatibilityやtargetCompatibilityがどこの実体を指しているのかは不明です(TODO)。
minecraft節
Kotlinでもほとんど同じように記述できます。
minecraft {
mappings channel: 'snapshot', version: '20171003-1.12'
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
}
server {
workingDirectory project.file('runServer')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
}
}
}
↓
minecraft {
mappings("snapshot", "20171003-1.12")
runs {
create("client") {
workingDirectory(project.file("run"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
create("server") {
workingDirectory(project.file("runServer"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
}
}
ここには大きなハマりポイントがありました。
client { }はcreate("client") { }と翻訳します。
register("client")だと初期化が正しく行われず、runClient中にプロパティの欠落で異常終了しました。
依存性の定義
ここもセオリー通りです。
dependencies {
minecraft 'net.minecraftforge:forge:1.12.2-14.23.5.2855'
}
↓
dependencies {
minecraft("net.minecraftforge:forge:1.12.2-14.23.5.2855")
}
minecraft関数はForgeGradleプラグインが提供してくれるため、関数として呼ぶことができます。
できたビルドスクリプト
Kotlin版のビルドスクリプトができました。
成果物に関係する記述がないため、現状Moddingをしてもその場で実行しかできません。
plugins {
id("net.minecraftforge.gradle")
}
tasks.withType<JavaCompile> {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
options.encoding = "UTF-8"
}
minecraft {
mappings("snapshot", "20171003-1.12")
runs {
create("client") {
workingDirectory(project.file("run"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
create("server") {
workingDirectory(project.file("runServer"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
}
}
dependencies {
minecraft("net.minecraftforge:forge:1.12.2-14.23.5.2855")
}
pluginManagement {
repositories {
mavenCentral()
maven("https://files.minecraftforge.net/maven")
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"net.minecraftforge.gradle" -> useModule("net.minecraftforge.gradle:ForgeGradle:5.1.11")
}
}
}
}
build.gradleは削除します。
ビルドスクリプトをIntelliJ IDEAで読み込んでみる
上手くいくとIntelliJ上でminecraft関数が関数として認識されます。
runClientの実行
この構成で普通に起動できました。
ModソースにKotlinコードを含められるようにする
Kotlinをコンパイルできるようにするための記述は非常に簡潔です。
plugins節でKotlin JVMのGradleプラグインの使用を定義する。
kotlin("jvm")
dependencies節でJVM版Kotlinのコンパイル・実行時に必要なライブラリへの依存性を定義する。
implementation(kotlin("stdlib-jdk8", "1.5.20"))
eachPlugin節でKotlin JVMのGradleプラグインの解決方法を定義する。
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20")
できたもの
plugins {
kotlin("jvm")
id("net.minecraftforge.gradle")
}
tasks.withType<JavaCompile> {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
options.encoding = "UTF-8"
}
minecraft {
mappings("snapshot", "20171003-1.12")
runs {
create("client") {
workingDirectory(project.file("run"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
create("server") {
workingDirectory(project.file("runServer"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
}
}
dependencies {
implementation(kotlin("stdlib-jdk8", "1.5.20"))
minecraft("net.minecraftforge:forge:1.12.2-14.23.5.2855")
}
pluginManagement {
repositories {
mavenCentral()
maven("https://files.minecraftforge.net/maven")
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20")
"net.minecraftforge.gradle" -> useModule("net.minecraftforge.gradle:ForgeGradle:5.1.11")
}
}
}
}
これでsrc/main/java内にKotlinソースを書けるようになりました。
ビルドスクリプトでコンパイル構成を変えた際はIntelliJの設定が変わる場合がある
前述のJavaバージョンが書き換わっていて、Javaバージョンをビルドスクリプト上で明示していてもWSL版Java 8を使いだしたりするので注意が必要です。
HotSwapの有効化
一旦ここでHotSwapに関する設定に触れます。
ファイル→設定→ビルド、実行、デプロイ→ビルドツール→Gradle→ビルドおよび実行に使用をIntelliJ IDEAに変更します。
これでどう言うわけだかHotSwapが可能になりました。
Kotlinソースを書いてみる
ExampleMod.javaを改造してKotlinClassTest.ktを呼び出すようにしてみます。
package com.example.examplemod;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@Mod(modid = "examplemod", name = "Example Mod", version = "1.0")
public class ExampleMod {
@EventHandler
public void init(FMLInitializationEvent event) {
MinecraftForge.EVENT_BUS.register(new Object() {
@SubscribeEvent
public void handle(LivingEntityUseItemEvent.Start event) {
new KotlinClassTest().function(event);
}
});
}
}
package com.example.examplemod
import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent
class KotlinClassTest {
fun function(event: LivingEntityUseItemEvent.Start) {
println("[[[ ${event.item.item.registryName} ]]]")
}
}
これで、弓矢や盾を使用開始した時点でそのアイテムIDがコンソール上に出るMODが出来ました。
実行
ついでにHotSwapのテストもするため、デバッグとして実行します。
書いたとおりの出力がコンソール上に出ました。
HotSwapのテスト
デバッグモードで実行したrunClientによるMinecraftクライアントがまだ起動している状態でソースコードを適当に改変して、再コンパイルを明示的に実行します。
上手くいった場合は次のようなポップアップが出ます。
弓を引き始めたときに表示されるメッセージが改変後のものになりました。
HotSwapは成功です。
サーバーを動かす
サーバーサイドの起動とホットスワップのテストも試みます。
この節の内容は次の記事と内容が部分的にかぶっています。
サーバーはここから起動します。
EULAに関する処理
ライセンスに同意していないため、サーバーの起動には初回は必ず失敗します。
You need to agree to the EULA in order to run the server. Go to eula.txt for more info.
ライセンスに同意するにはここをtrueにします。
認証をオフにする
認証をしていないPlayer123のような開発用のプレイヤーがログインするために、server.propertiesでonline-modeをfalseにします。
ログインしてみる
これでrunServerで起動したサーバーにrunClientで起動したクライアントからログインできるようになりました。
接続先アドレスはlocalhost:25565です。
ちゃんとサーバーサイドでもKotlinコードが動作しています。
HotSwapしてみる
ちゃんとソースコードを書き換えて再コンパイルしたらサーバーサイドのログも変わりました。
これでやりたいことはすべて完了です。
まとめ
gradlew 7.1.1を手に入れたらコレをコピペして使えばいい。
plugins {
kotlin("jvm")
id("net.minecraftforge.gradle")
}
tasks.withType<JavaCompile> {
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
options.encoding = "UTF-8"
}
minecraft {
mappings("snapshot", "20171003-1.12")
runs {
create("client") {
workingDirectory(project.file("run"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
create("server") {
workingDirectory(project.file("runServer"))
property("forge.logging.markers", "SCAN,REGISTRIES,REGISTRYDUMP")
property("forge.logging.console.level", "debug")
}
}
}
dependencies {
implementation(kotlin("stdlib-jdk8", "1.5.20"))
minecraft("net.minecraftforge:forge:1.12.2-14.23.5.2855")
}
pluginManagement {
repositories {
mavenCentral()
maven("https://files.minecraftforge.net/maven")
}
resolutionStrategy {
eachPlugin {
when (requested.id.id) {
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20")
"net.minecraftforge.gradle" -> useModule("net.minecraftforge.gradle:ForgeGradle:5.1.11")
}
}
}
}
IntelliJではGradleタスクをそのまま実行してもちゃんとHotSwapも動作するぞ!
追記
この方法では無理ということが判明しました。
バージョンを調整するとこれと近い手法でできるっぽい。
詳細はコメント欄にて。

























