/* * 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". * *

Types

*

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. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NBT types
ClassNumeric IDImmutable?DefaultDescription
{@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}NoEmpty arrayCorresponds to {@code byte[]}
{@link NbtString}{@value NbtElement#STRING_TYPE}Yes{@code ""}Corresponds to {@link String}
{@link NbtList}{@value NbtElement#LIST_TYPE}NoEmpty listList of NBT elements with the same type
{@link NbtCompound}{@value NbtElement#COMPOUND_TYPE}NoEmpty compoundHash map-like object with string keys that can store any NBT elements
{@link NbtIntArray}
{@value NbtElement#INT_ARRAY_TYPE}NoEmpty arrayCorresponds to {@code int[]}
{@link NbtLongArray}{@value NbtElement#LONG_ARRAY_TYPE}NoEmpty arrayCorresponds to {@code long[]}
* *

{@link NbtEnd}

*

NbtEnd is a special sentinel used to indicate the end of lists and compounds. * This is also used as the type of empty lists. * *

Numeric types

*

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. * *

NBT typed arrays

*

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}. * *

{@link NbtList}

*

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
 * }
* *

{@link NbtCompound}

*

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
 * }
* *

Using NBT

*

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;