あらまし
- 執筆時点でほぼ最新の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も動作するぞ!
追記
この方法では無理ということが判明しました。
バージョンを調整するとこれと近い手法でできるっぽい。
詳細はコメント欄にて。