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"
|
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"
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue