diff --git a/schemsearch-files/Cargo.toml b/schemsearch-files/Cargo.toml
index cfaaff8..76d6ddf 100644
--- a/schemsearch-files/Cargo.toml
+++ b/schemsearch-files/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
flate2 = "1.0.25"
-fastnbt = "2.4.3"
+hematite-nbt = "0.5.2"
serde = "1.0.152"
serde_json = "1.0.84"
diff --git a/schemsearch-files/src/lib.rs b/schemsearch-files/src/lib.rs
index 502a1e4..0fe2838 100644
--- a/schemsearch-files/src/lib.rs
+++ b/schemsearch-files/src/lib.rs
@@ -15,25 +15,12 @@
* along with this program. If not, see .
*/
-use std::collections::hash_map::{HashMap};
+use std::collections::hash_map::HashMap;
use std::io::Read;
use std::path::PathBuf;
-use fastnbt::error::Error;
-use fastnbt::Value;
-use flate2::read::GzDecoder;
-use serde::{Deserialize, Deserializer, Serialize};
-use serde::de::value::MapDeserializer;
+use nbt::Value;
-#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(rename_all = "PascalCase")]
-struct SchematicRaw {
- version: i32,
- #[serde(flatten)]
- data: HashMap,
-}
-
-#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(untagged, rename_all = "PascalCase")]
+#[derive(Clone, Debug)]
pub enum SchematicVersioned {
V1(SpongeV1Schematic),
V2(SpongeV2Schematic),
@@ -105,30 +92,7 @@ impl SchematicVersioned {
}
}
-impl TryFrom for SchematicVersioned {
- type Error = Error;
-
- fn try_from(value: SchematicRaw) -> Result {
- match value.version {
- 1 => {
- let schematic: SpongeV1Schematic = fastnbt::from_value(&fastnbt::to_value(value.data)?)?;
- return Ok(SchematicVersioned::V1(schematic));
- },
- 2 => {
- let schematic: SpongeV2Schematic = fastnbt::from_value(&fastnbt::to_value(value.data)?)?;
- return Ok(SchematicVersioned::V2(schematic));
- },
- 3 => {
- let schematic: SpongeV3Schematic = fastnbt::from_value(&fastnbt::to_value(value.data)?)?;
- return Ok(SchematicVersioned::V3(schematic));
- }
- _ => panic!("Unknown Schematic Version: {}", value.version),
- }
- }
-}
-
-#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Clone, Debug)]
pub struct SpongeV1Schematic {
pub metadata: HashMap,
pub width: u16,
@@ -137,13 +101,11 @@ pub struct SpongeV1Schematic {
pub offset: [i32; 3],
pub palette_max: i32,
pub palette: HashMap,
- #[serde(deserialize_with = "read_blockdata")]
pub block_data: Vec,
pub tile_entities: Vec,
}
-#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Clone, Debug)]
pub struct SpongeV2Schematic {
pub data_version: i32,
pub metadata: HashMap,
@@ -153,14 +115,12 @@ pub struct SpongeV2Schematic {
pub offset: [i32; 3],
pub palette_max: i32,
pub palette: HashMap,
- #[serde(deserialize_with = "read_blockdata")]
pub block_data: Vec,
pub block_entities: Vec,
pub entities: Option>,
}
-#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Clone, Debug)]
pub struct SpongeV3Schematic {
pub data_version: i32,
pub metadata: HashMap,
@@ -172,57 +132,263 @@ pub struct SpongeV3Schematic {
pub entities: Option>,
}
-#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Clone, Debug)]
pub struct BlockContainer {
pub palette: HashMap,
- #[serde(deserialize_with = "read_blockdata")]
pub block_data: Vec,
pub block_entities: Vec,
}
-fn read_blockdata<'de, D>(deserializer: D) -> Result, D::Error>
- where
- D: Deserializer<'de>,
-{
- let s: Vec = Deserialize::deserialize(deserializer)?;
- Ok(read_varint_array(&s))
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Debug, Clone)]
pub struct BlockEntity {
pub id: String,
pub pos: [i32; 3],
}
-#[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Debug, Clone)]
pub struct BlockEntityV3 {
pub id: String,
pub pos: [i32; 3],
pub data: HashMap,
}
-#[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "PascalCase")]
+#[derive(Debug, Clone)]
pub struct Entity {
pub id: String,
pub pos: [i32; 3],
}
impl SchematicVersioned {
- pub fn load_data(data: R) -> Result where R: Read {
- let raw: SchematicRaw = fastnbt::from_reader(GzDecoder::new(data))?;
- SchematicVersioned::try_from(raw)
+ 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()),
+ };
+
+ match version {
+ 1 => Ok(SchematicVersioned::V1(SpongeV1Schematic::from_nbt(nbt)?)),
+ 2 => Ok(SchematicVersioned::V2(SpongeV2Schematic::from_nbt(nbt)?)),
+ 3 => Ok(SchematicVersioned::V3(SpongeV3Schematic::from_nbt(nbt)?)),
+ _ => Err("Invalid schematic: Unknown Version".to_string()),
+ }
}
- pub fn load(path: &PathBuf) -> Result {
- let file = std::fs::File::open(path)?;
+ pub fn load(path: &PathBuf) -> Result {
+ let file = std::fs::File::open(path).map_err(|e| e.to_string())?;
Self::load_data(file)
}
}
+impl SpongeV1Schematic {
+ pub fn from_nbt(nbt: HashMap) -> 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"))?,
+ })
+ }
+}
+
+impl SpongeV2Schematic {
+ pub fn from_nbt(nbt: HashMap) -> 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"))?,
+ entities: None,
+ })
+ }
+}
+
+impl SpongeV3Schematic {
+ pub fn from_nbt(nbt: HashMap) -> Result {
+ 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()),
+ },
+ 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()),
+ }
+}
+
+#[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()),
+ }
+}
+
+#[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()),
+ }
+}
+
+#[inline]
pub fn read_varint_array(read: &Vec) -> Vec {
let mut data = Vec::new();
let mut value: i32 = 0;