diff --git a/azalea-client/src/movement.rs b/azalea-client/src/movement.rs index 03183e244..bdc29f2fb 100644 --- a/azalea-client/src/movement.rs +++ b/azalea-client/src/movement.rs @@ -195,7 +195,7 @@ pub fn send_position( pos: **position, x_rot: direction.x_rot, y_rot: direction.y_rot, - on_ground: physics.on_ground, + on_ground: physics.on_ground(), } .into_variant(), ) @@ -205,7 +205,7 @@ pub fn send_position( x: position.x, y: position.y, z: position.z, - on_ground: physics.on_ground, + on_ground: physics.on_ground(), } .into_variant(), ) @@ -214,14 +214,14 @@ pub fn send_position( ServerboundMovePlayerRot { x_rot: direction.x_rot, y_rot: direction.y_rot, - on_ground: physics.on_ground, + on_ground: physics.on_ground(), } .into_variant(), ) - } else if physics.last_on_ground != physics.on_ground { + } else if physics.last_on_ground() != physics.on_ground() { Some( ServerboundMovePlayerStatusOnly { - on_ground: physics.on_ground, + on_ground: physics.on_ground(), } .into_variant(), ) @@ -238,7 +238,8 @@ pub fn send_position( last_direction.x_rot = direction.x_rot; } - physics.last_on_ground = physics.on_ground; + let on_ground = physics.on_ground(); + physics.set_last_on_ground(on_ground); // minecraft checks for autojump here, but also autojump is bad so packet diff --git a/azalea-client/src/packet_handling/game.rs b/azalea-client/src/packet_handling/game.rs index d4d84f758..0c505d07f 100644 --- a/azalea-client/src/packet_handling/game.rs +++ b/azalea-client/src/packet_handling/game.rs @@ -451,8 +451,16 @@ pub fn process_packet_events(ecs: &mut World) { let new_y = apply_change(position.y, p.relative.y, p.change.pos.y); let new_z = apply_change(position.z, p.relative.z, p.change.pos.z); - let new_y_rot = apply_change(direction.y_rot, p.relative.y_rot, p.change.y_rot); - let new_x_rot = apply_change(direction.x_rot, p.relative.x_rot, p.change.x_rot); + let new_y_rot = apply_change( + direction.y_rot, + p.relative.y_rot, + p.change.look_direction.y_rot, + ); + let new_x_rot = apply_change( + direction.x_rot, + p.relative.x_rot, + p.change.look_direction.x_rot, + ); let mut new_delta_from_rotations = physics.velocity; if p.relative.rotate_delta { @@ -829,30 +837,29 @@ pub fn process_packet_events(ecs: &mut World) { let (mut commands, mut query) = system_state.get_mut(ecs); let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); - let entity = entity_id_index.get(&MinecraftEntityId(p.id)); - - if let Some(entity) = entity { - let new_pos = p.position; - let new_look_direction = LookDirection { - x_rot: (p.x_rot as i32 * 360) as f32 / 256., - y_rot: (p.y_rot as i32 * 360) as f32 / 256., - }; - commands.entity(entity).queue(RelativeEntityUpdate { - partial_world: instance_holder.partial_instance.clone(), - update: Box::new(move |entity| { - let mut position = entity.get_mut::().unwrap(); - if new_pos != **position { - **position = new_pos; - } - let mut look_direction = entity.get_mut::().unwrap(); - if new_look_direction != *look_direction { - *look_direction = new_look_direction; - } - }), - }); - } else { + let Some(entity) = entity_id_index.get(&MinecraftEntityId(p.id)) else { warn!("Got teleport entity packet for unknown entity id {}", p.id); - } + continue; + }; + + let new_pos = p.position; + let new_look_direction = LookDirection { + x_rot: (p.x_rot as i32 * 360) as f32 / 256., + y_rot: (p.y_rot as i32 * 360) as f32 / 256., + }; + commands.entity(entity).queue(RelativeEntityUpdate { + partial_world: instance_holder.partial_instance.clone(), + update: Box::new(move |entity| { + let mut position = entity.get_mut::().unwrap(); + if new_pos != **position { + **position = new_pos; + } + let mut look_direction = entity.get_mut::().unwrap(); + if new_look_direction != *look_direction { + *look_direction = new_look_direction; + } + }), + }); system_state.apply(ecs); } @@ -870,15 +877,26 @@ pub fn process_packet_events(ecs: &mut World) { let (mut commands, mut query) = system_state.get_mut(ecs); let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); + debug!("Got move entity pos packet {p:?}"); + let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id)); if let Some(entity) = entity { - let delta = p.delta.clone(); + let new_delta = p.delta.clone(); + let new_on_ground = p.on_ground; commands.entity(entity).queue(RelativeEntityUpdate { partial_world: instance_holder.partial_instance.clone(), update: Box::new(move |entity_mut| { + let mut physics = entity_mut.get_mut::().unwrap(); + let new_pos = physics.vec_delta_codec.decode( + new_delta.xa as i64, + new_delta.ya as i64, + new_delta.za as i64, + ); + physics.vec_delta_codec.set_base(new_pos); + physics.set_on_ground(new_on_ground); + let mut position = entity_mut.get_mut::().unwrap(); - let new_pos = position.with_delta(&delta); if new_pos != **position { **position = new_pos; } @@ -901,23 +919,36 @@ pub fn process_packet_events(ecs: &mut World) { let (mut commands, mut query) = system_state.get_mut(ecs); let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); + debug!("Got move entity pos rot packet {p:?}"); + let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id)); if let Some(entity) = entity { - let delta = p.delta.clone(); + let new_delta = p.delta.clone(); let new_look_direction = LookDirection { x_rot: (p.x_rot as i32 * 360) as f32 / 256., y_rot: (p.y_rot as i32 * 360) as f32 / 256., }; + let new_on_ground = p.on_ground; + commands.entity(entity).queue(RelativeEntityUpdate { partial_world: instance_holder.partial_instance.clone(), update: Box::new(move |entity_mut| { + let mut physics = entity_mut.get_mut::().unwrap(); + let new_pos = physics.vec_delta_codec.decode( + new_delta.xa as i64, + new_delta.ya as i64, + new_delta.za as i64, + ); + physics.vec_delta_codec.set_base(new_pos); + physics.set_on_ground(new_on_ground); + let mut position = entity_mut.get_mut::().unwrap(); - let new_pos = position.with_delta(&delta); if new_pos != **position { **position = new_pos; } + let mut look_direction = entity_mut.get_mut::().unwrap(); if new_look_direction != *look_direction { *look_direction = new_look_direction; @@ -949,10 +980,14 @@ pub fn process_packet_events(ecs: &mut World) { x_rot: (p.x_rot as i32 * 360) as f32 / 256., y_rot: (p.y_rot as i32 * 360) as f32 / 256., }; + let new_on_ground = p.on_ground; commands.entity(entity).queue(RelativeEntityUpdate { partial_world: instance_holder.partial_instance.clone(), update: Box::new(move |entity_mut| { + let mut physics = entity_mut.get_mut::().unwrap(); + physics.set_on_ground(new_on_ground); + let mut look_direction = entity_mut.get_mut::().unwrap(); if new_look_direction != *look_direction { *look_direction = new_look_direction; @@ -1416,7 +1451,7 @@ pub fn process_packet_events(ecs: &mut World) { system_state.apply(ecs); } - ClientboundGamePacket::StartConfiguration(_) => { + ClientboundGamePacket::StartConfiguration(_p) => { let mut system_state: SystemState<(Commands, EventWriter)> = SystemState::new(ecs); let (mut commands, mut packet_events) = system_state.get_mut(ecs); @@ -1434,6 +1469,52 @@ pub fn process_packet_events(ecs: &mut World) { system_state.apply(ecs); } + ClientboundGamePacket::EntityPositionSync(p) => { + let mut system_state: SystemState<( + Commands, + Query<(&EntityIdIndex, &InstanceHolder)>, + )> = SystemState::new(ecs); + let (mut commands, mut query) = system_state.get_mut(ecs); + let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); + + let Some(entity) = entity_id_index.get(&MinecraftEntityId(p.id)) else { + warn!("Got teleport entity packet for unknown entity id {}", p.id); + continue; + }; + + let new_position = p.values.pos; + let new_on_ground = p.on_ground; + let new_look_direction = p.values.look_direction; + + commands.entity(entity).queue(RelativeEntityUpdate { + partial_world: instance_holder.partial_instance.clone(), + update: Box::new(move |entity_mut| { + let is_local_entity = entity_mut.get::().is_some(); + let mut physics = entity_mut.get_mut::().unwrap(); + + physics.vec_delta_codec.set_base(new_position); + + if is_local_entity { + debug!("Ignoring entity position sync packet for local player"); + return; + } + + physics.set_on_ground(new_on_ground); + + let mut last_sent_position = + entity_mut.get_mut::().unwrap(); + **last_sent_position = new_position; + let mut position = entity_mut.get_mut::().unwrap(); + **position = new_position; + + let mut look_direction = entity_mut.get_mut::().unwrap(); + *look_direction = new_look_direction; + }), + }); + + system_state.apply(ecs); + } + ClientboundGamePacket::SelectAdvancementsTab(_) => {} ClientboundGamePacket::SetActionBarText(_) => {} ClientboundGamePacket::SetBorderCenter(_) => {} @@ -1476,7 +1557,6 @@ pub fn process_packet_events(ecs: &mut World) { ClientboundGamePacket::ProjectilePower(_) => {} ClientboundGamePacket::CustomReportDetails(_) => {} ClientboundGamePacket::ServerLinks(_) => {} - ClientboundGamePacket::EntityPositionSync(_) => {} ClientboundGamePacket::PlayerRotation(_) => {} ClientboundGamePacket::RecipeBookAdd(_) => {} ClientboundGamePacket::RecipeBookRemove(_) => {} diff --git a/azalea-core/src/position.rs b/azalea-core/src/position.rs index 9b800e288..14ecfcc10 100755 --- a/azalea-core/src/position.rs +++ b/azalea-core/src/position.rs @@ -20,7 +20,7 @@ macro_rules! vec3_impl { ($name:ident, $type:ty) => { impl $name { #[inline] - pub fn new(x: $type, y: $type, z: $type) -> Self { + pub const fn new(x: $type, y: $type, z: $type) -> Self { Self { x, y, z } } @@ -223,6 +223,8 @@ pub struct Vec3 { vec3_impl!(Vec3, f64); impl Vec3 { + pub const ZERO: Vec3 = Vec3::new(0.0, 0.0, 0.0); + /// Get the distance of this vector to the origin by doing /// `sqrt(x^2 + y^2 + z^2)`. pub fn length(&self) -> f64 { diff --git a/azalea-entity/src/dimensions.rs b/azalea-entity/src/dimensions.rs index b5a3f3103..5236b80f4 100755 --- a/azalea-entity/src/dimensions.rs +++ b/azalea-entity/src/dimensions.rs @@ -7,7 +7,7 @@ pub struct EntityDimensions { } impl EntityDimensions { - pub fn make_bounding_box(&self, pos: &Vec3) -> AABB { + pub fn make_bounding_box(&self, pos: Vec3) -> AABB { let radius = (self.width / 2.0) as f64; let height = self.height as f64; AABB { diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs index 1334ee0fd..95a2ed3c1 100644 --- a/azalea-entity/src/lib.rs +++ b/azalea-entity/src/lib.rs @@ -9,6 +9,7 @@ pub mod metadata; pub mod mining; pub mod particle; mod plugin; +pub mod vec_delta_codec; use std::{ fmt::Debug, @@ -17,6 +18,7 @@ use std::{ pub use attributes::Attributes; use azalea_block::BlockState; +use azalea_buf::AzBuf; use azalea_core::{ aabb::AABB, math, @@ -30,6 +32,7 @@ use derive_more::{Deref, DerefMut}; pub use dimensions::EntityDimensions; use plugin::indexing::EntityChunkPos; use uuid::Uuid; +use vec_delta_codec::VecDeltaCodec; use self::attributes::AttributeInstance; pub use crate::plugin::*; @@ -210,7 +213,7 @@ impl From<&LastSentPosition> for BlockPos { pub struct Jumping(bool); /// A component that contains the direction an entity is looking. -#[derive(Debug, Component, Copy, Clone, Default, PartialEq)] +#[derive(Debug, Component, Copy, Clone, Default, PartialEq, AzBuf)] pub struct LookDirection { /// Left and right. Aka yaw. pub y_rot: f32, @@ -245,7 +248,7 @@ impl Eq for LookDirection {} /// The physics data relating to the entity, such as position, velocity, and /// bounding box. -#[derive(Debug, Component, Clone)] +#[derive(Debug, Component, Clone, Default)] pub struct Physics { /// How fast the entity is moving. pub velocity: Vec3, @@ -257,8 +260,10 @@ pub struct Physics { /// Z acceleration. pub zza: f32, - pub on_ground: bool, - pub last_on_ground: bool, + on_ground: bool, + last_on_ground: bool, + + pub vec_delta_codec: VecDeltaCodec, /// The width and height of the entity. pub dimensions: EntityDimensions, @@ -274,7 +279,7 @@ pub struct Physics { } impl Physics { - pub fn new(dimensions: EntityDimensions, pos: &Vec3) -> Self { + pub fn new(dimensions: EntityDimensions, pos: Vec3) -> Self { Self { velocity: Vec3::default(), @@ -292,8 +297,30 @@ impl Physics { horizontal_collision: false, vertical_collision: false, + + vec_delta_codec: VecDeltaCodec::new(pos), } } + + pub fn on_ground(&self) -> bool { + self.on_ground + } + /// Updates [`Self::on_ground`] and [`Self::last_on_ground`]. + pub fn set_on_ground(&mut self, on_ground: bool) { + self.last_on_ground = self.on_ground; + self.on_ground = on_ground; + } + + /// The last value of the on_ground value. + /// + /// This is used by Azalea internally for physics, it might not work as you + /// expect since it can be influenced by packets sent by the server. + pub fn last_on_ground(&self) -> bool { + self.last_on_ground + } + pub fn set_last_on_ground(&mut self, last_on_ground: bool) { + self.last_on_ground = last_on_ground; + } } /// Marker component for entities that are dead. @@ -384,7 +411,7 @@ impl EntityBundle { position: Position(pos), chunk_pos: EntityChunkPos(ChunkPos::from(&pos)), last_sent_position: LastSentPosition(pos), - physics: Physics::new(dimensions, &pos), + physics: Physics::new(dimensions, pos), eye_height: EyeHeight(eye_height), direction: LookDirection::default(), @@ -427,25 +454,3 @@ impl FluidOnEyes { #[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)] pub struct OnClimbable(bool); - -// #[cfg(test)] -// mod tests { -// use super::*; -// use crate::PartialWorld; - -// #[test] -// fn from_mut_entity_to_ref_entity() { -// let mut world = PartialWorld::default(); -// let uuid = Uuid::from_u128(100); -// world.add_entity( -// 0, -// EntityData::new( -// uuid, -// Vec3::default(), -// EntityMetadata::Player(metadata::Player::default()), -// ), -// ); -// let entity: Entity = world.entity_mut(0).unwrap(); -// assert_eq!(entity.uuid, uuid); -// } -// } diff --git a/azalea-entity/src/plugin/mod.rs b/azalea-entity/src/plugin/mod.rs index 67763484b..90d7f1c57 100644 --- a/azalea-entity/src/plugin/mod.rs +++ b/azalea-entity/src/plugin/mod.rs @@ -198,7 +198,7 @@ pub fn clamp_look_direction(mut query: Query<&mut LookDirection>) { /// Cached position in the world must be updated. pub fn update_bounding_box(mut query: Query<(&Position, &mut Physics), Changed>) { for (position, mut physics) in query.iter_mut() { - let bounding_box = physics.dimensions.make_bounding_box(position); + let bounding_box = physics.dimensions.make_bounding_box(**position); physics.bounding_box = bounding_box; } } diff --git a/azalea-entity/src/vec_delta_codec.rs b/azalea-entity/src/vec_delta_codec.rs new file mode 100644 index 000000000..51aa7cea7 --- /dev/null +++ b/azalea-entity/src/vec_delta_codec.rs @@ -0,0 +1,60 @@ +use azalea_core::position::Vec3; + +#[derive(Debug, Clone, Default)] +pub struct VecDeltaCodec { + base: Vec3, +} + +impl VecDeltaCodec { + pub fn new(base: Vec3) -> Self { + Self { base } + } + + pub fn decode(&self, x: i64, y: i64, z: i64) -> Vec3 { + if x == 0 && y == 0 && z == 0 { + return self.base; + } + + let new_x = if x == 0 { + self.base.x + } else { + decode(encode(self.base.x) + x) + }; + let new_y = if y == 0 { + self.base.y + } else { + decode(encode(self.base.y) + y) + }; + let new_z = if z == 0 { + self.base.z + } else { + decode(encode(self.base.z) + z) + }; + + Vec3::new(new_x, new_y, new_z) + } + + pub fn encode_x(&self, pos: Vec3) -> i64 { + encode(pos.x) - encode(self.base.x) + } + pub fn encode_y(&self, pos: Vec3) -> i64 { + encode(pos.y) - encode(self.base.y) + } + pub fn encode_z(&self, pos: Vec3) -> i64 { + encode(pos.z) - encode(self.base.z) + } + + pub fn set_base(&mut self, pos: Vec3) { + self.base = pos; + } + pub fn base(&self) -> Vec3 { + self.base + } +} + +fn encode(value: f64) -> i64 { + (value * 4096.).round() as i64 +} +fn decode(value: i64) -> f64 { + (value as f64) / 4096. +} diff --git a/azalea-physics/src/collision/mod.rs b/azalea-physics/src/collision/mod.rs index 7d7ddc5e4..913cedacd 100644 --- a/azalea-physics/src/collision/mod.rs +++ b/azalea-physics/src/collision/mod.rs @@ -73,7 +73,7 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics) 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 = 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) { @@ -192,7 +192,7 @@ pub fn move_colliding( physics.horizontal_collision = horizontal_collision; physics.vertical_collision = vertical_collision; - physics.on_ground = on_ground; + physics.set_on_ground(on_ground); // TODO: minecraft checks for a "minor" horizontal collision here diff --git a/azalea-physics/src/lib.rs b/azalea-physics/src/lib.rs index c50095e41..2ca64b1f2 100644 --- a/azalea-physics/src/lib.rs +++ b/azalea-physics/src/lib.rs @@ -100,7 +100,7 @@ fn travel( let block_below: Box = block_state_below.into(); let block_friction = block_below.behavior().friction; - let inertia = if physics.on_ground { + let inertia = if physics.on_ground() { block_friction * 0.91 } else { 0.91 @@ -178,7 +178,7 @@ pub fn ai_step( if **jumping { // TODO: jumping in liquids and jump delay - if physics.on_ground { + if physics.on_ground() { jump_from_ground( &mut physics, position, @@ -358,7 +358,7 @@ fn get_friction_influenced_speed( is_sprinting: bool, ) -> f32 { // TODO: have speed & flying_speed fields in entity - if physics.on_ground { + if physics.on_ground() { let speed: f32 = attributes.speed.calculate() as f32; speed * (0.216f32 / (friction * friction * friction)) } else { diff --git a/azalea-protocol/src/packets/game/c_entity_position_sync.rs b/azalea-protocol/src/packets/game/c_entity_position_sync.rs index c5cde3229..6347ec5ed 100755 --- a/azalea-protocol/src/packets/game/c_entity_position_sync.rs +++ b/azalea-protocol/src/packets/game/c_entity_position_sync.rs @@ -1,7 +1,8 @@ use azalea_buf::AzBuf; -use azalea_core::position::Vec3; use azalea_protocol_macros::ClientboundGamePacket; +use super::c_player_position::PositionMoveRotation; + #[derive(Clone, Debug, AzBuf, ClientboundGamePacket)] pub struct ClientboundEntityPositionSync { #[var] @@ -9,11 +10,3 @@ pub struct ClientboundEntityPositionSync { pub values: PositionMoveRotation, pub on_ground: bool, } - -#[derive(AzBuf, Clone, Debug)] -pub struct PositionMoveRotation { - pub position: Vec3, - pub delta_movement: Vec3, - pub y_rot: f32, - pub x_rot: f32, -} diff --git a/azalea-protocol/src/packets/game/c_player_position.rs b/azalea-protocol/src/packets/game/c_player_position.rs index c6a2e3f96..8d19ce368 100755 --- a/azalea-protocol/src/packets/game/c_player_position.rs +++ b/azalea-protocol/src/packets/game/c_player_position.rs @@ -2,6 +2,7 @@ use std::io::{Cursor, Write}; use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError}; use azalea_core::{bitset::FixedBitSet, position::Vec3}; +use azalea_entity::LookDirection; use azalea_protocol_macros::ClientboundGamePacket; #[derive(Clone, Debug, AzBuf, ClientboundGamePacket)] @@ -18,9 +19,12 @@ pub struct ClientboundPlayerPosition { pub struct PositionMoveRotation { pub pos: Vec3, /// The updated delta movement (velocity). + /// + /// This is unused when included in a [`ClientboundEntityPositionSync`]. + /// + /// [`ClientboundEntityPositionSync`]: super::c_entity_position_sync::ClientboundEntityPositionSync pub delta: Vec3, - pub y_rot: f32, - pub x_rot: f32, + pub look_direction: LookDirection, } #[derive(Debug, Clone)] diff --git a/azalea-world/src/world.rs b/azalea-world/src/world.rs index 066981e56..0a09d387b 100644 --- a/azalea-world/src/world.rs +++ b/azalea-world/src/world.rs @@ -1,4 +1,5 @@ use std::fmt::Formatter; +use std::hash::{Hash, Hasher}; use std::{ collections::{HashMap, HashSet}, fmt::Debug, @@ -44,8 +45,8 @@ impl PartialInstance { #[derive(Component, Copy, Clone, Debug, PartialEq, Eq, Deref, DerefMut)] pub struct MinecraftEntityId(pub u32); -impl std::hash::Hash for MinecraftEntityId { - fn hash(&self, hasher: &mut H) { +impl Hash for MinecraftEntityId { + fn hash(&self, hasher: &mut H) { hasher.write_u32(self.0); } } diff --git a/azalea/src/auto_tool.rs b/azalea/src/auto_tool.rs index 5fcb8037a..768d30899 100644 --- a/azalea/src/auto_tool.rs +++ b/azalea/src/auto_tool.rs @@ -31,24 +31,10 @@ impl AutoToolClientExt for Client { /// or in water, use [`accurate_best_tool_in_hotbar_for_block`] instead if you /// care about those things. pub fn best_tool_in_hotbar_for_block(block: BlockState, menu: &Menu) -> BestToolResult { - accurate_best_tool_in_hotbar_for_block( - block, - menu, - &Physics { - on_ground: true, - velocity: Default::default(), - xxa: Default::default(), - yya: Default::default(), - zza: Default::default(), - last_on_ground: Default::default(), - dimensions: Default::default(), - bounding_box: Default::default(), - has_impulse: Default::default(), - horizontal_collision: Default::default(), - vertical_collision: Default::default(), - }, - &FluidOnEyes::new(Fluid::Empty), - ) + let mut physics = Physics::default(); + physics.set_on_ground(true); + + accurate_best_tool_in_hotbar_for_block(block, menu, &physics, &FluidOnEyes::new(Fluid::Empty)) } pub fn accurate_best_tool_in_hotbar_for_block( diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs index eab073481..78aafc2f8 100644 --- a/azalea/src/pathfinder/mod.rs +++ b/azalea/src/pathfinder/mod.rs @@ -516,7 +516,7 @@ pub fn check_node_reached( 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); // this is to make sure we don't fall off immediately after finishing the path - physics.on_ground + physics.on_ground() && BlockPos::from(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 diff --git a/azalea/src/pathfinder/simulation.rs b/azalea/src/pathfinder/simulation.rs index ca15fb7a4..630dd5917 100644 --- a/azalea/src/pathfinder/simulation.rs +++ b/azalea/src/pathfinder/simulation.rs @@ -32,7 +32,7 @@ impl SimulatedPlayerBundle { SimulatedPlayerBundle { position: Position::new(position), - physics: Physics::new(dimensions, &position), + physics: Physics::new(dimensions, position), physics_state: PhysicsState::default(), look_direction: LookDirection::new(0.0, 0.0), attributes: Attributes {