C#でMinecraftを操作する【中編】

[C# ではじめるマインクラフトプログラミング](https://zenn.dev/takunology/books/minecraft-programming-book)という無料で読める本を見つけた。[前編](https://qiita.com/zawanume/items/347e02ba5ff10d0e8ada)に引き続き触ってみる。

# 動作環境
以下の環境で動作させる。Minecraftマルチプレイ用のサーバを構築する必要がある。
- Minecraft 1.19.3
- OpenJDK 17.0.4
- Visual Studio 2022 17.4.3
- .NET 6.0.307
- MinecraftConnection 2.0.1

# 自動建築
`setblock`コマンドとC#の言語機能をうまく組み合わせて、設計図から建築物を作りたい。csvファイルなどが手っ取り早いのだろうが、Excelと違ってシートを複数枚持てない。[書籍でも紹介](https://zenn.dev/takunology/books/minecraft-programming-book/viewer/chapter15)されているように、Excelブックを読み込むことができるライブラリ「NPOI」を利用する。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370590/a321a643-fba4-0ac6-e6db-5fdc761741b0.png" width=80%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370590/aa7c918f-c18b-74f7-d11e-9550530b1b18.png" width=80%>
画像のようにy座標ごとに輪切りにした建物の設計図を作る。

# 実装
Excelブックを読み込む実装は`Loader`クラスとして分離した。
```cs:Loader.cs
using NPOI.SS.UserModel;

namespace MinecraftAutoBuild
{
    public class Loader
    {
        private string filePath;
        public readonly List<List<List<string>>> BlockId = new List<List<List<string>>>();

        public Loader(string filePath)
        {
            this.filePath = filePath;
            try
            {
                getData();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        private void getData()
        {
            var book = WorkbookFactory.Create(filePath);
            var sheetsCnt = book.NumberOfSheets;

            for(int i = 0; i < sheetsCnt; i++)
            {
                List<List<string>> rows = new List<List<string>>();
                var sheet = book.GetSheetAt(i);
                int rowsCnt = sheet.LastRowNum + 1;

                for(int j = 0; j < rowsCnt; j++)
                {
                    List<string> cols = new List<string>();
                    var row = sheet.GetRow(j);
                    int colsCnt = row.LastCellNum;

                    for(int k = 0; k < colsCnt; k++)
                    {
                        var cell = row.GetCell(k);
                        cols.Add(cell.StringCellValue);
                    }
                    rows.Add(cols);
                }
                BlockId.Add(rows);
            }
        }
    }
}
```
ブロックの配置をExcelブックから読み出して3次元リストに格納する。
```cs:Program.cs
using MinecraftAutoBuild;
using MinecraftConnection;

string address = "192.168.0.***";
ushort port = *****;
string pass = "*********";
MinecraftCommands command = new MinecraftCommands(address, port, pass);

string filePath = "../../../../tofu_house.xlsx";
var buildData = new Loader(filePath);
var TofuHouse = buildData.BlockId;

int x = -353;
int y = 81;
int z = -84;

for (int i = 0; i < TofuHouse.Count; i++)
{
    for (int j = 0; j < TofuHouse[i].Count; j++)
    {
        for (int k = 0; k < TofuHouse[i][j].Count; k++)
        {
            command.SendCommand($"setblock {x + j} {y + i} {z + k} {TofuHouse[i][j][k]}");
            command.Wait(10);
        }
    }
}
```
リストの中身を3重for文で`setblock`している。

# 動かしてみる
簡単な豆腐建築を作ってみる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370590/18526052-7ece-2061-b4a7-d2d9bf340cec.gif" width=80%>
3Dプリンタみたいな動きをしている。

# 最後に
書けることがたくさんありそうだったのでとりあえず中編ということにしたが、後編に何を書くかは全く決まっていない。