aboutsummaryrefslogtreecommitdiff
path: root/azalea-client
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-06-09 17:15:07 +0900
committermat <git@matdoes.dev>2025-06-09 17:15:07 +0900
commit4a4de819616d620d15680e71fb32390e28ab07cd (patch)
tree9bd1159dec3527b07651d0d9c78f96c95d115e7b /azalea-client
parent45d73712746fbfd365e8a68a75dfad6ae2e0d174 (diff)
downloadazalea-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.rs123
-rw-r--r--azalea-client/src/test_utils/simulation.rs3
-rw-r--r--azalea-client/tests/move_and_despawn_entity.rs57
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();
+}