mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
fix some edge cases when pathfinding on slabs and stairs
This commit is contained in:
parent
f7c9419045
commit
7b442368da
3 changed files with 104 additions and 2 deletions
|
@ -1,5 +1,6 @@
|
|||
use std::f32::consts::SQRT_2;
|
||||
|
||||
use azalea_block::{BlockState, properties};
|
||||
use azalea_client::{SprintDirection, WalkDirection};
|
||||
use azalea_core::{
|
||||
direction::CardinalDirection,
|
||||
|
@ -58,7 +59,34 @@ fn execute_forward_move(mut ctx: ExecuteCtx) {
|
|||
}
|
||||
|
||||
fn ascend_move(ctx: &mut PathfinderCtx, pos: RelBlockPos) {
|
||||
// the block we're standing on must be solid (so we don't try to ascend from a
|
||||
// bottom slab to a normal block in a way that's not possible)
|
||||
|
||||
let is_unusual_shape = !ctx.world.is_block_solid(pos.down(1));
|
||||
let mut stair_facing = None;
|
||||
|
||||
if is_unusual_shape {
|
||||
// this is potentially expensive but it's rare enough that it shouldn't matter
|
||||
// much
|
||||
let block_below = ctx.world.get_block_state(pos.down(1));
|
||||
|
||||
let Some(found_stair_facing) = validate_stair_and_get_facing(block_below) else {
|
||||
// return if it's not a stair or it's not facing the right way (like, if it's
|
||||
// upside down or something)
|
||||
return;
|
||||
};
|
||||
|
||||
stair_facing = Some(found_stair_facing);
|
||||
}
|
||||
|
||||
for dir in CardinalDirection::iter() {
|
||||
if let Some(stair_facing) = stair_facing {
|
||||
let expected_stair_facing = cardinal_direction_to_facing_property(dir);
|
||||
if stair_facing != expected_stair_facing {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let offset = RelBlockPos::new(dir.x(), 1, dir.z());
|
||||
|
||||
let break_cost_1 = ctx
|
||||
|
@ -134,6 +162,24 @@ fn execute_ascend_move(mut ctx: ExecuteCtx) {
|
|||
return;
|
||||
}
|
||||
|
||||
// if the target block is a stair that's facing in the direction we're going, we
|
||||
// shouldn't jump
|
||||
let block_below_target = ctx.get_block_state(target.down(1));
|
||||
if let Some(stair_facing) = validate_stair_and_get_facing(block_below_target) {
|
||||
let expected_stair_facing = match (x_axis, z_axis) {
|
||||
(0, 1) => Some(properties::FacingCardinal::North),
|
||||
(1, 0) => Some(properties::FacingCardinal::East),
|
||||
(0, -1) => Some(properties::FacingCardinal::South),
|
||||
(-1, 0) => Some(properties::FacingCardinal::West),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(expected_stair_facing) = expected_stair_facing {
|
||||
if stair_facing == expected_stair_facing {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if BlockPos::from(position) == start {
|
||||
// only jump if the target is more than 0.5 blocks above us
|
||||
if target.y as f64 - position.y > 0.5 {
|
||||
|
@ -150,6 +196,23 @@ pub fn ascend_is_reached(
|
|||
BlockPos::from(position) == target || BlockPos::from(position) == target.down(1)
|
||||
}
|
||||
|
||||
fn validate_stair_and_get_facing(block_state: BlockState) -> Option<properties::FacingCardinal> {
|
||||
let top_bottom = block_state.property::<properties::TopBottom>();
|
||||
if top_bottom != Some(properties::TopBottom::Bottom) {
|
||||
return None;
|
||||
}
|
||||
|
||||
block_state.property::<properties::FacingCardinal>()
|
||||
}
|
||||
fn cardinal_direction_to_facing_property(dir: CardinalDirection) -> properties::FacingCardinal {
|
||||
match dir {
|
||||
CardinalDirection::North => properties::FacingCardinal::North,
|
||||
CardinalDirection::East => properties::FacingCardinal::East,
|
||||
CardinalDirection::South => properties::FacingCardinal::South,
|
||||
CardinalDirection::West => properties::FacingCardinal::West,
|
||||
}
|
||||
}
|
||||
|
||||
fn descend_move(ctx: &mut PathfinderCtx, pos: RelBlockPos) {
|
||||
for dir in CardinalDirection::iter() {
|
||||
let dir_delta = RelBlockPos::new(dir.x(), 0, dir.z());
|
||||
|
|
|
@ -3,6 +3,7 @@ pub mod parkour;
|
|||
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use azalea_block::BlockState;
|
||||
use azalea_client::{
|
||||
SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
|
||||
inventory::SetSelectedHotbarSlotEvent, mining::StartMiningBlockEvent,
|
||||
|
@ -175,6 +176,13 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> {
|
|||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_block_state(&self, block: BlockPos) -> BlockState {
|
||||
self.instance
|
||||
.read()
|
||||
.get_block_state(&block)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IsReachedCtx<'a> {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use azalea_block::BlockState;
|
||||
use azalea_block::{BlockState, properties};
|
||||
use azalea_core::{
|
||||
bitset::FixedBitSet,
|
||||
position::{BlockPos, ChunkPos, ChunkSectionBlockPos, ChunkSectionPos},
|
||||
|
@ -241,6 +241,21 @@ impl CachedWorld {
|
|||
passable
|
||||
}
|
||||
|
||||
/// Get the block state at the given position. This is relatively slow, so
|
||||
/// you should avoid it whenever possible.
|
||||
pub fn get_block_state(&self, pos: RelBlockPos) -> BlockState {
|
||||
self.get_block_state_at_pos(pos.apply(self.origin))
|
||||
}
|
||||
|
||||
fn get_block_state_at_pos(&self, pos: BlockPos) -> BlockState {
|
||||
let (section_pos, section_block_pos) =
|
||||
(ChunkSectionPos::from(pos), ChunkSectionBlockPos::from(pos));
|
||||
let index = u16::from(section_block_pos) as usize;
|
||||
|
||||
self.with_section(section_pos, |section| section.get_at_index(index))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn is_block_solid(&self, pos: RelBlockPos) -> bool {
|
||||
self.is_block_pos_solid(pos.apply(self.origin))
|
||||
}
|
||||
|
@ -487,6 +502,10 @@ impl CachedWorld {
|
|||
}
|
||||
distance
|
||||
}
|
||||
|
||||
pub fn origin(&self) -> BlockPos {
|
||||
self.origin
|
||||
}
|
||||
}
|
||||
|
||||
/// whether this block is passable
|
||||
|
@ -537,7 +556,19 @@ pub fn is_block_state_solid(block: BlockState) -> bool {
|
|||
// fast path
|
||||
return false;
|
||||
}
|
||||
block.is_collision_shape_full()
|
||||
if block.is_collision_shape_full() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if matches!(
|
||||
block.property::<properties::Type>(),
|
||||
Some(properties::Type::Top | properties::Type::Double)
|
||||
) {
|
||||
// top slabs
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_block_state_standable(block: BlockState) -> bool {
|
||||
|
|
Loading…
Add table
Reference in a new issue