Minecraft1.21.1 Mod開発#6:基礎編④(独自のアイテムをタブに登録しよう!)

基礎

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

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

前回まででオリジナルのアイテムを作ることができました!
しかし今のところコマンドでしかアイテムを出せない状態・・・。
ということで今回の目標は

— クリエイティブタブにアイテムを登録しよう! —

早速始めましょう!
Let’s Minecraft Mod Life!

クリエイティブタブとは?

そもそもクリエイティブタブって?

筆者はMod作りで言葉が分からないことも多かったです。
この「クリエイティブタブ」もその1つでした。

クリエイティブタブって何かというと・・・

これです。
このインベントリの上や下に並んでいるこれの事です。
これに登録することで、コマンドを打たなくてもアイテムを取得できるようになるわけですね!

クリエイティブタブへの登録方法

さて、このクリエイティブタブへの登録ですが、Mod制作の場合には3通りの状況があります。

1つ目は「既存(マイクラの標準)のタブに登録する」
2つ目は「オリジナルのタブに登録する」
3つ目は「既存のタブにもオリジナルのタブにも登録する」

しかし3つ目は、「両方に登録するために特別なことをしなきゃいけない」ということはありません!
なので1つ目と2つ目の合体したものが3つ目、という感じです。

ではまずは「既存のタブに登録」していきましょう!

既存(マイクラの標準)のタブにアイテムを登録する

アイテムを登録するためには、既存のシステムへ、「このアイテムも一緒にグループに入れてほしい!」と教えてあげる必要があります。
そしてただ教えればいいというわけでもなく、「既存のクリエイティブタブの中でも、このクリエイティブタブの時にやってほしい」という指定もしてあげないといけません。

これはシステムへの動作の指定なので、「java」フォルダ内の階層に書きます。

今回も新しくファイルを作っていきましょう。
階層は下のようにして、「AddExistingCreativeModeTab.java」を作りましょう。

src/
 └─ main/
     └─ java/
         └─ com/
             └─ mypractice/
                 └─ mymod/
                     ├─ AddExistingCreativeModeTab.java ← 今回作るJavaファイル
                     ├─ ModItems.java
                     ├─ Config.java
                     ├─ PracticeMyMod.java
                     └─ PracticeMyModClient.java

こんな感じ。

そうしたらアイテムを追加するための処理を書いていくわけですが、
今回は「鋼鉄(Steel)」を「材料」タブに追加しましょう!

以下をさっき作った「AddExistingCreativeModeTab.java」に書きましょう。
(コピペする場合には、一番最初の「package com.mypractice.mymod」は自分のファイルがある階層に合うように書き換えてくださいね)

package com.mypractice.mymod;// ← ここはコピペする場合は書き換えが必要なので注意!

import net.minecraft.world.item.CreativeModeTabs;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;

public class AddExistingCreativeModeTab {
    // イベントを登録するメソッドを追加(スイッチ役)
    public static void register(IEventBus modEventBus) {
        modEventBus.addListener(AddExistingCreativeModeTab::addCreative);
    }
    
    // 実際にアイテムを追加する処理
    public static void addCreative(BuildCreativeModeTabContentsEvent event) {
        // もし「材料(INGREDIENTS)」タブを開いた時だったら
        if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
            event.accept(ModItems.STEEL);
        }
    }
}

このコードについても少し解説です。
(importは必要な要素を取得しているものです。解説はそれ以降の部分にします)

public class AddExistingCreativeModeTab {

... 中略 ...

}

この一番外側の部分は、Javaファイルの中で、処理のまとまりとして定義している部分です。
「public」なので他のJavaファイルからこの処理のまとまりを読み出すことができる、ということです。

なぜ読み込めるようにしなければいけないかというと・・・。

そもそもModが起動するときに読み込まれている大元のJavaファイルは「Config.java」「<Mod名>.java」「<Mod名>Client.java」なのです。
(筆者の場合には「Config.java」「PracticeMyMod.java」「PracticeMyModClient.java」となります)
なので他のJavaファイルは、実は直接読み込んではいないのです。

ではなぜ新しく作った「ModItems.java」の内容も反映されているのか。
それは「<Mod名>.java」の中に「ModItemsを読み込んでね!」という処理が書かれているからです!

なので今回の「AddExistingCreativeModeTab」も、読み込んでもらうための処理を書かなければいけません。
それはあとでやっていきましょう。

// イベントを登録するメソッドを追加(スイッチ役)
public static void register(IEventBus modEventBus) {
    modEventBus.addListener(AddExistingCreativeModeTab::addCreative);
}

この部分は他から読み込まれた時に、即座に中の処理を実行するんじゃなくて、特定のタイミングでだけ実行するんだよ、というスイッチを登録している場所です。

public static void addCreative(BuildCreativeModeTabContentsEvent event) {

... 中略 ...

}

この部分は新しくアイテムをタブに登録するルールを決めるためのものです。
この中に書かれたものがルールになる、という感じですね。

// もし「材料(INGREDIENTS)」タブを開いた時だったら
if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
... 中略 ...
}

そしてこれが、実際のルールを決めているコードになります。
「if」は「条件分岐」の書き方であり、「条件によって処理を分岐する」ための物です。
ただ、今回のように「if」だけで構成されている場合には、「条件に当てはまっている場合には処理して、そうじゃないときは何も処理しない」という感じになります。

この条件分岐の時の条件が「if」のあとの「()」の中の「event.getTabKey() == CreativeModeTabs.INGREDIENTS」です。

「==」は比較演算子の1つ。今回は「左と右が同じだったら」という条件を作るために使われています。
左側の「event.getTabKey()」は、全体の中の「public static void addCreative(BuildCreativeModeTabContentsEvent event)」の部分で、これが動いたときに、何かしらの情報が「()」の中の「event」に格納されています。
その「event」に「.」でくっついている「getTabKey()」があることで、「event」に格納されている情報の中から、どのタブが押されたのかの情報だけを取得してきてくれます。
そして右側の「CreativeModeTabs.INGREDIENTS」は、クリエイティブタブの材料(INGREDIENTS)タブという情報を取得してくれます。
この左側と右側が同じだったらというコードなので、「今回押されたクリエイティブタブが材料タブだったら条件に当てはまっている」ということになるのです。

そして条件が合っていたら、中に書いてあるこれが実行されるわけです。

event.accept(ModItems.STEEL);

これは「event」(今回でいえばクリエイティブタブの材料タブ)に「ModItems」で定義されている「STEEL」を「accept(受け入れる)」してくださいね、という処理です。

コードはこんな感じ。

それでは途中でも出てきたように「AddExistingCreativeModeTab」も動くように読み込んでもらいましょう。
まずは「<Mod名>.java」(筆者の場合には「PracticeMyMod.java」)を開きましょう。
開いたら少し下の方にスクロールしましょう。

コードの中から「ModItems」と書いてある場所を探して、その下に以下のコードを張りましょう。

AddExistingCreativeModeTab.register(modEventBus);

これができたら保存して、テスト起動してみましょう。

マイクラが起動したら、まずはインベントリを開いてみましょう。

インベントリを開いたら、クリエイティブタブの「材料」を押して、一番下までスクロールしてみましょう。

一番最後に「鋼鉄」が追加されていれば完成です!

オリジナルのタブにアイテムを登録する

次はオリジナルのタブを作り、そこにアイテムを登録する方法です。
Modを作れば、新しいアイテムたちは全部まとまって表示された方が分かりやすい時もありますよね。

まずやらなければいけないのは「オリジナルのクリエイティブタブの作成」です!

オリジナルのクリエイティブタブの作成

まずはJavaファイル「ModCreativeModeTabs.java」を用意します。
フォルダ階層はこんな感じ。

src/
 └─ main/
     └─ java/
         └─ com/
             └─ mypractice/
                 └─ mymod/
                     ├─ AddExistingCreativeModeTab.java
                     ├─ ModCreativeModeTabs.java ← 今回作るJavaファイル
                     ├─ ModItems.java
                     ├─ Config.java
                     ├─ PracticeMyMod.java
                     └─ PracticeMyModClient.java

そしたら「ModCreativeModeTabs.java」ファイルの内容は以下のように書きます。
(コピペする場合には、一番最初の「package com.mypractice.mymod」は自分のファイルがある階層に合うように書き換えてください。また途中2か所の「PracticeMyMod」の部分も、自分のMod名に書き換えてください)

package com.mypractice.mymod;// ← ここはコピペする場合は書き換えが必要なので注意!

import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;

public class ModCreativeModeTabs {
    // クリエイティブタブを登録するためのレジストリを用意
    public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS =
        DeferredRegister.create(Registries.CREATIVE_MODE_TAB, PracticeMyMod.MODID);// ← ここの「PracticeMyMod」の部分も書き換えが必要なので注意!
    
    // ★自作クリエイティブタブの登録
    public static final DeferredHolder<CreativeModeTab, CreativeModeTab> MYMOD_TAB =
        CREATIVE_MODE_TABS.register("mymod_tab", () -> CreativeModeTab.builder()
            // タブのアイコン(手持ちのアイテムから指定。ここでは炭製ダイヤモンド)
            .icon(() -> new ItemStack(ModItems.COAL_DIAMOND.get()))
            // タブの表示名(langファイルで指定するキー名)
            .title(Component.translatable("itemGroup." + PracticeMyMod.MODID + ".mymod_tab"))// ← ここの「PracticeMyMod」の部分も書き換えが必要なので注意!
            // タブの中に並べるアイテムのリスト
            .displayItems((itemDisplayParameters, output) -> {
                output.accept(ModItems.COAL_DIAMOND.get());
            })
            .build()
        );

    // メインのクラスから呼び出すための接続スイッチ
    public static void register(IEventBus eventBus) {
        CREATIVE_MODE_TABS.register(eventBus);
    }
}

そうしたらこれも、「AddExistingCreativeModeTab」と同じように、動かすために読み込んでもらわないといけません。
まずは「<Mod名>.java」(筆者の場合には「PracticeMyMod.java」)を開きましょう。
開いたら少し下の方にスクロールしましょう。

先ほど追加したコード「AddExistingCreativeModeTab.register(modEventBus);」の下に、以下を追記しましょう。

ModCreativeModeTabs.register(modEventBus);

これができたら保存して、テスト起動してみましょう。

マイクラが起動したら、まずはインベントリを開いてみます。

インベントリを開いたら、クリエイティブタブの2ページ目に移動してみましょう。
タブがちゃんとできていればクリエイティブタブがちゃんと作成できたということです。

タブを押してそこに炭製ダイヤモンドが表示されていればOKです!

ということで、タブが完成しました!

しかしタブの名前がIDのようなままですね。
これを変更するには「見た目」なので「resources」フォルダ内の「lang」フォルダ内のファイルを変更すればいいはずです!

早速「en_us.json」から変更していきましょう!

途中にこれを追加しましょう。
(途中の「practicemymod」の部分は自分のModのIDに変更してください)

"itemGroup.practicemymod.mymod_tab": "My Mod Tab",

変更したら保存して、テスト起動!

クリエイティブタブの名前が変わっていればOKです。

これができたらこの調子で「ja_jp.json」も直しちゃいましょう!

途中にこれを追加しましょう。
(途中の「practicemymod」の部分は自分のModのIDに変更してください)

"itemGroup.practicemymod.mymod_tab": "自作Mod用タブ",

変更したら保存して、テスト起動!

クリエイティブタブの名前が、今度は日本語に変わっていればOKです。

これでオリジナルのタブを作成して、そこにアイテムを登録することができました!

既存のタブとオリジナルのタブの両方に登録する

ここまでやってきましたが、現在は「既存のタブには鋼鉄が表示される」「オリジナルのタブには炭製ダイヤモンドが表示される」という状態。

ここからは「鋼鉄」は既存のタブとオリジナルのタブに表示され、「炭製ダイヤモンド」も既存のタブとオリジナルのタブに表示されるようにしていきたいと思います!

まずは鋼鉄の方から。

鋼鉄の方は新たにオリジナルのタブの方に登録しなければいけません。
なのでまずは「ModCreativeModeTabs.java」を開きましょう。

その中から「.displayItems((itemDisplayParameters, output) -> {」と書いてある行を探しましょう。
その周辺を見るとこんな感じ。

// タブの中に並べるアイテムのリスト
.displayItems((itemDisplayParameters, output) -> {
    output.accept(ModItems.COAL_DIAMOND.get());
})

メモの通り、まさにここでアイテムを登録しています!
(すでにCOAL_DIAMONDが入っていますね)

ここを、以下のように変更します。

// タブの中に並べるアイテムのリスト
.displayItems((itemDisplayParameters, output) -> {
    output.accept(ModItems.COAL_DIAMOND.get());
    output.accept(ModItems.STEEL.get());// ← ここを追加!
})

変更したら、また保存して、テスト起動!

こんな風に「オリジナルのタブの中」と「既存のタブの材料の中」の両方に入っていれば成功です!
案外自分のオリジナルのタブに追加するのは、2回目以降は簡単ですね!

次は今のの逆。
オリジナルのタブに登録されている「炭製ダイヤモンド」を「既存のタブの材料」にも表示されるようにしましょう。

そのためにはまず「AddExistingCreativeModeTab.java」ファイルを開きましょう。

その中から、以下のような場所を探しましょう。

// もし「材料(INGREDIENTS)」タブを開いた時だったら
if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
    event.accept(ModItems.STEEL);
}

この部分で、アイテムを登録しているのは「event.accept(ModItems.STEEL);」の部分でしたね。
これを追加します。
以下のように追記してみましょう。

// もし「材料(INGREDIENTS)」タブを開いた時だったら
if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
    event.accept(ModItems.STEEL);
    event.accept(ModItems.COAL_DIAMOND);// ← ここを追加!
}

変更したら、また保存して、テスト起動!

こんな風に「オリジナルのタブの中」と「既存のタブの材料の中」の両方に入っていれば成功です!
こちらも存外、2回目以降は難しくは無いですね。

しかしここで!
「やっぱり「炭製ダイヤモンド」は道具と実用品のタブに入れたい!」となった場合はどうしましょう。

ということでやっていきます。
まずは「AddExistingCreativeModeTab.java」ファイルを開きます。

今回はこの部分を修正していきます。

// 実際にアイテムを追加する処理
public static void addCreative(BuildCreativeModeTabContentsEvent event) {
    // もし「材料(INGREDIENTS)」タブを開いた時だったら
    if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
        event.accept(ModItems.STEEL);
        event.accept(ModItems.COAL_DIAMOND);
    }
}

この中で、まず炭製ダイヤモンドを材料タブには載せない場合には、登録を消してしまいます。

// 実際にアイテムを追加する処理
public static void addCreative(BuildCreativeModeTabContentsEvent event) {
    // もし「材料(INGREDIENTS)」タブを開いた時だったら
    if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
        event.accept(ModItems.STEEL);
    }
}

次に、この命令では、「材料タブかどうか」は「if」(条件分岐)文でしていしていましたね。
なので今度は同じように「アイテムタブかどうか」を判定します。

// 実際にアイテムを追加する処理
public static void addCreative(BuildCreativeModeTabContentsEvent event) {
    // もし「材料(INGREDIENTS)」タブを開いた時だったら
    if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
        event.accept(ModItems.STEEL);
    }
    // もし「道具と実用品(TOOLS_AND_UTILITIES)」タブを開いた時だったら
    if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {

    }
}

そして最後に、炭製ダイヤモンドを登録します。
(以下が完成なので、このように追記します)

// 実際にアイテムを追加する処理
public static void addCreative(BuildCreativeModeTabContentsEvent event) {
    // もし「材料(INGREDIENTS)」タブを開いた時だったら
    if (event.getTabKey() == CreativeModeTabs.INGREDIENTS) {
        event.accept(ModItems.STEEL);
    }
    // もし「道具と実用品(TOOLS_AND_UTILITIES)」タブを開いた時だったら
    if (event.getTabKey() == CreativeModeTabs.TOOLS_AND_UTILITIES) {
        event.accept(ModItems.COAL_DIAMOND);
    }
}

こんなふうに変更できたら、また保存して、テスト起動!

「材料タブ」から消え、「道具と実用品タブ」に入っていれば成功です!

※補足※
ちなみに、既存のマイクラのクリエイティブタブは以下のようなものがあります。
参考にしてみてください。

BUILDING_BLOCKS:建築ブロック
COLORED_BLOCKS:色付きブロック
NATURAL_BLOCKS:天然ブロック
FUNCTIONAL_BLOCKS:機能的ブロック
REDSTONE_BLOCKS:レッドストーン系ブロック
TOOLS_AND_UTILITIES:道具と実用品
COMBAT:戦闘
CONSUMABLES:食べ物と飲み物
INGREDIENTS:材料
SPAWN_EGGS:スポーンエッグ
HOTBAR:保存したホットバー
SEARCH:アイテム検索
(このアイテム検索には、何かのタブに入っていれば自動で表示されるようなので、特別にこれに割り当てなければいけないわけではないようです。つまり使わなくてもOK)

これにてタブへの登録は完了です!

おわりに&次回予告

今回は独自のアイテムを既存だったりオリジナルだったりのタブに登録しました。
これのおかげで、毎回コマンドからアイテムを出す必要は無くなりました!

さて次回の予定ですが、今まではアイテムだったので、今度は「オリジナルのブロックを登録」したいと思います。
アイテムと似ているようで少し違うので、解説できたらなと思います。

それでは、今回はこの辺で。
ありがとうございました。
次回もお楽しみに!

コメント