From 96a8de68584620f8e6d4ad4026a9e458a49bac9a Mon Sep 17 00:00:00 2001 From: Andy Killorin <37423245+Speedy6451@users.noreply.github.com> Date: Sun, 17 Dec 2023 15:28:18 -0600 Subject: [PATCH] authorized digging --- client/client.lua | 104 +++++++++++++++++++++++++++++++------------ server/src/main.rs | 87 ++++++++++++++++++++++++++---------- server/src/turtle.rs | 20 ++++++--- 3 files changed, 152 insertions(+), 59 deletions(-) diff --git a/client/client.lua b/client/client.lua index 04d0691..18d2db1 100644 --- a/client/client.lua +++ b/client/client.lua @@ -1,3 +1,38 @@ +local port = "48228" +local endpoint = "http://" .. ipaddr .. ":" .. port + +local function update(args) + if args[1] == "nested" then + -- no exec = stack overflow + return false + end + local req = http.get(endpoint .. "/turtle/client.lua") + if not req then + os.reboot() + end + local update = req.readAll() + req.close() + fs.delete("startup-backup") + if fs.exists("/startup") then + -- pcall does not work with cc fs + fs.move("startup", "startup-backup") + end + local startup = fs.open("startup", "w") + startup.write(update) + startup.close() + shell.run("startup", "nested") + return true +end + +local function cycle(func, n) + for i = 1, n, 1 do + if not func() then + return false + end + end + return true +end + if not ipaddr then if fs.exists("/disk/ip") then local ipfile = fs.open("/disk/ip") @@ -9,10 +44,6 @@ if not ipaddr then end end -local port = "48228" - -local endpoint = "http://" .. ipaddr .. ":" .. port - local idfile = fs.open("id", "r") local id = nil @@ -60,41 +91,54 @@ end repeat print(command) + local args = nil + if type(command) == "table" then + command, args = pairs(command)(command) + end + + local ret = nil + if command == "Wait" then - sleep(5) + sleep(args) elseif command == "Forward" then - turtle.forward() + ret = cycle(turtle.forward, args) elseif command == "Backward" then - turtle.back() + ret = cycle(turtle.back, args) elseif command == "Left" then - turtle.turnLeft() + ret = turtle.turnLeft() elseif command == "Right" then - turtle.turnRight() + ret = turtle.turnRight() elseif command == "Up" then - turtle.up() + ret = cycle(turtle.up, args) elseif command == "Down" then - turtle.down() + ret = cycle(turtle.down, args) + elseif command == "Dig" then + ret = turtle.dig() + elseif command == "DigUp" then + ret = turtle.digUp() + elseif command == "DigDown" then + ret = turtle.digDown() + elseif command == "ItemInfo" then + ret = { Item = turtle.getItemDetail(args) } elseif command == "Update" then - args = {...} - if args[1] == "nested" then - -- no exec = stack overflow + if not update({...}) then break end - local req = http.get(endpoint .. "/turtle/client.lua") - if not req then - os.reboot() + end + + local ret_table = nil + if type(ret) == "boolean" then + if ret then + ret_table = "Success" + else + ret_table = "Failure" end - local update = req.readAll() - req.close() - fs.delete("startup-backup") - if fs.exists("/startup") then - -- pcall does not work with cc fs - fs.move("startup", "startup-backup") - end - local startup = fs.open("startup", "w") - startup.write(update) - startup.close() - shell.run("startup", "nested") + else + ret_table = ret + end + + if not ret_table then + ret_table = "None" end local ahead = "minecraft:air" @@ -119,8 +163,10 @@ repeat fuel = turtle.getFuelLevel(), ahead = ahead, above = above, - below = below + below = below, + ret = ret_table, } + print(info.ret) local rsp = http.post( endpoint .. "/turtle/" .. id .. "/update" , diff --git a/server/src/main.rs b/server/src/main.rs index bfd1238..0882ace 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -10,7 +10,7 @@ use rstar::{self, AABB}; mod names; use names::Name; -use tokio::{sync::{Mutex, RwLock, watch}, signal}; +use tokio::{sync::{Mutex, RwLock, watch::{self, Sender}}, signal}; use serde::{Serialize, Deserialize}; use const_format::formatcp; use hyper_util::rt::TokioIo; @@ -116,14 +116,18 @@ async fn main() -> Result<(), Error> { .route("/flush", get(flush)) .with_state(state.clone()); - serve(server).await; + let server = serve(server).await; + + println!("writing"); write_to_disk(state).await?; + server.closed().await; + Ok(()) } -async fn serve(serv: Router) { +async fn serve(server: Router) -> Sender<()> { let listener = tokio::net::TcpListener::bind("0.0.0.0:48228").await.unwrap(); let (close_tx, close_rx) = watch::channel(()); @@ -139,7 +143,7 @@ async fn serve(serv: Router) { } }; - let tower = serv.clone(); + let tower = server.clone(); let close_rx = close_rx.clone(); tokio::spawn(async move { @@ -175,7 +179,7 @@ async fn serve(serv: Router) { drop(listener); - close_tx.closed().await; + close_tx } async fn write_to_disk(state: SharedControl) -> anyhow::Result<()> { @@ -259,13 +263,14 @@ async fn command( ) -> Json { let mut state = &mut state.write().await; + println!("{:?}", &req); + if id as usize > state.turtles.len() { return Json(TurtleCommand::Update); } Json( process_turtle_update(id, &mut state, req).unwrap_or(TurtleCommand::Update), - ) } @@ -317,9 +322,18 @@ fn process_turtle_update( if let Some(goal) = turtle.goal { // TODO: memoize this whenever we aren't digging - let route = route(turtle.position, goal, world); + let route = route(turtle.position, goal, world).unwrap(); println!("route: {:?}", route); - let next_move = difference(route[0], route[1]).unwrap(); + let mut next_move = difference(route[0], route[1]).unwrap(); + if world.locate_at_point(&route[1].0.into()).is_some_and(|b| b.name != "minecraft:air") { + next_move = match next_move { + TurtleCommand::Up(_) => TurtleCommand::DigUp, + TurtleCommand::Down(_) => TurtleCommand::DigDown, + TurtleCommand::Forward(_) => TurtleCommand::Dig, + _ => next_move, + + } + } turtle.queued_movement = next_move.delta(turtle.position.1); match next_move { TurtleCommand::Left => turtle.position.1 = turtle.position.1.left(), @@ -329,7 +343,7 @@ fn process_turtle_update( return Ok(next_move); } - Ok(TurtleCommand::Wait) + Ok(TurtleCommand::Wait(3)) } #[derive(Serialize, Deserialize)] @@ -354,13 +368,13 @@ fn difference(from: Position, to: Position) -> Option { } } else if to.1 == from.1 { if to.0 == from.0 + from.1.unit() { - Some(Forward) + Some(Forward(1)) } else if to.0 == from.0 - from.1.unit() { - Some(Backward) + Some(Backward(1)) } else if to.0 == from.0 + Vec3::y() { - Some(Up) + Some(Up(1)) } else if to.0 == from.0 - Vec3::y() { - Some(Down) + Some(Down(1)) } else { None } @@ -395,41 +409,66 @@ enum TurtleMineMethod { #[derive(Serialize, Deserialize, Clone)] enum TurtleCommand { - Wait, - Forward, - Backward, - Up, - Down, + Wait(u32), + Forward(u32), + Backward(u32), + Up(u32), + Down(u32), Left, Right, Dig, DigUp, DigDown, - TakeInventory, + PlaceUp, + Place, + PlaceDown, + /// Count + DropFront(u32), + DropUp(u32), + DropDown(u32), + Select(u32), + /// Slot in inventory + ItemInfo(u32), Update, Poweroff, } +#[derive(Serialize, Deserialize, Clone, Debug)] +struct InventorySlot { + name: String, + count: u32, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +enum TurtleCommandResponse { + None, + Success, + Failure, + Item(InventorySlot), + Inventory(Vec), +} + impl TurtleCommand { fn delta(&self, direction: Direction) -> Vec3 { let dir = direction.unit(); match self { - TurtleCommand::Forward => dir, - TurtleCommand::Backward => -dir, - TurtleCommand::Up => Vec3::y(), - TurtleCommand::Down => -Vec3::y(), + TurtleCommand::Forward(count) => dir * *count as i32, + TurtleCommand::Backward(count) => -dir * *count as i32, + TurtleCommand::Up(count) => Vec3::y() * *count as i32, + TurtleCommand::Down(count) => -Vec3::y() * *count as i32, _ => Vec3::zeros(), } } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] struct TurtleUpdate { fuel: usize, /// Block name ahead: String, above: String, below: String, + ret: TurtleCommandResponse, } #[derive(Serialize, Deserialize)] diff --git a/server/src/turtle.rs b/server/src/turtle.rs index b27e525..3eecbb4 100644 --- a/server/src/turtle.rs +++ b/server/src/turtle.rs @@ -5,9 +5,15 @@ use crate::{blocks::{World, Block}, Position, Direction}; use super::Vec3; -pub fn route(from: Position, to: Position, world: &World) -> Vec { +pub fn route(from: Position, to: Position, world: &World) -> Option> { + // attempt at not crashing by looking infinitely into the abyss + if world.locate_at_point(&to.0.into()) + .is_some_and(|b| difficulty(&b.name).is_none()) { + return None; + + } let route = astar(&from, move |p| {next(p, world)} , |p1| {(p1.0 - &to.0).abs().sum() as u32}, |p| {p == &to}).unwrap(); - route.0 + Some(route.0) } fn next(from: &Position, world: &World) -> Vec<(Position, u32)> { @@ -24,8 +30,8 @@ fn next(from: &Position, world: &World) -> Vec<(Position, u32)> { let ahead = from.0 + from.1.unit(); insert(&mut vec, ahead, from.1, world, UNKNOWN); - let behind = from.0 - from.1.unit(); - insert(&mut vec, behind, from.1, world, None); + //let behind = from.0 - from.1.unit(); + //insert(&mut vec, behind, from.1, world, None); let above = from.0 + Vec3::y(); insert(&mut vec, above, from.1, world,UNKNOWN); @@ -37,10 +43,12 @@ fn next(from: &Position, world: &World) -> Vec<(Position, u32)> { } /// Blocks that are fine to tunnel through -const GARBAGE: [&str; 3] = [ +const GARBAGE: [&str; 5] = [ "minecraft:stone", "minecraft:dirt", "minecraft:andesite", + "minecraft:sand", + "minecraft:gravel", ]; /// time taken to go through uncharted territory (in turtle. calls) @@ -49,6 +57,6 @@ const UNKNOWN: Option = Some(2); // time to go somewhere fn difficulty(name: &str) -> Option { if name == "minecraft:air" { return Some(1) }; - //if GARBAGE.contains(&name) { return Some(2)}; + if GARBAGE.contains(&name) { return Some(2)}; None }