1
Fork 0

switched to SwarmBot's schematic parser

This commit is contained in:
Andy Killorin 2023-12-30 10:20:42 -06:00
parent 70c096b6c7
commit c49f5735ec
Signed by: ank
GPG key ID: B6241CA3B552BCA4
4 changed files with 39 additions and 58 deletions

View file

@ -1,41 +1,30 @@
use std::{sync::{atomic::{AtomicBool, AtomicUsize, Ordering, AtomicI32}, Arc}, borrow::Cow}; 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 serde::{Serialize, Deserialize};
use swarmbot_interfaces::types::BlockState;
use tokio::task::AbortHandle; use tokio::task::AbortHandle;
use tracing::{error, info, trace}; use tracing::{error, info, trace};
use typetag::serde; 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<World> {
let mut world = World::new(); 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( let min = region.origin().context("bad schematic")?;
region.max_x() as i32 + 1, let area = Vec3::new(
region.max_y() as i32 + 1, region.width() as i32,
region.max_z() as i32 + 1, region.height() as i32,
region.length() as i32,
); );
let area = max - min;
info!("area {}", area); 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, block) in region.blocks() {
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);
println!("{:#?}, {}", block, position); println!("{:#?}, {}", block, position);
let name = match block { let name = match block {
BlockState::Air => None, BlockState::AIR => None,
BlockState::Stone => Some("minecraft:stone"),
// who cares // who cares
_ => Some("terrestria:hemlock_planks") _ => Some("terrestria:hemlock_planks")
}.map(|s| s.to_string()); }.map(|s| s.to_string());
@ -50,7 +39,7 @@ fn region2world<'a>(region: &'a Region) -> World {
} }
} }
world Ok(world)
} }
#[derive(Serialize, Deserialize,Clone)] #[derive(Serialize, Deserialize,Clone)]
@ -68,16 +57,16 @@ pub struct BuildSimple {
} }
impl 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( let size = Vec3::new(
(1 + schematic.max_x() - schematic.min_x()) as i32, schematic.width() as i32,
(1 + schematic.max_y() - schematic.min_y()) as i32, schematic.height() as i32,
(1 + schematic.max_z() - schematic.min_z()) as i32, schematic.length() as i32,
); );
Self { Self {
pos: position, pos: position,
size, size,
region: Some(SharedWorld::from_world(region2world(schematic))), region: Some(SharedWorld::from_world(schematic2world(schematic).unwrap())),
input, input,
miners: Default::default(), miners: Default::default(),
progress: Default::default(), progress: Default::default(),

View file

@ -2,12 +2,13 @@ use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use anyhow::{Ok, Context, anyhow, Result}; use anyhow::{Ok, Context, anyhow, Result};
use axum::{Router, routing::post, extract::State, Json}; use axum::{Router, routing::post, extract::State, Json};
use hyper::body::Buf;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::task::AbortHandle; use tokio::task::AbortHandle;
use tracing::{info, error}; use tracing::{info, error};
use typetag::serde; 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<SharedControl> { pub fn forms_api() -> Router<SharedControl> {
Router::new() Router::new()
@ -106,14 +107,7 @@ async fn omni_inner(state: SharedControl, req: GoogleOmniForm) -> anyhow::Result
match req.operation { match req.operation {
GoogleOmniFormMode::Schematic => { GoogleOmniFormMode::Schematic => {
let schematic = req.schematic.context("no schematic uploaded")?.get(0).context("zero schematics")?.to_owned(); 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 = reqwest::get(format!("https://docs.google.com/uc?export=download&id={schematic}")).await?.bytes().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 input = Position::new( let input = Position::new(
Vec3::new(53,73,77), 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 // this converts to my memory representation so it can take a while
let builder = tokio::task::spawn_blocking(move || { let builder = tokio::task::spawn_blocking(move || {
let region = schematic.regions.get(0).context("no regions"); let schematic = Schematic::load(&mut schematic.reader()).unwrap();
Ok(BuildSimple::new(position, region?, input)) BuildSimple::new(position, &schematic, input)
}).await??; }).await.unwrap();
schedule.add_task(Box::new(builder)); schedule.add_task(Box::new(builder));
}, },

View file

@ -12,6 +12,7 @@ use crate::turtle::IDLE_TIME;
use crate::turtle::TurtleCommandResponse; use crate::turtle::TurtleCommandResponse;
use crate::turtle::TurtleCommander; use crate::turtle::TurtleCommander;
use crate::turtle::TurtleInfo; use crate::turtle::TurtleInfo;
use crate::vendored::schematic::Schematic;
use axum::extract::Path; use axum::extract::Path;
use crate::turtle::TurtleCommand; use crate::turtle::TurtleCommand;
use crate::names::Name; use crate::names::Name;
@ -295,12 +296,7 @@ pub(crate) async fn build(
) -> &'static str { ) -> &'static str {
let state = state.read().await; let state = state.read().await;
let mut schedule = state.tasks.lock().await; let mut schedule = state.tasks.lock().await;
let schematic = rustmatica::Litematic::read_file("Tree.litematic").unwrap(); let schematic = Schematic::load(&mut fs::File::open("thethinkman.schematic").await.unwrap().into_std().await).unwrap();
info!("schematic \"{}\" downloaded", &schematic.name);
info!("{} blocks", schematic.total_blocks());
info!("{} regions", schematic.regions.len());
let input = Position::new( let input = Position::new(
Vec3::new(53,73,77), 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 // this converts to my memory representation so it can take a while
let builder = tokio::task::spawn_blocking(move || { let builder = tokio::task::spawn_blocking(move || {
let region = schematic.regions.get(0); BuildSimple::new(req, &schematic, input)
BuildSimple::new(req, region.unwrap(), input)
}).await.unwrap(); }).await.unwrap();
schedule.add_task(Box::new(builder)); schedule.add_task(Box::new(builder));

View file

@ -1,9 +1,11 @@
use std::io::Read; use std::io::Read;
use anyhow::Context; use anyhow::Context;
use swarmbot_interfaces::types::{BlockLocation, BlockState}; use swarmbot_interfaces::types::BlockState;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::blocks::Vec3;
/// The `WorldEdit` schematic format /// The `WorldEdit` schematic format
/// <https://minecraft.fandom.com/wiki/Schematic_file_format> /// <https://minecraft.fandom.com/wiki/Schematic_file_format>
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -45,17 +47,17 @@ impl Schematic {
} }
#[allow(unused)] #[allow(unused)]
pub fn origin(&self) -> Option<BlockLocation> { pub fn origin(&self) -> Option<Vec3> {
match (self.w_e_origin_x, self.w_e_origin_y, self.w_e_origin_z) { 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, _ => None,
} }
} }
#[allow(unused)] #[allow(unused)]
pub fn offset(&self) -> Option<BlockLocation> { pub fn offset(&self) -> Option<Vec3> {
match (self.w_e_offset_x, self.w_e_offset_y, self.w_e_offset_z) { 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, _ => None,
} }
} }
@ -76,7 +78,7 @@ impl Schematic {
} }
#[allow(unused, clippy::unwrap_used, clippy::indexing_slicing)] #[allow(unused, clippy::unwrap_used, clippy::indexing_slicing)]
pub fn blocks(&self) -> impl Iterator<Item = (BlockLocation, BlockState)> + '_ { pub fn blocks(&self) -> impl Iterator<Item = (Vec3, BlockState)> + '_ {
let origin = self.origin().unwrap_or_default(); let origin = self.origin().unwrap_or_default();
(0..self.volume()).map(move |idx| { (0..self.volume()).map(move |idx| {
@ -87,7 +89,7 @@ impl Schematic {
let y = leftover / self.length(); 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 id = self.blocks[idx as usize].abs_diff(0);
let data = self.data[idx as usize].abs_diff(0); let data = self.data[idx as usize].abs_diff(0);
@ -102,9 +104,10 @@ impl Schematic {
mod tests { mod tests {
use std::{collections::HashMap, fs::OpenOptions}; use std::{collections::HashMap, fs::OpenOptions};
use swarmbot_interfaces::types::BlockLocation;
use more_asserts::*; use more_asserts::*;
use crate::blocks::Vec3;
use super::Schematic; use super::Schematic;
#[test] #[test]
@ -126,14 +129,14 @@ mod tests {
assert_lt!(loc.x, origin.x + schematic.width as i32); assert_lt!(loc.x, origin.x + schematic.width as i32);
assert_ge!(loc.y, origin.y); 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_ge!(loc.z, origin.z);
assert_lt!(loc.z, origin.z + schematic.length as i32); assert_lt!(loc.z, origin.z + schematic.length as i32);
map.insert(loc, state); 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); assert_eq!(stained_glass.id(), 95);
} }
} }