1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

Implement EntityPositionSync (#196)

* implement EntityPositionSync

* fix EntityPositionSync setting the wrong vec_delta_codec and also move into a RelativeEntityUpdate
This commit is contained in:
mat 2024-12-11 19:51:12 -06:00 committed by GitHub
parent 23932003d9
commit e9136c9cbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 238 additions and 106 deletions

View file

@ -195,7 +195,7 @@ pub fn send_position(
pos: **position, pos: **position,
x_rot: direction.x_rot, x_rot: direction.x_rot,
y_rot: direction.y_rot, y_rot: direction.y_rot,
on_ground: physics.on_ground, on_ground: physics.on_ground(),
} }
.into_variant(), .into_variant(),
) )
@ -205,7 +205,7 @@ pub fn send_position(
x: position.x, x: position.x,
y: position.y, y: position.y,
z: position.z, z: position.z,
on_ground: physics.on_ground, on_ground: physics.on_ground(),
} }
.into_variant(), .into_variant(),
) )
@ -214,14 +214,14 @@ pub fn send_position(
ServerboundMovePlayerRot { ServerboundMovePlayerRot {
x_rot: direction.x_rot, x_rot: direction.x_rot,
y_rot: direction.y_rot, y_rot: direction.y_rot,
on_ground: physics.on_ground, on_ground: physics.on_ground(),
} }
.into_variant(), .into_variant(),
) )
} else if physics.last_on_ground != physics.on_ground { } else if physics.last_on_ground() != physics.on_ground() {
Some( Some(
ServerboundMovePlayerStatusOnly { ServerboundMovePlayerStatusOnly {
on_ground: physics.on_ground, on_ground: physics.on_ground(),
} }
.into_variant(), .into_variant(),
) )
@ -238,7 +238,8 @@ pub fn send_position(
last_direction.x_rot = direction.x_rot; 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 // minecraft checks for autojump here, but also autojump is bad so
packet packet

View file

@ -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_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_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_y_rot = apply_change(
let new_x_rot = apply_change(direction.x_rot, p.relative.x_rot, p.change.x_rot); 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; let mut new_delta_from_rotations = physics.velocity;
if p.relative.rotate_delta { 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 (mut commands, mut query) = system_state.get_mut(ecs);
let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap();
let entity = entity_id_index.get(&MinecraftEntityId(p.id)); let Some(entity) = entity_id_index.get(&MinecraftEntityId(p.id)) else {
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::<Position>().unwrap();
if new_pos != **position {
**position = new_pos;
}
let mut look_direction = entity.get_mut::<LookDirection>().unwrap();
if new_look_direction != *look_direction {
*look_direction = new_look_direction;
}
}),
});
} else {
warn!("Got teleport entity packet for unknown entity id {}", p.id); 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::<Position>().unwrap();
if new_pos != **position {
**position = new_pos;
}
let mut look_direction = entity.get_mut::<LookDirection>().unwrap();
if new_look_direction != *look_direction {
*look_direction = new_look_direction;
}
}),
});
system_state.apply(ecs); 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 (mut commands, mut query) = system_state.get_mut(ecs);
let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); 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)); let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id));
if let Some(entity) = entity { 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 { commands.entity(entity).queue(RelativeEntityUpdate {
partial_world: instance_holder.partial_instance.clone(), partial_world: instance_holder.partial_instance.clone(),
update: Box::new(move |entity_mut| { update: Box::new(move |entity_mut| {
let mut physics = entity_mut.get_mut::<Physics>().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::<Position>().unwrap(); let mut position = entity_mut.get_mut::<Position>().unwrap();
let new_pos = position.with_delta(&delta);
if new_pos != **position { if new_pos != **position {
**position = new_pos; **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 (mut commands, mut query) = system_state.get_mut(ecs);
let (entity_id_index, instance_holder) = query.get_mut(player_entity).unwrap(); 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)); let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id));
if let Some(entity) = entity { if let Some(entity) = entity {
let delta = p.delta.clone(); let new_delta = p.delta.clone();
let new_look_direction = LookDirection { let new_look_direction = LookDirection {
x_rot: (p.x_rot as i32 * 360) as f32 / 256., x_rot: (p.x_rot as i32 * 360) as f32 / 256.,
y_rot: (p.y_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 { commands.entity(entity).queue(RelativeEntityUpdate {
partial_world: instance_holder.partial_instance.clone(), partial_world: instance_holder.partial_instance.clone(),
update: Box::new(move |entity_mut| { update: Box::new(move |entity_mut| {
let mut physics = entity_mut.get_mut::<Physics>().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::<Position>().unwrap(); let mut position = entity_mut.get_mut::<Position>().unwrap();
let new_pos = position.with_delta(&delta);
if new_pos != **position { if new_pos != **position {
**position = new_pos; **position = new_pos;
} }
let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap(); let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap();
if new_look_direction != *look_direction { if new_look_direction != *look_direction {
*look_direction = new_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., x_rot: (p.x_rot as i32 * 360) as f32 / 256.,
y_rot: (p.y_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 { commands.entity(entity).queue(RelativeEntityUpdate {
partial_world: instance_holder.partial_instance.clone(), partial_world: instance_holder.partial_instance.clone(),
update: Box::new(move |entity_mut| { update: Box::new(move |entity_mut| {
let mut physics = entity_mut.get_mut::<Physics>().unwrap();
physics.set_on_ground(new_on_ground);
let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap(); let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap();
if new_look_direction != *look_direction { if new_look_direction != *look_direction {
*look_direction = new_look_direction; *look_direction = new_look_direction;
@ -1416,7 +1451,7 @@ pub fn process_packet_events(ecs: &mut World) {
system_state.apply(ecs); system_state.apply(ecs);
} }
ClientboundGamePacket::StartConfiguration(_) => { ClientboundGamePacket::StartConfiguration(_p) => {
let mut system_state: SystemState<(Commands, EventWriter<SendPacketEvent>)> = let mut system_state: SystemState<(Commands, EventWriter<SendPacketEvent>)> =
SystemState::new(ecs); SystemState::new(ecs);
let (mut commands, mut packet_events) = system_state.get_mut(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); 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::<LocalEntity>().is_some();
let mut physics = entity_mut.get_mut::<Physics>().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::<LastSentPosition>().unwrap();
**last_sent_position = new_position;
let mut position = entity_mut.get_mut::<Position>().unwrap();
**position = new_position;
let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap();
*look_direction = new_look_direction;
}),
});
system_state.apply(ecs);
}
ClientboundGamePacket::SelectAdvancementsTab(_) => {} ClientboundGamePacket::SelectAdvancementsTab(_) => {}
ClientboundGamePacket::SetActionBarText(_) => {} ClientboundGamePacket::SetActionBarText(_) => {}
ClientboundGamePacket::SetBorderCenter(_) => {} ClientboundGamePacket::SetBorderCenter(_) => {}
@ -1476,7 +1557,6 @@ pub fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::ProjectilePower(_) => {} ClientboundGamePacket::ProjectilePower(_) => {}
ClientboundGamePacket::CustomReportDetails(_) => {} ClientboundGamePacket::CustomReportDetails(_) => {}
ClientboundGamePacket::ServerLinks(_) => {} ClientboundGamePacket::ServerLinks(_) => {}
ClientboundGamePacket::EntityPositionSync(_) => {}
ClientboundGamePacket::PlayerRotation(_) => {} ClientboundGamePacket::PlayerRotation(_) => {}
ClientboundGamePacket::RecipeBookAdd(_) => {} ClientboundGamePacket::RecipeBookAdd(_) => {}
ClientboundGamePacket::RecipeBookRemove(_) => {} ClientboundGamePacket::RecipeBookRemove(_) => {}

View file

@ -20,7 +20,7 @@ macro_rules! vec3_impl {
($name:ident, $type:ty) => { ($name:ident, $type:ty) => {
impl $name { impl $name {
#[inline] #[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 } Self { x, y, z }
} }
@ -223,6 +223,8 @@ pub struct Vec3 {
vec3_impl!(Vec3, f64); vec3_impl!(Vec3, f64);
impl Vec3 { 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 /// Get the distance of this vector to the origin by doing
/// `sqrt(x^2 + y^2 + z^2)`. /// `sqrt(x^2 + y^2 + z^2)`.
pub fn length(&self) -> f64 { pub fn length(&self) -> f64 {

View file

@ -7,7 +7,7 @@ pub struct EntityDimensions {
} }
impl 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 radius = (self.width / 2.0) as f64;
let height = self.height as f64; let height = self.height as f64;
AABB { AABB {

View file

@ -9,6 +9,7 @@ pub mod metadata;
pub mod mining; pub mod mining;
pub mod particle; pub mod particle;
mod plugin; mod plugin;
pub mod vec_delta_codec;
use std::{ use std::{
fmt::Debug, fmt::Debug,
@ -17,6 +18,7 @@ use std::{
pub use attributes::Attributes; pub use attributes::Attributes;
use azalea_block::BlockState; use azalea_block::BlockState;
use azalea_buf::AzBuf;
use azalea_core::{ use azalea_core::{
aabb::AABB, aabb::AABB,
math, math,
@ -30,6 +32,7 @@ use derive_more::{Deref, DerefMut};
pub use dimensions::EntityDimensions; pub use dimensions::EntityDimensions;
use plugin::indexing::EntityChunkPos; use plugin::indexing::EntityChunkPos;
use uuid::Uuid; use uuid::Uuid;
use vec_delta_codec::VecDeltaCodec;
use self::attributes::AttributeInstance; use self::attributes::AttributeInstance;
pub use crate::plugin::*; pub use crate::plugin::*;
@ -210,7 +213,7 @@ impl From<&LastSentPosition> for BlockPos {
pub struct Jumping(bool); pub struct Jumping(bool);
/// A component that contains the direction an entity is looking. /// 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 { pub struct LookDirection {
/// Left and right. Aka yaw. /// Left and right. Aka yaw.
pub y_rot: f32, pub y_rot: f32,
@ -245,7 +248,7 @@ impl Eq for LookDirection {}
/// The physics data relating to the entity, such as position, velocity, and /// The physics data relating to the entity, such as position, velocity, and
/// bounding box. /// bounding box.
#[derive(Debug, Component, Clone)] #[derive(Debug, Component, Clone, Default)]
pub struct Physics { pub struct Physics {
/// How fast the entity is moving. /// How fast the entity is moving.
pub velocity: Vec3, pub velocity: Vec3,
@ -257,8 +260,10 @@ pub struct Physics {
/// Z acceleration. /// Z acceleration.
pub zza: f32, pub zza: f32,
pub on_ground: bool, on_ground: bool,
pub last_on_ground: bool, last_on_ground: bool,
pub vec_delta_codec: VecDeltaCodec,
/// The width and height of the entity. /// The width and height of the entity.
pub dimensions: EntityDimensions, pub dimensions: EntityDimensions,
@ -274,7 +279,7 @@ pub struct Physics {
} }
impl Physics { impl Physics {
pub fn new(dimensions: EntityDimensions, pos: &Vec3) -> Self { pub fn new(dimensions: EntityDimensions, pos: Vec3) -> Self {
Self { Self {
velocity: Vec3::default(), velocity: Vec3::default(),
@ -292,8 +297,30 @@ impl Physics {
horizontal_collision: false, horizontal_collision: false,
vertical_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. /// Marker component for entities that are dead.
@ -384,7 +411,7 @@ impl EntityBundle {
position: Position(pos), position: Position(pos),
chunk_pos: EntityChunkPos(ChunkPos::from(&pos)), chunk_pos: EntityChunkPos(ChunkPos::from(&pos)),
last_sent_position: LastSentPosition(pos), last_sent_position: LastSentPosition(pos),
physics: Physics::new(dimensions, &pos), physics: Physics::new(dimensions, pos),
eye_height: EyeHeight(eye_height), eye_height: EyeHeight(eye_height),
direction: LookDirection::default(), direction: LookDirection::default(),
@ -427,25 +454,3 @@ impl FluidOnEyes {
#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)] #[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]
pub struct OnClimbable(bool); 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);
// }
// }

View file

@ -198,7 +198,7 @@ pub fn clamp_look_direction(mut query: Query<&mut LookDirection>) {
/// Cached position in the world must be updated. /// Cached position in the world must be updated.
pub fn update_bounding_box(mut query: Query<(&Position, &mut Physics), Changed<Position>>) { pub fn update_bounding_box(mut query: Query<(&Position, &mut Physics), Changed<Position>>) {
for (position, mut physics) in query.iter_mut() { 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; physics.bounding_box = bounding_box;
} }
} }

View file

@ -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.
}

View file

@ -73,7 +73,7 @@ fn collide(movement: &Vec3, world: &Instance, physics: &azalea_entity::Physics)
let y_collision = movement.y != collided_delta.y; let y_collision = movement.y != collided_delta.y;
let z_collision = movement.z != collided_delta.z; 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; let max_up_step = 0.6;
if max_up_step > 0. && on_ground && (x_collision || z_collision) { 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.horizontal_collision = horizontal_collision;
physics.vertical_collision = vertical_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 // TODO: minecraft checks for a "minor" horizontal collision here

View file

@ -100,7 +100,7 @@ fn travel(
let block_below: Box<dyn Block> = block_state_below.into(); let block_below: Box<dyn Block> = block_state_below.into();
let block_friction = block_below.behavior().friction; let block_friction = block_below.behavior().friction;
let inertia = if physics.on_ground { let inertia = if physics.on_ground() {
block_friction * 0.91 block_friction * 0.91
} else { } else {
0.91 0.91
@ -178,7 +178,7 @@ pub fn ai_step(
if **jumping { if **jumping {
// TODO: jumping in liquids and jump delay // TODO: jumping in liquids and jump delay
if physics.on_ground { if physics.on_ground() {
jump_from_ground( jump_from_ground(
&mut physics, &mut physics,
position, position,
@ -358,7 +358,7 @@ fn get_friction_influenced_speed(
is_sprinting: bool, is_sprinting: bool,
) -> f32 { ) -> f32 {
// TODO: have speed & flying_speed fields in entity // TODO: have speed & flying_speed fields in entity
if physics.on_ground { if physics.on_ground() {
let speed: f32 = attributes.speed.calculate() as f32; let speed: f32 = attributes.speed.calculate() as f32;
speed * (0.216f32 / (friction * friction * friction)) speed * (0.216f32 / (friction * friction * friction))
} else { } else {

View file

@ -1,7 +1,8 @@
use azalea_buf::AzBuf; use azalea_buf::AzBuf;
use azalea_core::position::Vec3;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
use super::c_player_position::PositionMoveRotation;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)] #[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
pub struct ClientboundEntityPositionSync { pub struct ClientboundEntityPositionSync {
#[var] #[var]
@ -9,11 +10,3 @@ pub struct ClientboundEntityPositionSync {
pub values: PositionMoveRotation, pub values: PositionMoveRotation,
pub on_ground: bool, 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,
}

View file

@ -2,6 +2,7 @@ use std::io::{Cursor, Write};
use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError}; use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
use azalea_core::{bitset::FixedBitSet, position::Vec3}; use azalea_core::{bitset::FixedBitSet, position::Vec3};
use azalea_entity::LookDirection;
use azalea_protocol_macros::ClientboundGamePacket; use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, AzBuf, ClientboundGamePacket)] #[derive(Clone, Debug, AzBuf, ClientboundGamePacket)]
@ -18,9 +19,12 @@ pub struct ClientboundPlayerPosition {
pub struct PositionMoveRotation { pub struct PositionMoveRotation {
pub pos: Vec3, pub pos: Vec3,
/// The updated delta movement (velocity). /// The updated delta movement (velocity).
///
/// This is unused when included in a [`ClientboundEntityPositionSync`].
///
/// [`ClientboundEntityPositionSync`]: super::c_entity_position_sync::ClientboundEntityPositionSync
pub delta: Vec3, pub delta: Vec3,
pub y_rot: f32, pub look_direction: LookDirection,
pub x_rot: f32,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -1,4 +1,5 @@
use std::fmt::Formatter; use std::fmt::Formatter;
use std::hash::{Hash, Hasher};
use std::{ use std::{
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt::Debug, fmt::Debug,
@ -44,8 +45,8 @@ impl PartialInstance {
#[derive(Component, Copy, Clone, Debug, PartialEq, Eq, Deref, DerefMut)] #[derive(Component, Copy, Clone, Debug, PartialEq, Eq, Deref, DerefMut)]
pub struct MinecraftEntityId(pub u32); pub struct MinecraftEntityId(pub u32);
impl std::hash::Hash for MinecraftEntityId { impl Hash for MinecraftEntityId {
fn hash<H: std::hash::Hasher>(&self, hasher: &mut H) { fn hash<H: Hasher>(&self, hasher: &mut H) {
hasher.write_u32(self.0); hasher.write_u32(self.0);
} }
} }

View file

@ -31,24 +31,10 @@ impl AutoToolClientExt for Client {
/// or in water, use [`accurate_best_tool_in_hotbar_for_block`] instead if you /// or in water, use [`accurate_best_tool_in_hotbar_for_block`] instead if you
/// care about those things. /// care about those things.
pub fn best_tool_in_hotbar_for_block(block: BlockState, menu: &Menu) -> BestToolResult { pub fn best_tool_in_hotbar_for_block(block: BlockState, menu: &Menu) -> BestToolResult {
accurate_best_tool_in_hotbar_for_block( let mut physics = Physics::default();
block, physics.set_on_ground(true);
menu,
&Physics { accurate_best_tool_in_hotbar_for_block(block, menu, &physics, &FluidOnEyes::new(Fluid::Empty))
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),
)
} }
pub fn accurate_best_tool_in_hotbar_for_block( pub fn accurate_best_tool_in_hotbar_for_block(

View file

@ -516,7 +516,7 @@ pub fn check_node_reached(
let x_difference_from_center = position.x - (movement.target.x as f64 + 0.5); 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 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 // 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 && BlockPos::from(position) == movement.target
// adding the delta like this isn't a perfect solution but it helps to make // 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 // sure we don't keep going if our delta is high

View file

@ -32,7 +32,7 @@ impl SimulatedPlayerBundle {
SimulatedPlayerBundle { SimulatedPlayerBundle {
position: Position::new(position), position: Position::new(position),
physics: Physics::new(dimensions, &position), physics: Physics::new(dimensions, position),
physics_state: PhysicsState::default(), physics_state: PhysicsState::default(),
look_direction: LookDirection::new(0.0, 0.0), look_direction: LookDirection::new(0.0, 0.0),
attributes: Attributes { attributes: Attributes {