aboutsummaryrefslogtreecommitdiff
path: root/azalea/src/pathfinder/goals.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-12-15 11:26:40 -0600
committerGitHub <noreply@github.com>2023-12-15 11:26:40 -0600
commita707e2eb82b74994a16083b31fa4576332cf1995 (patch)
treedb6c2ac94dd73590befd68a9b1b0ef960410b0df /azalea/src/pathfinder/goals.rs
parent59e140ddd655c7dc6e35109b91286118c51bcc06 (diff)
downloadazalea-drasl-a707e2eb82b74994a16083b31fa4576332cf1995.tar.xz
Add mining to the pathfinder (#122)
* basic pathfinder mining poc * mining descending and autotool * pathfinder mining descending * pathfinder fixes * allow disabling pathfinder miner and other fixes * small optimization to avoid chunk vec iter lookup sometimes * seeded rng in pathfinder bench * consistently use f32::INFINITY this brings performance much closer to how it was before * astar heuristic optimization from baritone * add downward_move * fix downward move execute * avoid liquids and falling blocks when mining * fix COST_HEURISTIC * fix to not path through flowing liquids * only reset pathfinder timeout while mining if the block is close enough * cache mining costs of block positions * fix mine_while_at_start and move PathfinderDebugParticles to its own module * add ReachBlockPosGoal in other news: azalea's sin/cos functions were broken this whole time and i never noticed * clippy and add things that i accidentally didn't commit * improve wording on doc for azalea::pathfinder
Diffstat (limited to 'azalea/src/pathfinder/goals.rs')
-rw-r--r--azalea/src/pathfinder/goals.rs96
1 files changed, 91 insertions, 5 deletions
diff --git a/azalea/src/pathfinder/goals.rs b/azalea/src/pathfinder/goals.rs
index 9c01d486..3f8c7993 100644
--- a/azalea/src/pathfinder/goals.rs
+++ b/azalea/src/pathfinder/goals.rs
@@ -1,12 +1,21 @@
+//! The goals that a pathfinder can try to reach.
+
use std::f32::consts::SQRT_2;
use azalea_core::position::{BlockPos, Vec3};
+use azalea_world::ChunkStorage;
+
+use super::costs::{COST_HEURISTIC, FALL_N_BLOCKS_COST, JUMP_ONE_BLOCK_COST};
-use super::{
- costs::{FALL_N_BLOCKS_COST, JUMP_ONE_BLOCK_COST},
- Goal,
-};
+pub trait Goal {
+ #[must_use]
+ fn heuristic(&self, n: BlockPos) -> f32;
+ #[must_use]
+ fn success(&self, n: BlockPos) -> bool;
+}
+/// Move to the given block position.
+#[derive(Debug)]
pub struct BlockPosGoal(pub BlockPos);
impl Goal for BlockPosGoal {
fn heuristic(&self, n: BlockPos) -> f32 {
@@ -36,9 +45,11 @@ fn xz_heuristic(dx: f32, dz: f32) -> f32 {
diagonal = z;
}
- diagonal * SQRT_2 + straight
+ (diagonal * SQRT_2 + straight) * COST_HEURISTIC
}
+/// Move to the given block position, ignoring the y axis.
+#[derive(Debug)]
pub struct XZGoal {
pub x: i32,
pub z: i32,
@@ -62,6 +73,8 @@ fn y_heuristic(dy: f32) -> f32 {
}
}
+/// Move to the given y coordinate.
+#[derive(Debug)]
pub struct YGoal {
pub y: i32,
}
@@ -75,6 +88,8 @@ impl Goal for YGoal {
}
}
+/// Get within the given radius of the given position.
+#[derive(Debug)]
pub struct RadiusGoal {
pub pos: Vec3,
pub radius: f32,
@@ -96,6 +111,8 @@ impl Goal for RadiusGoal {
}
}
+/// Do the opposite of the given goal.
+#[derive(Debug)]
pub struct InverseGoal<T: Goal>(pub T);
impl<T: Goal> Goal for InverseGoal<T> {
fn heuristic(&self, n: BlockPos) -> f32 {
@@ -106,6 +123,8 @@ impl<T: Goal> Goal for InverseGoal<T> {
}
}
+/// Do either of the given goals, whichever is closer.
+#[derive(Debug)]
pub struct OrGoal<T: Goal, U: Goal>(pub T, pub U);
impl<T: Goal, U: Goal> Goal for OrGoal<T, U> {
fn heuristic(&self, n: BlockPos) -> f32 {
@@ -116,6 +135,24 @@ impl<T: Goal, U: Goal> Goal for OrGoal<T, U> {
}
}
+/// Do any of the given goals, whichever is closest.
+#[derive(Debug)]
+pub struct OrGoals<T: Goal>(pub Vec<T>);
+impl<T: Goal> Goal for OrGoals<T> {
+ fn heuristic(&self, n: BlockPos) -> f32 {
+ self.0
+ .iter()
+ .map(|goal| goal.heuristic(n))
+ .min_by(|a, b| a.partial_cmp(b).unwrap())
+ .unwrap_or(f32::INFINITY)
+ }
+ fn success(&self, n: BlockPos) -> bool {
+ self.0.iter().any(|goal| goal.success(n))
+ }
+}
+
+/// Try to reach both of the given goals.
+#[derive(Debug)]
pub struct AndGoal<T: Goal, U: Goal>(pub T, pub U);
impl<T: Goal, U: Goal> Goal for AndGoal<T, U> {
fn heuristic(&self, n: BlockPos) -> f32 {
@@ -125,3 +162,52 @@ impl<T: Goal, U: Goal> Goal for AndGoal<T, U> {
self.0.success(n) && self.1.success(n)
}
}
+
+/// Try to reach all of the given goals.
+#[derive(Debug)]
+pub struct AndGoals<T: Goal>(pub Vec<T>);
+impl<T: Goal> Goal for AndGoals<T> {
+ fn heuristic(&self, n: BlockPos) -> f32 {
+ self.0
+ .iter()
+ .map(|goal| goal.heuristic(n))
+ .max_by(|a, b| a.partial_cmp(b).unwrap())
+ .unwrap_or(f32::INFINITY)
+ }
+ fn success(&self, n: BlockPos) -> bool {
+ self.0.iter().all(|goal| goal.success(n))
+ }
+}
+
+/// Move to a position where we can reach the given block.
+#[derive(Debug)]
+pub struct ReachBlockPosGoal {
+ pub pos: BlockPos,
+ pub chunk_storage: ChunkStorage,
+}
+impl Goal for ReachBlockPosGoal {
+ fn heuristic(&self, n: BlockPos) -> f32 {
+ BlockPosGoal(self.pos).heuristic(n)
+ }
+ fn success(&self, n: BlockPos) -> bool {
+ // only do the expensive check if we're close enough
+ let max_pick_range = 6;
+ let actual_pick_range = 4.5;
+
+ let distance = (self.pos - n).length_sqr();
+ if distance > max_pick_range * max_pick_range {
+ return false;
+ }
+
+ let eye_position = n.to_vec3_floored() + Vec3::new(0.5, 1.62, 0.5);
+ let look_direction = crate::direction_looking_at(&eye_position, &self.pos.center());
+ let block_hit_result = azalea_client::interact::pick(
+ &look_direction,
+ &eye_position,
+ &self.chunk_storage,
+ actual_pick_range,
+ );
+
+ block_hit_result.block_pos == self.pos
+ }
+}