anvil-nbt

Crates.ioanvil-nbt
lib.rsanvil-nbt
version0.2.0
created_at2026-01-20 19:13:40.958801+00
updated_at2026-01-22 14:42:51.264574+00
descriptionA Rust library for parsing and encoding Minecraft's NBT and Anvil (.mca) formats.
homepagehttps://github.com/driedpampas/anvil-nbt
repositoryhttps://github.com/driedpampas/anvil-nbt
max_upload_size
id2057319
size136,551
supernova (driedpampas)

documentation

README

anvil-nbt

Docs License

A Rust library for parsing and encoding Minecraft's NBT and Anvil (.mca) formats.

Built for world editors, servers, and tools that need reliable access to Minecraft world data.

Features

  • High Performance: Manual byte-level parsing for maximum speed (no parser combinator overhead)
  • Lazy Loading: Memory-mapped Anvil region files via memmap2 load only the chunks you need
  • Full NBT Support: Handles all tag types, including Modified UTF-8 (MUTF-8) strings
  • Optional Serde Support: Serialize/Deserialize Rust structs directly to/from NBT via the serde feature
  • Bit-Perfect Round-trips: Idempotent parsers and encoders preserve data exactly
  • Compression Support: Built-in Gzip and Zlib compression handling via flate2
  • CLI Utility: Includes mc-inspect for inspecting world files from the terminal

Installation

Add this to your Cargo.toml:

[dependencies]
anvil-nbt = "0.1.0"

Quick Start

Reading a level.dat (Gzipped NBT)

use anvil_nbt::nbt::parse::parse_named_tag;
use flate2::read::GzDecoder;
use std::fs::File;
use std::io::Read;

fn main() -> anyhow::Result<()> {
    let file = File::open("level.dat")?;
    let mut decoder = GzDecoder::new(file);
    let mut data = Vec::new();
    decoder.read_to_end(&mut data)?;

    let mut input = &data[..];
    let (name, tag) = parse_named_tag::<nom::error::Error<&[u8]>>(&mut input)
        .map_err(|e| anyhow::anyhow!("Parse error: {:?}", e))?;

    println!("Root tag name: {}", name);
    println!("{:#?}", tag);
    Ok(())
}

Accessing an Anvil Region File

use anvil_nbt::anvil::access::Region;

fn main() -> anyhow::Result<()> {
    let region = Region::open("r.0.0.mca")?;
    
    // Get chunk at (5, 10) within this region
    if let Some((name, tag)) = region.get_chunk_nbt(5, 10)? {
        println!("Chunk (5,10) root: {}", name);
        // Do something with the NBT data!
    }
    
    Ok(())
}

Serde Support (Optional)

Enable the serde feature to serialize and deserialize Rust structs:

anvil-nbt = { version = "0.1.2", features = ["serde"] }
use anvil_nbt::nbt::serde_impl::{to_nbt, from_nbt};
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
struct PlayerData {
    name: String,
    health: f32,
    inventory: Vec<String>,
}

fn main() -> anyhow::Result<()> {
    let player = PlayerData {
        name: "Steve".to_owned(),
        health: 20.0,
        inventory: vec!["Sword".to_owned(), "Bread".to_owned()],
    };

    // Convert to NbtTag
    let tag = to_nbt(&player)?;
    
    // Convert back to struct
    let decoded: PlayerData = from_nbt(tag)?;
    Ok(())
}

CLI Utility: mc-inspect

Inspect Minecraft files directly from your terminal:

# Install the CLI tool
cargo install --path .

# Inspect a level.dat file
mc-inspect nbt level.dat

# Peek at a specific chunk in an Anvil file
mc-inspect anvil r.0.0.mca -x 5 -z 10

License

This project is licensed under the GPL-3.0-or-later License - see the LICENSE file for details.

Commit count: 9

cargo fmt