diff --git a/server/src/fell.rs b/server/src/fell.rs index cd5c284..c173e0e 100644 --- a/server/src/fell.rs +++ b/server/src/fell.rs @@ -3,7 +3,7 @@ use time::OffsetDateTime; use tokio::task::JoinHandle; use typetag::serde; -use crate::{blocks::{Vec3, Position, Direction}, turtle::TurtleCommander, tasks::Task, depot::Depots, mine::fill}; +use crate::{blocks::{Vec3, Position, Direction}, turtle::TurtleCommander, tasks::{Task, TaskState}, depot::Depots, mine::fill}; pub async fn fell_tree(turtle: TurtleCommander, bottom: Vec3) -> Option<()> { let mut log = bottom; @@ -73,12 +73,12 @@ impl Task for TreeFarm { }) } - fn poll(&mut self) -> Option { + fn poll(&mut self) -> TaskState { let elapsed = OffsetDateTime::now_utc() - self.last_sweep; if elapsed.whole_minutes() <= 16 { - return None; + return TaskState::Waiting; } self.last_sweep = OffsetDateTime::now_utc(); - Some(Position::new(self.position, Direction::North)) // request a turtle + TaskState::Ready(Position::new(self.position, Direction::North)) // request a turtle } } diff --git a/server/src/paths.rs b/server/src/paths.rs index ea0fa7e..6538db5 100644 --- a/server/src/paths.rs +++ b/server/src/paths.rs @@ -1,8 +1,11 @@ use crate::{ blocks::{World, Position, Direction, Vec3, WorldReadLock}, }; +use log::trace; use pathfinding::prelude::astar; +const LOOKUP_LIMIT: usize = 1_000_000; + pub async fn route_facing(from: Position, to: Vec3, world: &World) -> Option> { let facing = |p: &Position| { let ahead = p.dir.unit() + p.pos; @@ -23,18 +26,33 @@ pub async fn route(from: Position, to: Position, world: &World) -> Option(from: Position, to: Vec3, done: D, world: &World) -> Option> +async fn route_to(from: Position, to: Vec3, mut done: D, world: &World) -> Option> where D: FnMut(&Position) -> bool { // lock once, we'll be doing a lot of lookups let world = world.clone().lock().await; + let mut limit = LOOKUP_LIMIT; + let route = astar( &from, move |p| next(p, &world), |p1| (p1.pos - &to).abs().sum() as u32, - done, + |p| { + limit -= 1; + if limit == 0 { + return true + } else { + done(p) + } + }, )?; - Some(route.0) + + trace!("scanned {} states", LOOKUP_LIMIT-limit); + if limit != 0 { + Some(route.0) + } else { + None + } } fn next(from: &Position, world: &WorldReadLock) -> Vec<(Position, u32)> { @@ -94,7 +112,7 @@ const GARBAGE: [&str; 11] = [ ]; /// time taken to go through uncharted territory (in turtle. calls) -const UNKNOWN: Option = Some(1); +const UNKNOWN: Option = Some(2); // time to go somewhere pub fn difficulty(name: &str) -> Option { @@ -104,5 +122,5 @@ pub fn difficulty(name: &str) -> Option { if GARBAGE.contains(&name) { return Some(2); }; - Some(140) // providing a value here means that tunneling through builds is possible (bad) + None } diff --git a/server/src/tasks.rs b/server/src/tasks.rs index cb38832..4911894 100644 --- a/server/src/tasks.rs +++ b/server/src/tasks.rs @@ -1,21 +1,22 @@ -use std::sync::Arc; - -use erased_serde::serialize_trait_object; use log::info; use serde::{Deserialize, Serialize}; -use tokio::sync::{Mutex, MutexGuard, RwLock, OwnedMutexGuard}; use tokio::task::JoinHandle; -use crate::LiveState; use crate::names::Name; -use crate::{turtle::{self, TurtleCommander}, blocks::Position}; +use crate::{turtle::TurtleCommander, blocks::Position}; -#[typetag::serde(tag = "type")] +pub enum TaskState { + Ready(Position), + Waiting, + Complete, +} + +#[typetag::serde(tag = "task")] pub trait Task: Send + Sync { /// Execute the task fn run(&mut self, turtle: TurtleCommander) -> JoinHandle<()>; /// Return Some if the task should be scheduled - fn poll(&mut self) -> Option; + fn poll(&mut self) -> TaskState; } #[derive(Serialize, Deserialize)] @@ -67,7 +68,8 @@ impl Scheduler { } for task in &mut self.tasks { - if let Some(position) = task.poll() { + let poll = task.poll(); + if let TaskState::Ready(position) = poll { let closest_turtle = match free_turtles.iter_mut().zip(turtle_positions.iter()).min_by_key( |(_,p)| { p.manhattan(position) }) { @@ -77,6 +79,9 @@ impl Scheduler { closest_turtle.1 = Some(task.run(closest_turtle.0.clone())); } + if let TaskState::Complete = poll { + // TODO: removal + } } }