1
Fork 0

tasks (in progress)

This commit is contained in:
Andy Killorin 2023-12-17 19:53:21 -06:00
parent e01ef3d10d
commit 6d77acff8a
Signed by: ank
GPG key ID: B6241CA3B552BCA4
5 changed files with 149 additions and 46 deletions

View file

@ -1,3 +1,19 @@
local function refuel()
turtle.select(16)
turtle.dropUp()
while turtle.getFuelLevel() ~= turtle.getFuelLimit() do
turtle.suck()
turtle.refuel()
end
end
local function dump()
for i = 1, 16, 1 do
turtle.select(i)
turtle.drop()
end
end
local port = "48228"
local endpoint = "http://" .. ipaddr .. ":" .. port
@ -120,6 +136,10 @@ repeat
ret = turtle.digDown()
elseif command == "ItemInfo" then
ret = { Item = turtle.getItemDetail(args) }
elseif command == "Refuel" then
refuel()
elseif command == "Dump" then
dump()
elseif command == "Update" then
if not update({...}) then
break

View file

@ -10,14 +10,16 @@ anyhow = "1.0.75"
axum = "0.7.2"
bit-struct = "0.3.2"
const_format = "0.2.32"
erased-serde = "0.4.1"
feistel_rs = "0.1.0"
hilbert_index = "0.2.0"
hyper = "1.0.1"
hyper-util = "0.1.1"
nalgebra = { version = "0.32.3", features = ["serde-serialize"] }
pathfinding = "4.6.0"
rstar = { version = "0.11.0", features = ["serde"] }
rustmatica = "0.1.1"
serde = "1.0.193"
serde = { version = "1.0.193", features = ["rc"] }
serde_json = "1.0.108"
tokio = { version = "1.0", features = ["full"] }
tower = { version = "0.4", features = ["util", "timeout", "load-shed", "limit"] }
@ -31,3 +33,4 @@ tower-http = { version = "0.5.0", features = [
tower-layer = "0.3.2"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
typetag = "0.2.14"

View file

@ -62,3 +62,26 @@ impl Direction {
}
}
}
/// closest valid state to the given point from where you are
pub fn nearest(from: Vec3, to: Vec3) -> Position {
let diff = to.xz()-from.xz();
let dir = if diff.x.abs() > diff.y.abs() {
if diff.x > 0 {
Direction::East
} else {
Direction::West
}
} else {
if diff.y > 0 {
Direction::South
} else {
Direction::South
}
};
(
to - dir.unit(),
dir
)
}

View file

@ -8,6 +8,7 @@ use axum::{
Json, Router,
};
use blocks::{World, Position};
use mine::TurtleMineJob;
use rstar::{self, AABB};
use const_format::formatcp;
@ -20,6 +21,7 @@ use tokio::sync::{
Mutex, RwLock,
};
use tower::Service;
use turtle::TurtleTask;
use crate::{blocks::Block, paths::route};
@ -113,7 +115,9 @@ async fn set_goal(
State(state): State<SharedControl>,
Json(req): Json<Position>,
) -> &'static str {
state.write().await.turtles[id as usize].goal = Some(req);
state.write().await.turtles[id as usize].add_task(
TurtleMineJob::chunk(req.0)
);
"ACK"
}
@ -135,11 +139,7 @@ async fn turtle_info(
let state = &mut state.read().await;
let turtle = &state.turtles[id as usize];
let mut pseudomoves: VecDeque<turtle::TurtleCommand> = VecDeque::new();
turtle
.moves
.front()
.map(|m| pseudomoves.push_front(m.clone()));
let tasks: VecDeque<Arc<dyn TurtleTask + Send + Sync>> = VecDeque::new();
let cloned = turtle::Turtle {
name: turtle.name.clone(),
@ -148,7 +148,7 @@ async fn turtle_info(
position: turtle.position.clone(),
goal: turtle.goal.clone(),
pending_update: turtle.pending_update,
moves: pseudomoves,
tasks,
};
Json(cloned)

View file

@ -3,16 +3,19 @@ use crate::blocks::Block;
use crate::blocks::Direction;
use crate::blocks::Position;
use crate::blocks::Vec3;
use crate::blocks::nearest;
use crate::mine::TurtleMineJob;
use anyhow::Ok;
use anyhow;
use anyhow::Context;
use tokio::sync::RwLock;
use super::ControlState;
use std::collections::VecDeque;
use std::sync::Arc;
use super::names::Name;
@ -29,9 +32,24 @@ pub(crate) struct Turtle {
/// movement vector of last given command
pub(crate) queued_movement: Vec3,
pub(crate) position: Position,
pub(crate) goal: Option<Position>,
pub(crate) goal: Option<Iota>,
pub(crate) pending_update: bool,
pub(crate) moves: VecDeque<TurtleCommand>,
#[serde(skip)]
pub(crate) tasks: VecDeque<RwLock<Arc<dyn TurtleTask + Send + Sync>>>,
}
impl Default for Turtle {
fn default() -> Self {
Self {
name: Name::from_num(0),
fuel: Default::default(),
queued_movement: Default::default(),
position: (Vec3::zeros(), Direction::North),
goal: Default::default(),
pending_update: Default::default(),
tasks: VecDeque::new(),
}
}
}
impl Turtle {
@ -43,9 +61,13 @@ impl Turtle {
position: (position, facing),
goal: None,
pending_update: true,
moves: VecDeque::new(),
tasks: VecDeque::new(),
}
}
pub fn add_task(&mut self, task: impl TurtleTask + Send + Sync) {
self.tasks.push_back(Arc::new(task));
}
}
pub(crate) fn process_turtle_update(
@ -64,10 +86,6 @@ pub(crate) fn process_turtle_update(
return Ok(TurtleCommand::Update);
}
println!(
"above: {}, below: {}, ahead: {}",
update.above, update.below, update.ahead
);
if turtle.fuel != update.fuel {
turtle.fuel = update.fuel;
@ -96,45 +114,66 @@ pub(crate) fn process_turtle_update(
world.remove_at_point(&below.pos.into());
world.insert(below);
if turtle.goal.is_some_and(|g| g == turtle.position) {
turtle.goal = None;
if let Some(task) = turtle.tasks.front() {
task.handle_block(above);
task.handle_block(below);
task.handle_block(ahead);
}
if let Some(goal) = turtle.goal {
// TODO: memoize this whenever we aren't digging
let route = route(turtle.position, goal, world).unwrap();
println!("route: {:?}", route);
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(),
TurtleCommand::Right => turtle.position.1 = turtle.position.1.right(),
_ => {}
}
return Ok(next_move);
}
if let Some(goal) = turtle.tasks.front().map(|t| t.next(&turtle)) {
let command = match goal {
Iota::End => {
turtle.tasks.pop_front();
TurtleCommand::Wait(0) // TODO: fix
},
Iota::Goto(pos) => {
pathstep(turtle, world, pos).unwrap()
},
Iota::Mine(pos) => {
let pos = nearest(turtle.position.0, pos);
if pos == turtle.position {
TurtleCommand::Dig
} else {
pathstep(turtle, world, pos).unwrap()
}
},
Iota::Execute(cmd) => {
cmd
},
};
return Ok(command);
};
Ok(TurtleCommand::Wait(3))
}
#[derive(Serialize, Deserialize)]
pub(crate) enum TurtleTask {
Mining(TurtleMineJob),
Idle,
fn pathstep(turtle: &mut Turtle, world: &mut rstar::RTree<Block>, goal: Position) -> Option<TurtleCommand> {
// TODO: memoize this whenever we aren't digging
let route = route(turtle.position, goal, world)?;
let mut next_move = difference(route[0], route[1])?;
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(),
TurtleCommand::Right => turtle.position.1 = turtle.position.1.right(),
_ => {}
}
return Some(next_move);
}
#[derive(Serialize, Deserialize, Clone)]
#[derive(Serialize, Deserialize, Clone, Debug)]
pub(crate) enum TurtleCommand {
Wait(u32),
Forward(u32),
@ -158,6 +197,8 @@ pub(crate) enum TurtleCommand {
ItemInfo(u32),
Update,
Poweroff,
Refuel,
Dump,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
@ -240,3 +281,19 @@ fn difference(from: Position, to: Position) -> Option<TurtleCommand> {
None
}
}
#[derive(Serialize, Deserialize, Clone)]
pub enum Iota {
End,
Goto(Position),
Mine(Vec3),
Execute(TurtleCommand),
}
pub trait TurtleTask: erased_serde::Serialize {
fn handle_block(&mut self, _: Block) { }
fn next(&mut self, turtle: &Turtle) -> Iota
{ Iota::End }
}
erased_serde::serialize_trait_object!(TurtleTask);