py-mcwsの仕組みを見てみよう

クロームブックのマインクラフト統合版でプログラミングをしてみるで触れましたpy-mcwsについて改修しながら仕組みを見ていきましょう。


マインクラフト統合版でプログラミンをする時は、WebSocket(ウェブソケット)サーバを立ち上げて、マインクラフトとメッセージを送り合うような処理を書いていきます。


WebSocketはブラウザとウェブサーバーとの間で双方向通信を行うための通信規格と説明されていることを良く見かけますが、この内容は難解であるため、一通りプログラミングを 体験した後にWebSocketに関して詳しく記載されている読み物を探して読むことをおすすめします。




今回はメッセージを送り合うイメージを体感する為に、マインクラフト側でブロックを壊したという合図(メッセージ)をサーバに送信したら、サーバからマインクラフトに何らかのコマンドを送信するという処理を書いてみます。


/home/******(ユーザ名が入る)/workspace/ws-server/main.pyのファイルを下記のように書き換えてみます。

※もし前回の記事から続けて読んでいる場合は、クロスティーニの画面でctrl + cを押し、サーバを停止した後にコードの編集画面を開きます。

※ctrl + cについて詳しく知りたい方はシグナル(Unix)#個々のシグナル - WikipediaSIGINTをご覧ください

import py_mcws

server = py_mcws.WebsocketServer()

@server.event
async def on_ready(host, port):
    print(f"サーバーを起動しました。\n'/connect {host}:{port}'で接続できます")

@server.event
async def on_connect():
    print("接続しました")

@server.event
async def on_BlockBroken(event):
    await server.command("say Broken!")

server.start(host="0.0.0.0", port=19132)

今回の改修では、

@server.event
async def on_BlockBroken(event):
    await server.command("say Broken!")

のようにon_イベント名の関数を追加します。

※今回はブロックを壊した時のイベントのBlockBrokenを追加します。

※他のコマンドはMCPE & W10 Event Names - GitHub Gistを御覧ください。


今回はサーバがマインクラフト側からBlockBrokenというメッセージを受け取ったら、サーバからマインクラフト宛にsay Broken!というコマンドを送信するようにしています。

await server.command(コマンド 引数)を追加することで、マインクラフト側に送信するコマンドを作成できます。

※マインクラフトのコマンドに関しては、本屋のマインクラフトコーナーでコマンド一覧のような本がありますので、そちらを御覧ください。




早速、サーバを立ち上げ、マインクラフトと接続した後、マインクラフトのゲーム画面で手短のブロックを壊してみることにします。




画面左上にサーバから送信したコマンドが実行されていました。




次にマインクラフト側で壊したブロックが何であるか?をサーバの方で把握してみます。

先にクロスティーニの画面でctrl + cを押してサーバを停止し、main.pyを下記のように修正します。

@server.event
async def on_BlockBroken(event):
    await server.command("say Broken!")

@server.event
async def on_BlockBroken(event):
    print(event)
    await server.command("say Broken!")

に書き換えて、再びサーバを立ち上げ、マインクラフトと繋げてみます。

※マインクラフトのチャットとコマンドの画面で再びconnectコマンドを実行する必要があります。



最初に上の画像のようなところで剣を振ってみます。

ブロックが壊れた後にクロスティーニの方を確認してみましたら、


{
	"body": {
		"block": {
			"aux": 0,
			"id": "grass",
			"namespace": "minecraft"
		},
		"count": 1,
		"destructionMethod": 0,
		"player": {
			"color": "ffededed",
			"dimension": 0,
			"id": -4294967295,
			"name": "**********",
			"position": {
				"x": -108.836784362793,
				"y": 68.62001037597656,
				"z": -95.82759094238281
			},
			"type": "minecraft:player",
			"variant": 0,
			"yRot": -178.4168548583984
		},
		"tool": {
			"aux": 0,
			"enchantments": [],
			"freeStackSize": 255,
			"id": "",
			"maxStackSize": 255,
			"namespace": "",
			"stackSize": 0
		},
		"variant": 0
	},
	"header": {
		"eventName": "BlockBroken",
		"messagePurpose": "event",
		"version": 17039360
	}
}

のようなデータが返ってきました。

※JSONの整形を行った後のデータを記載しています。



次に上の図のようにカボチャの前で剣を振ってみたら、


{
	"body": {
		"block": {
			"aux": 2,
			"id": "pumpkin",
			"namespace": "minecraft"
		},
		"count": 1,
		"destructionMethod": 0,
		"player": {
			"color": "ffededed",
			"dimension": 0,
			"id": -4294967295,
			"name": "***********",
			"position": {
				"x": -85.21012878417969,
				"y": 66.62001037597656,
				"z": -48.49561309814453
			},
			"type": "minecraft:player",
			"variant": 0,
			"yRot": 35.52716064453125
		},
		"tool": {
			"aux": 0,
			"enchantments": [],
			"freeStackSize": 255,
			"id": "",
			"maxStackSize": 255,
			"namespace": "",
			"stackSize": 0
		},
		"variant": 0
	},
	"header": {
		"eventName": "BlockBroken",
		"messagePurpose": "event",
		"version": 17039360
	}
}

のようなデータが返ってきました。


これらの内容をうまく活用して、

@server.event
async def on_BlockBroken(event):
    print(event)
    await server.command("say Broken!")

@server.event
async def on_BlockBroken(event):
    if event["body"]["block"]["id"] == "grass":
        await server.command("say 草を刈ったぞ!")
    else:
        await server.command("say Broken!")

のように書き込んでみて、草(grass)のブロックを壊した時だけ送信するコマンドを変えて再びサーバを立ち上げ、マインクラフトと繋げてみます。




色々なブロックを壊してみて、草の時だけマインクラフトの左上に表示されるメッセージが表示されることを確認しましょう。

マインクラフト用ビジュアルエディタを開発しています。
詳しくはinunosinsi/mcws_blockly - githubをご覧ください。