mirror of https://github.com/FabricMC/yarn.git
239 lines
9.8 KiB
Java
239 lines
9.8 KiB
Java
/*
|
|
* This file is free for everyone to use under the Creative Commons Zero license.
|
|
*/
|
|
|
|
/**
|
|
* The Named Binary Tag (NBT) data format.
|
|
*
|
|
* <p>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 <strong>not
|
|
* the runtime form of data</strong>; 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".
|
|
*
|
|
* <h2 id=types>Types</h2>
|
|
* <p>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 <strong>read value</strong>
|
|
* can be any of the six numeric types; this cannot be used as the list's held type.
|
|
*
|
|
* <table>
|
|
* <caption>NBT types</caption>
|
|
* <thead>
|
|
* <tr>
|
|
* <th>Class</th>
|
|
* <th>Numeric ID</th>
|
|
* <th>Immutable?</th>
|
|
* <th>Default</th>
|
|
* <th>Description</th>
|
|
* </tr>
|
|
* </thead>
|
|
* <tbody>
|
|
* <tr>
|
|
* <td>{@link NbtEnd}<br></td>
|
|
* <td>{@value NbtElement#END_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>(none)</td>
|
|
* <td>Internal type used during serialization, should not be used directly</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtByte}</td>
|
|
* <td>{@value NbtElement#BYTE_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code 0}</td>
|
|
* <td>Corresponds to {@code byte}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtShort}</td>
|
|
* <td>{@value NbtElement#SHORT_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code 0}</td>
|
|
* <td>Corresponds to {@code short}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtInt}</td>
|
|
* <td>{@value NbtElement#INT_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code 0}</td>
|
|
* <td>Corresponds to {@code int}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtLong}</td>
|
|
* <td>{@value NbtElement#LONG_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code 0L}</td>
|
|
* <td>Corresponds to {@code long}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtFloat}</td>
|
|
* <td>{@value NbtElement#FLOAT_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code 0.0f}</td>
|
|
* <td>Corresponds to {@code float}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtDouble}</td>
|
|
* <td>{@value NbtElement#DOUBLE_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code 0.0}</td>
|
|
* <td>Corresponds to {@code double}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtByteArray}</td>
|
|
* <td>{@value NbtElement#BYTE_ARRAY_TYPE}</td>
|
|
* <td>No</td>
|
|
* <td>Empty array</td>
|
|
* <td>Corresponds to {@code byte[]}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtString}</td>
|
|
* <td>{@value NbtElement#STRING_TYPE}</td>
|
|
* <td>Yes</td>
|
|
* <td>{@code ""}</td>
|
|
* <td>Corresponds to {@link String}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtList}</td>
|
|
* <td>{@value NbtElement#LIST_TYPE}</td>
|
|
* <td>No</td>
|
|
* <td>Empty list</td>
|
|
* <td>List of NBT elements with the same type</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtCompound}</td>
|
|
* <td>{@value NbtElement#COMPOUND_TYPE}</td>
|
|
* <td>No</td>
|
|
* <td>Empty compound</td>
|
|
* <td>Hash map-like object with string keys that can store any NBT elements</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtIntArray}<br></td>
|
|
* <td>{@value NbtElement#INT_ARRAY_TYPE}</td>
|
|
* <td>No</td>
|
|
* <td>Empty array</td>
|
|
* <td>Corresponds to {@code int[]}</td>
|
|
* </tr>
|
|
* <tr>
|
|
* <td>{@link NbtLongArray}</td>
|
|
* <td>{@value NbtElement#LONG_ARRAY_TYPE}</td>
|
|
* <td>No</td>
|
|
* <td>Empty array</td>
|
|
* <td>Corresponds to {@code long[]}</td>
|
|
* </tr>
|
|
* </tbody>
|
|
* </table>
|
|
*
|
|
* <h3 id=nbt-end>{@link NbtEnd}</h3>
|
|
* <p>NbtEnd is a special sentinel used to indicate the end of lists and compounds.
|
|
* This is also used as the type of empty lists.
|
|
*
|
|
* <h3 id=numeric-types>Numeric types</h3>
|
|
* <p>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.
|
|
*
|
|
* <pre>{@code
|
|
* NbtInt nbt = NbtInt.of(100);
|
|
* int value = nbt.intValue();
|
|
* }</pre>
|
|
*
|
|
* <p>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.
|
|
*
|
|
* <h3 id=nbt-typed-array>NBT typed arrays</h3>
|
|
* <p>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}.
|
|
*
|
|
* <h3 id=nbt-list>{@link NbtList}</h3>
|
|
* <p>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.
|
|
*
|
|
* <pre>{@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
|
|
* }</pre>
|
|
*
|
|
* <h3 id=nbt-compound>{@link NbtCompound}</h3>
|
|
* <p>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.
|
|
*
|
|
* <pre>{@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
|
|
* }</pre>
|
|
*
|
|
* <h2 id=using-nbt>Using NBT</h2>
|
|
* <p>As noted before, NBT is a <strong>serialized format, not runtime format</strong>.
|
|
* 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.
|
|
*
|
|
* <p>With that said, here is how to use NBT in the vanilla code:
|
|
*
|
|
* <p>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.
|
|
*
|
|
* <p>There are several helper classes for NBTs:
|
|
* <ul>
|
|
* <li>{@link NbtHelper} contains methods for reading and writing game profiles, block
|
|
* states, UUIDs, and block positions. It also contains a method for comparing elements.</li>
|
|
* <li>{@link NbtIo} contains methods for reading and writing NBT compounds on a file.</li>
|
|
* <li>{@link NbtOps} is the class defining interactions with the DataFixerUpper library.
|
|
* The library abstracts operations between data formats (such as JSON or NBT) using "ops".
|
|
* Use {@link NbtOps#INSTANCE} to decode the NBT data using DataFixerUpper.</li>
|
|
* <li>{@link StringNbtReader} reads the stringified NBT (SNBT) and converts to NBT.</li>
|
|
* <li>{@link net.minecraft.nbt.visitor.NbtElementVisitor} and its subclasses allow converting
|
|
* NBT elements to string or {@link net.minecraft.text.Text}.</li>
|
|
* <li>{@link net.minecraft.nbt.scanner.NbtScanner} scans the NBT data without reading the
|
|
* whole data at once, allowing efficient decoding when only parts of the data are needed.</li>
|
|
* </ul>
|
|
*
|
|
* <p>NBT compounds can also be transported using {@link
|
|
* net.minecraft.network.PacketByteBuf#writeNbt} and {@link
|
|
* net.minecraft.network.PacketByteBuf#readNbt}.
|
|
*/
|
|
|
|
package net.minecraft.nbt;
|