🖥

C# で Minecraft プログラミングを始めよう!

2022/08/21に公開

はじめに

マイクラといえば「ゲーム」というイメージがあるかと思いますが, 実は「学習ツール」としても活用することができます. ここでは, マイクラを軸にクラウドサービス (Microsoft Azure) の利用方法と C# 言語を用いたプログラミングについてご紹介します. マイクラサーバの構築方法と, プログラムを活用したマイクラの自動化について知っていただけたら嬉しいです.

使用環境

  • Minecraft Java Edition 1.19
  • Windows 10
  • Microsoft Azure
  • Visual Studio 2022

必要なもの

  • Minecraft Java Edition
  • Microsoft アカウント (Minecraft を遊ぶのに必要です)
  • Azure クレジット (Azure for Students も可)

学生向け Azure クレジット (年間100ドル分) をもらえる, Azure for Students の登録方法はこちらを参考にしてください.

https://youtu.be/vXuwcdYUpA8

イベントについて

本資料は Microsoft Learn Student Ambassadors が主催する MS Tech Camp #17 のイベントで使用している資料です.

https://mspjp.connpass.com/event/249964/

前半:マイクラサーバ構築 & ゲーム設定
後半:マイクラプログラミング入門

1. マイクラサーバの構築

1.1 リソースグループの作成

リソースグループは各種サービス(リソース)を格納しておくためのコンテナです. これを作っておけば, マイクラサーバを構築するのに必要な仮想マシン, ディスク, ネットワークインターフェースなどを1箇所へまとめておくことができます. 必要無くなったときも, リソースグループごと一括で削除することもできるので便利です.

まずは リソースグループ を選択します.

次に, 作成 をクリックして, リソースグループの名前を決めます.

ここでは次のような設定値を例に進めていきます.

項目 入力例
サブスクリプション Azure for Students
リソースグループ rg-minecraft-server
リージョン (Asia Pacific)Japan East

記入できたら画面下にある 確認および作成 をクリックします.

検証に成功しました という表示が出たら 作成 をクリックしてください. もし, 作成できなかった場合はもう一度リソースグループの作成からやり直してみてください.

これでリソースグループの作成は完了です!

1.2 仮想マシンの作成

一度, Azure ポータルの ホーム に戻り, リソースの作成 をクリックします.

リソースの作成画面から, Ubuntu Server 20.04 LTS を探し, 作成 をクリックします.

一覧に表示されない場合

一覧に表示されない場合は検索欄から Ubuntu Server 20.04 LTS を入力して, 検索候補から選択してください.

表示されたらバージョンが 20.04 LTS になっていることを確認して 作成 をクリックします.

仮想マシンの作成に必要な入力欄ですが, ここでは下記のように設定します. (2022/08/19 の時点で地域から日本エリアが選択できなくなっています. この場合はお住まいの地域から近い国を選択することをおすすめします.)

項目 設定例
サブスクリプション Azure for Studnets
リソースグループ rg-minecraft-server
仮想マシン名 vm-minecraft-server
地域 (Asia Pacific) Japan East
可用性オプション インフラストラクチャ冗長は必要ありません
セキュリティの種類 Standard
イメージ Ubuntu Server 20.04 LTS - Gen2
Azure Spot 割引で実行する なし
サイズ Standard_B2s
認証の種類 SSH 公開キー
ユーザ名 azureuser
SSH公開キーのソース 新しいキーの組の生成
キーの組名 vm-minecraft_key
パブリック受信ポート 選択したポートを許可する
受信ポートを選択 SSH (22)

ユーザ名やキーの組名(秘密キーのファイル名)は自由に決めてください.

仮想マシンのサイズ選択について

サイズの項目から すべてのサイズを表示 をクリックします.

Azure ユーザが最もよく使用 の欄に B2s があればこれを選択してください.

もし, 一覧になければ Bシリーズ の中にありますので探してみてください.

サイズ選択すると元の画面にもどりますので, サイズが Standard_B2s になっていることを確認してください.

仮想マシンのサイズ(メモリ容量)の目安

マイクラサーバは少なくとも 2GB 割り振ることを推奨されています. マイクラへのリソースを 2GB 割くことを考えると OS へのリソースが割り当ても考慮して余裕を見て 4GB を選択しておくのが無難です.

ここでは1人でマルチプレイを行う想定ですが, 4人以上集まるようであれば 3GB を割り当てておくと安心です. これは Mod やプラグインを入れるかにもよりますが, 個人的な感覚では2人あたり 1GB 増やすと良いかもしれません.

ちなみに, Azure VM のサイズは後からでも自由に変えられるので, スペック不足になってきたら高スペックを選択し, 逆にスペック過多になったら低スペックを選択してコストを下げることもできます. Azure は使った分だけ課金が発生するので, 適宜調整していけば安く抑えることができます.

記入できたら, 確認および作成 をクリックします.

確認できたら 作成 をクリックして仮想マシンを作成します.

秘密キーのダウンロードとリソースの作成 をクリックして自分の PC 上に秘密キーをダウンロードしてください. 仮想マシンに接続するのに使用しますので, 必ず大切に保管してください.

デプロイが完了したら リソースに移動 をクリックしてください.

仮想マシンのダッシュボードが表示されれば, 仮想マシンの作成は完了です.

起動したままにしておくと, 課金されてしまうので使用しないときは 停止 をクリックして仮想マシンを止めておくのをオススメします.

1.3 ネットワーク設定

次に, 作成したサーバに DNS ラベルとポート番号の設定を行います. まずは仮想マシンを停止してください. 停止できたら パブリック IP アドレス のアドレス部分をクリックしてください.

DNS 名ラベル(オプション)の入力欄に好きなアドレスを入力します. この例では mstechcamp-minecraft という名前にしています. ここのアドレスはユニーク(世界でただ1つ)である必要があります. もし, チェックがつかない場合は別の命名を試してみてください.

DNS 名を記入できたら 保存 をクリックして, パンくずリストからダッシュボードへ戻ります.

次に, ダッシュボードの左側の一覧から ネットワーク を選択してください.

受信ポートの規則を追加する をクリックします.

受信セキュリティ規則の追加を次のような設定にします.

項目 記入例
ソース Any
ソースポート範囲 *
宛先 Any
サービス Custom
宛先ポート範囲 25565
プロトコル TCP
アクション 許可
優先度 310
名前 MinecraftServer
説明 なし

書けたら 追加 をクリックしてください. 受信ポートの規則から MinecraftServer のポート 25565 が追加されていれば OK です.

さらに, 今回はリモートコンソール (RCON) 接続も行いますので, そのためのポート 25575 も設定しておきます.

項目 記入例
ソース Any
ソースポート範囲 *
宛先 Any
サービス Custom
宛先ポート範囲 25575
プロトコル TCP
アクション 許可
優先度 320
名前 MinecraftRcon
説明 なし

できたら先と同様に 作成 をクリックして, 追記されているか確認してください. 図のようになっていればポートの設定は完了ですので, パンくずリストからダッシュボードへ戻ってください.

1.4 マイクラサーバのセットアップ

次に, 仮想マシンにて Minecraft Server を構築していきます. 仮想マシンのダッシュボードから 起動 をクリックして, 仮想マシンを立ち上げます. 1分ほどで起動しますので, その間に SSH 接続コマンドを用意します.

秘密キーは先程 DL したものを使用します.

ssh -i <秘密キーのパス> azureuser@<DNSラベル>.koreacentral.cloudapp.azure.com

私の環境ではこんな感じです.

ssh -i C:\Users\<User>\Desktop\vm-minecraft-server_key.pem azureuser@mstechcamp-minecraft.koreacentral.cloudapp.azure.com

お使いのターミナル(私の環境では)から Windows Terminal から上記のコマンドを使用して, 仮想マシンへ接続します.

下記のような質問をされたら yes を入力して実行してください.

Are you sure you want to continue connecting (yes/no/[fingerprint])?

このような画面が表示されれば仮想マシンへの接続は完了です.

次に, サーバファイルを入れておくためのディレクトリを作成して移動します.

mkdir MinecraftServer && cd $_

次に, Java 17 を導入するためのパッケージを取ってきます

sudo add-apt-repository ppa:linuxuprising/java -y

次に, アップデートを行います.

sudo apt update

次に, Java 17 をインストールします. (Minecraft 1.19 系は java 17 で動作します.)

sudo apt install openjdk-17-jdk -y

インストールが完了したら, バージョンの確認をしてみてください. このような表記になっていれば OK です.

java --version
openjdk 17.0.4 2022-07-19
OpenJDK Runtime Environment (build 17.0.4+8-Ubuntu-120.04)
OpenJDK 64-Bit Server VM (build 17.0.4+8-Ubuntu-120.04, mixed mode, sharing)

次に, マイクラサーバのソフトウェアをダウンロードします. ここでは最新版の 1.19.2 のセットアップを行います.

curl -L -O https://piston-data.mojang.com/v1/objects/f69c284232d7c7580bd89a5a4931c3581eae1378/server.jar

次に, 起動ファイルの作成を行います.

sudo vim start.sh
Vim の操作方法

vim でファイルを開くと, このような表示になります.

ここで, キーボードの i キーを押すと挿入モードになります. 挿入モードのときは左下に INSERT と表示されます.

この状態で文字の入力を行うことができます. 入力が終わったら, キーボードの ESC キーを押すと挿入モードが解除されます.

この状態で :wq と入力してエンターキーを押すとファイルを保存して Vim が終了します. 保存したくない場合は :q! と入力してエンターキーを押します.

ファイルの中身はこのようにします. 出来たら保存して終了してください.

start.sh
java -Xmx2G -Xms2G -jar server.jar

次に, 作成したファイルに実行権限を付与します.

sudo chmod o+x start.sh

次に, 起動ファイルを実行してサーバを立ち上げます.

./start.sh

初回起動時には同意書 (EULA) への同意が必要ですので, このようなエラーが表示されます.

[16:47:34] [ServerMain/INFO]: Building unoptimized datafixer
[16:47:36] [ServerMain/ERROR]: Failed to load properties from file: server.properties
[16:47:36] [ServerMain/WARN]: Failed to load eula.txt
[16:47:36] [ServerMain/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.

同意書への同意は下記のコマンドを実行します.(同意書は後で確認しておきます.)

echo eula=true > eula.txt

実行したら再度 ./start.sh を実行してサーバを立ち上げてみてください. 起動が完了するとコンソールの最後に Done と表示されます.

ここまでで, マルチプレイ用のサーバ構築は完了です!(普通に遊ぶだけならば Minecraft ランチャーでサーバとのバージョンを合わせて起動構成を作成し, マルチプレイから参加すれば遊べます.)

1.5 Minecraft Launcher の設定

次は Minecraft Launcher での作業になります.

まずは 起動構成 タブを開いて, 新規作成 をクリックします.

起動構成の作成画面にて, 次のような設定で作成します. ゲームディレクトリと名前はわかりやすいように設定してください. ゲームディレクトリにはゲームの設定ファイルなどが格納されます. また, バージョンは 必ずサーバとバージョンをあわせて ください.

項目 記入例
名前 Azure Server
バージョン release 1.19.2
ゲームディレクトリ C:\Users\takun\Desktop\AzureServer

記入できたら 作成 をクリックします.

プレイ タブをクリックして起動構成を先程作成したものに変更し, ゲームを開始します.

ゲームが起動したらまずは言語を日本語に設定します.

音量が大きい場合は 設定 から サウンド設定 を開くと設定できます.

設定が済んだら, マルチプレイ を選択します. 警告文が出てきたら この画面を再度表示しない にチェックを入れて 続ける をクリックします.

サーバを追加 をクリックして, サーバ名とサーバアドレスを入力します.

サーバアドレスは仮想マシンで設定した DNS 名を入力します. 仮想マシンのダッシュボードからコピペしましょう.

入力できたら 完了 をクリックします.

マルチプレイ選択画面に戻ってきたら, 電波のマークが緑色になっていることを確認してください. 緑色になっていれば接続できる状態ですので, 作ったサーバを選択して サーバに接続 をクリックしてください.

こんな感じでログインできればセットアップ完了です!

2. サーバとゲームの設定

2.1 RCON の設定

ここからはマイクラプログラミングをするための設定を行います. まずはゲームからログアウトして, マイクラサーバを停止します.

サーバコンソール上では下記のコマンドを実行します. 正しく終了されないとセーブデータが破損する可能性がありますので, 必ず実行してください.

stop

ここからはサーバコンソール上での作業になります. まずは Vim を使って server.properties のファイルを開きます.

sudo vim server.properties

開けたら挿入モードにして, 下記の3つの項目の設定を変更してください. enable-rcon がリモートコンソールを許可するかどうかの設定で, そのパスワードも設定しておきます. また, 設定の上にほうには rcon.port という設定項目がありますが, これが RCON 接続用のポート番号です. すでに Azure 上でポート設定をしていますので, このままにしておきます.

server.properties
enable-rcon=true
rcon.password=minecraft

できたら上書き保存して, サーバをもう一度起動します. 起動すると, 先程と少し表記がかわるはずです. 下記のような表示が出れば RCON 接続の準備ができています.

[17:34:02] [Server thread/INFO]: Starting remote control listener
[17:34:02] [Server thread/INFO]: Thread RCON Listener started
[17:34:02] [Server thread/INFO]: RCON running on 0.0.0.0:25575

2.2 ゲーム設定

次に, コンソールからプレイヤーへ管理者権限を付与します.

op <PlayerID>

次に, マイクラ本体へ移動して, もう一度サーバへログインします. 管理者用のコマンドが使える様になっていますので, いくつかの設定値を変更します. マイクラ上から下記コマンドを実行してください.

/gamemode creative
/gamerule doDaylightCycle false
/gamerule doWeatherCycle false

もし, ワールドが夜になっていたら昼にするコマンドを実行します.

/time set noon

ここまででやってきたゲームの設定は

  • ゲームモードをクリエイティブモードにする
  • 時間経過をオフにする
  • 天候変化をオフにする

の3つです. コーディング中にゾンビに襲われたり, 雨が降ったりすると色々面倒なので, この設定をしておくことをオススメします.

3. マイクラプログラミング入門 (C#)

ここからはイベント後半です.

3.1 MinecraftConnection の導入

マイクラでテキストプログラミングをやる場合は Python の mcrcon や, MakeCode にて JavaScript を使用したプログラムを書くのが一般的ですが, 今回は MinecraftConnection というライブラリを使用して C# でコーディングしていきます.

https://github.com/takunology/MinecraftConnection

.NET Standard 2.1 以上の環境であればどこでも動かせますので, Azure Functions, Visual Studio, VS Code などでも導入できます. お好きな環境に合わせて導入してみてください.

Azure Functions で使用する

Azure のホームから リソースの作成 をクリックし, 関数アプリ を選択します.

必要項目を次のように記入して, 確認および作成 をクリックします.

項目 記入例
サブスクリプション Azure for Students サブスクリプション
リソースグループ rg-minecraft-server
関数アプリ名 func-minecraft-app
公開 コード
ランタイムスタック .NET
バージョン 6
地域 Japan East
オペレーティングシステム Windows
プランの種類 App Service プラン
Windows プラン (Japan East) <そのままでOK>
プランの種類 Free F1
ゾーン冗長 無効

App Service プランならば無料で使えますので, ぜひ利用してみてください. もし, 他のリソースで Free プランを使用している場合は表示されない場合があるので, その場合は別のプランを選択してください.

確認できたら 作成 をクリックしてデプロイが完了するまで待ちます. 完了したら リソースへ移動 をクリックして関数アプリのダッシュボードを開きます.

左側のメニューから 関数 を選択し, 作成 をクリックします. トリガーは何でも良いですが, ここでは HTTP Trigger を選択し, そのまま 作成 をクリックします.

関数を作成できたら一度, 関数アプリのダッシュボードへ戻り, 左側のメニューから App Service Editor (プレビュー) を開き, 移動 をクリックします.

HttpTrigger1 ディレクトリにて右クリックし, New File をクリックします. ファイル名は必ず function.proj にしてください. このファイルは NuGet パッケージを導入するための特別な意味を持ちます.

ファイルを作成できたら, 下記の内容を記述してください.

function.proj
<Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
              <TargetFramework>netstandard2.1</TargetFramework>
       </PropertyGroup>
       <ItemGroup>
              <PackageReference Include="MinecraftConnection" Version="2.0.1"/>
       </ItemGroup>
</Project>

書けたら再び関数アプリのダッシュボードから 関数 を開き, 作った関数を選択します.

コードとテスト を選択するとコーディングできるようになります. これで Azure Functions の設定は完了です.

Visual Studio で使用する

コンソールアプリケーション (C#) を作成したら パッケージマネージャーコンソール を開きます.

コンソールにて下記コマンドを実行すると導入できます.

install-package MinecraftConnection

簡単ですね!

VS Code で使用する

dotnet コマンドを使用して, プロジェクトを作成します.

dotnet new console -o MinecraftApp

作成したディレクトリを VS Code から開きます.

拡張機能で NuGet を導入できるものをインストールしておきます. 私の環境では NuGet Package Manager を使用します.

Ctrl + Shift + P でコマンドパレットを開いて, Nuget と入力すると Add Package という項目が出てきますので, これを選択します.

検索欄に MinecraftConnection と入力し, 最新バージョンを選択して導入します.

このような表記がでれば導入完了です!
あとは dotnet restore を実行して再度読み込みを行ってください.

3.2 文字を表示と待機

ここからは MinecraftConnection を実際に使用していきます. まずは, 仮想マシンを起動してマイクラサーバを立ち上げます. 起動できたらゲームにログインしてください. ログインした状態で, キーボードの / を押すとアクティブウィンドウからエスケープすることができます. この状態でプログラムを書いていきます.

どのエディタでも良いので, まずは基本となるコードを書きます. 今回はトップレベルステートメントを使用して書きます.

using MinecraftConnection;

string address = "mstechcamp-minecraft.koreacentral.cloudapp.azure.com";
ushort port = 25575;
string pass = "minecraft";

MinecraftCommands commands = new MinecraftCommands(address, port, pass);

ここまでが共通のテンプレートです. 上から順にサーバのアドレス, RCON のポート番号, パスワード, そしてコマンド送信用のインスタンスです. この commands には色々なメソッドが用意されていますので, 試していきます.

DisplaryTitle メソッド

このメソッドはゲーム画面の中心に大きなタイトルを表示します.

commands.DisplayTitle("Hello, Minecraft!");

フェードイン・フェードアウトの効果がついているので, 連続して表示するのには向きませんが, 演出したいときにオススメです.

DisplayMessage メソッド

ゲーム画面のチャット欄に文字列を出力します.

commands.DisplayMessage("Hello");
commands.DisplayMessage("from");
commands.DisplayMessage("C#!");

チャット欄にすぐ表示されるので, 連続して表示したいときに向いています.

Wait メソッド

指定した時間(ミリ秒)だけコマンドの実行を待機します.

commands.DisplayMessage("Hello");
commands.Wait(1000);
commands.DisplayMessage("from");
commands.Wait(1000);
commands.DisplayMessage("C#!");

例えばブロックを配置するときに, その配置している様子をゆっくり見たいときは Wait メソッドを使ってコマンドの実行を遅らせるということもできます. また, 花火を打ち上げるときにも時間差を与えることができます.

いろんな言語を表示する

英語だけでなく, 日本語や中国語, アラビア語なども表示できます.

commands.DisplayMessage("Welcome");
commands.DisplayMessage("ようこそ");
commands.DisplayMessage("欢迎");
commands.DisplayMessage("أهلا وسهلا");

色々と試してみると面白いかもしれません.

3.3 ブロックを設置する

文字出力だけでは面白くないと思いますので, マイクラの醍醐味であるブロックの配置をやってみましょう.

SetBlock メソッド

指定した座標へプロックを設置することができるメソッドです. Position 構造体を利用することもできますが, 型変換が必要です.

commands.SetBlock(-7, 69, -10, "stone");

Position pos = new Position(-7, 69, -10);
commands.SetBlock((int)pos.X, (int)pos.Y, (int)pos.Z, "stone");
説明
第1引数 int ブロックを置く座標 x
第2引数 int ブロックを置く座標 y
第3引数 int ブロックを置く座標 z
第4引数 string ブロックID

上記の例では (x, y, z) = (-7, 69, -10) の位置に石ブロックを配置するプログラムです. ブロックIDにはそれぞれユニークな文字列が割り振られています. ここでは紹介しきれないので, ブロックIDに関してはマイクラWikiを参考にしてください.

https://minecraft.fandom.com/ja/wiki/データ値/Java_Edition

直線上にブロックを置く

for 文を使って直線上にブロックを置いていきます. ここでは金ブロックを設置してみます.

for(int i = 0; i < 5; i++)
{
    commands.SetBlock((int)pos.X + i, (int)pos.Y, (int)pos.Z, "gold_block");
}

ブロックを設置していくと, 視覚的にもわかりやすいのが良い点です. さらに, 条件式と更新式を少し変更してみると

for(int i = 0; i < 10; i+=2)
{
    commands.SetBlock((int)pos.X + i, (int)pos.Y, (int)pos.Z, "gold_block");
}

このように, ブロックを設置する個数は変わりませんが, 1ブロック空けながら設置することができます.

平面にブロックを置く

二重 for 文を使えば平面を作ることができます. (縦✕横のイメージ)

for(int i = 0; i < 5; i++)
{
    for(int j = 0; j < 5; j++)
    {
        commands.SetBlock((int)pos.X + i, (int)pos.Y, (int)pos.Z + j, "gold_block");
    }    
}

上記の例では地面と平行して平面を作りましたが, pos.Y にインクリメントしていけば垂直に平面を作ることもできます.

立体をつくる

三重 for 文を使用すれば立体をつくることができます. (縦✕横✕高さのイメージ)

for(int i = 0; i < 5; i++)
{
    for(int j = 0; j < 5; j++)
    {
        for(int k = 0; k < 5; k++)
        {
            commands.SetBlock((int)pos.X + j, (int)pos.Y + i, (int)pos.Z + k, "gold_block");
        }
    }    
}

整地する

三重 for 文を使えば立体を作ることができましたが, これをうまく利用すると整地(土地を平らにすること)ができるようになります. やり方は立体を作ったときと同じで, ブロックの種類を空気ブロック air にするだけです.

for(int i = 0; i < 5; i++)
{
    for(int j = 0; j < 5; j++)
    {
        for(int k = 0; k < 5; k++)
        {
            commands.SetBlock((int)pos.X + j, (int)pos.Y + i, (int)pos.Z + k, "air");
        }
    }    
}

さきほど設置した金ブロックの座標を使ってそのまま実行してみてください.

これを山や木など邪魔なブロックがある座標を指定して実行すれば, まっさらな土地にすることができます.

3.4 位置情報を利用する

プレイヤーの位置を取得する

GetPlayerData メソッドの Position というプロパティを参照すると, プレイヤーのいる座標を取得することができます.

var pos = commands.GetPlayerData("takunology").Postision;
Console.WriteLine($"{pos.X}\t{pos.Y}\t{pos.Z}");

リアルタイムで取得する場合は反復処理を使います.

while(true)
{
    var pos = commands.GetPlayerData("takunology").Postision;
    Console.WriteLine($"{pos.X}\t{pos.Y}\t{pos.Z}");
}

座標を使った条件分岐

ある座標を監視しておいて, その座標へきたらメッセージを表示するような処理も作れます.

while(true)
{
    var pos = commands.GetPlayerData("takunology").Postision;
    Console.WriteLine($"{pos.X}\t{pos.Y}\t{pos.Z}");
    if (pos.Y > 70)
    {   
        commands.DisplayMessage($"高さが70ブロックを超えました");
        break;
    }
}

歩いてきた道に松明を置く

リアルタイムに座標を取得できるのを利用して, 松明を置くような処理も作れます.

while(true)
{
    var pos = commands.GetPlayerData("takunology").Postision;
    Console.WriteLine($"{pos.X}\t{pos.Y}\t{pos.Z}");
    commands.SetBlock((int)pos.X, (int)pos.Y, (int)pos.Z, "torch");
}

プレイヤーの座標を取得できると, 相対座標として扱えるので便利です.

3.5 チェスト内のアイテムを操作する

GetChestItems メソッド

指定した座標にあるチェストの中身を取得します.

var chestPos = new Position(-449, 63, 58);
var chestItems = commands.GetChestItems(pos);

中身を取得した後は, 例えば並び変えたり書き換えたりしてチェスト内のアイテムを整理することができるようになります.

SetChestItems メソッド

指定した座標にあるチェストの中身を書き換えます.

var chestPos = new Position(-449, 63, 58);
var chestItems = new List<ItemStack>
{
    new ItemStack(0, "diamond", 4),
    new ItemStack(0, "stone", 16),
    new ItemStack(0, "oak_planks", 28),
    new ItemStack(0, "gold_ingot", 2)
}
commands.SetChestItems(chestPos, chestItems);

ItemStack は第一引数から順番にスロット番号, アイテムID, 数量の順で定義します. 好きなアイテムに書き換えることができます.

アイテムをソートする

List<ItemStack> には拡張メソッドとしてソートする機能があります. 例えば, チェストの中身がこのような状態であったとします.

これをそのまま GetChestItems によって取得して, その中身をコンソール出力してみます.

var items = commands.GetChestItems(pos);
items.ForEach(x => Console.WriteLine($"{x.Slot}\t{x.Id}\t{x.Count}"));
出力結果
0       minecraft:chest 1
1       minecraft:stone 62
2       minecraft:oak_planks    1
3       minecraft:oak_planks    1
4       minecraft:stone 1
5       minecraft:redstone      32
6       minecraft:redstone      16
7       minecraft:amethyst_block        13
8       minecraft:stone 1
9       minecraft:amethyst_block        15
10      minecraft:torch 16
11      minecraft:redstone      8
12      minecraft:tnt   32
13      minecraft:amethyst_block        1
14      minecraft:oak_planks    1
15      minecraft:oak_planks    29
16      minecraft:torch 10
17      minecraft:torch 6
18      minecraft:copper_block  1
19      minecraft:oak_planks    32
20      minecraft:torch 32
21      minecraft:amethyst_block        16
22      minecraft:redstone      8
23      minecraft:tnt   32
24      minecraft:copper_block  3
25      minecraft:copper_block  60
26      minecraft:amethyst_block        19

では, アイテムを名前順に並び替えてみましょう. アイテム名の順に並び替えるには SortById() を使用します.

using MinecraftConnection.Extends;
var items = commands.GetChestItems(pos).SortById();
items.ForEach(x => Console.WriteLine($"{x.Slot}\t{x.Id}\t{x.Count}"));
名前順に並び替えた結果

AからZにかけて並び替えが行われます.

0       minecraft:amethyst_block        13
1       minecraft:amethyst_block        15
2       minecraft:amethyst_block        1
3       minecraft:amethyst_block        16
4       minecraft:amethyst_block        19
5       minecraft:chest 1
6       minecraft:copper_block  1
7       minecraft:copper_block  3
8       minecraft:copper_block  60
9       minecraft:oak_planks    1
10      minecraft:oak_planks    1
11      minecraft:oak_planks    1
12      minecraft:oak_planks    29
13      minecraft:oak_planks    32
14      minecraft:redstone      32
15      minecraft:redstone      16
16      minecraft:redstone      8
17      minecraft:redstone      8
18      minecraft:stone 62
19      minecraft:stone 1
20      minecraft:stone 1
21      minecraft:tnt   32
22      minecraft:tnt   32
23      minecraft:torch 16
24      minecraft:torch 10
25      minecraft:torch 6
26      minecraft:torch 32

アイテムの数量順に並び替えるには SortByCount を使用します.

var items = commands.GetChestItems(pos).SortItems();
数量順に並び替えた実行結果

数量の少ない順に並び替わります.

0       minecraft:chest 1
1       minecraft:oak_planks    1
2       minecraft:oak_planks    1
3       minecraft:stone 1
4       minecraft:stone 1
5       minecraft:amethyst_block        1 
6       minecraft:oak_planks    1
7       minecraft:copper_block  1
8       minecraft:copper_block  3
9       minecraft:torch 6
10      minecraft:redstone      8
11      minecraft:redstone      8
12      minecraft:torch 10
13      minecraft:amethyst_block        13
14      minecraft:amethyst_block        15
15      minecraft:redstone      16        
16      minecraft:torch 16
17      minecraft:amethyst_block        16
18      minecraft:amethyst_block        19
19      minecraft:oak_planks    29
20      minecraft:redstone      32
21      minecraft:tnt   32
22      minecraft:oak_planks    32
23      minecraft:torch 32
24      minecraft:tnt   32
25      minecraft:copper_block  60
26      minecraft:stone 62

それぞれ降順に並び替えるには SortByIdDescending または SortByCountDescending を使用します.

また, 並び替えた後に SetChestItems を使用すれば, 実際にチェストの中身を並び替えることもできます.

var items = commands.GetChestItems(pos).SortById();
commands.SetChestItems(pos, items);

鉱石つかみゲーム

チェストの中身を書き換えるのをうまく利用して, 動き回るアイテムを掴むゲームを作ることができます.

while (true)
{
    Random rand = new Random();
    var myItem = new List<ItemStack>
    {
        new ItemStack((ushort)rand.Next(0, 27), "diamond", 1),
        new ItemStack((ushort)rand.Next(0, 27), "gold_ingot", 1),
        new ItemStack((ushort)rand.Next(0, 27), "iron_ingot", 1),
        new ItemStack((ushort)rand.Next(0, 27), "redstone", 1)
    };
    commands.SetChestItems(chestPos, myItem);
}

https://twitter.com/i/status/1559524059771465728

3.6 花火を打ち上げる

Fireworks クラス

花火を作るためのクラスです.

using MinecraftConnection.Entity;
Fireworks fw = new Fireworks();

このままでは空っぽの花火が打ち上がりますので, 色や形などを指定してあげます.

Fireworks fw = new Fireworks()
{
    LifeTime = 30,
    Type = FireworkType.LargeBall,
    Colors = new List<FireworkColors>{FireworkColors.CYAN},
    FadeColors = new List<FireworkColors>{FireworkColors.WHITE},
    Flicker = false,
    Trail = false
};
プロパティ 説明
LifeTime 花火が打ち上がってから爆発するまでの時間
Type 花火の形状
Colors 花火が爆発したときの色
FadeColors 花火がフェードアウトしていくときの色
Flicker きらめき効果
Trail 流星効果

花火の色は複数選択することができます.

SetOffFireworks メソッド

花火を打ち上げる座標と作った花火インスタンスを引数に, 指定した座標から花火を打ち上げます.

Position pos = new Position(33, 72, 20);
commands.SetOffFireworks(pos, fw);

例えば, 反復処理をうまく使えば何発も打ち上げることができます. 待機時間を設けてあげないと, その場で連続して花火が打ち上がってしまい, 形や色を確認できなくなってしまいます.

for(int i = 0; i < 10; i++)
{
    commands.SetOffFireworks(pos, fw);
    commands.Wait(1000);
}

FireworkOption

拡張メソッドとして, 色をランダムに取得するための機能を用意しています. List のジェネリックを宣言して色を指定するのが面倒な場合は, このようにランダムな色を設定させることができます.

Fireworks fw = new Fireworks()
{
    Colors = FireworkOption.RandomColor(),
};

疑似乱数の利用

疑似乱数を使うとランダムな座標から花火を打ち上げることができます.

Position pos = new Position(-32, 64, -8);

MinecraftCommands commands = new MinecraftCommands(address, port, pass);
Random rnd = new Random();

for(int i = 0; i < 20; i++)
{
    Fireworks fw = new Fireworks()
    {
        LifeTime = 30,
        Type = FireworkType.LargeBall,
        Colors = FireworkOption.RandomColor(),
        FadeColors = new List<FireworkColors>{FireworkColors.WHITE},
    };

    commands.SetOffFireworks(pos.X, pos.Y, pos.Z + rnd.Next(-10, 10), fw);
    commands.Wait(500);
}

もっと複雑な花火をつくるには???
同日21時より行われる「マイクラ花火師入門」のイベントへぜひご参加ください!

https://mspjp.connpass.com/event/249975/

4. リソースの削除

仮想マシンは維持しているだけでも若干の課金が発生しますので, 使用しない場合はリソースをまるごと消去するのがオススメです.

マイクラで遊び終わったらゲームを終了し, サーバコンソールにて stop コマンドを実行して停止します. 次に, Azure ポータルから仮想マシンのダッシュボードへ移動し, 停止ボタンをクリックします.

停止できたら再び Azure のホームに戻り, リソースグループをクリックします. 今回作成したリソースグループを選択します. (今回の例では rg-minecraft-server としました.)

リソースグループの削除 をクリックし, 入力欄にそのリソースグループ名を入力すると 削除 ボタンがアクティブになるので, 削除ボタンをクリックすると削除できます.

おわりに

マイクラ1つでクラウドまわりやプログラミングに触れることができることを知っていただけたら嬉しいです!
この記事は下記の本より一部を抜粋し, 最新版に修正して掲載しております. もし興味があれば(ライブラリバージョンが古いですが)ご覧ください. (フィードバックもお待ちしております.)

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

個人プロジェクトも進めていますので応援していただけると嬉しいです。

https://www.mcwithcode.com/

https://fw.mcwithcode.com/

また、Microsoft Learn Student Ambassadors に興味がある学生さんはぜひご覧ください!
Ambassadors の活動や応募方法についてまとめた資料になります.

https://speakerdeck.com/takunology/ambassadors-meetup-2022

Discussion