WebSocket(Node.js)でサーバーからマインクラフト統合版にコマンドを発行する【概要編】

マイクラ統合版に機能を追加する仕組みとして「アドオン」が存在しますが、実はアドオン以外にもWebSocketを利用すればマイクラ統合版の「外部」からマイクラを操作できます。この記事ではWebSocketサーバーの作り方と、実際に接続してマイクラを遠隔で操作する方法を紹介します。

マイクラ統合版はWebSocketでサーバーと通信できる

みなさんはマイクラ統合版の「wsserver」または「connect」コマンドをご存じでしょうか。普通にプレイしていたらまず使わないコマンドだと断言できるぐらい利用頻度の低いコマンドだと思います。コマンドの説明は「指定したURLのwebsocketサーバーへの接続を試行する。」となっています。

connectコマンドの説明文(wsserverコマンドも同様の説明)

実はこのコマンド、マイクロソフトが教育用に提供している「Code Connection for Minecraft」というアプリとマイクラ統合版を接続するために利用するコマンドなのです。Code Connection for Minecraftアプリの内部ではWebSocketサーバーが稼働していて、「connect」コマンドを利用してマイクラからそのWebSocketサーバーに接続することでビジュアルプログラミングができたりします。

ここで注目したいのが、「マイクラと外部のアプリケーション(サーバー)がやり取りすることができる」という点です。そう、公式ではサポートされていませんが、WebSocketを利用すればCode Connection以外もマイクラ統合版に接続できるのです。

ちなみにWebSocketとは、サーバーとクライアントが双方向に通信するためのプロトコル(方言みたいなもの)です。この記事ではWebSocketはマイクラと接続するための単なる手段として利用するため説明は割愛します。

ポイント

WebSocketを利用することで、外部のサーバーとマイクラ統合版を接続することができる!

WebSocketでマイクラと通信できると何が嬉しいの?

WebSocketを使えばマイクラ統合版と外部のサーバーを接続できることはわかりましたが、一体これをやって何が嬉しいのでしょうか。

いろいろな利点が考えられますが、私の考える一番の利点は「マイクラ統合版の制限を超えて、外部に作用することができる」点です。

マイクラ統合版の制限として、アドオンを利用したとしても外部のネットワークに接続することはできません。ネットワーク接続する手段が公式に提供されていないからです。しかしWebSocketサーバーに接続することによって、そのWebSocketサーバーが何かしらの処理を行えば、実質「マイクラ統合版から外部の環境をいじくることができる」ようになります。

言葉だけでは想像しづらいと思いますので、まずは以下の動画をご覧ください。

この動画では、以下のようなことを行っています。

この動画でやっていること
  • マイクラ内のプレイヤーが歩く
  • 「プレイヤーが歩いた」というイベントをWebSocketサーバーに通知
  • WebSocketサーバーに接続されたサーボモーターを動かし、人形を歩かせる

このように、WebSocketサーバーとマイクラ統合版を接続することにより、マイクラの世界を飛び出して実世界にも作用できるようになります。

また、そのほかの利点としては、使い慣れた言語でマイクラ統合版を外部から操作できることが挙げられます。例えばScripting APIだとプログラムのモジュール化が難しいのですが、この手法を使えばNode.jsを使ってプログラムを書けるため、プログラムのモジュール化も可能になります。

欠点としては、WebSocketサーバープログラムを起動しておかなければいけない、つまりマイクラ単体では動作しないことでしょう。(といっても、PCでマイクラ統合版を遊んでいる場合はそのPCでWebSocketサーバーを起動しておけばOKなんですけどね)

ポイント

マイクラ統合版とWebSocketサーバーを接続すると、マイクラの世界から実世界(外部)に作用することができる!

それでは実際にWebSocketサーバーを作ってマイクラ統合版と接続する手順を紹介します。いきなり電子工作に手を付けてもいいのですが、記事が長くなってしまうので、今回は電子工作ではなく、WebSocketサーバーと通信して、WebSocketサーバーからマイクラ統合版に対してコマンドを発行するような簡単なプログラムを作っていきます。

[ad]

環境構築

WebSocketはあくまでプロトコルなので、どのような言語を利用してもWebSocketサーバーを作成することができますが、ここではNode.jsを利用してJavaScriptでWebSocketサーバーを作成していきます。

あらかじめ以下のソフトウェアをインストールしておいてください。

  • マインクラフト統合版(PC版でもSwitch版でもスマホ版でもOK)
  • Node.js実行環境
  • Visual Studio Code(またはJavaScriptを編集できるエディタ)

また、Node.jsをコマンドプロンプトから使えるようにあらかじめPATHを通しておいてください。

プログラム作成

それでは、WebSocketサーバーを作成していきましょう。ここで作成するプログラム(WebSocketサーバー)は、「プレイヤーが歩いたら、プレイヤーの位置にニワトリをスポーンさせる」という単純だけど可愛い(迷惑?)プログラムにします。詳しい説明は次回以降の記事に記載しますが、ここでは「WebSocketサーバーとマインクラフト統合版はWebSocketでJSONをやりとりする」ということが理解できることをゴールとします。

パッケージのインストール

任意のフォルダをVisual Studio Codeで開き、以下のコマンドで必須パッケージをインストールします。

npm install ws uuid

コーディング

パッケージのインストールが終わったら、以下のようなコードを作成します。

example.js
const WebSocket = require("ws");
const uuid = require("uuid");

const wss = new WebSocket.Server({
  port: 19131,  // 19131ポートでWebSocketサーバーを待機
});

console.info(`WebSocket is Ready. Type "/connect localhost:${PORT}"`);

// マイクラから接続された際の処理
wss.on("connection", ws => {
  console.log("Connected");
  // イベント購読用のJSONを組み立てる
  const subscribeMessageJSON = {
    "header": {
      "version": 1, // プロトコルのバージョンを指定。1.18.2の時点では1で問題ない
      "requestId": uuid.v4(), // UUIDv4を指定
      "messageType": "commandRequest",  // "commandRequest" を指定
      "messagePurpose": "subscribe", // "subscribe" を指定
    },
    "body": {
      "eventName": "PlayerTravelled" // イベント名を指定。イベント名は後述
    },
  };

  // イベント購読用のJSONをシリアライズ(文字列化)して送信
  ws.send(JSON.stringify(subscribeMessageJSON));

  // マイクラからメッセージが届いた際の処理を定義
  ws.on("message", rawData => {
    const data = JSON.parse(rawData); // 生メッセージをオブジェクトに変換
    if (!data.body.eventName) { // メッセージにイベント名が含まれていない場合は処理を抜ける
      return;
    }
    if (data.body.eventName != "PlayerTravelled") {
      return; // メッセージのイベント名がPlayerTravelledでない場合は処理を抜ける
    }
    if (ws.readyState !== WebSocket.OPEN) {
      return; // WebSocketがOPEN状態でない場合は処理を抜ける
    }

    // コマンド発行用JSONの組み立て
    const commandRequestMessageJSON = {
      "header": {
        "version": 1, // プロトコルのバージョン1.18.2時点では1でOK
        "requestId": uuid.v4(), // UUIDv4を生成して指定
        "messageType": "commandRequest", // commandRequestを指定
        "messagePurpose": "commandRequest", // commandRequestを指定
      },
      "body": {
        "origin": {
          "type": "player" // 誰がコマンドを実行するかを指定(ただし、Player以外にどの値が利用可能かは要調査)
        },
        "version": 1, // プロトコルのバージョン1.18.2時点では1でOK
        "commandLine": "summon chicken ~~~", // マイクラで実行したいコマンドを指定(ここではニワトリをスポーンさせるコマンドを指定)
      }
    };

    // コマンド発行用のJSONをシリアライズ(文字列化)して送信
    ws.send(JSON.stringify(commandRequestMessageJSON));
  })
});

ローカル・ループバック・アドレス(127.0.0.1、localhost)への接続許可

マインクラフト統合版のようなUWPアプリはデフォルトではローカルループバックアドレスに接続ができないようになっています。ローカルでWebSocketサーバーを起動させる場合は、管理者権限でコマンドプロンプトを開き、次のコマンドを実行してlocalhostへの接続を許可します。

CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.MinecraftUWP_8wekyb3d8bbwe"
[ad]

接続・動作確認

WebSocketサーバーが完成したので、早速接続して動作を確認しましょう。

WebSocketサーバーの起動

先ほど作成したexample.jsを実行します。

node example.js
WebSocket is Ready. Type "/connect localhost:19131"

これでWebSocketサーバーが19131ポートで待機しましたので、マインクラフトからこのサーバーへ接続してみます。

Minecraftから接続

チートの実行をオンにしたワールドを開き、以下のコマンドを打ち込んでみましょう。

/connect localhost:19131

正常に接続できると、「サーバーへの接続を確立しました: ws://localhost:19131」と表示されるはずです。

正常に接続できた場合のメッセージ

これでマインクラフト統合版とWebSocketサーバーとの接続が無事に終わりました。

動作確認

実際に歩いてみると次の動画のように歩いたところにニワトリがスポーンするはずです。

拾えるイベント

この記事ではプレイヤーが歩いた場合のイベント「PlayerTravelled」を購読し、イベントが発生したらコマンドを発行しました。その他にも拾えるイベントはたくさんあるのですが、公式からは何もアナウンスされていません。

私の方でマイクラ統合版(PC)の解析を行ったところ、どうやら次のようなイベントであれば拾えるようです。実際にイベントを拾えるかどうかは確認していないため、各自で試してみてください。

拾えるイベント一覧
AgentCommand
AgentCreated
AndroidHelpRequest
ApiInit
AppPaused
AppResumed
AppSuspended
AppUnpaused
ArmorStandItemEquipped
ArmorStandPosed
AssertFailed
AvatarsListed
AvatarUpdated
BehaviorErrored
BehaviorFailed
BlockBroken
BlockBroken
BlockChecksumMismatchLevelFailedToLoad
BlockFound
BlockPlaced
BlockPlaced
BlockUsageAttempt
BlockUsed
BookCopied
BookEdited
BookExported
BookImageImported
BossKilled
BundleSubOfferClicked
ButtonPressed
CameraUsed
CaravanChanged
CaravanChanged
CauldronUsed
ChunkChanged
ChunkLoaded
ClassroomSettingUpdated
ClientIdCreated
ClubsEngagement
CommandBlockEdited
ConfigurationChanged
ConnectionFailed
ContentShared
ControlRemappedByPlayer
CraftingSessionCompleted
CrashDumpStatus
CustomContentRegistered
DBStorageError
DevConsoleOpen
DeviceAccountFailure
DeviceAccountSuccess
DeviceIdManagerFailOnIdentityGained
DeviceLost
DifficultySet
DiskStatus
DwellerDied
DwellerRemoved
EDUDemoConversion
EduOptionSet
EmotePlayed
GameRulesUpdated
GameSessionStart
GameTipShown
HardwareInfo
HowToPlayTopicChanged
IDESelected
IncognitoFailure
InputModeChanged
ItemAcquired
ItemCrafted
ItemDropped
ItemEquipped
ItemInteracted
ItemNamed
ItemSmelted
ItemTraded
JoinCanceled
JukeboxUsed
LockedItemGiven
MobEffectChanged
MobInteracted
NpcInteracted
OfferRated
OnAppResume
OnAppStart
OnAppSuspend
OnDeviceLost
OptionsUpdated
PackHashChanged
PackPlayed
PackRecovery
PackSettings
PatternAdded
PerformanceContext
PerformanceMetrics
PermissionsSet
PetDied
PlayerBanned
PlayerBounced
PlayerGameModeSet
PlayerMessage
PlayerSaved
PlayerTeleported
PlayerTransform
PlayerTravelled
PopupClosed
PopupFiredEdu
PortalUsed
PortfolioExported
PotionBrewed
Progressions
PurchaseFailedDetailed
PushNotificationPermission
PushNotificationReceived
QueryOfferResult
RaidUpdated
RealmShared
RealmsSubscriptionPurchaseFailed
RealmsSubscriptionPurchaseStarted
RealmsSubscriptionPurchaseSucceeded
RenderingSizeChanged
RespondedToAcceptContent
ScreenChanged
ScreenLoaded
ScreenLoadTime
ScriptRan
ServerConnection
ServerConnectionAttempt
ServerDrivenLayoutImageLoad
ServerDrivenLayoutPageLoad
SessionCrashed
SignedBookOpened
SignIn
SignInToEdu
SignOut
SignOutOfXboxLive
SlashCommandExecuted
StartClient
StartWorld
StorageCreated
storageReport
StoreDiscoveryServiceResponse
StoreOfferClicked
StorePlayFabResponse
StorePromoNotification
StorePromoNotificationClicked
StoreSearch
StoreSessionStartResponse
StructureBlockAction
TargetBlockHit
TextToSpeechToggled
TreatmentPackApplied
TreatmentPackRemoved
Treatments
TrialDeviceIdCorrelation
UgcDownloadCompleted
WaxedOnOrOff
WorldGenerated
WorldLoadedClassroomCustomization
WorldLoadTimes
XForgeCatalogSearch

また、別の方も拾えるイベントを調べていました。私が実際に解析したもの以外のイベントも含まれているので、合わせてご参照ください。

購読するイベントと発行するコマンドをいろいろ変えて試してみると面白いと思います。

[ad]

応用例

今回はイベントが発動した際にコマンドを発行しましたが、イベントを発行する以外にも様々な処理を挟んでみると面白いかもしれません。

例えば冒頭の動画で見せたような、「歩いたらロボットを動かす」みたいなこともできますね。実際に電子工作する場合はRespberry PiやArduinoなどを利用してWebSocketサーバーを立て、その中で電子部品を動かす処理を追加することになると思います。夢が膨らみますね。

まとめ

この記事ではWebSocketを利用することで、マインクラフト統合版の世界に閉じた処理だけではなく、マインクラフトの「外側」でいろいろな処理を行う仕組みと、WebSocketサーバーの立て方、JSONによるメッセージの受け渡しについて簡単に解説しました。アドオン以外にもマイクラに干渉できる仕組みがあるのは面白いですね。いろいろ試してみたいです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です