1
Fork 0

exec api (global state in limbo)

This commit is contained in:
Andy Killorin 2023-12-19 07:43:10 -06:00
parent fef8f7bce3
commit 715520801d
Signed by: ank
GPG key ID: B6241CA3B552BCA4
3 changed files with 61 additions and 26 deletions

View file

@ -12,10 +12,12 @@ bit-struct = "0.3.2"
const_format = "0.2.32" const_format = "0.2.32"
erased-serde = "0.4.1" erased-serde = "0.4.1"
feistel_rs = "0.1.0" feistel_rs = "0.1.0"
future-parking_lot = "0.3.3"
hilbert_index = "0.2.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"] }
parking_lot = { version = "0.11", features = ["serde"] }
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"

View file

@ -1,3 +1,5 @@
#![feature(iter_map_windows)]
use std::{collections::VecDeque, io::ErrorKind, sync::Arc}; use std::{collections::VecDeque, io::ErrorKind, sync::Arc};
use anyhow::{Context, Error, Ok}; use anyhow::{Context, Error, Ok};
@ -21,7 +23,7 @@ use tokio::sync::{
Mutex, RwLock, mpsc Mutex, RwLock, mpsc
}; };
use tower::Service; use tower::Service;
use turtle::{TurtleTask, Iota, Receiver, Sender, Turtle, TurtleUpdate}; use turtle::{TurtleTask, Iota, Receiver, Sender, Turtle, TurtleUpdate, TurtleInfo};
use crate::{blocks::Block, paths::route}; use crate::{blocks::Block, paths::route};
@ -127,11 +129,11 @@ async fn create_turtle(
async fn place_up( async fn place_up(
Path(id): Path<u32>, Path(id): Path<u32>,
State(state): State<SharedControl>, State(state): State<SharedControl>,
) -> Json<TurtleUpdate> { ) -> Json<TurtleInfo> {
let turtle = state.write().await.saved.turtles.get(id as usize).unwrap() let turtle = state.write().await.saved.turtles.get(id as usize).unwrap()
.cmd(); .cmd();
Json(turtle.execute(Iota::Execute(turtle::TurtleCommand::PlaceUp)).await) Json(turtle.execute(turtle::TurtleCommand::PlaceUp).await)
} }
async fn set_goal( async fn set_goal(
@ -139,9 +141,10 @@ 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.saved.tasks[id as usize].push_back( state.read().await.saved.turtles[id as usize].cmd().goto(req).await;
TurtleMineJob::chunk(req.0) //state.write().await.saved.tasks[id as usize].push_back(
); // TurtleMineJob::chunk(req.0)
//);
"ACK" "ACK"
} }

View file

@ -38,15 +38,34 @@ pub(crate) struct Turtle {
pub(crate) goal: Option<Iota>, pub(crate) goal: Option<Iota>,
pub(crate) pending_update: bool, pub(crate) pending_update: bool,
#[serde(skip)] #[serde(skip)]
callback: Option<oneshot::Sender<TurtleUpdate>>, callback: Option<oneshot::Sender<TurtleInfo>>,
#[serde(skip)] #[serde(skip)]
sender: Option<Arc<Sender>>, sender: Option<Arc<Sender>>,
#[serde(skip)] #[serde(skip)]
receiver: Option<Receiver>, receiver: Option<Receiver>,
} }
pub type Sender = mpsc::Sender<(Iota, oneshot::Sender<TurtleUpdate>)>; #[derive(Debug)]
pub type Receiver = mpsc::Receiver<(Iota, oneshot::Sender<TurtleUpdate>)>; pub struct TurtleInfo {
pub name: Name,
pub pos: Position,
pub fuel: usize,
/// Block name
pub ahead: String,
pub above: String,
pub below: String,
pub ret: TurtleCommandResponse,
}
impl TurtleInfo {
fn from_update(update: TurtleUpdate, name: Name, pos: Position) -> Self {
Self { name, pos,
fuel: update.fuel, ahead: update.ahead, above: update.above, below: update.below, ret: update.ret }
}
}
pub type Sender = mpsc::Sender<(TurtleCommand, oneshot::Sender<TurtleInfo>)>;
pub type Receiver = mpsc::Receiver<(TurtleCommand, oneshot::Sender<TurtleInfo>)>;
impl Default for Turtle { impl Default for Turtle {
fn default() -> Self { fn default() -> Self {
@ -102,25 +121,40 @@ pub struct TurtleCommander {
} }
impl TurtleCommander { impl TurtleCommander {
pub async fn execute(&self, command: Iota) -> TurtleUpdate { pub async fn execute(&self, command: TurtleCommand) -> TurtleInfo {
let (send, recv) = oneshot::channel::<TurtleUpdate>(); let (send, recv) = oneshot::channel::<TurtleInfo>();
self.sender.to_owned().send((command,send)).await.unwrap(); self.sender.to_owned().send((command,send)).await.unwrap();
recv.await.unwrap() recv.await.unwrap()
} }
}
pub async fn command(&self, command: TurtleCommand) -> TurtleUpdate { async fn goto(cmd: &TurtleCommander, recent: TurtleInfo, pos: Position, world: &rstar::RTree<Block>) -> Option<()> {
self.execute(Iota::Execute(command)).await let mut recent = recent.pos;
} loop {
if recent == pos {
break;
}
pub async fn goto(&self, pos: Position) -> TurtleUpdate { let route = route(recent, pos, world)?;
self.execute(Iota::Goto(pos)).await
}
pub async fn mine(&self, pos: Vec3) -> TurtleUpdate { let steps: Vec<TurtleCommand> = route.iter().map_windows(|[from,to]| difference(**from,**to).unwrap()).collect();
self.execute(Iota::Mine(pos)).await
'route: for (next_position, command) in route.into_iter().skip(1).zip(steps) {
// reroute if the goal point is not empty before moving
// valid routes will explicitly tell you to break ground
if world.locate_at_point(&next_position.0.into()).unwrap().name != "minecraft:air" {
break 'route;
}
let state = cmd.execute(command).await;
recent = state.pos;
}
} }
Some(())
} }
pub(crate) async fn process_turtle_update( pub(crate) async fn process_turtle_update(
@ -171,21 +205,17 @@ pub(crate) async fn process_turtle_update(
world.remove_at_point(&below.pos.into()); world.remove_at_point(&below.pos.into());
world.insert(below.clone()); world.insert(below.clone());
if let Some(task) = tasks.front_mut() { let info = TurtleInfo::from_update(update, turtle.name.clone(), turtle.position.clone());
task.handle_block(above);
task.handle_block(below);
task.handle_block(ahead);
}
if let Some(send) = turtle.callback.take() { if let Some(send) = turtle.callback.take() {
send.send(update).unwrap(); send.send(info).unwrap();
} }
if let Some(recv) = turtle.receiver.as_mut() { if let Some(recv) = turtle.receiver.as_mut() {
if let Some((cmd, ret)) = recv.try_recv().ok() { if let Some((cmd, ret)) = recv.try_recv().ok() {
turtle.callback = Some(ret); turtle.callback = Some(ret);
turtle.goal = Some(cmd); return Ok(cmd);
} }
} }