aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/plugins/packet/config
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-02-22 21:45:26 -0600
committerGitHub <noreply@github.com>2025-02-22 21:45:26 -0600
commite21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7 (patch)
treeadd6f8bfce40d0c07845d8aa4c9945a0b918444c /azalea-client/src/plugins/packet/config
parentf8130c3c92946d2293634ba4e252d6bc93026c3c (diff)
downloadazalea-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.rs90
-rw-r--r--azalea-client/src/plugins/packet/config/mod.rs223
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:?}");
+ }
+}