村人でもわかる！コマンドを用いたカスタム作物

# これは何？
これは、Minecraft Command Advent Calendar 2023 5日目の記事です。もうクリスマスまで20日ですよ。
# 必要な前提知識は何？
コマンドの基礎が分かること！初歩的な解説はしないので、ざっとどんなコマンドがどんな効果があるかとか覚えてるぐらいの知識があればいいです。
# 始めに
**皆さんは、minecraftでカスタム作物が追加したいと思ったことがあると思います。**

（...ね？そうですよね？）
でも、そう思ったときに先駆者が如何せん少ないので参考になるものが超絶少ないです。ほとんどmodでカスタム作物を追加する方法が検索にヒットしたりする上に、**たとえ見つかったとしてもバージョンが古かったりします。** 過去の私もこれに苦しめられました。
この記事では、最新バージョン上（1.20.x）でコマンドを用いてカスタム作物を実装する方法を、できるだけ簡単に知ることができます。
# んなこたええから手っ取り早くサンプル寄こせって！
サンプルデータパック

https://drive.google.com/file/d/1W9yr2F9c45jlil3LNrItCWQbG7j5-2Sg/view?usp=sharing

サンプルリソースパック

https://drive.google.com/file/d/11JrxoTz6btOq27N1G9FFm3JUH7E2dw5L/view?usp=sharing

ライセンスはCC BY-SA 4.0 DEEDです。「これ使ったよ！ってことを明記すること」と「これを使ったものを配布するときに同じライセンスで配布すればいい」ってことです。

コマンドがわけわかんない人は、テクスチャ差し替えるなりすればカスタム作物が作れるはずです。
# 何か犠牲にするものって、ある？
**カスタムブロックをコマンドで追加する際にはつきものです。** カスタムブロックの当たり判定に使用するブロックに見た目をかぶせて実装するため、作物のような透過部分が多いものの場合、消さないと見た目があまりよろしくなくなるのです。
今回の場合では、何かの作物の第一段階のテクスチャを消します。別に消さなくてもあんまり変わりませんが、消した方が特段に綺麗です。この記事では、ビートルートを犠牲にします。
# datapackの構成ってどうなってるの？

```
functions/
├tick.mcfunction
├load.mcfunction
├break.mcfunction
├loot.mcfunction
├return.mcfunction
├check.mcfunction
├plant.mcfunction
├looks.mcfunction
└grow.mcfunction

loot_tables/
├seeds/
│└tomato.json
└vegetables/
 └tomato.json
```

# 使うアイテムのカスタムタグを教えな！
以下の判別に使うカスタムタグを適当に決めてください。解説の際には長ったらしいので隣に例として書いたカスタムタグの名前で話を進めます。

・作物の名前を表すタグ (ccname)
・額縁を置き換えるための判別に使うタグ (ccreplace)
・作物の成長段階を表すタグ（ccstage)
・その作物の成長段階1の時のカスタムモデルデータの値を表すタグ (cccmd)

それぞれ
・作物の種類の識別
・額縁が作物なのかの識別
・作物の成長段階の識別
・成長した時のCustomModelDataの演算
に使用します。
# どんなテクスチャを用意すべき？
・種 (額縁)
・作物 (任意のアイテム、この記事では乾燥した昆布）
・植えてある作物の成長差分 （任意のアイテム、この記事ではシダ）
全てカスタムモデルデータを割り当てテクスチャを変更するようにしてください！
作物の成長差分のカスタムモデルデータには連続した数字を割り当て、数字が大きくなるほど成長段階が進むようにしてください。
# 用意する必要のあるloottable
### 種
アイテムの額縁は中に何が入っているかの情報を保持できるので、額縁を種の代わりとして使用します。後々返却処理などを作ることになるので、loottableでアイテムを作ります。この記事では例としてトマトを作ります。

額縁の中のアイテムのCustomModelDataをその作物の成長段階1の時の見た目の物にして、カスタムタグにccname:作物名とccreplace:1bを設定してください。この時、作物名とloottableの名前をそろえてください。

datapack/loot_tables/seed/tomato 
```

{
  "pools": [
    {
      "rolls": 1,
      "bonus_rolls": 0,
      "entries": [
        {
          "type": "minecraft:item",
          "weight": 1,
          "name": "minecraft:item_frame",
          "functions": [
            {
              "function": "minecraft:set_name",
              "name": {
                  "text": "トマトの種",
                  "color": "white"
                }
              },
              {
                "function": "minecraft:set_nbt",
                "tag": "{CustomModelData:1,EntityTag:{Item:{id:\"minecraft:fern\",Count:1b,tag:{CustomModelData:1,ccreplace:1b,ccname:tomato}},Silent:1b,Invulnerable:1b,Invisible:1b,Fixed:1b}}"
              },
              {
                "function": "minecraft:set_count",
                "count": {
                  "min": 1,
                  "max": 1
                }
              }
            ]
          }
        ]
      }
    ]
  }
```
### 作物
成長しきった作物を壊した時に出るloottableです。先ほどの種を数個と、作物を落とすようにします。

datapack/loot_tables/vegetables/tomato 
```
{
    "pools": [
      {
        "rolls": 3,
        "bonus_rolls": 0,
        "entries": [
          {
            "type": "minecraft:item",
            "weight": 1,
            "name": "minecraft:dried_kelp",
            "functions": [
              {
                "function": "minecraft:set_name",
                "name": {
                  "text": "とまと",
                  "color": "white"
                }
              },
              {
                "function": "minecraft:set_nbt",
                "tag": "{CustomModelData:1}"
              },
              {
                "function": "minecraft:set_count",
                "count": {
                  "min": 0,
                  "max": 3
                }
              }
            ]
          },
          {
            "type": "minecraft:item",
            "weight": 1,
            "name": "minecraft:item_frame",
            "functions": [
              {
                "function": "minecraft:set_name",
                "name": {
                  "text": "とまとの種",
                  "color": "white"
                }
              },
              {
                "function": "minecraft:set_nbt",
                "tag": "{CustomModelData:1,EntityTag:{Item:{id:\"minecraft:fern\",Count:1b,tag:{CustomModelData:1,ccreplace:1b,ccname:tomato}},Silent:1b,Invulnerable:1b,Invisible:1b,Fixed:1b}}"
              },
              {
                "function": "minecraft:set_count",
                "count": {
                  "min": 0,
                  "max": 2
                }
              }
            ]
          }
        ]
      }
    ]
  }
  
```
# loadで実行する物
minecraftのfunctionのloadのタグにこのfunctionを追加してください。

dummyのスコアボードを用意してください。(この記事ではcc.grow)
主にスコアボード上で演算を行う際にこのスコアを使うことになります。

datapack/functions/load
```
#スコアボード
scoreboard objectives add cc.grow dummy
#読み込めてるかメッセージ
tellraw @a [{"text":"正常に読み込めてるよ!","color":"white"}]
```
# tickで実行する物
minecraftのfunctionのtickのタグにこのfunctionを追加してください。

datapack/functions/tick
```
#当たり判定に使用しているビートルートが壊れた際に作物が壊れた処理を行う
execute as @e[tag=ccag,type=item_display] at @s unless block ~ ~ ~ beetroots run function datapack:break
#ビートルートの成長段階が1以外の時に見た目の更新の処理を行う
execute as @e[tag=ccag,type=item_display] at @s if block ~ ~ ~ beetroots unless block ~ ~ ~ beetroots[age=0] run function datapack:looks
#ccreplace:1bを持つアイテムが中に入っている額縁がある時に作物を植える処理を行う
execute as @e[type=item_frame,nbt={Item:{tag:{ccreplace:1b}}}] at @s run function datapack:check
```
# 植える処理
### 植えるか判定する処理
額縁が条件に合っているかをチェックした上で、アイテムの中のタグの情報を**マクロで次のfunctionに渡します。**

datapack/functions/check
```
#額縁が農地の上且つ上向きの場合に植える処理を行う
execute as @s[nbt={Facing:1b}] if block ~ ~-1 ~ farmland run function datapack:plant with entity @s Item.tag
#農地以外の上にあるか、額縁の向きが上向きじゃない時に種を返却する処理を行う
execute unless block ~ ~-1 ~ farmland run function datapack:return with entity @s Item.tag
execute unless entity @s[nbt={Facing:1b}] if block ~ ~-1 ~ farmland run function datapack:return with entity @s Item.tag

```
### 植える処理
植えれる時の処理です。この時出すitem displayは判別するために適当にタグをつけます。ここではccagというタグをつけています。
マクロで額縁の中のアイテムの情報をアイテムディスプレイに詰め込みます。

datapack/functions/plant
```
#成長段階0のビートルートを出す
setblock ~ ~ ~ beetroots[age=0] replace
#アイテムディスプレイを出す
$summon item_display ~ ~ ~ {transformation:{scale:[0.5f,0.5f,0.5f],left_rotation:[0f,0f,0f,1f],translation:[0f,0f,0f],right_rotation:[0f,0f,0f,1f]},Rotation:[0f,-90f,0f,0f],Tags:["ccag"],item:{id:"minecraft:fern",Count:1,tag:{ccstage:1,cccmd:$(CustomModelData),CustomModelData:$(CustomModelData),ccname:$(ccname)}},item_display:fixed}
#額縁を消す
kill @s
```
### 返却する処理
植えられない時の処理です。

datapack:return
```
#種を返すためにlootを呼び出す
$loot spawn ~ ~0.5 ~ loot datapack:seed/$(ccname)
#額縁を消す
kill @s
```
# 作物が壊れた処理
文字通りです。ここでは成長段階が最大(4)の時にアイテムを落とすようにしていますが、書き加えることでほかの成長段階の時にもアイテムを落とすようにすることができます。

datapack/functions/break
```
#成長段階が最大の時にfunctionを呼び出す
execute as @s[nbt={item:{tag:{ccstage:5}}}] run function datapack:loot with entity @s item.tag
#item displayを消す
kill @s
```
datapack/functions/loot
```
#作物のloottableを呼び出す
$loot spawn ~ ~.5 ~ loot cc:vegetables/$(ccname)
```

# 作物の見た目の処理
作物の当たり判定に使っているバニラ作物（ここではビートルート）が成長した際に行われる処理です。

datapack/functions/looks
```
#成長段階が最大でないときに成長させる
execute unless entity @s[nbt={item:{tag:{ccstage:5}}}] run function cc:grow
#華やかさを演出
particle happy_villager ~ ~ ~ 0 0 0 0.05 10 normal
#成長段階が1のビートルートに置きなおす
setblock ~ ~ ~ beetroots[age=0]
```

### 成長処理
一旦ストレージにアイテムのタグの情報を入れて、そこからあれこれ計算します。
・ccstageの値を1上げたものをストレージの中のccstageに反映させる
・ccstageとcccmdの値を用いてストレージの中のCustomModelDataとcccmdの値を変更する

datapack/functions/grow
```
# storageかます
data modify storage cc:temp data set from entity @s item.tag
# cc.growに成長段階を代入
execute store result score @s cc.grow run data get storage cc:temp data.ccstage
# 成長段階を1上げたものをcc:tempのccstageに代入
execute store result storage cc:temp data.ccstage int 1 run scoreboard players add @s cc.grow 1
# CustomModelDataの値を演算する
scoreboard players remove @s cc.grow 1
execute store result score #cccmd cc.grow run data get storage cc:temp data.cccmd
scoreboard players operation @s cc.grow += #cccmd cc.grow
execute store result storage cc:temp data.CustomModelData int 1 run scoreboard players get @s cc.grow
# storageから作物へ反映
data modify entity @s item.tag set from storage cc:temp data

# 要らないものをリセット
#data remove storage cc:temp data
scoreboard players reset @s cc.grow
scoreboard players reset #cccmd cc.grow
```

これらすべてを実装した後、reloadしてワールドに反映させればカスタム作物が追加出来てるはずです。種をlootで呼び出して、実際にできるか試してみよう！

# もっと作物を追加してえよ！
loottableに新しいファイルを追加して、対応するテクスチャを描いて割り当てましょう。
例えば、額縁の中のアイテムのタグを{CustomModelData:6,ccreplace:1b,ccname:cucumber}にして、植えてある作物の成長差分として6から10を割り当てて、きゅうりの種ときゅうりのテクスチャを割り当てるとあら不思議。きゅうりが実装できちゃいます。
一度このデータパックの仕組みを書いてしまえば、あとはloottableとテクスチャの追加だけで作物が沢山作れちゃうんです。
# 最後にもーいっかい
これらのサンプルはCC BY-SA 4.0 DEEDで提供するので、「これ使ったよ！ってことを明記すること」と「これを使ったものを配布するときに同じライセンスで配布すること」さえすれば何してもじゆーです。よき作物ライフを～！
# 補足
これらは自分が開発している、農業/食べ物のデータパックの作物部分を抜き出して少し変更したものになります。昔のバージョンからバージョンアップのたびに修正を繰り返している為、結構無駄が多いと思いますが、ご了承ください。その他ご不明な点があればTwitter(X)の@ShunjuMint向けに質問を送ってください。

特にサンプルと何ら変わってる場所はないですが、参考程度にどうぞ。
農業/食べ物のデータパック

https://drive.google.com/file/d/1XWDwoLHF0TahKxlzoyBMSVVhDvdSaJ6w/view?usp=drive_link

リソースパック

https://drive.google.com/file/d/1zR054mNfWZ_90NRErtfecNmM3KYElmKp/view?usp=drive_link