diff --git a/server/src/blocks.rs b/server/src/blocks.rs index 043fc6c..cb06e44 100644 --- a/server/src/blocks.rs +++ b/server/src/blocks.rs @@ -5,7 +5,7 @@ use rstar::{self, PointDistance, RTree, RTreeObject, AABB}; use serde::{Deserialize, Serialize}; use tokio::sync::{RwLock, RwLockReadGuard, OwnedRwLockReadGuard}; -use crate::{turtle::TurtleCommand, paths}; +use crate::{turtle::TurtleCommand, paths::{self, TRANSPARENT}}; pub type WorldReadLock = OwnedRwLockReadGuard>; @@ -30,9 +30,9 @@ impl World { self.state.write().await.insert(block); } - /// Returns true if a known non-air block exists at the point + /// Returns true if a known non-traversable block exists at the point pub async fn occupied(&self, block: Vec3) -> bool { - self.state.read().await.locate_at_point(&block.into()).is_some_and(|b| b.name != "minecraft:air") + self.state.read().await.locate_at_point(&block.into()).is_some_and(|b| !TRANSPARENT.contains(&b.name.as_str())) } /// Returns true if a "garbage" block exists at the given point which you are free to destroy diff --git a/server/src/main.rs b/server/src/main.rs index ddb4605..21a9ae6 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -212,11 +212,12 @@ async fn run_command( async fn dig( Path(id): Path, State(state): State, - Json(req): Json, + Json(req): Json<(Vec3, Position, Position)>, ) -> &'static str { let turtle = state.read().await.get_turtle(id).await.unwrap(); - let fuel = Position::new(Vec3::new(-19, 93, 73), blocks::Direction::East); - let inventory = Position::new(Vec3::new(-19, 92, 73), blocks::Direction::East); + let (req, fuel, inventory) = req; + //let fuel = Position::new(Vec3::new(-19, 93, 73), blocks::Direction::East); + //let inventory = Position::new(Vec3::new(-19, 92, 73), blocks::Direction::East); tokio::spawn( async move { mine::mine(turtle.clone(), req, fuel, inventory).await diff --git a/server/src/mine.rs b/server/src/mine.rs index 3410a8a..cb8eadc 100644 --- a/server/src/mine.rs +++ b/server/src/mine.rs @@ -130,8 +130,9 @@ impl TurtleTask for TurtleMineJob { use TurtleCommand::*; /// Things to leave in the field (not worth fuel) -const USELESS: [&str; 4] = [ +const USELESS: [&str; 5] = [ "minecraft:dirt", + "minecraft:gravel", "minecraft:cobblestone", "minecraft:cobbled_deepslate", "minecraft:diorite", @@ -150,17 +151,13 @@ pub async fn mine(turtle: TurtleCommander, pos: Vec3, fuel: Position, storage: P loop { mine_chunk(turtle.clone(), pos, chunk).await?; - turtle.world().lock().await - .locate_within_distance(pos.into(), chunk.map(|n| n.pow(2)).sum()) - .filter(|n| n.name != "minecraft:air") - .filter(|n| VALUABLE.iter().any(|v| n.name.contains(v))) - .map(|b|b.pos).collect_into(&mut valuables); - - dump_filter(turtle.clone(), |i| USELESS.iter().any(|u| **u == i.name)).await; + valuables.append(&mut near_valuables(&turtle, pos, chunk).await); while let Some(block) = valuables.pop() { let near = turtle.goto_adjacent(block).await?; turtle.execute(dbg!(near.dig(block))?).await; + observe(turtle.clone(), block).await; + valuables.append(&mut near_valuables(&turtle, near.pos, Vec3::new(2,2,2)).await); } if (turtle.fuel().await as f64) < (volume + (fuel.pos-turtle.pos().await.pos).abs().sum()) as f64 * 1.1 { @@ -169,7 +166,7 @@ pub async fn mine(turtle: TurtleCommander, pos: Vec3, fuel: Position, storage: P refuel(turtle.clone()).await; } - if let turtle::TurtleCommandResponse::Item(_) = turtle.execute(ItemInfo(13)).await.ret { + if dump_filter(turtle.clone(), |i| USELESS.iter().any(|u| **u == i.name)).await > 13 { println!("storage rtb"); turtle.goto(storage).await?; dump(turtle.clone()).await; @@ -179,6 +176,14 @@ pub async fn mine(turtle: TurtleCommander, pos: Vec3, fuel: Position, storage: P } } +async fn near_valuables(turtle: &TurtleCommander, pos: Vec3, chunk: Vec3) -> Vec { + turtle.world().lock().await + .locate_within_distance(pos.into(), chunk.map(|n| n.pow(2)).sum()) + .filter(|n| n.name != "minecraft:air") + .filter(|n| VALUABLE.iter().any(|v| n.name.contains(v))) + .map(|b|b.pos).collect() +} + pub async fn mine_chunk(turtle: TurtleCommander, pos: Vec3, chunk: Vec3) -> Option<()> { let turtle = turtle.clone(); let volume = chunk.x * chunk.y * chunk.z; @@ -224,15 +229,20 @@ async fn dump(turtle: TurtleCommander) { } /// Dump all items that match the predicate -async fn dump_filter(turtle: TurtleCommander, mut filter: F) +/// Returns the number of slots still full after the operation +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(Select(i)).await.ret { if filter(item) { turtle.execute(DropFront(64)).await; + } else { + counter += 1; } } } + counter } /// zig from 0 to x and back, stopping on each end @@ -255,3 +265,26 @@ fn fill(scale: Vec3, n: i32) -> Vec3 { step(n/scale.x/scale.y, scale.z) ) } + +/// Looks at all the blocks around the given pos +/// destructive +async fn observe(turtle: TurtleCommander, pos: Vec3) -> Option<()> { + let adjacent = [ + pos, + pos + Vec3::y(), + pos + Vec3::x(), + pos + Vec3::z(), + pos - Vec3::x(), + pos - Vec3::z(), + pos - Vec3::y(), + ]; + + for pos in adjacent { + if turtle.world().get(pos).await.is_none() { + turtle.goto_adjacent(pos).await?; + } + + } + + Some(()) +} diff --git a/server/src/paths.rs b/server/src/paths.rs index 7b4598f..e5b744f 100644 --- a/server/src/paths.rs +++ b/server/src/paths.rs @@ -35,8 +35,7 @@ where D: FnMut(&Position) -> bool { move |p| next(p, &world), |p1| (p1.pos - &to).abs().sum() as u32, done, - ) - .unwrap(); + )?; Some(route.0) } @@ -74,6 +73,13 @@ fn next(from: &Position, world: &WorldReadLock) -> Vec<(Position, u32)> { vec } +/// Blocks that you can go through without a pickaxe +pub const TRANSPARENT: [&str; 3] = [ + "minecraft:air", + "minecraft:water", + "minecraft:lava", +]; + /// Blocks that are fine to tunnel through const GARBAGE: [&str; 6] = [ "minecraft:stone", @@ -89,7 +95,7 @@ const UNKNOWN: Option = Some(2); // time to go somewhere pub fn difficulty(name: &str) -> Option { - if name == "minecraft:air" { + if TRANSPARENT.contains(&name) { return Some(1); }; if GARBAGE.contains(&name) {