Mod制作日記 - アイテムとブロックの追加
前回の続き。
今回は、とにかくアイテムとブロックを追加するという内容です。
目次 (折りたたみ可)
はじめる前に......
どこにフォルダ作るとか、ファイル(クラス)の名前がどうとか、コード(あるいは仕組みそのもの)を理解していれば、正直どうでもいいんです。 Javaのプログラミングなので、フォルダの構成がそもそも変わろうとimportとかの書き方に気をつけるだけで、機能は同じように作れるんですよね。
もしわたしのやり方を真似するなら、それはわたしの「流儀」に沿って行くことになります。 気に入らないところがあったり、ある程度進めて †完全理解† できたりしたら、どんどん好きなようにやるべきだと思います。
説明の言い方について
面倒なのでいろいろ決めておきます。
"「com/(作者名)/(ModのID)」フォルダ"
→ 「com.(作者名).(ModのID)」"「com.(作者名).(ModのID)」にabcフォルダを作成"
→ "「com.(作者名).(ModのID).abc」フォルダを作成""「com.(作者名).(ModのID)」にAbc.javaを作成"
→ "「com.(作者名).(ModのID).Abc」クラスを作成"
見づらくなってますが、要は
- カッコを省略
- import文ぽく
- .javaファイル作る = 実質、クラスの新規作成
- 「${ファイルパス}に${ファイル/フォルダ名}」は冗長
ということです。ただし、Javaがあんまり関係ないところではもとの書き方になるかもしれません。
フォルダ作成
「com.(作者名).(ModのID).registers」フォルダを作ります。
レジスターのクラス(アイテム)
「registers.ItemRegister」クラスを作ります。
クラスを新規作成するときは、VSCode内のエクスプローラで追加先のフォルダを「右クリック > New Java File > Class」で追加します。 出てきたテキストボックスにクラス名を入力して決定するとファイルが作られ、途中までコードを書いてくれます。
具体的な中身はこんな感じです。
package com.masuec.my_mod.registers;
import com.masuec.my_mod.MyMod;
import net.minecraft.world.item.Item;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
public class ItemRegister {
public static final DeferredRegister- ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MyMod.MODID);
// 今回追加するアイテム
public static final RegistryObject
- TEST_ITEM = ITEMS.register(
"test_item",
() -> new Item(new Item.Properties().fireResistant())
);
public static void register(IEventBus evBus) {
ITEMS.register(evBus);
}
}
もしコピペしようとしてるなら、手入力のほうがいいと思います。 補完機能を使ってimport文を自動で追加する方が、各自で違うところ(my_modとか)をあとから変える必要がなくなるからです。
以下のような同名のクラスには気をつけてください。これに関しては上記の完成形のコードのimpoert文でどっちのクラスかよく見てください。

今回はとにかく追加するだけなので、このアイテムには特に性質はありません。
レジスターのクラス(ブロック)
同じく「registers.BlockRegister」クラスを作ります。
ブロックは、ブロック本体を追加するだけでなく、そのブロックのアイテムも追加する必要があります。
package com.masuec.my_mod.registers;
import com.masuec.my_mod.MyMod;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
public class BlockRegister {
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, MyMod.MODID);
public static final DeferredRegister<Item> BLOCKITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MyMod.MODID);
// 今回追加するブロック
public static final RegistryObject<Block> TEST_BLOCK = BLOCKS
.register("test_block", () -> new Block(BlockBehaviour.Properties.copy(Blocks.STONE)));
// 今回追加するブロックのアイテム
public static final RegistryObject<Item> TEST_BLOCK_ITEM = BLOCKITEMS
.register("test_block", () -> new BlockItem(TEST_BLOCK.get(), new Item.Properties()));
public static void register(IEventBus evBus) {
BLOCKS.register(evBus);
BLOCKITEMS.register(evBus);
}
}
このブロックはバニラの石の性質をコピーしています。
メインのクラスの編集
「MyMod」クラスでこの部分を追加します。
public MyMod() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(this::commonSetup);
// アイテムの登録
ItemRegister.register(modEventBus);
// ブロックの登録
BlockRegister.register(modEventBus);
MinecraftForge.EVENT_BUS.register(this);
modEventBus.addListener(this::addCreative);
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}
リソース
「assets.(ModのID)」フォルダに「blockstates」「lang」「models」「textures」フォルダを作ります。
前回も書いたように、リソースに関してはバニラのリソースパックと同じ作り方なので、ちゃんと書くのは最初だけにします。
テクスチャ
「textures/block」と「textures/item」フォルダににテクスチャを追加します。 ファイル名は「test_block.png」「test_item.png」としました。
モデル
「models/item/my_item.json」ファイルを新規作成し、中身は以下のようにします。ファイル名はアイテムのIDと対応しています。
{
"parent": "item/generated",
"textures": {
"layer0":"my_mod:item/my_item"
}
}
{
"parent": "item/generated",
"textures": {
"layer0":"(ModのID):item/(テクスチャのファイル名)"
}
}
ブロックの分も必要です。「models/block/my_block.json」ファイルを新規作成し、中身は以下のようにします。
{
"parent": "block/cube_all",
"textures": {
"all": "my_mod:block/test_block"
}
}
{
"parent": "block/cube_all",
"textures": {
"all": "(ModのID):block/(テクスチャのファイル名)"
}
}
さらにブロックのアイテムの分も作る必要があります。「models/item/my_block.json」ファイルを新規作成し、中身は以下のようにします。
{
"parent": "my_mod:block/test_block"
}
{
"parent": "(ModのID):(参照するモデルのファイルパス)"
}
ブロックステート
「blockstates」フォルダに「test_block.json」を追加します。
{
"variants": {
"": { "model": "my_mod:block/test_block" }
}
}
{
"variants": {
"": { "model": "(ModのID):block/(モデルのファイル名)" }
}
}
ローカライズ
「lang」フォルダに「en_us.json」を新規作成し、中身は以下のようにします。
{
"item.my_mod.test_item": "Test Item",
"block.my_mod.test_block": "Test Block"
}
{
"item.(ModのID).(アイテムのID)": "(表示名)",
"block.(ModのID).(ブロックのID)": "(表示名)"
}
今後も何かを追加してローカライズテキストを設定するときは、新しくファイルを作らずに、このファイルに書き足していきます。
日本語は「ja_jp.json」ファイルです。
{
"item.my_mod.test_item": "テストアイテム",
"block.my_mod.test_block": "テストブロック"
}
起動して確認
マインクラフトを起動して確認します。
追加の仕組み
Javaがわかるひとにとってはコードの通りという感じですけど。
public class ItemRegister {
// (2) レジスタ
public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MyMod.MODID);
// (1) アイテムをレジスタに登録する
public static final RegistryObject TEST_ITEM = ITEMS.register("test_item",
() -> new Item(new Item.Properties())
);
// (4) このメソッドはMyMod.javaで呼び出される
public static void register(IEventBus evBus) {
// (3) レジスタを登録
ITEMS.register(evBus);
}
}
(1)でアイテムを作って、(2)で作ったレジスタに登録しています。 段ボールに詰めているみたいなイメージですね。
追加するアイテムをすべて入れたレジスタ(段ボール)を(3)で登録するという感じです。
(4)のメソッドはMyModクラスが処理されるとき = ゲームの起動時に処理されるので、ゲームが起動したらレジスタ(段ボール)を処理するということですね。