[Java]MinecraftのModを作成しよう 1.14.4【4. ツールの追加】

（この記事は一連の解説記事の一つになります）

先頭記事：[入門編](https://qiita.com/koteko/items/7afadf8261eac49bacad)
前の記事：[3. クリエイティブタブの追加](https://qiita.com/koteko/items/1d7a7fb2ff98bebce939)
次の記事：[5. 防具の追加](https://qiita.com/koteko/items/34e6cb63288cd30571b5)

# ツールの追加
[1. アイテムの追加](https://qiita.com/koteko/items/76910dbf9eb126bdfdf9)では何の機能も持たない単純なアイテムを追加しました。今度は剣やピッケルといった役割を持ったツールを追加してみましょう。

```
\src\main\java\jp\koteko\example_mod\
   ├ items
   │   ├ ItemExampleAxe.java
   │   ├ ItemExampleHoe.java
   │   ├ ItemExamplePickaxe.java
   │   ├ ItemExampleShovel.java
   │   └ ItemExampleSword.java
   ├ lists
   │   └ ItemList.java
   ├ ExampleItemGroup.java
   └ ExampleMod.java
```
`items`フォルダを作り、各アイテムのクラスを作ります。
今の時点では継承元のクラスとほぼ変わらないため、新たにクラスを作る必要はほとんどないですが、あとで色々とカスタマイズすることを想定して別クラスとしました。

```java:ItemExampleAxe.java
package jp.koteko.example_mod.items;

import net.minecraft.item.AxeItem;
import net.minecraft.item.ItemTier;

public class ItemExampleAxe extends AxeItem {
    public ItemExampleAxe(Properties properties) {
        super(ItemTier.IRON, 5, -3.0F, properties);
    }
}
```

```java:ItemExampleHoe.java
package jp.koteko.example_mod.items;

import net.minecraft.item.HoeItem;
import net.minecraft.item.ItemTier;

public class ItemExampleHoe extends HoeItem {
    public ItemExampleHoe(Properties properties) {
        super(ItemTier.IRON, 0, properties);
    }
}
```

```java:ItemExamplePickaxe.java
package jp.koteko.example_mod.items;

import net.minecraft.item.ItemTier;
import net.minecraft.item.PickaxeItem;

public class ItemExamplePickaxe extends PickaxeItem {
    public ItemExamplePickaxe(Properties properties) {
        super(ItemTier.IRON, 1, -2.8F, properties);
    }
}
```

```java:ItemExampleShovel.java
package jp.koteko.example_mod.items;

import net.minecraft.item.ItemTier;
import net.minecraft.item.ShovelItem;

public class ItemExampleShovel extends ShovelItem {
    public ItemExampleShovel(Properties properties) {
        super(ItemTier.IRON, 1.5F, -3.0F, properties);
    }
}
```

```java:ItemExampleSword.java
package jp.koteko.example_mod.items;

import net.minecraft.item.ItemTier;
import net.minecraft.item.SwordItem;

public class ItemExampleSword extends SwordItem {
    public ItemExampleSword(Properties properties) {
        super(ItemTier.IRON, 3, -2.4F, properties);
    }
}
```
継承元のコンストラクタに渡す引数は順に以下の通りです。`Properties`だけインスタンス化時に渡して、あとはここで決めてしまうようにしました。後述の「発展」の項も参照してください。

`IItemTier tier` : アイテムティア(いわゆるレア度・グレード的なもの)。
`int attackDamageIn`あるいは`float attackDamageIn` : 攻撃力。なぜかツールによってint, floatが異なる。Hoeには存在しない。
`float attackSpeedIn` :  攻撃速度。
`Properties builder` : アイテムプロパティ。今までクリエイティブタブの設定に使ってきたやつ。

___
アイテムリストに追加して登録していきます。

```java:ItemList.java
package jp.koteko.example_mod.lists;

import jp.koteko.example_mod.ExampleItemGroup;
import jp.koteko.example_mod.ExampleMod;
import jp.koteko.example_mod.items.*;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

@Mod.EventBusSubscriber(modid = ExampleMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class ItemList {
    public static Item ExampleIngot = new Item(new Item.Properties().group(ExampleItemGroup.DEFAULT))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_ingot"));
    public static Item ExampleAxe = new ItemExampleAxe(new Item.Properties().group(ExampleItemGroup.DEFAULT))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_axe"));
    public static Item ExampleHoe = new ItemExampleHoe(new Item.Properties().group(ExampleItemGroup.DEFAULT))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_hoe"));
    public static Item ExamplePickaxe = new ItemExamplePickaxe(new Item.Properties().group(ExampleItemGroup.DEFAULT))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_pickaxe"));
    public static Item ExampleShovel = new ItemExampleShovel(new Item.Properties().group(ExampleItemGroup.DEFAULT))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_shovel"));
    public static Item ExampleSword = new ItemExampleSword(new Item.Properties().group(ExampleItemGroup.DEFAULT))
            .setRegistryName(new ResourceLocation(ExampleMod.MOD_ID, "example_sword"));

    @SubscribeEvent
    public static void registerItems(RegistryEvent.Register<Item> event) {
        event.getRegistry().registerAll(
                ExampleIngot,
                ExampleAxe,
                ExampleHoe,
                ExamplePickaxe,
                ExampleShovel,
                ExampleSword
        );
    }
}

```
___
続いて設定をしていきます。

```
\src\main\resources\assets\example_mod
   ├ blockstates
   ├ lang
   │  └ en_us.json
   │  └ ja_jp.json
   ├ models
   │  ├ block
   │  └ item
   │     ├ example_axe.json
   │     ├ example_hoe.json
   │     ├ example_pickaxe.json
   │     ├ example_shovel.json
   │     └ example_sword.json
   └ textures
      ├ blocks
      └ items
         ├ example_axe.png
         ├ example_hoe.png
         ├ example_pickaxe.png
         ├ example_shovel.png
         └ example_sword.png
```

```json:en_us.json
{
  "item.example_mod.example_axe": "Example Axe",
  "item.example_mod.example_hoe": "Example Hoe",
  "item.example_mod.example_pickaxe": "Example Pickaxe",
  "item.example_mod.example_shovel": "Example Shovel",
  "item.example_mod.example_sword": "Example Sword"
}
```

```json:ja_jp.json
{
  "item.example_mod.example_axe": "例の斧",
  "item.example_mod.example_hoe": "例の鍬",
  "item.example_mod.example_pickaxe": "例のピッケル",
  "item.example_mod.example_shovel": "例のスコップ",
  "item.example_mod.example_sword": "例の剣",
}
```
~~(なんかいわくつきの武器みたいな名前になってしまった…)~~

```json:example_axe.json
{
  "parent": "item/handheld",
  "textures": {
    "layer0": "example_mod:items/example_axe"
  }
}
```

```json:example_hoe.json
{
  "parent": "item/handheld",
  "textures": {
    "layer0": "example_mod:items/example_hoe"
  }
}
```

```json:example_pickaxe.json
{
  "parent": "item/handheld",
  "textures": {
    "layer0": "example_mod:items/example_pickaxe"
  }
}
```

```json:example_shovel.json
{
  "parent": "item/handheld",
  "textures": {
    "layer0": "example_mod:items/example_shovel"
  }
}
```

```json:example_sword.json
{
  "parent": "item/handheld",
  "textures": {
    "layer0": "example_mod:items/example_sword"
  }
}
```
`parent`には`item/handheld`を指定することで手に持つタイプのアイテムとなります。

テクスチャも配置したらゲームを起動します。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256627/98c20b09-61d5-f81d-5b18-cf1fa47bcc5b.png)
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256627/75291ad5-3e3c-4d5b-0840-7504648febb2.png)
(クリエイティブで撮ったので耐久が減ってません)

**ツールの追加ができました！**

# 発展
Q. なんか攻撃力と攻撃速度の設定が値と違うんだけど？
Q. なんで攻撃速度マイナスなの？
**A. 攻撃力は、[`IItemTier`の値]+[各ツールでの値]+1、攻撃速度は4.0+[各ツールでの値]で求まるようです。**
今回追加したツールクラスの継承元クラスの1つ`SwordItem.java`を見てみましょう。

```java:SwordItem.java
//...
public class SwordItem extends TieredItem {
   private final float attackDamage;
   private final float attackSpeed;

   public SwordItem(IItemTier tier, int attackDamageIn, float attackSpeedIn, Item.Properties builder) {
      super(tier, builder);
      this.attackSpeed = attackSpeedIn;
      this.attackDamage = (float)attackDamageIn + tier.getAttackDamage();
   }
   //...
}
```
`(float)attackDamageIn + tier.getAttackDamage()`と計算しているのが分かります。
(なお実際GUI上での表示が+1されている理由がわかるコードは見つけられませんでしたが、バニラのアイテムもこのような式で求められる値に合致していました。表示上+1されているのか、内部計算的にも+1されているのかは不明です。)
(攻撃速度についても同様に、4.0のオフセットから計算している部分が見つけられていません。)

続いて`ItemTier`を見てみましょう。

```java:ItemTier.java
//...
public enum ItemTier implements IItemTier {
   WOOD(0, 59, 2.0F, 0.0F, 15, () -> {
      return Ingredient.fromTag(ItemTags.PLANKS);
   }),
   STONE(1, 131, 4.0F, 1.0F, 5, () -> {
      return Ingredient.fromItems(Blocks.COBBLESTONE);
   }),
   IRON(2, 250, 6.0F, 2.0F, 14, () -> {
      return Ingredient.fromItems(Items.IRON_INGOT);
   }),
   DIAMOND(3, 1561, 8.0F, 3.0F, 10, () -> {
      return Ingredient.fromItems(Items.DIAMOND);
   }),
   GOLD(0, 32, 12.0F, 0.0F, 22, () -> {
      return Ingredient.fromItems(Items.GOLD_INGOT);
   });
   //...
   private ItemTier(int harvestLevelIn, int maxUsesIn, float efficiencyIn, float attackDamageIn, int enchantabilityIn, Supplier<Ingredient> repairMaterialIn) {
      this.harvestLevel = harvestLevelIn;
      this.maxUses = maxUsesIn;
      this.efficiency = efficiencyIn;
      this.attackDamage = attackDamageIn;
      this.enchantability = enchantabilityIn;
      this.repairMaterial = new LazyLoadBase<>(repairMaterialIn);
   }
   //...
}
```
このようにTierごとに値が定まっています。

例えば、今回追加した`Example Sword`では、`ItemTier.IRON`なので、
攻撃力
[IItemTierの値]+[各ツールでの値]+1 = 2 + 3 + 1 = 6
攻撃速度
4.0+[各ツールでの値] = 4.0 - 2.4 = 1.6
となります。
___
Q. 石とか鉄とかじゃなくて、ちゃんと固有の素材にしたい
Q. 耐久値の設定ってどこ？
**A. 新しく`ItemTier`を作りましょう。**
上で触れた`ItemTier`のEnumを新しく定義します。

```
\src\main\java\jp\koteko\example_mod\
   ├ items
   │   └ ExampleItemTier.java
   ├ lists
   ├ ExampleItemGroup.java
   └ ExampleMod.java
```

```java:ExampleItemTier.java
package jp.koteko.example_mod.items;

import jp.koteko.example_mod.lists.ItemList;
import net.minecraft.item.IItemTier;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.util.LazyLoadBase;

import java.util.function.Supplier;

public enum ExampleItemTier implements IItemTier {
    EXAMPLE(4, 3122, 10.0F, 4.0F, 25, () -> {
        return Ingredient.fromItems(ItemList.ExampleIngot);
    });

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

    private ExampleItemTier(int harvestLevelIn, int maxUsesIn, float efficiencyIn, float attackDamageIn, int enchantabilityIn, Supplier<Ingredient> repairMaterialIn) {
        this.harvestLevel = harvestLevelIn;
        this.maxUses = maxUsesIn;
        this.efficiency = efficiencyIn;
        this.attackDamage = attackDamageIn;
        this.enchantability = enchantabilityIn;
        this.repairMaterial = new LazyLoadBase<>(repairMaterialIn);
    }

    public int getMaxUses() {
        return this.maxUses;
    }

    public float getEfficiency() {
        return this.efficiency;
    }

    public float getAttackDamage() {
        return this.attackDamage;
    }

    public int getHarvestLevel() {
        return this.harvestLevel;
    }

    public int getEnchantability() {
        return this.enchantability;
    }

    public Ingredient getRepairMaterial() {
        return this.repairMaterial.getValue();
    }
}
```
引数は順に、採取レベル、耐久値、効率、攻撃力、エンチャント効率、修理素材(のリスト的なもの)です。
ダイヤモンドの`DIAMOND(3, 1561, 8.0F, 3.0F, 10, ...)`より良い値にしてみました。

ツールクラスの`Tier`を変更します。

```java:ItemExampleSword.java
package jp.koteko.example_mod.items;

import net.minecraft.item.SwordItem;

public class ItemExampleSword extends SwordItem {
    public ItemExampleSword(Properties properties) {
        super(ExampleItemTier.EXAMPLE, 3, -2.4F, properties);
    }
}
```
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256627/26b8ffcb-02e6-6548-cb63-bb784a18b5c0.png)
きちんと攻撃力、耐久値が伸びています。(F3でデバック表示をしてF3+Hで耐久値などが表示できます。)
___
Q. 雷や炎の出るぼくのかんがえたさいきょうのぶきがつくりたい！
**A. 私もまだ難しくてわからないので一緒に勉強しましょう。**(解説予定なし)

# 参考
[Minecraft 1.14.4 Forge Modの作成 その6 【5種ツールの追加】](https://qiita.com/Hiroya_W/items/6e8232cc5b3d1c0aa878)

# 次の記事
[5. 防具の追加](https://qiita.com/koteko/items/34e6cb63288cd30571b5)