更新shen-nbt5版本到0.2.0,修复了一些bug,添加了对Java版本的支持。

This commit is contained in:
shenjack 2024-03-10 12:26:34 +08:00
parent 6eda5a38fe
commit bf6a390eb7
Signed by: shenjack
GPG Key ID: 7B1134A979775551
5 changed files with 160 additions and 80 deletions

View File

@ -19,6 +19,14 @@
- 数据都是小端序 - 数据都是小端序
- 根节点必须有名称 - 根节点必须有名称
- 根节点是 `NbtCompound(10)` 或者 `NbtList(9)` 类型 - 根节点是 `NbtCompound(10)` 或者 `NbtList(9)` 类型
- ```text
与Java版本使用的big-endian格式相同但所有数字都以little-endian编码。
这包括标记名称和TAG_String值之前的16位长度前缀以及TAG_Float和TAG_Double值。
---- https://wiki.vg/NBT
```
- `BedrockNetVarInt` - `BedrockNetVarInt`
- 基岩版用于网络传输的 NBT 格式 - 基岩版用于网络传输的 NBT 格式
@ -33,7 +41,6 @@
---- https://wiki.vg/NBT ---- https://wiki.vg/NBT
``` ```
writen in rust! writen in rust!
## 感谢 ## 感谢

View File

@ -1,6 +1,6 @@
[package] [package]
name = "shen-nbt5" name = "shen-nbt5"
version = "0.1.0" version = "0.2.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -28,9 +28,14 @@ pub mod nbt_version {
use super::{NbtReader, NbtResult, NbtValue}; use super::{NbtReader, NbtResult, NbtValue};
pub trait NbtReadTrait { pub trait NbtReadTrait {
fn from_reader(reader: NbtReader) -> NbtResult<NbtValue>; fn read_i8_array(reader: &mut NbtReader) -> NbtResult<Vec<i8>>;
fn read_i32_array(reader: &mut NbtReader) -> NbtResult<Vec<i32>>;
fn read_i64_array(reader: &mut NbtReader) -> NbtResult<Vec<i64>>;
fn read_nbt_string(reader: &mut NbtReader) -> NbtResult<String>;
fn read_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>>; fn read_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>>;
fn read_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>>; fn read_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>>;
fn from_reader(reader: NbtReader) -> NbtResult<NbtValue>;
} }
/// Java 版 绝大部分的 NBT 格式 /// Java 版 绝大部分的 NBT 格式
/// ///
@ -179,75 +184,10 @@ pub enum NbtValue {
impl NbtValue { impl NbtValue {
pub fn from_binary<T>(data: &mut [u8]) -> NbtResult<NbtValue> pub fn from_binary<T>(data: &mut [u8]) -> NbtResult<NbtValue>
where T: nbt_version::NbtReadTrait { where
T: nbt_version::NbtReadTrait,
{
let reader = NbtReader::new(data); let reader = NbtReader::new(data);
T::from_reader(reader) T::from_reader(reader)
} }
// fn read_nbt_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>> {
// let mut compound = Vec::with_capacity(10);
// loop {
// let tag_id = reader.read_u8();
// if tag_id == 0 {
// break;
// }
// let name = reader.read_nbt_string()?;
// let value = match tag_id {
// 1 => NbtValue::Byte(reader.read_i8()),
// 2 => NbtValue::Short(reader.read_be_i16()),
// 3 => NbtValue::Int(reader.read_be_i32()),
// 4 => NbtValue::Long(reader.read_be_i64()),
// 5 => NbtValue::Float(reader.read_be_f32()),
// 6 => NbtValue::Double(reader.read_be_f64()),
// 7 => NbtValue::ByteArray(reader.read_nbt_i8_array()),
// 8 => NbtValue::String(reader.read_nbt_string()?),
// 9 => NbtValue::List(NbtValue::read_nbt_list(reader)?),
// 10 => NbtValue::Compound(None, NbtValue::read_nbt_compound(reader)?),
// 11 => NbtValue::IntArray(reader.read_nbt_i32_array()),
// 12 => NbtValue::LongArray(reader.read_nbt_i64_array()),
// _ => unimplemented!(),
// };
// compound.push((name, value));
// }
// Ok(compound)
// }
// fn read_nbt_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>> {
// let type_id = reader.read_u8();
// let len = reader.read_be_i32() as usize;
// let mut list = Vec::with_capacity(len);
// for _ in 0..len {
// let value = match type_id {
// 1 => NbtValue::Byte(reader.read_i8()),
// 2 => NbtValue::Short(reader.read_be_i16()),
// 3 => NbtValue::Int(reader.read_be_i32()),
// 4 => NbtValue::Long(reader.read_be_i64()),
// 5 => NbtValue::Float(reader.read_be_f32()),
// 6 => NbtValue::Double(reader.read_be_f64()),
// 7 => NbtValue::ByteArray(reader.read_nbt_i8_array()),
// 8 => NbtValue::String(reader.read_nbt_string()?),
// 9 => NbtValue::List(NbtValue::read_nbt_list(reader)?),
// 10 => NbtValue::Compound(None, NbtValue::read_nbt_compound(reader)?),
// 11 => NbtValue::IntArray(reader.read_nbt_i32_array()),
// 12 => NbtValue::LongArray(reader.read_nbt_i64_array()),
// _ => unimplemented!(),
// };
// list.push(value);
// }
// Ok(list)
// }
// pub fn from_reader(mut reader: NbtReader) -> NbtValue {
// // 第一个 tag, 不可能是 0
// match reader.read_u8() {
// 9 => NbtValue::List(NbtValue::read_nbt_list(&mut reader).unwrap()),
// 10 => {
// let name = reader.read_nbt_string().unwrap();
// NbtValue::Compound(Some(name), NbtValue::read_nbt_compound(&mut reader).unwrap())
// }
// x => {
// panic!("根节点类型错误 {}", x.as_nbt_type_name());
// }
// }
// }
} }

View File

@ -1,5 +1,5 @@
use crate::nbt_version; use crate::nbt_version::{BedrockDisk, BedrockNetVarInt, Java, JavaNetAfter1_20_2, NbtReadTrait};
use crate::{NbtError, NbtResult, NbtValue}; use crate::{nbt_version, NbtError, NbtResult, NbtValue};
/// 用于读取 NBT 数据 /// 用于读取 NBT 数据
pub struct NbtReader<'data> { pub struct NbtReader<'data> {
@ -17,11 +17,143 @@ pub struct NbtReader<'data> {
/// ///
/// 上面说的那玩意 请使用 `JavaNetAfter1_20_2` /// 上面说的那玩意 请使用 `JavaNetAfter1_20_2`
impl nbt_version::NbtReadTrait for nbt_version::Java { impl nbt_version::NbtReadTrait for nbt_version::Java {
fn from_reader(reader: NbtReader) -> NbtResult<NbtValue> { todo!() } #[inline]
fn read_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>> { todo!() } fn read_nbt_string(reader: &mut NbtReader) -> NbtResult<String> {
fn read_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>> { todo!() } let len = reader.read_be_u16() as usize;
reader.read_string(len)
}
#[inline]
fn read_i8_array(reader: &mut NbtReader) -> NbtResult<Vec<i8>> {
let len = reader.read_be_i32() as usize;
let value = reader.read_i8_array(len);
Ok(value)
}
#[inline]
fn read_i32_array(reader: &mut NbtReader) -> NbtResult<Vec<i32>> {
let len = reader.read_be_i32() as usize;
let value = reader.read_i32_array(len);
Ok(value)
}
#[inline]
fn read_i64_array(reader: &mut NbtReader) -> NbtResult<Vec<i64>> {
let len = reader.read_be_i32() as usize;
let value = reader.read_i64_array(len);
Ok(value)
}
#[inline]
fn read_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>> {
let mut compound = Vec::with_capacity(10);
loop {
let tag_id = reader.read_u8();
if tag_id == 0 {
break;
}
let name = Java::read_nbt_string(reader)?;
let value = match tag_id {
1 => NbtValue::Byte(reader.read_i8()),
2 => NbtValue::Short(reader.read_be_i16()),
3 => NbtValue::Int(reader.read_be_i32()),
4 => NbtValue::Long(reader.read_be_i64()),
5 => NbtValue::Float(reader.read_be_f32()),
6 => NbtValue::Double(reader.read_be_f64()),
7 => NbtValue::ByteArray(Java::read_i8_array(reader)?),
8 => NbtValue::String(Java::read_nbt_string(reader)?),
9 => NbtValue::List(Java::read_list(reader)?),
10 => NbtValue::Compound(None, nbt_version::Java::read_compound(reader)?),
11 => NbtValue::IntArray(Java::read_i32_array(reader)?),
12 => NbtValue::LongArray(Java::read_i64_array(reader)?),
_ => unimplemented!(),
};
compound.push((name, value));
}
Ok(compound)
}
#[inline]
fn read_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>> {
let type_id = reader.read_u8();
let len = reader.read_be_i32() as usize;
let mut list = Vec::with_capacity(len);
for _ in 0..len {
let value = match type_id {
1 => NbtValue::Byte(reader.read_i8()),
2 => NbtValue::Short(reader.read_be_i16()),
3 => NbtValue::Int(reader.read_be_i32()),
4 => NbtValue::Long(reader.read_be_i64()),
5 => NbtValue::Float(reader.read_be_f32()),
6 => NbtValue::Double(reader.read_be_f64()),
7 => NbtValue::ByteArray(Java::read_i8_array(reader)?),
8 => NbtValue::String(Java::read_nbt_string(reader)?),
9 => NbtValue::List(Java::read_list(reader)?),
10 => NbtValue::Compound(None, nbt_version::Java::read_compound(reader)?),
11 => NbtValue::IntArray(Java::read_i32_array(reader)?),
12 => NbtValue::LongArray(Java::read_i64_array(reader)?),
_ => unimplemented!(),
};
list.push(value);
}
Ok(list)
}
fn from_reader(mut reader: NbtReader) -> NbtResult<NbtValue> {
// 第一个 tag, 不可能是 0
match reader.read_u8() {
10 => {
let name = Java::read_nbt_string(&mut reader)?;
Ok(NbtValue::Compound(Some(name), nbt_version::Java::read_compound(&mut reader)?))
}
x => Err(NbtError::WrongRootType(x)),
}
}
} }
/// 两个最好实现的就在这里了
///
/// 网络 NBT: 1.20.2+ 的网络 NBT 根节点没有名字
impl NbtReadTrait for JavaNetAfter1_20_2 {
#[inline]
fn read_nbt_string(reader: &mut NbtReader) -> NbtResult<String> {
Java::read_nbt_string(reader)
}
#[inline]
fn read_i8_array(reader: &mut NbtReader) -> NbtResult<Vec<i8>> { Java::read_i8_array(reader) }
#[inline]
fn read_i32_array(reader: &mut NbtReader) -> NbtResult<Vec<i32>> {
Java::read_i32_array(reader)
}
#[inline]
fn read_i64_array(reader: &mut NbtReader) -> NbtResult<Vec<i64>> {
Java::read_i64_array(reader)
}
#[inline]
fn read_compound(reader: &mut NbtReader) -> NbtResult<Vec<(String, NbtValue)>> {
Java::read_compound(reader)
}
#[inline]
fn read_list(reader: &mut NbtReader) -> NbtResult<Vec<NbtValue>> { Java::read_list(reader) }
fn from_reader(mut reader: NbtReader) -> NbtResult<NbtValue> {
// 第一个 tag, 不可能是 0
match reader.read_u8() {
10 => {
// Java 1.20.2+ 的网络 NBT 没有名字
Ok(NbtValue::Compound(None, nbt_version::Java::read_compound(&mut reader)?))
}
x => Err(NbtError::WrongRootType(x)),
}
}
}
/// 基岩版的其实也还行, 就是有点麻烦
///
/// 所有都是小端
// impl NbtReadTrait for BedrockDisk {
// #[inline]
// fn read_nbt_string(reader: &mut NbtReader) -> NbtResult<String> {
// let len = reader.read_le_u16() as usize;
// reader.read_string(len)
// }
// }
macro_rules! read_uncheck { macro_rules! read_uncheck {
($be_name:ident, $le_name:ident, $ty:ty, $size:literal) => { ($be_name:ident, $le_name:ident, $ty:ty, $size:literal) => {
#[doc = concat!("读取 ", stringify!($ty), " 类型 ", $size, " 长度的数据")] #[doc = concat!("读取 ", stringify!($ty), " 类型 ", $size, " 长度的数据")]

View File

@ -1,4 +1,4 @@
use crate::{NbtReader, NbtTypeConversion, NbtValue, nbt_version}; use crate::{nbt_version, NbtReader, NbtTypeConversion, NbtValue};
/// 生成测试数据 /// 生成测试数据
pub fn gen_datas(len: usize) -> Vec<u8> { pub fn gen_datas(len: usize) -> Vec<u8> {
@ -303,7 +303,7 @@ mod nbt {
#[test] #[test]
fn big_test() { fn big_test() {
let mut data: [u8; 0x608] = [ let data: [u8; 0x608] = [
0x0A, 0x00, 0x05, 0x4C, 0x65, 0x76, 0x65, 0x6C, 0x04, 0x00, 0x08, 0x6C, 0x6F, 0x6E, 0x0A, 0x00, 0x05, 0x4C, 0x65, 0x76, 0x65, 0x6C, 0x04, 0x00, 0x08, 0x6C, 0x6F, 0x6E,
0x67, 0x54, 0x65, 0x73, 0x74, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02, 0x67, 0x54, 0x65, 0x73, 0x74, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x02,
0x00, 0x09, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x54, 0x65, 0x73, 0x74, 0x7F, 0xFF, 0x08, 0x00, 0x09, 0x73, 0x68, 0x6F, 0x72, 0x74, 0x54, 0x65, 0x73, 0x74, 0x7F, 0xFF, 0x08,
@ -416,7 +416,8 @@ mod nbt {
0x6F, 0x75, 0x62, 0x6C, 0x65, 0x54, 0x65, 0x73, 0x74, 0x3F, 0xDF, 0x8F, 0x6B, 0xBB, 0x6F, 0x75, 0x62, 0x6C, 0x65, 0x54, 0x65, 0x73, 0x74, 0x3F, 0xDF, 0x8F, 0x6B, 0xBB,
0xFF, 0x6A, 0x5E, 0x00, 0xFF, 0x6A, 0x5E, 0x00,
]; ];
let value = NbtValue::from_binary::<nbt_version::Java>(&mut data); let value = NbtValue::from_binary::<nbt_version::Java>(&mut data.clone());
println!("{:?}", value); println!("{:?}", value);
// 其他版本
} }
} }