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 port = "48228"
|
||||||
local endpoint = "http://" .. ipaddr .. ":" .. port
|
local endpoint = "http://" .. ipaddr .. ":" .. port
|
||||||
|
|
||||||
|
@ -120,6 +136,10 @@ repeat
|
||||||
ret = turtle.digDown()
|
ret = turtle.digDown()
|
||||||
elseif command == "ItemInfo" then
|
elseif command == "ItemInfo" then
|
||||||
ret = { Item = turtle.getItemDetail(args) }
|
ret = { Item = turtle.getItemDetail(args) }
|
||||||
|
elseif command == "Refuel" then
|
||||||
|
refuel()
|
||||||
|
elseif command == "Dump" then
|
||||||
|
dump()
|
||||||
elseif command == "Update" then
|
elseif command == "Update" then
|
||||||
if not update({...}) then
|
if not update({...}) then
|
||||||
break
|
break
|
||||||
|
|
|
@ -10,14 +10,16 @@ anyhow = "1.0.75"
|
||||||
axum = "0.7.2"
|
axum = "0.7.2"
|
||||||
bit-struct = "0.3.2"
|
bit-struct = "0.3.2"
|
||||||
const_format = "0.2.32"
|
const_format = "0.2.32"
|
||||||
|
erased-serde = "0.4.1"
|
||||||
feistel_rs = "0.1.0"
|
feistel_rs = "0.1.0"
|
||||||
|
hilbert_index = "0.2.0"
|
||||||
hyper = "1.0.1"
|
hyper = "1.0.1"
|
||||||
hyper-util = "0.1.1"
|
hyper-util = "0.1.1"
|
||||||
nalgebra = { version = "0.32.3", features = ["serde-serialize"] }
|
nalgebra = { version = "0.32.3", features = ["serde-serialize"] }
|
||||||
pathfinding = "4.6.0"
|
pathfinding = "4.6.0"
|
||||||
rstar = { version = "0.11.0", features = ["serde"] }
|
rstar = { version = "0.11.0", features = ["serde"] }
|
||||||
rustmatica = "0.1.1"
|
rustmatica = "0.1.1"
|
||||||
serde = "1.0.193"
|
serde = { version = "1.0.193", features = ["rc"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
tokio = { version = "1.0", features = ["full"] }
|
||||||
tower = { version = "0.4", features = ["util", "timeout", "load-shed", "limit"] }
|
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"
|
tower-layer = "0.3.2"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
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,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use blocks::{World, Position};
|
use blocks::{World, Position};
|
||||||
|
use mine::TurtleMineJob;
|
||||||
use rstar::{self, AABB};
|
use rstar::{self, AABB};
|
||||||
|
|
||||||
use const_format::formatcp;
|
use const_format::formatcp;
|
||||||
|
@ -20,6 +21,7 @@ use tokio::sync::{
|
||||||
Mutex, RwLock,
|
Mutex, RwLock,
|
||||||
};
|
};
|
||||||
use tower::Service;
|
use tower::Service;
|
||||||
|
use turtle::TurtleTask;
|
||||||
|
|
||||||
use crate::{blocks::Block, paths::route};
|
use crate::{blocks::Block, paths::route};
|
||||||
|
|
||||||
|
@ -113,7 +115,9 @@ async fn set_goal(
|
||||||
State(state): State<SharedControl>,
|
State(state): State<SharedControl>,
|
||||||
Json(req): Json<Position>,
|
Json(req): Json<Position>,
|
||||||
) -> &'static str {
|
) -> &'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"
|
"ACK"
|
||||||
}
|
}
|
||||||
|
@ -135,11 +139,7 @@ async fn turtle_info(
|
||||||
let state = &mut state.read().await;
|
let state = &mut state.read().await;
|
||||||
let turtle = &state.turtles[id as usize];
|
let turtle = &state.turtles[id as usize];
|
||||||
|
|
||||||
let mut pseudomoves: VecDeque<turtle::TurtleCommand> = VecDeque::new();
|
let tasks: VecDeque<Arc<dyn TurtleTask + Send + Sync>> = VecDeque::new();
|
||||||
turtle
|
|
||||||
.moves
|
|
||||||
.front()
|
|
||||||
.map(|m| pseudomoves.push_front(m.clone()));
|
|
||||||
|
|
||||||
let cloned = turtle::Turtle {
|
let cloned = turtle::Turtle {
|
||||||
name: turtle.name.clone(),
|
name: turtle.name.clone(),
|
||||||
|
@ -148,7 +148,7 @@ async fn turtle_info(
|
||||||
position: turtle.position.clone(),
|
position: turtle.position.clone(),
|
||||||
goal: turtle.goal.clone(),
|
goal: turtle.goal.clone(),
|
||||||
pending_update: turtle.pending_update,
|
pending_update: turtle.pending_update,
|
||||||
moves: pseudomoves,
|
tasks,
|
||||||
};
|
};
|
||||||
|
|
||||||
Json(cloned)
|
Json(cloned)
|
||||||
|
|
|
@ -3,16 +3,19 @@ use crate::blocks::Block;
|
||||||
use crate::blocks::Direction;
|
use crate::blocks::Direction;
|
||||||
use crate::blocks::Position;
|
use crate::blocks::Position;
|
||||||
use crate::blocks::Vec3;
|
use crate::blocks::Vec3;
|
||||||
|
use crate::blocks::nearest;
|
||||||
use crate::mine::TurtleMineJob;
|
use crate::mine::TurtleMineJob;
|
||||||
|
|
||||||
use anyhow::Ok;
|
use anyhow::Ok;
|
||||||
|
|
||||||
use anyhow;
|
use anyhow;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use super::ControlState;
|
use super::ControlState;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
||||||
use super::names::Name;
|
use super::names::Name;
|
||||||
|
@ -29,9 +32,24 @@ pub(crate) struct Turtle {
|
||||||
/// movement vector of last given command
|
/// movement vector of last given command
|
||||||
pub(crate) queued_movement: Vec3,
|
pub(crate) queued_movement: Vec3,
|
||||||
pub(crate) position: Position,
|
pub(crate) position: Position,
|
||||||
pub(crate) goal: Option<Position>,
|
pub(crate) goal: Option<Iota>,
|
||||||
pub(crate) pending_update: bool,
|
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 {
|
impl Turtle {
|
||||||
|
@ -43,9 +61,13 @@ impl Turtle {
|
||||||
position: (position, facing),
|
position: (position, facing),
|
||||||
goal: None,
|
goal: None,
|
||||||
pending_update: true,
|
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(
|
pub(crate) fn process_turtle_update(
|
||||||
|
@ -64,10 +86,6 @@ pub(crate) fn process_turtle_update(
|
||||||
return Ok(TurtleCommand::Update);
|
return Ok(TurtleCommand::Update);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
|
||||||
"above: {}, below: {}, ahead: {}",
|
|
||||||
update.above, update.below, update.ahead
|
|
||||||
);
|
|
||||||
if turtle.fuel != update.fuel {
|
if turtle.fuel != update.fuel {
|
||||||
turtle.fuel = update.fuel;
|
turtle.fuel = update.fuel;
|
||||||
|
|
||||||
|
@ -96,15 +114,45 @@ pub(crate) fn process_turtle_update(
|
||||||
world.remove_at_point(&below.pos.into());
|
world.remove_at_point(&below.pos.into());
|
||||||
world.insert(below);
|
world.insert(below);
|
||||||
|
|
||||||
if turtle.goal.is_some_and(|g| g == turtle.position) {
|
if let Some(task) = turtle.tasks.front() {
|
||||||
turtle.goal = None;
|
task.handle_block(above);
|
||||||
|
task.handle_block(below);
|
||||||
|
task.handle_block(ahead);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(goal) = turtle.goal {
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pathstep(turtle: &mut Turtle, world: &mut rstar::RTree<Block>, goal: Position) -> Option<TurtleCommand> {
|
||||||
// TODO: memoize this whenever we aren't digging
|
// TODO: memoize this whenever we aren't digging
|
||||||
let route = route(turtle.position, goal, world).unwrap();
|
let route = route(turtle.position, goal, world)?;
|
||||||
println!("route: {:?}", route);
|
let mut next_move = difference(route[0], route[1])?;
|
||||||
let mut next_move = difference(route[0], route[1]).unwrap();
|
|
||||||
if world
|
if world
|
||||||
.locate_at_point(&route[1].0.into())
|
.locate_at_point(&route[1].0.into())
|
||||||
.is_some_and(|b| b.name != "minecraft:air")
|
.is_some_and(|b| b.name != "minecraft:air")
|
||||||
|
@ -122,19 +170,10 @@ pub(crate) fn process_turtle_update(
|
||||||
TurtleCommand::Right => turtle.position.1 = turtle.position.1.right(),
|
TurtleCommand::Right => turtle.position.1 = turtle.position.1.right(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
return Ok(next_move);
|
return Some(next_move);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(TurtleCommand::Wait(3))
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
pub(crate) enum TurtleTask {
|
|
||||||
Mining(TurtleMineJob),
|
|
||||||
Idle,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
|
||||||
pub(crate) enum TurtleCommand {
|
pub(crate) enum TurtleCommand {
|
||||||
Wait(u32),
|
Wait(u32),
|
||||||
Forward(u32),
|
Forward(u32),
|
||||||
|
@ -158,6 +197,8 @@ pub(crate) enum TurtleCommand {
|
||||||
ItemInfo(u32),
|
ItemInfo(u32),
|
||||||
Update,
|
Update,
|
||||||
Poweroff,
|
Poweroff,
|
||||||
|
Refuel,
|
||||||
|
Dump,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
@ -240,3 +281,19 @@ fn difference(from: Position, to: Position) -> Option<TurtleCommand> {
|
||||||
None
|
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