4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Minecraft Modding環境をgradle.kts・kotlinにする試み◆[forge 1.12.2][gradle 7.1.1][kotlin]

Last updated at Posted at 2021-07-28

あらまし

  • 執筆時点でほぼ最新の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


中身はこのような感じです。

image.png

1.17.1 - 37.0.9

これは現時点で最新のModding環境です。
これにはモダンなForgeGradleプラグインの扱い方の情報が含まれています。

forge-1.17.1-37.0.9-mdk.zip

中身はこのような感じです。

image.png

ビルドに関わるファイル

ビルドに関わる部分は次のものです。

  • 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"
        }
    }
}

以下は差分です。

image.png

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-Versionversionから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を使用したプロジェクトは普通に開けました。

image.png

ForgeGradleはGradleのバージョンに依存性があります。
古いForgeGradleは古いGradle、新しいForgeGradleは新しいGradleでしか動きません。

クライアントを起動してみる

runClientタスクを実行します。
このタスクはruns節内で定義されたclientに由来するものです。

image.png

無事実行できるとチャット内容がIDE上に現れます。

image.png


Forge MDKにはデフォルトでサンプルMODが用意されていますが、これがちゃんと動いていることが確認できます。

image.png

image.png

java.nio.ByteBuffer.flipエラー

当初ここでエラーに遭遇しました。

java.nio.ByteBuffer.flipがどうとか言われる場合は、Minecraftクライアントをビルドした時点でのJavaバージョンとrunClient時に使われるJavaバージョンがあっていません。
ビルドされたMinecraftは%HOMEPATH%\.gradle内に存在するようです。

その場合、次の場所をすべて1.8に統一したあとでIntelliJを閉じてキャッシュを削除し、再び起動を試みます。


ファイル→プロジェクト構成→プロジェクト設定→プロジェクト→プロジェクトSDK = corretto-1.8

image.png

ここでWSL版のjavaがリストにある場合がありますが、それを使用すると別のエラーが出ます。


ファイル→設定→ビルド、実行、デプロイ→ビルドツール→Gradle→Gradle JVM = プロジェクト SDK 1.8

image.png


ファイル→プロジェクト構成→プロジェクト設定→モジュール→モジュールSDK = プロジェクト SDK

image.png

image.png


実行構成の編集→(ここに何かある場合はそこ)

image.png

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では次のように書きます。

build.gradle.kts
plugins {
    id("net.minecraftforge.gradle")
}
settings.gradle.kts
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"
}

無修飾のsourceCompatibilitytargetCompatibilityがどこの実体を指しているのかは不明です(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をしてもその場で実行しかできません。

build.gradle.kts
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")
}
settings.gradle.kts
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関数が関数として認識されます。

image.png

runClientの実行

この構成で普通に起動できました。

image.png

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")

できたもの

build.gradle.kts
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")
}
settings.gradle.kts
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に変更します。

image.png

これでどう言うわけだかHotSwapが可能になりました。

Kotlinソースを書いてみる

ExampleMod.javaを改造してKotlinClassTest.ktを呼び出すようにしてみます。

src/main/java/examplemod/ExampleMod.java
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);
            }
        });
    }
}
src/main/java/examplemod/KotlinClassTest.kt
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のテストもするため、デバッグとして実行します。

image.png


書いたとおりの出力がコンソール上に出ました。

image.png

HotSwapのテスト

デバッグモードで実行したrunClientによるMinecraftクライアントがまだ起動している状態でソースコードを適当に改変して、再コンパイルを明示的に実行します。

image.png


上手くいった場合は次のようなポップアップが出ます。

image.png


弓を引き始めたときに表示されるメッセージが改変後のものになりました。
HotSwapは成功です。

image.png

サーバーを動かす

サーバーサイドの起動とホットスワップのテストも試みます。

この節の内容は次の記事と内容が部分的にかぶっています。


サーバーはここから起動します。

image.png

EULAに関する処理

ライセンスに同意していないため、サーバーの起動には初回は必ず失敗します。

You need to agree to the EULA in order to run the server. Go to eula.txt for more info.

ライセンスに同意するにはここをtrueにします。

image.png

認証をオフにする

認証をしていないPlayer123のような開発用のプレイヤーがログインするために、server.propertiesonline-modefalseにします。

image.png

ログインしてみる

これでrunServerで起動したサーバーにrunClientで起動したクライアントからログインできるようになりました。

接続先アドレスはlocalhost:25565です。


ちゃんとサーバーサイドでもKotlinコードが動作しています。

image.png

HotSwapしてみる

ちゃんとソースコードを書き換えて再コンパイルしたらサーバーサイドのログも変わりました。

image.png

これでやりたいことはすべて完了です。

まとめ

gradlew 7.1.1を手に入れたらコレをコピペして使えばいい。

build.gradle.kts
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")
}
settings.gradle.kts
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も動作するぞ!

追記

この方法では無理ということが判明しました。
バージョンを調整するとこれと近い手法でできるっぽい。
詳細はコメント欄にて。

4
3
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?