diff --git a/schemsearch-files/Cargo.toml b/schemsearch-files/Cargo.toml index 0a87157..8134d7e 100644 --- a/schemsearch-files/Cargo.toml +++ b/schemsearch-files/Cargo.toml @@ -7,5 +7,5 @@ edition = "2021" [dependencies] flate2 = "1.0.25" -hematite-nbt = "0.5.2" +named-binary-tag = "0.6" diff --git a/schemsearch-files/src/lib.rs b/schemsearch-files/src/lib.rs index 0fe2838..7ef964f 100644 --- a/schemsearch-files/src/lib.rs +++ b/schemsearch-files/src/lib.rs @@ -18,7 +18,7 @@ use std::collections::hash_map::HashMap; use std::io::Read; use std::path::PathBuf; -use nbt::Value; +use nbt::{CompoundTag, Tag}; #[derive(Clone, Debug)] pub enum SchematicVersioned { @@ -94,7 +94,7 @@ impl SchematicVersioned { #[derive(Clone, Debug)] pub struct SpongeV1Schematic { - pub metadata: HashMap, + pub metadata: CompoundTag, pub width: u16, pub height: u16, pub length: u16, @@ -108,7 +108,7 @@ pub struct SpongeV1Schematic { #[derive(Clone, Debug)] pub struct SpongeV2Schematic { pub data_version: i32, - pub metadata: HashMap, + pub metadata: CompoundTag, pub width: u16, pub height: u16, pub length: u16, @@ -123,7 +123,7 @@ pub struct SpongeV2Schematic { #[derive(Clone, Debug)] pub struct SpongeV3Schematic { pub data_version: i32, - pub metadata: HashMap, + pub metadata: CompoundTag, pub width: u16, pub height: u16, pub length: u16, @@ -149,7 +149,7 @@ pub struct BlockEntity { pub struct BlockEntityV3 { pub id: String, pub pos: [i32; 3], - pub data: HashMap, + pub data: HashMap, } #[derive(Debug, Clone)] @@ -159,17 +159,9 @@ pub struct Entity { } impl SchematicVersioned { - pub fn load_data(data: R) -> Result where R: Read { - let nbt: HashMap = nbt::de::from_gzip_reader(data).map_err(|e| e.to_string())?; - let version = match nbt.get("Version") { - Some(version) => match version { - Value::Short(n) => *n as i32, - Value::Byte(n) => *n as i32, - Value::Int(n) => *n, - _ => return Err("Invalid schematic: Wrong Version Type".to_string()), - }, - None => return Err("Invalid schematic: Version not Found".to_string()), - }; + pub fn load_data(data: &mut R) -> Result where R: Read { + let nbt: CompoundTag = nbt::decode::read_gzip_compound_tag(data).map_err(|e| e.to_string())?; + let version = nbt.get_i32("Version").map_err(|e| e.to_string())?; match version { 1 => Ok(SchematicVersioned::V1(SpongeV1Schematic::from_nbt(nbt)?)), @@ -180,212 +172,99 @@ impl SchematicVersioned { } pub fn load(path: &PathBuf) -> Result { - let file = std::fs::File::open(path).map_err(|e| e.to_string())?; - Self::load_data(file) + let mut file = std::fs::File::open(path).map_err(|e| e.to_string())?; + Self::load_data(&mut file) } } impl SpongeV1Schematic { - pub fn from_nbt(nbt: HashMap) -> Result { + pub fn from_nbt(nbt: CompoundTag) -> Result { Ok(Self { - metadata: match nbt.get("Metadata").ok_or("Invalid schematic: Metadata not found".to_string())? { - Value::Compound(metadata) => metadata.clone(), - _ => return Err("Invalid schematic: Metadata Wrong Type".to_string()), - }, - width: match nbt.get("Width").ok_or("Invalid schematic: Width not found".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic: Width Wrong Type".to_string()), - }, - height: match nbt.get("Height").ok_or("Invalid schematic: Height not found".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic: Height Wrong Type".to_string()), - }, - length: match nbt.get("Length").ok_or("Invalid schematic: Length not found".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic: Length Wrong Type".to_string()), - }, - offset: read_offset(nbt.get("Offset"))?, - palette_max: match nbt.get("PaletteMax").ok_or("Invalid schematic: PaletteMax not found".to_string())? { - Value::Int(p) => *p, - _ => return Err("Invalid schematic: PaletteMax Wrong Type".to_string()), - }, - palette: read_palette(nbt.get("Palette"))?, - block_data: read_blocks(nbt.get("BlockData"))?, - tile_entities: read_tile_entities(nbt.get("TileEntities"))?, + metadata: nbt.get_compound_tag("Metadata").map_err(|e| e.to_string())?.clone(), + width: nbt.get_i16("Width").map_err(|e| e.to_string())? as u16, + height: nbt.get_i16("Height").map_err(|e| e.to_string())? as u16, + length: nbt.get_i16("Length").map_err(|e| e.to_string())? as u16, + offset: read_offset(nbt.get_i32_vec("Offset").map_err(|e| e.to_string())?)?, + palette_max: nbt.get_i32("PaletteMax").map_err(|e| e.to_string())?, + palette: read_palette(nbt.get_compound_tag("Palette").map_err(|e| e.to_string())?), + block_data: read_blocks(nbt.get_i8_vec("BlockData").map_err(|e| e.to_string())?), + tile_entities: read_tile_entities(nbt.get_compound_tag_vec("TileEntities").map_err(|e| e.to_string())?)?, }) } } impl SpongeV2Schematic { - pub fn from_nbt(nbt: HashMap) -> Result { + pub fn from_nbt(nbt: CompoundTag) -> Result { Ok(Self{ - data_version: match nbt.get("DataVersion").ok_or("Invalid schematic: DataVersion Missing".to_string())? { - Value::Short(n) => *n as i32, - Value::Byte(n) => *n as i32, - Value::Int(n) => *n, - _ => return Err("Invalid schematic: DataVersion Wrong Type".to_string()), - }, - metadata: match nbt.get("Metadata").ok_or("Invalid schematic".to_string())? { - Value::Compound(m) => m.clone(), - _ => return Err("Invalid schematic: Metadata Wrong Type".to_string()), - }, - width: match nbt.get("Width").ok_or("Invalid schematic".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic: Width Wrong Type".to_string()), - }, - height: match nbt.get("Height").ok_or("Invalid schematic".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic: Height Wrong Type".to_string()), - }, - length: match nbt.get("Length").ok_or("Invalid schematic".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic: Length Wrong Type".to_string()), - }, - offset: read_offset(nbt.get("Offset"))?, - palette_max: match nbt.get("PaletteMax").ok_or("Invalid schematic: PaletteMax Missing".to_string())? { - Value::Short(n) => *n as i32, - Value::Byte(n) => *n as i32, - Value::Int(n) => *n, - _ => return Err("Invalid schematic: PaletteMax Invalid Type".to_string()), - }, - palette: read_palette(nbt.get("Palette"))?, - block_data: read_blocks(nbt.get("BlockData"))?, - block_entities: read_tile_entities(nbt.get("BlockEntities"))?, + data_version: nbt.get_i32("DataVersion").map_err(|e| e.to_string())?, + metadata: nbt.get_compound_tag("Metadata").map_err(|e| e.to_string())?.clone(), + width: nbt.get_i16("Width").map_err(|e| e.to_string())? as u16, + height: nbt.get_i16("Height").map_err(|e| e.to_string())? as u16, + length: nbt.get_i16("Length").map_err(|e| e.to_string())? as u16, + offset: read_offset(nbt.get_i32_vec("Offset").map_err(|e| e.to_string())?)?, + palette_max: nbt.get_i32("PaletteMax").map_err(|e| e.to_string())?, + palette: read_palette(nbt.get_compound_tag("Palette").map_err(|e| e.to_string())?), + block_data: read_blocks(nbt.get_i8_vec("BlockData").map_err(|e| e.to_string())?), + block_entities: read_tile_entities(nbt.get_compound_tag_vec("BlockEntities").map_err(|e| e.to_string())?)?, entities: None, }) } } impl SpongeV3Schematic { - pub fn from_nbt(nbt: HashMap) -> Result { + pub fn from_nbt(nbt: CompoundTag) -> Result { + let blocks = nbt.get_compound_tag("Blocks").map_err(|e| e.to_string())?; Ok(Self{ - data_version: match nbt.get("DataVersion").ok_or("Invalid schematic".to_string())? { - Value::Int(d) => *d, - _ => return Err("Invalid schematic".to_string()), - }, - metadata: match nbt.get("Metadata").ok_or("Invalid schematic".to_string())? { - Value::Compound(m) => m.clone(), - _ => return Err("Invalid schematic".to_string()), - }, - width: match nbt.get("Width").ok_or("Invalid schematic".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic".to_string()), - }, - height: match nbt.get("Height").ok_or("Invalid schematic".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic".to_string()), - }, - length: match nbt.get("Length").ok_or("Invalid schematic".to_string())? { - Value::Short(n) => *n as u16, - Value::Byte(n) => *n as u16, - _ => return Err("Invalid schematic".to_string()), - }, - offset: read_offset(nbt.get("Offset"))?, - blocks: match nbt.get("Blocks").ok_or("Invalid schematic".to_string())? { - Value::Compound(b) => { - BlockContainer { - palette: read_palette(b.get("Palette"))?, - block_data: read_blocks(b.get("BlockData"))?, - block_entities: read_tile_entities(b.get("BlockEntities"))?, - } - } - _ => return Err("Invalid schematic".to_string()), + data_version: nbt.get_i32("DataVersion").map_err(|e| e.to_string())?, + metadata: nbt.get_compound_tag("Metadata").map_err(|e| e.to_string())?.clone(), + width: nbt.get_i16("Width").map_err(|e| e.to_string())? as u16, + height: nbt.get_i16("Height").map_err(|e| e.to_string())? as u16, + length: nbt.get_i16("Length").map_err(|e| e.to_string())? as u16, + offset: read_offset(nbt.get_i32_vec("Offset").map_err(|e| e.to_string())?)?, + blocks: BlockContainer { + palette: read_palette(blocks.get_compound_tag("Palette").map_err(|e| e.to_string())?), + block_data: read_blocks(blocks.get_i8_vec("BlockData").map_err(|e| e.to_string())?), + block_entities: read_tile_entities(blocks.get_compound_tag_vec("BlockEntities").map_err(|e| e.to_string())?)?, }, entities: None, }) } } -fn read_tile_entities(tag: Option<&Value>) -> Result, String> { - match tag.ok_or("Invalid schematic: read_tile_entities not found".to_string())? { - Value::List(t) => { - let mut tile_entities = Vec::new(); - for te in t.iter() { - match te { - Value::Compound(te) => { - let id = match te.get("Id") { - None => return Err("Invalid schematic: Id Not Found".to_string()), - Some(id) => match id { - Value::String(id) => id.clone(), - _ => return Err("Invalid schematic: Id Wrong Type".to_string()), - }, - }; - let pos = read_offset(te.get("Pos"))?; - tile_entities.push(BlockEntity { id, pos }); - }, - _ => return Err("Invalid schematic: te Wrong Type".to_string()), - }; - } - Ok(tile_entities) - }, - Value::ByteArray(_) => Ok(vec![]), - _ => return Err("Invalid schematic: te wrong type".to_string()), +fn read_tile_entities(tag: Vec<&CompoundTag>) -> Result, String> { +let mut tile_entities = Vec::new(); + for t in tag { + tile_entities.push(BlockEntity { + id: t.get_str("Id").map_err(|e| e.to_string())?.to_string(), + pos: read_offset(t.get("Pos").map_err(|e| e.to_string())?)?, + }); + } + Ok(tile_entities) +} + +#[inline] +fn read_offset(offset: &Vec) -> Result<[i32; 3], String> { + match offset.len() { + 3 => Ok([offset[0], offset[1], offset[2]]), + _ => Err("Invalid schematic: read_offset wrong length".to_string()), } } #[inline] -fn read_offset(offset: Option<&Value>) -> Result<[i32; 3], String> { - match offset.ok_or("Invalid schematic: read_offset missing".to_string())? { - Value::IntArray(o) => match o.len() { - 3 => Ok([o[0], o[1], o[2]]), - _ => Err("Invalid schematic: Invalid IntArray".to_string()), - }, - Value::ByteArray(o) => match o.len() { - 3 => Ok([o[0] as i32, o[1] as i32, o[2] as i32]), - _ => Err("Invalid schematic: Invalid byteArray".to_string()), - }, - Value::List(l) => match l.len() { - 3 => { - let mut offset = [0; 3]; - for (i, v) in l.iter().enumerate() { - match v { - Value::Int(n) => offset[i] = *n, - Value::Byte(n) => offset[i] = *n as i32, - Value::Short(n) => offset[i] = *n as i32, - _ => return Err("Invalid schematic: read_offset invalid Number".to_string()), - }; - } - Ok(offset) - }, - _ => Err("Invalid schematic: Invalid List".to_string()), - } - _ => Err("Invalid schematic: read_offset".to_string()), +fn read_palette(p: &CompoundTag) -> HashMap { + let mut palette = HashMap::new(); + for (key, value) in p.iter() { + match value { + Tag::Int(n) => { palette.insert(key.clone(), *n); }, + _ => {}, + }; } + palette } #[inline] -fn read_palette(palette: Option<&Value>) -> Result, String> { - match palette.ok_or("Invalid schematic: read_palette missing".to_string())? { - Value::Compound(p) => { - let mut palette = HashMap::new(); - for (k, v) in p.iter() { - match v { - Value::Int(v) => { palette.insert(k.clone(), *v); }, - Value::Byte(v) => { palette.insert(k.clone(), *v as i32); }, - Value::Short(v) => { palette.insert(k.clone(), *v as i32); }, - _ => return Err("Invalid schematic: read_palette invalid Number".to_string()), - }; - } - Ok(palette) - }, - _ => Err("Invalid schematic: read_palette invalid Type".to_string()), - } -} - -#[inline] -fn read_blocks(blockdata: Option<&Value>) -> Result, String> { - match blockdata.ok_or("Invalid schematic: BlockData not found".to_string())? { - Value::ByteArray(b) => Ok(read_varint_array(b)), - _ => Err("Invalid schematic: Invalid BlockData".to_string()), - } +fn read_blocks(blockdata: &Vec) -> Vec { + read_varint_array(blockdata) } #[inline] diff --git a/schemsearch-lib/Cargo.toml b/schemsearch-lib/Cargo.toml index 96602a9..5c33e50 100644 --- a/schemsearch-lib/Cargo.toml +++ b/schemsearch-lib/Cargo.toml @@ -7,4 +7,6 @@ license = "AGPL-3.0-or-later" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = { version = "1.0.160", features = ["derive"] } schemsearch-files = { path = "../schemsearch-files" } +named-binary-tag = "0.6" diff --git a/schemsearch-lib/src/lib.rs b/schemsearch-lib/src/lib.rs index 3892e50..ce5d599 100644 --- a/schemsearch-lib/src/lib.rs +++ b/schemsearch-lib/src/lib.rs @@ -17,6 +17,7 @@ pub mod pattern_mapper; +use serde::{Serialize, Deserialize}; use pattern_mapper::match_palette; use schemsearch_files::SchematicVersioned; use crate::pattern_mapper::match_palette_adapt; diff --git a/schemsearch-lib/src/pattern_mapper.rs b/schemsearch-lib/src/pattern_mapper.rs index 8f3ddea..a74dab5 100644 --- a/schemsearch-lib/src/pattern_mapper.rs +++ b/schemsearch-lib/src/pattern_mapper.rs @@ -15,7 +15,8 @@ * along with this program. If not, see . */ -use nbt::Map; +use std::collections::HashMap; +use nbt::CompoundTag; use schemsearch_files::{SchematicVersioned, SpongeV2Schematic}; use crate::normalize_data; @@ -31,7 +32,7 @@ fn create_reverse_palette(schem: &SchematicVersioned) -> Vec<&str> { pub fn strip_data(schem: &SchematicVersioned) -> SchematicVersioned { let mut data: Vec = Vec::new(); - let mut palette: Map = Map::new(); + let mut palette: HashMap = HashMap::new(); let mut palette_max: i32 = 0; let reverse_palette = create_reverse_palette(schem); @@ -56,7 +57,7 @@ pub fn strip_data(schem: &SchematicVersioned) -> SchematicVersioned { height: schem.get_height(), length: schem.get_length(), width: schem.get_width(), - metadata: Map::new(), + metadata: CompoundTag::new(), offset: [0; 3], entities: None, },) @@ -64,7 +65,7 @@ pub fn strip_data(schem: &SchematicVersioned) -> SchematicVersioned { } -pub fn match_palette_adapt(schem: &SchematicVersioned, matching_palette: &Map, ignore_data: bool) -> Vec { +pub fn match_palette_adapt(schem: &SchematicVersioned, matching_palette: &HashMap, ignore_data: bool) -> Vec { let mut data: Vec = Vec::new(); let reverse_palette = create_reverse_palette(schem); @@ -109,7 +110,7 @@ fn match_palette_internal( height: pattern.get_height(), length: pattern.get_length(), width: pattern.get_width(), - metadata: Map::new(), + metadata: CompoundTag::new(), offset: [0; 3], entities: None, })