Minecraft1.8.2 Forge で 自作 dimension を作成する

## 動機
最近 Minecraft の　Mod 動画をよくみるので、巷にはナレッジが溢れていると思い Mod 制作に取り組んで見たのですが、思ったよりナレッジが少なく、さらに v1.82 あたりはほぼ情報がない状態だったので非常に苦労しました。なんとか一通りサンプル作成まで至ったのでその内容をまとめたいと思います。

https://github.com/mikanbox/Minecraft_SampleWorld

## 手順
### 導入
まずは Minecraft の Mod 作成にあたってツールをインストールします。
有名どころの OSS は「Forge」ならびに「Fabric」だと思いますが、今回は一番有名な「Forge」にしました。
https://github.com/MinecraftForge/MinecraftForge

インストールは以下の通り、 Forge の配布ページからパッケージをダウンロードする形なので、それに従います。
> Go to the Forge website and select the Minecraft version

その後は以下資料に従って黙々と開発を進めていくことになります。
https://docs.minecraftforge.net/en/1.18.x/gettingstarted/

ざっくりまとめると概要は以下となります
- Forge `1.18.x は　Java 17 Development Kit` と `JVM` が必要
- インストールページから `Forge MDK` (Mod Development Kit)をダウンロード
- パッケージの「/src/main/java」を置き換えていけば OK
- パッケージ管理ツールの Gradle は設定済みなので再利用可
- IDE として IntelliJ IDEA を使用している場合、`gradlew genIntellijRuns` / `./gradlew genIntellijRuns` で起動設定を構築可能

一通りやると、IntelliJ だとこのように起動できる状態になり、ここで「runClinet」を実行することでお馴染みの画面が起動します
![intellij.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254034/49413ad1-aa8d-03f4-b502-6b24ef7bf226.png)


### バイオームを登録する
ここからが本番です。以下を眺めていると、どうやら DeferredRegister クラスのインスタンスで　オブジェクトの情報を登録していくようです。
https://docs.minecraftforge.net/en/1.18.x/gettingstarted/

初見の際には Forge の違うバージョンの資料を追ってしまい苦労しましたが、 Forge側も大きく変更が入ったようです。
どうしたものかと頭を抱えていたら、curseforge.com　にてまさに求めている sample を提供してくださっている方がいました。結果、こちらを拝見してさらにシンプルなものを作成することにしました。
https://www.curseforge.com/minecraft/mc-mods/jamd



ソースの構成は以下です。
```
tree ./src/main
./src/main
├── java
│   └── com
│       └── mikanbox55
│           └── sampleworld
│               ├── EntryPoint.java
│               └── Register.java
└── resources
    ├── META-INF
    │   └── mods.toml
    └── pack.mcmeta

```

mods.toml
```toml
modLoader="javafml"
loaderVersion="[40,)"
license="MIT"
[[mods]]
modId="sampleworld"
version="${file.jarVersion}"
displayName="Sample Biome and Dimension"
authors="mikanbox55"
description='''A minimal mod for generating dimension and biome'''

[[dependencies.sampleworld]] #optional
    modId="forge" #mandatory
    mandatory=true #mandatory
    versionRange="[40,)" #mandatory
    ordering="NONE"
    side="BOTH"
[[dependencies.sampleworld]]
    modId="minecraft"
    mandatory=true
    versionRange="[1.18.2,1.19)"
    ordering="NONE"
    side="BOTH"
```

EntryPoint.java
```java
package com.mikanbox55.sampleworld;

import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;


@Mod(EntryPoint.MODID)
public class EntryPoint {
    public static final String MODID = "sampleworld";
    public static final ResourceLocation DIM_ID = new ResourceLocation(MODID, "sample_world_location");

    public EntryPoint() {
        IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
        MinecraftForge.EVENT_BUS.register(this);
        Register.FORGEREGISTRIES.forEach(item -> item.register(bus));
    }
}
```

`@mod`アノテーションをつけることで、このクラスをエントリーポイント的な扱いにできます。また、`@mod` で指定した MODID　は`　mods.toml` にきちんと指定する必要があります。
ここでは最低限の作業を行い、実際のバイオームの登録は Register.java でおこなっています。


Register.java
```java
package com.mikanbox55.sampleworld;

import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeGenerationSettings;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import net.minecraft.world.level.biome.MobSpawnSettings;

import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;

import java.util.ArrayList;
import java.util.List;


public class Register {
    public static List<DeferredRegister<?>> FORGEREGISTRIES = new ArrayList<>();
    private static final DeferredRegister<Biome> BIOMES = register(DeferredRegister.create(ForgeRegistries.BIOMES, EntryPoint.MODID));

    public static final RegistryObject<Biome> BIOME = BIOMES.register(
            EntryPoint.DIM_ID.getPath(),
            () -> new Biome.BiomeBuilder()
                    .precipitation(Biome.Precipitation.RAIN)
                    .temperature(0.5F)
                    .downfall(0.5F)
                    .biomeCategory(Biome.BiomeCategory.FOREST)
                    .mobSpawnSettings(MobSpawnSettings.EMPTY)
                    .specialEffects(new BiomeSpecialEffects.Builder()
                            .skyColor(8103167)
                            .fogColor(12638463)
                            .waterColor(4445678)
                            .waterFogColor(270131)
                            .build())
                    .generationSettings(BiomeGenerationSettings.EMPTY)
                    .build()
    );

    //    登録は後で一括で行う
    private static <T> DeferredRegister<T> register(DeferredRegister<T> registry) {
        FORGEREGISTRIES.add(registry);
        return registry;
    }
}

```
なぜ static で宣言するのかはまだよくわかってないのですが、 `DeferredRegister<Biome> BIOMES`を宣言後、これに対して `RegistryObject<Biome>` を登録します。
`RegistryObject` は Block とか Item とかだと単一の builder で生成できて楽なんですが、バイオームは色々設定が含まれていて一筋縄ではいきません。今回はなるべく簡単にするため、static で EMPTY が定義されているクラスについてはそちらを利用させてもらいました。 `BiomeSpecialEffects` については static での定義がなさそうなので、Biome 生成中に同時生成しています。

ここまでできたら 「runClient」 で起動します。ワールド生成ロジックの方はいじってないのでバイオームは見れませんが、 Minecraft に登録されていることは `/locatebiome`コマンドで以下の通り確認できます。

![locatebiome.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254034/9320ea11-1562-c38b-9ff3-d81500ff9f06.png)

### ディメンションを登録する
さて、同じように ディメンションも Register したいところなのですが、どうも Dimension は対応する定義が存在してないように見えます。
Forge の対応待ち？とも一瞬考えたのですが、どうやら違うようです。

色々探してみると　データパックの機能でどうやら登録できるようです。
データパックと Forge の使い分けは？というところは気になるところではありますが、Forge で登録したバイオームを データパックで参照することもできそうなので、今回の目的には十分そうです。これは今後の宿題とし、データパックの詳細を追っていくことにします。

データパック周りは以下の Wiki にお世話になりました。
https://minecraft.fandom.com/wiki/Custom_dimension

こちらの データパックの定義にある内容を埋めていくことでディメンションを定義できるようです。
今回は以下ディレクトリに、 JSON を格納しました。
`src/main/resources/data/sampleworld/dimension/sample_world_location.json`
```json
{
  "type": "minecraft:overworld",
  "generator": {
    "type": "flat",
    "settings": {
      "biome": "sampleworld:sample_world_location",
      "lakes": false,
      "features": true,
      "layers": [
        {
          "block": "minecraft:bedrock",
          "height": 1
        },
        {
          "block": "minecraft:deepslate",
          "height": 64
        },
        {
          "block": "minecraft:stone",
          "height": 64
        },
        {
          "block": "minecraft:dirt",
          "height": 3
        },
        {
          "block": "minecraft:grass_block",
          "height": 1
        }
      ]
    }
  }
}
```

この状態で再度起動します。
今回はディメンションがあるので、`/execute in `コマンドで起動後移動してみます。画像から無事ディメンション候補が現れて移動できたことが確認できるかと思います。

![Pasted image 20221204050107.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254034/500fc933-be3f-afb3-6ec7-3ab76aaf8166.png)


## まとめ
なんとなくですが、海外製の mod は割と最新のバージョンに追従しているにもかかわらず、日本語の資料がものすごく少なく感じました。やはり mod だとメジャーなバージョンはもっと前のバージョンなのかなとも思います。
最終的には何かまとまった mod を作成してどっかに載せられたらいいなと思いちょくちょく記事を投稿していく予定です。
本記事について不明点や何か齟齬がありましたらコメントいただけますと幸いです。