【マインクラフト（統合版）】Websocketサーバーを使って「いなずまの弓」を作ってみました

# はじめに

以下のように矢を放った方向へ稲妻を落とせます。
![いなずまの弓](https://socket-manager.github.io/document/minecraft-contents/img/bow-thunder/ground.gif "いなずまの弓")

👇空を見上げるアングルではこんなイメージ
<img src="https://socket-manager.github.io/document/minecraft-contents/img/bow-thunder/sky_thunder.png" height="600px" width="728px" />

矢を放ったタイミングで稲妻を落とすので、近距離／遠距離の同時攻撃が可能なチート装備です。
自分がダメージを受けないギリギリのところへ落とすようにしているのでサバイバルモードでも安心です。

地上だけではなく以下の場所でも使える事を確認しています。

<ul>
    <li>水中</li>
    <li>洞窟</li>
    <li>ネザー</li>
    <li>エンド</li>
</ul>

何故か雲がないのにネザーやエンドでも使えるようです。

操作に慣れてくれば矢で牽制しながら稲妻を落とせるので帯電クリーパーやピグリンも量産し放題でしょう。

山の中で連発しすぎると大火事になりますのでご注意を。

# 動作環境

<dl>
    <dt>プラットフォーム</dt>
    <dd>Windows10</dd>
    <dt>マインクラフト（統合版）</dt>
    <dd>Windows Edition v1.21.2</dd>
    <dt>socket-manager</dt>
    <dd>v1.13.3</dd>
    <dt>言語</dt>
    <dd>PHP v8.2.4（v8.1.0以降）</dd>
</dl>


# 導入方法

動作環境は以下のコマンドでインストール（ダウンロード）できます。
```terminal
> composer create-project socket-manager/contents-project <インストール先のディレクトリ名>
```

インストール後のディレクトリ構成は以下のようになっています。
```
/app
    /client             Webブラウザ用クライアント
        /jquery         jQuery版
        /react          React版
    /packs              マインクラフト適用データ
        /behavior_packs ビヘイビアパック
        /resource_packs リソースパック
    /InitClass          初期化クラス
    /UnitParameter      UNITパラメータクラス
    /ProtocolUnits      プロトコルUNIT定義クラス
    /CommandUnits       コマンドUNIT定義クラス
    /MainClass          メイン処理クラス
/logs                   ログ出力用
/setting                設定ファイル用
```

専用コンテンツを有効にするため`app/packs`ディレクトリにビヘイビアパック／リソースパックなどのアドオンパックを同梱しています。

このディレクトリの中身をそのまま統合版ゲームデータのディレクトリにコピーしてお使いください。

:::note info
アドオンパックの適用方法については以下のページでご紹介しています。
:::

https://qiita.com/glasses_seven/items/7a174722c9030e669eac


### 「いなずまの弓」を取得

上記のアドオンパックを適用しておけば、以下の方法でユニークアイテムとして「いなずまの弓」が手に入ります。

#### ショップで購入する場合

以下のショップで購入できます。

https://qiita.com/glasses_seven/items/e77bfb43baf55e35680b/

#### コマンドで取得する場合

以下はワールドオーナーやシステム組み込み用としてコマンドで取得する方法です。
<img src="https://socket-manager.github.io/document/minecraft-contents/img/bow-thunder/command_bow.png" height="600px" width="728px" />

<img src="https://socket-manager.github.io/document/minecraft-contents/img/bow-thunder/get_bow.png" height="600px" width="728px" />


### Websocketサーバーへの接続

例えばマインクラフト用のWebsocketサーバーを起ち上げる場合にはプロジェクトルートで以下のようにコマンドを実行すれば起動します。

```terminal
> php worker app:minecraft-chat-server [<ポート番号>]
```

マインクラフトはUWPアプリのためlocalhost（127.0.0.1）で利用する場合は以下のコマンドを実行してループバックアドレスへのアクセスを許可しておく必要があります（一度設定しておけば以降はそのまま使用できます）。

```terminal
> CheckNetIsolation.exe LoopbackExempt -a -n="Microsoft.MinecraftUWP_8wekyb3d8bbwe"
```

マインクラフトからWebsocketサーバーへ接続する時はチャット画面で以下のように入力します。
<img src="https://socket-manager.github.io/document/minecraft-contents/img/index/command_wsserver.png" height="600px" width="728px" />

```terminal:入力書式
> /wsserver localhost:<ポート番号>/<ユーザー名>
```

上記のユーザー名はマインクラフト内のユーザー名でなくても構いません。
あくまでWebsocketサーバー内で使用する名前です。

<img src="https://socket-manager.github.io/document/minecraft-contents/img/index/complete_wsserver.png" height="600px" width="728px" />

接続が完了すれば画面左上に上記のようなメッセージが表示されます。
接続後は「いなずまの弓」を含めた各種コンテンツが使えるようになります。


### 接続に失敗する場合

Websocketサーバーに接続しようとすると以下のエラーが出る事があります。
![エラーメッセージ画面](https://socket-manager.github.io/document/minecraft-contents/img/index/bad-connection.png "エラーメッセージ画面")

そんな時は以下の赤枠部分と同じ設定にしてください。
![Websocket接続設定](https://socket-manager.github.io/document/minecraft-contents/img/index/connection-setting.png "Websocket接続設定")


### サーバーサイドの実装

今回の主要な実装ポイントは以下３点です。
<br />

```php:setting/minecraft.php
return [
    'subscribe_types' =>
    [
        'ItemUsed'
    ]
];
```
サブスクライブイベントは上記の設定ファイルへ登録します（複数登録可）。
サブスクライブイベントの処理内容については以下の記事をご覧ください。

https://socket-manager.github.io/document/extra-minecraft.html#send

:::note info
このサブスクライブイベントを登録しておく事で、弓を使ったイベントを検知してマインクラフトがWebsocketサーバーへイベントデータを送信してくれます。
:::
<br />

```php:app/InitClass/InitForMinecraft.php
public function getCommandDispatcher()
{
    return function(ParameterForMinecraft $p_param, $p_dat): ?string
    {
        $minecraft = $p_param->isMinecraft();
        if($minecraft === true)
        {
            ・
            ・
            ・
            if(isset($p_dat['data']['header']['eventName']) && $p_dat['data']['header']['eventName'] === 'ItemUsed')
            {
                if($p_dat['data']['body']['item']['id'] === 'bow')
                {
                    return CommandQueueEnumForMinecraft::ITEM_USED->value;
                }
            }
            ・
            ・
            ・
        }
    }
}
```
受信したイベントデータをコマンド名へ変換する処理を上記のコマンドディスパッチャーへ追加します。

:::note info
ここでは`bow`というアイテム名を検知しています。
:::
<br />

```php:app/CommandUnits/CommandForMinecraft.php
protected function getItemUsedStart()
{
    return function(ParameterForMinecraft $p_param): ?string
    {
        $p_param->logWriter('debug', ['MINECRAFT ITEM_USED:START' => 'START']);

        if($rcv['data']['body']['item']['aux'] !== 401)
        {
            return null;
        }

        // 受信データの取得
        $rcv = $p_param->getRecvData();
        $x = (float)$rcv['data']['body']['player']['position']['x'];
        $y = (float)$rcv['data']['body']['player']['position']['y'];
        $x = (float)$rcv['data']['body']['player']['position']['z'];
        $y_rot = (float)$rcv['data']['body']['player']['yRot'];
        $y_rot_abs = abs($y_rot);

        // Z座標の計算
        $z = cos(deg2rad($y_rot_abs)) * 5;

        // X座標の計算
        $x = sin(deg2rad($y_rot_abs)) * 5;
        if($y_rot > 0)
        {
            $x = -$x;
        }

        // コマンド送信
        $cmd_data = $p_param->getCommandDataForSummonThunder($x, 0, $z, $rcv['data']['body']['item']['id']);
        $data =
        [
            'data' => $cmd_data
        ];
        $p_param->setSendStack($data);

        return null;
    };
}
```
コマンド名に紐づけた処理（関数）を上記のファイルへ実装します。

:::note info
処理の冒頭で`aux`の数字を判定していますが、この`aux`がないと全ての弓アイテム使用時に発動してしまいます。「いなずまの弓」の`aux`データ値（401）はビヘイビアパックで定義しています。ここでは受信した座標データと三角関数を使って稲妻を落とす座標を計算した後、マインクラフトへ`summon`コマンドを送信しています。
:::


# おわりに

このページではsocket-managerフレームワークを使う上でのお決まりの書き方は省略しています。
実装内容の詳細は他のコンテンツも含めて以下のページでご紹介していますのでご興味のある方はご覧ください。

https://socket-manager.github.io/document/minecraft-contents/bow-thunder.html

<br />
以下のページでご紹介している「いなずまの矢」や「はかいの矢」とコンボで使用する事も可能です。

https://qiita.com/glasses_seven/items/a34873dfb559e49d5095/

https://qiita.com/glasses_seven/items/98ea8e43b406f75c41df/

<br />
この環境は以下のページでご紹介したデモ環境を引き継いでいますのでWebブラウザとのチャット機能もそのまま使えます。

https://qiita.com/glasses_seven/items/7a490dc8694348505a53/

`app/client`ディレクトリにはデモ環境と同じくjQuery版とReact版のHTMLファイル（chat.html）が入っていますのでお好きな方をブラウザにドラッグ＆ドロップしてお使いください。

<br />
Websocketサーバー上でイベントが取得できるようになっただけでもかなり負担が減らせるので助かります。
座標計算等の処理もサーバーサイドのスクリプトで自由に組める事と、WebブラウザをUIとして使えるメリットも大きいと思います。