マイクラのstorageについて備忘録

storageってなんだ?

極論を言ってしまえば、自由に作れるNBTみたいなもの。

私のざっくり感覚でまとめると。

  • スコアボードを使わなくても数字や文字を保存できる
  • ストレージの中身はチェックに使ったり、テキストチャットに表示することができる
  • データの外に保存しておける(他のワールドデータに入れれば使い回せる)

どうやって使うんだ?

storageに値を入れる方法(コマンド)は基本的にはdataコマンドになるでしょう。

data merge storage test {name:"keiduki"}

上はこういう感じになってます。

data merge storage <ストレージの名前> <NBTっぽいもの>

そうすると、testっていうストレージのnameに"keiduki"が保存されます。

使うときは例えばこういう感じ。

execute if data storage test {name:"keiduki"} run say "名前はケイヅキだった"

これが基本で、ここからさらに深めていきますよ。

データを保存してみる

保存する内容は自由に決められる

上で書いたように、適当なNBTっぽいものであれば何でも保存できます。

data merge storage test {aaa:0,bbb:"あいう",ccc:true,ddd:[1,2,3],eee:{fff:"ggg"}}

ちょっと見にくいので、見やすく整理すると、こう書いてます。

{
    aaa: 0,
    bbb: "あいう",
    ccc: true,
    ddd: [
        1,
        2,
        3
    ],
    eee: {
        fff: "ggg"
    }
}

こんなNBTはもちろん存在しません。だけれども、保存できちゃいます。

他のエンティティのNBTをそのままコピーする

dataコマンドということは、他のNBTを持ってこれます。

data modify storage test player set from entity @p

これは近くのプレイヤーの全NBTをtestの中のplayerに保存してくれます。

# gamerule sendCommandFeedback true にしておいてくださいね
data get storage test player

これで、中身を見ることができます。


全部はいらないって言う場合は一部だけ保存することもできます。

体力だけ保存しておきたい場合は、こんな感じ。

data modify storage test HP set from entity @p Health

もちろん同じ感じでブロックのNBTや他のストレージの情報もコピーできちゃいます。

こうすることで何がいいかっていうと、「その時点の」NBTデータを保存できるってことですね。プレイヤーとかブロックは、時間がたつといろんな値が変わりますからね。

スコアボードの値を保存する

ちょっと長くなりますが、executeのstoreを使って結果をストレージで保存することができます。

execute store result storage test score int 1 run scoreboard players get @p SCORE

これも「その時点の」スコアボードの値を保存できますね。

保存したデータを使ってみる

保存したデータを見る

例えば、testの中身を全部みたいなあってときはこうします。

# gamerule sendCommandFeedback true にしておいてくださいね
data get storage test

一部だけ、testのplayerだけみたいなあってときはこうします。

data get storage test player

さらに、playerのHealthだけみたいなあってときはこうします。

data get storage test player.Health

保存したデータを使う

ストレージの中身をチェックする

まずは最初の例で見せたように、シンプルなチェック。

execute if data storage test {name:"keiduki"} run say test

ただし、チェックするのは「かなり厳密に一致している必要がある」ので、地面の上で立っている判定をしたい時には、こうなります。

# ストレージの中身
{
  player: {
    OnGround: 1b
  }
}

# 失敗例 (1bにしていない)
execute if data storage test {player:{OnGround:1}} run say test

# 成功例 (1bにしている)
execute if data storage test {player:{OnGround:1b}} run say test

テキストチャットに表示する

ストレージに保存した情報はテキストチャットとして表示することもできます。

具体的にはこんな感じ。

tellraw @p {"nbt":"name","storage":"test"}

そうすると「keiduki」って表示されちゃいます。

もちろんtellrawなのでこういうふうに書けば、

tellraw @p [{"text":"名前は"},{"nbt":"name","storage":"test"},{"text":"です"}]

「私の名前はkeidukiです」って表示されます。


注意: 非常にやっかいな話ですが、tellrawやtitleなど表示する系のコマンドは「通常のJSON」で書かないといけません。「通常のJSON」とはなにかっていうお話は以下を参考にしてください。

keiduki.hatenablog.com

どこに保存されているのか?

ストレージはセーブデータの中にファイル化して、保存されます。

どこに保存されているかというと、ここになります。

.minecraft/saves/<ワールド名>/data/command_storage_<ストレージのパック名>.dat

はい、突然出てきた<ストレージのパック名>。これは何かというと、複数のストレージをさらに名前を付けて保存できるのです。

本来はストレージに保存するときはこういうふうに書きます。

data merge storage <ストレージのパック名>:<ストレージの名前> <NBTっぽいもの>

今までは、ストレージのパック名を省略していました。省略されるとパック名は何になるのか?

そうです。ド定番の「minecraft」ですね。

他のワールドで使う

ストレージはセーブデータの中に「ファイル化」されて保存されていました。

つ・ま・り、他のワールドの同じフォルダの中に入れてしまえば、使い回すことができるんですね。

結局、使い道は?

さて、ここまでで一通りざっくり使い方は説明してみましたが、具体的にどう使えばいいのか考えつかない方のために、結構頻繁に使っている私なりの使い道をご説明します。

スコアボードの数を減らしたい

スコアボードのobjectって管理するために大量にあるワールドとかってあるじゃないですか。

f:id:Keiduki:20200425104534p:plain

デバッグのときに表示すると、えーっと…どれだっけ?ってなるわけです。

そこで出た私の結論。

  • 頻繁に変更するやつはスコアボード
  • 保持しておきたいだけのやつはストレージ

チェックする内容を分かりやすく置き換えたい

今まではスコアボードで何でも管理していたわけです。

# ストーリーのアイテム入手イベントが起こった
scoreboard players set item EVENT 1
# ストーリーのアイテム2の入手イベントが起こった
scoreboard players set item2 EVENT 1

こんなのが大量にあって、いろんなファイルに書かれていると、チェックする時に非常に読みにくい。

# ストーリーのアイテム入手イベント1~3が全部達成している
execute if score item EVENT matches 1 if score item2 EVENT matches 1 if score item3 EVENT matches 1 run say "達成"

そこでストレージです。

# ストーリーのアイテム入手イベントが起こった
data modify storage event item append value "金の斧"
# ストーリーのアイテム2の入手イベントが起こった
data modify storage event item append value "銀の斧"

そして、チェックするときはこう書けばよいのです。

# ストーリーのアイテム入手イベント1~3が全部達成している
execute if data storage event {item:["金の斧","銀の斧","鉄の斧"]} run say "達成"

かなりシンプルになりました。しかも、こういうふうにも書けます。

# ストーリーのアイテム入手イベント1~3のどれかを達成していない
execute unless data storage event {item:["金の斧","銀の斧","鉄の斧"]} run say "未達成"

# ストーリーのアイテム入手イベント1を達成している(銀の斧、鉄の斧もitemに入っていてもOK)
execute if data storage event {item:["金の斧"]} run say "達成"

わかりやすく、汎用性もあがりますね。

会話の内容を一箇所にまとめたい

例えば会話の内容って、今まではこんな感じで書いていたわけです。

tellraw @p [{"text":"[村人]: "},{"text":"こんにちは!"}]
tellraw @p [{"text":"[村人]: "},{"text":"いい天気ですね!"}]
tellraw @p [{"text":"[村人]: "},{"text":"いまお時間よろしいですか!"}]
tellraw @p [{"text":"[村人]: "},{"text":"そうですか..."}]

それを会話だけを最初に登録するmcfunctionファイルを作ってしまって。

data modify storage villager name set value "村人"
# talkをまるごと消して初期化
data remove storage villager talk
data modify storage villager talk append value "こんにちは!"
data modify storage villager talk append value "いい天気ですね!"
data modify storage villager talk append value "いまお時間よろしいですか!"
data modify storage villager talk append value "そうですか..."

こう呼び出せばいいのです。

tellraw @p [{"nbt":"name","storage":"villager"},{"nbt":"talk[0]","storage":"villager"}]
tellraw @p [{"nbt":"name","storage":"villager"},{"nbt":"talk[1]","storage":"villager"}]
tellraw @p [{"nbt":"name","storage":"villager"},{"nbt":"talk[2]","storage":"villager"}]
tellraw @p [{"nbt":"name","storage":"villager"},{"nbt":"talk[3]","storage":"villager"}]

確かに書く量は増えました。

ですが、喋る人が増えれば増えるほど、修正する数が多ければ多いほど、1つのファイルを見るだけで済むのです。


ちなみにこういうふうに登録すると、そのまま表示されちゃいます。

data modify storage villager talk append value {"text":"こんにちは!","color":"red"}

## {text:"こんにちは!",color:"red"} が表示される

それは困るので、こう書けば、ちゃんと赤い文字で「こんにちは!」と表示されます。

# ' 'でくくってあげる
data modify storage villager talk append value '{"text":"こんにちは!","color":"red"}'
# interpretをつける
tellraw @p [{"interpret":true,"nbt":"talk[0]","storage":"villager"}]