Minecraft Forge 1.15.2 で Mod にオリジナル武器を追加する

## 概要

- Minecraft Forge を使用して Mod にオリジナルの武器を追加する
- 今回は剣タイプ (SwordItem クラスのインスタンス) の武器を3つ追加した

## 環境

- Minecraft Forge 1.15.2-31.1.0
- ビルド環境: macOS Catalina + Java 8 (AdoptOpenJDK) + Gradle

## ソースコード

### ファイル一覧

```
├── build.gradle
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── bukimod
        │               ├── BukiItemTier.java
        │               ├── BukiMod.java
        │               └── BukiModRegister.java
        └── resources
            ├── META-INF
            │   └── mods.toml
            ├── assets
            │   └── bukimod
            │       ├── lang
            │       │   ├── en_us.json
            │       │   └── ja_jp.json
            │       ├── models
            │       │   └── item
            │       │       ├── maigo_ita.json
            │       │       └── murasama_blade.json
            │       └── textures
            │           └── items
            │               ├── maigo_icon.png
            │               └── murasama_blade.png
            └── pack.mcmeta
```

今回は build.gradle, pack.mcmeta, mods.toml には必要最低限の記述程度のみしている。
参考: [Minecraft Mod 開発環境構築 \(IntelliJ IDEA \+ Minecraft Forge 1\.15\.2\) \+ Hello World Mod 作成 \- Qiita](https://qiita.com/niwasawa/items/ca565091468abce48f53)

### src/main/java/com/example/bukimod/BukiMod.java

MOD メインクラス。@Mod アノテーションを付けて MOD であることを示す。
今回は特に処理をせず MOD 内で使用する値を定義している。

```java
package com.example.bukimod;

import net.minecraftforge.fml.common.Mod;

/**
 * Buki Mod.
 */
@Mod(BukiMod.MOD_ID)
public class BukiMod {

  /** MODのID */
  public static final String MOD_ID = "bukimod";

  /** ムラサマ・ブレードのID (アイテムを一意に識別するために必要) */
  public static final String ITEM_ID_MURASAMA_BLADE = "murasama_blade";

  /** 迷子板のID (アイテムを一意に識別するために必要) */
  public static final String ITEM_ID_MAIGO_ITA = "maigo_ita";

  /** ひのきのぼうのID (アイテムを一意に識別するために必要) */
  public static final String ITEM_ID_HINOKINO_BOU = "hinokino_bou";
}
```

### src/main/java/com/example/bukimod/BukiItemTier.java

IItemTier インターフェースを実装したクラスまたは列挙型を用意する。今回は列挙型で実装した。

IItemTier は以前のバージョンでツール・マテリアル (Item.ToolMaterial クラス) と呼ばれていたものの後継であるようだ。

IItemTier インターフェースの各メソッドでは耐久度や攻撃力を返すようにしている。

IItemTier#getAttackDamage で返す値がそのまま攻撃力になるのではなく、武器のオブジェクトを生成する際にも別途攻撃力を指定しており、最終的な攻撃力はそれらの複数の値から算出されている。

```java
package com.example.bukimod;

import net.minecraft.item.IItemTier;
import net.minecraft.item.Items;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.tags.ItemTags;
import net.minecraft.util.LazyValue;

import java.util.function.Supplier;

/**
 * IItemTier インターフェースの実装列挙型。
 */
public enum BukiItemTier implements IItemTier {

  /**
   * 鋼。
   * harvestLevel: 2
   * maxUses: 9999
   * efficiency: 6.0F
   * attackDamage: 2.0F
   * enchantability: 14
   * repairMaterial: Ingredient.fromItems(Items.IRON_INGOT)
   */
  HAGENE(2, 9999, 6.0F, 2.0F, 14, () -> {
    return Ingredient.fromItems(Items.IRON_INGOT);
  }),

  /**
   * ベニヤ。
   */
  VENEER(1, 1, 1.0F, 1.0F, 1, () -> {
    return Ingredient.fromTag(ItemTags.PLANKS);
  });

  private final int harvestLevel;
  private final int maxUses;
  private final float efficiency;
  private final float attackDamage;
  private final int enchantability;
  private final LazyValue<Ingredient> repairMaterial;

  BukiItemTier(int harvestLevel, int maxUses, float efficiency, float attackDamage, int enchantability, Supplier<Ingredient> repairMaterial) {
    this.harvestLevel = harvestLevel;
    this.maxUses = maxUses;
    this.efficiency = efficiency;
    this.attackDamage = attackDamage;
    this.enchantability = enchantability;
    this.repairMaterial = new LazyValue<>(repairMaterial);
  }

  @Override
  public int getHarvestLevel() {
    return harvestLevel;
  }

  @Override
  public int getMaxUses() {
    return maxUses;
  }

  @Override
  public float getEfficiency() {
    return efficiency;
  }

  @Override
  public float getAttackDamage() {
    return attackDamage;
  }

  @Override
  public int getEnchantability() {
    return enchantability;
  }

  @Override
  public Ingredient getRepairMaterial() {
    return repairMaterial.getValue();
  }
}
```

### src/main/java/com/example/bukimod/BukiModRegister.java

アイテム登録クラス。Minecraft Forge からアイテム登録のイベント発行時に呼び出される。

今回は3つのオリジナル武器を登録している。
3つとも剣タイプの武器で SwordItem クラスのインスタンスを使用している。
SwordItem クラスは以前のバージョンで存在していた ItemSword クラスの後継であるようだ。

```java
package com.example.bukimod;

import net.minecraft.item.IItemTier;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemTier;
import net.minecraft.item.SwordItem;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.registries.IForgeRegistry;

/**
 * アイテム登録クラス。
 */
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) // システム内部で MOD を導入する際のイベントを受け取るためのアノテーション
public class BukiModRegister {

  /**
   * システム内部でアイテム登録イベントが発生した時に呼び出されるメソッド。
   */
  @SubscribeEvent
  public static void onItemsRegistry(final RegistryEvent.Register<Item> event) {
    IForgeRegistry<Item> registry = event.getRegistry();
    registry.registerAll(
      createMurasamaBlade(), // ムラサマ・ブレードを登録する
      createMaigoIta(), // 迷子板を登録する
      createHinokinoBou()); // ひのきのぼうを登録する
  }

  /**
   * ムラサマ・ブレードを生成する。
   */
  private static Item createMurasamaBlade() {

    // ムラサマ・ブレードのオブジェクトを生成
    IItemTier tier = BukiItemTier.HAGENE; // 鋼
    int attackDamage = 9999; // 攻撃力
    float attackSpeed = 99.0f; // 攻撃速度
    Item.Properties builder = new Item.Properties().group(ItemGroup.COMBAT); // Combat 戦闘タブに置く
    Item murasamaBlade = new SwordItem(tier, attackDamage, attackSpeed, builder);

    // 一意になる名称をアイテムに設定
    String namespace = BukiMod.MOD_ID;
    String path = BukiMod.ITEM_ID_MURASAMA_BLADE;
    murasamaBlade.setRegistryName(new ResourceLocation(namespace, path));

    return murasamaBlade;
  }

  /**
   * 迷子板を生成する。
   */
  private static Item createMaigoIta() {

    // 迷子板のオブジェクトを生成
    IItemTier tier = BukiItemTier.VENEER; // ベニヤ
    int attackDamage = 1; // 攻撃力
    float attackSpeed = 1.0f; // 攻撃速度
    Item.Properties builder = new Item.Properties().group(ItemGroup.MISC); // Miscellaneous その他タブに置く
    Item maigoIta = new SwordItem(tier, attackDamage, attackSpeed, builder);

    // 一意になる名称をアイテムに設定
    String namespace = BukiMod.MOD_ID;
    String path = BukiMod.ITEM_ID_MAIGO_ITA;
    maigoIta.setRegistryName(new ResourceLocation(namespace, path));

    return maigoIta;
  }

  /**
   * ひのきのぼうを生成する。
   */
  private static Item createHinokinoBou() {

    // ひのきのぼうのオブジェクトを生成
    IItemTier tier = ItemTier.WOOD; // 木
    int attackDamage = 1; // 攻撃力
    float attackSpeed = 1.0f; // 攻撃速度
    Item.Properties builder = new Item.Properties().group(ItemGroup.MISC); // Miscellaneous その他タブに置く
    Item hinokinoBou = new SwordItem(tier, attackDamage, attackSpeed, builder);

    // 一意になる名称をアイテムに設定
    String namespace = BukiMod.MOD_ID;
    String path = BukiMod.ITEM_ID_HINOKINO_BOU;
    hinokinoBou.setRegistryName(new ResourceLocation(namespace, path));

    return hinokinoBou;
  }
}
```

武器の名前は有名RPGなどから借りてきた。

[「村正」、「手裏剣」、「聖なる鎧」 全部手に入れた？ 『ウィザードリィ』の楽しさはアイテム収集にもアリ！ \- AKIBA PC Hotline\!](https://akiba-pc.watch.impress.co.jp/docs/column/masudaretro/1049069.html)

> 実際の村正は徳川家に祟る妖刀として知られているが、最初のAppleII版では「MURASAMA BLADE」となっていたのは、ファンの間では有名なトリビアである。

[「ひのきのぼう」に込めたドラクエ精神　堀井雄二が語ったこだわり](https://withnews.jp/article/f0170726004qq000000000000000W00810701qq000015620A)

> 今とは考えられない開発条件の中、最弱のアイテムだと「一目でわかる」名前が「ひのきのぼう」だったのです。

### src/main/resources/assets/bukimod/lang/*.json

en_us.json にはアイテムの名称を記述する (英語環境用であり、言語用ファイルを定義していない環境用でもある)。
「item.MODのID.アイテムID: アイテム名称」のフォーマットとなる。

```json
{
  "item.bukimod.murasama_blade":  "Murasama Blade",
  "item.bukimod.maigo_ita":  "Maigo Ita"
}
```

ja_jp.json にはアイテムの名称を記述する(日本語環境用)。

```json
{
  "item.bukimod.murasama_blade":  "ムラサマ・ブレード",
  "item.bukimod.maigo_ita":  "迷子板"
}
```

### src/main/resources/assets/bukimod/models/item/*.json

アイテムのモデル情報ファイル。アイテムの描画情報などを記述する。

murasama_blade.json で murasama_blade.png を使うように指定。

```json
{
  "parent": "item/generated",
  "textures": {
    "layer0": "bukimod:items/murasama_blade"
  }
}
```

maigo_ita.json で maigo_icon.png を使うように指定。

```json
{
  "parent": "item/generated",
  "textures": {
    "layer0": "bukimod:items/maigo_icon"
  }
}
```

[モデル \- Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E3%83%A2%E3%83%87%E3%83%AB)

> layer#: アイテムのパスで指定する。parentで "item/generated" としたときのみ有効で、インベントリに表示するアイコンを指定する。通常は1つだけだがスポーンエッグのように複数のlayerを持つものもある。この数はアイテムごとに決まっている。

### src/main/resources/assets/bukimod/textures/items/*.png

アイテムのテクスチャ画像。

murasama_blade.png 背景透過 PNG 画像。
2100 x 2100 ピクセル。こんなに大きい画像を使う必要はないはず。

![murasama_blade.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/07864e28-1090-c9af-8a09-bd690f90de40.png)

maigo_icon.png 背景透過していない PNG 画像。
500 x 500 ピクセル。こんなに大きい画像を使う必要はないはず。

![maigo_icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/5f4c7cca-0aa6-74d8-0000-70425997cfaa.png)

## Minecraft Forge で動かす

クリエイティブモードのワールドで確認する。

### ムラサマ・ブレード

ムラサマ・ブレードは背景透過PNG画像を使ったのでちゃんと剣らしいものになっている。

クリエイティブ・インベントリの戦闘(Combat)タブに追加されている。

<img width="854" alt="mod_murasama_blade_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/83588580-3531-0e20-e6a2-a852ff858799.png">

<img width="854" alt="mod_murasama_blade_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/8a049e6e-2094-b272-3aba-66671beeda59.png">

<img width="854" alt="mod_murasama_blade_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/965f14b0-d078-d07a-f9b1-69470f4823b4.png">

### 迷子板

迷子板は背景透過していないPNG画像を使ったので板のような形状で描画されている。

<img width="854" alt="mod_maigo_ita_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/993320d8-b79e-8a04-96c6-c818c6203788.png">

<img width="854" alt="mod_maigo_ita_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/55e38824-415a-996b-8c6b-37a03b71aea6.png">

<img width="854" alt="mod_maigo_ita_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/ae6fa438-c586-20a0-cacc-2af75fbe782f.png">

### ひのきのぼう

「ひのきのぼう」はモデルもテクスチャも用意しなかったため、名称や画像が自動で設定されたようだ。

<img width="854" alt="mod_hinokino_bou_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/b45ccd06-9304-ebc4-9f90-653bc097c465.png">

<img width="854" alt="mod_hinokino_bou_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/40a3c881-be12-7592-47c5-9796175cc1de.png">

## 参考資料

### Minecraft の武器について

- [剣 \- Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E5%89%A3)
- [武器 \- Minecraft Japan Wiki \- アットウィキ](https://w.atwiki.jp/minecraft/pages/35.html)
- [アイテム耐久度 \- Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E8%80%90%E4%B9%85%E5%BA%A6)
- [アイテム修繕 \- Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E4%BF%AE%E7%B9%95)

### Minecraft Forge での開発について

- [Minecraft Mod 開発環境構築 \(IntelliJ IDEA \+ Minecraft Forge 1\.15\.2\) \+ Hello World Mod 作成 \- Qiita](https://qiita.com/niwasawa/items/ca565091468abce48f53)
- [Minecraft 1\.12\.2 Forge Modの作成 その3 【剣の追加とレシピ登録,クラフト後に返ってくるアイテムの設定】 \- Qiita](https://qiita.com/Hiroya_W/items/5eea1538a75e79f88c58)
- [Minecraft 1\.14\.4 Forge Modの作成 その3 【無機能アイテムの追加】 \- Qiita](https://qiita.com/Hiroya_W/items/4fec2d799e499c4cd7c2)
- [Minecraft 1\.14\.4 Forge Modの作成 その6 【5種ツールの追加】 \- Qiita](https://qiita.com/Hiroya_W/items/6e8232cc5b3d1c0aa878)
- [モデル \- Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E3%83%A2%E3%83%87%E3%83%AB)
- [ツール類の追加\(1\.7\.10\) \| TNT Modders](https://www.tntmodders.com/tutorial/tool-1710/)
- [Forge Documentation](https://mcforge.readthedocs.io/en/1.15.x/)
    - [Resources \- Forge Documentation](https://mcforge.readthedocs.io/en/1.15.x/concepts/resources/)
    - [Registries \- Forge Documentation](https://mcforge.readthedocs.io/en/1.15.x/concepts/registries/)
    - [Internationalization and localization \- Forge Documentation](https://mcforge.readthedocs.io/en/1.15.x/concepts/internationalization/)
    - [Model Files \- Forge Documentation](https://mcforge.readthedocs.io/en/1.15.x/models/files/)
- [Overview \(Forge 1\.12\.2\-14\.23\.5\.2838 \[MCP stable\_39\]\)](https://forge.galaxy.nctu.me/forge/javadoc/14.23.5.2838-stable_39/)
    - [Item\.ToolMaterial \(Forge 1\.12\.2\-14\.23\.5\.2838 \[MCP stable\_39\]\)](https://forge.galaxy.nctu.me/forge/javadoc/14.23.5.2838-stable_39/net/minecraft/item/item.toolmaterial)
    - [ItemSword \(Forge 1\.12\.2\-14\.23\.5\.2838 \[MCP stable\_39\]\)](https://forge.galaxy.nctu.me/forge/javadoc/14.23.5.2838-stable_39/net/minecraft/item/itemsword)
    - [IForgeRegistryEntry\.Impl \(Forge 1\.12\.2\-14\.23\.5\.2838 \[MCP stable\_39\]\)](https://forge.galaxy.nctu.me/forge/javadoc/14.23.5.2838-stable_39/net/minecraftforge/registries/iforgeregistryentry.impl)