diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-08-14 20:40:13 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-14 20:40:13 -0500 |
| commit | e74ed047dbaf3877db4a89a2d589e992abd0bb11 (patch) | |
| tree | 0a728c8be167a1d59a5492ed9df666f41cf12e57 /azalea-physics | |
| parent | 6695132ddb31780786c67b8b9ff5df8ab3891438 (diff) | |
| download | azalea-drasl-e74ed047dbaf3877db4a89a2d589e992abd0bb11.tar.xz | |
Sneaking (#237)
* start implementing sneaking
* fix horizontal_collision being inverted and cleanup
* clippy
* change dimensions and eye height based on pose
* proper support for automatically crouching in certain cases
* fix anticheat issues
* add line to changelog and update a comment
Diffstat (limited to 'azalea-physics')
| -rw-r--r-- | azalea-physics/src/collision/mod.rs | 226 | ||||
| -rw-r--r-- | azalea-physics/src/lib.rs | 117 | ||||
| -rw-r--r-- | azalea-physics/src/local_player.rs | 67 | ||||
| -rw-r--r-- | azalea-physics/src/travel.rs | 246 |
4 files changed, 382 insertions, 274 deletions
diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index dc439f7b..d8ac3a95 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -11,9 +11,13 @@ use azalea_block::{BlockState, fluid_state::FluidState}; use azalea_core::{ aabb::AABB, direction::Axis, - math::EPSILON, + math::{self, EPSILON}, position::{BlockPos, Vec3}, }; +use azalea_entity::{ + Attributes, Jumping, LookDirection, OnClimbable, Physics, PlayerAbilities, Pose, Position, + metadata::Sprinting, +}; use azalea_world::{ChunkStorage, Instance, MoveEntityError}; use bevy_ecs::{entity::Entity, world::Mut}; pub use blocks::BlockWithShape; @@ -23,6 +27,7 @@ pub use shape::*; use tracing::warn; use self::world_collisions::get_block_collisions; +use crate::{local_player::PhysicsState, travel::no_collision}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MoverType { @@ -34,22 +39,16 @@ pub enum MoverType { } // Entity.collide -fn collide( - movement: Vec3, - world: &Instance, - physics: &azalea_entity::Physics, - source_entity: Option<Entity>, - physics_query: &PhysicsQuery, - collidable_entity_query: &CollidableEntityQuery, -) -> Vec3 { - let entity_bounding_box = physics.bounding_box; +fn collide(ctx: &MoveCtx, movement: Vec3) -> Vec3 { + let entity_bounding_box = ctx.physics.bounding_box; let entity_collisions = get_entity_collisions( - world, + ctx.world, &entity_bounding_box.expand_towards(movement), - source_entity, - physics_query, - collidable_entity_query, + Some(ctx.source_entity), + ctx.physics_query, + ctx.collidable_entity_query, ); + let world = ctx.world; let collided_delta = if movement.length_squared() == 0.0 { movement } else { @@ -60,7 +59,7 @@ fn collide( let y_collision = movement.y != collided_delta.y; let z_collision = movement.z != collided_delta.z; - let on_ground = physics.on_ground() || y_collision && movement.y < 0.; + let on_ground = ctx.physics.on_ground() || y_collision && movement.y < 0.; let max_up_step = 0.6; if max_up_step > 0. && on_ground && (x_collision || z_collision) { @@ -106,20 +105,30 @@ fn collide( collided_delta } +pub struct MoveCtx<'world, 'state, 'a, 'b> { + pub mover_type: MoverType, + pub world: &'a Instance, + pub position: Mut<'a, Position>, + pub physics: &'a mut Physics, + pub source_entity: Entity, + pub physics_query: &'a PhysicsQuery<'world, 'state, 'b>, + pub collidable_entity_query: &'a CollidableEntityQuery<'world, 'state>, + pub physics_state: Option<&'a PhysicsState>, + pub attributes: &'a Attributes, + pub abilities: Option<&'a PlayerAbilities>, + + pub direction: LookDirection, + pub sprinting: Sprinting, + pub on_climbable: OnClimbable, + pub pose: Option<Pose>, + pub jumping: Jumping, +} + /// Move an entity by a given delta, checking for collisions. /// /// In Mojmap, this is `Entity.move`. #[allow(clippy::too_many_arguments)] -pub fn move_colliding( - _mover_type: MoverType, - movement: Vec3, - world: &Instance, - position: &mut Mut<azalea_entity::Position>, - physics: &mut azalea_entity::Physics, - source_entity: Option<Entity>, - physics_query: &PhysicsQuery, - collidable_entity_query: &CollidableEntityQuery, -) -> Result<(), MoveEntityError> { +pub fn move_colliding(ctx: &mut MoveCtx, mut movement: Vec3) -> Result<(), MoveEntityError> { // TODO: do all these // if self.no_physics { @@ -139,20 +148,16 @@ pub fn move_colliding( // this.setDeltaMovement(Vec3.ZERO); // } - // movement = this.maybeBackOffFromEdge(movement, moverType); + movement = maybe_back_off_from_edge(ctx, movement); + let collide_result = collide(ctx, movement); - let collide_result = collide( - movement, - world, - physics, - source_entity, - physics_query, - collidable_entity_query, - ); + let move_distance_sqr = collide_result.length_squared(); - let move_distance = collide_result.length_squared(); + let position = &mut ctx.position; + let physics = &mut *ctx.physics; + let world = ctx.world; - if move_distance > EPSILON { + if move_distance_sqr > EPSILON || movement.length_squared() - move_distance_sqr < EPSILON { // TODO: fall damage let new_pos = { @@ -168,8 +173,8 @@ pub fn move_colliding( } } - let x_collision = movement.x != collide_result.x; - let z_collision = movement.z != collide_result.z; + let x_collision = !math::equal(movement.x, collide_result.x); + let z_collision = !math::equal(movement.z, collide_result.z); let horizontal_collision = x_collision || z_collision; physics.horizontal_collision = horizontal_collision; @@ -180,14 +185,15 @@ pub fn move_colliding( // TODO: minecraft checks for a "minor" horizontal collision here - let _block_pos_below = azalea_entity::on_pos_legacy(&world.chunks, **position); - // let _block_state_below = self - // .world - // .get_block_state(&block_pos_below) - // .expect("Couldn't get block state below"); + let block_pos_below = azalea_entity::on_pos_legacy(&world.chunks, **position); + let block_state_below = world.get_block_state(block_pos_below).unwrap_or_default(); - // self.check_fall_damage(collide_result.y, on_ground, block_state_below, - // block_pos_below); + check_fall_damage( + physics, + collide_result.y, + block_state_below, + block_pos_below, + ); // if self.isRemoved() { return; } @@ -238,6 +244,136 @@ pub fn move_colliding( Ok(()) } +fn check_fall_damage( + physics: &mut Physics, + delta_y: f64, + _block_state_below: BlockState, + _block_pos_below: BlockPos, +) { + if !physics.is_in_water() && delta_y < 0. { + physics.fall_distance -= delta_y as f32 as f64; + } + + if physics.on_ground() { + // vanilla calls block.fallOn here but it's not relevant for us + + physics.fall_distance = 0.; + } +} + +fn maybe_back_off_from_edge(move_ctx: &mut MoveCtx, mut movement: Vec3) -> Vec3 { + let is_staying_on_ground_surface = move_ctx.physics_state.is_some_and(|s| s.trying_to_crouch); + let max_up_step = get_max_up_step(move_ctx.attributes); + + let fall_ctx = CanFallAtLeastCtx { + physics: move_ctx.physics, + world: move_ctx.world, + source_entity: move_ctx.source_entity, + physics_query: move_ctx.physics_query, + collidable_entity_query: move_ctx.collidable_entity_query, + }; + + let Some(abilities) = move_ctx.abilities else { + return movement; + }; + + let is_backing_off = !abilities.flying + && movement.y <= 0. + && matches!(move_ctx.mover_type, MoverType::Own | MoverType::Player) + && is_staying_on_ground_surface + && is_above_ground(&fall_ctx, max_up_step); + if !is_backing_off { + return movement; + } + + let min_movement = 0.05; + let min_movement_x = movement.x.signum() * min_movement; + let min_movement_z = movement.z.signum() * min_movement; + + while movement.x != 0. && can_fall_at_least(&fall_ctx, movement.x, 0., max_up_step as f64) { + if movement.x.abs() <= min_movement { + movement.x = 0.; + break; + } + + movement.x -= min_movement_x + } + while movement.z != 0. && can_fall_at_least(&fall_ctx, 0., movement.z, max_up_step as f64) { + if movement.z.abs() <= min_movement { + movement.z = 0.; + break; + } + + movement.z -= min_movement_z + } + while movement.x != 0.0 + && movement.z != 0.0 + && can_fall_at_least(&fall_ctx, movement.x, movement.z, max_up_step as f64) + { + if movement.x.abs() <= min_movement { + movement.x = 0.; + } else { + movement.x -= min_movement_x; + } + if movement.z.abs() <= min_movement { + movement.z = 0.; + } else { + movement.z -= min_movement_z; + } + } + + movement +} + +fn get_max_up_step(attributes: &Attributes) -> f32 { + // this would be different if we were riding an entity + attributes.step_height.calculate() as f32 +} + +fn is_above_ground(ctx: &CanFallAtLeastCtx, max_up_step: f32) -> bool { + ctx.physics.on_ground() + && ctx.physics.fall_distance < max_up_step as f64 + && !can_fall_at_least(ctx, 0., 0., max_up_step as f64 - ctx.physics.fall_distance) +} + +pub struct CanFallAtLeastCtx<'world, 'state, 'a, 'b> { + physics: &'a Physics, + world: &'a Instance, + source_entity: Entity, + physics_query: &'a PhysicsQuery<'world, 'state, 'b>, + collidable_entity_query: &'a CollidableEntityQuery<'world, 'state>, +} + +fn can_fall_at_least( + ctx: &CanFallAtLeastCtx, + delta_x: f64, + delta_z: f64, + max_up_step: f64, +) -> bool { + let aabb = ctx.physics.bounding_box; + let aabb = AABB { + min: Vec3 { + x: aabb.min.x + EPSILON + delta_x, + y: aabb.min.y - max_up_step - EPSILON, + z: aabb.min.z + EPSILON + delta_z, + }, + max: Vec3 { + x: aabb.max.x - EPSILON + delta_x, + y: aabb.min.y, + z: aabb.max.z - EPSILON + delta_z, + }, + }; + no_collision( + ctx.world, + Some(ctx.source_entity), + ctx.physics_query, + ctx.collidable_entity_query, + ctx.physics, + &aabb, + false, + ) +} + fn collide_bounding_box( movement: Vec3, entity_bounding_box: &AABB, diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index 27250f61..fb62b48b 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -4,6 +4,7 @@ pub mod clip; pub mod collision; pub mod fluids; +pub mod local_player; pub mod travel; use std::collections::HashSet; @@ -16,18 +17,17 @@ use azalea_core::{ }; use azalea_entity::{ Attributes, EntityKindComponent, HasClientLoaded, Jumping, LocalEntity, LookDirection, - OnClimbable, Physics, Pose, Position, metadata::Sprinting, move_relative, + OnClimbable, Physics, Pose, Position, dimensions::EntityDimensions, metadata::Sprinting, + move_relative, }; use azalea_registry::{Block, EntityKind}; use azalea_world::{Instance, InstanceContainer, InstanceName}; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use clip::box_traverse_blocks; -use collision::{ - BLOCK_SHAPE, BlockWithShape, MoverType, VoxelShape, - entity_collisions::{CollidableEntityQuery, PhysicsQuery}, - move_colliding, -}; +use collision::{BLOCK_SHAPE, BlockWithShape, VoxelShape, move_colliding}; + +use crate::collision::MoveCtx; /// A Bevy [`SystemSet`] for running physics that makes entities do things. #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] @@ -161,12 +161,12 @@ fn jump_in_liquid(physics: &mut Physics) { #[allow(clippy::type_complexity)] pub fn apply_effects_from_blocks( mut query: Query< - (&mut Physics, &Position, &InstanceName), + (&mut Physics, &Position, &EntityDimensions, &InstanceName), (With<LocalEntity>, With<HasClientLoaded>), >, instance_container: Res<InstanceContainer>, ) { - for (mut physics, position, world_name) in &mut query { + for (mut physics, position, dimensions, world_name) in &mut query { let Some(world_lock) = instance_container.get(world_name) else { continue; }; @@ -189,12 +189,13 @@ pub fn apply_effects_from_blocks( to: **position, }]; - check_inside_blocks(&mut physics, &world, &movement_this_tick); + check_inside_blocks(&mut physics, dimensions, &world, &movement_this_tick); } } fn check_inside_blocks( physics: &mut Physics, + dimensions: &EntityDimensions, world: &Instance, movements: &[EntityMovement], ) -> Vec<BlockState> { @@ -202,8 +203,7 @@ fn check_inside_blocks( let mut visited_blocks = HashSet::<BlockState>::new(); for movement in movements { - let bounding_box_at_target = physics - .dimensions + let bounding_box_at_target = dimensions .make_bounding_box(movement.to) .deflate_all(1.0E-5); @@ -242,7 +242,7 @@ fn check_inside_blocks( movement.to, traversed_block, entity_inside_collision_shape, - physics, + dimensions, ) { continue; @@ -262,9 +262,9 @@ fn collided_with_shape_moving_from( to: Vec3, traversed_block: BlockPos, entity_inside_collision_shape: &VoxelShape, - physics: &Physics, + dimensions: &EntityDimensions, ) -> bool { - let bounding_box_from = physics.dimensions.make_bounding_box(from); + let bounding_box_from = dimensions.make_bounding_box(from); let delta = to - from; bounding_box_from.collided_along_vector( delta, @@ -367,63 +367,27 @@ fn get_block_pos_below_that_affects_movement(position: Position) -> BlockPos { ) } -/// Options for [`handle_relative_friction_and_calculate_movement`] -struct HandleRelativeFrictionAndCalculateMovementOpts<'a, 'b, 'world, 'state> { - block_friction: f32, - world: &'a Instance, - physics: &'a mut Physics, - direction: LookDirection, - position: Mut<'a, Position>, - attributes: &'a Attributes, - is_sprinting: bool, - on_climbable: OnClimbable, - pose: Option<Pose>, - jumping: Jumping, - entity: Entity, - physics_query: &'a PhysicsQuery<'world, 'state, 'b>, - collidable_entity_query: &'a CollidableEntityQuery<'world, 'state>, -} -fn handle_relative_friction_and_calculate_movement( - HandleRelativeFrictionAndCalculateMovementOpts { - block_friction, - world, - physics, - direction, - mut position, - attributes, - is_sprinting, - on_climbable, - pose, - jumping, - entity, - physics_query, - collidable_entity_query, - }: HandleRelativeFrictionAndCalculateMovementOpts<'_, '_, '_, '_>, -) -> Vec3 { +fn handle_relative_friction_and_calculate_movement(ctx: &mut MoveCtx, block_friction: f32) -> Vec3 { move_relative( - physics, - direction, - get_friction_influenced_speed(physics, attributes, block_friction, is_sprinting), + ctx.physics, + ctx.direction, + get_friction_influenced_speed(ctx.physics, ctx.attributes, block_friction, ctx.sprinting), Vec3::new( - physics.x_acceleration as f64, - physics.y_acceleration as f64, - physics.z_acceleration as f64, + ctx.physics.x_acceleration as f64, + ctx.physics.y_acceleration as f64, + ctx.physics.z_acceleration as f64, ), ); - physics.velocity = handle_on_climbable(physics.velocity, on_climbable, *position, world, pose); - - move_colliding( - MoverType::Own, - physics.velocity, - world, - &mut position, - physics, - Some(entity), - physics_query, - collidable_entity_query, - ) - .expect("Entity should exist"); + ctx.physics.velocity = handle_on_climbable( + ctx.physics.velocity, + ctx.on_climbable, + *ctx.position, + ctx.world, + ctx.pose, + ); + + move_colliding(ctx, ctx.physics.velocity).expect("Entity should exist"); // let delta_movement = entity.delta; // ladders // if ((entity.horizontalCollision || entity.jumping) && (entity.onClimbable() @@ -431,19 +395,20 @@ fn handle_relative_friction_and_calculate_movement( // PowderSnowBlock.canEntityWalkOnPowderSnow(entity))) { var3 = new // Vec3(var3.x, 0.2D, var3.z); } - if physics.horizontal_collision || *jumping { - let block_at_feet: Block = world + if ctx.physics.horizontal_collision || *ctx.jumping { + let block_at_feet: Block = ctx + .world .chunks - .get_block_state((*position).into()) + .get_block_state(BlockPos::from(*ctx.position)) .unwrap_or_default() .into(); - if *on_climbable || block_at_feet == Block::PowderSnow { - physics.velocity.y = 0.2; + if *ctx.on_climbable || block_at_feet == Block::PowderSnow { + ctx.physics.velocity.y = 0.2; } } - physics.velocity + ctx.physics.velocity } fn handle_on_climbable( @@ -467,7 +432,7 @@ fn handle_on_climbable( // sneaking on ladders/vines if y < 0.0 - && pose == Some(Pose::Sneaking) + && pose == Some(Pose::Crouching) && azalea_registry::Block::from( world .chunks @@ -488,15 +453,15 @@ fn get_friction_influenced_speed( physics: &Physics, attributes: &Attributes, friction: f32, - is_sprinting: bool, + sprinting: Sprinting, ) -> f32 { // TODO: have speed & flying_speed fields in entity if physics.on_ground() { - let speed: f32 = attributes.speed.calculate() as f32; + let speed = attributes.movement_speed.calculate() as f32; speed * (0.21600002f32 / (friction * friction * friction)) } else { // entity.flying_speed - if is_sprinting { 0.025999999f32 } else { 0.02 } + if *sprinting { 0.025999999f32 } else { 0.02 } } } diff --git a/azalea-physics/src/local_player.rs b/azalea-physics/src/local_player.rs new file mode 100644 index 00000000..6ce196b6 --- /dev/null +++ b/azalea-physics/src/local_player.rs @@ -0,0 +1,67 @@ +use azalea_core::position::Vec2; +use bevy_ecs::component::Component; + +/// Component for entities that can move and sprint. Usually only in +/// [`LocalEntity`]s. +/// +/// [`LocalEntity`]: azalea_entity::LocalEntity +#[derive(Default, Component, Clone)] +pub struct PhysicsState { + /// Minecraft only sends a movement packet either after 20 ticks or if the + /// player moved enough. This is that tick counter. + pub position_remainder: u32, + pub was_sprinting: bool, + // Whether we're going to try to start sprinting this tick. Equivalent to + // holding down ctrl for a tick. + pub trying_to_sprint: bool, + + /// Whether our player is currently trying to sneak. + /// + /// This is distinct from + /// [`AbstractEntityShiftKeyDown`](azalea_entity::metadata::AbstractEntityShiftKeyDown), + /// which is a metadata value that is controlled by the server and affects + /// how the nametags of other entities are displayed. + /// + /// To check whether we're actually sneaking, you can check the + /// [`Crouching`] or [`Pose`] components. + pub trying_to_crouch: bool, + + pub move_direction: WalkDirection, + pub move_vector: Vec2, +} + +/// A direction that a player can walk in, including none. +/// +/// Superset of [`SprintDirection`]. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub enum WalkDirection { + #[default] + None, + Forward, + Backward, + Left, + Right, + ForwardRight, + ForwardLeft, + BackwardRight, + BackwardLeft, +} + +/// The directions that a player can sprint in. It's a subset of +/// [`WalkDirection`]. +#[derive(Clone, Copy, Debug)] +pub enum SprintDirection { + Forward, + ForwardRight, + ForwardLeft, +} + +impl From<SprintDirection> for WalkDirection { + fn from(d: SprintDirection) -> Self { + match d { + SprintDirection::Forward => WalkDirection::Forward, + SprintDirection::ForwardRight => WalkDirection::ForwardRight, + SprintDirection::ForwardLeft => WalkDirection::ForwardLeft, + } + } +} diff --git a/azalea-physics/src/travel.rs b/azalea-physics/src/travel.rs index 80c289d9..1c473a45 100644 --- a/azalea-physics/src/travel.rs +++ b/azalea-physics/src/travel.rs @@ -4,20 +4,21 @@ use azalea_core::{ position::{BlockPos, Vec3}, }; use azalea_entity::{ - Attributes, HasClientLoaded, Jumping, LocalEntity, LookDirection, OnClimbable, Physics, Pose, - Position, metadata::Sprinting, move_relative, + Attributes, HasClientLoaded, Jumping, LocalEntity, LookDirection, OnClimbable, Physics, + PlayerAbilities, Pose, Position, metadata::Sprinting, move_relative, }; use azalea_world::{Instance, InstanceContainer, InstanceName}; use bevy_ecs::prelude::*; use crate::{ - HandleRelativeFrictionAndCalculateMovementOpts, collision::{ - MoverType, Shapes, + MoveCtx, MoverType, Shapes, entity_collisions::{CollidableEntityQuery, PhysicsQuery, get_entity_collisions}, move_colliding, + world_collisions::{get_block_and_liquid_collisions, get_block_collisions}, }, get_block_pos_below_that_affects_movement, handle_relative_friction_and_calculate_movement, + local_player::PhysicsState, }; /// Move the entity with the given acceleration while handling friction, @@ -27,15 +28,17 @@ pub fn travel( mut query: Query< ( Entity, - &mut Physics, - &mut LookDirection, - &mut Position, - Option<&Sprinting>, - Option<&Pose>, &Attributes, &InstanceName, &OnClimbable, &Jumping, + Option<&PhysicsState>, + Option<&Sprinting>, + Option<&Pose>, + Option<&PlayerAbilities>, + &mut Physics, + &mut LookDirection, + &mut Position, ), (With<LocalEntity>, With<HasClientLoaded>), >, @@ -45,15 +48,17 @@ pub fn travel( ) { for ( entity, - mut physics, - direction, - position, - sprinting, - pose, attributes, world_name, on_climbable, jumping, + physics_state, + sprinting, + pose, + abilities, + mut physics, + direction, + position, ) in &mut query { let Some(world_lock) = instance_container.get(world_name) else { @@ -65,92 +70,57 @@ pub fn travel( // TODO: elytras - if physics.is_in_water() || physics.is_in_lava() { + let mut ctx = MoveCtx { + mover_type: MoverType::Own, + world: &world, + position, + physics: &mut physics, + source_entity: entity, + physics_query: &physics_query, + collidable_entity_query: &collidable_entity_query, + physics_state, + attributes, + abilities, + direction: *direction, + sprinting, + on_climbable: *on_climbable, + pose: pose.copied(), + jumping: *jumping, + }; + + if ctx.physics.is_in_water() || ctx.physics.is_in_lava() { // minecraft also checks for `this.isAffectedByFluids() && // !this.canStandOnFluid(fluidAtBlock)` here but it doesn't matter // for players - travel_in_fluid( - &world, - entity, - &mut physics, - *direction, - position, - attributes, - sprinting, - on_climbable, - &physics_query, - &collidable_entity_query, - ); + travel_in_fluid(&mut ctx); } else { - travel_in_air( - &world, - entity, - &mut physics, - *direction, - position, - attributes, - sprinting, - *on_climbable, - pose, - *jumping, - &physics_query, - &collidable_entity_query, - ); + travel_in_air(&mut ctx); } } } /// The usual movement when we're not in water or using an elytra. -#[allow(clippy::too_many_arguments)] -fn travel_in_air( - world: &Instance, - entity: Entity, - physics: &mut Physics, - direction: LookDirection, - position: Mut<Position>, - attributes: &Attributes, - sprinting: Sprinting, - on_climbable: OnClimbable, - pose: Option<&Pose>, - jumping: Jumping, - physics_query: &PhysicsQuery, - collidable_entity_query: &CollidableEntityQuery, -) { +fn travel_in_air(ctx: &mut MoveCtx) { let gravity = get_effective_gravity(); - let block_pos_below = get_block_pos_below_that_affects_movement(*position); + let block_pos_below = get_block_pos_below_that_affects_movement(*ctx.position); - let block_state_below = world + let block_state_below = ctx + .world .chunks .get_block_state(block_pos_below) .unwrap_or(BlockState::AIR); let block_below: Box<dyn BlockTrait> = block_state_below.into(); let block_friction = block_below.behavior().friction; - let inertia = if physics.on_ground() { + let inertia = if ctx.physics.on_ground() { block_friction * 0.91 } else { 0.91 }; // this applies the current delta - let mut movement = handle_relative_friction_and_calculate_movement( - HandleRelativeFrictionAndCalculateMovementOpts { - block_friction, - world, - physics, - direction, - position, - attributes, - is_sprinting: *sprinting, - on_climbable, - pose: pose.copied(), - jumping, - entity, - physics_query, - collidable_entity_query, - }, - ); + let mut movement = handle_relative_friction_and_calculate_movement(ctx, block_friction); movement.y -= gravity; @@ -162,9 +132,9 @@ fn travel_in_air( // if should_discard_friction(self) { if false { - physics.velocity = movement; + ctx.physics.velocity = movement; } else { - physics.velocity = Vec3 { + ctx.physics.velocity = Vec3 { x: movement.x * inertia as f64, y: movement.y * 0.9800000190734863f64, z: movement.z * inertia as f64, @@ -172,116 +142,86 @@ fn travel_in_air( } } -#[allow(clippy::too_many_arguments)] -fn travel_in_fluid( - world: &Instance, - entity: Entity, - physics: &mut Physics, - direction: LookDirection, - mut position: Mut<Position>, - attributes: &Attributes, - sprinting: Sprinting, - on_climbable: &OnClimbable, - physics_query: &PhysicsQuery, - collidable_entity_query: &CollidableEntityQuery, -) { - let moving_down = physics.velocity.y <= 0.; - let y = position.y; +fn travel_in_fluid(ctx: &mut MoveCtx) { + let moving_down = ctx.physics.velocity.y <= 0.; + let y = ctx.position.y; let gravity = get_effective_gravity(); let acceleration = Vec3::new( - physics.x_acceleration as f64, - physics.y_acceleration as f64, - physics.z_acceleration as f64, + ctx.physics.x_acceleration as f64, + ctx.physics.y_acceleration as f64, + ctx.physics.z_acceleration as f64, ); - if physics.was_touching_water { - let mut water_movement_speed = if *sprinting { 0.9 } else { 0.8 }; + if ctx.physics.was_touching_water { + let mut water_movement_speed = if *ctx.sprinting { 0.9 } else { 0.8 }; let mut speed = 0.02; - let mut water_efficiency_modifier = attributes.water_movement_efficiency.calculate() as f32; - if !physics.on_ground() { + let mut water_efficiency_modifier = + ctx.attributes.water_movement_efficiency.calculate() as f32; + if !ctx.physics.on_ground() { water_efficiency_modifier *= 0.5; } if water_efficiency_modifier > 0. { water_movement_speed += (0.54600006 - water_movement_speed) * water_efficiency_modifier; - speed += (attributes.speed.calculate() as f32 - speed) * water_efficiency_modifier; + speed += (ctx.attributes.movement_speed.calculate() as f32 - speed) + * water_efficiency_modifier; } // if (this.hasEffect(MobEffects.DOLPHINS_GRACE)) { // waterMovementSpeed = 0.96F; // } - move_relative(physics, direction, speed, acceleration); - move_colliding( - MoverType::Own, - physics.velocity, - world, - &mut position, - physics, - Some(entity), - physics_query, - collidable_entity_query, - ) - .expect("Entity should exist"); + move_relative(ctx.physics, ctx.direction, speed, acceleration); + move_colliding(ctx, ctx.physics.velocity).expect("Entity should exist"); - let mut new_velocity = physics.velocity; - if physics.horizontal_collision && **on_climbable { + let mut new_velocity = ctx.physics.velocity; + if ctx.physics.horizontal_collision && *ctx.on_climbable { // underwater ladders new_velocity.y = 0.2; } new_velocity.x *= water_movement_speed as f64; new_velocity.y *= 0.8; new_velocity.z *= water_movement_speed as f64; - physics.velocity = - get_fluid_falling_adjusted_movement(gravity, moving_down, new_velocity, sprinting); + ctx.physics.velocity = + get_fluid_falling_adjusted_movement(gravity, moving_down, new_velocity, ctx.sprinting); } else { - move_relative(physics, direction, 0.02, acceleration); - move_colliding( - MoverType::Own, - physics.velocity, - world, - &mut position, - physics, - Some(entity), - physics_query, - collidable_entity_query, - ) - .expect("Entity should exist"); + move_relative(ctx.physics, ctx.direction, 0.02, acceleration); + move_colliding(ctx, ctx.physics.velocity).expect("Entity should exist"); - if physics.lava_fluid_height <= fluid_jump_threshold() { - physics.velocity.x *= 0.5; - physics.velocity.y *= 0.8; - physics.velocity.z *= 0.5; + if ctx.physics.lava_fluid_height <= fluid_jump_threshold() { + ctx.physics.velocity.x *= 0.5; + ctx.physics.velocity.y *= 0.8; + ctx.physics.velocity.z *= 0.5; let new_velocity = get_fluid_falling_adjusted_movement( gravity, moving_down, - physics.velocity, - sprinting, + ctx.physics.velocity, + ctx.sprinting, ); - physics.velocity = new_velocity; + ctx.physics.velocity = new_velocity; } else { - physics.velocity *= 0.5; + ctx.physics.velocity *= 0.5; } if gravity != 0.0 { - physics.velocity.y -= gravity / 4.0; + ctx.physics.velocity.y -= gravity / 4.0; } } - let velocity = physics.velocity; - if physics.horizontal_collision + let velocity = ctx.physics.velocity; + if ctx.physics.horizontal_collision && is_free( - world, - entity, - physics_query, - collidable_entity_query, - physics, - physics.bounding_box, - velocity.up(0.6).down(position.y).up(y), + ctx.world, + ctx.source_entity, + ctx.physics_query, + ctx.collidable_entity_query, + ctx.physics, + ctx.physics.bounding_box, + velocity.up(0.6).down(ctx.position.y).up(y), ) { - physics.velocity.y = 0.3; + ctx.physics.velocity.y = 0.3; } } @@ -316,7 +256,7 @@ fn is_free( source_entity: Entity, physics_query: &PhysicsQuery, collidable_entity_query: &CollidableEntityQuery, - entity_physics: &mut Physics, + entity_physics: &Physics, bounding_box: AABB, delta: Vec3, ) -> bool { @@ -333,19 +273,19 @@ fn is_free( ) && !contains_any_liquid(world, bounding_box) } -fn no_collision( +pub fn no_collision( world: &Instance, source_entity: Option<Entity>, physics_query: &PhysicsQuery, collidable_entity_query: &CollidableEntityQuery, - entity_physics: &mut Physics, + entity_physics: &Physics, aabb: &AABB, include_liquid_collisions: bool, ) -> bool { let collisions = if include_liquid_collisions { - crate::collision::world_collisions::get_block_and_liquid_collisions(world, aabb) + get_block_and_liquid_collisions(world, aabb) } else { - crate::collision::world_collisions::get_block_collisions(world, aabb) + get_block_collisions(world, aabb) }; for collision in collisions { |
