exec api (global state in limbo)
This commit is contained in:
parent
fef8f7bce3
commit
715520801d
3 changed files with 61 additions and 26 deletions
|
@ -12,10 +12,12 @@ bit-struct = "0.3.2"
|
|||
const_format = "0.2.32"
|
||||
erased-serde = "0.4.1"
|
||||
feistel_rs = "0.1.0"
|
||||
future-parking_lot = "0.3.3"
|
||||
hilbert_index = "0.2.0"
|
||||
hyper = "1.0.1"
|
||||
hyper-util = "0.1.1"
|
||||
nalgebra = { version = "0.32.3", features = ["serde-serialize"] }
|
||||
parking_lot = { version = "0.11", features = ["serde"] }
|
||||
pathfinding = "4.6.0"
|
||||
rstar = { version = "0.11.0", features = ["serde"] }
|
||||
rustmatica = "0.1.1"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#![feature(iter_map_windows)]
|
||||
|
||||
use std::{collections::VecDeque, io::ErrorKind, sync::Arc};
|
||||
|
||||
use anyhow::{Context, Error, Ok};
|
||||
|
@ -21,7 +23,7 @@ use tokio::sync::{
|
|||
Mutex, RwLock, mpsc
|
||||
};
|
||||
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};
|
||||
|
||||
|
@ -127,11 +129,11 @@ async fn create_turtle(
|
|||
async fn place_up(
|
||||
Path(id): Path<u32>,
|
||||
State(state): State<SharedControl>,
|
||||
) -> Json<TurtleUpdate> {
|
||||
) -> Json<TurtleInfo> {
|
||||
let turtle = state.write().await.saved.turtles.get(id as usize).unwrap()
|
||||
.cmd();
|
||||
|
||||
Json(turtle.execute(Iota::Execute(turtle::TurtleCommand::PlaceUp)).await)
|
||||
Json(turtle.execute(turtle::TurtleCommand::PlaceUp).await)
|
||||
}
|
||||
|
||||
async fn set_goal(
|
||||
|
@ -139,9 +141,10 @@ async fn set_goal(
|
|||
State(state): State<SharedControl>,
|
||||
Json(req): Json<Position>,
|
||||
) -> &'static str {
|
||||
state.write().await.saved.tasks[id as usize].push_back(
|
||||
TurtleMineJob::chunk(req.0)
|
||||
);
|
||||
state.read().await.saved.turtles[id as usize].cmd().goto(req).await;
|
||||
//state.write().await.saved.tasks[id as usize].push_back(
|
||||
// TurtleMineJob::chunk(req.0)
|
||||
//);
|
||||
|
||||
"ACK"
|
||||
}
|
||||
|
|
|
@ -38,15 +38,34 @@ pub(crate) struct Turtle {
|
|||
pub(crate) goal: Option<Iota>,
|
||||
pub(crate) pending_update: bool,
|
||||
#[serde(skip)]
|
||||
callback: Option<oneshot::Sender<TurtleUpdate>>,
|
||||
callback: Option<oneshot::Sender<TurtleInfo>>,
|
||||
#[serde(skip)]
|
||||
sender: Option<Arc<Sender>>,
|
||||
#[serde(skip)]
|
||||
receiver: Option<Receiver>,
|
||||
}
|
||||
|
||||
pub type Sender = mpsc::Sender<(Iota, oneshot::Sender<TurtleUpdate>)>;
|
||||
pub type Receiver = mpsc::Receiver<(Iota, oneshot::Sender<TurtleUpdate>)>;
|
||||
#[derive(Debug)]
|
||||
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 {
|
||||
fn default() -> Self {
|
||||
|
@ -102,25 +121,40 @@ pub struct TurtleCommander {
|
|||
}
|
||||
|
||||
impl TurtleCommander {
|
||||
pub async fn execute(&self, command: Iota) -> TurtleUpdate {
|
||||
let (send, recv) = oneshot::channel::<TurtleUpdate>();
|
||||
pub async fn execute(&self, command: TurtleCommand) -> TurtleInfo {
|
||||
let (send, recv) = oneshot::channel::<TurtleInfo>();
|
||||
|
||||
self.sender.to_owned().send((command,send)).await.unwrap();
|
||||
|
||||
recv.await.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn command(&self, command: TurtleCommand) -> TurtleUpdate {
|
||||
self.execute(Iota::Execute(command)).await
|
||||
async fn goto(cmd: &TurtleCommander, recent: TurtleInfo, pos: Position, world: &rstar::RTree<Block>) -> Option<()> {
|
||||
let mut recent = recent.pos;
|
||||
loop {
|
||||
if recent == pos {
|
||||
break;
|
||||
}
|
||||
|
||||
pub async fn goto(&self, pos: Position) -> TurtleUpdate {
|
||||
self.execute(Iota::Goto(pos)).await
|
||||
let route = route(recent, pos, world)?;
|
||||
|
||||
let steps: Vec<TurtleCommand> = route.iter().map_windows(|[from,to]| difference(**from,**to).unwrap()).collect();
|
||||
|
||||
'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;
|
||||
}
|
||||
|
||||
pub async fn mine(&self, pos: Vec3) -> TurtleUpdate {
|
||||
self.execute(Iota::Mine(pos)).await
|
||||
let state = cmd.execute(command).await;
|
||||
recent = state.pos;
|
||||
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
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.insert(below.clone());
|
||||
|
||||
if let Some(task) = tasks.front_mut() {
|
||||
task.handle_block(above);
|
||||
task.handle_block(below);
|
||||
task.handle_block(ahead);
|
||||
}
|
||||
let info = TurtleInfo::from_update(update, turtle.name.clone(), turtle.position.clone());
|
||||
|
||||
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((cmd, ret)) = recv.try_recv().ok() {
|
||||
turtle.callback = Some(ret);
|
||||
|
||||
turtle.goal = Some(cmd);
|
||||
return Ok(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue