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:
parent
23932003d9
commit
e9136c9cbb
15 changed files with 238 additions and 106 deletions
|
@ -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
|
||||||
|
|
|
@ -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(_) => {}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
60
azalea-entity/src/vec_delta_codec.rs
Normal file
60
azalea-entity/src/vec_delta_codec.rs
Normal 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.
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue