Skip to content
forked from Querz/NBT

A java implementation of the NBT protocol, including a way to implement custom tags.

License

Notifications You must be signed in to change notification settings

BlueMap-Minecraft/NBT

Repository files navigation

NBT

Build Status Coverage Status Release

A java implementation of the NBT protocol, including a way to implement custom tags.


Specification

According to the specification, there are currently 13 different types of tags:

Tag class Superclass ID Payload
EndTag Tag 0 None
ByteTag NumberTag 1 1 byte / 8 bits, signed
ShortTag NumberTag 2 2 bytes / 16 bits, signed, big endian
IntTag NumberTag 3 4 bytes / 32 bits, signed, big endian
LongTag NumberTag 4 8 bytes / 64 bits, signed, big endian
FloatTag NumberTag 5 4 bytes / 32 bits, signed, big endian, IEEE 754-2008, binary32
DoubleTag NumberTag 6 8 bytes / 64 bits, signed, big endian, IEEE 754-2008, binary64
ByteArrayTag ArrayTag 7 IntTag payload size, then size ByteTag payloads
StringTag Tag 8 ShortTag payload length, then a UTF-8 string with size length
ListTag Tag 9 ByteTag payload tagId, then IntTag payload size, then size tags' payloads, all of type tagId
CompoundTag Tag 10 Fully formed tags, followed by an EndTag
IntArrayTag ArrayTag 11 IntTag payload size, then size IntTag payloads
LongArrayTag ArrayTag 12 IntTag payload size, then size LongTag payloads
  • The EndTag is only used to mark the end of a CompoundTag in its serialized state or an empty ListTag.

  • The maximum depth of the NBT structure is 512. If the depth exceeds this restriction during serialization, deserialization or String conversion, a MaxDepthReachedException is thrown. This usually happens when a circular reference exists in the NBT structure. The NBT specification does not allow circular references, as there is no tag to represent this.


Example usage:

The following code snippet shows how to create a CompoundTag:

CompoundTag ct = new CompoundTag();

ct.put("byte", new ByteTag((byte) 1));
ct.put("double", new DoubleTag(1.234));
ct.putString("string", "stringValue");

An example how to use a ListTag:

ListTag<FloatTag> fl = new ListTag<>(FloatTag.class);

fl.add(new FloatTag(1.234f);
fl.addFloat(5.678f);

Utility

There are several utility methods to make your life easier if you use this library.

NBTUtil

NBTUtil.writeTag() lets you write a Tag into a gzip compressed or uncompressed file in one line (not counting exception handling). Files are gzip compressed by default.

Example usage:

NBTUtil.writeTag(tag, "filename.dat");

NBTUtil.readTag() reads any file containing NBT data. No worry about compression, it will automatically uncompress gzip compressed files.

Example usage:

Tag<?> tag = NBTUtil.readTag("filename.dat");

Playing Minecraft?

Each tag can be converted into a JSON-like NBT String used in Minecraft commands.

Example usage:

CompoundTag c = new CompoundTag();
c.putByte("blah", (byte) 5);
c.putString("foo", "bär");
System.out.println(c.toTagString()); // {blah:5b,foo:"bär"}

ListTag<StringTag> s = new ListTag<>(StringTag.class);
s.addString("test");
s.add(new StringTag("text"));
c.add("list", s);
System.out.println(c.toTagString()); // {blah:5b,foo:"bär",list:[test,text]}

There is also a tool to read, change and write MCA files.

Here are some examples:

// This changes the InhabitedTime field of the chunk at x=68, z=81 to 0
MCAFile mcaFile = MCAUtil.readMCAFile("r.2.2.mca");
Chunk chunk = mcaFile.getChunk(68, 81);
chunk.setInhabitedTime(0);
MCAUtil.writeMCAFile("r.2.2.mca", mcaFile);

There is also an optimized api to retrieve and set block information (BlockStates) in MCA files.

Example:

// Retrieves block information from the MCA file
CompoundTag blockState = mcaFile.getBlockStateAt(1090, 25, 1301);

// Retrieves block information from a single chunk
CompoundTag blockState = chunk.getBlockStateAt(2, 25, 5);

// Set block information
CompoundTag stone = new CompoundTag();
stone.putString("Name", "minecraft:stone");
mcaFile.setBlockStateAt(1090, 25, 1301, stone, false);

To ensure good performance even when setting a lot of blocks and / or editing sections with a huge palette of block states, the size of the BlockStates array is only updated when the size of the palette requires it. This means there might be blocks in the palette that are not actually used in the BlockStates array. You can trigger a cleanup process by calling one of the following three methods, depending on the desired depth:

mcaFile.cleanupPalettesAndBlockStates();
chunk.cleanupPalettesAndBlockStates();
section.cleanupPaletteAndBlockStates();

Custom tags

Interested in more advanced features, and the default NBT protocol just isn't enough? Simply create your own tags! There are 4 example classes in net.querz.nbt.custom that show how to implement custom tags:

Class ID Description
ObjectTag 90 A wrapper tag that serializes and deserializes any object using the default java serialization.
ShortArrayTag 100 In addition to the already existing ByteArrayTag, IntArrayTag and LongArrayTag.
CharTag 110 Character (char) tag.
StructTag 120 Similar to the ListTag, but with the ability to store multiple types.

To be able to use a custom tag with deserialization, a Supplier and the custom tag class must be registered at runtime alongside its id with TagFactory.registerCustomTag(). The Supplier can be anything that returns a new instance of this custom tag. Here is an example using the custom tags no-args constructor:

TagFactory.registerCustomTag(90, ObjectTag::new, ObjectTag.class);

About

A java implementation of the NBT protocol, including a way to implement custom tags.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Java 100.0%