diff options
| author | mat <git@matdoes.dev> | 2025-06-09 17:15:07 +0900 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-06-09 17:15:07 +0900 |
| commit | 4a4de819616d620d15680e71fb32390e28ab07cd (patch) | |
| tree | 9bd1159dec3527b07651d0d9c78f96c95d115e7b /azalea-client | |
| parent | 45d73712746fbfd365e8a68a75dfad6ae2e0d174 (diff) | |
| download | azalea-drasl-4a4de819616d620d15680e71fb32390e28ab07cd.tar.xz | |
handle relative teleports correctly and fix entity chunk indexing warnings
Diffstat (limited to 'azalea-client')
| -rw-r--r-- | azalea-client/src/plugins/packet/game/mod.rs | 123 | ||||
| -rw-r--r-- | azalea-client/src/test_utils/simulation.rs | 3 | ||||
| -rw-r--r-- | azalea-client/tests/move_and_despawn_entity.rs | 57 |
3 files changed, 91 insertions, 92 deletions
diff --git a/azalea-client/src/plugins/packet/game/mod.rs b/azalea-client/src/plugins/packet/game/mod.rs index 2fb9e1cd..1307473d 100644 --- a/azalea-client/src/plugins/packet/game/mod.rs +++ b/azalea-client/src/plugins/packet/game/mod.rs @@ -1,10 +1,9 @@ mod events; -use std::{collections::HashSet, ops::Add, sync::Arc}; +use std::{collections::HashSet, sync::Arc}; use azalea_core::{ game_type::GameMode, - math, position::{ChunkPos, Vec3}, }; use azalea_entity::{ @@ -425,68 +424,12 @@ impl GamePacketHandler<'_> { **last_sent_position = **position; - fn apply_change<T: Add<Output = T>>(base: T, condition: bool, change: T) -> T { - if condition { base + change } else { change } - } - - let new_x = apply_change(position.x, p.relative.x, p.change.pos.x); - 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.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 { - let y_rot_delta = direction.y_rot - new_y_rot; - let x_rot_delta = direction.x_rot - new_x_rot; - new_delta_from_rotations = new_delta_from_rotations - .x_rot(math::to_radians(x_rot_delta as f64) as f32) - .y_rot(math::to_radians(y_rot_delta as f64) as f32); - } - - let new_delta = Vec3::new( - apply_change( - new_delta_from_rotations.x, - p.relative.delta_x, - p.change.delta.x, - ), - apply_change( - new_delta_from_rotations.y, - p.relative.delta_y, - p.change.delta.y, - ), - apply_change( - new_delta_from_rotations.z, - p.relative.delta_z, - p.change.delta.z, - ), - ); - - // apply the updates - - physics.velocity = new_delta; - - (direction.y_rot, direction.x_rot) = (new_y_rot, new_x_rot); - - let new_pos = Vec3::new(new_x, new_y, new_z); - if new_pos != **position { - **position = new_pos; - } - + p.relative + .apply(&p.change, &mut position, &mut direction, &mut physics); // old_pos is set to the current position when we're teleported physics.set_old_pos(&position); // send the relevant packets - commands.trigger(SendPacketEvent::new( self.player, ServerboundAcceptTeleportation { id: p.id }, @@ -494,8 +437,8 @@ impl GamePacketHandler<'_> { commands.trigger(SendPacketEvent::new( self.player, ServerboundMovePlayerPosRot { - pos: new_pos, - look_direction: LookDirection::new(new_y_rot, new_x_rot), + pos: **position, + look_direction: *direction, // this is always false on_ground: false, }, @@ -852,6 +795,8 @@ impl GamePacketHandler<'_> { } pub fn teleport_entity(&mut self, p: &ClientboundTeleportEntity) { + debug!("Got teleport entity packet {p:?}"); + as_system::<(Commands, Query<(&EntityIdIndex, &InstanceHolder)>)>( self.ecs, |(mut commands, mut query)| { @@ -862,26 +807,28 @@ impl GamePacketHandler<'_> { return; }; - let new_pos = p.change.pos; - let new_look_direction = LookDirection { - x_rot: (p.change.look_direction.x_rot as i32 * 360) as f32 / 256., - y_rot: (p.change.look_direction.y_rot as i32 * 360) as f32 / 256., - }; + let relative = p.relative.clone(); + let change = p.change.clone(); + commands.entity(entity).queue(RelativeEntityUpdate::new( instance_holder.partial_instance.clone(), move |entity| { - let mut position = entity.get_mut::<Position>().unwrap(); - if new_pos != **position { - **position = new_pos; - } - let position = *position; - let mut look_direction = entity.get_mut::<LookDirection>().unwrap(); - if new_look_direction != *look_direction { - *look_direction = new_look_direction; - } - // old_pos is set to the current position when we're teleported - let mut physics = entity.get_mut::<Physics>().unwrap(); - physics.set_old_pos(&position); + let entity_id = entity.id(); + entity.world_scope(move |world| { + let mut query = + world.query::<(&mut Physics, &mut LookDirection, &mut Position)>(); + let (mut physics, mut look_direction, mut position) = + query.get_mut(world, entity_id).unwrap(); + let old_position = *position; + relative.apply( + &change, + &mut position, + &mut look_direction, + &mut physics, + ); + // old_pos is set to the current position when we're teleported + physics.set_old_pos(&old_position); + }); }, )); }, @@ -914,11 +861,7 @@ impl GamePacketHandler<'_> { instance_holder.partial_instance.clone(), 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, - ); + let new_pos = physics.vec_delta_codec.decode(&new_delta); physics.vec_delta_codec.set_base(new_pos); physics.set_on_ground(new_on_ground); @@ -968,17 +911,13 @@ impl GamePacketHandler<'_> { instance_holder.partial_instance.clone(), 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); + let new_position = physics.vec_delta_codec.decode(&new_delta); + physics.vec_delta_codec.set_base(new_position); physics.set_on_ground(new_on_ground); let mut position = entity_mut.get_mut::<Position>().unwrap(); - if new_pos != **position { - **position = new_pos; + if new_position != **position { + **position = new_position; } let mut look_direction = entity_mut.get_mut::<LookDirection>().unwrap(); diff --git a/azalea-client/src/test_utils/simulation.rs b/azalea-client/src/test_utils/simulation.rs index 00b35dee..caf63113 100644 --- a/azalea-client/src/test_utils/simulation.rs +++ b/azalea-client/src/test_utils/simulation.rs @@ -106,6 +106,9 @@ impl Simulation { pub fn tick(&mut self) { tick_app(&mut self.app); } + pub fn update(&mut self) { + self.app.update(); + } pub fn minecraft_entity_id(&self) -> MinecraftEntityId { self.component::<MinecraftEntityId>() diff --git a/azalea-client/tests/move_and_despawn_entity.rs b/azalea-client/tests/move_and_despawn_entity.rs new file mode 100644 index 00000000..080ca903 --- /dev/null +++ b/azalea-client/tests/move_and_despawn_entity.rs @@ -0,0 +1,57 @@ +use azalea_client::test_utils::prelude::*; +use azalea_core::{ + position::{ChunkPos, Vec3}, + resource_location::ResourceLocation, +}; +use azalea_entity::metadata::Cow; +use azalea_protocol::{ + common::movements::{PositionMoveRotation, RelativeMovements}, + packets::{ + ConnectionProtocol, + game::{ClientboundRemoveEntities, ClientboundTeleportEntity}, + }, +}; +use azalea_registry::{DataRegistry, DimensionType, EntityKind}; +use azalea_world::MinecraftEntityId; +use bevy_ecs::query::With; + +#[test] +fn test_move_and_despawn_entity() { + init_tracing(); + + let mut simulation = Simulation::new(ConnectionProtocol::Game); + simulation.receive_packet(make_basic_login_packet( + DimensionType::new_raw(0), + ResourceLocation::new("azalea:overworld"), + )); + + for x in 0..=10 { + simulation.receive_packet(make_basic_empty_chunk(ChunkPos::new(x, 0), (384 + 64) / 16)); + } + simulation.tick(); + + simulation.receive_packet(make_basic_add_entity(EntityKind::Cow, 123, (0.5, 64., 0.5))); + simulation.tick(); + + simulation.receive_packet(ClientboundTeleportEntity { + id: MinecraftEntityId(123), + change: PositionMoveRotation { + pos: Vec3::new(16., 0., 0.), + delta: Vec3::ZERO, + look_direction: Default::default(), + }, + relative: RelativeMovements::all_relative(), + on_ground: true, + }); + simulation.receive_packet(ClientboundRemoveEntities { + entity_ids: vec![MinecraftEntityId(123)], + }); + simulation.tick(); + + // make sure it's despawned + let mut cow_query = simulation.app.world_mut().query_filtered::<(), With<Cow>>(); + let cow_iter = cow_query.iter(simulation.app.world()); + assert_eq!(cow_iter.count(), 0, "cow should be despawned"); + + simulation.tick(); +} |
