switched to SwarmBot's schematic parser
This commit is contained in:
parent
70c096b6c7
commit
c49f5735ec
4 changed files with 39 additions and 58 deletions
|
@ -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(),
|
||||||
|
|
|
@ -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));
|
||||||
},
|
},
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue