ブロックの設置座標取得

# 0.初めに
本記事で紹介するものはMinecraft:JE向けに作成したものです。BEで実装できるかはわかりません。

あと、初心者向けじゃないです。がんばって読んでください。()

# 1.目的
ブロックの設置位置を取得して関数を実行する仕組みを作る。


例:ブロックの設置をプレイヤーごとに制限する仕組みを実装
・普通に設置
![設置.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/d63fb308-2b0d-0e69-7b4b-85f430d40d6a.gif)

・範囲外に設置
![範囲外設置.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/0320df09-e500-0734-2453-6a4548305b83.gif)

# 2.作成方法
#### 2.0.用意するもの(作成環境など)
* Minecraft:JE 1.20.2
* 十分な広さを持つワールド(特に座標[0,0,0]あたりが自由に使えるようにする)(あと、コマンドが使える環境であること)
* テキストエディタ(データパック作成用)

![2023-12-03_09.59.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/d71d21b6-43b2-90eb-d71a-2bae1f20936f.png)

#### 2.1.データパックを作る
"(作ったワールドデータ)/datapacks/"にデータパックを作成しましょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/8c47a280-1962-433a-19b3-225d6cf39080.png)

```pack.mcmeta
{
	"pack": {
		"pack_format": 18,
		"description": "説明文"
	}
}
```

ワールドに戻って`/reload`でデータパックが読み込まれていることを確認しましょう。(`/datapack list`で確認)
![2023-12-03_10.12.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/a6355872-c0a7-f81b-edfc-039ab474b5e2.png)

#### 2.2.設置するブロックを作る
プレイヤーが実際に設置するブロックを作ります。
コマンドで判別するために、NBTを工夫します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/f6e488e5-fdbe-b735-db76-9d663fe8936e.png)

```place_detector\loot_tables\test-block.json
{
    "pools": [
        {
            "rolls": 1,
            "entries": [
                {
                    "type": "item",
                    "name": "furnace",
                    "functions": [
                        {
                            "function": "set_name",
                            "name": {
                                "translate": "block.minecraft.red_wool",
                                "italic": false
                            }
                        },
                        {
                            "function": "set_nbt",
                            "tag": "{BlockEntityTag:{Items:[{id:\"debug_stick\",Count:1b,tag:{place_detector:1b,block_name:\"red_wool\"}}]}}"
                        }
                    ]
                }
            ]
        }
    ]
}
```
ルートテーブルにするとアイテムの管理が楽になりますね。
では、ワールドに戻ってアイテムを出してみましょう。
```
/reload
/loot give @s loot place_detector:test-block
```
![2023-12-03_10.52.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/c252fd46-67e6-b42a-2054-e95e95509470.png)

かまどの中にデバッグ棒を入れて、さらにカスタムタグ(`place_detector:1b,block_name:"red_wool"`)をつけています。

#### 2.3.設置検知を作る
進捗でブロックの検知をします。進捗解除時に関数が実行されるようにしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/c7230a63-02bd-7e5d-e71b-24887171d29d.png)
```place_detector\advancements\place.json
{
    "criteria": {
        "place": {
            "trigger": "placed_block",
            "conditions": {
                "location": [
                    {
                        "condition": "location_check",
                        "predicate": {
                            "block": {
                                "blocks": [
                                    "furnace"
                                ],
                                "nbt": "{Items:[{tag:{place_detector:1b}}]}"
                            }
                        }
                    }
                ]
            }
        }
    },
    "rewards": {
        "function": "place_detector:place"
    }
}
```
```place_detector\functions\place.mcfunction
#>place_detector:place
say 設置した
advancement revoke @s only place_detector:place
```
ワールドに戻って、先ほど作ったかまどを設置してみましょう。
```
/reload
```
![2023-12-03_11.05.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/b2e2df2d-ec2b-a6a0-292c-85b2ef79151a.png)
設置するたびに、チャットにメッセージが出てきます。

#### 2.4.設置位置を取得する
設置したブロックの位置を取得するには、何かしらのエンティティを介す必要があります。今回は、かまどの中にあるデバッグ棒を`座標[0,0,0]`付近でドロップさせベクトルを得る方法を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/5f981ad3-94ba-a57d-8108-41a2cd68523d.png)

```minecraft\tags\functions\load.json
{
    "values": [
        "place_detector:scores"
    ]
}
```
```place_detector\functions\scores.mcfunction
#>place_detector:scores
# 計算用のスコア
scoreboard objectives add _ dummy
```
```place_detector\functions\place.mcfunction
#>place_detector:place

# かまどの設置位置にマーカーを召喚
function place_detector:get_pos

# マーカーの位置でコマンドを実行
execute at @e[tag=place_detector_pos] run setblock ~ ~ ~ red_wool

# マーカーを消去
kill @e[type=marker,tag=place_detector_pos]

# 進捗の初期化
advancement revoke @s only place_detector:place
```
```place_detector\functions\get_pos.mcfunction
#>place_detector:get_pos

# チャンクロード
forceload add 0 0 -1 -1

# プレイヤーの周囲にある特定のかまどをコピー (ワールド外対策としてy座標を分けて実行)
clone ~5 ~-5 ~5 ~-5 ~-5 ~-5 to overworld -5 -5 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~-4 ~5 ~-5 ~-4 ~-5 to overworld -5 -4 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~-3 ~5 ~-5 ~-3 ~-5 to overworld -5 -3 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~-2 ~5 ~-5 ~-2 ~-5 to overworld -5 -2 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~-1 ~5 ~-5 ~-1 ~-5 to overworld -5 -1 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~0 ~5 ~-5 ~0 ~-5 to overworld -5 0 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~1 ~5 ~-5 ~1 ~-5 to overworld -5 1 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~2 ~5 ~-5 ~2 ~-5 to overworld -5 2 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~3 ~5 ~-5 ~3 ~-5 to overworld -5 3 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~4 ~5 ~-5 ~4 ~-5 to overworld -5 4 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}
clone ~5 ~5 ~5 ~-5 ~5 ~-5 to overworld -5 5 -5 filtered furnace{Items:[{tag:{place_detector:1b}}]}

# かまどを破壊
fill -5 -5 -5 5 5 5 air destroy

# デバッグ棒にタグをつける(検索の最適化)
tag @e[type=item,nbt={Item:{id:"minecraft:debug_stick",tag:{place_detector:1b}}}] add place_detector_vector

# マーカーをプレイヤーの位置に召喚
summon marker ~ ~ ~ {Tags:["place_detector_pos"]}

# マーカーにデバッグ棒の座標(ベクトル)を加える
execute store result score #pos _ run data get entity @e[type=marker,tag=place_detector_pos,limit=1] Pos[0]
execute store result score #vector _ run data get entity @e[type=item,tag=place_detector_vector,limit=1] Pos[0]
execute store result entity @e[type=marker,tag=place_detector_pos,limit=1] Pos[0] double 1 run scoreboard players operation #pos _ += #vector _
execute store result score #pos _ run data get entity @e[type=marker,tag=place_detector_pos,limit=1] Pos[1]
execute store result score #vector _ run data get entity @e[type=item,tag=place_detector_vector,limit=1] Pos[1]
execute store result entity @e[type=marker,tag=place_detector_pos,limit=1] Pos[1] double 1 run scoreboard players operation #pos _ += #vector _
execute store result score #pos _ run data get entity @e[type=marker,tag=place_detector_pos,limit=1] Pos[2]
execute store result score #vector _ run data get entity @e[type=item,tag=place_detector_vector,limit=1] Pos[2]
execute store result entity @e[type=marker,tag=place_detector_pos,limit=1] Pos[2] double 1 run scoreboard players operation #pos _ += #vector _

# マーカーにblock_nameをコピー
data modify entity @e[type=marker,tag=place_detector_pos,limit=1] data.block_name set from entity @e[type=item,tag=place_detector_vector,limit=1] Item.tag.block_name

# ドロップしたアイテムを消去
kill @e[x=-5,y=-5,z=-5,dx=10,dy=10,dz=10,type=item]
```
ワールドに戻って、かまどを設置してみましょう。
```
/reload
```
![2023-12-03_11.52.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/0f8218d9-c52c-e516-0bdf-371d3c14dfa7.png)
かまどが赤色の羊毛に置き換わりました！

#### 2.5.マーカーの位置でマクロ実行
マーカーの`data`の中に`block_name`の内容をコピーしました。(`get_pos.mcfunction`)
このblock_nameを使って関数実行を管理してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/75731bb0-adcf-8ab2-5f7b-0660242d00ba.png)

```place_detector\functions\place.mcfunction
#>place_detector:place

# かまどの設置位置にマーカーを召喚
function place_detector:get_pos

# マーカーの位置でコマンドを実行(変更部分！,関数のマクロ実行)
execute at @e[tag=place_detector_pos] run function place_detector:block_function/macro with entity @e[tag=place_detector_pos,limit=1] data

# マーカーを消去
kill @e[type=marker,tag=place_detector_pos]

# 進捗の初期化
advancement revoke @s only place_detector:place
```
```place_detector\functions\block_function\macro.mcfunction
#>place_detector:block_function/macro

# マクロで関数のパスを設定,実行
$function place_detector:block_function/$(block_name)
```
```place_detector\functions\block_function\red_wool.mcfunction
#>place_detector:block_function/red_wool

# 設置音を変える
stopsound @a block block.stone.place
playsound block.wool.place block @a ~ ~ ~ 1 1
# ブロックを設置
setblock ~ ~ ~ red_wool
```
ワールドに戻って、かまどを設置してみましょう。
```
/reload
```
かまどが赤色の羊毛に置き換わり、設置音が羊毛の音になります。(たまに石を設置した音が聞こえることがあります。)

#### 2.6.ブロックの種類を増やす
ブロックの種類を増やしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/5f0153dd-54b8-734b-a82d-e3b94a19d7d0.png)

```place_detector\loot_tables\test-block2.json
{
    "pools": [
        {
            "rolls": 1,
            "entries": [
                {
                    "type": "item",
                    "name": "furnace",
                    "functions": [
                        {
                            "function": "set_name",
                            "name": {
                                "translate": "block.minecraft.diorite",
                                "italic": false
                            }
                        },
                        {
                            "function": "set_nbt",
                            "tag": "{BlockEntityTag:{Items:[{id:\"debug_stick\",Count:1b,tag:{place_detector:1b,block_name:\"diorite\"}}]}}"
                        }
                    ]
                }
            ]
        }
    ]
}
```
```place_detector\functions\block_function\diorite.mcfunction
#>place_detector:block_function/diorite

# ブロックを設置
setblock ~ ~ ~ diorite
```
ワールドに戻って、新しく作ったかまどを設置してみましょう。
```
/reload
/loot give @s loot place_detector:test-block2
```
![2023-12-03_12.27.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/e4aa31c3-971a-8108-a114-5c8befbc2ad5.png)
閃緑岩が設置できました。

# 3.あとがき
今回はブロックの設置位置を取得して関数を実行する方法を紹介しました。
この仕組みの応用例として、
* 「ブロックの設置制限を設ける」
* 「ブロックの位置にエンティティを設置する」

といったものがあります。

この仕組みを使って作った配布マップを公開しています。ぜひ遊んでみてください！

**【Minecraft:JE 1.19.4,1.20.2】Air Red Tactics**
![game_サムネ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3594205/4dfa581a-933e-ff5b-d788-d88fda21c22d.png)
[配布リンク](https://forum.civa.jp/viewtopic.php?p=4694#p4694, "Air Red Tactics")

~~風邪つらい~~