/* * Copyright (C) 2023 Chaoscaot * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use std::io::Read; use std::path::Path; use nbt::{Map, Value}; use serde::{Deserialize, Deserializer, Serialize}; #[derive(Serialize, Deserialize, Debug)] pub struct Schematic { #[serde(rename = "Version")] pub version: i32, #[serde(rename = "DataVersion")] pub data_version: i32, #[serde(rename = "Metadata")] pub metadata: Map, #[serde(rename = "Width")] pub width: u16, #[serde(rename = "Height")] pub height: u16, #[serde(rename = "Length")] pub length: u16, #[serde(rename = "Offset")] pub offset: [i32; 3], #[serde(rename = "PaletteMax")] pub palette_max: i32, #[serde(rename = "Palette")] pub palette: Map, #[serde(rename = "BlockData", deserialize_with = "read_blockdata")] pub block_data: Vec, #[serde(rename = "BlockEntities")] pub block_entities: Vec, #[serde(rename = "Entities")] pub entities: Option>, } 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)] pub struct BlockEntity { #[serde(rename = "Id")] pub id: String, #[serde(rename = "Pos")] pub pos: [i32; 3], } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Entity { #[serde(rename = "Id")] pub id: String, #[serde(rename = "Pos")] pub pos: [i32; 3], } impl Schematic { pub fn load_data(data: R) -> Result where R: Read { let schematic: Schematic = match nbt::from_gzip_reader(data) { Ok(schem) => schem, Err(e) => return Err(format!("Failed to parse schematic: {}", e)) }; Ok(schematic) } pub fn load(path: &Path) -> Result { let file = match std::fs::File::open(path) { Ok(x) => x, Err(_) => return Err(format!("Failed to open file: {}", path.display())) }; Schematic::load_data(file) } } pub fn read_varint_array(read: &Vec) -> Vec { let mut data = Vec::new(); let mut value: i32 = 0; let mut position = 0; let mut current_byte; let mut cursor = 0; loop { match read.get(cursor) { Some(byte) => { current_byte = *byte as u8; cursor += 1; }, None => break, }; value |= (((current_byte & 0x7F) as u32) << position) as i32; if(current_byte & 0x80) == 0 { data.push(value); value = 0; position = 0; } else { position += 7; if position > 32 { panic!("VarInt too big"); } } } data }