ルッキーのコマンドメモ

主にマイクラのコマンドやデータパックに関することを書いていきます。

(マイクラ コマンド・データパック) プレイヤーのインベントリが一杯かを調べる

プレイヤのインベントリがいっぱいかを検知する

最近、データパックを作っているときにプレイヤのインベントリとホットバーがいっぱいかどうか(物が拾えない状態か)を検知して、コマンドを動かしたい、ということがありました。
オフハンドや防具スロットも含めてインベントリがいっぱいかを検知するのは簡単だったのですが、それらのスロットを除いてインベントリがいっぱいかを検知するのは調べてもあまり出てこなかったのでここに書いておきます。

目次

単にインベントリがいっぱいかを調べるコマンド

防具スロットやオフハンドを含めて、単純にインベントリがいっぱいかを調べるだけなら簡単にできます。 あらかじめtestというスコアを作っておくものとして、実装はこのようになります。

execute store result score @s test run data get entity @s Inventory
execute if score @s test matches 41 run say yes

このコマンドの内容は以下のようになります。

  1. 実行したプレイヤのnbtのInventoryの要素数をプレイヤのtestスコアに代入する。
    つまり、プレイヤのスロットのうち、埋まっているスロットの数をtestスコアに代入する。
  2. testスコアの値が41(インベントリの36スロット+防具の4スロット+オフハンドの1スロット)ならyesとチャットに表示する。

advancementを利用する方法

コマンドだけで実装したい場合は上記のような方法になりますが、データパックを利用するならadvancementを使う方法があります。
データパック内のdata/<名前空間>/advancementsフォルダ内にて、<好きな名前>.jsonというファイルを作成し、以下のように記述します。

{
  "criteria": {
    "requirement": {
      "trigger": "minecraft:inventory_changed",
      "conditions": {
        "slots": {
          "occupied": 41
        }
      }
    }
  },
  "rewards": {
    "function": "<名前空間>:full"
  }
}

そして、functionファイル内で以下のようなコマンドを記述します。(#の部分はコメントです)

#> full.mcfunction
say yes
advancement revoke @s only <名前空間>:<設定した名前>

内容としては、以下のようになります。

  1. まず、jsonファイルによって、インベントリの変更が行われたときに、空でないスロットの数が41個であると、達成される進捗を用意する。
  2. 1の進捗が達成されると、報酬(reward)としてfunctionファイルが実行される。
  3. functionファイル内で、チャットにyesと表示し、進捗を未達成の状態に戻す。

こちらの方法は少し複雑な方法になりますが、プレイヤのインベントリが変更された場合にしかコマンドが実行されないため、少しだけ処理が軽くなります。

特定のスロットを除いてインベントリがいっぱいかを検知する

上記のコマンドでは防具やオフハンドスロットを含めたインベントリが一杯であるかを調べることができるのですが、単純に新しいアイテムを拾えるかどうかを調べるといった時には、このコマンドを利用することはできません。
防具スロットやオフハンドスロットにアイテムを持っていなくても、他のスロットがいっぱいであればアイテムは拾えないからです。
そこで、特定のスロットを除いて、インベントリがいっぱいであるかを調べる方法を紹介します。

強引な方法

まず、かなり強引な方法を紹介します。 以下のような感じでコマンドを書けば実装できます。

# ひたすら検知するスロットを並べていく
execute if data entity @s Inventory[{Slot:0b}] if data entity @s Inventory[{Slot:1b}] if data entity @s Inventory[{Slot:2b}] if data entity @s Inventory[{Slot:3b}] if data entity @s Inventory[{Slot:4b}] if data entity @s Inventory[{Slot:5b}] if data entity @s Inventory[{Slot:6b}] if data entity @s Inventory[{Slot:7b}] if data entity @s Inventory[{Slot:8b}] run say yes

これはプレイヤのホットバーのスロットが全て埋まっているかを調べるコマンドです。
内容としては、実行したプレイヤのnbtのInventoryにスロット0番から8番のデータがある、つまりスロット0から8番が空のスロットでなければyesと表示するというものになります。

コマンド一つで実行できるという利点がありますが、調べたいスロットの数が多くなると、これを書くのはかなり大変になります。

調べたいスロットが多い場合に有効な方法

調べたいスロットの数が多い場合には以下のような方法が有効です。

execute store result storage test Inventory run data get entity @s Inventory
data remove storage test Inventory[{Slot:100b}]
data remove storage test Inventory[{Slot:101b}]
data remove storage test Inventory[{Slot:102b}]
data remove storage test Inventory[{Slot:103b}]
data remove storage test Inventory[{Slot:-106b}]
execute store result score @s test run data get storage test Inventory
execute if score @s test matches 36 run say yes

これは防具スロットとオフハンドスロットを除いたプレイヤのインベントリが全て埋まっているかを調べるコマンドになります。
細かな内容は以下のようになります。

  1. プレイヤのnbtのInventoryをtestというストレージのInventoryという部分にコピーしてくる。
  2. コピーしてきたストレージに入っているインベントリのデータから防具スロットとオフハンドスロットに関する部分のデータを消去する。
  3. ストレージに入っているデータの要素数をtestというスコアに代入する。
  4. testスコアの値が36(防具とオフハンドを除いたスロット数)であればyesと表示する。

こちらのコマンドは少し複雑ですが調べたいスロットの数が多い場合には有効です。

まとめ

ただプレイヤのインベントリがいっぱいかどうかを調べたい場合にはプレイヤのInventoryというnbtデータの要素数が41であるかを調べるだけで検知することができます。
特定のインベントリを除いて、プレイヤのインベントリがいっぱいであるかを調べる場合には、調べたいスロットを全てチェックするか、もしくはInventoryのnbtから除外するインベントリのスロットを除いて、その後にその要素数を調べるという方法で検知することができます。