1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

fix errors when switching to Game state and add fast_login test

This commit is contained in:
mat 2025-03-02 05:42:15 +00:00
parent 72d87349fe
commit c9022e8f67
6 changed files with 101 additions and 20 deletions

View file

@ -23,8 +23,8 @@ pub mod test_simulation;
pub use account::{Account, AccountOpts};
pub use azalea_protocol::common::client_information::ClientInformation;
pub use client::{
Client, DefaultPlugins, InConfigState, JoinError, JoinedClientBundle, LocalPlayerBundle,
StartClientOpts, TickBroadcast, start_ecs_runner,
Client, DefaultPlugins, InConfigState, InGameState, JoinError, JoinedClientBundle,
LocalPlayerBundle, StartClientOpts, TickBroadcast, start_ecs_runner,
};
pub use events::Event;
pub use local_player::{GameProfileComponent, Hunger, InstanceHolder, TabList};

View file

@ -55,7 +55,7 @@ pub fn handle_send_packet_event(
}
}
pub fn send_packet_events(
pub fn emit_receive_config_packet_events(
query: Query<(Entity, &RawConnection), With<InConfigState>>,
mut packet_events: ResMut<Events<ReceiveConfigPacketEvent>>,
) {
@ -67,7 +67,9 @@ pub fn send_packet_events(
let packets_lock = raw_conn.incoming_packet_queue();
let mut packets = packets_lock.lock();
if !packets.is_empty() {
let mut packets_read = 0;
for raw_packet in packets.iter() {
packets_read += 1;
let packet = match deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new(
raw_packet,
)) {
@ -78,13 +80,32 @@ pub fn send_packet_events(
continue;
}
};
let should_interrupt = packet_interrupts(&packet);
packet_events.send(ReceiveConfigPacketEvent {
entity: player_entity,
packet,
});
if should_interrupt {
break;
}
// clear the packets right after we read them
packets.clear();
}
packets.drain(0..packets_read);
}
}
}
/// Whether the given packet should make us stop deserializing the received
/// packets until next update.
///
/// This is used for packets that can switch the client state.
fn packet_interrupts(packet: &ClientboundConfigPacket) -> bool {
matches!(
packet,
ClientboundConfigPacket::FinishConfiguration(_)
| ClientboundConfigPacket::Disconnect(_)
| ClientboundConfigPacket::Transfer(_)
)
}

View file

@ -75,7 +75,7 @@ pub fn handle_outgoing_packets(
}
}
pub fn send_receivepacketevent(
pub fn emit_receive_packet_events(
query: Query<(Entity, &RawConnection), With<InGameState>>,
mut packet_events: ResMut<Events<ReceivePacketEvent>>,
) {
@ -87,7 +87,9 @@ pub fn send_receivepacketevent(
let packets_lock = raw_connection.incoming_packet_queue();
let mut packets = packets_lock.lock();
if !packets.is_empty() {
let mut packets_read = 0;
for raw_packet in packets.iter() {
packets_read += 1;
let packet =
match deserialize_packet::<ClientboundGamePacket>(&mut Cursor::new(raw_packet))
{
@ -98,15 +100,34 @@ pub fn send_receivepacketevent(
continue;
}
};
let should_interrupt = packet_interrupts(&packet);
packet_events.send(ReceivePacketEvent {
entity: player_entity,
packet: Arc::new(packet),
});
}
// clear the packets right after we read them
packets.clear();
if should_interrupt {
break;
}
}
packets.drain(0..packets_read);
}
}
}
/// Whether the given packet should make us stop deserializing the received
/// packets until next update.
///
/// This is used for packets that can switch the client state.
fn packet_interrupts(packet: &ClientboundGamePacket) -> bool {
matches!(
packet,
ClientboundGamePacket::StartConfiguration(_)
| ClientboundGamePacket::Disconnect(_)
| ClientboundGamePacket::Transfer(_)
)
}
/// A player joined the game (or more specifically, was added to the tab

View file

@ -38,7 +38,10 @@ impl Plugin for PacketPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
First,
(game::send_receivepacketevent, config::send_packet_events),
(
game::emit_receive_packet_events,
config::emit_receive_config_packet_events,
),
)
.add_systems(
PreUpdate,

View file

@ -1,10 +1,9 @@
use azalea_client::{InConfigState, test_simulation::*};
use azalea_client::{InConfigState, InGameState, test_simulation::*};
use azalea_core::{position::ChunkPos, resource_location::ResourceLocation};
use azalea_entity::{LocalEntity, metadata::Health};
use azalea_entity::LocalEntity;
use azalea_protocol::packets::{
ConnectionProtocol,
config::{ClientboundFinishConfiguration, ClientboundRegistryData},
game::ClientboundSetHealth,
};
use azalea_registry::DimensionType;
use azalea_world::InstanceName;
@ -17,6 +16,7 @@ fn test_change_dimension_to_nether_and_back() {
let mut simulation = Simulation::new(ConnectionProtocol::Configuration);
assert!(simulation.has_component::<InConfigState>());
assert!(!simulation.has_component::<InGameState>());
simulation.receive_packet(ClientboundRegistryData {
registry_id: ResourceLocation::new("minecraft:dimension_type"),
@ -53,16 +53,9 @@ fn test_change_dimension_to_nether_and_back() {
simulation.tick();
assert!(!simulation.has_component::<InConfigState>());
assert!(simulation.has_component::<InGameState>());
assert!(simulation.has_component::<LocalEntity>());
simulation.receive_packet(ClientboundSetHealth {
health: 15.,
food: 20,
saturation: 20.,
});
simulation.tick();
assert_eq!(*simulation.component::<Health>(), 15.);
//
// OVERWORLD
//

View file

@ -0,0 +1,43 @@
use azalea_client::{InConfigState, test_simulation::*};
use azalea_core::resource_location::ResourceLocation;
use azalea_entity::metadata::Health;
use azalea_protocol::packets::{
ConnectionProtocol,
config::{ClientboundFinishConfiguration, ClientboundRegistryData},
game::ClientboundSetHealth,
};
use bevy_log::tracing_subscriber;
use simdnbt::owned::{NbtCompound, NbtTag};
#[test]
fn test_fast_login() {
let _ = tracing_subscriber::fmt::try_init();
let mut simulation = Simulation::new(ConnectionProtocol::Configuration);
assert!(simulation.has_component::<InConfigState>());
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.receive_packet(ClientboundFinishConfiguration);
// note that there's no simulation tick here
simulation.receive_packet(ClientboundSetHealth {
health: 15.,
food: 20,
saturation: 20.,
});
simulation.tick();
// we need a second tick to handle the state switch properly
simulation.tick();
assert_eq!(*simulation.component::<Health>(), 15.);
}