A C++ library for parsing, editing and serialising NBT data used in Java edition Minecraft.
I should warn you that this is not a finished library. Also I might rewrite it later but for now I stopped working on this
Currently the only docs are in tests/README.org
, I will be figuring out a way to generate a github.io soon probably.
That readme I mentioned is just a description of what tests do and I may get rid of it if that readme will prevent me from just rewriting the tests or changing my mind about which implementation seems more logical or intuituve.
All started with an idea to make a procedural world generator, but since minecraft uses the same format for all it’s files this became a general purpose parser for NBT.
In real use case just using this library is insufficient since it doesn’t handle compression which is present in almost all minecraft files. Thus you will need to use gzip
or zlib
for decompression purposes.
This library also doesn’t read data from the file directly and instead uses a custom implementation of stream to access data. This in my opinion is better than using fstream
since you can parse anything you really want and you are not restricted to compression type, position of the data in the file and the way you save/retrieve data from the file (FILE*
vs fstream
vs iostream
, etc). And there is a safeguard build into the stream implementation to prevent infinite recursion after you run out of data.
Currently the development has stopped and I am adding Google test to catch any bugs and I know there are many. After all the code is finished I will get to work on increasing performance and efficiency.
You must have basic knowledge of C++ and some understanding of NBT.
It is a CMake project so all you need is this line in the terminal:
# run this in the root of the project
$ cmake -S . -B build
You should see CMake build an object library and automatically run google test. There is no sample executable yet.
Quote from Web Archieve: NBT specification by Notch:
NBT (Named Binary Tag) is a tag based binary format designed to carry large amounts of binary data with smaller amounts of additional data. An NBT file consists of a single GZIPped Named Tag of type
TAG_Compound
.A Named Tag has the following format:
byte tagType TAG_String name [payload]
There were originally 10 data types, but since snapshot 12w07a, (release version 1.2.1)[fn:1] 2 more tags have beed added making 12 total. Here is a list of all the tags:
Name | ID |
---|---|
End of compoud | 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 |
Where: ID is byte tagType
from NBT specs above.
If you spend some time reading the specs by Notch you will soon realize that there are 4 categories (kinds) of NBT tags[fn:2]:
- Primitive
- A non-array type
- Byte
- Short
- Int
- Long
- Float
- Double
- String
- Array
- Mono-type non-recusrive array container
- Byte Array
- Int Array
- Long Array
- List
- Potentially[fn:3] recursive and multi-type array container
- Compound
- Multitype potentially recursive container
Attempting to create an object of invalid tag (e.g. ArrayTag<unsigned int>
instead of signed version) will result in undefined reference to [Kind]Tag::type()
.
[fn:1] Minecraft Wiki: Anvil file format.
[fn:2]End tag is excluded from the list since it is useless and dangerous to keep in memory as a class
or struct
, except for one case (list of end tags) where it is useless as a separate type either.
[fn:3] ListTag<ListTag<...> >
is totally possible and in fact is part of minecraft files.
Even though the nested ListTag
has a defined type, that type is undefined at a parent level (well, it is defined, but it’s a list, which is ambigious).
The above makes ListTag
recursive and multitype.