diff options
| author | mat <git@matdoes.dev> | 2025-10-13 09:54:22 +0930 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-10-13 09:54:22 +0930 |
| commit | 5f6ebb98c9ef5775ed5fe39662436b83a3108aa6 (patch) | |
| tree | 950161fb4577a03abdaf599f8b014da4ac10f014 | |
| parent | 51198a48ed0797ae80a35d6f3540cf6285ec52d8 (diff) | |
| download | azalea-drasl-5f6ebb98c9ef5775ed5fe39662436b83a3108aa6.tar.xz | |
don't fall when the last pathfinder node is slippery
| -rw-r--r-- | azalea-physics/src/lib.rs | 2 | ||||
| -rw-r--r-- | azalea/src/pathfinder/mod.rs | 52 |
2 files changed, 44 insertions, 10 deletions
diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index b49d734c..ab9c2084 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -363,7 +363,7 @@ pub fn update_old_position(mut query: Query<(&mut Physics, &Position)>) { } } -fn get_block_pos_below_that_affects_movement(position: Position) -> BlockPos { +pub fn get_block_pos_below_that_affects_movement(position: Position) -> BlockPos { BlockPos::new( position.x.floor() as i32, // TODO: this uses bounding_box.min_y instead of position.y diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs index c001f838..7f0bd841 100644 --- a/azalea/src/pathfinder/mod.rs +++ b/azalea/src/pathfinder/mod.rs @@ -32,6 +32,7 @@ use std::{ }; use astar::{Edge, PathfinderTimeout}; +use azalea_block::{BlockState, BlockTrait}; use azalea_client::{ StartSprintEvent, StartWalkEvent, inventory::{Inventory, InventorySystems}, @@ -44,7 +45,7 @@ use azalea_core::{ tick::GameTick, }; use azalea_entity::{LocalEntity, Physics, Position, metadata::Player}; -use azalea_physics::PhysicsSystems; +use azalea_physics::{PhysicsSystems, get_block_pos_below_that_affects_movement}; use azalea_world::{InstanceContainer, InstanceName}; use bevy_app::{PreUpdate, Update}; use bevy_ecs::prelude::*; @@ -733,11 +734,19 @@ pub fn check_node_reached( &mut ExecutingPath, &Position, &Physics, + &InstanceName, )>, mut walk_events: MessageWriter<StartWalkEvent>, mut commands: Commands, + instance_container: Res<InstanceContainer>, ) { - for (entity, mut pathfinder, mut executing_path, position, physics) in &mut query { + for (entity, mut pathfinder, mut executing_path, position, physics, instance_name) in &mut query + { + let Some(instance) = instance_container.get(instance_name) else { + warn!("entity is pathfinding but not in a valid world"); + continue; + }; + 'skip: loop { // we check if the goal was reached *before* actually executing the movement so // we don't unnecessarily execute a movement when it wasn't necessary @@ -758,20 +767,45 @@ pub fn check_node_reached( position: **position, physics, }; - let extra_strict_if_last = if i == executing_path.path.len() - 1 { + let extra_check = if i == executing_path.path.len() - 1 { + // be extra strict about the velocity and centering if we're on the last node so + // we don't fall off + let x_difference_from_center = position.x - (movement.target.x as f64 + 0.5); let z_difference_from_center = position.z - (movement.target.z as f64 + 0.5); + + let block_pos_below = get_block_pos_below_that_affects_movement(*position); + + let block_state_below = { + let instance = instance.read(); + instance + .chunks + .get_block_state(block_pos_below) + .unwrap_or(BlockState::AIR) + }; + let block_below: Box<dyn BlockTrait> = block_state_below.into(); + // friction for normal blocks is 0.6, for ice it's 0.98 + let block_friction = block_below.behavior().friction as f64; + + // if the block has the default friction, this will multiply by 1 + // for blocks like ice, it'll multiply by a higher number + let scaled_velocity = physics.velocity * (0.4 / (1. - block_friction)); + + let x_predicted_offset = (x_difference_from_center + scaled_velocity.x).abs(); + let z_predicted_offset = (z_difference_from_center + scaled_velocity.z).abs(); + // this is to make sure we don't fall off immediately after finishing the path physics.on_ground() - && player_pos_to_block_pos(**position) == movement.target - // adding the delta like this isn't a perfect solution but it helps to make - // sure we don't keep going if our delta is high - && (x_difference_from_center + physics.velocity.x).abs() < 0.2 - && (z_difference_from_center + physics.velocity.z).abs() < 0.2 + && player_pos_to_block_pos(**position) == movement.target + // adding the delta like this isn't a perfect solution but it helps to make + // sure we don't keep going if our delta is high + && x_predicted_offset < 0.2 + && z_predicted_offset < 0.2 } else { true }; - if (movement.data.is_reached)(is_reached_ctx) && extra_strict_if_last { + + if (movement.data.is_reached)(is_reached_ctx) && extra_check { executing_path.path = executing_path.path.split_off(i + 1); executing_path.last_reached_node = movement.target; executing_path.last_node_reached_at = Instant::now(); |
