diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs index cd8a3301..9ecc6093 100644 --- a/azalea/src/pathfinder/mod.rs +++ b/azalea/src/pathfinder/mod.rs @@ -1,3 +1,6 @@ +//! A pathfinding plugin to make bots navigate the world. A lot of this code is +//! based on [Baritone](https://github.com/cabaletta/baritone). + mod astar; pub mod costs; pub mod goals; @@ -144,7 +147,7 @@ fn goto_listener( // we store the goal so it can be recalculated later if necessary pathfinder.goal = Some(event.goal.clone()); - pathfinder.successors_fn = Some(event.successors_fn.clone()); + pathfinder.successors_fn = Some(event.successors_fn); pathfinder.is_calculating = true; let start = if pathfinder.path.is_empty() { @@ -419,6 +422,7 @@ fn tick_execute_path( start: pathfinder.last_reached_node.expect( "pathfinder.last_reached_node should always be present if there's a path", ), + physics, look_at_events: &mut look_at_events, sprint_events: &mut sprint_events, walk_events: &mut walk_events, diff --git a/azalea/src/pathfinder/moves/basic.rs b/azalea/src/pathfinder/moves/basic.rs index 4219f1e7..af940dc2 100644 --- a/azalea/src/pathfinder/moves/basic.rs +++ b/azalea/src/pathfinder/moves/basic.rs @@ -1,6 +1,6 @@ use std::f32::consts::SQRT_2; -use azalea_client::{SprintDirection, StartSprintEvent}; +use azalea_client::{SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection}; use azalea_core::{BlockPos, CardinalDirection}; use azalea_world::Instance; @@ -88,7 +88,7 @@ fn ascend_move(world: &Instance, pos: BlockPos) -> Vec { target: pos + offset, data: MoveData { execute: &execute_ascend_move, - is_reached: &default_is_reached, + is_reached: &ascend_is_reached, }, }, cost, @@ -99,24 +99,58 @@ fn ascend_move(world: &Instance, pos: BlockPos) -> Vec { fn execute_ascend_move( ExecuteCtx { entity, + position, target, + start, look_at_events, - sprint_events, + walk_events, jump_events, + physics, .. }: ExecuteCtx, ) { - let center = target.center(); + let target_center = target.center(); + look_at_events.send(LookAtEvent { entity, - position: center, + position: target_center, }); - jump_events.send(JumpEvent { entity }); - sprint_events.send(StartSprintEvent { + walk_events.send(StartWalkEvent { entity, - direction: SprintDirection::Forward, + direction: WalkDirection::Forward, }); + + // these checks are to make sure we don't fall if our velocity is too high in + // the wrong direction + + let x_axis = (start.x - target.x).abs(); // either 0 or 1 + let z_axis = (start.z - target.z).abs(); // either 0 or 1 + + let flat_distance_to_next = x_axis as f64 * (target_center.x - position.x) + + z_axis as f64 * (target_center.z - position.z); + let side_distance = z_axis as f64 * (target_center.x - position.x).abs() + + x_axis as f64 * (target_center.z - position.z).abs(); + + let lateral_motion = x_axis as f64 * physics.delta.z + z_axis as f64 * physics.delta.x; + if lateral_motion > 0.1 { + return; + } + + if flat_distance_to_next > 1.2 || side_distance > 0.2 { + return; + } + + jump_events.send(JumpEvent { entity }); } +#[must_use] +pub fn ascend_is_reached( + IsReachedCtx { + position, target, .. + }: IsReachedCtx, +) -> bool { + BlockPos::from(position) == target || BlockPos::from(position) == target.down(1) +} + fn descend_move(world: &Instance, pos: BlockPos) -> Vec { let mut edges = Vec::new(); for dir in CardinalDirection::iter() { @@ -143,7 +177,7 @@ fn descend_move(world: &Instance, pos: BlockPos) -> Vec { target: new_position, data: MoveData { execute: &execute_descend_move, - is_reached: &is_reached_descend_move, + is_reached: &descend_is_reached, }, }, cost, @@ -176,6 +210,7 @@ fn execute_descend_move( if BlockPos::from(position) != target || horizontal_distance_from_target > 0.25 { // if we're only falling one block then it's fine to try to overshoot if horizontal_distance_from_start < 1.25 || start.y - target.y == 1 { + // this basically just exists to avoid doing spins while we're falling look_at_events.send(LookAtEvent { entity, position: dest_ahead.center(), @@ -197,7 +232,7 @@ fn execute_descend_move( } } #[must_use] -pub fn is_reached_descend_move( +pub fn descend_is_reached( IsReachedCtx { target, start, diff --git a/azalea/src/pathfinder/moves/mod.rs b/azalea/src/pathfinder/moves/mod.rs index 9aa6b363..01df0929 100644 --- a/azalea/src/pathfinder/moves/mod.rs +++ b/azalea/src/pathfinder/moves/mod.rs @@ -98,6 +98,7 @@ pub struct ExecuteCtx<'w1, 'w2, 'w3, 'w4, 'a> { /// The last node that we reached. pub start: BlockPos, pub position: Vec3, + pub physics: &'a azalea_entity::Physics, pub look_at_events: &'a mut EventWriter<'w1, LookAtEvent>, pub sprint_events: &'a mut EventWriter<'w2, StartSprintEvent>, @@ -120,11 +121,11 @@ pub fn default_is_reached( IsReachedCtx { position, target, - physics, + // physics, .. }: IsReachedCtx, ) -> bool { - BlockPos::from(position) == target && physics.on_ground + BlockPos::from(position) == target } #[cfg(test)]