Crate fastnbt[][src]

Expand description

fastnbt aims for fast parsing of NBT data from Minecraft: Java Edition. This format is used by the game to store various things, such as the world data and player inventories.

  • For documentation and examples of serde deserialization, see de.
  • For a serde_json-like Value type see Value.
  • For NBT array types see ByteArray, IntArray, and LongArray.
  • For ‘zero-copy’ NBT array types see borrow.

Both this and related crates are under one fastnbt Github repository

[dependencies]
fastnbt = "1"

Byte, Int and Long array types

There are three array types in NBT. To capture these, use ByteArray, IntArray, and LongArray. These NBT types do not deserialize straight into serde sequences like Vec in order to preserve the information from the original NBT. Without these types, it is not possible to tell if some data came from a NBT List or an NBT Array.

Use these in your own data structures. They all implement Deref for dereferencing into the underlying Vec.

For versions that borrow their data, see borrow.

An example of deserializing a section of a chunk:

use fastnbt::LongArray;
use serde::Deserialize;

#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Section {
    pub block_states: Option<LongArray>,
    pub y: i8,
}

fn main(){
    let buf: &[u8] = unimplemented!("get a buffer from somewhere");
    let section: Section = fastnbt::de::from_bytes(buf).unwrap();
    let states = section.block_states.unwrap();

    for long in states.iter() {
        // do something
    }
}

Example: Player inventory

This example demonstrates printing out a players inventory and ender chest contents from the player dat files found in worlds.

Here we

  • use serde’s renaming attributes to have rustfmt conformant field names,
  • use lifetimes to save on some string allocations, and
  • use the Value type to deserialize a field we don’t know the exact structure of.
 use fastnbt::error::Result; use fastnbt::{de::from_bytes, Value}; use
 flate2::read::GzDecoder; use serde::Deserialize; use std::io::Read;

 #[derive(Deserialize, Debug)] #[serde(rename_all = "PascalCase")] struct
 PlayerDat<'a> {data_version: i32,

     #[serde(borrow)]
     inventory: Vec<InventorySlot<'a>>,
     ender_items: Vec<InventorySlot<'a>>,
 }

 #[derive(Deserialize, Debug)]
 struct InventorySlot<'a> {
     // We avoid allocating a string here.
     id: &'a str,

     // Also get the less structured properties of the object.
     tag: Option<Value>,

     // We need to rename fields a lot.
     #[serde(rename = "Count")]
     count: i8,
 }

 fn main() {
     let args: Vec<_> = std::env::args().skip(1).collect();
     let file = std::fs::File::open(args[0].clone()).unwrap();

     // Player dat files are compressed with GZip.
     let mut decoder = GzDecoder::new(file);
     let mut data = vec![];
     decoder.read_to_end(&mut data).unwrap();

     let player: Result<PlayerDat> = from_bytes(data.as_slice());

     println!("{:#?}", player);
 }

Read based parser

A lower level parser also exists in the stream module that only requires the Read trait on the input. This parser however doesn’t support deserializing to Rust objects directly.

Modules

This module contains types enabling ‘zero-copy’ capture of the array NBT types. These types retain a reference to the input data when deserializing, meaning the input has to live as long as the deserialized object. This can be hard to manage, but offers potential performance improvements. Measure! Usually the dominating factor in deserialization is decompressing the NBT data.

This module contains a serde deserializer. It can do most of the things you would expect of a typical serde deserializer, such as deserializing into:

Contains the Error and Result type used by the deserializer.

Allows streaming of NBT data without prior knowledge of the structure.

Structs

Enums

An NBT tag. This does not carry the value or the name of the data.

Value is a complete NBT value. It owns its data. Compounds and Lists are resursively deserialized. This type takes care to preserve all the information from the original NBT, with the exception of the name of the root compound (which is usually the empty string).