mod events; use std::io::Cursor; use azalea_entity::LocalEntity; use azalea_protocol::{ packets::{ConnectionProtocol, config::*}, read::{ReadPacketError, deserialize_packet}, }; use bevy_ecs::prelude::*; pub use events::*; use tracing::{debug, warn}; use super::{as_system, declare_packet_handlers}; use crate::{ client::InConfigState, connection::RawConnection, cookies::{RequestCookieEvent, StoreCookieEvent}, disconnect::DisconnectEvent, local_player::WorldHolder, packet::game::{KeepAliveEvent, ResourcePackEvent}, }; pub fn process_raw_packet( ecs: &mut World, player: Entity, raw_packet: &[u8], ) -> Result<(), Box> { let packet = deserialize_packet(&mut Cursor::new(raw_packet))?; process_packet(ecs, player, &packet); Ok(()) } pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundConfigPacket) { let mut handler = ConfigPacketHandler { player, 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, clear_dialog, show_dialog, code_of_conduct, ] ); } pub struct ConfigPacketHandler<'a> { pub ecs: &'a mut World, pub player: Entity, } impl ConfigPacketHandler<'_> { pub fn registry_data(&mut self, p: &ClientboundRegistryData) { as_system::>(self.ecs, |mut query| { let world_holder = query.get_mut(self.player).unwrap(); let mut world = world_holder.shared.write(); // add the new registry data world .registries .append(p.registry_id.clone(), p.entries.clone()); }); } 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::>(self.ecs, |mut events| { events.write(DisconnectEvent { entity: self.player, reason: Some(p.reason.clone()), }); }); } pub fn finish_configuration(&mut self, _p: &ClientboundFinishConfiguration) { debug!("got FinishConfiguration packet"); as_system::<(Commands, Query<&mut RawConnection>)>( self.ecs, |(mut commands, mut query)| { let mut raw_conn = query.get_mut(self.player).unwrap(); raw_conn.state = ConnectionProtocol::Game; commands.trigger(SendConfigPacketEvent::new( self.player, ServerboundFinishConfiguration, )); // these components are added now that we're going to be in the Game state commands .entity(self.player) .remove::() .insert(( crate::JoinedClientBundle::default(), // localentity should already be added, but in case the user forgot or // something we also add it here LocalEntity, )); }, ); } pub fn keep_alive(&mut self, p: &ClientboundKeepAlive) { debug!( "Got keep alive packet (in configuration) {p:?} for {:?}", self.player ); as_system::(self.ecs, |mut commands| { commands.trigger(KeepAliveEvent { entity: self.player, id: p.id, }); commands.trigger(SendConfigPacketEvent::new( self.player, ServerboundKeepAlive { id: p.id }, )); }); } pub fn ping(&mut self, p: &ClientboundPing) { debug!("Got ping packet (in configuration) {p:?}"); as_system::(self.ecs, |mut commands| { commands.trigger(ConfigPingEvent { entity: self.player, packet: p.clone(), }); }); } pub fn resource_pack_push(&mut self, p: &ClientboundResourcePackPush) { debug!("Got resource pack push packet {p:?}"); as_system::>(self.ecs, |mut events| { events.write(ResourcePackEvent { entity: self.player, id: p.id, url: p.url.to_owned(), hash: p.hash.to_owned(), required: p.required, prompt: p.prompt.to_owned(), }); }); } 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::(self.ecs, |mut commands| { commands.trigger(RequestCookieEvent { entity: self.player, key: p.key.clone(), }); }); } pub fn store_cookie(&mut self, p: &ClientboundStoreCookie) { debug!("Got store cookie packet {p:?}"); as_system::(self.ecs, |mut commands| { commands.trigger(StoreCookieEvent { entity: self.player, key: p.key.clone(), payload: p.payload.clone(), }); }); } pub fn reset_chat(&mut self, p: &ClientboundResetChat) { debug!("Got reset chat 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::(self.ecs, |mut commands| { // resource pack management isn't implemented commands.trigger(SendConfigPacketEvent::new( self.player, ServerboundSelectKnownPacks { known_packs: vec![], }, )); }); } 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:?}"); } pub fn clear_dialog(&mut self, p: &ClientboundClearDialog) { debug!("Got clear dialog packet {p:?}"); } pub fn show_dialog(&mut self, p: &ClientboundShowDialog) { debug!("Got show dialog packet {p:?}"); } pub fn code_of_conduct(&mut self, p: &ClientboundCodeOfConduct) { debug!("Got code of conduct packet {p:?}"); } }