10 个版本
0.2.9 | 2024 年 3 月 19 日 |
---|---|
0.2.8 | 2023 年 6 月 2 日 |
0.2.7 | 2023 年 4 月 26 日 |
0.2.6 | 2022 年 2 月 27 日 |
0.1.0 |
|
#387 在 编码
303 每月下载量
用于 3 crates
230KB
5.5K SLoC
quartz_nbt
支持对 Minecraft 的 NBT 格式进行编码和解码。该软件包支持 zlib 和 gz 压缩,并提供将 NBT 数据转换为字符串化 NBT (SNBT) 及反之的工具。
这是 Quartz 的独立 NBT 软件包,Quartz 是一个 Rust 实现的 Minecraft 服务器。
用法
查看这里的文档以获取示例。
lib.rs
:
支持对 Minecraft 的 NBT 格式进行编码和解码。该软件包支持 zlib 和 gz 压缩,并提供将 NBT 数据转换为字符串化 NBT (SNBT) 及反之的工具。
基本用法
NBT 数据的基本单位是 NbtTag
。较大的数据结构通过 NBT 标签的树状复合(哈希映射)和列表(向量)表示。
创建 NBT 数据
let mut compound = NbtCompound::new();
compound.insert("foo", 123);
compound.insert("bar", -3.6f32);
let mut list = NbtList::with_capacity(3);
(1i64..=3).for_each(|x| list.push(x));
compound.insert("list", list);
*compound.get_mut::<_, &mut i32>("foo").unwrap() += 1;
assert!(matches!(compound.get::<_, i32>("foo"), Ok(124)));
assert!(compound.get::<_, f64>("bar").is_err());
assert!(compound.get::<_, &NbtTag>("list").is_ok());
读取和写入 NBT
use quartz_nbt::io::{self, Flavor};
use std::io::Cursor;
let mut compound = NbtCompound::new();
compound.insert("foo", 123);
compound.insert("bar", -3.6f32);
let mut binary: Vec<u8> = Vec::new();
io::write_nbt(&mut binary, Some("root-tag"), &compound, Flavor::Uncompressed);
let read_compound = io::read_nbt(&mut Cursor::new(binary), Flavor::Uncompressed).unwrap();
assert_eq!(read_compound.1, "root-tag"); // The root tag's name is generally unused
assert_eq!(read_compound.0, compound);
查询标签
使用泛型使标签查询过程尽可能无缝,但这也允许发生两种类型的错误:缺少标签(无效键或索引)和标签类型不匹配。因此,在 std
集合等效中通常返回 Option
的方法在此软件包中返回 Result
。
直接将NBT标签转换为未包装值的错误通过TryFrom
和TryInto
表示,由NbtStructureError
表示。查询NbtCompound
或NbtList
的错误由NbtReprError
表示,其缩写为“NBT表示错误”。有关详细信息,请参阅错误的文档。
use std::convert::TryFrom;
let tag1: NbtTag = vec![1i8, 2, 3].into();
let tag2: NbtTag = "abcde".into();
assert_eq!(Vec::<i8>::try_from(tag1).unwrap(), vec![1i8, 2, 3]);
assert!(i16::try_from(tag2).is_err()); // Type mismatch
let mut compound = NbtCompound::new();
compound.insert("foo", 123);
compound.insert("bar", -3.6f32);
assert!(compound.get::<_, i32>("fooz").is_err()); // Missing tag
assert!(compound.get::<_, i32>("bar").is_err()); // Type mismatch
集合类型和迭代
NbtCompound
和NbtList
类型分别围绕Map
和Vec
进行包装。由于NbtTag
隐藏了实际存储的数据类型,这些包装器提供了将标签解包到具体类型的实用工具。如果需要更多功能,则可以通过调用inner
、inner_mut
和/或into_inner
来访问这些包装器管理的内部集合。
列表
Minecraft的NBT规范目前对数组(或Rust中的Vec
)有特殊的标签,用于存储i8
、i32
和i64
。因此,这些类型的vec可以直接转换为NbtTag
。所有其他NBT兼容类型必须存储在NbtList
中。
可以通过常规查询获取上述特殊列表类型。
let mut compound = NbtCompound::new();
compound.insert("list", vec![10i32, 20, 30]);
compound.get_mut::<_, &mut [i32]>("list")
.unwrap()
.iter_mut()
.for_each(|x| *x /= 10);
let list = compound.get::<_, &[i32]>("list");
assert!(list.is_ok());
assert_eq!(list.unwrap(), [1i32, 2, 3].as_ref());
为NBT列表提供了迭代解包值的实用方法。请参阅iter_map
和iter_mut_map
。
let mut list = NbtList::new();
list.push("abc");
list.push("ijk");
list.push("xyz");
list.iter_mut_map::<&mut String>()
.for_each(|s| s.unwrap().push('!'));
let mut iter = list.iter_map::<&str>();
assert!(matches!(iter.next(), Some(Ok("abc!"))));
assert!(matches!(iter.next(), Some(Ok("ijk!"))));
assert!(matches!(iter.next(), Some(Ok("xyz!"))));
assert!(matches!(iter.next(), None));
可以通过clone_from
从迭代器(或将转换为迭代器的任何内容)中克隆数据来创建NBT列表。
let mut list1 = NbtList::new();
list1.push("abc");
list1.push("ijk");
list1.push("xyz");
let list2 = NbtList::clone_from(&["abc", "ijk", "xyz"]);
assert_eq!(list1, list2);
化合物
NbtCompound
具有与NbtList
相同的实用函数集,除了使用字符串键而不是索引之外。与列表类似,化合物具有iter_map
和iter_mut_map
实用函数,以及clone_from
构造函数。有关更多详细信息,请参阅文档。
字符串化NBT (SNBT)
Minecraft还包含一个名为SNBT的NBT数据字符串编码。此编码基本上是JSON的扩展,具有更严格的类型和更宽松的字符串引号规则。有关更多详细信息,请参阅snbt
模块文档。
use quartz_nbt::snbt;
let tag: NbtTag = vec![10i8, 15, 20].into();
assert_eq!(tag.to_snbt(), "[B;10,15,20]");
let mut compound = NbtCompound::new();
compound.insert("short", -10i16);
compound.insert("string", "fizzbuzz");
compound.insert("array", vec![1i64, 1, 2, 3, 5]);
const SNBT: &str = "{short: -10s, string: fizzbuzz, array: [L; 1, 1, 2, 3, 5]}";
assert_eq!(compound, snbt::parse(SNBT).unwrap());
依赖项
~1.7–2.3MB
~49K SLoC