Minecraft NBT (Named Binary Tag): Python (read-write) parsing library

A structured binary format native to Minecraft for saving game data and transferring it over the network (in multiplayer), such as player data (<player>.dat; contains e.g. player's inventory and location), saved worlds (level.dat and Chunk format), list of saved multiplayer servers (servers.dat) and so on - see https://minecraft.wiki/w/NBT_format#Uses.

The entire file should be gzip-compressed (in accordance with the original specification NBT.txt by Notch), but can also be compressed with zlib or uncompressed.

This spec can only handle uncompressed NBT data, so be sure to first detect what type of data you are dealing with. You can use the Unix file command to do this (file-5.20 or later is required; older versions do not recognize zlib-compressed data and return application/octet-stream instead):

file --brief --mime-type input-unknown.nbt

If it says:

  • application/x-gzip or application/gzip (since file-5.37), you can decompress it by
    • gunzip -c input-gzip.nbt > output.nbt or
    • python3 -c "import sys, gzip; sys.stdout.buffer.write( gzip.decompress(sys.stdin.buffer.read()) )" < input-gzip.nbt > output.nbt
  • application/zlib, you can use
    • openssl zlib -d -in input-zlib.nbt -out output.nbt (does not work on most systems)
    • python3 -c "import sys, zlib; sys.stdout.buffer.write( zlib.decompress(sys.stdin.buffer.read()) )" < input-zlib.nbt > output.nbt
  • something else (especially image/x-pcx and application/octet-stream), it is most likely already uncompressed.

The file output.nbt generated by one of the above commands can already be processed with this Kaitai Struct specification.

This spec only implements the Java edition format. There is also a Bedrock edition NBT format, which uses little-endian encoding and has a few other differences, but it isn't as popular as the Java edition format.

Implementation note: strings in TAG_String are incorrectly decoded with standard UTF-8, while they are encoded in Modified UTF-8 (MUTF-8). That's because MUTF-8 is not supported natively by most target languages, and thus one must use external libraries to achieve a fully-compliant decoder. But decoding in standard UTF-8 is still better than nothing, and it usually works fine.

All Unicode code points with incompatible representations in MUTF-8 and UTF-8 are U+0000 (NUL), U+D800-U+DFFF (High and Low Surrogates) and U+10000-U+10FFFF (all Supplementary Planes; includes e.g. emoticons, pictograms). A MUTF-8-encoded string containing these code points cannot be successfully decoded as UTF-8. The behavior in this case depends on the target language - usually an exception is thrown, or the bytes that are not valid UTF-8 are replaced or ignored.

Sample files:

Application

Minecraft

File extension

["nbt", "dat", "schematic", "schem"]

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of Minecraft NBT (Named Binary Tag) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Python (read-write) source code to parse Minecraft NBT (Named Binary Tag)

minecraft_nbt.py

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
# type: ignore

import kaitaistruct
from kaitaistruct import ReadWriteKaitaiStruct, KaitaiStream, BytesIO
from enum import IntEnum


if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11):
    raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__))

class MinecraftNbt(ReadWriteKaitaiStruct):
    """A structured binary format native to Minecraft for saving game data and transferring
    it over the network (in multiplayer), such as player data
    ([`<player>.dat`](https://minecraft.wiki/w/Player.dat_format); contains
    e.g. player's inventory and location), saved worlds
    ([`level.dat`](
      https://minecraft.wiki/w/Java_Edition_level_format#level.dat_format
    ) and [Chunk format](https://minecraft.wiki/w/Chunk_format#NBT_structure)),
    list of saved multiplayer servers
    ([`servers.dat`](https://minecraft.wiki/w/Servers.dat_format)) and so on -
    see <https://minecraft.wiki/w/NBT_format#Uses>.
    
    The entire file should be _gzip_-compressed (in accordance with the original
    specification [NBT.txt](
      https://web.archive.org/web/20110723210920/https://www.minecraft.net/docs/NBT.txt
    ) by Notch), but can also be compressed with _zlib_ or uncompressed.
    
    This spec can only handle uncompressed NBT data, so be sure to first detect
    what type of data you are dealing with. You can use the Unix `file` command
    to do this (`file-5.20` or later is required; older versions do not recognize
    _zlib_-compressed data and return `application/octet-stream` instead):
    
    ```shell
    file --brief --mime-type input-unknown.nbt
    ```
    
    If it says:
    
      * `application/x-gzip` or `application/gzip` (since `file-5.37`), you can decompress it by
        * `gunzip -c input-gzip.nbt > output.nbt` or
        * `python3 -c "import sys, gzip; sys.stdout.buffer.write(
          gzip.decompress(sys.stdin.buffer.read()) )" < input-gzip.nbt > output.nbt`
      * `application/zlib`, you can use
        * `openssl zlib -d -in input-zlib.nbt -out output.nbt` (does not work on most systems)
        * `python3 -c "import sys, zlib; sys.stdout.buffer.write(
          zlib.decompress(sys.stdin.buffer.read()) )" < input-zlib.nbt > output.nbt`
      * something else (especially `image/x-pcx` and `application/octet-stream`),
        it is most likely already uncompressed.
    
    The file `output.nbt` generated by one of the above commands can already be
    processed with this Kaitai Struct specification.
    
    This spec **only** implements the Java edition format. There is also
    a [Bedrock edition](https://wiki.vg/NBT#Bedrock_edition) NBT format,
    which uses little-endian encoding and has a few other differences, but it isn't
    as popular as the Java edition format.
    
    **Implementation note:** strings in `TAG_String` are incorrectly decoded with
    standard UTF-8, while they are encoded in [**Modified UTF-8**](
      https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8
    ) (MUTF-8). That's because MUTF-8 is not supported natively by most target
    languages, and thus one must use external libraries to achieve a fully-compliant
    decoder. But decoding in standard UTF-8 is still better than nothing, and
    it usually works fine.
    
    All Unicode code points with incompatible representations in MUTF-8 and UTF-8 are
    U+0000 (_NUL_), U+D800-U+DFFF (_High_ and _Low Surrogates_) and U+10000-U+10FFFF
    (all _Supplementary_ Planes; includes e.g. emoticons, pictograms).
    A _MUTF-8_-encoded string containing these code points cannot be successfully
    decoded as UTF-8. The behavior in this case depends on the target language -
    usually an exception is thrown, or the bytes that are not valid UTF-8
    are replaced or ignored.
    
    **Sample files:**
    
      * <https://wiki.vg/NBT#Download>
      * <https://github.com/twoolie/NBT/blob/f9e892e/tests/world_test/data/scoreboard.dat>
      * <https://github.com/chmod222/cNBT/tree/3f74b69/testdata>
      * <https://github.com/PistonDevelopers/hematite_nbt/tree/0b85f89/tests>
    
    .. seealso::
       Source - https://wiki.vg/NBT
    
    
    .. seealso::
       Source - https://web.archive.org/web/20110723210920/https://www.minecraft.net/docs/NBT.txt
    
    
    .. seealso::
       Source - https://minecraft.wiki/w/NBT_format
    """

    class Tag(IntEnum):
        end = 0
        byte = 1
        short = 2
        int = 3
        long = 4
        float = 5
        double = 6
        byte_array = 7
        string = 8
        list = 9
        compound = 10
        int_array = 11
        long_array = 12
    def __init__(self, _io=None, _parent=None, _root=None):
        super(MinecraftNbt, self).__init__(_io)
        self._parent = _parent
        self._root = _root or self
        self._should_write_root_type = False
        self.root_type__enabled = True

    def _read(self):
        if  ((self.root_type == MinecraftNbt.Tag.end) and (False)) :
            pass
            self.root_check = self._io.read_bytes(0)

        self.root = MinecraftNbt.NamedTag(self._io, self, self._root)
        self.root._read()
        self._dirty = False


    def _fetch_instances(self):
        pass
        if  ((self.root_type == MinecraftNbt.Tag.end) and (False)) :
            pass

        self.root._fetch_instances()
        _ = self.root_type
        if hasattr(self, '_m_root_type'):
            pass



    def _write__seq(self, io=None):
        super(MinecraftNbt, self)._write__seq(io)
        self._should_write_root_type = self.root_type__enabled
        if  ((self.root_type == MinecraftNbt.Tag.end) and (False)) :
            pass
            if len(self.root_check) != 0:
                raise kaitaistruct.ConsistencyError(u"root_check", 0, len(self.root_check))
            self._io.write_bytes(self.root_check)

        self.root._write__seq(self._io)


    def _check(self):
        if self.root._root != self._root:
            raise kaitaistruct.ConsistencyError(u"root", self._root, self.root._root)
        if self.root._parent != self:
            raise kaitaistruct.ConsistencyError(u"root", self, self.root._parent)
        if self.root_type__enabled:
            pass
            if not self._m_root_type == MinecraftNbt.Tag.compound:
                raise kaitaistruct.ValidationNotEqualError(MinecraftNbt.Tag.compound, self._m_root_type, None, u"/instances/root_type")

        self._dirty = False

    class NamedTag(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.NamedTag, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.type = KaitaiStream.resolve_enum(MinecraftNbt.Tag, self._io.read_u1())
            if (not (self.is_tag_end)):
                pass
                self.name = MinecraftNbt.TagString(self._io, self, self._root)
                self.name._read()

            if (not (self.is_tag_end)):
                pass
                _on = self.type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                    self.payload = self._io.read_s1()
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    self.payload = MinecraftNbt.TagByteArray(self._io, self, self._root)
                    self.payload._read()
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    self.payload = MinecraftNbt.TagCompound(self._io, self, self._root)
                    self.payload._read()
                elif _on == MinecraftNbt.Tag.double:
                    pass
                    self.payload = self._io.read_f8be()
                elif _on == MinecraftNbt.Tag.float:
                    pass
                    self.payload = self._io.read_f4be()
                elif _on == MinecraftNbt.Tag.int:
                    pass
                    self.payload = self._io.read_s4be()
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    self.payload = MinecraftNbt.TagIntArray(self._io, self, self._root)
                    self.payload._read()
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    self.payload = MinecraftNbt.TagList(self._io, self, self._root)
                    self.payload._read()
                elif _on == MinecraftNbt.Tag.long:
                    pass
                    self.payload = self._io.read_s8be()
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    self.payload = MinecraftNbt.TagLongArray(self._io, self, self._root)
                    self.payload._read()
                elif _on == MinecraftNbt.Tag.short:
                    pass
                    self.payload = self._io.read_s2be()
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    self.payload = MinecraftNbt.TagString(self._io, self, self._root)
                    self.payload._read()

            self._dirty = False


        def _fetch_instances(self):
            pass
            if (not (self.is_tag_end)):
                pass
                self.name._fetch_instances()

            if (not (self.is_tag_end)):
                pass
                _on = self.type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    self.payload._fetch_instances()
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    self.payload._fetch_instances()
                elif _on == MinecraftNbt.Tag.double:
                    pass
                elif _on == MinecraftNbt.Tag.float:
                    pass
                elif _on == MinecraftNbt.Tag.int:
                    pass
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    self.payload._fetch_instances()
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    self.payload._fetch_instances()
                elif _on == MinecraftNbt.Tag.long:
                    pass
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    self.payload._fetch_instances()
                elif _on == MinecraftNbt.Tag.short:
                    pass
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    self.payload._fetch_instances()



        def _write__seq(self, io=None):
            super(MinecraftNbt.NamedTag, self)._write__seq(io)
            self._io.write_u1(int(self.type))
            if (not (self.is_tag_end)):
                pass
                self.name._write__seq(self._io)

            if (not (self.is_tag_end)):
                pass
                _on = self.type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                    self._io.write_s1(self.payload)
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    self.payload._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    self.payload._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.double:
                    pass
                    self._io.write_f8be(self.payload)
                elif _on == MinecraftNbt.Tag.float:
                    pass
                    self._io.write_f4be(self.payload)
                elif _on == MinecraftNbt.Tag.int:
                    pass
                    self._io.write_s4be(self.payload)
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    self.payload._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    self.payload._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.long:
                    pass
                    self._io.write_s8be(self.payload)
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    self.payload._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.short:
                    pass
                    self._io.write_s2be(self.payload)
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    self.payload._write__seq(self._io)



        def _check(self):
            if (not (self.is_tag_end)):
                pass
                if self.name._root != self._root:
                    raise kaitaistruct.ConsistencyError(u"name", self._root, self.name._root)
                if self.name._parent != self:
                    raise kaitaistruct.ConsistencyError(u"name", self, self.name._parent)

            if (not (self.is_tag_end)):
                pass
                _on = self.type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    if self.payload._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"payload", self._root, self.payload._root)
                    if self.payload._parent != self:
                        raise kaitaistruct.ConsistencyError(u"payload", self, self.payload._parent)
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    if self.payload._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"payload", self._root, self.payload._root)
                    if self.payload._parent != self:
                        raise kaitaistruct.ConsistencyError(u"payload", self, self.payload._parent)
                elif _on == MinecraftNbt.Tag.double:
                    pass
                elif _on == MinecraftNbt.Tag.float:
                    pass
                elif _on == MinecraftNbt.Tag.int:
                    pass
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    if self.payload._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"payload", self._root, self.payload._root)
                    if self.payload._parent != self:
                        raise kaitaistruct.ConsistencyError(u"payload", self, self.payload._parent)
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    if self.payload._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"payload", self._root, self.payload._root)
                    if self.payload._parent != self:
                        raise kaitaistruct.ConsistencyError(u"payload", self, self.payload._parent)
                elif _on == MinecraftNbt.Tag.long:
                    pass
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    if self.payload._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"payload", self._root, self.payload._root)
                    if self.payload._parent != self:
                        raise kaitaistruct.ConsistencyError(u"payload", self, self.payload._parent)
                elif _on == MinecraftNbt.Tag.short:
                    pass
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    if self.payload._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"payload", self._root, self.payload._root)
                    if self.payload._parent != self:
                        raise kaitaistruct.ConsistencyError(u"payload", self, self.payload._parent)

            self._dirty = False

        @property
        def is_tag_end(self):
            if hasattr(self, '_m_is_tag_end'):
                return self._m_is_tag_end

            self._m_is_tag_end = self.type == MinecraftNbt.Tag.end
            return getattr(self, '_m_is_tag_end', None)

        def _invalidate_is_tag_end(self):
            del self._m_is_tag_end

    class TagByteArray(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.TagByteArray, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.len_data = self._io.read_s4be()
            self.data = self._io.read_bytes(self.len_data)
            self._dirty = False


        def _fetch_instances(self):
            pass


        def _write__seq(self, io=None):
            super(MinecraftNbt.TagByteArray, self)._write__seq(io)
            self._io.write_s4be(self.len_data)
            self._io.write_bytes(self.data)


        def _check(self):
            if len(self.data) != self.len_data:
                raise kaitaistruct.ConsistencyError(u"data", self.len_data, len(self.data))
            self._dirty = False


    class TagCompound(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.TagCompound, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.tags = []
            i = 0
            while True:
                _t_tags = MinecraftNbt.NamedTag(self._io, self, self._root)
                try:
                    _t_tags._read()
                finally:
                    _ = _t_tags
                    self.tags.append(_)
                if _.is_tag_end:
                    break
                i += 1
            self._dirty = False


        def _fetch_instances(self):
            pass
            for i in range(len(self.tags)):
                pass
                self.tags[i]._fetch_instances()



        def _write__seq(self, io=None):
            super(MinecraftNbt.TagCompound, self)._write__seq(io)
            for i in range(len(self.tags)):
                pass
                self.tags[i]._write__seq(self._io)



        def _check(self):
            if len(self.tags) == 0:
                raise kaitaistruct.ConsistencyError(u"tags", 0, len(self.tags))
            for i in range(len(self.tags)):
                pass
                if self.tags[i]._root != self._root:
                    raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                if self.tags[i]._parent != self:
                    raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)
                _ = self.tags[i]
                if _.is_tag_end != (i == len(self.tags) - 1):
                    raise kaitaistruct.ConsistencyError(u"tags", i == len(self.tags) - 1, _.is_tag_end)

            self._dirty = False

        @property
        def dump_num_tags(self):
            if hasattr(self, '_m_dump_num_tags'):
                return self._m_dump_num_tags

            self._m_dump_num_tags = len(self.tags) - (1 if  ((len(self.tags) >= 1) and (self.tags[-1].is_tag_end))  else 0)
            return getattr(self, '_m_dump_num_tags', None)

        def _invalidate_dump_num_tags(self):
            del self._m_dump_num_tags

    class TagIntArray(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.TagIntArray, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.num_tags = self._io.read_s4be()
            self.tags = []
            for i in range(self.num_tags):
                self.tags.append(self._io.read_s4be())

            self._dirty = False


        def _fetch_instances(self):
            pass
            for i in range(len(self.tags)):
                pass



        def _write__seq(self, io=None):
            super(MinecraftNbt.TagIntArray, self)._write__seq(io)
            self._io.write_s4be(self.num_tags)
            for i in range(len(self.tags)):
                pass
                self._io.write_s4be(self.tags[i])



        def _check(self):
            if len(self.tags) != self.num_tags:
                raise kaitaistruct.ConsistencyError(u"tags", self.num_tags, len(self.tags))
            for i in range(len(self.tags)):
                pass

            self._dirty = False

        @property
        def tags_type(self):
            if hasattr(self, '_m_tags_type'):
                return self._m_tags_type

            self._m_tags_type = MinecraftNbt.Tag.int
            return getattr(self, '_m_tags_type', None)

        def _invalidate_tags_type(self):
            del self._m_tags_type

    class TagList(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.TagList, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.tags_type = KaitaiStream.resolve_enum(MinecraftNbt.Tag, self._io.read_u1())
            self.num_tags = self._io.read_s4be()
            self.tags = []
            for i in range(self.num_tags):
                _on = self.tags_type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                    self.tags.append(self._io.read_s1())
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    _t_tags = MinecraftNbt.TagByteArray(self._io, self, self._root)
                    try:
                        _t_tags._read()
                    finally:
                        self.tags.append(_t_tags)
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    _t_tags = MinecraftNbt.TagCompound(self._io, self, self._root)
                    try:
                        _t_tags._read()
                    finally:
                        self.tags.append(_t_tags)
                elif _on == MinecraftNbt.Tag.double:
                    pass
                    self.tags.append(self._io.read_f8be())
                elif _on == MinecraftNbt.Tag.float:
                    pass
                    self.tags.append(self._io.read_f4be())
                elif _on == MinecraftNbt.Tag.int:
                    pass
                    self.tags.append(self._io.read_s4be())
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    _t_tags = MinecraftNbt.TagIntArray(self._io, self, self._root)
                    try:
                        _t_tags._read()
                    finally:
                        self.tags.append(_t_tags)
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    _t_tags = MinecraftNbt.TagList(self._io, self, self._root)
                    try:
                        _t_tags._read()
                    finally:
                        self.tags.append(_t_tags)
                elif _on == MinecraftNbt.Tag.long:
                    pass
                    self.tags.append(self._io.read_s8be())
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    _t_tags = MinecraftNbt.TagLongArray(self._io, self, self._root)
                    try:
                        _t_tags._read()
                    finally:
                        self.tags.append(_t_tags)
                elif _on == MinecraftNbt.Tag.short:
                    pass
                    self.tags.append(self._io.read_s2be())
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    _t_tags = MinecraftNbt.TagString(self._io, self, self._root)
                    try:
                        _t_tags._read()
                    finally:
                        self.tags.append(_t_tags)

            self._dirty = False


        def _fetch_instances(self):
            pass
            for i in range(len(self.tags)):
                pass
                _on = self.tags_type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    self.tags[i]._fetch_instances()
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    self.tags[i]._fetch_instances()
                elif _on == MinecraftNbt.Tag.double:
                    pass
                elif _on == MinecraftNbt.Tag.float:
                    pass
                elif _on == MinecraftNbt.Tag.int:
                    pass
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    self.tags[i]._fetch_instances()
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    self.tags[i]._fetch_instances()
                elif _on == MinecraftNbt.Tag.long:
                    pass
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    self.tags[i]._fetch_instances()
                elif _on == MinecraftNbt.Tag.short:
                    pass
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    self.tags[i]._fetch_instances()



        def _write__seq(self, io=None):
            super(MinecraftNbt.TagList, self)._write__seq(io)
            self._io.write_u1(int(self.tags_type))
            self._io.write_s4be(self.num_tags)
            for i in range(len(self.tags)):
                pass
                _on = self.tags_type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                    self._io.write_s1(self.tags[i])
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    self.tags[i]._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    self.tags[i]._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.double:
                    pass
                    self._io.write_f8be(self.tags[i])
                elif _on == MinecraftNbt.Tag.float:
                    pass
                    self._io.write_f4be(self.tags[i])
                elif _on == MinecraftNbt.Tag.int:
                    pass
                    self._io.write_s4be(self.tags[i])
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    self.tags[i]._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    self.tags[i]._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.long:
                    pass
                    self._io.write_s8be(self.tags[i])
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    self.tags[i]._write__seq(self._io)
                elif _on == MinecraftNbt.Tag.short:
                    pass
                    self._io.write_s2be(self.tags[i])
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    self.tags[i]._write__seq(self._io)



        def _check(self):
            if len(self.tags) != self.num_tags:
                raise kaitaistruct.ConsistencyError(u"tags", self.num_tags, len(self.tags))
            for i in range(len(self.tags)):
                pass
                _on = self.tags_type
                if _on == MinecraftNbt.Tag.byte:
                    pass
                elif _on == MinecraftNbt.Tag.byte_array:
                    pass
                    if self.tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                    if self.tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)
                elif _on == MinecraftNbt.Tag.compound:
                    pass
                    if self.tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                    if self.tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)
                elif _on == MinecraftNbt.Tag.double:
                    pass
                elif _on == MinecraftNbt.Tag.float:
                    pass
                elif _on == MinecraftNbt.Tag.int:
                    pass
                elif _on == MinecraftNbt.Tag.int_array:
                    pass
                    if self.tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                    if self.tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)
                elif _on == MinecraftNbt.Tag.list:
                    pass
                    if self.tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                    if self.tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)
                elif _on == MinecraftNbt.Tag.long:
                    pass
                elif _on == MinecraftNbt.Tag.long_array:
                    pass
                    if self.tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                    if self.tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)
                elif _on == MinecraftNbt.Tag.short:
                    pass
                elif _on == MinecraftNbt.Tag.string:
                    pass
                    if self.tags[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"tags", self._root, self.tags[i]._root)
                    if self.tags[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"tags", self, self.tags[i]._parent)

            self._dirty = False


    class TagLongArray(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.TagLongArray, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.num_tags = self._io.read_s4be()
            self.tags = []
            for i in range(self.num_tags):
                self.tags.append(self._io.read_s8be())

            self._dirty = False


        def _fetch_instances(self):
            pass
            for i in range(len(self.tags)):
                pass



        def _write__seq(self, io=None):
            super(MinecraftNbt.TagLongArray, self)._write__seq(io)
            self._io.write_s4be(self.num_tags)
            for i in range(len(self.tags)):
                pass
                self._io.write_s8be(self.tags[i])



        def _check(self):
            if len(self.tags) != self.num_tags:
                raise kaitaistruct.ConsistencyError(u"tags", self.num_tags, len(self.tags))
            for i in range(len(self.tags)):
                pass

            self._dirty = False

        @property
        def tags_type(self):
            if hasattr(self, '_m_tags_type'):
                return self._m_tags_type

            self._m_tags_type = MinecraftNbt.Tag.long
            return getattr(self, '_m_tags_type', None)

        def _invalidate_tags_type(self):
            del self._m_tags_type

    class TagString(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(MinecraftNbt.TagString, self).__init__(_io)
            self._parent = _parent
            self._root = _root

        def _read(self):
            self.len_data = self._io.read_u2be()
            self.data = (self._io.read_bytes(self.len_data)).decode(u"UTF-8")
            self._dirty = False


        def _fetch_instances(self):
            pass


        def _write__seq(self, io=None):
            super(MinecraftNbt.TagString, self)._write__seq(io)
            self._io.write_u2be(self.len_data)
            self._io.write_bytes((self.data).encode(u"UTF-8"))


        def _check(self):
            if len((self.data).encode(u"UTF-8")) != self.len_data:
                raise kaitaistruct.ConsistencyError(u"data", self.len_data, len((self.data).encode(u"UTF-8")))
            self._dirty = False


    @property
    def root_type(self):
        if self._should_write_root_type:
            self._write_root_type()
        if hasattr(self, '_m_root_type'):
            return self._m_root_type

        if not self.root_type__enabled:
            return None

        _pos = self._io.pos()
        self._io.seek(0)
        self._m_root_type = KaitaiStream.resolve_enum(MinecraftNbt.Tag, self._io.read_u1())
        if not self._m_root_type == MinecraftNbt.Tag.compound:
            raise kaitaistruct.ValidationNotEqualError(MinecraftNbt.Tag.compound, self._m_root_type, self._io, u"/instances/root_type")
        self._io.seek(_pos)
        return getattr(self, '_m_root_type', None)

    @root_type.setter
    def root_type(self, v):
        self._dirty = True
        self._m_root_type = v

    def _write_root_type(self):
        self._should_write_root_type = False
        _pos = self._io.pos()
        self._io.seek(0)
        self._io.write_u1(int(self._m_root_type))
        self._io.seek(_pos)