From c49f5735ecf829b2ec30b45d0228d62f4982cf4a Mon Sep 17 00:00:00 2001 From: Andy Killorin <37423245+Speedy6451@users.noreply.github.com> Date: Sat, 30 Dec 2023 10:20:42 -0600 Subject: [PATCH] switched to SwarmBot's schematic parser --- server/src/construct.rs | 45 ++++++++++++-------------------- server/src/googleforms.rs | 18 +++++-------- server/src/turtle_api.rs | 11 +++----- server/src/vendored/schematic.rs | 23 +++++++++------- 4 files changed, 39 insertions(+), 58 deletions(-) diff --git a/server/src/construct.rs b/server/src/construct.rs index 93c4b13..830d9ef 100644 --- a/server/src/construct.rs +++ b/server/src/construct.rs @@ -1,41 +1,30 @@ use std::{sync::{atomic::{AtomicBool, AtomicUsize, Ordering, AtomicI32}, Arc}, borrow::Cow}; -use rustmatica::{Region, Litematic, BlockState, util::UVec3}; +use anyhow::{Context, Ok}; use serde::{Serialize, Deserialize}; +use swarmbot_interfaces::types::BlockState; use tokio::task::AbortHandle; use tracing::{error, info, trace}; use typetag::serde; -use crate::{blocks::{Vec3, Position, World, Block, SharedWorld, Direction}, mine::{ChunkedTask, fill}, turtle::{TurtleCommander, TurtleCommandResponse, TurtleCommand}, tasks::{Task, TaskState}}; +use crate::{blocks::{Vec3, Position, World, Block, SharedWorld, Direction}, mine::{ChunkedTask, fill}, turtle::{TurtleCommander, TurtleCommandResponse, TurtleCommand}, tasks::{Task, TaskState}, vendored::schematic::Schematic}; -fn region2world<'a>(region: &'a Region) -> World { +fn schematic2world(region: &Schematic) -> anyhow::Result { let mut world = World::new(); - let min = Vec3::new( - region.min_x() as i32, - region.min_y() as i32, - region.min_z() as i32, - ); - let max = Vec3::new( - region.max_x() as i32 + 1, - region.max_y() as i32 + 1, - region.max_z() as i32 + 1, + let min = region.origin().context("bad schematic")?; + let area = Vec3::new( + region.width() as i32, + region.height() as i32, + region.length() as i32, ); - - let area = max - min; info!("area {}", area); - // region.blocks() is broken (or how I was using it), which cost me quite some time TODO: make a pr - - for position in (0..area.product()).map(|n| fill(area, n)) { - let block = UVec3::new(position.x as usize, position.y as usize, position.z as usize); - let block = region.get_block(block); - + for (position, block) in region.blocks() { println!("{:#?}, {}", block, position); let name = match block { - BlockState::Air => None, - BlockState::Stone => Some("minecraft:stone"), + BlockState::AIR => None, // who cares _ => Some("terrestria:hemlock_planks") }.map(|s| s.to_string()); @@ -50,7 +39,7 @@ fn region2world<'a>(region: &'a Region) -> World { } } - world + Ok(world) } #[derive(Serialize, Deserialize,Clone)] @@ -68,16 +57,16 @@ pub struct BuildSimple { } impl BuildSimple { - pub fn new<'a>(position: Vec3, schematic: &'a Region, input: Position) -> Self { + pub fn new(position: Vec3, schematic: &Schematic, input: Position) -> Self { let size = Vec3::new( - (1 + schematic.max_x() - schematic.min_x()) as i32, - (1 + schematic.max_y() - schematic.min_y()) as i32, - (1 + schematic.max_z() - schematic.min_z()) as i32, + schematic.width() as i32, + schematic.height() as i32, + schematic.length() as i32, ); Self { pos: position, size, - region: Some(SharedWorld::from_world(region2world(schematic))), + region: Some(SharedWorld::from_world(schematic2world(schematic).unwrap())), input, miners: Default::default(), progress: Default::default(), diff --git a/server/src/googleforms.rs b/server/src/googleforms.rs index 6532ece..fc6df10 100644 --- a/server/src/googleforms.rs +++ b/server/src/googleforms.rs @@ -2,12 +2,13 @@ use std::sync::{Arc, atomic::{AtomicBool, Ordering}}; use anyhow::{Ok, Context, anyhow, Result}; use axum::{Router, routing::post, extract::State, Json}; +use hyper::body::Buf; use serde::{Deserialize, Serialize}; use tokio::task::AbortHandle; use tracing::{info, error}; use typetag::serde; -use crate::{SharedControl, mine::{Remove, ChunkedTask, Quarry}, blocks::{Vec3, Direction, Position}, tasks::{TaskState, Task}, turtle::TurtleCommander, construct::BuildSimple}; +use crate::{SharedControl, mine::{Remove, ChunkedTask, Quarry}, blocks::{Vec3, Direction, Position}, tasks::{TaskState, Task}, turtle::TurtleCommander, construct::BuildSimple, vendored::schematic::Schematic}; pub fn forms_api() -> Router { Router::new() @@ -106,14 +107,7 @@ async fn omni_inner(state: SharedControl, req: GoogleOmniForm) -> anyhow::Result match req.operation { GoogleOmniFormMode::Schematic => { let schematic = req.schematic.context("no schematic uploaded")?.get(0).context("zero schematics")?.to_owned(); - let schematic = reqwest::get(format!("https://docs.google.com/uc?export=download&id={schematic}")).await?; - - let schematic = rustmatica::Litematic::from_bytes(&schematic.bytes().await?)?; - - - info!("schematic \"{}\" downloaded", &schematic.name); - info!("{} blocks", schematic.total_blocks()); - info!("{} regions", schematic.regions.len()); + let schematic = reqwest::get(format!("https://docs.google.com/uc?export=download&id={schematic}")).await?.bytes().await?; let input = Position::new( Vec3::new(53,73,77), @@ -122,9 +116,9 @@ async fn omni_inner(state: SharedControl, req: GoogleOmniForm) -> anyhow::Result // this converts to my memory representation so it can take a while let builder = tokio::task::spawn_blocking(move || { - let region = schematic.regions.get(0).context("no regions"); - Ok(BuildSimple::new(position, region?, input)) - }).await??; + let schematic = Schematic::load(&mut schematic.reader()).unwrap(); + BuildSimple::new(position, &schematic, input) + }).await.unwrap(); schedule.add_task(Box::new(builder)); }, diff --git a/server/src/turtle_api.rs b/server/src/turtle_api.rs index af58e5a..41a598b 100644 --- a/server/src/turtle_api.rs +++ b/server/src/turtle_api.rs @@ -12,6 +12,7 @@ use crate::turtle::IDLE_TIME; use crate::turtle::TurtleCommandResponse; use crate::turtle::TurtleCommander; use crate::turtle::TurtleInfo; +use crate::vendored::schematic::Schematic; use axum::extract::Path; use crate::turtle::TurtleCommand; use crate::names::Name; @@ -295,12 +296,7 @@ pub(crate) async fn build( ) -> &'static str { let state = state.read().await; let mut schedule = state.tasks.lock().await; - let schematic = rustmatica::Litematic::read_file("Tree.litematic").unwrap(); - - - info!("schematic \"{}\" downloaded", &schematic.name); - info!("{} blocks", schematic.total_blocks()); - info!("{} regions", schematic.regions.len()); + let schematic = Schematic::load(&mut fs::File::open("thethinkman.schematic").await.unwrap().into_std().await).unwrap(); let input = Position::new( Vec3::new(53,73,77), @@ -309,8 +305,7 @@ pub(crate) async fn build( // this converts to my memory representation so it can take a while let builder = tokio::task::spawn_blocking(move || { - let region = schematic.regions.get(0); - BuildSimple::new(req, region.unwrap(), input) + BuildSimple::new(req, &schematic, input) }).await.unwrap(); schedule.add_task(Box::new(builder)); diff --git a/server/src/vendored/schematic.rs b/server/src/vendored/schematic.rs index a429d08..122464c 100644 --- a/server/src/vendored/schematic.rs +++ b/server/src/vendored/schematic.rs @@ -1,9 +1,11 @@ use std::io::Read; use anyhow::Context; -use swarmbot_interfaces::types::{BlockLocation, BlockState}; +use swarmbot_interfaces::types::BlockState; use serde::{Deserialize, Serialize}; +use crate::blocks::Vec3; + /// The `WorldEdit` schematic format /// #[derive(Serialize, Deserialize, Debug)] @@ -45,17 +47,17 @@ impl Schematic { } #[allow(unused)] - pub fn origin(&self) -> Option { + pub fn origin(&self) -> Option { 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)), + (Some(x), Some(y), Some(z)) => Some(Vec3::new(x, y, z)), _ => None, } } #[allow(unused)] - pub fn offset(&self) -> Option { + pub fn offset(&self) -> Option { 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)), + (Some(x), Some(y), Some(z)) => Some(Vec3::new(x, y, z)), _ => None, } } @@ -76,7 +78,7 @@ impl Schematic { } #[allow(unused, clippy::unwrap_used, clippy::indexing_slicing)] - pub fn blocks(&self) -> impl Iterator + '_ { + pub fn blocks(&self) -> impl Iterator + '_ { let origin = self.origin().unwrap_or_default(); (0..self.volume()).map(move |idx| { @@ -87,7 +89,7 @@ impl Schematic { let y = leftover / self.length(); - let location = BlockLocation::new(x as i32, y as i16, z as i32) + origin; + let location = Vec3::new(x as i32, y as i32, z as i32) + origin; let id = self.blocks[idx as usize].abs_diff(0); let data = self.data[idx as usize].abs_diff(0); @@ -102,9 +104,10 @@ impl Schematic { mod tests { use std::{collections::HashMap, fs::OpenOptions}; - use swarmbot_interfaces::types::BlockLocation; use more_asserts::*; + use crate::blocks::Vec3; + use super::Schematic; #[test] @@ -126,14 +129,14 @@ mod tests { 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_lt!(loc.y, origin.y + schematic.height as i32); 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)]; + let stained_glass = map[&Vec3::new(-162, 81, -357)]; assert_eq!(stained_glass.id(), 95); } }