【マインクラフト（統合版）】Websocketサーバーと連携できる「風の杖」を作ってみました

# はじめに

以下のようにウインドチャージをそのまま投げると、投げた方向によっては障害物に当たらない限り、落下運動が働かずに延々とワールドを彷徨う事があります。

![ウインドチャージの投擲](https://socket-manager.github.io/document/minecraft-contents/img/wind-rod/wind-charge.gif "ウインドチャージの投擲")

これを避ける意味も踏まえて今回は以下の２つの目的で作成しました。
<dl>
    <dt>・ウインドチャージの重力化</dt>
    <dt>・カスタムエンティティの発射</dt>
</dl>
以降ではその内容を見ていきます。

# 動作環境

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


# ウインドチャージの重力化

バニラでのウインドチャージのデータはほぼ流用できますので、今回はウインドチャージの本体（<ビヘイビアパック>/entities/wind_charge_projectile.json）のみを持ってきて、これにカスタマイズをかけていきます。

バニラのデータは以下の通り。

```json:<ビヘイビアパック>/entities/wind_charge_projectile.json
{
    "format_version": "1.21.40",
    "minecraft:entity": {
        "description": {
            "identifier": "minecraft:wind_charge_projectile",
            "is_spawnable": false,
            "is_summonable": true
        },
        "components": {
            "minecraft:explode": {
                "power": 1.2,
                "particle_effect": "wind_burst",
                "sound_effect": "wind_charge.burst",
                "knockback_scaling": 1.22,
                "negates_fall_damage": true,
                "causes_fire": false,
                "breaks_blocks": false,
                "allow_underwater": true,
                "toggles_blocks": true,
                "damage_scaling": 0,
                "max_resistance": 0
            },
            "minecraft:collision_box": {
                "width": 0.3125,
                "height": 0.3125
            },
            "minecraft:projectile": {
                "on_hit": {
                    "impact_damage": {
                        "damage": 1,
                        "max_critical_damage": 1.0,
                        "knockback": true
                    },
                    "wind_burst_on_hit": {}
                },
                "power": 1.5,
                "gravity": 0.0,
                "inertia": 1.0,
                "liquid_inertia": 1.0,
                "uncertainty_base": 1.0,
                "uncertainty_multiplier": 0.0,
                "reflect_on_hurt": true,
                "multiple_targets": false,
                "reflect_immunity": 0.5,
                "ignored_entities": [
                    "ender_crystal",
                    "wind_charge_projectile",
                    "breeze_wind_charge_projectile"
                ]
            },
            "minecraft:physics": {
            },
            "minecraft:pushable": {
                "is_pushable": false,
                "is_pushable_by_piston": true
            },
            "minecraft:conditional_bandwidth_optimization": {
                "default_values": {
                    "max_optimized_distance": 80.0,
                    "max_dropped_ticks": 7,
                    "use_motion_prediction_hints": true
                }
            },
            "minecraft:type_family": {
                "family": [ "wind_charge", "wind_charge_projectile" ]
            }
        }
    }
}
```

以下の２点が重力に関わる部分の定義です。
<dl>
    <dt>・minecraft:physics</dt>
    <dt>・minecraft:projectileブロック内のgravity（=0.0）</dt>
</dl>

前者の方は[>> ダミーエンティティ](https://qiita.com/glasses_seven/items/abf1aecba67284e88e27/ "ダミーエンティティの作り方")のページでもご紹介させて頂きましたが、物理法則（重力）の影響を受けるものです。

それに比べて後者の方は`0.0`で設定されているので、この設定が優先されて無重力状態になっているようです。

ところが不思議な事に、この定義をカスタムエンティティ化して動かしてみると、どの方向へ投げても重力が働いていたので前者の定義が優先されているようです。

何故かはわかりませんが今回の実装を通して、既存のものとカスタムエンティティ化したものとでは優先される定義が異なっている事がわかりました。

いずれにしても結果オーライという事で、今回は`description`内の`identifier`（識別子）の変更だけで済みました。

以下のように風の杖を使うと重力化したウインドチャージを発射できます。

![風の杖で発射](https://socket-manager.github.io/document/minecraft-contents/img/wind-rod/wind-rod.gif "風の杖で発射")


# カスタムエンティティの発射

今までの実装でもそうでしたが、基本的には既存アイテムへの影響を与えないようにするため、アイテムのデータ値で制御するかカスタムアイテムを自作するかのどちらかの方法をとってきました。

今回は発射アイテムも含めて発射体エンティティもカスタムエンティティ化するようにしていますが、折角なので補充アイテムがなくても使えるものを作ってみました。

:::note info
基本的な作り方は以下のページでご紹介しています。
:::

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

https://qiita.com/glasses_seven/items/6bcd386abd74db01e450/

今回は発射アイテムの定義を以下のようにしています。

```json:<ビヘイビアパック>/item/wind_rod.json
{
    "format_version": "1.20.50",
    "minecraft:item": {
        "description": {
            "identifier": "customize:wind_rod",
            "menu_category": {
                "category": "none"
            }
        },
        "components": {
            "minecraft:icon": {
                "texture": "wind_rod"
            },
            "minecraft:display_name": {
                "value": "item.customize:wind_rod.name"
            },
            "minecraft:can_destroy_in_creative": false,
            "minecraft:hand_equipped": false,
            "minecraft:damage": 6,
            "minecraft:glint": true,
            "minecraft:use_animation": "bow",
            "minecraft:use_modifiers": {
                "use_duration": 1.6,
                "movement_modifier": 0.35
            },
            "minecraft:shooter":{
                "ammunition" :[{
                    "item" :"customize:wind_rod",                       // ←①自身の発射アイテムを補充アイテムとする
                    "use_offhand" :true,
                    "search_inventory" :true,
                    "use_in_creative" :true
                }],
                "max_draw_duration" :0.1,
                "scale_power_by_draw_duration" :true,
                "charge_on_draw" :false
            },
            "minecraft:projectile": {
                "projectile_entity": "customize:wind_rod_projectile"    // ←②発射体エンティティの指定
            },
            "minecraft:cooldown": {
                "category": "wind_rod",
                "duration": 1.0
            },
            "minecraft:enchantable": {                                  // ←③エンチャント可能にする
                "slot": "bow",
                "value": 0
            }
        }
    }
}
```

上記のコメントの箇所が今回のポイントとなる部分です。
内容は以下の通り。
<dl>
    <dt>①補充アイテムの指定（minecraft:shooter）</dt>
    <dd>この定義を入れる事で補充アイテムが要らなくなります</dd>
    <dt>②発射体エンティティの指定（minecraft:projectile）</dt>
    <dd>自身の発射アイテムを補充アイテムとしているので発射体エンティティを指定する必要があります</dd>
    <dt>③エンチャント可能にする（minecraft:enchantable）</dt>
    <dd>上記の設定だけでは１回発射するだけで自身のアイテムが消滅してしまうので、エンチャント付与可能な状態で「無限」のエンチャントを付与する事によって無限撃ちを可能にしています</dd>
</dl>

:::note info
カスタムレシピではクラフトアイテムにエンチャントを付与する手段がないので、上記③の定義を入れる事でユーザー側での付与を可能にしています。
:::


# 「風の杖」の取得

socket-manager環境のビヘイビアパック／リソースパックなどのアドオンパックを適用しておけば、以下の方法で「風の杖」が手に入ります。

### クラフトする場合

▼必要な素材
![必要な素材](https://socket-manager.github.io/document/minecraft-contents/img/wind-rod/recipe-material.png "必要な素材")

▼レシピパターン
<img src="https://socket-manager.github.io/document/minecraft-contents/img/wind-rod/recipe.png" />　<img src="https://socket-manager.github.io/document/minecraft-contents/img/wind-rod/recipe-left.png" />　<img src="https://socket-manager.github.io/document/minecraft-contents/img/wind-rod/recipe-right.png" />

カスタムレシピの作り方は以下のページでご紹介しています。

https://qiita.com/glasses_seven/items/6865c9c3ae5d756a2989

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

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

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

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

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

---

あとはsocket-managerでWebsocketサーバーを起動後、マインクラフトからの接続が完了すれば「風の杖」を含めた各種コンテンツが使えるようになります。

:::note info
socket-managerの導入方法やアドオンパックの所在については以下のページでご紹介していますのでご興味のある方はご覧ください。
:::

https://qiita.com/glasses_seven/items/433ac9d9fcbdb72c6d18/

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

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


# おわりに

本来であれば[>> 発射アイテム](https://qiita.com/glasses_seven/items/ed7e18730c9c5de3295c/ "発射アイテムの作り方")のページでご紹介したように補充アイテムを準備する必要がありますが、補充アイテム要らずの無限撃ちを実現するために発射アイテムのJSONデータを再帰的に実装しているイメージで捉えて頂ければよろしいかと思います。

ちなみに[>> ネットショップ](https://qiita.com/glasses_seven/items/e77bfb43baf55e35680b/ "ネットショップ")で手に入れたものは購入特典としてあらかじめエンチャントを付与した状態で配布していますので、カスタムレシピを使わない限りは`minecraft:enchantable`ブロックを定義しなくても利用する事は可能です。

また[>> 召雷の魔石](https://qiita.com/glasses_seven/items/e58ec2ceaf2850461965/ "召雷の魔石")実装時と同じように、Websocketサーバーを介してネットショップと接続中は発射できないようにしています。