【Minecraft + C#】村人を遠隔操作する

久しぶりのマイクラ記事です。今回はタイトルにある通り、村人を遠隔操作します。具体的には、村人に指示した方向へ移動してもらいます。

1. 村人のスポーンと指定

まずは操作したい村人を指定する必要があります。方法としては村人の UUID を指定する方法と、NAME を指定する方法があります。が、個人的には後者をおすすめします。前者の方法では、村人のデータタグを確認する必要があるので少し面倒です。

遠隔操作したい村人を指定する場合は、名前をつけた村人をスポーンさせます。また、そのままスポーンさせると移動してしまうので、停止させるためのタグ NoAI:true を付け加えます。したがって、村人スポーンコマンドは次のようになります。

/summon minecraft:villager <x> <y> <z> {CustomName:`{"text":"Villager_01"}`,NoAI:true}

f:id:takunology:20210424130740p:plain

これで Villager_01 という村人が生成されたので、今度は data get コマンドを使用して村人の情報を取得してみます。この村人を指定するには次のようなコマンドにして実行します。

/data get entity @e[name="Villager_01", limit=1]

このコマンドの @e[name="Villager_01", limit=1] についてですが、@e はエンティティを指定するためのアノテーションです。name は名札でつけた名前で、limit はその上限数です。なので、名付けた村人を指定する場合はこの部分をオプションに指定してあげれば良いことになります。

f:id:takunology:20210424131245p:plain

このように村人に関する様々なデータを取得することができます。

2. NoAI の有無について

村人をスポーンさせるとき、NoAI を指定しましたが、これは AI モードのオンとオフを切り替えるものです。オンの状態では、村人は自由に動き回ることができます。オフにすると村人の動きを停止させることができます。

今回、遠隔操作するにあたってポイントになってくるのがこの設定で、オフの状態のままでは指定した方向に歩かせる事ができません。なので、動かす直前にオンに設定し、遠隔操作した後はオフに設定しなければなりません。(オフにするのは放っておくとどこかに行ってしまうからです。)

3. 村人を指定した方向に歩かせる

歩かせる前に、村人の AI モードをオンにします。(村人が逃げないように柵で囲むのをおすすめします。)

/data modify entity @e[name="Villager_01", limit=1] NoAI set value false

これで村人が自由に動き回ります。

次に、このコマンドを実行してみてください。

/data modify entity @e[name="Villager_01", limit=1] Motion[1] set value 0.7d

村人がジャンプします。value の後の値を自由に変えることでジャンプ力が変わりますが、大きい値にすると落下ダメージを受けるので注意が必要です。

さて、このコマンドのポイントになるのは Motion[1] set value 0.7d の部分です。まず、Motion の部分は配列になっており、それぞれ

Motion[0] => x 座標
Motion[1] => y 座標
Motion[2] => z 座標

のようになっています。つぎに、set value ですが、これは読んでそのままの通り、Motion に対する値を設定します。上記の例では 0.7d という値に設定しました。これをうまく使うと任意の方向へ動かす事ができます。正確には加速させることになります。

例えば、

/data modify entity @e[name="Villager_01", limit=1] Motion[0] set value 0.5d

とすれば村人を x 座標に 0.5d だけ加速させることができますし、

/data modify entity @e[name="Villager_01", limit=1] Motion set value [0.5d, 0.5d, 1d]

とすれば x 座標に 0.5d, y 座標に 0.5d, z 座標に 1d だけ加速させる事ができます。

これを応用すれば、村人に対して指定した方向へ歩かせることも可能です。

4. 村人を歩かせてみた

ここからは応用例です。コマンドを1つ1つ手で打つのがすごく面倒なので、プログラムで自動化してみます。

今回は C# コンソールアプリで、MinecraftConnectionCore ライブラリ を使用して実装します。

ソースコードはこんな感じです。

using System;
using System.Net;
using MinecraftConnectionCore;

class Program
{
    private static readonly IPAddress address = IPAddress.Parse("127.0.0.1");
    private static readonly string pass = "minecraft";
    private static readonly ushort port = 25575;
    private static MinecraftCommands commands = new MinecraftCommands(address, port, pass);

    private static readonly string villager = "@e[limit=1,name=\"Villager_01\"]";

    static void Main(string[] args)
    {
        Console.WriteLine("Remort Control to Villager.");

        while (true)
        {
            commands.SendCommand($"/data modify entity {villager} NoAI set value false");
            MotionX(-1.1);
            commands.Wait(500);
            MotionZ(-1.1);
            commands.Wait(500);
            MotionX(1.1);
            commands.Wait(500);
            MotionZ(1.1);
            commands.Wait(500);
            commands.SendCommand($"/data modify entity {villager} NoAI set value true");
        }
    }

    static void MotionX(double x)
    {
        commands.SendCommand($"/data modify entity {villager} Motion[0] set value {x}");
    }

    static void MotionZ(double z)
    {
        commands.SendCommand($"/data modify entity {villager} Motion[2] set value {z}");
    }
}

これを実行するとこのようになります。

f:id:takunology:20210424144209g:plain

本当はぐるぐるするはずなのですが、AI をオンにしている間は村人自身が動くので、座標にズレが生じます。解決策としては、他の加速の成分をゼロにするしかないかもしれません。AI をオフにした瞬間、動かなくなってしまうので少し工夫が必要です。

5. おわりに

今回は村人を遠隔操作する方法についてやりました。これを応用すれば村人に何か作業させることができるかもしれません。強化学習を使うなどして何かをクラフトしたり、洞窟を探検できるような村人とかできたら面白いと思います。

ちなみに、Project Malmo や MineRL などのマイクラ用の人工知能をつくるプロジェクトがあります。これらは村人ではなくプレイヤーを操作しているみたいです。

www.microsoft.com

minerl.io

人工知能でダイヤ鉱石を掘ったり、様々なミッションをクリアしたりと様々なことを行っているので興味があればぜひご覧ください。