diff options
| author | mat <git@matdoes.dev> | 2025-06-26 12:32:01 +0930 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-06-26 10:05:58 +0700 |
| commit | f9e4b65713bbacabcd54416a388a92b90f56ab47 (patch) | |
| tree | 25d392d60836351311e9f498d40277c226c1e32c /azalea-client/tests | |
| parent | af1ef9310093aa3c8dfd5054eb6d0b8c7c0d0b31 (diff) | |
| download | azalea-drasl-f9e4b65713bbacabcd54416a388a92b90f56ab47.tar.xz | |
start adding packet_order test
Diffstat (limited to 'azalea-client/tests')
| -rw-r--r-- | azalea-client/tests/packet_order.rs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/azalea-client/tests/packet_order.rs b/azalea-client/tests/packet_order.rs new file mode 100644 index 00000000..1d3b29a2 --- /dev/null +++ b/azalea-client/tests/packet_order.rs @@ -0,0 +1,150 @@ +use std::{collections::VecDeque, sync::Arc}; + +use azalea_client::{packet::game::SendPacketEvent, test_utils::prelude::*}; +use azalea_core::{ + position::{ChunkPos, Vec3}, + resource_location::ResourceLocation, +}; +use azalea_entity::LookDirection; +use azalea_protocol::{ + common::movements::{PositionMoveRotation, RelativeMovements}, + packets::{ + ConnectionProtocol, + config::{ClientboundFinishConfiguration, ClientboundRegistryData}, + game::{ClientboundPlayerPosition, ServerboundAcceptTeleportation, ServerboundGamePacket}, + }, +}; +use azalea_registry::{DataRegistry, DimensionType}; +use bevy_ecs::observer::Trigger; +use parking_lot::Mutex; +use simdnbt::owned::{NbtCompound, NbtTag}; + +#[test] +fn test_set_health_before_login() { + init_tracing(); + + let mut simulation = Simulation::new(ConnectionProtocol::Configuration); + let sent_packets = SentPackets::new(&mut simulation); + + simulation.receive_packet(ClientboundRegistryData { + registry_id: ResourceLocation::new("minecraft:dimension_type"), + entries: vec![( + ResourceLocation::new("minecraft:overworld"), + Some(NbtCompound::from_values(vec![ + ("height".into(), NbtTag::Int(384)), + ("min_y".into(), NbtTag::Int(-64)), + ])), + )] + .into_iter() + .collect(), + }); + simulation.tick(); + simulation.receive_packet(ClientboundFinishConfiguration); + simulation.tick(); + + simulation.receive_packet(make_basic_login_packet( + DimensionType::new_raw(0), // overworld + ResourceLocation::new("minecraft:overworld"), + )); + simulation.tick(); + + sent_packets.expect_tick_end(); + sent_packets.expect_empty(); + + // receive a chunk so the player is "loaded" now + simulation.receive_packet(make_basic_empty_chunk(ChunkPos::new(0, 0), (384 + 64) / 16)); + simulation.receive_packet(ClientboundPlayerPosition { + id: 1, + change: PositionMoveRotation { + pos: Vec3::new(1., 2., 3.), + delta: Vec3::ZERO, + look_direction: LookDirection::default(), + }, + relative: RelativeMovements::all_absolute(), + }); + simulation.tick(); + println!("sent_packets: {:?}", sent_packets.list.lock()); + sent_packets.expect("AcceptTeleportation", |p| { + matches!( + p, + ServerboundGamePacket::AcceptTeleportation(ServerboundAcceptTeleportation { id: 1 }) + ) + }); + sent_packets.expect("MovePlayerPosRot", |p| { + matches!(p, ServerboundGamePacket::MovePlayerPosRot(_)) + }); + + // in vanilla these might be sent in a later tick (depending on how long it + // takes to render the chunks)... see the comment in player_loaded_packet. + // this might be worth changing later for better anticheat compat? + sent_packets.expect("PlayerLoaded", |p| { + matches!(p, ServerboundGamePacket::PlayerLoaded(_)) + }); + sent_packets.expect("MovePlayerPos", |p| { + matches!(p, ServerboundGamePacket::MovePlayerPos(_)) + }); + + sent_packets.expect_tick_end(); + sent_packets.expect_empty(); +} + +#[derive(Clone)] +pub struct SentPackets { + list: Arc<Mutex<VecDeque<ServerboundGamePacket>>>, +} +impl SentPackets { + pub fn new(simulation: &mut Simulation) -> Self { + let sent_packets = SentPackets { + list: Default::default(), + }; + + let simulation_entity = simulation.entity; + let sent_packets_clone = sent_packets.clone(); + simulation + .app + .add_observer(move |trigger: Trigger<SendPacketEvent>| { + if trigger.sent_by == simulation_entity { + sent_packets_clone + .list + .lock() + .push_back(trigger.event().packet.clone()) + } + }); + + sent_packets + } + + pub fn clear(&self) { + self.list.lock().clear(); + } + + pub fn expect_tick_end(&self) { + self.expect("TickEnd", |p| { + matches!(p, ServerboundGamePacket::ClientTickEnd(_)) + }); + } + pub fn expect_empty(&self) { + let sent_packet = self.next(); + if let None = sent_packet { + } else { + panic!("Expected no packet, got {sent_packet:?}"); + } + } + pub fn expect( + &self, + expected_formatted: &str, + check: impl FnOnce(&ServerboundGamePacket) -> bool, + ) { + let sent_packet = self.next(); + if let Some(sent_packet) = sent_packet { + if !check(&sent_packet) { + panic!("Expected {expected_formatted}, got {sent_packet:?}"); + } + } else { + panic!("Expected {expected_formatted}, got nothing"); + } + } + pub fn next(&self) -> Option<ServerboundGamePacket> { + self.list.lock().pop_front() + } +} |
