気分でマイクラMOD制作

<details><summary>別に読まなくていい前置き</summary>

こんにちは、私です。この間マイクラで使うMOD選定をしていたのですが、いい感じのMODがなかったので、ここは自分でMODを作ってウハウハしていきたいと思います。途中で遊んだりもしますが、この記事はその過程も含めてのメモです。

なお、プログラミング知識が不足しているがゆえに、表記が不明瞭でしたり、あからさまな間違いのある可能性がありますが、ご了承ください。

</details>

# 本編

https://docs.fabricmc.net/develop/getting-started/setting-up-a-development-environment

まず公式ガイドに従って環境構築を終えました。

```:環境
Minecraft JE 1.21
Fabric loader 0.16.9
Java 21
Intellij IDEA Community Edition 2024.2.3
```

## アイテムを追加してみる

ディレクトリ構成はこんな感じです。MOD名がTemplateModとデフォルトのままなので分かりにくい所があるかもしれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623062/82882376-57a9-a0e8-9492-32f5eb8c8c10.png)

<details><summary>TemplateMod.java</summary>

```java:TemplateMod
package io.github.scratch221171.init;

import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.minecraft.component.type.FoodComponent;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroups;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;

import static io.github.scratch221171.TemplateMod.MOD_ID;

public class item {
    public static Item register(Item item, String id) {
        // Create the identifier for the item.
        Identifier itemID = Identifier.of(MOD_ID, id);

        // Register the item.
        Item registeredItem = Registry.register(Registries.ITEM, itemID, item);

        // Return the registered item!
        return registeredItem;
    }

    public static void Init() {
        final Item SUSPICIOUS_SUBSTANCE = register(new Item(new Item.Settings().food(new FoodComponent.Builder().nutrition(5).saturationModifier(5).build())), "suspicious_substance");

        ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register((itemGroup) -> itemGroup.add(SUSPICIOUS_SUBSTANCE));
    }
}

```
</details>

<details><summary>item.java</summary>

```java:item
package io.github.scratch221171.init;

import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents;
import net.minecraft.component.type.FoodComponent;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroups;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;

import static io.github.scratch221171.TemplateMod.MOD_ID;

public class item {
    public static Item register(Item item, String id) {
        //アイテムの識別ID
        Identifier itemID = Identifier.of(MOD_ID, id);

        //登録
        Item registeredItem = Registry.register(Registries.ITEM, itemID, item);

        //戻り値
        return registeredItem;
    }

    public static void Init() {
        final Item SUSPICIOUS_SUBSTANCE = register(new Item(new Item.Settings().food(new FoodComponent.Builder().nutrition(5).saturationModifier(5).build())), "suspicious_substance");

        ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register((itemGroup) -> itemGroup.add(SUSPICIOUS_SUBSTANCE));
    }
}

```
</details>

ちゃんとモデル、テクスチャ、アイテム名が反映されていますね。公式ガイドでは英語(`en_us`)のみでしたが`ja_jp`を使えば日本語に対応することができるみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623062/953bf522-80af-80ab-f96a-249c5cfdb4d0.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3623062/5cd5004f-c732-7781-a39c-765e4a72d8bb.png)

クラフトレシピは`resources/data/(mod-id)/recipe/(item).json`で指定できます。詳しい書き方は[こちら](https://ja.minecraft.wiki/w/%E3%83%AC%E3%82%B7%E3%83%94_(%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0))を参照のこと。[Recipe JSON Generator](https://crafting.thedestruc7i0n.ca/)を使うと便利。クラフトレシピは作業台だけでなく鍛冶台なども指定できるようです。

https://docs.fabricmc.net/develop/items/food

食べ物にも指定できるみたいなのでやってみましょう。Initメソッドのアイテムを追加する部分をいじってみます。

```java:item
public static void Init() {
        final Item SUSPICIOUS_SUBSTANCE = register(new Item(new Item.Settings().food(new FoodComponent.Builder().nutrition(5).build())), "suspicious_substance");

        ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register((itemGroup) -> itemGroup.add(SUSPICIOUS_SUBSTANCE));
    }
```

ちゃんと食べられて、満腹度も回復しますね。エフェクトとかも追加できるみたいです。

### Hot swapping

調べてみるとどうやらIntellijにはHot swappingなる機能があるそうです。デバッグモードでマイクラを起動すれば、再起動せずメソッド内を変更を反映できるとのことです。ウィンドウ上部の`ビルド(B)`>`プロジェクトの再ビルド(R)`をクリックすると、確認が出てきて変更できるらしいです。

私の場合、アイテムの満腹度の数値をいじってもHot swappingで変更できませんでしたが、初期化するときのメソッドの中にありますし、そもそもメソッドが呼ばれなかった可能性もあるので、後々別の要素を追加したときにまた試してみたいと思います。

## ツール・防具を追加してみる

アイテムを追加したらもちろん次は装備を追加しますよね。ということで早速やってみましょう。

https://docs.fabricmc.net/develop/items/custom-tools

https://docs.fabricmc.net/develop/items/custom-armor

<details><summary>TestMaterial.java</summary>

```java:TestMaterial
package io.github.scratch221171;

import io.github.scratch221171.init.item;
//ここを忘れるとエラー吐く

import net.minecraft.block.Block;
import net.minecraft.item.ToolMaterial;
import net.minecraft.recipe.Ingredient;
import net.minecraft.registry.tag.BlockTags;
import net.minecraft.registry.tag.TagKey;

public class TestMaterial implements ToolMaterial {
    @Override
    public int getDurability() {
        return 455;
    }
    @Override
    public float getMiningSpeedMultiplier() {
        return 5.0F;
    }
    @Override
    public float getAttackDamage() {
        return 1.5F;
    }
    @Override
    public TagKey<Block> getInverseTag() {
        return BlockTags.INCORRECT_FOR_IRON_TOOL;
    }
    @Override
    public int getEnchantability() {
        return 22;
    }
    @Override
    public Ingredient getRepairIngredient() {
        return Ingredient.ofItems(item.SUSPICIOUS_SUBSTANCE);
    }

    public static final TestMaterial INSTANCE = new TestMaterial();
}

```

</details>

そうすると、最後の`getRepairIngredient()`で`item.SUSPICIOUS_SUBSTANCE`の所がシンボルを解決できないとかなんとか言われました。これはitemクラスで変数`SUSPICIOUS_SUBSTANCE`を定義する場所を間違えていたみたいなので、訂正しておきます。

```diff_java
-public static void Init() {
-    final Item SUSPICIOUS_SUBSTANCE = register(new Item(new Item.Settings().food(new FoodComponent.Builder().nutrition(5).saturationModifier(5).build())), "suspicious_substance");
-
-    ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register((itemGroup) -> itemGroup.add(SUSPICIOUS_SUBSTANCE));
-}

+public static final Item SUSPICIOUS_SUBSTANCE = register(new Item(new +Item.Settings().food(new FoodComponent.Builder().nutrition(5).build())), "suspicious_substance");
+
+public static void Init() {
+    ItemGroupEvents.modifyEntriesEvent(ItemGroups.INGREDIENTS).register((itemGroup) -> itemGroup.add(item.SUSPICIOUS_SUBSTANCE));
+}
```