tasks (in progress)
This commit is contained in:
parent
e01ef3d10d
commit
6d77acff8a
5 changed files with 149 additions and 46 deletions
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue