From 81a56331f9737158882140527f2bc5f35f7f9989 Mon Sep 17 00:00:00 2001 From: Andy Killorin <37423245+Speedy6451@users.noreply.github.com> Date: Tue, 26 Dec 2023 20:15:49 -0600 Subject: [PATCH] cache inventory --- server/src/depot.rs | 8 ++--- server/src/mine.rs | 6 ++-- server/src/turtle.rs | 70 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/server/src/depot.rs b/server/src/depot.rs index 59d1508..50cf614 100644 --- a/server/src/depot.rs +++ b/server/src/depot.rs @@ -52,8 +52,8 @@ impl Depots { turtle.goto(*depot.position()).await?; // dump inventory - for i in 1..=16 { - turtle.execute(Select(i)).await; + for (i, _) in turtle.inventory().await.into_iter().enumerate().filter(|(_,n)| n.is_some()) { + turtle.execute(Select(i as u32)).await; turtle.execute(DropDown(64)).await; } @@ -81,8 +81,8 @@ impl Depots { drop(depot); // lava bucket fix - for i in 1..=16 { - turtle.execute(Select(i)).await; + for (i, _) in turtle.inventory().await.into_iter().enumerate().filter(|(_,n)| n.is_some()) { + turtle.execute(Select(i as u32)).await; turtle.execute(DropDown(64)).await; } diff --git a/server/src/mine.rs b/server/src/mine.rs index aae12a8..4ef3357 100644 --- a/server/src/mine.rs +++ b/server/src/mine.rs @@ -131,10 +131,10 @@ async fn dump(turtle: TurtleCommander) { async fn dump_filter(turtle: TurtleCommander, mut filter: F) -> u32 where F: FnMut(InventorySlot) -> bool { let mut counter = 0; - for i in 1..=16 { - if let TurtleCommandResponse::Item(item) = turtle.execute(ItemInfo(i)).await.ret { + for (i, slot) in turtle.inventory().await.into_iter().enumerate() { + if let Some(item) = slot { if filter(item) { - turtle.execute(Select(i)).await; + turtle.execute(Select(i as u32)).await; turtle.execute(DropFront(64)).await; } else { counter += 1; diff --git a/server/src/turtle.rs b/server/src/turtle.rs index 845de68..5ef1053 100644 --- a/server/src/turtle.rs +++ b/server/src/turtle.rs @@ -154,6 +154,7 @@ pub struct TurtleCommander { fuel: Arc, max_fuel: Arc, name: Arc>, + inventory: Arc>>>>, } impl fmt::Debug for TurtleCommander { @@ -176,6 +177,7 @@ impl TurtleCommander { max_fuel: Arc::new(AtomicUsize::new(turtle.fuel_limit)), name: Arc::new(OnceCell::new_with(Some(turtle.name))), depots: state.depots.clone(), + inventory: Default::default(), }) } @@ -188,6 +190,7 @@ impl TurtleCommander { max_fuel: Arc::new(AtomicUsize::new(turtle.fuel_limit)), name: Arc::new(OnceCell::new_with(Some(turtle.name))), depots: state.depots.clone(), + inventory: Default::default(), } } @@ -195,16 +198,33 @@ impl TurtleCommander { pub async fn execute(&self, command: TurtleCommand) -> TurtleInfo { let (send, recv) = oneshot::channel::(); - if let Err(_) = self.sender.to_owned().send((command,send)).await { + if let Err(_) = self.sender.to_owned().send((command.clone(),send)).await { error!("server disappeared"); // It's fine to continue, nobody // is left to read garbage }; let resp = recv.await.unwrap_or_else(|_| { - error!("server dissapering"); + error!("server disappearing"); TurtleInfo::from_update(TurtleUpdate { fuel: self.fuel(), ahead: "".into(), above: "".into(), below: "".into(), ret: TurtleCommandResponse::Failure }, self.name(), Position::new(Vec3::zeros(), Direction::North)) }); + // invalidate inventory when we run commands that modify it + // this is not safe if you make a second TurtleCommander + if let TurtleCommandResponse::Success = resp.ret { + if match command { + TurtleCommand::Wait(_) => false, + TurtleCommand::Forward(_) => false, + TurtleCommand::Backward(_) => false, + TurtleCommand::Up(_) => false, + TurtleCommand::Down(_) => false, + TurtleCommand::Left => false, + TurtleCommand::Right => false, + _ => true, + } { + *self.inventory.write().await = None; + } + } + let mut pos = self.pos.write().await; *pos = resp.pos; self.fuel.store(resp.fuel, std::sync::atomic::Ordering::SeqCst); @@ -231,20 +251,42 @@ impl TurtleCommander { self.world.clone() } + pub async fn inventory(&self) -> Vec> { + let mut inventory = self.inventory.write().await; + + if inventory.is_some() { + return inventory.clone().unwrap(); + } + + let mut scan = Vec::new(); + + for i in 1..=16 { + match self.execute(TurtleCommand::ItemInfo(i)).await.ret { + TurtleCommandResponse::Item(item) => { + scan.push(Some(item)); + } + TurtleCommandResponse::None => { + scan.push(None); + } + _ => { + error!("inventory scan for #{} is going sideways", self.name().to_str()); + scan.push(None); + }, + } + }; + + *inventory = Some(scan.clone()); + scan + } + #[tracing::instrument(skip(self))] pub async fn dock(&self) -> usize { - let mut wait = 1; - loop { - let res = Depots::dock(&self.depots, self.to_owned()).await; - if let Some(fuel) = res { - return fuel; - } - error!("depot lock failed"); - // this is a poor way to do this, but I feel like select! ing on 30 different things - // would be harder - tokio::time::sleep(Duration::from_millis(wait)).await; - wait += 1; - } + let res = Depots::dock(&self.depots, self.to_owned()).await; + if let Some(fuel) = res { + return fuel; + }; + error!("dock failed"); + self.fuel() } pub async fn try_dock(&self) -> Option {