diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-02-22 21:45:26 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-22 21:45:26 -0600 |
| commit | e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7 (patch) | |
| tree | add6f8bfce40d0c07845d8aa4c9945a0b918444c /azalea-client/src/plugins/packet/config | |
| parent | f8130c3c92946d2293634ba4e252d6bc93026c3c (diff) | |
| download | azalea-drasl-e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7.tar.xz | |
Refactor azalea-client (#205)
* start organizing packet_handling more by moving packet handlers into their own functions
* finish writing all the handler functions for packets
* use macro for generating match statement for packet handler functions
* fix set_entity_data
* update config state to also use handler functions
* organize az-client file structure by moving things into plugins directory
* fix merge issues
Diffstat (limited to 'azalea-client/src/plugins/packet/config')
| -rw-r--r-- | azalea-client/src/plugins/packet/config/events.rs | 90 | ||||
| -rw-r--r-- | azalea-client/src/plugins/packet/config/mod.rs | 223 |
2 files changed, 313 insertions, 0 deletions
diff --git a/azalea-client/src/plugins/packet/config/events.rs b/azalea-client/src/plugins/packet/config/events.rs new file mode 100644 index 00000000..6b647d74 --- /dev/null +++ b/azalea-client/src/plugins/packet/config/events.rs @@ -0,0 +1,90 @@ +use std::io::Cursor; + +use azalea_protocol::{ + packets::{ + config::{ClientboundConfigPacket, ServerboundConfigPacket}, + Packet, + }, + read::deserialize_packet, +}; +use bevy_ecs::prelude::*; +use tracing::{debug, error}; + +use crate::{raw_connection::RawConnection, InConfigState}; + +#[derive(Event, Debug, Clone)] +pub struct ReceiveConfigPacketEvent { + /// The client entity that received the packet. + pub entity: Entity, + /// The packet that was actually received. + pub packet: ClientboundConfigPacket, +} + +/// An event for sending a packet to the server while we're in the +/// `configuration` state. +#[derive(Event)] +pub struct SendConfigPacketEvent { + pub sent_by: Entity, + pub packet: ServerboundConfigPacket, +} +impl SendConfigPacketEvent { + pub fn new(sent_by: Entity, packet: impl Packet<ServerboundConfigPacket>) -> Self { + let packet = packet.into_variant(); + Self { sent_by, packet } + } +} + +pub fn handle_send_packet_event( + mut send_packet_events: EventReader<SendConfigPacketEvent>, + mut query: Query<(&mut RawConnection, Option<&InConfigState>)>, +) { + for event in send_packet_events.read() { + if let Ok((raw_conn, in_configuration_state)) = query.get_mut(event.sent_by) { + if in_configuration_state.is_none() { + error!( + "Tried to send a configuration packet {:?} while not in configuration state", + event.packet + ); + continue; + } + debug!("Sending packet: {:?}", event.packet); + if let Err(e) = raw_conn.write_packet(event.packet.clone()) { + error!("Failed to send packet: {e}"); + } + } + } +} + +pub fn send_packet_events( + query: Query<(Entity, &RawConnection), With<InConfigState>>, + mut packet_events: ResMut<Events<ReceiveConfigPacketEvent>>, +) { + // we manually clear and send the events at the beginning of each update + // since otherwise it'd cause issues with events in process_packet_events + // running twice + packet_events.clear(); + for (player_entity, raw_conn) in &query { + let packets_lock = raw_conn.incoming_packet_queue(); + let mut packets = packets_lock.lock(); + if !packets.is_empty() { + for raw_packet in packets.iter() { + let packet = match deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new( + raw_packet, + )) { + Ok(packet) => packet, + Err(err) => { + error!("failed to read packet: {err:?}"); + debug!("packet bytes: {raw_packet:?}"); + continue; + } + }; + packet_events.send(ReceiveConfigPacketEvent { + entity: player_entity, + packet, + }); + } + // clear the packets right after we read them + packets.clear(); + } + } +} diff --git a/azalea-client/src/plugins/packet/config/mod.rs b/azalea-client/src/plugins/packet/config/mod.rs new file mode 100644 index 00000000..5cb19b9d --- /dev/null +++ b/azalea-client/src/plugins/packet/config/mod.rs @@ -0,0 +1,223 @@ +mod events; + +use azalea_protocol::packets::config::*; +use azalea_protocol::packets::ConnectionProtocol; +use bevy_ecs::prelude::*; +use bevy_ecs::system::SystemState; +pub use events::*; +use tracing::{debug, warn}; + +use super::as_system; +use crate::client::InConfigState; +use crate::disconnect::DisconnectEvent; +use crate::packet::game::KeepAliveEvent; +use crate::raw_connection::RawConnection; +use crate::{declare_packet_handlers, InstanceHolder}; + +pub fn process_packet_events(ecs: &mut World) { + let mut events_owned = Vec::new(); + let mut system_state: SystemState<EventReader<ReceiveConfigPacketEvent>> = + SystemState::new(ecs); + let mut events = system_state.get_mut(ecs); + for ReceiveConfigPacketEvent { + entity: player_entity, + packet, + } in events.read() + { + // we do this so `ecs` isn't borrowed for the whole loop + events_owned.push((*player_entity, packet.clone())); + } + for (player_entity, packet) in events_owned { + let mut handler = ConfigPacketHandler { + player: player_entity, + ecs, + }; + + declare_packet_handlers!( + ClientboundConfigPacket, + packet, + handler, + [ + cookie_request, + custom_payload, + disconnect, + finish_configuration, + keep_alive, + ping, + reset_chat, + registry_data, + resource_pack_pop, + resource_pack_push, + store_cookie, + transfer, + update_enabled_features, + update_tags, + select_known_packs, + custom_report_details, + server_links, + ] + ); + } +} + +pub struct ConfigPacketHandler<'a> { + pub ecs: &'a mut World, + pub player: Entity, +} +impl ConfigPacketHandler<'_> { + pub fn registry_data(&mut self, p: ClientboundRegistryData) { + as_system::<Query<&mut InstanceHolder>>(self.ecs, |mut query| { + let instance_holder = query.get_mut(self.player).unwrap(); + let mut instance = instance_holder.instance.write(); + + // add the new registry data + instance.registries.append(p.registry_id, p.entries); + }); + } + + pub fn custom_payload(&mut self, p: ClientboundCustomPayload) { + debug!("Got custom payload packet {p:?}"); + } + + pub fn disconnect(&mut self, p: ClientboundDisconnect) { + warn!("Got disconnect packet {p:?}"); + as_system::<EventWriter<_>>(self.ecs, |mut events| { + events.send(DisconnectEvent { + entity: self.player, + reason: Some(p.reason), + }); + }); + } + + pub fn finish_configuration(&mut self, p: ClientboundFinishConfiguration) { + debug!("got FinishConfiguration packet: {p:?}"); + + as_system::<(Commands, Query<&mut RawConnection>)>( + self.ecs, + |(mut commands, mut query)| { + let mut raw_conn = query.get_mut(self.player).unwrap(); + + raw_conn + .write_packet(ServerboundFinishConfiguration) + .expect( + "we should be in the right state and encoding this packet shouldn't fail", + ); + raw_conn.set_state(ConnectionProtocol::Game); + + // these components are added now that we're going to be in the Game state + commands + .entity(self.player) + .remove::<InConfigState>() + .insert(crate::JoinedClientBundle::default()); + }, + ); + } + + pub fn keep_alive(&mut self, p: ClientboundKeepAlive) { + debug!( + "Got keep alive packet (in configuration) {p:?} for {:?}", + self.player + ); + + as_system::<(Query<&RawConnection>, EventWriter<_>)>(self.ecs, |(query, mut events)| { + let raw_conn = query.get(self.player).unwrap(); + + events.send(KeepAliveEvent { + entity: self.player, + id: p.id, + }); + raw_conn + .write_packet(ServerboundKeepAlive { id: p.id }) + .unwrap(); + }); + } + + pub fn ping(&mut self, p: ClientboundPing) { + debug!("Got ping packet (in configuration) {p:?}"); + + as_system::<Query<&RawConnection>>(self.ecs, |query| { + let raw_conn = query.get(self.player).unwrap(); + + raw_conn.write_packet(ServerboundPong { id: p.id }).unwrap(); + }); + } + + pub fn resource_pack_push(&mut self, p: ClientboundResourcePackPush) { + debug!("Got resource pack push packet {p:?}"); + + as_system::<Query<&RawConnection>>(self.ecs, |query| { + let raw_conn = query.get(self.player).unwrap(); + + // always accept resource pack + raw_conn + .write_packet(ServerboundResourcePack { + id: p.id, + action: s_resource_pack::Action::Accepted, + }) + .unwrap(); + }); + } + + pub fn resource_pack_pop(&mut self, p: ClientboundResourcePackPop) { + debug!("Got resource pack pop packet {p:?}"); + } + + pub fn update_enabled_features(&mut self, p: ClientboundUpdateEnabledFeatures) { + debug!("Got update enabled features packet {p:?}"); + } + + pub fn update_tags(&mut self, _p: ClientboundUpdateTags) { + debug!("Got update tags packet"); + } + + pub fn cookie_request(&mut self, p: ClientboundCookieRequest) { + debug!("Got cookie request packet {p:?}"); + + as_system::<Query<&RawConnection>>(self.ecs, |query| { + let raw_conn = query.get(self.player).unwrap(); + + raw_conn + .write_packet(ServerboundCookieResponse { + key: p.key, + // cookies aren't implemented + payload: None, + }) + .unwrap(); + }); + } + + pub fn reset_chat(&mut self, p: ClientboundResetChat) { + debug!("Got reset chat packet {p:?}"); + } + + pub fn store_cookie(&mut self, p: ClientboundStoreCookie) { + debug!("Got store cookie packet {p:?}"); + } + + pub fn transfer(&mut self, p: ClientboundTransfer) { + debug!("Got transfer packet {p:?}"); + } + + pub fn select_known_packs(&mut self, p: ClientboundSelectKnownPacks) { + debug!("Got select known packs packet {p:?}"); + + as_system::<Query<&RawConnection>>(self.ecs, |query| { + let raw_conn = query.get(self.player).unwrap(); + + // resource pack management isn't implemented + raw_conn + .write_packet(ServerboundSelectKnownPacks { + known_packs: vec![], + }) + .unwrap(); + }); + } + + pub fn server_links(&mut self, p: ClientboundServerLinks) { + debug!("Got server links packet {p:?}"); + } + + pub fn custom_report_details(&mut self, p: ClientboundCustomReportDetails) { + debug!("Got custom report details packet {p:?}"); + } +} |
