Mirror von
https://github.com/Chaoscaot/schemsearch
synchronisiert 2024-11-19 10:20:08 +01:00
Something™️
Dieser Commit ist enthalten in:
Ursprung
246927d840
Commit
a47c2f44bd
@ -7,7 +7,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
flate2 = "1.0.25"
|
flate2 = "1.0.25"
|
||||||
fastnbt = "2.4.3"
|
hematite-nbt = "0.5.2"
|
||||||
serde = "1.0.152"
|
serde = "1.0.152"
|
||||||
serde_json = "1.0.84"
|
serde_json = "1.0.84"
|
||||||
|
|
||||||
|
@ -15,25 +15,12 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::collections::hash_map::{HashMap};
|
use std::collections::hash_map::HashMap;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use fastnbt::error::Error;
|
use nbt::Value;
|
||||||
use fastnbt::Value;
|
|
||||||
use flate2::read::GzDecoder;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
|
||||||
use serde::de::value::MapDeserializer;
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
struct SchematicRaw {
|
|
||||||
version: i32,
|
|
||||||
#[serde(flatten)]
|
|
||||||
data: HashMap<String, Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
|
||||||
#[serde(untagged, rename_all = "PascalCase")]
|
|
||||||
pub enum SchematicVersioned {
|
pub enum SchematicVersioned {
|
||||||
V1(SpongeV1Schematic),
|
V1(SpongeV1Schematic),
|
||||||
V2(SpongeV2Schematic),
|
V2(SpongeV2Schematic),
|
||||||
@ -105,30 +92,7 @@ impl SchematicVersioned {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<SchematicRaw> for SchematicVersioned {
|
#[derive(Clone, Debug)]
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(value: SchematicRaw) -> Result<Self, Self::Error> {
|
|
||||||
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")]
|
|
||||||
pub struct SpongeV1Schematic {
|
pub struct SpongeV1Schematic {
|
||||||
pub metadata: HashMap<String, Value>,
|
pub metadata: HashMap<String, Value>,
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
@ -137,13 +101,11 @@ pub struct SpongeV1Schematic {
|
|||||||
pub offset: [i32; 3],
|
pub offset: [i32; 3],
|
||||||
pub palette_max: i32,
|
pub palette_max: i32,
|
||||||
pub palette: HashMap<String, i32>,
|
pub palette: HashMap<String, i32>,
|
||||||
#[serde(deserialize_with = "read_blockdata")]
|
|
||||||
pub block_data: Vec<i32>,
|
pub block_data: Vec<i32>,
|
||||||
pub tile_entities: Vec<BlockEntity>,
|
pub tile_entities: Vec<BlockEntity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct SpongeV2Schematic {
|
pub struct SpongeV2Schematic {
|
||||||
pub data_version: i32,
|
pub data_version: i32,
|
||||||
pub metadata: HashMap<String, Value>,
|
pub metadata: HashMap<String, Value>,
|
||||||
@ -153,14 +115,12 @@ pub struct SpongeV2Schematic {
|
|||||||
pub offset: [i32; 3],
|
pub offset: [i32; 3],
|
||||||
pub palette_max: i32,
|
pub palette_max: i32,
|
||||||
pub palette: HashMap<String, i32>,
|
pub palette: HashMap<String, i32>,
|
||||||
#[serde(deserialize_with = "read_blockdata")]
|
|
||||||
pub block_data: Vec<i32>,
|
pub block_data: Vec<i32>,
|
||||||
pub block_entities: Vec<BlockEntity>,
|
pub block_entities: Vec<BlockEntity>,
|
||||||
pub entities: Option<Vec<Entity>>,
|
pub entities: Option<Vec<Entity>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct SpongeV3Schematic {
|
pub struct SpongeV3Schematic {
|
||||||
pub data_version: i32,
|
pub data_version: i32,
|
||||||
pub metadata: HashMap<String, Value>,
|
pub metadata: HashMap<String, Value>,
|
||||||
@ -172,57 +132,263 @@ pub struct SpongeV3Schematic {
|
|||||||
pub entities: Option<Vec<Entity>>,
|
pub entities: Option<Vec<Entity>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct BlockContainer {
|
pub struct BlockContainer {
|
||||||
pub palette: HashMap<String, i32>,
|
pub palette: HashMap<String, i32>,
|
||||||
#[serde(deserialize_with = "read_blockdata")]
|
|
||||||
pub block_data: Vec<i32>,
|
pub block_data: Vec<i32>,
|
||||||
pub block_entities: Vec<BlockEntity>,
|
pub block_entities: Vec<BlockEntity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_blockdata<'de, D>(deserializer: D) -> Result<Vec<i32>, D::Error>
|
#[derive(Debug, Clone)]
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let s: Vec<i8> = Deserialize::deserialize(deserializer)?;
|
|
||||||
Ok(read_varint_array(&s))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct BlockEntity {
|
pub struct BlockEntity {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub pos: [i32; 3],
|
pub pos: [i32; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct BlockEntityV3 {
|
pub struct BlockEntityV3 {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub pos: [i32; 3],
|
pub pos: [i32; 3],
|
||||||
pub data: HashMap<String, Value>,
|
pub data: HashMap<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
|
||||||
pub struct Entity {
|
pub struct Entity {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub pos: [i32; 3],
|
pub pos: [i32; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SchematicVersioned {
|
impl SchematicVersioned {
|
||||||
pub fn load_data<R>(data: R) -> Result<SchematicVersioned, Error> where R: Read {
|
pub fn load_data<R>(data: R) -> Result<SchematicVersioned, String> where R: Read {
|
||||||
let raw: SchematicRaw = fastnbt::from_reader(GzDecoder::new(data))?;
|
let nbt: HashMap<String, Value> = nbt::de::from_gzip_reader(data).map_err(|e| e.to_string())?;
|
||||||
SchematicVersioned::try_from(raw)
|
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<SchematicVersioned, Error> {
|
pub fn load(path: &PathBuf) -> Result<SchematicVersioned, String> {
|
||||||
let file = std::fs::File::open(path)?;
|
let file = std::fs::File::open(path).map_err(|e| e.to_string())?;
|
||||||
Self::load_data(file)
|
Self::load_data(file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SpongeV1Schematic {
|
||||||
|
pub fn from_nbt(nbt: HashMap<String, Value>) -> Result<Self, String> {
|
||||||
|
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<String, Value>) -> Result<Self, String> {
|
||||||
|
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<String, Value>) -> Result<Self, 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()),
|
||||||
|
},
|
||||||
|
entities: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_tile_entities(tag: Option<&Value>) -> Result<Vec<BlockEntity>, 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<HashMap<String, i32>, 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<Vec<i32>, 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<i8>) -> Vec<i32> {
|
pub fn read_varint_array(read: &Vec<i8>) -> Vec<i32> {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
let mut value: i32 = 0;
|
let mut value: i32 = 0;
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren