1
Fork 0

vendored the SwarmBot schematic parsing code (of dubious licensure)

This commit is contained in:
Andy Killorin 2023-12-30 09:48:44 -06:00
parent 44837cfc1d
commit 70c096b6c7
Signed by: ank
GPG key ID: B6241CA3B552BCA4
4 changed files with 145 additions and 0 deletions

View file

@ -45,3 +45,6 @@ tracing-appender = "0.2.3"
ron = "0.8.1"
crossbeam = "0.8.3"
reqwest = "0.11.23"
swarmbot-interfaces = { git = "https://github.com/SwarmBotMC/SwarmBot" }
hematite-nbt = "0.5.2"
more-asserts = "0.3.1"

View file

@ -41,6 +41,7 @@ mod turtle_api;
mod tasks;
mod depot;
mod googleforms;
mod vendored;
static PORT: OnceCell<u16> = OnceCell::const_new();
static SAVE: OnceCell<path::PathBuf> = OnceCell::const_new();

View file

@ -0,0 +1,2 @@
/// MIT (Andrew Gazelka) from [SwarmBot](https://github.com/SwarmBotMC/SwarmBot/tree/b25367843f30ae72797db694d95ceeb0d49da82a)
pub mod schematic;

View file

@ -0,0 +1,139 @@
use std::io::Read;
use anyhow::Context;
use swarmbot_interfaces::types::{BlockLocation, BlockState};
use serde::{Deserialize, Serialize};
/// The `WorldEdit` schematic format
/// <https://minecraft.fandom.com/wiki/Schematic_file_format>
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct Schematic {
pub width: i16,
pub height: i16,
pub length: i16,
materials: String,
blocks: Vec<i8>,
add_blocks: Option<Vec<i8>>,
data: Vec<i8>,
w_e_origin_x: Option<i32>,
w_e_origin_y: Option<i32>,
w_e_origin_z: Option<i32>,
w_e_offset_x: Option<i32>,
w_e_offset_y: Option<i32>,
w_e_offset_z: Option<i32>,
}
impl Schematic {
#[allow(unused)]
pub const fn volume(&self) -> u64 {
let v = (self.width as i64) * (self.height as i64) * (self.length as i64);
v.abs_diff(0)
}
#[allow(unused)]
pub fn load(reader: &mut impl Read) -> anyhow::Result<Self> {
let res: Result<Self, _> =
nbt::from_gzip_reader(reader).context("could not load schematic");
res
}
#[allow(unused)]
pub fn is_valid(&self) -> bool {
self.volume() == self.blocks.len() as u64
}
#[allow(unused)]
pub fn origin(&self) -> Option<BlockLocation> {
match (self.w_e_origin_x, self.w_e_origin_y, self.w_e_origin_z) {
(Some(x), Some(y), Some(z)) => Some(BlockLocation::new(x, y as i16, z)),
_ => None,
}
}
#[allow(unused)]
pub fn offset(&self) -> Option<BlockLocation> {
match (self.w_e_offset_x, self.w_e_offset_y, self.w_e_offset_z) {
(Some(x), Some(y), Some(z)) => Some(BlockLocation::new(x, y as i16, z)),
_ => None,
}
}
#[allow(unused, clippy::unwrap_used)]
pub fn width(&self) -> u64 {
u64::try_from(self.width).unwrap()
}
#[allow(unused, clippy::unwrap_used)]
pub fn height(&self) -> u64 {
u64::try_from(self.width).unwrap()
}
#[allow(unused, clippy::unwrap_used)]
pub fn length(&self) -> u64 {
u64::try_from(self.length).unwrap()
}
#[allow(unused, clippy::unwrap_used, clippy::indexing_slicing)]
pub fn blocks(&self) -> impl Iterator<Item = (BlockLocation, BlockState)> + '_ {
let origin = self.origin().unwrap_or_default();
(0..self.volume()).map(move |idx| {
let x = idx % self.width();
let leftover = idx / self.width();
let z = leftover % self.length();
let y = leftover / self.length();
let location = BlockLocation::new(x as i32, y as i16, z as i32) + origin;
let id = self.blocks[idx as usize].abs_diff(0);
let data = self.data[idx as usize].abs_diff(0);
let state = BlockState::from(u32::from(id), u16::from(data));
(location, state)
})
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashMap, fs::OpenOptions};
use swarmbot_interfaces::types::BlockLocation;
use more_asserts::*;
use super::Schematic;
#[test]
fn test_load() {
let mut reader = OpenOptions::new()
.read(true)
.open("test-data/parkour.schematic")
.unwrap();
let schematic = Schematic::load(&mut reader).unwrap();
assert!(schematic.is_valid());
let origin = schematic.origin().unwrap_or_default();
let mut map = HashMap::new();
for (loc, state) in schematic.blocks() {
assert_ge!(loc.x, origin.x);
assert_lt!(loc.x, origin.x + schematic.width as i32);
assert_ge!(loc.y, origin.y);
assert_lt!(loc.y, origin.y + schematic.height);
assert_ge!(loc.z, origin.z);
assert_lt!(loc.z, origin.z + schematic.length as i32);
map.insert(loc, state);
}
let stained_glass = map[&BlockLocation::new(-162, 81, -357)];
assert_eq!(stained_glass.id(), 95);
}
}