Kotlinで始めるMinecraft Forge Mod開発入門


Kotlinで始めるMinecraft Forge Mod開発入門

Minecraftの世界を自分自身の手で拡張したいと思ったことはありませんか?新しいアイテム、ブロック、モブ、あるいは全く新しいゲームメカニクスを追加する。Minecraft Mod開発は、あなたの創造性をゲーム内で実現するための素晴らしい方法です。そして、その開発をより楽しく、より効率的にしてくれるのがKotlinです。

この記事では、人気のあるMod開発フレームワークであるMinecraft Forgeを使い、プログラミング言語としてKotlinを選択して、Mod開発の第一歩を踏み出す方法を、初心者向けに詳細に解説します。開発環境の準備から、シンプルなアイテムとブロックの作成、そしてModのテストまで、段階を追って進めていきましょう。

さあ、あなただけのMinecraft Modを作り始める旅に出かけましょう!

目次

  1. Mod開発の世界へようこそ

    • Minecraft Mod開発とは?
    • なぜForgeを選ぶのか?
    • なぜKotlinを選ぶのか? (Javaとの比較)
    • この記事で学ぶこと
  2. 開発環境の準備

    • 必要なもの (前提条件)
    • Java Development Kit (JDK) のインストール
    • IntelliJ IDEA のインストール
    • Git のインストール (推奨)
    • Minecraft Forge MDK のダウンロード
    • MDKプロジェクトのセットアップとIntelliJ IDEAへのインポート
  3. プロジェクト構造と初期設定

    • 生成されたファイルとディレクトリの概要
    • build.gradle.kts ファイルの解説 (Kotlin DSL)
    • mods.toml ファイルの解説 (Mod情報の定義)
    • ソースコードディレクトリ (src/main/kotlin) の構成
  4. Modのコア – エントリポイント

    • メインModクラスの作成
    • @Mod アノテーションとその役割
    • Modコンストラクタと初期化処理
    • Forge イベントバスの基本
  5. Registryについて理解する

    • Registryとは? なぜRegistryが必要なのか?
    • DeferredRegister の使い方
    • アイテムとブロックのための DeferredRegister の準備
  6. シンプルなアイテムを作成する

    • アイテムの設計 (ID, 名前, テクスチャ)
    • アイテムクラスの作成と登録
    • Item.Properties の設定
    • データ生成の基本 (リソースファイルの配置)
      • 言語ファイル (lang)
      • テクスチャファイル (textures)
      • モデルファイル (models)
    • アイテムの表示名とテクスチャの設定方法
  7. シンプルなブロックを作成する

    • ブロックの設計 (ID, 名前, テクスチャ, 材質, 硬さなど)
    • ブロッククラスの作成と登録
    • Block.Properties の設定
    • ブロックに対応するアイテム (BlockItem) の作成と登録
    • データ生成の詳細 (ブロック関連リソース)
      • 言語ファイル (lang)
      • テクスチャファイル (textures)
      • モデルファイル (models) – ブロックモデルとアイテムモデル
      • ブロックスステートファイル (blockstates)
    • ブロックの見た目と動作の設定方法
  8. イベントを利用する

    • ForgeイベントバスとModイベントバスの違い
    • イベントハンドラの作成 (@SubscribeEvent)
    • 主要なMod初期化イベント (FMLCommonSetupEvent) の利用
    • イベントハンドラクラスの登録
  9. Modをテストする

    • IntelliJ IDEAの実行構成 (runClient, runServer)
    • 開発環境でのModの実行
    • Modが正しく読み込まれたかの確認
    • 作成したアイテムやブロックの確認
  10. 次のステップと発展

    • より複雑なアイテムやブロック
    • カスタムレシピの追加
    • GUI (Graphical User Interface) の作成
    • エンティティ (モブなど) の作成
    • ワールド生成への介入
    • データジェネレーターの活用 (コードによるリソース生成)
    • Kotlinの高度な機能の活用
    • バージョン管理 (Git) の実践
  11. トラブルシューティングとよくある問題

    • Gradle sync の失敗
    • ゲーム起動時のクラッシュ (ログの見方)
    • アイテムやブロックが表示されない
    • コンパイルエラー
    • バージョン不整合
  12. まとめ


1. Mod開発の世界へようこそ

Minecraft Mod開発とは?

Minecraft Mod開発とは、Mojang Studiosによって開発されたサンドボックスゲーム「Minecraft」に、プレイヤーが自ら新しい要素(アイテム、ブロック、エンティティ、ゲームルールなど)を追加したり、既存の要素を変更したりするプログラム(Mod = Modification)を作成することです。これにより、Minecraftの無限の可能性をさらに広げることができます。

Mod開発にはプログラミングの知識が必要ですが、完成したModがゲーム内で動作する様子を見るのは非常にやりがいがあります。

なぜForgeを選ぶのか?

Minecraft Mod開発にはいくつかのフレームワークが存在しますが、最も古くからあり、最も広く利用されているのがMinecraft Forgeです。Forgeは、Mod開発者がMinecraftの内部構造に安全かつ効率的にアクセスするための多くのAPI(Application Programming Interface)を提供します。これにより、Mod開発者はゲームの複雑なコードを直接改変することなく、独自の機能を追加できます。

Forgeを選ぶ利点は以下の通りです。
* 安定性と成熟度: 長い歴史を持ち、多くのModで使用されているため、情報が多く安定しています。
* 豊富なAPI: アイテム、ブロック、エンティティ、イベントなど、ゲームのほぼ全ての側面にアクセスできるAPIが用意されています。
* 大規模なコミュニティ: 問題に直面した際に助けを求めることができる、活発な開発者コミュニティが存在します。
* Mod間の互換性: Forgeの設計により、複数のModが衝突することなく共存しやすくなっています(ただし、Modによっては相性問題が発生することもあります)。

この記事では、このForgeフレームワークを使って開発を進めます。

なぜKotlinを選ぶのか? (Javaとの比較)

伝統的にMinecraft Mod開発はJavaで行われてきました。Minecraft自体がJavaで書かれているからです。しかし、近年ではKotlinという言語が人気を集めています。KotlinはJetBrains社によって開発されたモダンな静的型付けプログラミング言語で、Java仮想マシン(JVM)上で動作します。

KotlinをMod開発に使う利点は以下の通りです。
* Javaとの完全な相互運用性: KotlinはJavaと100%互換性があります。既存のForge APIや他のJavaライブラリをそのままKotlinから呼び出すことができますし、Kotlinで書かれたコードをJavaから利用することも可能です。
* 簡潔さ: Javaに比べてコードが少なく、より簡潔に同じ処理を記述できます。ボイラープレートコード(定型的な記述)が少ないため、コードが読みやすく、書き間違いも減ります。
* 安全性: null安全性を言語レベルでサポートしています。これにより、Javaでよく遭遇するNullPointerException(Nullポインタ例外)を大幅に減らすことができます。
* 表現力の高さ: 拡張関数、プロパティ、データクラス、コルーチン(非同期処理)など、開発効率を高めるための多くのモダンな言語機能を持っています。
* IntelliJ IDEAとの統合: KotlinはJetBrainsによって開発されており、同じくJetBrains製のIDEであるIntelliJ IDEAとの連携が非常に強力です。快適な開発体験が得られます。

Mod開発の学習コストという点では、Javaの情報が多いという側面はありますが、Kotlinの情報も増えてきており、Javaの知識があればKotlinの学習は比較的容易です。一度Kotlinの便利さを知ると、Javaに戻るのが億劫になるかもしれません。

この記事で学ぶこと

この記事では、Minecraft ForgeとKotlinを使って、以下のことを学びます。
* Mod開発に必要なツール(JDK, IDEなど)を準備する。
* Forge MDKを使って開発プロジェクトをセットアップする。
* Modの基本構造と設定ファイルを理解する。
* Modのエントリポイントを作成し、Forgeのイベントシステムと連携する。
* MinecraftのRegistryシステムについて理解する。
* DeferredRegister を使ってアイテムやブロックを登録する。
* シンプルなカスタムアイテムを作成し、ゲーム内で使えるようにする。
* シンプルなカスタムブロックを作成し、ゲーム内で設置できるようにする。
* アイテムやブロックに必要なリソース(テクスチャ、モデル、言語ファイルなど)を準備する。
* 開発中のModをMinecraftでテスト実行する。

このガイドを終える頃には、あなた自身のMod開発プロジェクトを開始し、基本的なカスタムコンテンツを追加できるようになっているはずです。

2. 開発環境の準備

Mod開発を始める前に、必要なツールをコンピューターにインストールする必要があります。

必要なもの (前提条件)

  1. Java Development Kit (JDK): MinecraftもForgeもJavaで動作するため、Modを開発・実行するにはJDKが必要です。Forgeのバージョンによって要求されるJDKのバージョンが異なります。開発しようとしているMinecraftのバージョンに対応するForgeのドキュメントを確認してください。記事執筆時点の最新のForge (Minecraft 1.20.x以降) では、通常JDK 17以降が必要です。Oracle JDK, OpenJDK, Adoptium Temurinなど、どのディストリビューションでも構いません。
  2. IntelliJ IDEA: Kotlin開発に最適な統合開発環境 (IDE) です。コミュニティエディション(無料)で十分です。
  3. Git: バージョン管理システムです。必須ではありませんが、Mod開発の進行状況を記録したり、後で変更を追跡したり、他の開発者と協力したりするのに非常に役立ちます。インストールを強く推奨します。

Java Development Kit (JDK) のインストール

使用しているOS (Windows, macOS, Linux) に応じて、適切なJDKインストーラをダウンロードしてインストールしてください。前述の通り、Forgeのバージョンに合ったJDKバージョンを選択することが重要です。例えば、Adoptium Temurinのウェブサイトから対応するバージョンのJDKをダウンロードするのが一般的です。

インストール後、コマンドプロンプトやターミナルを開いて以下のコマンドを実行し、JDKが正しくインストールされ、パスが通っているか確認してください。

bash
java -version
javac -version

両方のコマンドでバージョン情報が表示されればOKです。

IntelliJ IDEA のインストール

JetBrainsの公式ウェブサイトからIntelliJ IDEAをダウンロードし、インストールしてください。
https://www.jetbrains.com/ja/idea/download/
コミュニティエディションを選択してください。

インストール時には、JavaとKotlinのプラグインが有効になっていることを確認してください(通常デフォルトで有効になっています)。

Git のインストール (推奨)

Gitがインストールされていない場合は、以下の公式サイトからダウンロードしてインストールしてください。
https://git-scm.com/downloads

インストール後、コマンドプロンプトやターミナルで以下のコマンドを実行し、インストールされているか確認してください。

bash
git --version

バージョン情報が表示されればOKです。

Minecraft Forge MDK のダウンロード

Mod開発の基盤となるForgeのMDK (Mod Developer Kit) をダウンロードします。

  1. Forge公式サイト (https://files.minecraftforge.net/) にアクセスします。
  2. 左側のメニューで、開発したいMinecraftのバージョンを選択します。今回は最新バージョン(例えば 1.20.x)を選択するのが良いでしょう。
  3. 「Download Recommended」の欄にある「Mdk」ボタンをクリックしてダウンロードします。もし「Latest」しかない場合はそちらをダウンロードします。

ダウンロードしたファイルは .zip 形式です。これをMod開発用の作業ディレクトリに解凍してください。例えば、~/MinecraftMods/MyFirstMod/ のようなディレクトリを作成し、その中にzipファイルの中身を全て展開します。

MDKプロジェクトのセットアップとIntelliJ IDEAへのインポート

解凍したMDKディレクトリには、Mod開発に必要な基本的なファイルとGradleラッパーが含まれています。GradleはJava/Kotlinプロジェクトのビルド自動化ツールです。Forge MDKはGradleを使ってプロジェクトの依存関係のダウンロード、Minecraftクライアント/サーバーのセットアップ、Modのビルドなどを行います。

  1. 解凍したMDKディレクトリを開きます。
  2. コマンドプロンプトやターミナルを開き、そのディレクトリに移動します。
  3. 以下のGradleタスクを実行して、開発環境(特にIntelliJ IDEAの設定ファイル)を生成します。Windowsの場合は gradlew.bat、macOS/Linuxの場合は ./gradlew を使用します。

    “`bash

    Windowsの場合

    gradlew genIntellijRuns

    macOS/Linuxの場合

    ./gradlew genIntellijRuns
    “`

    このコマンドはForgeのダウンロード、Minecraftクライアント/サーバーのセットアップなどを行うため、完了するまでに時間がかかります。インターネット接続が必要です。完了すると、プロジェクトディレクトリに .idea ディレクトリや run ディレクトリなどが生成されます。

  4. IntelliJ IDEAを起動します。

  5. ウェルカム画面が表示されたら、「Open」または「プロジェクトを開く」を選択します。
  6. 先ほどMDKを解凍し、genIntellijRuns を実行したディレクトリを開きます。IntelliJ IDEAはGradleプロジェクトとして自動的に認識するはずです。

    • もし自動的に認識されない場合: 「File」->「New」->「Project from Existing Sources…」を選択し、MDKディレクトリを開き、「Import project from external model」で「Gradle」を選択してインポートします。
  7. プロジェクトが開かれると、IntelliJ IDEAはGradleプロジェクトの同期を求めます。画面右下などに表示される「Load Gradle Changes」や「Import Changes」をクリックして同期を実行してください。これも時間がかかる場合があります。

Gradleの同期が完了し、プロジェクトエクスプローラーにファイル構造が表示されれば、開発環境のセットアップは完了です!

プロジェクトエクスプローラーには、以下のような主要なディレクトリやファイルが見えるはずです。
* .gradle/: Gradleが内部で使用するファイル
* .idea/: IntelliJ IDEAがプロジェクト設定を保存するファイル
* gradle/: Gradleラッパーのファイル
* run/: 開発環境でMinecraftを実行する際に使用されるディレクトリ
* src/: ソースコードとリソースが含まれる最も重要なディレクトリ
* main/: Modのメインソース
* kotlin/: Kotlinのソースコードを配置する場所
* resources/: Modのリソース(テクスチャ、モデル、言語ファイルなど)を配置する場所
* META-INF/: Modの情報ファイル (mods.toml)
* assets/: Modのゲーム内アセット(テクスチャ、モデルなど)
* build.gradle.kts: Gradleビルドスクリプト (Kotlin DSL)
* gradlew, gradlew.bat: Gradleラッパー実行ファイル
* LICENSE.txt: Forge MDKのライセンス情報
* README.txt: MDKの簡単な説明

3. プロジェクト構造と初期設定

開発を始める前に、プロジェクトの主要なファイルと構造を理解しておきましょう。

生成されたファイルとディレクトリの概要

前述の通り、src ディレクトリがあなたのModのコードとリソースを格納する主要な場所です。
* src/main/kotlin: あなたのKotlinソースコードはこのディレクトリ以下に配置します。パッケージ構造 (com.yourname.yourmodid のようなディレクトリ階層) を作って整理するのが一般的です。
* src/main/resources: Modに必要な静的なリソース(画像、設定ファイル、言語ファイルなど)を配置します。ForgeはこのディレクトリをMinecraftのリソースパックシステムに自動的に統合します。
* META-INF/mods.toml: Modの識別情報、説明、依存関係などを定義する重要な設定ファイルです。
* assets/yourmodid/...: あなたのMod固有のアセット(テクスチャ、モデル、言語ファイル、サウンドなど)を配置します。yourmodid の部分は後で設定するMod IDに合わせる必要があります。

build.gradle.kts ファイルの解説 (Kotlin DSL)

build.gradle.kts は、Gradleを使ってModをビルドするための設定ファイルです。Kotlin DSL(Domain Specific Language)で記述されており、Kotlinの構文を使って設定を書くことができます。最初は複雑に見えるかもしれませんが、Modの情報、依存関係、ビルドタスクなどが定義されています。

MDKに含まれる build.gradle.kts ファイルには、既にForge Modとしてビルドするための基本的な設定が記述されています。いくつかの重要な部分を見てみましょう。

“`kotlin
// build.gradle.kts の一部 (Forge 1.20.xの例)

// Gradleのプラグインを定義
plugins {
kotlin(“jvm”) version “1.9.20” // Kotlinプラグイン
id(“net.minecraftforge.gradle”) version “6.0.+” // Forge Gradleプラグイン
}

// グループIDとバージョンを定義 – これらは通常、Modのパッケージ名やバージョンになります
group = “com.yourname.yourmodid” // あなたのModのパッケージ名に合わせる
version = “1.0.0” // Modのバージョン

// Mod IDを定義 – Modを識別する一意の文字列(小文字の英数字とアンダースコアのみ)
val modid = “yourmodid” // あなたのMod IDに合わせる

// MinecraftとForgeのバージョンを指定
minecraft {
// Minecraftのバージョンを指定
refmap = “refmap.json” // Forgeのマッピング情報
// リソースパックパスを設定 – assets/yourmodid/… をゲームから参照できるようにする
// これにより、開発中にリソースを変更した際にゲームに反映されやすくなります
// runs { client { … resources.extra.add(file(“src/main/resources”)) } } のように設定されているはずです

// Minecraftのバージョンを指定
mappings("parchment", "1.20.1-1.20.2-1.20.3-1.20.4") // 例: Parchmentマッピングを使用する場合
// mappings("official", "1.20.1") // 例: Mojang公式マッピングを使用する場合

// Forgeのバージョンを指定
runs {
    client {
        workingDirectory(file("run"))
        // VMオプションなど...
    }
    server {
        workingDirectory(file("run"))
        // VMオプションなど...
    }
}

}

// 依存関係を定義
dependencies {
// Minecraft Forge本体への依存関係 (不要な場合もある、Forgeのビルドスクリプトが自動で追加するため)
// forge dependsOn minecraft
// “org.jetbrains.kotlin:kotlin-stdlib-jdk8” も通常は自動で追加されます

// 外部ライブラリを追加する場合
// implementation("com.example:mylib:1.0")

// Mod間依存関係 (例: Forge自体の依存関係)
// runtimeOnly("net.minecraftforge:forge:1.20.1-47.1.0:relauncher") // 例: 特定バージョンのForgeランタイム

}

// ソースセットを設定 (Kotlinソースの場所を指定)
kotlin {
sourceSets {
main {
kotlin.srcDirs(“src/main/kotlin”) // Kotlinソースはここにある
resources.srcDirs(“src/main/resources”) // リソースはここにある
}
test {
kotlin.srcDirs(“src/test/kotlin”) // テストソースはここにある
resources.srcDirs(“src/test/resources”) // テストリソースはここにある
}
}
}

// jarファイル(Modファイル)生成時の設定
tasks.jar {
manifest {
attributes[“FMLModType”] = “FMLMod”
attributes[“FMLClean”] = “fmlclean”
attributes[“Mod-Version”] = version // jarファイルにModのバージョンを埋め込む
attributes[“Mod-Id”] = modid // jarファイルにModのIDを埋め込む
attributes[“Implementation-Version”] = archiveVersion.get() // 実装バージョン
}
// Modファイル名を設定 (例: mymodid-1.0.0.jar)
archiveBaseName.set(modid)
}
“`

編集が必要な部分:
* group: あなたの組織やユーザー名に合わせたパッケージ名に変更してください (com.yourname.yourmodidyourname 部分)。
* version: Modのバージョンです。開発中は適宜変更してください。
* val modid = "yourmodid": 最も重要です。 この文字列はあなたのModを一意に識別します。他のModと重複しないように、ユニークな名前(小文字の英数字とアンダースコアのみ)を設定してください。例えば mymodsupertools_mod のようにします。このMod IDは、以降のリソースファイルのパスなど、様々な場所で使用されます。
* minecraft.mappings: 使用するマッピング(難読化解除情報)を指定します。通常MDKのREADMEに従うか、Forgeのドキュメントを確認してください。parchmentofficial などがあります。バージョンも正確に指定する必要があります。

これらの変更を行ったら、IntelliJ IDEAのGradleウィンドウで「Reload All Gradle Projects」(更新ボタンのようなアイコン)をクリックして、変更を同期してください。

mods.toml ファイルの解説 (Mod情報の定義)

src/main/resources/META-INF/mods.toml は、ModローダーであるForgeがModを認識し、必要な情報を取得するために使用する設定ファイルです。TOML (Tom’s Obvious, Minimal Language) 形式で記述されています。

MDKに含まれる mods.toml ファイルを開いてみましょう。

“`toml

mods.toml の一部

modLoader=”javafml” # Modローダーの種類を指定
loaderVersion=”[47,)” # このModがサポートするForgeローダーのバージョン範囲。通常MDKの指定に従う。
license=”All Rights Reserved” # Modのライセンス

[[mods]] # 複数のModを定義できるが、通常は一つ

modId=”yourmodid” # <– build.gradle.ktsで定義したMod IDと一致させる!
version=”${file.jar.version}” # build.gradle.ktsで設定したバージョンを取得

displayName=”Your Mod Name” # ゲーム内のModリストに表示される名前

updateJSONURL=”” # アップデート情報を取得するURL (任意)

displayURL=”” # ModのウェブサイトURL (任意)
logoFile=”” # Modのロゴ画像ファイル名 (任意)
credits=”The Forge and Mojang teams” # クレジット表示 (任意)
authors=”Your Name” # 作者名 (任意)
description=”’ # Modの説明文 (複数行可)
Write a nice and concise description of your mod!
”’

Modの依存関係を定義 (任意)

[[dependencies.yourmodid]] # ここもMod IDに合わせる

modId=”forge” # 依存するMod ID

mandatory=true # 必須の依存関係か

versionRange=”[47,)” # 依存Modのバージョン範囲

ordering=”NONE” # 依存Modの読み込み順序

side=”BOTH” # 依存Modが必要な環境 (CLIENT, SERVER, BOTH)

“`

編集が必要な部分:
* modId: build.gradle.kts で定義したMod IDと全く同じ文字列にしてください。
* version: ${file.jar.version}build.gradle.kts で設定したバージョンを自動的に参照します。通常変更は不要です。
* displayName: ゲーム内のModリストに表示される、人間が読めるMod名です。例えば「My Awesome Mod」のように分かりやすい名前を設定してください。
* license: Modのライセンスを指定します。
* authors: あなたの名前や開発チームの名前を設定してください。
* description: Modの説明文を記述します。

mods.toml はForgeがあなたのModをゲームにロードするために必要な情報源です。正確に設定することが重要です。

ソースコードディレクトリ (src/main/kotlin) の構成

src/main/kotlin ディレクトリ以下には、あなたのModのKotlinソースコード (.kt ファイル) が配置されます。Javaと同様に、パッケージ(ディレクトリ)でコードを整理するのが一般的です。

build.gradle.ktsgroup で設定したパッケージ名 (com.yourname.yourmodid) に合わせて、src/main/kotlin の下にディレクトリを作成します。

例: group = "com.example.mymod" の場合、src/main/kotlin/com/example/mymod/ というディレクトリ構造を作成します。Modのメインクラスや他のKotlinファイルはこのディレクトリ以下に配置します。

重要な注意: build.gradle.ktsmods.tomlmodid は必ず一致させてください。また、src/main/resources/assets/ の直下にも、この modid と同じ名前のディレクトリを作成する必要があります。例えば、modidmymod なら、src/main/resources/assets/mymod/ となります。ゲーム内のリソースパックシステムはこの assets/MODID/ パスを使ってあなたのModのリソースを見つけます。

4. Modのコア – エントリポイント

すべてのModには、Forgeが最初にロードするプログラムのエントリポイントが必要です。ここでModの初期設定やイベントハンドラの登録などを行います。

メインModクラスの作成

Modのエントリポイントとなるクラスを作成します。このクラスは通常、src/main/kotlin/com/yourname/yourmodid/ パッケージ以下に配置します。クラス名は任意ですが、Mod IDにちなんだ名前(例: MyMod, YourModIdMod)にすることが多いです。

Kotlinでは、シングルトンオブジェクトを定義する object キーワードを使うのが、Modのメインクラスに適しています。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdMod.kt

package com.yourname.yourmodid // build.gradle.ktsのgroupに合わせる

import net.minecraftforge.fml.common.Mod
import thedarkcolour.kotlinforforge.forge.MOD_BUS

// build.gradle.ktsとmods.tomlで定義したMod IDを定数として定義しておくと便利
const val MODID = “yourmodid”

// @Modアノテーションを付けて、このオブジェクトがModのエントリポイントであることをForgeに伝える
@Mod(MODID)
object YourModIdMod {
init {
// Modの初期化処理をここで行う
// 後述するModイベントバスへの登録などもここで行うことが多い

    // 例: 初期化イベントのリスナーを登録する (後のセクションで詳しく解説)
    // MOD_BUS.addListener(::commonSetup)
}

// 例: FMLCommonSetupEventのイベントハンドラ関数
// private fun commonSetup(event: FMLCommonSetupEvent) {
//     // 共通セットアップ(クライアント/サーバー両方で実行)
//     // Modの主要な初期化、Registryへの登録完了後の処理など
// }

}
“`

@Mod アノテーションとその役割

作成した object または class@Mod(MODID) アノテーションを付けることで、ForgeはこのオブジェクトがあなたのModのメインクラスであると認識します。アノテーションの引数には、build.gradle.ktsmods.toml で定義したMod IDを指定します。

Modコンストラクタと初期化処理

Kotlinの object では、init ブロックがそのオブジェクトが初めて使用される際に実行されます。Modのメインクラスの init ブロックは、ForgeがModをロードした直後に実行されるため、Mod全体の初期設定を行うのに適した場所です。

ここで、Forgeが提供する様々なイベントリスナーを登録したり、Registryオブジェクトを準備したりします。

Forge イベントバスの基本

Forge Moddingの重要な概念の一つに「イベントバス(Event Bus)」があります。MinecraftやForgeは、ゲームの様々な段階(初期化、ティック更新、プレイヤーの行動など)で「イベント」を発行します。あなたのModは、これらのイベントを「購読(subscribe)」することで、特定のタイミングで独自のコードを実行できます。

Forgeには主に二つのイベントバスがあります。
1. Mod Event Bus: Modの初期化段階に関連するイベント(FMLCommonSetupEventRegisterEvent など)を扱うバスです。これらのイベントはModのライフサイクルに関連しており、通常Modのメインクラスで処理されます。thedarkcolour.kotlinforforge.forge.MOD_BUS オブジェクトを通じてアクセスします。
2. Minecraft Forge Event Bus: ゲーム中のイベント(プレイヤーのログイン、ブロックの破壊、エンティティのスポーンなど)を扱うバスです。これらのイベントはゲームプレイに関連しており、専用のイベントハンドラクラスを作成して処理することが多いです。net.minecraftforge.common.MinecraftForge.EVENT_BUS オブジェクトを通じてアクセスします。

イベントを購読するには、対象のイベントクラスを引数にとる関数(イベントハンドラ)を作成し、その関数を適切なイベントバスに登録します。Kotlin for Forgeライブラリを使うと、MOD_BUS.addListener(::yourEventHandlerFunction) のように、関数リファレンスを使って簡単に登録できます。Javaの場合 @SubscribeEvent アノテーションを使用するのが一般的ですが、Kotlinでも利用可能ですし、関数リファレンスの方がよりKotlinらしい書き方と言えます。

例: Mod初期化イベント (FMLCommonSetupEvent) のリスナー登録

“`kotlin
// YourModIdMod.kt の init ブロック内
init {
val eventBus = MOD_BUS // Mod Event Busを取得

// FMLCommonSetupEvent イベントが発生したら commonSetup 関数を実行するように登録
eventBus.addListener(::commonSetup)

// 他の初期化関連イベントも同様に登録できる
// eventBus.addListener(::interModEnqueue)
// eventBus.addListener(::interModProcess)
// eventBus.addListener(::gatherData)

// Registry関連の登録もここで行うことが多い (詳細は後述)
// YourModItems.REGISTRY.register(eventBus)
// YourModBlocks.REGISTRY.register(eventBus)

}

// FMLCommonSetupEvent のイベントハンドラ関数
private fun commonSetup(event: FMLCommonSetupEvent) {
// このイベントはクライアント/サーバー両方で一度だけ発生する
// 主要な初期化処理、クロスMod連携のための情報のやり取りなどを行う
println(“Hello from Mod setup!”) // 例
}
“`

このcommonSetup関数のシグネチャ(関数名と引数の型)は、購読したいイベント(ここではFMLCommonSetupEvent)に合わせて定義する必要があります。関数名は任意ですが、引数は通常イベントオブジェクト一つです。

次のセクションでは、Mod開発の根幹となるRegistryについて詳しく見ていきます。Registryを理解することが、アイテムやブロックを追加するための第一歩となります。

5. Registryについて理解する

Minecraftには、ゲーム内に存在するすべての要素(アイテム、ブロック、エンティティ、バイオーム、エフェクトなど)を管理するための「Registry(レジストリ)」システムがあります。Mod開発者は、自分のカスタム要素をMinecraftに追加するために、これらのRegistryに登録する必要があります。

各Registryは、要素をユニークな識別子(例: minecraft:coal_ore, minecraft:stone_sword)と関連付けて管理しています。この識別子は、Mod IDと要素のパスから構成される ResourceLocation という形式で表現されます(例: yourmodid:my_custom_item)。

Registryとは? なぜRegistryが必要なのか?

Registryは、ゲーム内のすべての要素をまとめて管理する中央集権的なデータベースのようなものです。これにより、ゲームは特定のIDから対応するアイテムやブロックのデータを効率的に取得できます。

Mod開発者は、自分が追加したいカスタムアイテムやブロックなどのオブジェクトを、ゲームが起動する前にForgeのRegistryシステムに「登録」する必要があります。登録されない要素はゲームに認識されず、使用できません。

Registryへの登録は、特定のMod初期化イベント (RegisterEvent または以前のRegistryEvent.Register) のタイミングで行うのがForge Moddingの標準的な方法です。しかし、Forgeはより扱いやすい DeferredRegister というユーティリティクラスを提供しています。

DeferredRegister の使い方

DeferredRegister は、Modの初期化段階(FMLCommonSetupEventなどの前)に登録対象をあらかじめリストアップしておき、適切なRegistryイベントが発行された際に、まとめてRegistryに登録してくれる便利なツールです。これにより、開発者は複雑なイベントハンドリングを意識することなく、登録対象のリストを作成することに集中できます。

DeferredRegister を使う基本的な流れは以下の通りです。

  1. 登録したい要素の型(例: Item, Block)と、登録先のRegistryキー(例: Registries.ITEM, Registries.BLOCK)を指定して DeferredRegister のインスタンスを作成します。
  2. 作成した DeferredRegister インスタンスの register メソッドを使って、追加したいカスタム要素(やそのファクトリ関数)を登録名(パス部分)とともにリストアップします。
  3. Modのメインクラスの初期化(initブロック)で、DeferredRegister インスタンスをModイベントバス (MOD_BUS) に登録します。

アイテムとブロックのための DeferredRegister の準備

カスタムアイテムやブロックを登録するために、それぞれ専用の DeferredRegister インスタンスを準備します。これらは通常、別のKotlinファイルにまとめて定義します。

例: アイテム登録用の DeferredRegister を保持するオブジェクト

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdItems.kt

package com.yourname.yourmodid

import net.minecraft.core.registries.Registries
import net.minecraft.world.item.Item
import net.minecraftforge.registries.DeferredRegister
import net.minecraftforge.registries.RegistryObject

// アイテム登録用のDeferredRegisterインスタンスを作成
// MODID: build.gradle.ktsで定義したMod ID
// Registries.ITEM: アイテムRegistryのキー
object YourModIdItems {
// アイテムRegistry用のDeferredRegisterを作成
val REGISTRY: DeferredRegister = DeferredRegister.create(Registries.ITEM, MODID)

// ここにカスタムアイテムのRegistryObjectを定義していく (次のセクションで実装)
// val MY_CUSTOM_ITEM: RegistryObject<Item> = REGISTRY.register("my_custom_item") { Item(Item.Properties()) }

}
“`

例: ブロック登録用の DeferredRegister を保持するオブジェクト

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdBlocks.kt

package com.yourname.yourmodid

import net.minecraft.core.registries.Registries
import net.minecraft.world.item.BlockItem
import net.minecraft.world.item.Item
import net.minecraft.world.level.block.Block
import net.minecraftforge.registries.DeferredRegister
import net.minecraftforge.registries.RegistryObject

// ブロック登録用のDeferredRegisterインスタンスを作成
object YourModIdBlocks {
// ブロックRegistry用のDeferredRegisterを作成
val REGISTRY: DeferredRegister = DeferredRegister.create(Registries.BLOCK, MODID)

// ブロックに対応するアイテム(BlockItem)も登録する必要があるため、アイテムRegistryも参照
val ITEMS_REGISTRY: DeferredRegister<Item> = YourModIdItems.REGISTRY // YourModIdItemsで定義したものを再利用

// ここにカスタムブロックのRegistryObjectを定義していく (次のセクションで実装)
// val MY_CUSTOM_BLOCK: RegistryObject<Block> = REGISTRY.register("my_custom_block") { Block(Block.Properties.of()) }

// カスタムブロックに対応するBlockItemもここで定義していく (次のセクションで実装)
// val MY_CUSTOM_BLOCK_ITEM: RegistryObject<Item> = ITEMS_REGISTRY.register("my_custom_block") {
//     BlockItem(MY_CUSTOM_BLOCK.get(), Item.Properties())
// }

}
“`

メインModクラスからの登録:

作成した DeferredRegister インスタンスをModイベントバスに登録することで、Registryイベント発生時に登録が実行されるようになります。これはModのメインクラス (YourModIdMod object) の init ブロック内で行います。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdMod.kt

package com.yourname.yourmodid

import net.minecraftforge.fml.common.Mod
import thedarkcolour.kotlinforforge.forge.MOD_BUS

const val MODID = “yourmodid”

@Mod(MODID)
object YourModIdMod {
init {
val eventBus = MOD_BUS

    // Mod初期化イベントのリスナーを登録
    eventBus.addListener(::commonSetup)

    // **DeferredRegisterをModイベントバスに登録**
    YourModIdItems.REGISTRY.register(eventBus)
    YourModIdBlocks.REGISTRY.register(eventBus) // ブロックRegistryも登録

    // BlockItemはYourModIdItems.REGISTRYに登録されるため、Blocks側で再登録する必要はない
}

private fun commonSetup(event: FMLCommonSetupEvent) {
    // ... その他の初期化処理 ...
}

}
“`

これで、アイテムとブロックを登録するための基盤が整いました。次のセクションでは、実際にシンプルなアイテムを作成し、このDeferredRegisterを使って登録する方法を見ていきます。

6. シンプルなアイテムを作成する

RegistryとDeferredRegisterの準備ができたので、いよいよ具体的なカスタムアイテムを作成します。

アイテムの設計 (ID, 名前, テクスチャ)

最初のカスタムアイテムとして、例えば特別な鉱石から取れる「不思議なインゴット」のようなものを考えましょう。

  • ID: mystic_ingot (Mod IDと組み合わせて yourmodid:mystic_ingot となる)
  • ゲーム内の表示名: 「不思議なインゴット」 (多言語対応可能)
  • テクスチャ: インゴットらしい見た目の画像ファイル

アイテムクラスの作成と登録

Minecraftのほとんどのシンプルなアイテムは、net.minecraft.world.item.Item クラスのインスタンスとして表現できます。複雑な動作を持つアイテム(ツールや食料など)は Item を継承した専用クラスを作成する必要がありますが、ここでは基本的な Item クラスをそのまま使用します。

アイテムの登録は、前述の YourModIdItems オブジェクト内の REGISTRY を使って行います。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdItems.kt の REGISTRY 定義の下に追加

object YourModIdItems {
val REGISTRY: DeferredRegister = DeferredRegister.create(Registries.ITEM, MODID)

// === ここからカスタムアイテムの定義 ===

// 不思議なインゴット
val MYSTIC_INGOT: RegistryObject<Item> = REGISTRY.register("mystic_ingot") {
    // Itemクラスのインスタンスを作成
    // Item.Properties() でアイテムの基本的な性質(スタックサイズなど)を設定できる
    Item(Item.Properties().stacksTo(64)) // 64個までスタック可能
}

// 他のカスタムアイテムもここに追加していく
// val ANOTHER_ITEM: RegistryObject<Item> = REGISTRY.register("another_item") { ... }

// === ここまでカスタムアイテムの定義 ===

}
“`

REGISTRY.register("mystic_ingot") { ... } の部分は、Registryに登録するアイテムのパス(mystic_ingot)と、アイテムのインスタンスを作成するためのファクトリ関数(ラムダ式 { ... })を指定しています。Forgeは適切なタイミングでこのファクトリ関数を呼び出し、生成されたアイテムインスタンスを yourmodid:mystic_ingot というIDでRegistryに登録します。

RegistryObject<Item> は、登録されたアイテムのインスタンスに後からアクセスするためのラッパーです。.get() メソッドで実際の Item インスタンスを取得できますが、通常は RegistryObject のまま扱います。

Item.Properties の設定

Item.Properties クラスは、アイテムの基本的な性質を設定するために使用されます。

一般的な設定例:
* stacksTo(maxStackSize: Int): アイテムの最大スタックサイズ (デフォルトは64)
* durability(maxDamage: Int): アイテムの耐久値(ツールや防具の場合)
* food(FoodProperties): 食料としての性質
* craftRemainder(item: Item): クラフト後に残るアイテム(例: バケツ)
* tab(CreativeModeTab.Builder): 所属するクリエイティブタブ (1.20.5以降のForge推奨方法、複雑なのでここでは割愛しデフォルトタブに入るのを期待するか旧来の方法を使う)

ここではシンプルにスタックサイズを64に設定しています。

データ生成の基本 (リソースファイルの配置)

Mod開発において、コードでアイテムやブロックの動作を定義するだけでなく、ゲーム内の見た目や名前などを定義する「リソースファイル」を準備することが非常に重要です。これらはテクスチャ、モデル、言語ファイルなどです。

これらのリソースは src/main/resources/assets/yourmodid/ ディレクトリ以下に配置します。yourmodid はあなたのMod IDです。

言語ファイル (lang)

アイテムやブロックのゲーム内での表示名(ローカライズされた名前)は、言語ファイル (.json 形式) で定義します。

  1. src/main/resources/assets/yourmodid/lang/ ディレクトリを作成します。
  2. その中に、例えば英語 (en_us.json) や日本語 (ja_jp.json) のファイルを作成します。

en_us.json の例:

json
{
"item.yourmodid.mystic_ingot": "Mystic Ingot"
}

ja_jp.json の例:

json
{
"item.yourmodid.mystic_ingot": "不思議なインゴット"
}

形式は "要素のタイプ.Mod ID.登録名": "表示名" です。アイテムの場合は item、ブロックの場合は block となります。登録名は Registry.register() メソッドで指定した文字列 (mystic_ingot) です。

テクスチャファイル (textures)

アイテムの見た目を定義する画像ファイル(.png 形式)を配置します。Forgeはアイテムテクスチャを assets/yourmodid/textures/item/ ディレクトリから読み込みます。

  1. src/main/resources/assets/yourmodid/textures/item/ ディレクトリを作成します。
  2. その中に、アイテムの登録名と同じ名前 (mystic_ingot.png) でテクスチャ画像ファイルを配置します。テクスチャの推奨サイズは16×16ピクセルですが、より大きいサイズでも構いません。

モデルファイル (models)

Minecraftは、アイテムやブロックの見た目を3Dモデルやスプライトで表現します。アイテムのモデルは assets/yourmodid/models/item/ ディレクトリに配置します。

ほとんどのシンプルなアイテム(ツール、インゴット、食料など)は、Inventoryで2Dのスプライトとして表示されます。これらのアイテムモデルは、特定のテクスチャファイルを参照するように定義します。

  1. src/main/resources/assets/yourmodid/models/item/ ディレクトリを作成します。
  2. その中に、アイテムの登録名と同じ名前 (mystic_ingot.json) でモデルファイルを作成します。

mystic_ingot.json の例 (標準的なアイテムモデル):

json
{
"parent": "item/generated",
"textures": {
"layer0": "yourmodid:item/mystic_ingot"
}
}

  • "parent": "item/generated": これはMinecraftの標準的なアイテムモデルの一つで、指定されたテクスチャをそのまま2Dスプライトとして表示します。
  • "textures": { ... }: 使用するテクスチャを指定します。"layer0"item/generated モデルが参照するテクスチャレイヤーです。"yourmodid:item/mystic_ingot" は、テクスチャファイル assets/yourmodid/textures/item/mystic_ingot.png を参照するパスです(.png 拡張子は省略)。

これで、「不思議なインゴット」アイテムのコードと、ゲーム内で表示するための基本的なリソースファイルが準備できました。

7. シンプルなブロックを作成する

次に、シンプルなカスタムブロックを作成し、Registryに登録する方法を見ていきます。ブロックはアイテムとしてもインベントリに表示され、設置されるため、アイテムよりも少し複雑なリソースが必要です。

ブロックの設計 (ID, 名前, テクスチャ, 材質, 硬さなど)

最初のカスタムブロックとして、例えば「不思議な鉱石」のようなものを考えましょう。

  • ID: mystic_ore (Mod IDと組み合わせて yourmodid:mystic_ore となる)
  • ゲーム内の表示名: 「不思議な鉱石」
  • テクスチャ: 鉱石らしい見た目の画像ファイル
  • 材質: 石や岩盤のような材質
  • 硬さ・耐爆性: 採掘にはツルハシが必要で、爆発にある程度耐える

ブロッククラスの作成と登録

ほとんどのシンプルな固体ブロックは、net.minecraft.world.level.block.Block クラスのインスタンスとして表現できます。複雑なブロック(特殊なGUIを持つもの、特殊な相互作用をするものなど)は Block を継承した専用クラスを作成する必要がありますが、ここでは基本的な Block クラスをそのまま使用します。

ブロックの登録は、YourModIdBlocks オブジェクト内の REGISTRY を使って行います。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdBlocks.kt の REGISTRY 定義の下に追加

import net.minecraft.world.level.block.state.BlockBehaviour
import net.minecraft.world.level.material.Material
import net.minecraft.world.level.material.PushReaction

object YourModIdBlocks {
val REGISTRY: DeferredRegister = DeferredRegister.create(Registries.BLOCK, MODID)
val ITEMS_REGISTRY: DeferredRegister = YourModIdItems.REGISTRY // ブロックアイテム登録用

// === ここからカスタムブロックの定義 ===

// 不思議な鉱石ブロック
val MYSTIC_ORE: RegistryObject<Block> = REGISTRY.register("mystic_ore") {
    Block(
        // BlockBehavior.Properties() でブロックの性質を設定
        // Minecraftの既存のブロックプロパティを参考にすると良い
        BlockBehaviour.Properties.of()
            .material(Material.STONE) // 材質: 石
            .strength(3.0f, 3.0f) // 硬さ: 3.0 (石と同じくらい), 耐爆性: 3.0 (石と同じくらい)
            .requiresCorrectToolForDrops() // 適切なツール(ツルハシなど)でないとドロップしない
    )
}

// === ここまでカスタムブロックの定義 ===

}
“`

BlockBehaviour.Properties.of() は、新しいブロックプロパティ設定のビルダーを作成します。チェーンメソッドで各種プロパティを設定していきます。

  • material(): ブロックの材質。音や物理的な挙動に影響します。Material.STONE, Material.WOOD, Material.METAL などがあります。
  • strength(hardness: Float, resistance: Float): 硬さ(採掘にかかる時間)と耐爆性(爆発に対する強さ)を設定します。
  • requiresCorrectToolForDrops(): このフラグを立てると、ブロックに対応するピッケル(ツルハシ)やシャベルなどのツールで採掘しないと何もドロップしなくなります。
  • 他にも sound(), lightLevel(), randomTicks() など多くのプロパティがあります。

ブロックに対応するアイテム (BlockItem) の作成と登録

ブロックをインベントリに入れたり、ゲーム世界に設置したりするためには、そのブロックに対応するアイテムが必要です。これは通常 net.minecraft.world.item.BlockItem というクラスのインスタンスとして作成します。

BlockItem もアイテムの一種なので、アイテムRegistry (Registries.ITEM) に登録する必要があります。これを YourModIdBlocks オブジェクト内で、ブロック登録と同時に行うのが一般的です。アイテムRegistryは YourModIdItems.REGISTRY を再利用します。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdBlocks.kt に BlockItemの定義を追加

object YourModIdBlocks {
val REGISTRY: DeferredRegister = DeferredRegister.create(Registries.BLOCK, MODID)
val ITEMS_REGISTRY: DeferredRegister = YourModIdItems.REGISTRY // ブロックアイテム登録用

// 不思議な鉱石ブロックの定義 (上記と同じ)
val MYSTIC_ORE: RegistryObject<Block> = REGISTRY.register("mystic_ore") {
    Block(BlockBehaviour.Properties.of().material(Material.STONE).strength(3.0f, 3.0f).requiresCorrectToolForDrops())
}

// **不思議な鉱石ブロックに対応するBlockItemの定義**
val MYSTIC_ORE_ITEM: RegistryObject<Item> = ITEMS_REGISTRY.register("mystic_ore") {
    // BlockItemインスタンスを作成
    // 第1引数: このアイテムが対応するブロックのRegistryObject
    // 第2引数: アイテム自体のプロパティ (スタックサイズなど)
    BlockItem(MYSTIC_ORE.get(), Item.Properties().stacksTo(64))
}

// 他のカスタムブロックもここに追加していく
// val ANOTHER_BLOCK: RegistryObject<Block> = REGISTRY.register("another_block") { ... }
// val ANOTHER_BLOCK_ITEM: RegistryObject<Item> = ITEMS_REGISTRY.register("another_block") {
//     BlockItem(ANOTHER_BLOCK.get(), Item.Properties())
// }

}
“`

BlockItemの登録名は、対応するブロックの登録名と同じにすることが必須です。これにより、ゲームはアイテムとブロックを正しく紐づけることができます。

注意: MYSTIC_ORE_ITEM の定義で MYSTIC_ORE.get() を呼び出していますが、これは register のラムダ式内で行われるため問題ありません。DeferredRegister は登録処理を適切なタイミングで行い、その際に .get() が有効になります。

データ生成の詳細 (ブロック関連リソース)

ブロックもアイテムと同様に、ゲーム内で正しく表示・動作させるためには様々なリソースファイルが必要です。これらはアイテムのリソースと同じ src/main/resources/assets/yourmodid/ ディレクトリ以下に配置します。

言語ファイル (lang)

ブロックの表示名も言語ファイルで定義します。形式はアイテムと同様です。

en_us.json の例に追加:

json
{
"item.yourmodid.mystic_ingot": "Mystic Ingot",
"block.yourmodid.mystic_ore": "Mystic Ore" // <-- ブロックの表示名
}

ja_jp.json の例に追加:

json
{
"item.yourmodid.mystic_ingot": "不思議なインゴット",
"block.yourmodid.mystic_ore": "不思議な鉱石" // <-- ブロックの表示名
}

テクスチャファイル (textures)

ブロックの見た目を定義する画像ファイル(.png 形式)を配置します。Forgeはブロックテクスチャを assets/yourmodid/textures/block/ ディレクトリから読み込みます。

  1. src/main/resources/assets/yourmodid/textures/block/ ディレクトリを作成します。
  2. その中に、ブロックの登録名と同じ名前 (mystic_ore.png) でテクスチャ画像ファイルを配置します。このテクスチャはブロックの全6面に使用されます(後述のモデルファイルで指定)。

モデルファイル (models) – ブロックモデルとアイテムモデル

ブロックには2種類のモデルが必要です。
1. ブロックモデル: ゲーム世界に設置されたブロックの見た目を定義します。assets/yourmodid/models/block/ に配置します。
2. アイテムモデル: インベントリや手に持った際のブロックアイテムの見た目を定義します。assets/yourmodid/models/item/ に配置します。

ブロックモデル (assets/yourmodid/models/block/mystic_ore.json) の例:

json
{
"parent": "block/cube_all",
"textures": {
"all": "yourmodid:block/mystic_ore"
}
}

  • "parent": "block/cube_all": Minecraftの標準的なブロックモデルの一つで、指定されたテクスチャをブロックの全6面に適用します。
  • "textures": { ... }: 使用するテクスチャを指定します。"all"cube_all モデルが参照するテクスチャキーです。"yourmodid:block/mystic_ore" は、テクスチャファイル assets/yourmodid/textures/block/mystic_ore.png を参照するパスです。

アイテムモデル (assets/yourmodid/models/item/mystic_ore.json) の例:

ブロックアイテムのモデルは、通常、対応するブロックモデルを参照するように定義します。

json
{
"parent": "yourmodid:block/mystic_ore"
}

  • "parent": "yourmodid:block/mystic_ore": このアイテムモデルは、assets/yourmodid/models/block/mystic_ore.json で定義されたブロックモデルをそのまま使用します。

ブロックスステートファイル (blockstates)

ブロックは、特定の状態(例: 向き、水源の有無、作物の成長段階など)によって見た目が変わることがあります。これらの状態と、対応するブロックモデルの紐づけを定義するのが、ブロックスステートファイル (.json 形式) です。

シンプルなブロック(状態によって見た目が変わらないもの)の場合、ブロックスステートファイルは特定のブロックモデルを常に参照するように定義します。

  1. src/main/resources/assets/yourmodid/blockstates/ ディレクトリを作成します。
  2. その中に、ブロックの登録名と同じ名前 (mystic_ore.json) でブロックスステートファイルを作成します。

mystic_ore.json の例:

json
{
"variants": {
"": { "model": "yourmodid:block/mystic_ore" }
}
}

  • "variants": ブロックの状態ごとのモデルを定義するセクションです。
  • "": { ... }: 空のキー ("") は、ブロックのデフォルト状態(特定の状態プロパティが指定されていない場合)を意味します。
  • "model": "yourmodid:block/mystic_ore": デフォルト状態では、assets/yourmodid/models/block/mystic_ore.json で定義されたブロックモデルを使用することを指定します。

これで、「不思議な鉱石」ブロックのコードと、ゲーム内で表示・設置するための基本的なリソースファイルが準備できました。

8. イベントを利用する

Registryへの登録はMod Event Busの機能を使って行いましたが、ゲーム中の様々なタイミングで独自の処理を実行するためには、Forge Event Busを利用することがよくあります。

ForgeイベントバスとModイベントバスの違い

前述の通り、Mod Event BusはModの初期化関連イベントを扱い、Forge Event Busはゲームプレイ中のイベントを扱います。

  • Mod Event Bus (MOD_BUS):
    • イベント例: FMLCommonSetupEvent, RegisterEvent, GatherDataEvent など。
    • リスナー登録: Modのメインクラスのinitブロックなどで、MOD_BUS.addListener(::yourFunction) を使用。
  • Forge Event Bus (MinecraftForge.EVENT_BUS):
    • イベント例: PlayerEvent.PlayerLoggedInEvent, LivingAttackEvent, BlockEvent.BreakEvent, ServerStartingEvent など。
    • リスナー登録: Modのメインクラスのinitブロックなどで、MinecraftForge.EVENT_BUS.register(YourEventHandlerObject) のように、イベントハンドラクラスやオブジェクト自体を登録します。

イベントハンドラの作成 (@SubscribeEvent)

Forge Event Busのイベントを購読するには、イベントハンドラとなるクラスまたはオブジェクトを作成し、その中に @SubscribeEvent アノテーションを付けたメソッド(関数)を定義するのが一般的な方法です。このメソッドは、引数として購読したいイベントクラスのインスタンスを受け取ります。

Kotlinでは、イベントハンドラを保持するための object を作成するのが簡潔です。

例: プレイヤーがゲームにログインした際にメッセージを表示するイベントハンドラ

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdEvents.kt

package com.yourname.yourmodid

import net.minecraft.world.entity.player.Player
import net.minecraftforge.event.entity.player.PlayerEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.common.Mod

@Mod.EventBusSubscriber(modid = MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) // Forgeイベントバスのイベントを購読
object YourModIdEvents {

// PlayerLoggedInEvent が発生した際にこの関数が呼び出される
@SubscribeEvent
fun onPlayerLoggedIn(event: PlayerEvent.PlayerLoggedInEvent) {
    val player: Player = event.entity
    // プレイヤーにメッセージを送信 (サーバーサイドでのみ有効)
    // クライアントサイドでのみ実行したい処理の場合は、event.side が CLIENT かどうかチェック
    if (!player.level().isClientSide) {
        // 例: プレイヤー名を取得して挨拶メッセージを作成
        val playerName = player.displayName.string // ComponentをStringに変換
        val message = "§a${playerName}さん、${MODID} Modへようこそ!" // §aは緑色の文字コード
        // プレイヤーにメッセージを送信 (Component形式)
        // sendMessageは非推奨になったため、ChatComponentsなどを使用するのが望ましいが、ここでは簡単な例として文字列で説明
        // player.sendSystemMessage(net.minecraft.network.chat.Component.literal(message)) // 1.19.4以降の例
    }
}

// 他のForgeイベントハンドラもここに追加していく
// @SubscribeEvent
// fun onLivingAttack(event: LivingAttackEvent) { ... }

}
“`

  • @Mod.EventBusSubscriber: このアノテーションを objectclass に付けると、Forgeが起動時にその中に定義された @SubscribeEvent メソッドを自動的に探し、指定されたイベントバスに登録してくれます。modidbus を指定する必要があります。bus = Mod.EventBusSubscriber.Bus.FORGE は Forge Event Bus を意味します。bus = Mod.EventBusSubscriber.Bus.MOD とすると Mod Event Bus になりますが、通常Mod Event Busは addListener で登録します。
  • @SubscribeEvent: このアノテーションが付けられた関数がイベントハンドラとして認識されます。関数の引数は、処理したいイベントの型と一致させる必要があります。

主要なMod初期化イベント (FMLCommonSetupEvent) の利用

先ほど少し触れましたが、FMLCommonSetupEvent はModの主要な初期化処理を行うのに適したイベントです。Registryへの登録が完了し、Forgeが基本的なセットアップを終えた後に発生します。クライアント側とサーバー側の両方で実行されます。

このイベントハンドラはMod Event Busに登録するため、YourModIdMod オブジェクトの init ブロックから MOD_BUS.addListener(::commonSetup) のように登録します。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdMod.kt

import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent // イベントクラスをインポート

@Mod(MODID)
object YourModIdMod {
init {
val eventBus = MOD_BUS

    // FMLCommonSetupEvent リスナーを登録
    eventBus.addListener(::commonSetup)

    // DeferredRegisterをModイベントバスに登録
    YourModIdItems.REGISTRY.register(eventBus)
    YourModIdBlocks.REGISTRY.register(eventBus)
}

// FMLCommonSetupEvent のイベントハンドラ関数
private fun commonSetup(event: FMLCommonSetupEvent) {
    // ここでは、Registryオブジェクト自体ではなく、Registryに登録された**後の**処理を行う
    // 例: レシピの登録、エンティティ属性の登録、ネットワークメッセージハンドラの登録など

    // 遅延実行したい処理をenqueueWorkに渡す
    event.enqueueWork {
        // 例: ポーション効果のRegistryオブジェクトを取得して何かする (実際にはもっと複雑な処理に使う)
        // val speedEffect = ForgeRegistries.POTION_EFFECTS.getValue(ResourceLocation("minecraft", "speed"))
        // println("Speed effect registry name: ${speedEffect?.registryName}")
    }

    println("$MODID: Common setup complete.")
}

}
“`

event.enqueueWork {} は、ゲームのメインループとは別のスレッドで安全に実行されるように処理をキューに入れるためのものです。Registryの参照など、ゲームデータにアクセスする処理はこれを使って安全に実行することが推奨されます。

イベントハンドラクラスの登録

@Mod.EventBusSubscriber アノテーションを使った方法は便利ですが、手動でイベントハンドラクラスのインスタンスをForge Event Busに登録することも可能です。これは、コンストラクタで依存関係を受け取るようなクラスベースのイベントハンドラを作成する場合に有用です。

“`kotlin
// src/main/kotlin/com/yourname/yourmodid/YourModIdMod.kt の init ブロック内

// PlayerLoggedInEventハンドラを手動で登録する場合 (上記の@EventBusSubscriberの代わり)
// MinecraftForge.EVENT_BUS.register(YourModIdEvents) // YourModIdEventsオブジェクトを登録
“`

@Mod.EventBusSubscriber は内部的にこの登録を行ってくれます。オブジェクトの場合は @Mod.EventBusSubscriber が最も簡単です。クラスの場合は、インスタンスを作成して手動で登録するか、またはDependency Injectionフレームワークと連携させる方法もありますが、初心者は @Mod.EventBusSubscriber を使うのが良いでしょう。

イベントシステムはMod開発において非常に強力なツールです。ゲーム内のほぼ全ての出来事に対応するイベントが存在するため、イベントを使いこなすことでModの機能を柔軟に拡張できます。

9. Modをテストする

コードを書き、リソースを配置したら、実際にゲーム内でModが動作するかを確認する必要があります。IntelliJ IDEAのGradle設定を使って、簡単に開発中のMinecraftクライアントまたはサーバーを起動できます。

IntelliJ IDEAの実行構成 (runClient, runServer)

Forge MDKをインポートし、gradlew genIntellijRuns を実行した際に、IntelliJ IDEAにはGradleによって自動的にいくつかの実行構成(Run Configuration)が作成されています。これらはIntelliJ IDEAウィンドウの右上にあるドロップダウンメニュー(再生ボタンやデバッグボタンの隣)で確認できます。

主要な実行構成は以下の通りです。
* runClient: 開発中のModをロードしたMinecraftクライアントを起動します。一人プレイでModをテストする際に使用します。
* runServer: 開発中のModをロードしたMinecraftサーバーを起動します。マルチプレイヤー環境での動作確認や、サーバーサイド専用の機能テストに使用します。
* runData: データ生成タスクを実行します(後述)。
* genIntellijRuns: MDKインポート時に実行したGradleタスク。再度実行すると設定を再生成します。

開発環境でのModの実行

Modをテストするには、以下の手順で runClient 実行構成を使用します。

  1. IntelliJ IDEAの右上にあるドロップダウンメニューから runClient を選択します。
  2. 緑色の「再生」ボタンをクリックするか、「Run」メニューから「Run ‘runClient’」を選択します。

IntelliJ IDEAはGradleを使って必要なファイル(Modのコンパイル結果など)を準備し、Minecraftクライアントを起動します。初めて起動する際には、Minecraft本体やForgeのダウンロード、ゲームデータのセットアップなどが行われるため、時間がかかることがあります。

成功すると、通常のMinecraftランチャーを介さずに、Forgeが導入された開発環境用のMinecraftクライアントが起動します。ゲームのタイトル画面が表示されたら成功です。

Modが正しく読み込まれたかの確認

Minecraftのタイトル画面で、「Mods」ボタン(または同様の項目)を探してクリックしてください。Modリストが表示されます。

あなたのModがリストに表示されているか確認してください。mods.toml で設定した displayNameversion が正しく表示されているはずです。もしリストに表示されない場合は、mods.toml の設定 (modId がコードと一致しているかなど) や、メインModクラスの @Mod アノテーション、DeferredRegister の登録などが正しいか確認してください。

作成したアイテムやブロックの確認

ゲーム内に入り、クリエイティブモードにしてインベントリを開いてみてください。

標準のクリエイティブタブ(検索タブなど)を開き、あなたのModで追加したアイテムやブロックがリストに追加されているか確認します。mods.tomldisplayName や、言語ファイル (.lang ファイル) で定義した名前で表示されているはずです。

アイテムやブロックが見つからない場合は、Registryへの登録コード (YourModIdItems, YourModIdBlocksregister 呼び出しと、YourModIdModREGISTRY.register(eventBus))、そしてリソースファイル (lang, textures, models, blockstates) のパスとファイル名が正しいか、スペルミスがないかなどを徹底的に確認してください。特にリソースパスは assets/yourmodid/... のようにMod IDを含める必要があることに注意してください。

ゲームがクラッシュした場合や、アイテム/ブロックが見つからない場合などは、IntelliJ IDEAのRunウィンドウに表示されるログや、プロジェクトディレクトリ直下に生成される run/logs/latest.log ファイルを確認することがトラブルシューティングの第一歩です。エラーメッセージやスタックトレースから原因を特定する手がかりを得られます。

10. 次のステップと発展

基本的なアイテムとブロックの作成に成功したら、Mod開発の楽しさはさらに広がります。ここでは、今後の開発で挑戦できるステップをいくつか紹介します。

  • より複雑なアイテムやブロック:
    • ツール、防具、武器などのアイテムクラスを継承したカスタムアイテム。
    • 右クリックで特殊な効果を発動するアイテム。
    • GUIを持つブロック(チェストやかまどのようなもの)。Tile Entity(またはBlock Entity)という仕組みを理解する必要があります。
    • 特殊な状態変化を持つブロック(作物の成長や溶ける氷など)。
  • カスタムレシピの追加: 作業台やかまどであなたのアイテムやブロックをクラフト・精錬できるように、レシピを追加します。これはJSONファイル(データパックの仕組みを利用)またはコードで行えます。Forgeにはレシピ登録のAPIがあります。
  • GUI (Graphical User Interface) の作成: カスタムブロックやアイテムと連携するGUIを作成します。これには、サーバーサイドでアイテムのやり取りを管理する Container(または Menu)と、クライアントサイドでGUIを描画する Screen クラスを作成する必要があります。
  • エンティティ (モブなど) の作成: 独自のモブ、発射物、特殊効果エンティティなどを追加します。エンティティの動き、AI、モデル、テクスチャなどを定義する必要があります。
  • ワールド生成への介入: 新しいバイオーム、構造物、鉱石の生成などをModで追加または変更します。World GenerationやFeature/PlacementModifierの概念を理解する必要があります。
  • データジェネレーターの活用: 手動でJSONファイルを編集する代わりに、コードでブロックステート、モデル、レシピなどのリソースファイルを自動生成する仕組みです。大規模なMod開発では必須のツールとなります。Forge MDKにはデータジェネレーターの基本的な設定が含まれています (runData 実行構成)。
  • Kotlinの高度な機能の活用: 拡張関数、データクラス、sealed class、コルーチンなど、Kotlinのモダンな機能をMod開発に積極的に取り入れることで、コードをより簡潔かつ安全に記述できます。例えば、RegistryObjectのコレクションに対して拡張関数を定義するなど。
  • バージョン管理 (Git) の実践: Mod開発プロジェクトをGitで管理しましょう。これにより、変更履歴の追跡、以前の状態への復帰、実験的な機能の開発などが容易になります。GitHubなどのサービスを利用すれば、コードのバックアップや公開もできます。
  • コミュニティリソースの活用:
    • Forge Documentation: Forgeの公式ドキュメントはMod開発のバイブルです。APIの詳細や高度なトピックについて調べることができます。
    • Forge Forums & Discord: 他のMod開発者と交流し、質問したり、問題の解決策を探したりできます。
    • 他のModのソースコード: GitHubなどで公開されている他のForge Modのソースコードを読むことは、非常に良い学習方法です。どのように複雑な機能が実装されているかを知ることができます。

これらのステップはそれぞれ奥が深く、学習が必要ですが、一つずつ取り組むことであなたのMod開発スキルは大きく向上するでしょう。

11. トラブルシューティングとよくある問題

Mod開発はスムーズに進むことばかりではありません。様々な問題に遭遇する可能性がありますが、多くの場合、ログを注意深く読んだり、基本的なチェックリストを確認したりすることで解決できます。

  • Gradle sync の失敗:
    • インターネット接続を確認してください。Gradleは依存関係(Forge本体やライブラリ)をダウンロードします。
    • build.gradle.kts の構文エラーや、指定したForge/Minecraft/JDKのバージョンが間違っていないか確認してください。
    • IntelliJ IDEAのGradleウィンドウで「Offline mode」が有効になっていないか確認してください。
    • ~/.gradle/caches/ ディレクトリを削除してから再度同期を試すのも有効な場合があります(ただし時間がかかります)。
  • ゲーム起動時のクラッシュ (ログの見方):
    • ゲームが起動中にクラッシュした場合、IntelliJ IDEAのRunウィンドウの出力か、プロジェクトの run/logs/latest.log ファイルにエラー情報が記録されています。
    • ログの一番下から遡って、「Error」や「Exception」という単語を探してください。特に Caused by: の行は根本原因を示していることが多いです。
    • NullPointerException, IllegalStateException, Registry entry not found などのエラーメッセージをよく読んでください。どのクラスやメソッドでエラーが発生したか、どのRegistryエントリが見つからないかなどが記載されています。
    • あなたのMod IDやクラス名がエラーメッセージに含まれている場合は、あなたのコードに問題がある可能性が高いです。
  • アイテムやブロックが表示されない:
    • Registryへの登録: DeferredRegister を作成し、アイテム/ブロックを register() メソッドでリストアップし、YourModIdMod オブジェクトの init ブロックで REGISTRY.register(eventBus) を呼び出しているか確認してください。
    • Mod IDの一致: build.gradle.kts, mods.toml, YourModIdModMODID 定数、そしてリソースディレクトリ (assets/yourmodid/...) の yourmodid が全て正確に一致しているか確認してください(大文字・小文字も含む)。
    • リソースファイルのパスとファイル名: assets/yourmodid/lang/, assets/yourmodid/textures/item/, assets/yourmodid/textures/block/, assets/yourmodid/models/item/, assets/yourmodid/models/block/, assets/yourmodid/blockstates/ ディレクトリの下に、適切な名前 (登録名.json, 登録名.png) でファイルが配置されているか確認してください。特に、モデルファイル内で参照しているテクスチャや親モデルのパスが正しいか確認してください。
    • タイプミスの確認: コード、JSONファイル、ファイル名にタイプミスがないか、慎重に確認してください。特にResourceLocation (yourmodid:my_item) のコロン : の使い方は重要です。
  • コンパイルエラー:
    • IntelliJ IDEAのエディタや「Build」ウィンドウに表示されるエラーメッセージを読んで、原因となっているコードの場所とエラーの種類を特定してください。
    • 必要なクラスやメソッドが存在するか(Forgeのバージョンと合っているか)、インポートが正しく行われているか確認してください。
  • バージョン不整合:
    • 使用しているMinecraftのバージョン、Forgeのバージョン、Forge MDKのバージョン、そして要求されるJDKのバージョンが全て互換性があるか確認してください。Forge公式サイトで互換性情報を確認できます。

トラブルシューティングはMod開発の一部です。忍耐強くログを読み、一つずつ可能性を潰していくことが重要です。また、インターネットでエラーメッセージを検索すると、同じ問題に遭遇した他の開発者による解決策が見つかることが多いです。

12. まとめ

この記事では、Minecraft Forgeを使い、KotlinでMod開発を始めるための基本的なステップを詳細に解説しました。開発環境の準備、プロジェクト構造の理解、Modのエントリポイント作成、RegistryとDeferredRegisterの概念、そしてシンプルなアイテムとブロックのコードとリソースの作成方法を学びました。

Mod開発は、プログラミングスキルを実践的に学ぶのに最適な方法の一つです。Minecraftという具体的な目標があるためモチベーションを維持しやすく、すぐに結果(ゲーム内での変化)を確認できるため達成感も得やすいです。Kotlinはその簡潔さと安全性で、Mod開発をより効率的かつ快適にしてくれます。

もちろん、この記事で触れた内容はMod開発のほんの一端に過ぎません。しかし、ここまでの知識があれば、Forgeの公式ドキュメントや他のModのソースコードを読み進めるための基礎は十分に築けているはずです。

ぜひ、この記事を足がかりに、あなただけのユニークなMinecraft Modを開発してみてください。最初は小さなアイデアから始めて、少しずつ機能を拡張していくのがおすすめです。

Mod開発の世界は広大で、学ぶことは尽きません。新しい発見や挑戦が常にあなたを待っています。このガイドが、あなたの素晴らしいMod開発の旅の始まりとなれば幸いです。

頑張ってください!そして、Minecraft Mod開発を楽しんでください!


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール