3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Minecraft】UbuntuのCLI上でNBT→JSONするツールを作った

Last updated at Posted at 2020-02-26

前提

  • Ubuntu 18.04.3 LTS
  • bash
  • jqを使用
    • apt install jq

あらまし

Minecraftのサーバーを動かしていて、Ubuntuのコマンドライン上でMinecraftのセーブデータを解析したい需要が生じたので、Minecraftのセーブデータのフォーマットと、それをJSON文字列化する方法を調べた。その結果、期待したようなものは得られなかったため、以下のNBTとJSONを相互に変換するプログラムをPerlで作った。

背景

Minecraftのサーバーを動かしていて、Ubuntuのコマンドライン上でMinecraftのセーブデータを解析したい需要が生じた。

NBT

Minecraftのゲームデータは、NBTフォーマットで記述されている。これは値に型がついたバイナリ形式のJSON的なものである。セーブデータはほとんどがこのフォーマットで書かれている。

詳しい説明はWikiに任せる。

既存のプログラム

NBTExplorer

NBTExplorerはぱっと見LinuxのCLI上でJSON化できるツールではなさそうだった。

Windows用のGUIのNBT編集ソフトとしてはとても素晴らしかったが、今回はGUIのないUbuntuを使うので使用できない。

NBTUtilみたいな名前のツールが同封されており、これはWindowsのコマンドプロンプト(Bashからも可能)からならコマンドでNBTを独特のフォーマットに文字列化できる。JSONにもできるかもしれないが、Windows環境が求められたので無視した。

nbt2json(midnightfreddie)

Goで書かれたツールがあった。
こちらは入れようとしたけどGoの使い方が分からず、Go入門するくらいなら劣化版を自分で作った方が早そうだったので無視した。

prismarine-nbt

node用のモジュールらしい。かなりまともみたいなので本記事で作ったものよりよさそう。

JSON-to-NBT-Converter(KSashaDF)

2020年2月27日現在imperfectらしく良い出来ではなさそうだった。

成果物

以下のプログラムを作った。

元々はここに使用例などを記載する予定だったが、結局READMEに色々書いたのでここでは軽く触れるだけに留める。

NBTバイナリのJSON化

nbt2jsonを使うとNBTバイナリをJSONにできる。ただし、Minecraftのセーブデータは大体gzip圧縮されていることに気を付けなければならない。nbt2jsonは非圧縮のNBTバイナリデータを受け付ける。

  • $ cat sample/1.nbt | ./nbt2json
{"key":"","type":10,"value":[{"key":"list","type":9,"value":{"type":1,"values":[1,2]}},{"key":"double","type":6,"value":"0x3fd0000000000000=0.25"},{"key":"int","type":3,"value":-1}]}

便利化と整形

-cpを付けると便利で整形された出力になる。
-cが便利化、pが整形である。-cを付けるとCompoundタグはJSONオブジェクトになるが、タグの順序は保持されないことに気を付けなければならない。

  • $ cat sample/1.nbt | ./nbt2json -cp
{
   "C": {
      "Alist": {
         "type": "byte",
         "values": [
            1,
            2
         ]
      },
      "Ddouble": "0x3fd0000000000000=0.25",
      "Iint": -1
   }
}

逆変換

json2nbt -cnbt2json -cpの逆関数で、JSONを呼んでNBTを吐く。
-cはCompoundタグの内部のタグの順序が崩れること以外は大体元のNBTを返す。
nbt2jsonにはいろいろなオプションがあるが、いくつかのオプションはjson2nbtにそのまま食わせても読んでくれる。

浮動小数では、NaNや非正規数など複数のバイナリが一つの文字列表現になることがある。
これをjson2nbtで逆変換すると恒等にならないため、浮動小数は16進文字列と10進表現ペアとして出力される。
nbt2json -Hnbt2json -Bを使うとすべての数値が16進文字列や2進文字列に強制的になる。
json2nbtには-H-Bのオプションはないが、付けなくても受け付けてくれる。

  • $ cat sample/1.nbt | ./nbt2json -cp | ./json2nbt -c | ./nbt2json -cp
{
   "C": {
      "Alist": {
         "type": "byte",
         "values": [
            1,
            2
         ]
      },
      "Ddouble": "0x3fd0000000000000=0.25",
      "Iint": -1
   }
}

-eオプションの使用例

level.datを読んでワールドのSeed値を得たい場合、jqとかを使うよりも次のように直接perlの変数を書き換えるのがよい。

  • $ cat level.dat | inflate-gzip | nbt2json -cp -e '$_ = $_->{C}->{CData}->{LRandomSeed}'
7546217594578327695

jsonをすべて吐いてからjqを使う場合、データの変換のオーバーヘッドがかかるのはともかくとして、jsonは64ビット整数の扱いに難がある。

  • $ cat level.dat | inflate-gzip | nbt2json -cp | jq '.C.CData.LRandomSeed'
7546217594578328000

そのような場合は-Hオプションで16進文字列にして出力するとよい。

  • $ cat level.dat | inflate-gzip | nbt2json -cpH | jq '.C.CData.LRandomSeed'
"0x6c443070ec80dfb0"
3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?