/* * This file is free for everyone to use under the Creative Commons Zero license. */ /** * The Named Binary Tag (NBT) data format. * *
NBT is a simple data structure format used in Minecraft's in-game data * serialization. Data stored on disks, modified by commands, and transported * via packets are usually in this format. In most cases, NBT is not * the runtime form of data; data are instead written to Java * class fields using Java types, and during serialization (as part of saving * or network transportation) or modification by commands, the code will write * the fields to NBT data. NBT data is also known as "NBT element". * *
There are 13 NBT element types, as shown below. Each NBT type has its own class, * and a {@link NbtType} instance used during deserialization in the {@code TYPE} * static field. They also have the "numeric ID" used during serialization and at * {@link NbtCompound#getList(String, int)} method. The ID of the element's type can * be obtained via the {@link NbtElement#getType()} method. There is also a special * ID, {@link NbtElement#NUMBER_TYPE}, which indicates the read value * can be any of the six numeric types; this cannot be used as the list's held type. * *
Class | *Numeric ID | *Immutable? | *Default | *Description | *
---|---|---|---|---|
{@link NbtEnd} |
* {@value NbtElement#END_TYPE} | *Yes | *(none) | *Internal type used during serialization, should not be used directly | *
{@link NbtByte} | *{@value NbtElement#BYTE_TYPE} | *Yes | *{@code 0} | *Corresponds to {@code byte} | *
{@link NbtShort} | *{@value NbtElement#SHORT_TYPE} | *Yes | *{@code 0} | *Corresponds to {@code short} | *
{@link NbtInt} | *{@value NbtElement#INT_TYPE} | *Yes | *{@code 0} | *Corresponds to {@code int} | *
{@link NbtLong} | *{@value NbtElement#LONG_TYPE} | *Yes | *{@code 0L} | *Corresponds to {@code long} | *
{@link NbtFloat} | *{@value NbtElement#FLOAT_TYPE} | *Yes | *{@code 0.0f} | *Corresponds to {@code float} | *
{@link NbtDouble} | *{@value NbtElement#DOUBLE_TYPE} | *Yes | *{@code 0.0} | *Corresponds to {@code double} | *
{@link NbtByteArray} | *{@value NbtElement#BYTE_ARRAY_TYPE} | *No | *Empty array | *Corresponds to {@code byte[]} | *
{@link NbtString} | *{@value NbtElement#STRING_TYPE} | *Yes | *{@code ""} | *Corresponds to {@link String} | *
{@link NbtList} | *{@value NbtElement#LIST_TYPE} | *No | *Empty list | *List of NBT elements with the same type | *
{@link NbtCompound} | *{@value NbtElement#COMPOUND_TYPE} | *No | *Empty compound | *Hash map-like object with string keys that can store any NBT elements | *
{@link NbtIntArray} |
* {@value NbtElement#INT_ARRAY_TYPE} | *No | *Empty array | *Corresponds to {@code int[]} | *
{@link NbtLongArray} | *{@value NbtElement#LONG_ARRAY_TYPE} | *No | *Empty array | *Corresponds to {@code long[]} | *
NbtEnd is a special sentinel used to indicate the end of lists and compounds. * This is also used as the type of empty lists. * *
NBT offers 6 numeric types (4 for integers and 2 for decimals), all corresponding * to Java equivalents. There is no unsigned type or {@code char} equivalent. These * inherit {@link AbstractNbtNumber}. To create an instance of these, use the {@code of} * static method, and to obtain the value as the Java primitive value, use the * {@code typeValue()} method. * *
{@code * NbtInt nbt = NbtInt.of(100); * int value = nbt.intValue(); * }* *
One thing to note here is that NBT lacks the boolean type; instead {@link NbtByte} * is used when boolean values are needed. See also {@link NbtByte#of(boolean)} method. * *
There are 3 typed arrays in NBT: {@link NbtByteArray}, {@link NbtIntArray}, and * {@link NbtLongArray}. There are no array types for shorts, floats or doubles. While they * are arrays internally, they also support {@linkplain AbstractNbtList#add adding items} * at runtime. Like Java arrays, out of bounds access is forbidden and will throw * {@link ArrayIndexOutOfBoundsException}. * *
NbtList is a list of a specific type of NBT elements. Empty lists always have the type * set as {@link NbtEnd}. {@link NbtList#add} throws when the type is incompatible, while * {@link NbtList#addElement} does nothing and returns {@code false} in that case. * There are type-specific getters which can be used to get the value. They return the default * value when type mismatch occurs or when the index is out of bounds. Note that they do not * cast the value at all. * *
{@code * NbtList list = new NbtList(); * list.addElement(0, NbtFloat.of(0.5f)); * float firstItem = list.getFloat(0); // 0.5f * float secondItem = list.getFloat(1); // 0.0f (default value) * double firstItemDouble = list.getDouble(0); // 0.0 (no casting) * list.addElement(1, NbtDouble.of(1.0)); // returns false, does nothing * list.add(NbtDouble.of(2.0)); // throws UnsupportedOperationException * }* *
NbtCompound is a hash map-like key-value storage object. It also acts as the root * object for serialized NBTs. The keys are always strings, while the values can be of * any type, and multiple value types can be mixed in a single compound. The order of items * is not guaranteed. There are generic {@link NbtCompound#put} and {@link NbtCompound#get} * methods, and there also exist type-specific getters and putters. Like the list getters * mentioned above, they return the default value when the key is missing or type mismatch * occurs. However, unlike lists, they attempt to cast numeric values. * *
{@code * NbtCompound compound = new NbtCompound(); * compound.put("Awesomeness", NbtInt.of(90)); * * // Don't do this! This will crash if the type is incompatible, * // even if they can be casted! * NbtInt awesomenessNbt = (NbtInt)compound.get("Awesomeness"); * * compound.putLong("Awesomeness", 100L); * int awesomeness = compound.getInt("Awesomeness"); // 100 (after casting) * int evilness = compound.getInt("Evilness"); // 0 (default value) * * // Shortcuts for getting and putting a boolean value * // (internally represented as a byte) * compound.putBoolean("Awesome", true); * boolean awesome = compound.getBoolean("Awesome"); * compound.put("awesome", NbtDouble.of(1.0)); // key is case-sensitive * }* *
As noted before, NBT is a serialized format, not runtime format. * Unrecognized custom data stored inside NBT will be lost once the game loads it and saves. * Therefore, modifying NBT is usually not the solution for attaching custom data to * objects like entities. For this purpose it is recommended to use third-party APIs * or use Mixin to add a field to the class. * *
With that said, here is how to use NBT in the vanilla code: * *
Methods named {@code readNbt} will read the values from the element, modifying * the current instance. Static methods named {@code fromNbt} will create a new instance * of the class with values from the element. Methods named {@code writeNbt} will add * the NBT data to the passed element. Methods named {@code toNbt} will create and return * a new element with the data. * *
There are several helper classes for NBTs: *
NBT compounds can also be transported using {@link * net.minecraft.network.PacketByteBuf#writeNbt} and {@link * net.minecraft.network.PacketByteBuf#readNbt}. */ package net.minecraft.nbt;