diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs index 85ff91109..1512bbd33 100644 --- a/azalea-entity/src/lib.rs +++ b/azalea-entity/src/lib.rs @@ -207,8 +207,8 @@ impl From<&LastSentPosition> for BlockPos { /// A component for entities that can jump. /// -/// If this is true, the entity will try to jump every tick. (It's equivalent to -/// the space key being held in vanilla.) +/// If this is true, the entity will try to jump every tick. It's equivalent to +/// the space key being held in vanilla. #[derive(Debug, Component, Copy, Clone, Deref, DerefMut, Default)] pub struct Jumping(bool); @@ -273,6 +273,12 @@ pub struct Physics { on_ground: bool, last_on_ground: bool, + /// The number of ticks until we jump again, if the jump key is being held. + /// + /// This must be 0 for us to be able to jump. Sets to 10 when we do a jump + /// and sets to 0 if we're not trying to jump. + pub no_jump_delay: u32, + /// The width and height of the entity. pub dimensions: EntityDimensions, /// The bounding box of the entity. This is more than just width and height, @@ -310,6 +316,8 @@ impl Physics { on_ground: false, last_on_ground: false, + no_jump_delay: 0, + bounding_box: dimensions.make_bounding_box(&pos), dimensions, diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index eb408a631..77dde13e3 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -77,6 +77,10 @@ pub fn ai_step( // vanilla does movement interpolation here, doesn't really matter much for a // bot though + if physics.no_jump_delay > 0 { + physics.no_jump_delay -= 1; + } + if physics.velocity.x.abs() < 0.003 { physics.velocity.x = 0.; } @@ -91,17 +95,45 @@ pub fn ai_step( if **jumping { // TODO: jumping in liquids and jump delay - if physics.on_ground() { - jump_from_ground( - &mut physics, - position, - look_direction, - sprinting, - instance_name, - &instance_container, - ) + let fluid_height = if physics.is_in_lava() { + physics.lava_fluid_height + } else if physics.is_in_water() { + physics.water_fluid_height + } else { + 0. + }; + + let in_water = physics.is_in_water() && fluid_height > 0.; + let fluid_jump_threshold = travel::fluid_jump_threshold(); + + if !in_water || physics.on_ground() && fluid_height <= fluid_jump_threshold { + if !physics.is_in_lava() + || physics.on_ground() && fluid_height <= fluid_jump_threshold + { + if physics.on_ground() + || in_water + && fluid_height <= fluid_jump_threshold + && physics.no_jump_delay == 0 + { + jump_from_ground( + &mut physics, + position, + look_direction, + sprinting, + instance_name, + &instance_container, + ); + physics.no_jump_delay = 10; + } + } else { + jump_in_liquid(&mut physics); + } + } else { + jump_in_liquid(&mut physics); } } + } else { + physics.no_jump_delay = 0; } physics.x_acceleration *= 0.98; @@ -112,38 +144,19 @@ pub fn ai_step( } } +fn jump_in_liquid(physics: &mut Physics) { + physics.velocity.y += 0.04; +} + // in minecraft, this is done as part of aiStep immediately after travel pub fn apply_effects_from_blocks( mut query: Query< - ( - &mut Physics, - &mut LookDirection, - &mut Position, - &mut LastSentPosition, - Option<&Sprinting>, - Option<&Pose>, - &Attributes, - &InstanceName, - &OnClimbable, - &Jumping, - ), + (&mut Physics, &Position, &InstanceName), (With, With), >, instance_container: Res, ) { - for ( - mut physics, - mut look_direction, - mut position, - mut last_sent_position, - sprinting, - pose, - attributes, - world_name, - on_climbable, - jumping, - ) in &mut query - { + for (mut physics, position, world_name) in &mut query { let Some(world_lock) = instance_container.get(world_name) else { continue; }; diff --git a/azalea-physics/src/travel.rs b/azalea-physics/src/travel.rs index a968fed7c..c2d096868 100644 --- a/azalea-physics/src/travel.rs +++ b/azalea-physics/src/travel.rs @@ -291,7 +291,7 @@ fn get_effective_gravity() -> f64 { 0.08 } -fn fluid_jump_threshold() -> f64 { +pub fn fluid_jump_threshold() -> f64 { // this is 0.0 for entities with an eye height lower than 0.4, but that's not // implemented since it's usually not relevant for players (unless the player // was shrunk)