Difference between revisions of "NBT"

From wiki.vg
Jump to navigation Jump to search
m (Categorizing)
 
(→‎Libraries: add craftflow-nbt implementation)
 
(117 intermediate revisions by 55 users not shown)
Line 1: Line 1:
'''The following is a slightly modified mirror of the no longer existent NBT.txt '''
+
The Named Binary Tag (NBT) file format is an extremely simple and efficient structured binary format used by Minecraft for a variety of things. Due to this, several third-party utilities now also utilize the format. You may find example files at the bottom of this article.
  
----
+
Mojang has released a reference implementation along with their Anvil conversion tool, available from [https://web.archive.org/web/20190710093131/https://mojang.com/2012/02/new-minecraft-map-format-anvil/ this archived page]
  
NBT (Named Binary Tag) is a tag based binary format designed to carry large amounts of binary data with smaller amounts of additional data.
+
== Current Uses ==
An NBT file consists of a single GZIPped Named Tag of type TAG_Compound.
+
The NBT format is currently used in several places, chiefly:
 +
* In the [[Protocol]] as part of [[Slot Data]]
 +
* Multiplayer saved server list (<code>servers.dat</code>).
 +
* Player data (both single player and multiplayer, one file per player). This includes such things as inventory and location.
 +
* Saved worlds (both single player and multiplayer).
 +
** World index file (<code>level.dat</code>) that contains general information (spawn point, time of day, etc...)
 +
** Chunk data (see [[Region Files]])
  
A Named Tag has the following format:
+
NBT files you can encounter as a developer will be stored in three different ways, mainly the second variation as per Notch's original specification.
 +
* Uncompressed,
 +
* [[wikipedia:Gzip|gzip'd]],
 +
* [[wikipedia:Zlib|zlib'd]] (aka DEFLATE with a few bytes extra)
  
    byte tagType
+
=== Libraries ===
    TAG_String name
 
    [payload]
 
   
 
The tagType is a single byte defining the contents of the payload of the tag.
 
  
The name is a descriptive name, and can be anything (eg "cat", "banana", "Hello World!"). It has nothing to do with the tagType.
+
There are many, many libraries for manipulating NBT, written in several languages, and often several per language. For example,
The purpose for this name is to name tags so parsing is easier and can be made to only look for certain recognized tag names.
 
Exception: If tagType is TAG_End, the name is skipped and assumed to be "".
 
  
The [payload] varies by tagType.
+
{| class="wikitable sortable" style="width: auto; text-align: center;"
 +
|-style="background:#eee"
 +
!Name
 +
!Description
 +
!Language
 +
|-
 +
! [https://github.com/nickelpro/cNBT cNBT]
 +
| As simple (and, consequently, as fast) as possible NBT file parser.
 +
| {{C}}
 +
|-
 +
! [https://sr.ht/~azbantium/libnbt/ libnbt]
 +
| A lightweight library to work with NBT, written in C.
 +
| {{C}}
 +
|-
 +
! [https://github.com/PrismLauncher/libnbtplusplus libnbt++]
 +
| A free C++ library for Minecraft's file format Named Binary Tag (NBT).
 +
| {{C++}}
 +
|-
 +
! [https://github.com/SpockBotMC/cpp-nbt cpp-nbt]
 +
| A C++23 header-only library for reading/writing Minecraft NBT data.
 +
| {{C++}}
 +
|-
 +
! [https://github.com/Bentechy66/venom Venom]
 +
| An NBT decoder written in pure Elixir.
 +
| [https://elixir-lang.org/ Elixir]
 +
|-
 +
! [https://github.com/Tnze/go-mc/tree/master/nbt go-nbt]
 +
| This package implements the Named Binary Tag format of Minecraft.
 +
| [https://go.dev/ Go]
 +
|-
 +
! [https://github.com/BitBuf/nbt BitBuf/nbt]
 +
| Flexible and intuitive library for reading and writing Minecraft's NBT format.
 +
| {{Java}}
 +
|-
 +
! [https://github.com/jglrxavpok/hephaistos hephaistos]
 +
| This library is both a NBT library and a Minecraft Anvil format library.
 +
| {{Java}} & {{Kotlin}}
 +
|-
 +
! [https://github.com/TheNullicorn/Nedit Nedit]
 +
| A simple, lightweight NBT parsing library
 +
| {{Java}}
 +
|-
 +
! [https://github.com/sjmulder/nbt-js NBT.js]
 +
| A JavaScript parser and serializer for NBT archives.
 +
| {{JavaScript}}
 +
|-
 +
! [https://github.com/Offroaders123/NBTify NBTify]
 +
| Parser & writer NBT library intended for usage in a web browser.
 +
| {{JavaScript}}, {{TypeScript}}
 +
|-
 +
! [https://github.com/BenWoodworth/knbt knbt]
 +
| Kotlin NBT library for kotlinx.serialization.
 +
| {{Kotlin}}
 +
|-
 +
! [https://github.com/luizrcs/KotlinNBT KotlinNBT]
 +
| With a builder DSL and type-safety
 +
| {{Kotlin}}
 +
|-
 +
! [https://gist.github.com/camdenorrb/bec73c5608267f0232bd8f5c42e0784d simpleNBT]
 +
| Streams, ByteBuffer, NIO, Endianness, Zlib, Gzip, Any Input/Output, Examples in Comments.
 +
| {{Kotlin}}
 +
|-
 +
! [https://github.com/Nimberite-Development/TagForge-Nim TagForge]
 +
| A library made for the serialisation and deserialisation of MC NBT!
 +
| [https://nim-lang.org/ Nim]
 +
|-
 +
! [https://github.com/aternosorg/php-nbt php-nbt]
 +
| A full PHP implementation of Minecraft's Named Binary Tag (NBT) format.
 +
| {{PHP}}
 +
|-
 +
! [https://github.com/twoolie/NBT NBT]
 +
| This is mainly a Named Binary Tag parser & writer library.
 +
| {{Python}}
 +
|-
 +
! [https://github.com/CorentinPtrl/hematite_nbt HematiteNBT]
 +
| A full-featured Rust crate for Minecraft's NBT file format, including Serde support.
 +
| {{Rust}}
 +
|-
 +
! [https://github.com/Rusty-Quartz/quartz_nbt Quartz NBT]
 +
| Provides support for encoding and decoding Minecraft's NBT format.
 +
| {{Rust}}
 +
|-
 +
! [https://github.com/azalea-rs/simdnbt SimdNBT]
 +
| A very fast NBT serializer and deserializer.
 +
| {{Rust}}
 +
|-
 +
! [https://github.com/owengage/fastnbt fastnbt]
 +
| Fast serde serializer and deserializer for Minecraft's NBT and Anvil formats
 +
| {{Rust}}
 +
|-
 +
! [https://github.com/shenjackyuanjie/nbt-rust shen-nbt5]
 +
| A Fast NBT parser/writer (warning: lot's of unsafe (from author))
 +
| {{Rust}}
 +
|-
 +
! [https://github.com/CrabCraftDev/CrabNBT CrabNBT]
 +
| Up-to-date Rust crate for easy and intuitive working with NBT data.
 +
| {{Rust}}
 +
|-
 +
! [https://crates.io/crates/craftflow-nbt CraftFlow-NBT]
 +
| Serde based NBT binary format implementation.
 +
| {{Rust}}
 +
|-
 +
! [https://github.com/drXor/ScalaNBT ScalaNBT]
 +
| Scala library for NBT io with some Mojangson support.
 +
| [https://www.scala-lang.org/ Scala]
 +
|-
 +
|}
  
Note that ONLY Named Tags carry the name and tagType data. Explicitly identified Tags (such as TAG_String above) only contains the payload.  
+
Unless you have specific goals or licence requirements, it is ''extremely recommended'' to go with one of the existing libraries.
  
The tag types and respective payloads are:
+
=== Utilities ===
 +
Almost every 3rd-party Minecraft application uses NBT on some level. There also exist several dedicated NBT editors, which will likely be useful to you if you are developing an NBT library of your own. These include:
 +
* [https://www.minecraftforum.net/forums/mapping-and-modding-java-edition/minecraft-tools/1262665-nbtexplorer-nbt-editor-for-windows-and-mac NBTExplorer] (C#) NBT Directory-tree interface that fully supports the Minecraft .mcr/.mca region files.
 +
* [https://web.archive.org/web/20180428090808/http://gerritg.de/wp/archives/152 NEINedit] (Obj-C), an OS X specific editor.
 +
* [https://bitbucket.org/zzzeek/nbt2yaml nbt2yaml] (Python), provides command-line editing of NBT via the YAML format, as well as a fast and minimalist NBT parsing/rendering API.
 +
* [https://github.com/C4K3/nbted nbted] (Rust; CC0), provides command-line editing of NBT files via your $EDITOR
 +
* [https://git.sleeping.town/unascribed/unbted unbted] (Rust; GPL-v3) Command-line interactive NBT editor
 +
* [https://github.com/midnightfreddie/nbt2json nbt2json] (Golang; MIT) Command-line utility for NBT to JSON/YAML conversion and back. MCPE-NBT support. Can be used as library.
 +
* [https://github.com/tryashtar/nbt-studio NBT Studio] (C#) A visual editor similar to NBT-Explorer (A claimed, spiritual successor). Supports Minecraft Bedrock Edition files and SNBT.
 +
* [https://sourceforge.net/projects/nbtfsutils/ NBTFS] (C; MPL-2) Editing NBT as using a file system; supports Minecraft region files.
 +
* [https://github.com/Lenni0451/ImNbt ImNbt] (Java) ImGui based NBT Directory-tree interface that supports Minecraft Java and Bedrock Edition NBT. Features diffing, searching and exporting in different NBT formats.
 +
* [https://offroaders123.github.io/Dovetail/ Dovetail] (JavaScript) web-based NBT editor for Java and Bedrock Edition.
  
    TYPE: 0  NAME: TAG_End
+
== Specification ==
    Payload: None.
+
The NBT file format is extremely simple, and writing a library capable of reading/writing it is a simple affair. There are 13 datatypes supported by this format, one of which is used to close compound tags. It is strongly advised to read this entire section or you may run into issues.
    Note:    This tag is used to mark the end of a list.
 
            Cannot be named! If type 0 appears where a Named Tag is expected, the name is assumed to be "".
 
            (In other words, this Tag is always just a single 0 byte when named, and nothing in all other cases)
 
  
    TYPE: 1  NAME: TAG_Byte
 
    Payload: A single signed byte (8 bits)
 
  
    TYPE: 2 NAME: TAG_Short
+
{{Warning|Heads up! Since 1.20.2 NBT sent over the network has a subtle but critical specification change, refer to the Network NBT section below for more information}}
    Payload: A signed short (16 bits, big endian)
 
  
    TYPE: 3  NAME: TAG_Int
 
    Payload: A signed short (32 bits, big endian)
 
  
    TYPE: 4 NAME: TAG_Long
+
{| class="wikitable"
    Payload: A signed long (64 bits, big endian)
+
|-
 +
! Type ID
 +
! Type Name
 +
! Payload Size (Bytes)
 +
! Description
 +
|- id=Specification:end_tag
 +
| 0
 +
| [[#Specification:end_tag|TAG_End]]
 +
| 0 
 +
| Signifies the end of a TAG_Compound. It is only ever used inside a TAG_Compound, a TAG_List that has it's type id set to TAG_Compound or as the type for a TAG_List if the length is 0 or negative, and is not named even when in a TAG_Compound
 +
|- id=Specification:byte_tag
 +
| 1
 +
| [[#Specification:byte_tag|TAG_Byte]]
 +
| 1
 +
| A single signed byte
 +
|- id=Specification:short_tag
 +
| 2
 +
| [[#Specification:short_tag|TAG_Short]]
 +
| 2
 +
| A single signed, big endian 16 bit integer
 +
|- id=Specification:int_tag
 +
| 3
 +
| [[#Specification:int_tag|TAG_Int]]
 +
| 4
 +
| A single signed, big endian 32 bit integer
 +
|- id=Specification:long_tag
 +
| 4
 +
| [[#Specification:long_tag|TAG_Long]]
 +
| 8
 +
| A single signed, big endian 64 bit integer
 +
|- id=Specification:float_tag
 +
| 5
 +
| [[#Specification:float_tag|TAG_Float]]
 +
| 4
 +
| A single, big endian [[wikipedia:IEEE 754-2008|IEEE-754]] single-precision floating point number ([[wikipedia:NaN|NaN]] possible)
 +
|- id=Specification:double_tag
 +
| 6
 +
| [[#Specification:double_tag|TAG_Double]]
 +
| 8
 +
| A single, big endian [[wikipedia:IEEE 754-2008|IEEE-754]] double-precision floating point number ([[wikipedia:NaN|NaN]] possible)
 +
|- id=Specification:byte_array_tag
 +
| 7
 +
| [[#Specification:byte_array_tag|TAG_Byte_Array]]
 +
| ...
 +
| A length-prefixed array of '''signed''' bytes. The prefix is a '''signed''' integer (thus 4 bytes)
 +
|- id=Specification:string_tag
 +
| 8
 +
| [[#Specification:string_tag|TAG_String]]
 +
| ...
 +
| A length-prefixed [https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8 modified UTF-8] string. The prefix is an '''unsigned''' short (thus 2 bytes) signifying the length of the string in bytes
 +
|- id=Specification:list_tag
 +
| 9
 +
| [[#Specification:list_tag|TAG_List]]
 +
| ...
 +
| A list of '''nameless''' tags, all of the same type. The list is prefixed with the <code>Type ID</code> of the items it contains (thus 1 byte), and the length of the list as a '''signed''' integer (a further 4 bytes).  If the length of the list is 0 or negative, the type may be 0 (TAG_End) but otherwise it must be any other type.  (The notchian implementation uses TAG_End in that situation, but another reference implementation by Mojang uses 1 instead; parsers should accept any type if the length is <= 0).
 +
|- id=Specification:compound_tag
 +
| 10
 +
| [[#Specification:compound_tag|TAG_Compound]]
 +
| ...
 +
| Effectively a list of '''named''' tags. Order is not guaranteed.
 +
|- id=Specification:int_array_tag
 +
| 11
 +
| [[#Specification:int_array_tag|TAG_Int_Array]]
 +
| ...
 +
| A length-prefixed array of '''signed''' integers. The prefix is a '''signed''' integer (thus 4 bytes) and indicates the number of 4 byte integers.
 +
|- id=Specification:long_array_tag
 +
| 12
 +
| [[#Specification:long_array_tag|TAG_Long_Array]]
 +
| ...
 +
| A length-prefixed array of '''signed''' longs. The prefix is a '''signed''' integer (thus 4 bytes) and indicates the number of 8 byte longs.
 +
|}
  
    TYPE: 5  NAME: TAG_Float
+
There are a couple of simple things to remember:
    Payload: A floating point value (32 bits, big endian, IEEE 754-2008, binary32)
+
* The datatypes representing numbers are in big-endian in Java edition, but Bedrock edition changes things up a bit. See the below section on Bedrock edition
 +
* Every NBT file will '''always''' implicitly be inside a tag compound, and also begin with a TAG_Compound (except in Bedrock edition, see below)
 +
* The structure of a NBT file is defined by the TAG_List and TAG_Compound types, as such a tag itself will only contain the payload, but depending on what the tag is contained within may contain additional headers. I.e. if it's inside a Compound, then each tag will begin with the TAG_id, and then a [https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8 modified UTF-8] string (the tag's name), and finally the payload. While in a list it will be only the payload, as there is no name and the tag type is given in the beginning of the list.
  
    TYPE: 6  NAME: TAG_Double
+
For example, here's the example layout of a <code>TAG_Short</code> on disk:
    Payload: A floating point value (64 bits, big endian, IEEE 754-2008, binary64)
 
  
    TYPE: 7  NAME: TAG_Byte_Array
+
{| class="wikitable"
    Payload: Int length (NOT TAGGED)
+
|-
            An array of bytes of unspecified format. The length of this array is <length> bytes
+
|
 +
! Type ID
 +
! Length of Name
 +
! Name
 +
! Payload
 +
|-
 +
! Decoded
 +
| 2
 +
| 9
 +
| <code>shortTest</code>
 +
| <code>32767</code>
 +
|-
 +
! On Disk (in hex)
 +
| <code>02</code>
 +
| <code>00 09</code>
 +
| <code>73 68 6F 72 74 54 65 73 74</code>
 +
| <code>7F FF</code>
 +
|}
  
    TYPE: 8  NAME: TAG_String
+
If this <code>TAG_Short</code> had been in a <code>TAG_List</code>, it would have been nothing more than the payload, since the type is implied and tags within the first level of a list are nameless.
    Payload: Short length  (NOT TAGGED)
 
            An array of bytes defining a string in UTF-8 format. The length of this array is <length> bytes
 
  
    TYPE: 9  NAME: TAG_List
+
=== Network NBT (Java Edition) ===
    Payload: Byte tagId (NOT TAGGED)
+
Since 1.20.2 (Protocol 764) NBT sent over the network has been updated to exclude the name from the root <code>TAG_COMPOUND</code>, this essentially boils down to the following.
            Int length (NOT TAGGED)
+
{| class="wikitable"
            A sequential list of Tags (not Named Tags), of type <typeId>. The length of this array is <length> Tags
+
|-
    Notes:  All tags share the same type.
+
|
 +
! Type ID
 +
! Length of Name
 +
! Name
 +
! Payload
 +
|-
 +
! < 1.20.2 (Protocol 764)
 +
| <code>0x0a</code>
 +
| <code>0x00 0x00</code>
 +
| (Empty name)
 +
| <code>0x02 0x09</code>
 +
|-
 +
! >= 1.20.2 (Protocol 764)
 +
| <code>0x0a</code>
 +
| N/A
 +
| N/A
 +
| <code>0x02 0x09</code>
 +
|}
 +
Remember - This only applies to network NBT. Player data, world data, etc... will not be affected.
  
    TYPE: 10 NAME: TAG_Compound
+
=== Bedrock edition ===
    Payload: A sequential list of Named Tags. This array keeps going until a TAG_End is found.
+
Bedrock edition makes a couple of significant changes to the NBT format. First of all, first tag in an NBT file can sometimes be a TAG_List instead of a TAG_Compound. Additionally, NBT data is encoded in one of two different formats, a little-endian version intended for writing to disk, and a VarInt version intended for transport over the network.
            TAG_End end
 
    Notes:  If there's a nested TAG_Compound within this tag, that one will also have a TAG_End, so simply reading until the next TAG_End will not work.
 
            The names of the named tags have to be unique within each TAG_Compound
 
            The order of the tags is not guaranteed.
 
           
 
           
 
  
 +
==== Little-endian ====
 +
Identical to the big-endian format used by Java edition, but all numbers are encoded in little-endian. This includes the 16-bit length prefix before tag names and TAG_String values, as well as TAG_Float and TAG_Double values.
  
 +
==== VarInt ====
 +
This format is a bit more complex than the others. The differences from Java edition's big-endian format are as follows:
 +
* TAG_Short, TAG_Float and TAG_Double values are encoded as their little-endian counterparts
 +
* TAG_Int values and the length prefixes for TAG_List, TAG_Byte_Array, TAG_Int_Array and TAG_Long_Array are encoded as [https://developers.google.com/protocol-buffers/docs/encoding#varints VarInts with ZigZag encoding]
 +
* TAG_Long values are encoded as [https://developers.google.com/protocol-buffers/docs/encoding#varints VarLongs with ZigZag encoding]
 +
* All strings (Tag names and TAG_String values) are length-prefixed with a normal [https://wiki.vg/Protocol#VarInt_and_VarLong VarInt]
  
Decoding example:
+
=== Examples ===
(Use http://www.minecraft.net/docs/test.nbt to test your implementation)
+
There are two defacto example files used for testing your implementation (<code>test.nbt</code> & <code>bigtest.nbt</code>), originally provided by Markus. The example output provided below was generated using [https://github.com/TkTech/PyNBT PyNBT]'s ''debug-nbt'' tool.
  
 +
==== test.nbt ====
 +
This first example is an uncompressed [[wikipedia:Hello world program|"Hello World"]] NBT example. Should you parse it correctly, you will get a structure similar to the following:
  
First we start by reading a Named Tag.
+
<pre>
After unzipping the stream, the first byte is a 10. That means the tag is a TAG_Compound (as expected by the specification).
+
  TAG_Compound('hello world'): 1 entry
 +
  {
 +
    TAG_String('name'): 'Bananrama'
 +
  }
 +
</pre>
  
The next two bytes are 0 and 11, meaning the name string consists of 11 UTF-8 characters. In this case, they happen to be "hello world".
+
Here is the example explained:
That means our root tag is named "hello world". We can now move on to the payload.
+
{| class="wikitable"
 +
|-
 +
| (The entire thing is implicitly inside a compound)
 +
! Type ID (first element in the implicit compound)
 +
! Length of name of the root compound
 +
! Name of the root compound
 +
! Type ID of first element in root compound
 +
! Length of name of first element in root
 +
! Name of first element
 +
! Length of string
 +
! String
 +
! Tag end (of root compound)
 +
|-
 +
! Decoded
 +
| Compound
 +
| 11
 +
| ''hello world''
 +
| String
 +
| 4
 +
| ''name''
 +
| 9
 +
| ''Bananrama''
 +
|
 +
|-
 +
! On Disk (in hex)
 +
| <code>0a</code>
 +
| <code>00 0b</code>
 +
| <code>68 65 6c 6c 6f 20 77 6f 72 6c 64</code>
 +
| <code>08</code>
 +
| <code>00 04</code>
 +
| <code>6e 61 6d 65</code>
 +
| <code>00 09</code>
 +
| <code>42 61 6e 61 6e 72 61 6d 61</code>
 +
| <code>00</code>
 +
|}
  
From the specification, we see that TAG_Compound consists of a series of Named Tags, so we read another byte to find the tagType.
+
==== bigtest.nbt ====
It happens to be an 8. The name is 4 letters long, and happens to be "name". Type 8 is TAG_String, meaning we read another two bytes to get the length,
+
This second example is a gzip compressed test of every available tag. If your program can successfully parse this file, then you've done well. Note that the tags under ''TAG_List'' do not have a name, as mentioned above.  
then read that many bytes to get the contents. In this case, it's "Bananrama".
+
<pre>
 
+
  TAG_Compound('Level'): 11 entries
So now we know the TAG_Compound contains a TAG_String named "name" with the content "Bananrama"
+
  {
 
+
    TAG_Compound('nested compound test'): 2 entries
We move on to reading the next Named Tag, and get a 0. This is TAG_End, which always has an implied name of "". That means that the list of entries
+
    {
in the TAG_Compound is over, and indeed all of the NBT file.
+
      TAG_Compound('egg'): 2 entries
 
+
      {
So we ended up with this:
+
        TAG_String('name'): 'Eggbert'
 +
        TAG_Float('value'): 0.5
 +
      }
 +
      TAG_Compound('ham'): 2 entries
 +
      {
 +
        TAG_String('name'): 'Hampus'
 +
        TAG_Float('value'): 0.75
 +
      }
 +
    }
 +
    TAG_Int('intTest'): 2147483647
 +
    TAG_Byte('byteTest'): 127
 +
    TAG_String('stringTest'): 'HELLO WORLD THIS IS A TEST STRING \xc5\xc4\xd6!'
 +
    TAG_List('listTest (long)'): 5 entries
 +
    {
 +
      TAG_Long(None): 11
 +
      TAG_Long(None): 12
 +
      TAG_Long(None): 13
 +
      TAG_Long(None): 14
 +
      TAG_Long(None): 15
 +
    }
 +
    TAG_Double('doubleTest'): 0.49312871321823148
 +
    TAG_Float('floatTest'): 0.49823147058486938
 +
    TAG_Long('longTest'): 9223372036854775807L
 +
    TAG_List('listTest (compound)'): 2 entries
 +
    {
 +
      TAG_Compound(None): 2 entries
 +
      {
 +
        TAG_Long('created-on'): 1264099775885L
 +
        TAG_String('name'): 'Compound tag #0'
 +
      }
 +
      TAG_Compound(None): 2 entries
 +
      {
 +
        TAG_Long('created-on'): 1264099775885L
 +
        TAG_String('name'): 'Compound tag #1'
 +
      }
 +
    }
 +
    TAG_Byte_Array('byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))'): [1000 bytes]
 +
    TAG_Short('shortTest'): 32767
 +
  }
 +
</pre>
  
    TAG_Compound("hello world"): 1 entries
+
==== servers.dat ====
 +
The ''servers.dat'' file contains a list of multiplayer servers you've added to the game. To mix things up a bit, this file will always be uncompressed. Below is an example of the structure seen in ''servers.dat''.
 +
<pre>
 +
  TAG_Compound(<nowiki>''</nowiki>): 1 entry
 +
  {
 +
    TAG_List('servers'): 2 entries
 
     {
 
     {
         TAG_String("name"): Bananrama
+
      TAG_Compound(None): 3 entries
 +
      {
 +
        TAG_Byte('acceptTextures'): 1 (Automatically accept resourcepacks from this server)
 +
        TAG_String('ip'): '199.167.132.229:25620'
 +
         TAG_String('name'): 'Dainz1 - Creative'
 +
       
 +
      }
 +
      TAG_Compound(None): 3 entries
 +
      {
 +
        TAG_String('icon'): 'iVBORw0KGgoAAAANUhEUgAAAEAAAABACA...' (The base64-encoded server icon. Trimmed here for the example's sake)
 +
        TAG_String('ip'): '76.127.122.65:25565'
 +
        TAG_String('name'): 'minstarmin4'
 +
       
 +
      }
 
     }
 
     }
 +
  }
 +
</pre>
  
 
+
==== level.dat ====
 
+
This final example is of a single player ''level.dat'', which is compressed using gzip. Notice the player's inventory and general world details such as spawn position, world name, and the game seed.
For a slightly longer test, download http://www.minecraft.net/docs/bigtest.nbt
+
<pre>
You should end up with this:
+
  TAG_Compound(<nowiki>''</nowiki>): 1 entry
 
+
  {
     TAG_Compound("Level"): 11 entries
+
     TAG_Compound('Data'): 17 entries
 
     {
 
     {
      TAG_Short("shortTest"): 32767
+
      TAG_Byte('raining'): 0
      TAG_Long("longTest"): 9223372036854775807
+
      TAG_Long('RandomSeed'): 3142388825013346304L
      TAG_Float("floatTest"): 0.49823147
+
      TAG_Int('SpawnX'): 0
      TAG_String("stringTest"): HELLO WORLD THIS IS A TEST STRING !
+
      TAG_Int('SpawnZ'): 0
      TAG_Int("intTest"): 2147483647
+
      TAG_Long('LastPlayed'): 1323133681772L
      TAG_Compound("nested compound test"): 2 entries
+
      TAG_Int('GameType'): 1
      {
+
      TAG_Int('SpawnY'): 63
           TAG_Compound("ham"): 2 entries
+
      TAG_Byte('MapFeatures'): 1
 +
      TAG_Compound('Player'): 24 entries
 +
      {
 +
        TAG_Int('XpTotal'): 0
 +
        TAG_Compound('abilities'): 4 entries
 +
        {
 +
          TAG_Byte('instabuild'): 1
 +
          TAG_Byte('flying'): 1
 +
          TAG_Byte('mayfly'): 1
 +
          TAG_Byte('invulnerable'): 1
 +
        }
 +
        TAG_Int('XpLevel'): 0
 +
        TAG_Int('Score'): 0
 +
        TAG_Short('Health'): 20
 +
        TAG_List('Inventory'): 13 entries
 +
        {
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 1
 +
            TAG_Byte('Slot'): 0
 +
            TAG_Short('id'): 24
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 1
 +
            TAG_Byte('Slot'): 1
 +
            TAG_Short('id'): 25
 +
            TAG_Short('Damage'): 0
 +
          }
 +
           TAG_Compound(None): 4 entries
 
           {
 
           {
            TAG_String("name"): Hampus
+
            TAG_Byte('Count'): 1
            TAG_Float("value"): 0.75
+
            TAG_Byte('Slot'): 2
 +
            TAG_Short('id'): 326
 +
            TAG_Short('Damage'): 0
 
           }
 
           }
           TAG_Compound("egg"): 2 entries
+
           TAG_Compound(None): 4 entries
 
           {
 
           {
            TAG_String("name"): Eggbert
+
            TAG_Byte('Count'): 1
            TAG_Float("value"): 0.5
+
            TAG_Byte('Slot'): 3
 +
            TAG_Short('id'): 29
 +
            TAG_Short('Damage'): 0
 
           }
 
           }
      }
+
           TAG_Compound(None): 4 entries
      TAG_List("listTest (long)"): 5 entries of type TAG_Long
 
      {
 
           TAG_Long: 11
 
          TAG_Long: 12
 
          TAG_Long: 13
 
          TAG_Long: 14
 
          TAG_Long: 15
 
      }
 
      TAG_Byte("byteTest"): 127
 
      TAG_List("listTest (compound)"): 2 entries of type TAG_Compound
 
      {
 
          TAG_Compound: 2 entries
 
 
           {
 
           {
            TAG_String("name"): Compound tag #0
+
            TAG_Byte('Count'): 10
            TAG_Long("created-on"): 1264099775885
+
            TAG_Byte('Slot'): 4
 +
            TAG_Short('id'): 69
 +
            TAG_Short('Damage'): 0
 
           }
 
           }
           TAG_Compound: 2 entries
+
           TAG_Compound(None): 4 entries
 
           {
 
           {
            TAG_String("name"): Compound tag #1
+
            TAG_Byte('Count'): 3
            TAG_Long("created-on"): 1264099775885
+
            TAG_Byte('Slot'): 5
 +
            TAG_Short('id'): 33
 +
            TAG_Short('Damage'): 0
 
           }
 
           }
      }
+
          TAG_Compound(None): 4 entries
      TAG_Byte_Array("byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))"): [1000 bytes]
+
          {
      TAG_Double("doubleTest"): 0.4931287132182315
+
            TAG_Byte('Count'): 43
 +
            TAG_Byte('Slot'): 6
 +
            TAG_Short('id'): 356
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 64
 +
            TAG_Byte('Slot'): 7
 +
            TAG_Short('id'): 331
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 20
 +
            TAG_Byte('Slot'): 8
 +
            TAG_Short('id'): 76
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 64
 +
            TAG_Byte('Slot'): 9
 +
            TAG_Short('id'): 331
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 1
 +
            TAG_Byte('Slot'): 10
 +
            TAG_Short('id'): 323
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 16
 +
            TAG_Byte('Slot'): 11
 +
            TAG_Short('id'): 331
 +
            TAG_Short('Damage'): 0
 +
          }
 +
          TAG_Compound(None): 4 entries
 +
          {
 +
            TAG_Byte('Count'): 1
 +
            TAG_Byte('Slot'): 12
 +
            TAG_Short('id'): 110
 +
            TAG_Short('Damage'): 0
 +
          }
 +
        }
 +
        TAG_Short('HurtTime'): 0
 +
        TAG_Short('Fire'): -20
 +
        TAG_Float('foodExhaustionLevel'): 0.0
 +
        TAG_Float('foodSaturationLevel'): 5.0
 +
        TAG_Int('foodTickTimer'): 0
 +
        TAG_Short('SleepTimer'): 0
 +
        TAG_Short('DeathTime'): 0
 +
        TAG_List('Rotation'): 2 entries
 +
        {
 +
          TAG_Float(None): 1151.9342041015625
 +
          TAG_Float(None): 32.249679565429688
 +
        }
 +
        TAG_Float('XpP'): 0.0
 +
        TAG_Float('FallDistance'): 0.0
 +
        TAG_Short('Air'): 300
 +
        TAG_List('Motion'): 3 entries
 +
        {
 +
          TAG_Double(None): -2.9778325794951344e-11
 +
          TAG_Double(None): -0.078400001525878907
 +
          TAG_Double(None): 1.1763942772801152e-11
 +
        }
 +
        TAG_Int('Dimension'): 0
 +
        TAG_Byte('OnGround'): 1
 +
        TAG_List('Pos'): 3 entries
 +
        {
 +
          TAG_Double(None): 256.87499499518492
 +
          TAG_Double(None): 112.62000000476837
 +
          TAG_Double(None): -34.578128612797634
 +
        }
 +
        TAG_Byte('Sleeping'): 0
 +
        TAG_Short('AttackTime'): 0
 +
        TAG_Int('foodLevel'): 20
 +
      }
 +
      TAG_Int('thunderTime'): 2724
 +
      TAG_Int('version'): 19132
 +
      TAG_Int('rainTime'): 5476
 +
      TAG_Long('Time'): 128763
 +
      TAG_Byte('thundering'): 1
 +
      TAG_Byte('hardcore'): 0
 +
      TAG_Long('SizeOnDisk'): 0
 +
      TAG_String('LevelName'): 'Sandstone Test World'
 
     }
 
     }
 +
  }
 +
</pre>
 +
 +
==== Download ====
 +
* [https://raw.github.com/Dav1dde/nbd/master/test/hello_world.nbt test.nbt/hello_world.nbt] (uncompressed),
 +
* [https://raw.github.com/Dav1dde/nbd/master/test/bigtest.nbt bigtest.nbt] (gzip compressed)
 +
* [https://github.com/VADemon/nbd/raw/5de7a3f37569e1ffee11afbc017ae08e2c24523e/test/Player-nan-value.dat NaN-value-double.dat] (compressed, origin version unknown)
 +
* [https://web.archive.org/web/20110723210920/http://www.minecraft.net/docs/NBT.txt NBT.txt] (original NBT specification)
  
[[Category:Minecraft Alpha]]
+
[[Category:Protocol_Details]]
[[Category:Minecraft Classic]]
+
[[Category:Minecraft_Modern]]
[[Category:File Formats]]
+
[[Category:File_Formats]]

Latest revision as of 09:49, 26 October 2024

The Named Binary Tag (NBT) file format is an extremely simple and efficient structured binary format used by Minecraft for a variety of things. Due to this, several third-party utilities now also utilize the format. You may find example files at the bottom of this article.

Mojang has released a reference implementation along with their Anvil conversion tool, available from this archived page

Current Uses

The NBT format is currently used in several places, chiefly:

  • In the Protocol as part of Slot Data
  • Multiplayer saved server list (servers.dat).
  • Player data (both single player and multiplayer, one file per player). This includes such things as inventory and location.
  • Saved worlds (both single player and multiplayer).
    • World index file (level.dat) that contains general information (spawn point, time of day, etc...)
    • Chunk data (see Region Files)

NBT files you can encounter as a developer will be stored in three different ways, mainly the second variation as per Notch's original specification.

  • Uncompressed,
  • gzip'd,
  • zlib'd (aka DEFLATE with a few bytes extra)

Libraries

There are many, many libraries for manipulating NBT, written in several languages, and often several per language. For example,

Name Description Language
cNBT As simple (and, consequently, as fast) as possible NBT file parser. C
libnbt A lightweight library to work with NBT, written in C. C
libnbt++ A free C++ library for Minecraft's file format Named Binary Tag (NBT). C++
cpp-nbt A C++23 header-only library for reading/writing Minecraft NBT data. C++
Venom An NBT decoder written in pure Elixir. Elixir
go-nbt This package implements the Named Binary Tag format of Minecraft. Go
BitBuf/nbt Flexible and intuitive library for reading and writing Minecraft's NBT format. Java
hephaistos This library is both a NBT library and a Minecraft Anvil format library. Java & Kotlin
Nedit A simple, lightweight NBT parsing library Java
NBT.js A JavaScript parser and serializer for NBT archives. JavaScript
NBTify Parser & writer NBT library intended for usage in a web browser. JavaScript, TypeScript
knbt Kotlin NBT library for kotlinx.serialization. Kotlin
KotlinNBT With a builder DSL and type-safety Kotlin
simpleNBT Streams, ByteBuffer, NIO, Endianness, Zlib, Gzip, Any Input/Output, Examples in Comments. Kotlin
TagForge A library made for the serialisation and deserialisation of MC NBT! Nim
php-nbt A full PHP implementation of Minecraft's Named Binary Tag (NBT) format. PHP
NBT This is mainly a Named Binary Tag parser & writer library. Python
HematiteNBT A full-featured Rust crate for Minecraft's NBT file format, including Serde support. Rust
Quartz NBT Provides support for encoding and decoding Minecraft's NBT format. Rust
SimdNBT A very fast NBT serializer and deserializer. Rust
fastnbt Fast serde serializer and deserializer for Minecraft's NBT and Anvil formats Rust
shen-nbt5 A Fast NBT parser/writer (warning: lot's of unsafe (from author)) Rust
CrabNBT Up-to-date Rust crate for easy and intuitive working with NBT data. Rust
CraftFlow-NBT Serde based NBT binary format implementation. Rust
ScalaNBT Scala library for NBT io with some Mojangson support. Scala

Unless you have specific goals or licence requirements, it is extremely recommended to go with one of the existing libraries.

Utilities

Almost every 3rd-party Minecraft application uses NBT on some level. There also exist several dedicated NBT editors, which will likely be useful to you if you are developing an NBT library of your own. These include:

  • NBTExplorer (C#) NBT Directory-tree interface that fully supports the Minecraft .mcr/.mca region files.
  • NEINedit (Obj-C), an OS X specific editor.
  • nbt2yaml (Python), provides command-line editing of NBT via the YAML format, as well as a fast and minimalist NBT parsing/rendering API.
  • nbted (Rust; CC0), provides command-line editing of NBT files via your $EDITOR
  • unbted (Rust; GPL-v3) Command-line interactive NBT editor
  • nbt2json (Golang; MIT) Command-line utility for NBT to JSON/YAML conversion and back. MCPE-NBT support. Can be used as library.
  • NBT Studio (C#) A visual editor similar to NBT-Explorer (A claimed, spiritual successor). Supports Minecraft Bedrock Edition files and SNBT.
  • NBTFS (C; MPL-2) Editing NBT as using a file system; supports Minecraft region files.
  • ImNbt (Java) ImGui based NBT Directory-tree interface that supports Minecraft Java and Bedrock Edition NBT. Features diffing, searching and exporting in different NBT formats.
  • Dovetail (JavaScript) web-based NBT editor for Java and Bedrock Edition.

Specification

The NBT file format is extremely simple, and writing a library capable of reading/writing it is a simple affair. There are 13 datatypes supported by this format, one of which is used to close compound tags. It is strongly advised to read this entire section or you may run into issues.


Warning.png Heads up! Since 1.20.2 NBT sent over the network has a subtle but critical specification change, refer to the Network NBT section below for more information


Type ID Type Name Payload Size (Bytes) Description
0 TAG_End 0 Signifies the end of a TAG_Compound. It is only ever used inside a TAG_Compound, a TAG_List that has it's type id set to TAG_Compound or as the type for a TAG_List if the length is 0 or negative, and is not named even when in a TAG_Compound
1 TAG_Byte 1 A single signed byte
2 TAG_Short 2 A single signed, big endian 16 bit integer
3 TAG_Int 4 A single signed, big endian 32 bit integer
4 TAG_Long 8 A single signed, big endian 64 bit integer
5 TAG_Float 4 A single, big endian IEEE-754 single-precision floating point number (NaN possible)
6 TAG_Double 8 A single, big endian IEEE-754 double-precision floating point number (NaN possible)
7 TAG_Byte_Array ... A length-prefixed array of signed bytes. The prefix is a signed integer (thus 4 bytes)
8 TAG_String ... A length-prefixed modified UTF-8 string. The prefix is an unsigned short (thus 2 bytes) signifying the length of the string in bytes
9 TAG_List ... A list of nameless tags, all of the same type. The list is prefixed with the Type ID of the items it contains (thus 1 byte), and the length of the list as a signed integer (a further 4 bytes). If the length of the list is 0 or negative, the type may be 0 (TAG_End) but otherwise it must be any other type. (The notchian implementation uses TAG_End in that situation, but another reference implementation by Mojang uses 1 instead; parsers should accept any type if the length is <= 0).
10 TAG_Compound ... Effectively a list of named tags. Order is not guaranteed.
11 TAG_Int_Array ... A length-prefixed array of signed integers. The prefix is a signed integer (thus 4 bytes) and indicates the number of 4 byte integers.
12 TAG_Long_Array ... A length-prefixed array of signed longs. The prefix is a signed integer (thus 4 bytes) and indicates the number of 8 byte longs.

There are a couple of simple things to remember:

  • The datatypes representing numbers are in big-endian in Java edition, but Bedrock edition changes things up a bit. See the below section on Bedrock edition
  • Every NBT file will always implicitly be inside a tag compound, and also begin with a TAG_Compound (except in Bedrock edition, see below)
  • The structure of a NBT file is defined by the TAG_List and TAG_Compound types, as such a tag itself will only contain the payload, but depending on what the tag is contained within may contain additional headers. I.e. if it's inside a Compound, then each tag will begin with the TAG_id, and then a modified UTF-8 string (the tag's name), and finally the payload. While in a list it will be only the payload, as there is no name and the tag type is given in the beginning of the list.

For example, here's the example layout of a TAG_Short on disk:

Type ID Length of Name Name Payload
Decoded 2 9 shortTest 32767
On Disk (in hex) 02 00 09 73 68 6F 72 74 54 65 73 74 7F FF

If this TAG_Short had been in a TAG_List, it would have been nothing more than the payload, since the type is implied and tags within the first level of a list are nameless.

Network NBT (Java Edition)

Since 1.20.2 (Protocol 764) NBT sent over the network has been updated to exclude the name from the root TAG_COMPOUND, this essentially boils down to the following.

Type ID Length of Name Name Payload
< 1.20.2 (Protocol 764) 0x0a 0x00 0x00 (Empty name) 0x02 0x09
>= 1.20.2 (Protocol 764) 0x0a N/A N/A 0x02 0x09

Remember - This only applies to network NBT. Player data, world data, etc... will not be affected.

Bedrock edition

Bedrock edition makes a couple of significant changes to the NBT format. First of all, first tag in an NBT file can sometimes be a TAG_List instead of a TAG_Compound. Additionally, NBT data is encoded in one of two different formats, a little-endian version intended for writing to disk, and a VarInt version intended for transport over the network.

Little-endian

Identical to the big-endian format used by Java edition, but all numbers are encoded in little-endian. This includes the 16-bit length prefix before tag names and TAG_String values, as well as TAG_Float and TAG_Double values.

VarInt

This format is a bit more complex than the others. The differences from Java edition's big-endian format are as follows:

  • TAG_Short, TAG_Float and TAG_Double values are encoded as their little-endian counterparts
  • TAG_Int values and the length prefixes for TAG_List, TAG_Byte_Array, TAG_Int_Array and TAG_Long_Array are encoded as VarInts with ZigZag encoding
  • TAG_Long values are encoded as VarLongs with ZigZag encoding
  • All strings (Tag names and TAG_String values) are length-prefixed with a normal VarInt

Examples

There are two defacto example files used for testing your implementation (test.nbt & bigtest.nbt), originally provided by Markus. The example output provided below was generated using PyNBT's debug-nbt tool.

test.nbt

This first example is an uncompressed "Hello World" NBT example. Should you parse it correctly, you will get a structure similar to the following:

  TAG_Compound('hello world'): 1 entry
  {
    TAG_String('name'): 'Bananrama'
  }

Here is the example explained:

(The entire thing is implicitly inside a compound) Type ID (first element in the implicit compound) Length of name of the root compound Name of the root compound Type ID of first element in root compound Length of name of first element in root Name of first element Length of string String Tag end (of root compound)
Decoded Compound 11 hello world String 4 name 9 Bananrama
On Disk (in hex) 0a 00 0b 68 65 6c 6c 6f 20 77 6f 72 6c 64 08 00 04 6e 61 6d 65 00 09 42 61 6e 61 6e 72 61 6d 61 00

bigtest.nbt

This second example is a gzip compressed test of every available tag. If your program can successfully parse this file, then you've done well. Note that the tags under TAG_List do not have a name, as mentioned above.

  TAG_Compound('Level'): 11 entries
  {
    TAG_Compound('nested compound test'): 2 entries
    {
      TAG_Compound('egg'): 2 entries
      {
        TAG_String('name'): 'Eggbert'
        TAG_Float('value'): 0.5
      }
      TAG_Compound('ham'): 2 entries
      {
        TAG_String('name'): 'Hampus'
        TAG_Float('value'): 0.75
      }
    }
    TAG_Int('intTest'): 2147483647
    TAG_Byte('byteTest'): 127
    TAG_String('stringTest'): 'HELLO WORLD THIS IS A TEST STRING \xc5\xc4\xd6!'
    TAG_List('listTest (long)'): 5 entries
    {
      TAG_Long(None): 11
      TAG_Long(None): 12
      TAG_Long(None): 13
      TAG_Long(None): 14
      TAG_Long(None): 15
    }
    TAG_Double('doubleTest'): 0.49312871321823148
    TAG_Float('floatTest'): 0.49823147058486938
    TAG_Long('longTest'): 9223372036854775807L
    TAG_List('listTest (compound)'): 2 entries
    {
      TAG_Compound(None): 2 entries
      {
        TAG_Long('created-on'): 1264099775885L
        TAG_String('name'): 'Compound tag #0'
      }
      TAG_Compound(None): 2 entries
      {
        TAG_Long('created-on'): 1264099775885L
        TAG_String('name'): 'Compound tag #1'
      }
    }
    TAG_Byte_Array('byteArrayTest (the first 1000 values of (n*n*255+n*7)%100, starting with n=0 (0, 62, 34, 16, 8, ...))'): [1000 bytes]
    TAG_Short('shortTest'): 32767
  }

servers.dat

The servers.dat file contains a list of multiplayer servers you've added to the game. To mix things up a bit, this file will always be uncompressed. Below is an example of the structure seen in servers.dat.

  TAG_Compound(''): 1 entry
  {
    TAG_List('servers'): 2 entries
    {
      TAG_Compound(None): 3 entries
      {
        TAG_Byte('acceptTextures'): 1 (Automatically accept resourcepacks from this server)
        TAG_String('ip'): '199.167.132.229:25620'
        TAG_String('name'): 'Dainz1 - Creative'
        
      }
      TAG_Compound(None): 3 entries
      {
        TAG_String('icon'): 'iVBORw0KGgoAAAANUhEUgAAAEAAAABACA...' (The base64-encoded server icon. Trimmed here for the example's sake)
        TAG_String('ip'): '76.127.122.65:25565'
        TAG_String('name'): 'minstarmin4'
        
      }
    }
  }

level.dat

This final example is of a single player level.dat, which is compressed using gzip. Notice the player's inventory and general world details such as spawn position, world name, and the game seed.

  TAG_Compound(''): 1 entry
  {
    TAG_Compound('Data'): 17 entries
    {
      TAG_Byte('raining'): 0
      TAG_Long('RandomSeed'): 3142388825013346304L
      TAG_Int('SpawnX'): 0
      TAG_Int('SpawnZ'): 0
      TAG_Long('LastPlayed'): 1323133681772L
      TAG_Int('GameType'): 1
      TAG_Int('SpawnY'): 63
      TAG_Byte('MapFeatures'): 1
      TAG_Compound('Player'): 24 entries
      {
        TAG_Int('XpTotal'): 0
        TAG_Compound('abilities'): 4 entries
        {
          TAG_Byte('instabuild'): 1
          TAG_Byte('flying'): 1
          TAG_Byte('mayfly'): 1
          TAG_Byte('invulnerable'): 1
        }
        TAG_Int('XpLevel'): 0
        TAG_Int('Score'): 0
        TAG_Short('Health'): 20
        TAG_List('Inventory'): 13 entries
        {
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 1
            TAG_Byte('Slot'): 0
            TAG_Short('id'): 24
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 1
            TAG_Byte('Slot'): 1
            TAG_Short('id'): 25
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 1
            TAG_Byte('Slot'): 2
            TAG_Short('id'): 326
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 1
            TAG_Byte('Slot'): 3
            TAG_Short('id'): 29
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 10
            TAG_Byte('Slot'): 4
            TAG_Short('id'): 69
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 3
            TAG_Byte('Slot'): 5
            TAG_Short('id'): 33
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 43
            TAG_Byte('Slot'): 6
            TAG_Short('id'): 356
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 64
            TAG_Byte('Slot'): 7
            TAG_Short('id'): 331
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 20
            TAG_Byte('Slot'): 8
            TAG_Short('id'): 76
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 64
            TAG_Byte('Slot'): 9
            TAG_Short('id'): 331
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 1
            TAG_Byte('Slot'): 10
            TAG_Short('id'): 323
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 16
            TAG_Byte('Slot'): 11
            TAG_Short('id'): 331
            TAG_Short('Damage'): 0
          }
          TAG_Compound(None): 4 entries
          {
            TAG_Byte('Count'): 1
            TAG_Byte('Slot'): 12
            TAG_Short('id'): 110
            TAG_Short('Damage'): 0
          }
        }
        TAG_Short('HurtTime'): 0
        TAG_Short('Fire'): -20
        TAG_Float('foodExhaustionLevel'): 0.0
        TAG_Float('foodSaturationLevel'): 5.0
        TAG_Int('foodTickTimer'): 0
        TAG_Short('SleepTimer'): 0
        TAG_Short('DeathTime'): 0
        TAG_List('Rotation'): 2 entries
        {
          TAG_Float(None): 1151.9342041015625
          TAG_Float(None): 32.249679565429688
        }
        TAG_Float('XpP'): 0.0
        TAG_Float('FallDistance'): 0.0
        TAG_Short('Air'): 300
        TAG_List('Motion'): 3 entries
        {
          TAG_Double(None): -2.9778325794951344e-11
          TAG_Double(None): -0.078400001525878907
          TAG_Double(None): 1.1763942772801152e-11
        }
        TAG_Int('Dimension'): 0
        TAG_Byte('OnGround'): 1
        TAG_List('Pos'): 3 entries
        {
          TAG_Double(None): 256.87499499518492
          TAG_Double(None): 112.62000000476837
          TAG_Double(None): -34.578128612797634
        }
        TAG_Byte('Sleeping'): 0
        TAG_Short('AttackTime'): 0
        TAG_Int('foodLevel'): 20
      }
      TAG_Int('thunderTime'): 2724
      TAG_Int('version'): 19132
      TAG_Int('rainTime'): 5476
      TAG_Long('Time'): 128763
      TAG_Byte('thundering'): 1
      TAG_Byte('hardcore'): 0
      TAG_Long('SizeOnDisk'): 0
      TAG_String('LevelName'): 'Sandstone Test World'
    }
  }

Download