-
Notifications
You must be signed in to change notification settings - Fork 9
Reading
SharpNBT is capable of reading multiple flavors or NBT (see Protocols page), but it will need a minimal amount of information ahead of time to know about the source data to know how it should be interpreted.
The TagReader
class is the heart and soul of parsing a data stream. It only requires a base Stream
object and flag indicating the data type to begin parsing.
using Stream stream = File.OpenRead("/path/to/file.nbt");
using TagReader reader = new TagReader(stream, FormatOptions.BigEndian);
Once created, you are ready to start parsing. For the majority of users, there is only one method that is pertinent: ReadTag
and its asynchronous counterpart ReadTagAsync
. This will read the next tag in the stream, which will in nearly all cases be a CompoundTag
, with the sole exception of Bedrock editions occasionally using a ListTag
. Both of these types share the common ancestor TagContainer
, so it is always safe to cast the top-level tag to this type regardless of Minecraft version. When using Java-compatible data, it is always safe to assume the top-level tag is a CompoundTag
.
TagContainer topLevel = (TagContainer) reader.ReadTag();
The above function return a generic Tag
instance, but if the tag type is known ahead of time, you can use the shorthand read function to return it as the proper type.
CompoundTag compoundTag = reader.ReadTag<CompoundTag>();
CompoundTag compoundTag = await reader.ReadTagAsync<CompoundTag>();
There are numerous other methods available for reading each individual type of tag, but is very important to keep in mind the difference in where the current pointer in the stream is positioned. Using ReadTag
assumes that the first byte indicating the type is still unread, while the individual tag read methods (i.e. ReadByteArray
, ReadList
, etc.) assume that the first byte has already been consumed and the pointer is positioned at the beginning of the payload. Keep this mind if you decide to inject any functionality into the parsing process through the use of callbacks or manual parsing.
There are two callback events that are available for subscribers: TagRead
and TagEncountered
.
Called whenever the TagReader
has completed parsing a tag from the stream. The parsed Tag
and TagType
are supplied in the arguments.
Called when a tag is encountered in the stream, after only reading the first byte to determine the type. The arguments provide properties for the TagType
and the underlying Stream
itself. These arguments derive from HandledEventArgs
, and give an opportunity for subscribers to fully take over the parsing process if needed. The only important guideline to follow is that the stream needs to be properly positioned depending on whether the tag was handled or not. When not handled, the stream position should not be moved, and when it is handled, the tag payload should be completely consumed.
Compression is not handled by the TagReader
class, it is the responsibility of higher-level abstractions to pass in the proper decompression stream during initialization. As the TagReader
is designed to be able to read from non-seekable streams (i.e. packets over a network stream), it is unable to assume that it is positioned at the start of a stream or attempt to detect compression.
The static NbtFile
class provides various methods for simplifying reading NBT files into a single invocation, including automatically detecting and handling compression.
CompoundTag tag = NbtFile.Read("/path/to/file.nbt", FormatOptions.Java);
As with other relevant methods in SharpNBT, there is an asynchronous counterpart:
var compoundTag = await NbtFile.ReadAsync("/path/to/file.nbt", FormatOptions.Java);
That's all there is to it, essentially the analog of the File.ReadAllText
function found in System.IO
, but for NBT data instead of text. If you wish to retrieve the data as a TagReader
instance, but not consume the stream, the OpenRead
function is also available:
using TagReader reader = NbtFile.OpenRead("/path/to/file.nbt", FormatOptions.BedrockFile);