mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
start adding packet_order test
This commit is contained in:
parent
af1ef93100
commit
f9e4b65713
11 changed files with 224 additions and 36 deletions
|
@ -16,6 +16,7 @@ pub mod ping;
|
|||
pub mod player;
|
||||
mod plugins;
|
||||
|
||||
#[cfg(feature = "log")]
|
||||
#[doc(hidden)]
|
||||
pub mod test_utils;
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ impl Client {
|
|||
pub struct AttackQueued {
|
||||
pub target: Entity,
|
||||
}
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn handle_attack_queued(
|
||||
mut commands: Commands,
|
||||
mut query: Query<(
|
||||
|
|
|
@ -14,8 +14,8 @@ impl Plugin for PlayerLoadedPlugin {
|
|||
GameTick,
|
||||
player_loaded_packet
|
||||
.after(PhysicsSet)
|
||||
.after(MiningSet)
|
||||
.after(crate::movement::send_position),
|
||||
.before(MiningSet)
|
||||
.before(crate::movement::send_position),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,11 @@ pub fn player_loaded_packet(
|
|||
Entity,
|
||||
(
|
||||
With<LocalEntity>,
|
||||
With<InLoadedChunk>,
|
||||
Without<HasClientLoaded>,
|
||||
// the vanilla client waits for the chunk mesh to be "compiled" for the renderer (or
|
||||
// some other conditions) before sending PlayerLoaded. see LevelLoadStatusManager.tick
|
||||
// in the decompiled source
|
||||
With<InLoadedChunk>,
|
||||
),
|
||||
>,
|
||||
) {
|
||||
|
|
|
@ -6,14 +6,17 @@ use azalea_entity::{
|
|||
metadata::Sprinting,
|
||||
};
|
||||
use azalea_physics::{PhysicsSet, ai_step};
|
||||
use azalea_protocol::packets::{
|
||||
Packet,
|
||||
game::{
|
||||
ServerboundPlayerCommand, ServerboundPlayerInput,
|
||||
s_move_player_pos::ServerboundMovePlayerPos,
|
||||
s_move_player_pos_rot::ServerboundMovePlayerPosRot,
|
||||
s_move_player_rot::ServerboundMovePlayerRot,
|
||||
s_move_player_status_only::ServerboundMovePlayerStatusOnly,
|
||||
use azalea_protocol::{
|
||||
common::movements::MoveFlags,
|
||||
packets::{
|
||||
Packet,
|
||||
game::{
|
||||
ServerboundPlayerCommand, ServerboundPlayerInput,
|
||||
s_move_player_pos::ServerboundMovePlayerPos,
|
||||
s_move_player_pos_rot::ServerboundMovePlayerPosRot,
|
||||
s_move_player_rot::ServerboundMovePlayerRot,
|
||||
s_move_player_status_only::ServerboundMovePlayerStatusOnly,
|
||||
},
|
||||
},
|
||||
};
|
||||
use azalea_world::{MinecraftEntityId, MoveEntityError};
|
||||
|
@ -186,12 +189,16 @@ pub fn send_position(
|
|||
// if self.is_passenger() {
|
||||
// TODO: posrot packet for being a passenger
|
||||
// }
|
||||
let flags = MoveFlags {
|
||||
on_ground: physics.on_ground(),
|
||||
horizontal_collision: physics.horizontal_collision,
|
||||
};
|
||||
let packet = if sending_position && sending_direction {
|
||||
Some(
|
||||
ServerboundMovePlayerPosRot {
|
||||
pos: **position,
|
||||
look_direction: *direction,
|
||||
on_ground: physics.on_ground(),
|
||||
flags,
|
||||
}
|
||||
.into_variant(),
|
||||
)
|
||||
|
@ -199,7 +206,7 @@ pub fn send_position(
|
|||
Some(
|
||||
ServerboundMovePlayerPos {
|
||||
pos: **position,
|
||||
on_ground: physics.on_ground(),
|
||||
flags,
|
||||
}
|
||||
.into_variant(),
|
||||
)
|
||||
|
@ -207,17 +214,12 @@ pub fn send_position(
|
|||
Some(
|
||||
ServerboundMovePlayerRot {
|
||||
look_direction: *direction,
|
||||
on_ground: physics.on_ground(),
|
||||
flags,
|
||||
}
|
||||
.into_variant(),
|
||||
)
|
||||
} else if physics.last_on_ground() != physics.on_ground() {
|
||||
Some(
|
||||
ServerboundMovePlayerStatusOnly {
|
||||
on_ground: physics.on_ground(),
|
||||
}
|
||||
.into_variant(),
|
||||
)
|
||||
Some(ServerboundMovePlayerStatusOnly { flags }.into_variant())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
|
|
@ -12,7 +12,10 @@ use azalea_entity::{
|
|||
indexing::{EntityIdIndex, EntityUuidIndex},
|
||||
metadata::{Health, apply_metadata},
|
||||
};
|
||||
use azalea_protocol::packets::{ConnectionProtocol, game::*};
|
||||
use azalea_protocol::{
|
||||
common::movements::MoveFlags,
|
||||
packets::{ConnectionProtocol, game::*},
|
||||
};
|
||||
use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId, PartialInstance};
|
||||
use bevy_ecs::{prelude::*, system::SystemState};
|
||||
pub use events::*;
|
||||
|
@ -319,15 +322,6 @@ impl GamePacketHandler<'_> {
|
|||
.entity(self.player)
|
||||
.insert(LoadedBy(HashSet::from_iter(vec![self.player])));
|
||||
}
|
||||
|
||||
// send the client information that we have set
|
||||
debug!(
|
||||
"Sending client information because login: {:?}",
|
||||
client_information
|
||||
);
|
||||
commands.trigger(SendPacketEvent::new(self.player,
|
||||
azalea_protocol::packets::game::s_client_information::ServerboundClientInformation { client_information: client_information.clone() },
|
||||
));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -443,8 +437,7 @@ impl GamePacketHandler<'_> {
|
|||
ServerboundMovePlayerPosRot {
|
||||
pos: **position,
|
||||
look_direction: *direction,
|
||||
// this is always false
|
||||
on_ground: false,
|
||||
flags: MoveFlags::default(),
|
||||
},
|
||||
));
|
||||
});
|
||||
|
|
150
azalea-client/tests/packet_order.rs
Normal file
150
azalea-client/tests/packet_order.rs
Normal file
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -131,3 +131,33 @@ impl AzaleaWrite for RelativeMovements {
|
|||
set.azalea_write(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct MoveFlags {
|
||||
pub on_ground: bool,
|
||||
pub horizontal_collision: bool,
|
||||
}
|
||||
impl AzaleaWrite for MoveFlags {
|
||||
fn azalea_write(&self, buf: &mut impl io::Write) -> Result<(), io::Error> {
|
||||
let mut bitset = FixedBitSet::<8>::new();
|
||||
if self.on_ground {
|
||||
bitset.set(0);
|
||||
}
|
||||
if self.horizontal_collision {
|
||||
bitset.set(1);
|
||||
}
|
||||
bitset.azalea_write(buf)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl AzaleaRead for MoveFlags {
|
||||
fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
|
||||
let bitset = FixedBitSet::<8>::azalea_read(buf)?;
|
||||
let on_ground = bitset.index(0);
|
||||
let horizontal_collision = bitset.index(1);
|
||||
Ok(Self {
|
||||
on_ground,
|
||||
horizontal_collision,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ use azalea_buf::AzBuf;
|
|||
use azalea_core::position::Vec3;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
use crate::common::movements::MoveFlags;
|
||||
|
||||
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundMovePlayerPos {
|
||||
pub pos: Vec3,
|
||||
pub on_ground: bool,
|
||||
pub flags: MoveFlags,
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ use azalea_core::position::Vec3;
|
|||
use azalea_entity::LookDirection;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
use crate::common::movements::MoveFlags;
|
||||
|
||||
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundMovePlayerPosRot {
|
||||
pub pos: Vec3,
|
||||
pub look_direction: LookDirection,
|
||||
pub on_ground: bool,
|
||||
pub flags: MoveFlags,
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ use azalea_buf::AzBuf;
|
|||
use azalea_entity::LookDirection;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
use crate::common::movements::MoveFlags;
|
||||
|
||||
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundMovePlayerRot {
|
||||
pub look_direction: LookDirection,
|
||||
pub on_ground: bool,
|
||||
pub flags: MoveFlags,
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use azalea_buf::AzBuf;
|
||||
use azalea_protocol_macros::ServerboundGamePacket;
|
||||
|
||||
use crate::common::movements::MoveFlags;
|
||||
|
||||
#[derive(Clone, Debug, AzBuf, ServerboundGamePacket)]
|
||||
pub struct ServerboundMovePlayerStatusOnly {
|
||||
pub on_ground: bool,
|
||||
pub flags: MoveFlags,
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue