diff --git a/azalea/src/pathfinder/moves/basic.rs b/azalea/src/pathfinder/moves/basic.rs index 71641716..531a2d00 100644 --- a/azalea/src/pathfinder/moves/basic.rs +++ b/azalea/src/pathfinder/moves/basic.rs @@ -1,15 +1,12 @@ use std::f32::consts::SQRT_2; -use azalea_client::{SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection}; +use azalea_client::{SprintDirection, WalkDirection}; use azalea_core::{ direction::CardinalDirection, position::{BlockPos, Vec3}, }; -use crate::{ - pathfinder::{astar, costs::*}, - JumpEvent, LookAtEvent, -}; +use crate::pathfinder::{astar, costs::*}; use super::{default_is_reached, Edge, ExecuteCtx, IsReachedCtx, MoveData, PathfinderCtx}; @@ -18,6 +15,7 @@ pub fn basic_move(edges: &mut Vec, ctx: &PathfinderCtx, node: BlockPos) { ascend_move(edges, ctx, node); descend_move(edges, ctx, node); diagonal_move(edges, ctx, node); + descend_forward_1_move(edges, ctx, node); } fn forward_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { @@ -43,24 +41,10 @@ fn forward_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { } } -fn execute_forward_move( - ExecuteCtx { - entity, - target, - look_at_events, - sprint_events, - .. - }: ExecuteCtx, -) { - let center = target.center(); - look_at_events.send(LookAtEvent { - entity, - position: center, - }); - sprint_events.send(StartSprintEvent { - entity, - direction: SprintDirection::Forward, - }); +fn execute_forward_move(mut ctx: ExecuteCtx) { + let center = ctx.target.center(); + ctx.look_at(center); + ctx.sprint(SprintDirection::Forward); } fn ascend_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { @@ -88,29 +72,19 @@ fn ascend_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { }) } } -fn execute_ascend_move( - ExecuteCtx { - entity, - position, +fn execute_ascend_move(mut ctx: ExecuteCtx) { + let ExecuteCtx { target, start, - look_at_events, - walk_events, - jump_events, + position, physics, .. - }: ExecuteCtx, -) { + } = ctx; + let target_center = target.center(); - look_at_events.send(LookAtEvent { - entity, - position: target_center, - }); - walk_events.send(StartWalkEvent { - entity, - direction: WalkDirection::Forward, - }); + ctx.look_at(target_center); + ctx.walk(WalkDirection::Forward); // these checks are to make sure we don't fall if our velocity is too high in // the wrong direction @@ -133,7 +107,7 @@ fn execute_ascend_move( } if BlockPos::from(position) == start { - jump_events.send(JumpEvent { entity }); + ctx.jump(); } } #[must_use] @@ -187,19 +161,17 @@ fn descend_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { }) } } -fn execute_descend_move( - ExecuteCtx { - entity, +fn execute_descend_move(mut ctx: ExecuteCtx) { + let ExecuteCtx { target, start, - look_at_events, - walk_events, position, .. - }: ExecuteCtx, -) { + } = ctx; + let start_center = start.center(); let center = target.center(); + let horizontal_distance_from_target = (center - position).horizontal_distance_sqr().sqrt(); let horizontal_distance_from_start = (start.center() - position).horizontal_distance_sqr().sqrt(); @@ -213,32 +185,16 @@ fn execute_descend_move( if BlockPos::from(position) != target || horizontal_distance_from_target > 0.25 { if horizontal_distance_from_start < 1.25 { // this basically just exists to avoid doing spins while we're falling - look_at_events.send(LookAtEvent { - entity, - position: dest_ahead, - }); - walk_events.send(StartWalkEvent { - entity, - direction: WalkDirection::Forward, - }); + ctx.look_at(dest_ahead); + ctx.walk(WalkDirection::Forward); } else { - look_at_events.send(LookAtEvent { - entity, - position: center, - }); - walk_events.send(StartWalkEvent { - entity, - direction: WalkDirection::Forward, - }); + ctx.look_at(center); + ctx.walk(WalkDirection::Forward); } } else { - walk_events.send(StartWalkEvent { - entity, - direction: WalkDirection::None, - }); + ctx.walk(WalkDirection::None); } } - #[must_use] pub fn descend_is_reached( IsReachedCtx { @@ -258,6 +214,58 @@ pub fn descend_is_reached( && (position.y - target.y as f64) < 0.5 } +fn descend_forward_1_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { + for dir in CardinalDirection::iter() { + let dir_delta = BlockPos::new(dir.x(), 0, dir.z()); + let gap_horizontal_position = pos + dir_delta; + let new_horizontal_position = pos + dir_delta * 2; + + let gap_fall_distance = ctx.fall_distance(gap_horizontal_position); + let fall_distance = ctx.fall_distance(new_horizontal_position); + + if fall_distance == 0 || fall_distance > 3 || gap_fall_distance < fall_distance { + continue; + } + + let new_position = new_horizontal_position.down(fall_distance as i32); + + // check whether 2 blocks vertically forward are passable + if !ctx.is_passable(new_horizontal_position) { + continue; + } + if !ctx.is_passable(gap_horizontal_position) { + continue; + } + // check whether we can stand on the target position + if !ctx.is_standable(new_position) { + continue; + } + + let cost = WALK_OFF_BLOCK_COST + + WALK_ONE_BLOCK_COST + + f32::max( + FALL_N_BLOCKS_COST + .get(fall_distance as usize) + .copied() + // avoid panicking if we fall more than the size of FALL_N_BLOCKS_COST + // probably not possible but just in case + .unwrap_or(f32::MAX), + CENTER_AFTER_FALL_COST, + ); + + edges.push(Edge { + movement: astar::Movement { + target: new_position, + data: MoveData { + execute: &execute_descend_move, + is_reached: &descend_is_reached, + }, + }, + cost, + }) + } +} + fn diagonal_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { for dir in CardinalDirection::iter() { let right = dir.right(); @@ -296,23 +304,9 @@ fn diagonal_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: BlockPos) { }) } } -fn execute_diagonal_move( - ExecuteCtx { - entity, - target, - look_at_events, - sprint_events, - .. - }: ExecuteCtx, -) { - let target_center = target.center(); +fn execute_diagonal_move(mut ctx: ExecuteCtx) { + let target_center = ctx.target.center(); - look_at_events.send(LookAtEvent { - entity, - position: target_center, - }); - sprint_events.send(StartSprintEvent { - entity, - direction: SprintDirection::Forward, - }); + ctx.look_at(target_center); + ctx.sprint(SprintDirection::Forward); } diff --git a/azalea/src/pathfinder/moves/mod.rs b/azalea/src/pathfinder/moves/mod.rs index c39590be..7feb8f40 100644 --- a/azalea/src/pathfinder/moves/mod.rs +++ b/azalea/src/pathfinder/moves/mod.rs @@ -11,7 +11,7 @@ use crate::{JumpEvent, LookAtEvent}; use super::astar; use azalea_block::BlockState; -use azalea_client::{StartSprintEvent, StartWalkEvent}; +use azalea_client::{SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection}; use azalea_core::{ bitset::FixedBitSet, position::{BlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos, Vec3}, @@ -313,6 +313,41 @@ pub struct ExecuteCtx<'w1, 'w2, 'w3, 'w4, 'a> { pub walk_events: &'a mut EventWriter<'w3, StartWalkEvent>, pub jump_events: &'a mut EventWriter<'w4, JumpEvent>, } + +impl ExecuteCtx<'_, '_, '_, '_, '_> { + pub fn look_at(&mut self, position: Vec3) { + self.look_at_events.send(LookAtEvent { + entity: self.entity, + position: Vec3 { + x: position.x, + // look forward + y: self.position.up(1.53).y, + z: position.z, + }, + }); + } + + pub fn sprint(&mut self, direction: SprintDirection) { + self.sprint_events.send(StartSprintEvent { + entity: self.entity, + direction, + }); + } + + pub fn walk(&mut self, direction: WalkDirection) { + self.walk_events.send(StartWalkEvent { + entity: self.entity, + direction, + }); + } + + pub fn jump(&mut self) { + self.jump_events.send(JumpEvent { + entity: self.entity, + }); + } +} + pub struct IsReachedCtx<'a> { /// The node that we're trying to reach. pub target: BlockPos, diff --git a/azalea/src/pathfinder/moves/parkour.rs b/azalea/src/pathfinder/moves/parkour.rs index e13581a0..e066fdb8 100644 --- a/azalea/src/pathfinder/moves/parkour.rs +++ b/azalea/src/pathfinder/moves/parkour.rs @@ -1,10 +1,7 @@ -use azalea_client::{SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection}; +use azalea_client::{SprintDirection, WalkDirection}; use azalea_core::{direction::CardinalDirection, position::BlockPos}; -use crate::{ - pathfinder::{astar, costs::*}, - JumpEvent, LookAtEvent, -}; +use crate::pathfinder::{astar, costs::*}; use super::{default_is_reached, Edge, ExecuteCtx, IsReachedCtx, MoveData, PathfinderCtx}; @@ -109,39 +106,25 @@ fn parkour_forward_2_move(edges: &mut Vec, ctx: &PathfinderCtx, pos: Block } } -fn execute_parkour_move( - ExecuteCtx { - entity, +fn execute_parkour_move(mut ctx: ExecuteCtx) { + let ExecuteCtx { position, target, start, - look_at_events, - sprint_events, - walk_events, - jump_events, .. - }: ExecuteCtx, -) { + } = ctx; + let start_center = start.center(); let target_center = target.center(); - look_at_events.send(LookAtEvent { - entity, - position: target_center, - }); + ctx.look_at(target_center); let jump_distance = i32::max((target - start).x.abs(), (target - start).z.abs()); if jump_distance >= 4 { // 3 block gap - sprint_events.send(StartSprintEvent { - entity, - direction: SprintDirection::Forward, - }); + ctx.sprint(SprintDirection::Forward); } else { - walk_events.send(StartWalkEvent { - entity, - direction: WalkDirection::Forward, - }); + ctx.walk(WalkDirection::Forward); } let x_dir = (target.x - start.x).clamp(-1, 1); @@ -165,7 +148,7 @@ fn execute_parkour_move( if !is_at_start_block && is_at_jump_block && distance_from_start > required_distance_from_center { - jump_events.send(JumpEvent { entity }); + ctx.jump(); } }