azalea_client/plugins/packet/config/
mod.rs

1mod events;
2
3use std::io::Cursor;
4
5use azalea_entity::LocalEntity;
6use azalea_protocol::{
7    packets::{ConnectionProtocol, config::*},
8    read::{ReadPacketError, deserialize_packet},
9};
10use bevy_ecs::prelude::*;
11pub use events::*;
12use tracing::{debug, warn};
13
14use super::as_system;
15use crate::{
16    client::InConfigState,
17    connection::RawConnection,
18    declare_packet_handlers,
19    disconnect::DisconnectEvent,
20    local_player::InstanceHolder,
21    packet::game::{KeepAliveEvent, ResourcePackEvent},
22};
23
24pub fn process_raw_packet(
25    ecs: &mut World,
26    player: Entity,
27    raw_packet: &[u8],
28) -> Result<(), Box<ReadPacketError>> {
29    let packet = deserialize_packet(&mut Cursor::new(raw_packet))?;
30    process_packet(ecs, player, &packet);
31    Ok(())
32}
33
34pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundConfigPacket) {
35    let mut handler = ConfigPacketHandler { player, ecs };
36
37    declare_packet_handlers!(
38        ClientboundConfigPacket,
39        packet,
40        handler,
41        [
42            cookie_request,
43            custom_payload,
44            disconnect,
45            finish_configuration,
46            keep_alive,
47            ping,
48            reset_chat,
49            registry_data,
50            resource_pack_pop,
51            resource_pack_push,
52            store_cookie,
53            transfer,
54            update_enabled_features,
55            update_tags,
56            select_known_packs,
57            custom_report_details,
58            server_links,
59        ]
60    );
61}
62
63pub struct ConfigPacketHandler<'a> {
64    pub ecs: &'a mut World,
65    pub player: Entity,
66}
67impl ConfigPacketHandler<'_> {
68    pub fn registry_data(&mut self, p: &ClientboundRegistryData) {
69        as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
70            let instance_holder = query.get_mut(self.player).unwrap();
71            let mut instance = instance_holder.instance.write();
72
73            // add the new registry data
74            instance
75                .registries
76                .append(p.registry_id.clone(), p.entries.clone());
77        });
78    }
79
80    pub fn custom_payload(&mut self, p: &ClientboundCustomPayload) {
81        debug!("Got custom payload packet {p:?}");
82    }
83
84    pub fn disconnect(&mut self, p: &ClientboundDisconnect) {
85        warn!("Got disconnect packet {p:?}");
86        as_system::<EventWriter<_>>(self.ecs, |mut events| {
87            events.write(DisconnectEvent {
88                entity: self.player,
89                reason: Some(p.reason.clone()),
90            });
91        });
92    }
93
94    pub fn finish_configuration(&mut self, _p: &ClientboundFinishConfiguration) {
95        debug!("got FinishConfiguration packet");
96
97        as_system::<(Commands, Query<&mut RawConnection>)>(
98            self.ecs,
99            |(mut commands, mut query)| {
100                let mut raw_conn = query.get_mut(self.player).unwrap();
101                raw_conn.state = ConnectionProtocol::Game;
102
103                commands.trigger(SendConfigPacketEvent::new(
104                    self.player,
105                    ServerboundFinishConfiguration,
106                ));
107
108                // these components are added now that we're going to be in the Game state
109                commands
110                    .entity(self.player)
111                    .remove::<InConfigState>()
112                    .insert((
113                        crate::JoinedClientBundle::default(),
114                        // localentity should already be added, but in case the user forgot or
115                        // something we also add it here
116                        LocalEntity,
117                    ));
118            },
119        );
120    }
121
122    pub fn keep_alive(&mut self, p: &ClientboundKeepAlive) {
123        debug!(
124            "Got keep alive packet (in configuration) {p:?} for {:?}",
125            self.player
126        );
127
128        as_system::<(Commands, EventWriter<_>)>(self.ecs, |(mut commands, mut events)| {
129            events.write(KeepAliveEvent {
130                entity: self.player,
131                id: p.id,
132            });
133            commands.trigger(SendConfigPacketEvent::new(
134                self.player,
135                ServerboundKeepAlive { id: p.id },
136            ));
137        });
138    }
139
140    pub fn ping(&mut self, p: &ClientboundPing) {
141        debug!("Got ping packet (in configuration) {p:?}");
142
143        as_system::<Commands>(self.ecs, |mut commands| {
144            commands.trigger_targets(ConfigPingEvent(p.clone()), self.player);
145        });
146    }
147
148    pub fn resource_pack_push(&mut self, p: &ClientboundResourcePackPush) {
149        debug!("Got resource pack push packet {p:?}");
150
151        as_system::<EventWriter<_>>(self.ecs, |mut events| {
152            events.write(ResourcePackEvent {
153                entity: self.player,
154                id: p.id,
155                url: p.url.to_owned(),
156                hash: p.hash.to_owned(),
157                required: p.required,
158                prompt: p.prompt.to_owned(),
159            });
160        });
161    }
162
163    pub fn resource_pack_pop(&mut self, p: &ClientboundResourcePackPop) {
164        debug!("Got resource pack pop packet {p:?}");
165    }
166
167    pub fn update_enabled_features(&mut self, p: &ClientboundUpdateEnabledFeatures) {
168        debug!("Got update enabled features packet {p:?}");
169    }
170
171    pub fn update_tags(&mut self, _p: &ClientboundUpdateTags) {
172        debug!("Got update tags packet");
173    }
174
175    pub fn cookie_request(&mut self, p: &ClientboundCookieRequest) {
176        debug!("Got cookie request packet {p:?}");
177
178        as_system::<Commands>(self.ecs, |mut commands| {
179            commands.trigger(SendConfigPacketEvent::new(
180                self.player,
181                ServerboundCookieResponse {
182                    key: p.key.clone(),
183                    // cookies aren't implemented
184                    payload: None,
185                },
186            ));
187        });
188    }
189
190    pub fn reset_chat(&mut self, p: &ClientboundResetChat) {
191        debug!("Got reset chat packet {p:?}");
192    }
193
194    pub fn store_cookie(&mut self, p: &ClientboundStoreCookie) {
195        debug!("Got store cookie packet {p:?}");
196    }
197
198    pub fn transfer(&mut self, p: &ClientboundTransfer) {
199        debug!("Got transfer packet {p:?}");
200    }
201
202    pub fn select_known_packs(&mut self, p: &ClientboundSelectKnownPacks) {
203        debug!("Got select known packs packet {p:?}");
204
205        as_system::<Commands>(self.ecs, |mut commands| {
206            // resource pack management isn't implemented
207            commands.trigger(SendConfigPacketEvent::new(
208                self.player,
209                ServerboundSelectKnownPacks {
210                    known_packs: vec![],
211                },
212            ));
213        });
214    }
215
216    pub fn server_links(&mut self, p: &ClientboundServerLinks) {
217        debug!("Got server links packet {p:?}");
218    }
219
220    pub fn custom_report_details(&mut self, p: &ClientboundCustomReportDetails) {
221        debug!("Got custom report details packet {p:?}");
222    }
223}