4 releases
Uses new Rust 2024
| 0.2.0 | Jan 22, 2026 |
|---|---|
| 0.1.2 | Jan 21, 2026 |
| 0.1.1 | Jan 20, 2026 |
| 0.1.0 | Jan 20, 2026 |
#984 in Parser implementations
57KB
1K
SLoC
anvil-nbt
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
memmap2load 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
serdefeature - 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-inspectfor 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.
Dependencies
~2–3MB
~55K SLoC