Minecraftバニラサーバでも外部アプリから操作する

この記事は[Minecraft Command Advent Calendar 2023](https://qiita.com/advent-calendar/2023/mccmd)の10日目の1シリーズ記事です。

- 10日目 1シリーズ記事: Minecraftバニラサーバでも外部アプリから操作する

https://qiita.com/waxsd100/private/baf3e3bd6e8069f5e81d

- 10日目 2シリーズ記事: YoutubeのコメントをMinecraftに送信する

https://qiita.com/waxsd100/private/f9cc735f3fba6b67bdea

- 10日目 3シリーズ記事: バニラのMinecraftでChatGPTに質問したりてコマンド実行する

https://qiita.com/waxsd100/private/9fe00127c1c63c451fa6

# はじめに

Minecraftでは、RCONプロトコルを使用して外部からコマンドを実行することが可能です。
本記事では、このプロトコルの使用方法について紹介します。

:::note warn
MinecraftのRCONは、Source RCON Protocolに基づいて拡張されています。
そのため、Source RCON Protocol対応のSDKを使用する際は
互換性の問題に注意が必要です。
:::

## クライアント

接続用のクライアントは多数存在しますが、以下にいくつかの有名なものを紹介します。

- mcrcon
  - Windows, Mac, Linuxで使用可能なバイナリファイル。非常にメジャーなクライアントです。

https://github.com/Tiiffi/mcrcon

- async-mcrcon
  - 非同期処理を行う場合に推奨されるクライアント。

https://github.com/MrReacher/async-mcrcon
- CoreRCON
  - C#アプリケーションでの使用に適したクライアント。使い方は以下の記事で詳しく解説されています。
    - [Qiita - CoreRCONの使い方](https://qiita.com/takunology_net/items/4c270331c9559449febd)

https://www.nuget.org/packages/CoreRCON/

- MinecraftConnection
  - 初心者向けで、多機能がラップされているC#ライブラリ。
  - 詳細なリファレンスは[こちら](https://www.mcwithcode.com/Reference/Index)。

https://www.nuget.org/packages/MinecraftConnection

## 実際に使ってみる

今回は初心者にも扱いやすい`MinecraftConnection`クライアントを使用します。

```c#
using MinecraftConnection;

string address = "127.0.0.1";
ushort port = 25575;
string pass = "minecraft";
MinecraftCommands command = new MinecraftCommands(address, port, pass);

// 時間を夜中に設定
command.SendCommand("time set midnight");

// 夜中を通知
command.SendCommand("say 夜中になったよ");
```

まずは簡単に夜中にするコマンドを書いてみます。

設定ファイルはserver.propertiesで設定してください。
ここにあるaddressはサーバのアドレス
port は`rcon.port=25575` の値
password は`rcon.password=minecraft`の値
`enable-rcon=true` は必ずTrueにしてください。

コマンドを送信するには`command.SendCommand("");` を使います。

![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187514/cb082dd6-c290-88b2-b686-df3cec970874.gif)

無事に夜中に設定し、通知することができました。

# プレイヤー情報の取得

特定のプレイヤー情報を取得するには、`Player`クラスを使用します。

```c#
// プレイヤーの名前を設定
string playername = "waxsd100";

// プレイヤーのエンティティ情報を取得
Player player = command.GetPlayerData(playername);

// プレイヤーの座標を取得し、コンソールに出力
Position pos = player.Position;
Console.WriteLine($"{pos.X}\t{pos.Y}\t{pos.Z}");
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187514/fed4211d-fa89-658a-9296-c58fea824c16.png)

これにより、プレイヤーの現在座標を取得できます。リアルタイムで座標を表示したい場合は、以下のような`while`ループを使用します。

```c# 
while (true)
{
    // プレイヤーの名前を設定
    string playername = "waxsd100";

    // プレイヤーのエンティティクラスを取得する
    Player player = command.GetPlayerData(playername);

    // プレイヤーの座標を取得する
    Position pos = player.Position;

    command.DisplayTitle($"{player.EntityId}");
    command.SetSubTitle($"{pos.X:f5},{pos.Y:f5},{pos.Z:f5}");
}
```

![Animation.gif](https://drive.google.com/uc?id=1Pq97YPbE7nW-7Np_yOskHpVbxT1xF-LC)

# 花火の打ち上げ

このライブラリでは花火の操作も簡単です。

```c# 
while (true)
{
    // プレイヤーの名前を設定
    string playername = "waxsd100";

    // プレイヤーのエンティティクラスを取得する
    Player player = command.GetPlayerData(playername);

    // プレイヤーの座標を取得する
    Position pos = player.Position;
    // プレイヤーより5mに高い場所を取得
    Position pos2 = new Position(pos.X, pos.Y+5, pos.Z);
    // ランダムな爆発時間を生成
    int rnd = new Random().Next(10, 60);

    Fireworks fireworks = new Fireworks()
    {
        // 花火が爆発するまでの時間(ランダム時間)
        LifeTime = (ushort)rnd,
        // 花火の形状
        Type = FireworkType.LargeBall,
        // 花火の色（ランダム）
        Colors = FireworkOption.RandomColor(),
        // 爆発後の色
        FadeColors = new List<FireworkColors> { FireworkColors.WHITE },
    };
    // 花火を打ち上げる
    command.SetOffFireworks(pos2, fireworks);
}
```

![Something went wrong](https://drive.google.com/uc?id=1E9JwRHIVt1fiUTXPeIimJZIWKYMsxuYf)

詳細な情報は[Fireworksのドキュメント](https://www.mcwithcode.com/Reference/GitHubDocument?version=ver2&path=Fireworks&fileName=Fireworks)を参照してください。

ただしこのままだと待機がないため、コマンドが限界まで送信されてしまいます。
この場合はWaitを使うことで解決する事ができます。

```c#
while (true)
{
    // 1秒(1000ms)待機
    command.Wait(1000);
    // 現在時刻を取得して通知
    command.SendCommand($"say {DateTime.Now}");

    // ... 10秒たったら花火打ち上げる
}
```

![firetimer (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187514/2cd0fb5f-dd34-4131-80e5-cd7421fa1b7b.gif)



# さいごに

外部からMinecraftにコマンドを送信する方法を学びました。
ライブラリには花火の操作以外にも多くの機能があります。興味があれば、ぜひ触れてみてください。

RCON学については、「たくのろじぃ | Takumi Okawa」さんの記事が参考になるかと思います。　

https://zenn.dev/takunology

応用すれば、農作物の自動収穫、LINE等の外部SNS通知連携、収穫率計測などModのような動きを
することができます。

https://zenn.dev/takunology/books/5c3375fcc105fc

https://zenn.dev/takunology/books/minecraft-programming-book

次回はYouTubeとの連携について紹介します。面白かったらぜひいいねやシェアをお願いします。
それではまた次回。

次回:

https://qiita.com/waxsd100/private/f9cc735f3fba6b67bdea