【マインクラフト（統合版）】ブロックステートの使い方まとめ

# はじめに

ここではカスタムブロック内で定義できるブロックステートの使い方をまとめています。
ブロックステートの性質はエンティティプロパティに似ていて、オブジェクト指向型言語のプロパティのようなもので、カスタムブロック内で使える内部変数と言っていいでしょう。

https://qiita.com/glasses_seven/items/5553772d3fa8edd09cc0/


# 値の定義

使える値は以下の３種類で、それぞれで扱う値を配列として定義します。
ちなみに、配列で列挙した一番左端の値がデフォルトとなります。

```json:数値型の定義例
"states": {
    "customize:number_data": [ 0, 1, 2 ]
}
```

```json:文字列型の定義例
"states": {
    "customize:string_data": [ "one", "two", "three" ]
}
```

```json:ブール型の定義例
"states": {
    "customize:bool_data": [ true, false ]
}
```


# 値の設定

値の設定は`setblock`や`fill`コマンドで行います。
今回は以下のページでご紹介した「ダミーブロック」を使用する前提なので`customize:dummy_block`というブロックIDを利用しています。

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

```text:setblockコマンド使用例
setblock <X座標> <Y座標> <Z座標> customize:dummy_block ["customize:bool_data"=true]
```

```text:fillコマンド使用例
fill <開始X座標> <開始Y座標> <開始Z座標> <終了X座標> <終了Y座標> <終了Z座標> customize:dummy_block ["customize:bool_data"=true]
```

最後の角括弧（["customize:bool_data"=true]）の部分がクライアント（マインクラフト）側でブロックステートを設定する時の書き方です。
但し、サーバー（Websocketサーバー）側から送信する時はブロックステートを設定する時の代入演算子が”=”ではなく”:”になるので注意が必要です。


# 値の参照

値を参照する時は以下のような`permutations`定義内で行い、Molangの`query.block_state`を使います。

```json:permutations定義例
"permutations": [
    {
        "condition": "query.block_state('customize:bool_data') == true",
        "components": {
            "minecraft:collision_box": true
        }
    },
    {
        "condition": "query.block_state('customize:bool_data') == false",
        "components": {
            "minecraft:collision_box": false
        }
    }
]
```

<dl>
    <dt>・permutations</dt>
    <dd>
        以下の定義ブロックを配列で設定します。<br />
        <dl>
            <dt>condition</dt>
            <dd>
                ブロックステートの値を参照して条件式を設定します。
            </dd>
            <dt>components</dt>
            <dd>
                <code>condition</code>の条件に一致した時に適用する<code>components</code>を設定します。<br />
                今回の場合は以下の動作になります。
                <dl>
                    <dt>ブロックステートがtrueの時</dt>
                    <dd>
                        <code>minecraft:collision_box</code>をtrueにしてブロックとの衝突判定を有りにしています。
                    </dd>
                    <dt>ブロックステートがfalseの時</dt>
                    <dd>
                        <code>minecraft:collision_box</code>をfalseにしてブロックとの衝突判定を無しにしています。
                    </dd>
                </dl>
                <code>components</code>の詳細については<font><a href="https://qiita.com/glasses_seven/items/7b17bc6f55139ceae3d7/#コンポーネント定義">&gt;&gt; ダミーブロック（コンポーネント定義）</a></font>の項をご覧ください。
            </dd>
        </dl>
    </dd>
</dl>


# テストしてみる

今回のケースでブロック定義を作成すると以下のような内容になります。

```json:ブール型のブロックステートを使った例
{ 
    "format_version": "1.20.80", 
    "minecraft:block": { 
        "description": { 
            "identifier": "customize:dummy_block",
            "states": {
                "customize:bool_data": [ true, false ]
            }
        },
        "permutations": [
            {
                "condition": "query.block_state('customize:bool_data') == true",
                "components": {
                    "minecraft:collision_box": true
                }
            },
            {
                "condition": "query.block_state('customize:bool_data') == false",
                "components": {
                    "minecraft:collision_box": false
                }
            }
        ],
        "components": { 
        }
    } 
}
```

`states`定義は`description`定義ブロック内に記述します。
`permutations`定義ブロックは`description`や`components`定義ブロックと同じ階層に並べて記述します。

コマンドで設置する場合、以下のように”[”まで入力すると入力補助が働いてブロック内で定義しているブロックステートの名前が表示されるので便利です。
<img src="https://socket-manager.github.io/document/minecraft-contents/img/custom-block-states/input-assistance1.png" height="333px" width="500px" />

さらに”=”まで入力すると、該当のブロックステートに設定できる値が以下のようにリスト表示されます。
<img src="https://socket-manager.github.io/document/minecraft-contents/img/custom-block-states/input-assistance2.png" height="333px" width="500px" />

### ブロックステートをtrueにして設置

```text:setblockのコマンドライン
setblock <X座標> <Y座標> <Z座標> customize:dummy_block ["customize:bool_data"=true]
```

▼ブロック設置後
<img src="https://socket-manager.github.io/document/minecraft-contents/img/custom-block-states/state-true.png" height="333px" width="500px" />
衝突判定有りなのでブロックの上に乗る事ができます。

### ブロックステートをfalseにして設置

```text:setblockのコマンドライン
setblock <X座標> <Y座標> <Z座標> customize:dummy_block ["customize:bool_data"=false]
```

▼ブロック設置後
<img src="https://socket-manager.github.io/document/minecraft-contents/img/custom-block-states/state-false.png" height="333px" width="500px" />
衝突判定無しなのでブロックの上に乗ろうとしてもすり抜けます。


# おわりに

今回の`states`定義は以下の「光の剣」で利用しているブロックでも使っています。

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

<br />

「光の剣」で使えるブロックは以下の３つのモードに分けて実装しています。
<br />
<dl>
    <dt>・シールドモードとして設置した時</dt>
    <dd>
        <br />
        バリアブロックと同じ性質にする事によってサバイバルモードでは破壊できないようにしています。<br />
        <img src="https://socket-manager.github.io/document/minecraft-contents/img/light-sword/shield-summon.gif" /><br /><br /><br />
    </dd>
    <dt>・ブロックモードとして設置した時</dt>
    <dd>
        <br />
        松明代わりに光源ブロック（光源レベルは１５）として使えるので、ブロックを通り抜けできると同時に素手で簡単に壊せるようにしています。<br />
        <img src="https://socket-manager.github.io/document/minecraft-contents/img/light-sword/through-block.gif" height="333px" width="500px" /><br /><br /><br />
    </dd>
    <dt>・建築モードとして設置した時</dt>
    <dd>
        <br />
        ガラスブロックと同じ性質にする事で、簡単には壊せますが通り抜けはできないようにしています。<br />
        また、光源ブロックとしても機能するので松明を使わなくても窓の設置だけで明るく照らす事ができます。<br />
        <img src="https://socket-manager.github.io/document/minecraft-contents/img/light-sword/window-use.png" height="333px" width="500px" /><br />
    </dd>
</dl>