diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs index e1993b18..f6bc4157 100755 --- a/azalea-core/src/position.rs +++ b/azalea-core/src/position.rs @@ -259,6 +259,7 @@ impl ChunkSectionPos { block >> 4 } } + /// The coordinates of a block inside a chunk. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct ChunkBlockPos { diff --git a/azalea/src/pathfinder/astar.rs b/azalea/src/pathfinder/astar.rs index bc7b2309..4e1d1039 100644 --- a/azalea/src/pathfinder/astar.rs +++ b/azalea/src/pathfinder/astar.rs @@ -6,7 +6,7 @@ use std::{ time::{Duration, Instant}, }; -use log::{trace, warn}; +use log::{debug, trace, warn}; use priority_queue::PriorityQueue; pub struct Path
@@ -55,8 +55,12 @@ where
let mut best_paths: [P; 7] = [start; 7];
let mut best_path_scores: [f32; 7] = [heuristic(start); 7];
+ let mut num_nodes = 0;
+
while let Some((current_node, _)) = open_set.pop() {
+ num_nodes += 1;
if success(current_node) {
+ debug!("Nodes considered: {num_nodes}");
return Path {
movements: reconstruct_path(nodes, current_node),
partial: false,
@@ -99,7 +103,8 @@ where
}
}
- if start_time.elapsed() > timeout {
+ // check for timeout every ~1ms
+ if num_nodes % 1000 == 0 && start_time.elapsed() > timeout {
// timeout, just return the best path we have so far
trace!("A* couldn't find a path in time, returning best path");
break;
diff --git a/azalea/src/pathfinder/goals.rs b/azalea/src/pathfinder/goals.rs
index 4e278c74..c8e2c211 100644
--- a/azalea/src/pathfinder/goals.rs
+++ b/azalea/src/pathfinder/goals.rs
@@ -1,6 +1,11 @@
+use std::f32::consts::SQRT_2;
+
use azalea_core::position::{BlockPos, Vec3};
-use super::Goal;
+use super::{
+ costs::{FALL_ONE_BLOCK_COST, JUMP_ONE_BLOCK_COST},
+ Goal,
+};
pub struct BlockPosGoal(pub BlockPos);
impl Goal for BlockPosGoal {
@@ -8,13 +13,32 @@ impl Goal for BlockPosGoal {
let dx = (self.0.x - n.x) as f32;
let dy = (self.0.y - n.y) as f32;
let dz = (self.0.z - n.z) as f32;
- dx * dx + dy * dy + dz * dz
+
+ xz_heuristic(dx, dz) + y_heuristic(dy)
}
fn success(&self, n: BlockPos) -> bool {
n == self.0
}
}
+fn xz_heuristic(dx: f32, dz: f32) -> f32 {
+ let x = dx.abs();
+ let z = dz.abs();
+
+ let diagonal;
+ let straight;
+
+ if x < z {
+ straight = z - x;
+ diagonal = x;
+ } else {
+ straight = x - z;
+ diagonal = z;
+ }
+
+ diagonal * SQRT_2 + straight
+}
+
pub struct XZGoal {
pub x: i32,
pub z: i32,
@@ -23,20 +47,28 @@ impl Goal for XZGoal {
fn heuristic(&self, n: BlockPos) -> f32 {
let dx = (self.x - n.x) as f32;
let dz = (self.z - n.z) as f32;
- dx * dx + dz * dz
+ xz_heuristic(dx, dz)
}
fn success(&self, n: BlockPos) -> bool {
n.x == self.x && n.z == self.z
}
}
+fn y_heuristic(dy: f32) -> f32 {
+ if dy < 0.0 {
+ FALL_ONE_BLOCK_COST * -dy
+ } else {
+ *JUMP_ONE_BLOCK_COST * dy
+ }
+}
+
pub struct YGoal {
pub y: i32,
}
impl Goal for YGoal {
fn heuristic(&self, n: BlockPos) -> f32 {
let dy = (self.y - n.y) as f32;
- dy * dy
+ y_heuristic(dy)
}
fn success(&self, n: BlockPos) -> bool {
n.y == self.y
diff --git a/azalea/src/pathfinder/moves/mod.rs b/azalea/src/pathfinder/moves/mod.rs
index 81a184aa..1714f8bc 100644
--- a/azalea/src/pathfinder/moves/mod.rs
+++ b/azalea/src/pathfinder/moves/mod.rs
@@ -25,6 +25,11 @@ type Edge = astar::Edge