xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

Minecraft に C# からコマンド叩き込んで操作してみた

f:id:xin9le:20190708020622p:plain

最近日本マイクロソフトさんが #くらでべ という YouTube チャンネルをやっていて、その中で Minecraft の自動化を取り上げていました。誕生日もクリスマスも Minecraft の LEGO やグッズをせがむくらい Minecraft が大好き過ぎる娘がいるのですが、ここは自動化して娘に「お父さん、すごいじゃん!」と言わせてみたい!ということで、勉強も兼ねて真似してみました。

Minecraft 自動化の動画

以下が #くらでべ さんがやっていた動画です。@rioriost さんの説明は非常に分かりやすいですし、@chomado ちゃんの合いの手も面白くって、入門としては大変素晴らしいです。

今回僕が試したのは第 3 回までの範囲で、ここまでが重要です。それができればあとはプログラミングとしての応用なので、まずは第 3 回の内容までを押さえましょう。

この動画の中では Azure Notebooks というお手軽なプログラム実行環境から Python を使って Minecraft にコマンドを投げているのですが、僕は生粋の C#er なのでやっぱり C# でコマンドを投げたい!ということで C# で Minecraft のコマンドを投げて操作するところまでを簡単に紹介してみたいと思います。

Step.1 : オレオレ Minecraft サーバーを立てる

まず、好き勝手するためのオレオレサーバーを立てます。今回は先の動画で紹介されている方法に従って Azure 上にサーバーを立てる方向で進めてみますが、慣れている方 (?) はローカル環境にサーバーを立ててみても良いでしょう。今は Dockerfile とかの設定は大変に面倒なので、@rioriost さんが Docker Hub に公開しているコンテナイメージをありがたく利用させていただきます。

これを Azure Container Instances (ACI) にホストします。これまた @rioriost さんがご丁寧に Bash の Deploy Script を準備してくださっているので、ちょこっと書き換えて実行します。僕は冒頭を以下のように書き換えました。

#!/bin/bash

# Here you need to specify these parameters
readonly AZURE_ACCT="xin9le" 
readonly ACI_RES_LOC="japaneast"
readonly ACI_RES_GRP="${AZURE_ACCT}democraft"
readonly ACI_STR_SH_NAME="acishare"
readonly RCON_PASSWORD="すごく文字列です"
readonly ACI_CNT_NAME="${ACI_RES_GRP}-container"
readonly ACI_STR_AN="democraftstorage"

これを Azure CLI がインストールされた環境で実行すると Azure 上にサーバーができあがります。僕は Azure CLI をインストールするのが面倒だったので、Azure Portal に付属している Cloud Shell から叩きました。

f:id:xin9le:20190708033007p:plain

Step.2 : 接続確認

サーバーが出来上がったら接続確認をしてみましょう。執筆時点で構築したサーバーは v1.14.3 なので、v1.14.3 でプレイするのが良いのではないかと思います。

  1. Minecraft Java Edition (v1.14.3) を起動
  2. [マルチプレイ] - [ダイレクト接続] を開く
  3. [サーバーアドレス] に Azure Container Instances の IP アドレス or FQDN を入力
  4. [サーバーに接続] をクリック

内容に問題がなければこれで接続できます。僕の場合、サーバーアドレスは xin9ledemocraft-container.japaneast.azurecontainer.io となりました。

f:id:xin9le:20190708035640p:plain

Step.3 : C# からコマンドを投げてみる

最後に C# で Minecraft のコマンドを送信してみましょう。Minecraft のコマンドは RCON なるプロトコルでやりとりされるようです。単純な REST API じゃないので HttpClient ではダメで、古き良き (?) Socket プログラミングが求められます。とはいえ (当然ながら) 先駆者はいるので、ありがたく先人の作ったライブラリを使わせていただきましょう。今回は .NET Standard に対応している CoreRCON *1 というライブラリを使ってみます。

PM> Install-Package CoreRCON

以下のようなコードを書いて実行してみます。するとあら不思議!昼が夜になる!

async Task Main()
{
    var fqdn = "xin9ledemocraft-container.japaneast.azurecontainer.io";
    var ipAddresses = await Dns.GetHostAddressesAsync(fqdn);
    var ipAddress = ipAddresses.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork);
    ushort port = 25575;
    var password = "すごく文字列です";
    var command = "/time set night";  // テクマクマヤコン!夜にな〜れ!

    var connection = new CoreRCON.RCON(ipAddress, port, password);
    var result = await connection.SendCommandAsync(command);
    Console.WriteLine(result);
}

f:id:xin9le:20190708041011p:plain

調子に乗って昼と夜を 3 秒ごとにパッパッと切り替わるようにしてみましょう。特に意味のないイタズラですw

async Task Main()
{
    var fqdn = "xin9ledemocraft-container.japaneast.azurecontainer.io";
    var ipAddresses = await Dns.GetHostAddressesAsync(fqdn);
    var ipAddress = ipAddresses.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetwork);
    ushort port = 25575;
    var password = "すごく文字列です";
    var commands = new []{ "/time set day", "/time set night" };
    var connection = new CoreRCON.RCON(ipAddress, port, password);

    var isDay = true;
    while (true)
    {
        await Task.Delay(3000);
        var index = Convert.ToInt32(isDay);
        var command = commands[index];
        var result = await connection.SendCommandAsync(command);
        Console.WriteLine($"{DateTimeOffset.Now} - {result}");
        isDay = !isDay;
    }
}

まとめ

C# を使った Minecraft 自動化の第一歩として、Azure 上に Minecraft サーバーを立てて C# からコマンド発行するところまでやってみました。「#くらでべ の写経してみた」という薄っぺらい記事ですが、ここまでできれば後は C# で自由自在!子供たちから「すごい!」と言ってもらえること間違いナシですよ!

あ、途中の Deploy Script で立ち上げた Azure Container Instances はすごくお高いヤツなので、使い終わったら必ず停止しましょう!くれぐれもクラウド死しないようご注意ください。

*1:すでにメンテナンスはされていないらしい