/dataコマンド基礎:NBTを読み書きしよう

前回はアドバンスメントを使って「特定のアイテムを入手した瞬間にfunctionを自動実行する」仕組みを作りました。今回はその先へ進んで、エンティティやブロック・ストレージが内部に持つデータを /data コマンドで読み書きする方法を学びます。あわせて、1.20.5以降に導入された「データコンポーネント」と従来の「NBT」の使い分けについても整理します。これを押さえておくと、中級Datapackへの理解がぐっと深まります。

対応バージョン:Java Edition 1.21.11

目次

前提知識

NBTとデータコンポーネント:何が違う?

Minecraftのデータ管理には、大きく2つの仕組みがあります。まずここを整理しておくと、この先の説明がスムーズに入ってきます。

NBT(Named Binary Tag)は、エンティティ・ブロックエンティティ(チェストや看板など)・ストレージに使われるデータ形式です。プレイヤーの体力や座標、ゾンビの怒り状態、チェストの中身といった情報はすべてNBTで管理されており、/data コマンドでアクセスします。1.21.11でも変わらず使われています。

データコンポーネント(Data Components)は、Java Edition 1.20.5から導入されたアイテム専用の新しいデータ形式です。以前はアイテムのカスタム名や耐久値もNBTで {display:{Name:'...'}, Damage:10} のように書いていましたが、1.20.5以降は minecraft:custom_nameminecraft:damage といった「コンポーネント」として個別に管理されます。コマンド上では [minecraft:custom_name='{"text":"名前"}'] のように角括弧で表現されます。

この記事では /data コマンドを使うNBT側(エンティティ・ブロック・ストレージ)を中心に解説します。アイテムのデータコンポーネントは別記事で扱います。

ステップ1:data get でNBTを読む

/data get は、エンティティ・ブロックエンティティ・ストレージのNBTを読み取るコマンドです。アクセス先によって構文が3パターンあります。

# エンティティのNBTを読む
data get entity <セレクタ> [<パス>] [<倍率>]

# ブロックエンティティ(チェスト・看板など)のNBTを読む
data get block ~ ~ ~ [<パス>]

# ストレージのNBTを読む
data get storage <名前空間:ストレージ名> [<パス>]

まずパスなしで実行すると、そのエンティティが持つNBT全体がチャットに流れます。どんなキーが存在するかを調べるときに使います。

/data get entity @s

出力は {Health:20.0f, FoodLevel:20, XpLevel:0, Inventory:[...], ...} のようなキーと値の羅列です。量が多くて読みにくいので、目的のキーが分かったらパスを指定して絞り込みます

/data get entity @s Health

これで 20.0f だけが返ってきます。末尾の f は「float(小数)型」であることを示すMinecraftのNBT表記です。整数なら 20、byte型なら 1b のようにサフィックスが付きます。

パスなしで実行したときのNBT全体出力と、Health だけを絞り込んだ出力の対比GIF

パスの書き方

NBTのパスはドット(.)でネスト階層をたどり、角括弧([])でリストのインデックスを指定します。たとえばインベントリの最初のスロットのアイテムIDを見たい場合は次のように書きます。

# インベントリ全体を見る
/data get entity @s Inventory

# インベントリの0番目のスロットだけを見る
/data get entity @s Inventory[0]

# 0番目スロットのアイテムIDだけを取り出す
/data get entity @s Inventory[0].id

パスは大文字・小文字が区別される点に注意してください。health では取得できず、Health と正確に書く必要があります。正しいキー名は一度パスなしで全体を出力して確認するのが確実です。

/data get entity @s Inventory を実行し、アイテムリストのNBTが表示されている様子

ステップ2:data modify でNBTを書く

/data modify は、指定したパスのNBT値を変更するコマンドです。操作の種類(サブコマンド)によって動作が変わります。

# 直接値をセットする
data modify <ターゲット種別> <対象> <パス> set value <値>

# 別のNBT源からコピーする
data modify <ターゲット種別> <対象> <パス> set from <コピー元種別> <コピー元> [<パス>]

# リストの末尾に値を追加する
data modify <ターゲット種別> <対象> <パス> append value <値>

<ターゲット種別>entity / block / storage の3種類です。

値の型に注意する

NBTは値の型が厳密です。型を間違えるとエラーになったり、意図した動作をしないことがあります。よく使う型と書き方は以下のとおりです。

# 文字列(ダブルクォートで囲む)
data modify storage my_datapack:temp player.name set value "冒険者"

# 整数(int型、サフィックスなし)
data modify storage my_datapack:temp player.score set value 100

# 小数(float型、末尾にf)
data modify storage my_datapack:temp player.speed set value 1.5f

# 真偽値(byte型。1b = true、0b = false)
data modify storage my_datapack:temp player.isOnline set value 1b

文字列を囲むダブルクォートはNBT上の「文字列型」を意味します。コマンド自体をシングルクォートで囲むと内側でダブルクォートが使えるため、mcfunctionに書く場合は set value "文字列" の形がそのまま使えます。

set from でNBTをコピーする

set from を使うと、エンティティ・ブロック・ストレージ間でNBTをコピーできます。たとえば「プレイヤーの現在の体力をストレージに保存する」場合は次のように書きます。

# @s(実行者)の体力値をストレージにコピーする
data modify storage my_datapack:temp player.health set from entity @s Health

これで実行時点のプレイヤーの体力(例:18.0f)がストレージに保存されます。コピー元にもパスを指定することで、NBTの特定キーだけを取り出せます。パスを省略するとコピー元のNBT全体がそのままコピーされます。

なお、プレイヤーのゲーム内ユーザー名はNBTには存在しません。プレイヤー名を文字列として扱いたい場合は、スコアボードのプレイヤー名を利用するか、tellraw{"selector":"@s"} で表示するのが一般的です。CustomName はネームタグで名前を付けたMob専用のキーで、プレイヤーには使えません。

【画像】/data get entity @s Inventory を実行し、インベントリのNBTリストがチャット欄に表示されているスクリーンショット

ステップ3:storage とは何か、なぜ使うのか

エンティティのNBTはそのエンティティが消えると失われます。ブロックエンティティのNBTも、ブロックを壊せば消えます。では「Datapack全体で使いたいデータ」はどこに保存すればいいのでしょうか。それが storage(ストレージ) です。

ストレージはエンティティやブロックとは独立した、ワールドに紐付いたデータの保存領域です。ワールドを閉じても残り、/reload しても消えません。Datapackの複数の関数間で「変数」のようにデータをやり取りするときに使います。

ストレージのキーは 名前空間:識別子 の形式で自由に命名できます。my_datapack:tempmy_datapack:player_data のように、必ず自分のパックの名前空間を先頭に付けてください。複数のDatapackが同じサーバーで動く場面では、名前空間がないとキーが衝突する可能性があります。

ステップ4:storage を使った実例

「プレイヤー名をストレージに保存し、別の関数で読み出す」という基本パターンを作ります。

# save_name.mcfunction
# ストレージに文字列を書き込む
data modify storage my_datapack:temp player.name set value "冒険者"

# 確認:書き込んだ値を読み出してチャットに表示する
data get storage my_datapack:temp player.name

実行すると my_datapack:temp というストレージの player.name キーに "冒険者" が保存され、その値がチャットに表示されます。次に別の関数から読み出してみます。

# read_name.mcfunction
# ストレージから値を読み出す
data get storage my_datapack:temp player.name

別の関数からでも同じキーを指定すれば値を取り出せます。これが「関数間でのデータ受け渡し」の基本です。前回のアドバンスメントと組み合わせると、「アイテムを入手したときにアドバンスメントが save_name を呼び出し、その後別のタイミングで read_name でデータを参照する」といった構成が作れます。

save_name → read_name の順にfunctionを実行し、ストレージへの書き込みと読み出しの流れがチャットに表示されるまでのGIF

ステップ5:フォルダ構成と初期化の設計

ストレージは /reload しても内容が残るため、Datapackを作り直したときや初回ロード時に意図しない値が残っている可能性があります。そのため、初期値を保証したいストレージは load.mcfunction でリセットする設計にしましょう。

my_datapack/
├── pack.mcmeta
└── data/
    ├── minecraft/
    │   └── tags/
    │       └── function/
    │           └── load.json        ← minecraft名前空間に置くのがポイント
    └── my_datapack/
        └── function/
            ├── load.mcfunction      ← 起動時に自動実行される
            ├── save_name.mcfunction
            └── read_name.mcfunction
# data/minecraft/tags/function/load.json
# minecraft:load タグに my_datapack:load を登録する
# 「minecraft」名前空間のフォルダに置かないと認識されないので注意
{
  "values": ["my_datapack:load"]
}
# load.mcfunction
# Datapack読み込み時にストレージを初期値にリセットする
data modify storage my_datapack:temp player.name set value "名無し"
data modify storage my_datapack:temp player.score set value 0

load.jsontags/function/ に置き、minecraft:load タグに my_datapack:load を登録することで、Datapackが読み込まれるたびに load.mcfunction が自動実行されます。これでストレージの初期値が常に保証されます。

まとめ

  • 1.21.11ではエンティティ・ブロック・ストレージはNBTのまま。アイテムのデータは1.20.5以降「データコンポーネント」に移行しており、用途によって使い分ける
  • /data get でNBTを読み出せる。パスなしで全体確認→パスを絞り込む手順がおすすめ。パスは大文字・小文字を区別し、ドット(.)で階層、角括弧([])でリストインデックスを指定する
  • /data modify ... set value で値を直接書き込み、set from で別のNBT源からコピーできる。値の型(int・float・string・byte)を正しく書くことが重要
  • ストレージはDatapack専用の永続的な保存領域。関数間の「変数」として使い、名前空間を必ず付ける
  • ストレージの初期化は load.mcfunction で行う。minecraft:load タグに登録するとDatapack読み込み時に自動実行される

次の記事「Datapackが動かない!よくあるエラーと対処法」では、構文ミスやパスの大文字・小文字間違いなど初心者がハマりやすいポイントを網羅して解説します。/data コマンドを書いているときにもエラーが出やすいので、あわせて読んでみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次