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            clear_dialog,
60            show_dialog,
61        ]
62    );
63}
64
65pub struct ConfigPacketHandler<'a> {
66    pub ecs: &'a mut World,
67    pub player: Entity,
68}
69impl ConfigPacketHandler<'_> {
70    pub fn registry_data(&mut self, p: &ClientboundRegistryData) {
71        as_system::<Query<&InstanceHolder>>(self.ecs, |mut query| {
72            let instance_holder = query.get_mut(self.player).unwrap();
73            let mut instance = instance_holder.instance.write();
74
75            // add the new registry data
76            instance
77                .registries
78                .append(p.registry_id.clone(), p.entries.clone());
79        });
80    }
81
82    pub fn custom_payload(&mut self, p: &ClientboundCustomPayload) {
83        debug!("Got custom payload packet {p:?}");
84    }
85
86    pub fn disconnect(&mut self, p: &ClientboundDisconnect) {
87        warn!("Got disconnect packet {p:?}");
88        as_system::<EventWriter<_>>(self.ecs, |mut events| {
89            events.write(DisconnectEvent {
90                entity: self.player,
91                reason: Some(p.reason.clone()),
92            });
93        });
94    }
95
96    pub fn finish_configuration(&mut self, _p: &ClientboundFinishConfiguration) {
97        debug!("got FinishConfiguration packet");
98
99        as_system::<(Commands, Query<&mut RawConnection>)>(
100            self.ecs,
101            |(mut commands, mut query)| {
102                let mut raw_conn = query.get_mut(self.player).unwrap();
103                raw_conn.state = ConnectionProtocol::Game;
104
105                commands.trigger(SendConfigPacketEvent::new(
106                    self.player,
107                    ServerboundFinishConfiguration,
108                ));
109
110                // these components are added now that we're going to be in the Game state
111                commands
112                    .entity(self.player)
113                    .remove::<InConfigState>()
114                    .insert((
115                        crate::JoinedClientBundle::default(),
116                        // localentity should already be added, but in case the user forgot or
117                        // something we also add it here
118                        LocalEntity,
119                    ));
120            },
121        );
122    }
123
124    pub fn keep_alive(&mut self, p: &ClientboundKeepAlive) {
125        debug!(
126            "Got keep alive packet (in configuration) {p:?} for {:?}",
127            self.player
128        );
129
130        as_system::<(Commands, EventWriter<_>)>(self.ecs, |(mut commands, mut events)| {
131            events.write(KeepAliveEvent {
132                entity: self.player,
133                id: p.id,
134            });
135            commands.trigger(SendConfigPacketEvent::new(
136                self.player,
137                ServerboundKeepAlive { id: p.id },
138            ));
139        });
140    }
141
142    pub fn ping(&mut self, p: &ClientboundPing) {
143        debug!("Got ping packet (in configuration) {p:?}");
144
145        as_system::<Commands>(self.ecs, |mut commands| {
146            commands.trigger_targets(ConfigPingEvent(p.clone()), self.player);
147        });
148    }
149
150    pub fn resource_pack_push(&mut self, p: &ClientboundResourcePackPush) {
151        debug!("Got resource pack push packet {p:?}");
152
153        as_system::<EventWriter<_>>(self.ecs, |mut events| {
154            events.write(ResourcePackEvent {
155                entity: self.player,
156                id: p.id,
157                url: p.url.to_owned(),
158                hash: p.hash.to_owned(),
159                required: p.required,
160                prompt: p.prompt.to_owned(),
161            });
162        });
163    }
164
165    pub fn resource_pack_pop(&mut self, p: &ClientboundResourcePackPop) {
166        debug!("Got resource pack pop packet {p:?}");
167    }
168
169    pub fn update_enabled_features(&mut self, p: &ClientboundUpdateEnabledFeatures) {
170        debug!("Got update enabled features packet {p:?}");
171    }
172
173    pub fn update_tags(&mut self, _p: &ClientboundUpdateTags) {
174        debug!("Got update tags packet");
175    }
176
177    pub fn cookie_request(&mut self, p: &ClientboundCookieRequest) {
178        debug!("Got cookie request packet {p:?}");
179
180        as_system::<Commands>(self.ecs, |mut commands| {
181            commands.trigger(SendConfigPacketEvent::new(
182                self.player,
183                ServerboundCookieResponse {
184                    key: p.key.clone(),
185                    // cookies aren't implemented
186                    payload: None,
187                },
188            ));
189        });
190    }
191
192    pub fn reset_chat(&mut self, p: &ClientboundResetChat) {
193        debug!("Got reset chat packet {p:?}");
194    }
195
196    pub fn store_cookie(&mut self, p: &ClientboundStoreCookie) {
197        debug!("Got store cookie packet {p:?}");
198    }
199
200    pub fn transfer(&mut self, p: &ClientboundTransfer) {
201        debug!("Got transfer packet {p:?}");
202    }
203
204    pub fn select_known_packs(&mut self, p: &ClientboundSelectKnownPacks) {
205        debug!("Got select known packs packet {p:?}");
206
207        as_system::<Commands>(self.ecs, |mut commands| {
208            // resource pack management isn't implemented
209            commands.trigger(SendConfigPacketEvent::new(
210                self.player,
211                ServerboundSelectKnownPacks {
212                    known_packs: vec![],
213                },
214            ));
215        });
216    }
217
218    pub fn server_links(&mut self, p: &ClientboundServerLinks) {
219        debug!("Got server links packet {p:?}");
220    }
221
222    pub fn custom_report_details(&mut self, p: &ClientboundCustomReportDetails) {
223        debug!("Got custom report details packet {p:?}");
224    }
225
226    pub fn clear_dialog(&mut self, p: &ClientboundClearDialog) {
227        debug!("Got clear dialog packet {p:?}");
228    }
229    pub fn show_dialog(&mut self, p: &ClientboundShowDialog) {
230        debug!("Got show dialog packet {p:?}");
231    }
232}