vendored the SwarmBot schematic parsing code (of dubious licensure)
This commit is contained in:
parent
44837cfc1d
commit
70c096b6c7
4 changed files with 145 additions and 0 deletions
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
2
server/src/vendored/mod.rs
Normal file
2
server/src/vendored/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
/// MIT (Andrew Gazelka) from [SwarmBot](https://github.com/SwarmBotMC/SwarmBot/tree/b25367843f30ae72797db694d95ceeb0d49da82a)
|
||||
pub mod schematic;
|
139
server/src/vendored/schematic.rs
Normal file
139
server/src/vendored/schematic.rs
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue