1
Fork 0

authorized digging

This commit is contained in:
Andy Killorin 2023-12-17 15:28:18 -06:00
parent 42eff1af2b
commit 96a8de6858
Signed by: ank
GPG key ID: B6241CA3B552BCA4
3 changed files with 152 additions and 59 deletions

View file

@ -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 not ipaddr then
if fs.exists("/disk/ip") then if fs.exists("/disk/ip") then
local ipfile = fs.open("/disk/ip") local ipfile = fs.open("/disk/ip")
@ -9,10 +44,6 @@ if not ipaddr then
end end
end end
local port = "48228"
local endpoint = "http://" .. ipaddr .. ":" .. port
local idfile = fs.open("id", "r") local idfile = fs.open("id", "r")
local id = nil local id = nil
@ -60,41 +91,54 @@ end
repeat repeat
print(command) print(command)
local args = nil
if type(command) == "table" then
command, args = pairs(command)(command)
end
local ret = nil
if command == "Wait" then if command == "Wait" then
sleep(5) sleep(args)
elseif command == "Forward" then elseif command == "Forward" then
turtle.forward() ret = cycle(turtle.forward, args)
elseif command == "Backward" then elseif command == "Backward" then
turtle.back() ret = cycle(turtle.back, args)
elseif command == "Left" then elseif command == "Left" then
turtle.turnLeft() ret = turtle.turnLeft()
elseif command == "Right" then elseif command == "Right" then
turtle.turnRight() ret = turtle.turnRight()
elseif command == "Up" then elseif command == "Up" then
turtle.up() ret = cycle(turtle.up, args)
elseif command == "Down" then 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 elseif command == "Update" then
args = {...} if not update({...}) then
if args[1] == "nested" then
-- no exec = stack overflow
break break
end end
local req = http.get(endpoint .. "/turtle/client.lua") end
if not req then
os.reboot() local ret_table = nil
if type(ret) == "boolean" then
if ret then
ret_table = "Success"
else
ret_table = "Failure"
end end
local update = req.readAll() else
req.close() ret_table = ret
fs.delete("startup-backup") end
if fs.exists("/startup") then
-- pcall does not work with cc fs if not ret_table then
fs.move("startup", "startup-backup") ret_table = "None"
end
local startup = fs.open("startup", "w")
startup.write(update)
startup.close()
shell.run("startup", "nested")
end end
local ahead = "minecraft:air" local ahead = "minecraft:air"
@ -119,8 +163,10 @@ repeat
fuel = turtle.getFuelLevel(), fuel = turtle.getFuelLevel(),
ahead = ahead, ahead = ahead,
above = above, above = above,
below = below below = below,
ret = ret_table,
} }
print(info.ret)
local rsp = http.post( local rsp = http.post(
endpoint .. "/turtle/" .. id .. "/update" , endpoint .. "/turtle/" .. id .. "/update" ,

View file

@ -10,7 +10,7 @@ use rstar::{self, AABB};
mod names; mod names;
use names::Name; use names::Name;
use tokio::{sync::{Mutex, RwLock, watch}, signal}; use tokio::{sync::{Mutex, RwLock, watch::{self, Sender}}, signal};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use const_format::formatcp; use const_format::formatcp;
use hyper_util::rt::TokioIo; use hyper_util::rt::TokioIo;
@ -116,14 +116,18 @@ async fn main() -> Result<(), Error> {
.route("/flush", get(flush)) .route("/flush", get(flush))
.with_state(state.clone()); .with_state(state.clone());
serve(server).await;
let server = serve(server).await;
println!("writing");
write_to_disk(state).await?; write_to_disk(state).await?;
server.closed().await;
Ok(()) 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 listener = tokio::net::TcpListener::bind("0.0.0.0:48228").await.unwrap();
let (close_tx, close_rx) = watch::channel(()); 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(); let close_rx = close_rx.clone();
tokio::spawn(async move { tokio::spawn(async move {
@ -175,7 +179,7 @@ async fn serve(serv: Router) {
drop(listener); drop(listener);
close_tx.closed().await; close_tx
} }
async fn write_to_disk(state: SharedControl) -> anyhow::Result<()> { async fn write_to_disk(state: SharedControl) -> anyhow::Result<()> {
@ -259,13 +263,14 @@ async fn command(
) -> Json<TurtleCommand> { ) -> Json<TurtleCommand> {
let mut state = &mut state.write().await; let mut state = &mut state.write().await;
println!("{:?}", &req);
if id as usize > state.turtles.len() { if id as usize > state.turtles.len() {
return Json(TurtleCommand::Update); return Json(TurtleCommand::Update);
} }
Json( Json(
process_turtle_update(id, &mut state, req).unwrap_or(TurtleCommand::Update), 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 { if let Some(goal) = turtle.goal {
// TODO: memoize this whenever we aren't digging // 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); 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); turtle.queued_movement = next_move.delta(turtle.position.1);
match next_move { match next_move {
TurtleCommand::Left => turtle.position.1 = turtle.position.1.left(), TurtleCommand::Left => turtle.position.1 = turtle.position.1.left(),
@ -329,7 +343,7 @@ fn process_turtle_update(
return Ok(next_move); return Ok(next_move);
} }
Ok(TurtleCommand::Wait) Ok(TurtleCommand::Wait(3))
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -354,13 +368,13 @@ fn difference(from: Position, to: Position) -> Option<TurtleCommand> {
} }
} else if to.1 == from.1 { } else if to.1 == from.1 {
if to.0 == from.0 + from.1.unit() { if to.0 == from.0 + from.1.unit() {
Some(Forward) Some(Forward(1))
} else if to.0 == from.0 - from.1.unit() { } else if to.0 == from.0 - from.1.unit() {
Some(Backward) Some(Backward(1))
} else if to.0 == from.0 + Vec3::y() { } else if to.0 == from.0 + Vec3::y() {
Some(Up) Some(Up(1))
} else if to.0 == from.0 - Vec3::y() { } else if to.0 == from.0 - Vec3::y() {
Some(Down) Some(Down(1))
} else { } else {
None None
} }
@ -395,41 +409,66 @@ enum TurtleMineMethod {
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
enum TurtleCommand { enum TurtleCommand {
Wait, Wait(u32),
Forward, Forward(u32),
Backward, Backward(u32),
Up, Up(u32),
Down, Down(u32),
Left, Left,
Right, Right,
Dig, Dig,
DigUp, DigUp,
DigDown, DigDown,
TakeInventory, PlaceUp,
Place,
PlaceDown,
/// Count
DropFront(u32),
DropUp(u32),
DropDown(u32),
Select(u32),
/// Slot in inventory
ItemInfo(u32),
Update, Update,
Poweroff, 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<InventorySlot>),
}
impl TurtleCommand { impl TurtleCommand {
fn delta(&self, direction: Direction) -> Vec3 { fn delta(&self, direction: Direction) -> Vec3 {
let dir = direction.unit(); let dir = direction.unit();
match self { match self {
TurtleCommand::Forward => dir, TurtleCommand::Forward(count) => dir * *count as i32,
TurtleCommand::Backward => -dir, TurtleCommand::Backward(count) => -dir * *count as i32,
TurtleCommand::Up => Vec3::y(), TurtleCommand::Up(count) => Vec3::y() * *count as i32,
TurtleCommand::Down => -Vec3::y(), TurtleCommand::Down(count) => -Vec3::y() * *count as i32,
_ => Vec3::zeros(), _ => Vec3::zeros(),
} }
} }
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug)]
struct TurtleUpdate { struct TurtleUpdate {
fuel: usize, fuel: usize,
/// Block name /// Block name
ahead: String, ahead: String,
above: String, above: String,
below: String, below: String,
ret: TurtleCommandResponse,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]

View file

@ -5,9 +5,15 @@ use crate::{blocks::{World, Block}, Position, Direction};
use super::Vec3; use super::Vec3;
pub fn route(from: Position, to: Position, world: &World) -> Vec<Position> { pub fn route(from: Position, to: Position, world: &World) -> Option<Vec<Position>> {
// 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(); 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)> { 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(); let ahead = from.0 + from.1.unit();
insert(&mut vec, ahead, from.1, world, UNKNOWN); insert(&mut vec, ahead, from.1, world, UNKNOWN);
let behind = from.0 - from.1.unit(); //let behind = from.0 - from.1.unit();
insert(&mut vec, behind, from.1, world, None); //insert(&mut vec, behind, from.1, world, None);
let above = from.0 + Vec3::y(); let above = from.0 + Vec3::y();
insert(&mut vec, above, from.1, world,UNKNOWN); 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 /// Blocks that are fine to tunnel through
const GARBAGE: [&str; 3] = [ const GARBAGE: [&str; 5] = [
"minecraft:stone", "minecraft:stone",
"minecraft:dirt", "minecraft:dirt",
"minecraft:andesite", "minecraft:andesite",
"minecraft:sand",
"minecraft:gravel",
]; ];
/// time taken to go through uncharted territory (in turtle. calls) /// time taken to go through uncharted territory (in turtle. calls)
@ -49,6 +57,6 @@ const UNKNOWN: Option<u32> = Some(2);
// time to go somewhere // time to go somewhere
fn difficulty(name: &str) -> Option<u32> { fn difficulty(name: &str) -> Option<u32> {
if name == "minecraft:air" { return Some(1) }; if name == "minecraft:air" { return Some(1) };
//if GARBAGE.contains(&name) { return Some(2)}; if GARBAGE.contains(&name) { return Some(2)};
None None
} }