Minecraft1.21.1 Mod開発#3:基礎編①(Modの構造を知ろう)

基礎

こんにちは!
初めましての方は初めまして。
___です。

Minecraft(マイクラ)のMODを実際に作りながら、読者の皆さんにも一緒に作ってもらえるような、実践型連載の第三弾!

前回までで環境構築ができたので、今回からいよいよ!Modの制作に入っていこうと思います!
今回の目標は・・・

— 進捗を表示しよう! —

ですがその前に・・・
Modってそもそもどうやってできてるの?
なんで動くの?
どんなファイルを作ればいいの?

そんな疑問に少しばかりですが応えられるような、Modの構造についての解説をさせていただこうと思います!

(今回やることだけやりたいよって人はここまで飛ばしても大丈夫です)

※注意※

筆者は本物の専門家ではありません。
あくまで一個人として、筆者自身がわかりやすい解釈を踏まえて記載します。
なので完璧な正解である表現ではないかもしれません。
あくまでわかりやすさ優先であることを理解して読み進めてください。

ModおよびMinecraftの基礎知識

Minecraftってどうやってデータを処理してる?

さて、Minecraftをやっていると何気なくいろいろなことをやっていますね。
まずは木を切って、原木を材木にし、作業台を作り・・・。
このような動作、それら全てがデータとして処理されているのです。

そんなデータの世界。
もちろんそこにはプログラミングが関わってきます。

それなら、例えば「木を切る」なら木を切るためのプログラムが、「土を掘る」なら土を掘るためのプログラムが組まれているように思えます。
また「原木から材木にする」ためのプログラムが、「材木を作業台にする」ためのプログラムが組まれているようにも思えます。

それってものすごく莫大なデータ量なのでは?
プログラミングも莫大な量を書かなければいけないのでは?

しかし!実はマイクラはそうではないのです!

じゃぁどうやって処理しているのか?
そこでカギを握るのが、「リソース(resources)」という考え方なのです。

「プログラム(脳)」と「リソース(見た目・データ)」

プログラムがさまざまなものを動かすための「脳」であることは、理解しやすいと思います。
じゃぁその「脳」に全て書いておけばいいのでは?と思うかもしれません。

確かに世のプログラムは多くがそういう作りになっています。

しかし、もしプログラムが直接、画面に表示される文字を変えていたら。もしプログラムが直接、ブロックのテクスチャ(見た目)を変えていたら。
それに変更があったときにどうしますか?

膨大なプログラムの中から、当てはまる場所を探し、その中の文字の色やテクスチャを変更することになります。
また、プログラムは基本的に「コンパイル」と言って、「これで完成だからちゃんと動くようにパッケージにまとめといてね」ということもしています。
プログラムが変わるということは、そのコンパイルもやり直さなければいけないのです。
しかもそれがもし多言語化(つまり全ての単語を翻訳したデータ)を追加するとなれば、全ての箇所に修正を施さなければならない。

あまりにも気が遠くなりますね・・・。

そこで!マイクラでは、プログラムは「基本構造とリソースからのデータの読み出し」を担い、リソースは「設定やテキストなどをJSONファイル(リソースファイル)に書いておき、プログラム側から読み込んだ時に動くようにしておく」という仕組みが徹底されています。
それのおかげで、根幹のプログラムは書き直さなくても、リソースで変更点を変えられる、という仕組みで動いているのです。

プログラムの役割

先ほど書いたようにマイクラのプログラムは「基本構造とリソースからのデータの読み出し」を担っています。

じゃぁマイクラのMod開発ではテキストコードを書くプログラミングしなくてもできるの?

答えはYesであり、Noでもあります。
確かにリソースからのデータの読み出しを行うのは、そもそものマイクラやNeoForgeがやってくれます。
つまりそこではプログラミングをする必要はなく、ただリソースファイルとして「.json」ファイルを作ればいいだけです。
(まぁでもプログラミング全然したことがないと、この.jsonファイルを作るのもプログラミングじゃん!って思ったりもしますが・・・)

さてここからが本題。
じゃぁプログラミングしないのかというと、そうではないのです。
確かに簡単なものであればプログラミングは必要ありません。リソースだけで完結します。
しかしリソースはあくまで「設定やテキストなどをJSONファイル(リソースファイル)に書いておき、プログラム側から読み込んだ時に動くようにしておく」というもの。
つまり「動きそのものやルールを作るとき」に関しては、Javaのコードを書く、つまりプログラミングしなくてはいけないのです!

例えば・・・

  • プレイヤーがブロックを右クリックしたら爆発 → つまり「動き」
  • プレイヤーはジャンプできなくなる → つまり「ルール」

これらは動きそのものやルールのため、Javaでのプログラミングが必要になります。
(見た目や設定ではないんです)

リソースの役割

リソースは、プログラムとは違い、動きやルールを作ることはできません。
しかし、例えば・・・

  • ブロックのテクスチャ → つまり「見た目」
  • ブロックの破壊音 → つまり「音」
  • アイテムの表示名 → つまり「文章」
  • 進捗の解除条件 → つまり「設定(データ)」

これらが全てリソースに分類されます。

マイクラでテクスチャが無ければ、何も見えない世界になってしまいます。
マイクラで文章が無ければ、いったい何のアイテムを持っているのかもわかりません。

つまりリソースは、マイクラの見た目や状態を形作る上で欠かせないものなのです!

プログラムとリソースはどうやって連携してるの?

ここまでプログラムとリソースの話をしてきましたが、そもそもの話として、この二つはどうやって連携しているのかという話です。

と、言いたいのですが、正直なところはマイクラの根幹システムの話ですので、あまりに専門的すぎて私は理解できていません(

それでもマイクラのModが動く理由。

それこそがマイクラの根幹システムが優れている点です!

マイクラは根幹システム側が、フォルダの階層構造(フォルダの名前)を自動で判別しています。
「このフォルダの中のこの名前のフォルダだから、中身はこれに違いない!よし、それに合わせて中身のファイルを解析するぞ!」
と自動判別しているのです。

なので「java」というフォルダの中に入っていれば「この中の物は全て動作やルールに関わるものだ!」となり、「resource」というフォルダの中に入っていれば「この中の物は全て見た目や設定などのリソースだ!」となるわけです。

実際のフォルダ階層はこんな感じ

src/
 └─ main/
     ├─ java/                 ← ① Javaプログラムの置き場
     └─ resources/            ← ② リソースの置き場

こうやってフォルダ分けしておけば、マイクラが勝手に読み込んでくれます!

参考までに、本格的になるとこんな感じのフォルダ階層になるようです。
※ただし、現在同じように空のフォルダだけを作るのはNGです。
※空のフォルダがある場合にも、マイクラは自動で「ファイルの無い壊れたModは読み込むのをやめておこう」と処理をスルーしてしまいます。あくまで以下は参考です。

src/
 └─ main/
     ├─ java/                 ← Javaプログラムの置き場(動的ロジック)
     └─ resources/            ← リソースの置き場(静的データ)
         ├─ META-INF/         ← MODの基本情報設定
         │   └─ neoforge.mods.toml
         ├─ assets/           ← アセット(見た目・音・言語)
         │   └─ <modid>/
         │       ├─ blockstates/
         │       ├─ font/
         │       ├─ lang/
         │       ├─ models/
         │       ├─ sounds/
         │       └─ textures/
         └─ data/             ← データ(ゲームルール・サーバー処理)
             └─ <modid>/
                 ├─ advancement/   ★今回使うフォルダ
                 ├─ loot_table/
                 ├─ recipe/
                 └─ tags/

Mod開発の留意点

ここで1つ大事なことです。
解説の通り、マイクラはフォルダの名前と階層構造から、自動で中身が何者なのかを判別します。

ということは、もし「フォルダ名が違った」り、「フォルダの階層がズレていた」りしたとき、マイクラはどうなるでしょう?

正解は、「そのModやファイルを無かったことにしてスルー」します。

普通のプログラムだと、エラーを吐いてクラッシュ、というのが多いですが、マイクラの場合にはそうはならず、ただ「これはゲームには使えないデータだ」ということになり処理しません。

つまりエラーも出ずにマイクラは平常運転で起動します!
ただModのリソースやプログラムが読み込まれません!

そう考えると、マイクラModを作る上で、フォルダの名前とフォルダの階層はかなり厳密です。
これが少しでも違うといけない、ということです。

これからModを作っていきますが、このフォルダの扱い方には十分注意して取り組みましょう!

はじめてのMod(進捗を表示しよう!)

さぁ!いよいよModの作成です!

すでにModの基礎構造はダウンロードしたNeoForgeでできていますが、今回の目標「進捗の表示」のために、必要なものを追加していきましょう!

まずはMod開発で一番神経を使う「フォルダ階層構造」の作成です。

フォルダの階層構造

以下が今回の目標になる階層構造です。

src/
 └─ main/
     └─ resources/
          └─ data/
               └─ <modid>/   ← 自分のMOD ID(筆者の場合はpractisemymod)
                    └─ advancement/  ← 進捗を入れるフォルダー
                         └─ hello_minecraft_mod_life.json  ← これがリソースファイル

※注意※
ここに記載のないフォルダを全て削除しろという意図はありません!
今回作る部分だけを抜き出しています。

必要なフォルダ、ファイルの作成

新しく作らなくてはいけないのは「data」フォルダ以下にあるフォルダとファイルですね。

VSCodeでのフォルダの作り方は、まず起動した画面でフォルダ「resources」を開きます。

そうすると、現在「resources」フォルダの中には「assets」フォルダしかないため、一行になってしまいます。
この一行に書かれてしまっている「resources」の文字の上で右クリックします。

そうしたら、出てきたメニューの中にある「新しいフォルダー…」を押します。

すると、エクスプローラーの中に文字を入力できる新しいフォルダーができるので、名前を付けます。
今回は「data」です。
全て小文字です。間違えないように気を付けましょう。

フォルダができたら、同じように作った「data」フォルダの文字の上で右クリックをして、「新しいフォルダーを作成」をします。
今度は「自分のModのID」がフォルダの名前になります。

ここで、自分のModのIDを間違えないために、コピペしましょう。
エクスプローラーの中の「gradle.properties」ファイルを開いてみましょう。

少し下にスクロールすると、「mod_id」という記載があります。
それのイコールより右側(筆者の場合には「practicemymod」)をコピーしましょう。

そうしたら、先ほどの「data」の中に、今コピーした名前で新しいフォルダーを作成しましょう。

そしてさらにその中に「advancement」という新しいフォルダーも作成しましょう。

そこまでできたら次は「advancement」フォルダの中に新しいファイルを作成します。

「advancement」という文字の上で右クリック。
出てきたメニューの中から「新しいファイル…」を押します。

フォルダーの時と同じように名前の入力ができるようになると思うので、そこに任意の名前を付けましょう。
(ファイルの名前には決まりはありません。しかしスペースが入るとエラーになります。名前の間をあけたい場合には「_」か「-」で代用しましょう。)

筆者は、このファイルは何をするものか分かりやすいように、「hello_mmlife.json」にしました。
この時、名前だけではなく拡張子も一緒に記載しましょう!
今回の場合には「.json」です。

ここまで出来たら今一度、階層構造を確認しましょう。

src/
 └─ main/
     └─ resources/
          └─ data/
               └─ <modid>/   ← 自分のMOD ID(筆者の場合はpracticemymod)
                    └─ advancement/  ← 進捗を入れるフォルダー
                         └─ hello_minecraft_mod_life.json  ← これがリソースファイル

あっていれば、次はJSONファイルの中身です。

JSONファイルのデータの作成

先ほど作ったJSONファイル(.json)の中身を作りましょう!
と言っても今回はコピペしてみましょう。

以下を全部コピーして、JSONファイルの中に張り付けてみましょう!

{
  "display": {
    "icon": {
      "id": "minecraft:grass_block"
    },
    "title": {
      "text": "Hello Minecraft Mod Life!",
      "color": "green",
      "bold": true
    },
    "description": {
      "text": "初めてのMOD開発の一歩を踏み出した!"
    },
    "frame": "task",
    "show_toast": true,
    "announce_to_chat": true
  },
  "criteria": {
    "auto_unlock": {
      "trigger": "minecraft:tick"
    }
  }
}

これは進捗(実績)を作る内容になっています。

詳しいことはまた別の機会に、しっかり進捗を達成する内容を作るときに解説したいと思いますが、簡単に何をしているかの解説です。

"title": {
  "text": "Hello Minecraft Mod Life!",
  "color": "green",
  "bold": true
},

ここでは進捗のタイトルを決めています。
進捗のタイトルはチャット欄にも表示される文字列です。

"description": {
  "text": "初めてのMOD開発の一歩を踏み出した!"
},

ここでは進捗の説明文を決めています。
進捗の確認画面を出したときに、マウスをアイコンに乗せると表示される文章です。

"criteria": {
  "auto_unlock": {
    "trigger": "minecraft:tick"
  }
}

ここで「いつ進捗達成されるか」を決めています。
今回は「マインクラフトに初めてログインした瞬間」をトリガーにしています。

今回はこれにてJSONファイルも完成し、必要なものは全て完成です!

起動テスト(確認をしてみよう!)

起動テストをしてみましょう!
やり方は前回と一緒です。

左のメニューのGradleを押して、「Tasks」>「mod development」の順で階層を開きます。

その中にある「runClient」の上にマウスを乗せると右端に出てくる三角形「Runs the client Minecraft run configuration」を押します。

少し待って、マイクラが起動できたら、新しいワールドを作成しましょう!

今回はModの要素がわかりやすいように、クリエイティブモードで、ピースフルにしてます。
(ここでコマンドもオンにしておくと、今後の確認がしやすいです)
ワールドは軽いのでスーパーフラット。余計な村などが生成されないように構造物はオフにしました。

これでマイクラのワールドを作成すると・・・

進捗が達成されます!(チャットにメッセージが表示されるときとされないときがあるようです)

「L」キーで進捗画面を開くと、そこにもちゃんと載っています!
(今回はちゃんと背景を設定していないので、「テクスチャが無いよ」という意味の黒と紫の市松模様が出ています)

ということで、進捗を作ることができました!

今回は以上になります。
お疲れ様でした。

おわりに&次回予告

今回は説明が長くなってしまったので、実践的にModに触れたのは少しになってしまいました。
今後はもっと実践を多く取り入れたいですね!
理論はその途中で少しづつ挟めばいい気がしています。

なので次回はアイテムの追加をしたいですね。
アイテムが追加されるのはModの醍醐味っぽい気がするんですよね。

今回はありがとうございました。
次回もお楽しみに!

コメント