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, declare_packet_handlers};
15use crate::{
16    client::InConfigState,
17    connection::RawConnection,
18    disconnect::DisconnectEvent,
19    local_player::InstanceHolder,
20    packet::game::{KeepAliveEvent, ResourcePackEvent},
21};
22
23pub fn process_raw_packet(
24    ecs: &mut World,
25    player: Entity,
26    raw_packet: &[u8],
27) -> Result<(), Box<ReadPacketError>> {
28    let packet = deserialize_packet(&mut Cursor::new(raw_packet))?;
29    process_packet(ecs, player, &packet);
30    Ok(())
31}
32
33pub fn process_packet(ecs: &mut World, player: Entity, packet: &ClientboundConfigPacket) {
34    let mut handler = ConfigPacketHandler { player, ecs };
35
36    declare_packet_handlers!(
37        ClientboundConfigPacket,
38        packet,
39        handler,
40        [
41            cookie_request,
42            custom_payload,
43            disconnect,
44            finish_configuration,
45            keep_alive,
46            ping,
47            reset_chat,
48            registry_data,
49            resource_pack_pop,
50            resource_pack_push,
51            store_cookie,
52            transfer,
53            update_enabled_features,
54            update_tags,
55            select_known_packs,
56            custom_report_details,
57            server_links,
58            clear_dialog,
59            show_dialog,
60            code_of_conduct,
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::<MessageWriter<_>>(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, MessageWriter<_>)>(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(ConfigPingEvent {
147                entity: self.player,
148                packet: p.clone(),
149            });
150        });
151    }
152
153    pub fn resource_pack_push(&mut self, p: &ClientboundResourcePackPush) {
154        debug!("Got resource pack push packet {p:?}");
155
156        as_system::<MessageWriter<_>>(self.ecs, |mut events| {
157            events.write(ResourcePackEvent {
158                entity: self.player,
159                id: p.id,
160                url: p.url.to_owned(),
161                hash: p.hash.to_owned(),
162                required: p.required,
163                prompt: p.prompt.to_owned(),
164            });
165        });
166    }
167
168    pub fn resource_pack_pop(&mut self, p: &ClientboundResourcePackPop) {
169        debug!("Got resource pack pop packet {p:?}");
170    }
171
172    pub fn update_enabled_features(&mut self, p: &ClientboundUpdateEnabledFeatures) {
173        debug!("Got update enabled features packet {p:?}");
174    }
175
176    pub fn update_tags(&mut self, _p: &ClientboundUpdateTags) {
177        debug!("Got update tags packet");
178    }
179
180    pub fn cookie_request(&mut self, p: &ClientboundCookieRequest) {
181        debug!("Got cookie request packet {p:?}");
182
183        as_system::<Commands>(self.ecs, |mut commands| {
184            commands.trigger(SendConfigPacketEvent::new(
185                self.player,
186                ServerboundCookieResponse {
187                    key: p.key.clone(),
188                    // cookies aren't implemented
189                    payload: None,
190                },
191            ));
192        });
193    }
194
195    pub fn reset_chat(&mut self, p: &ClientboundResetChat) {
196        debug!("Got reset chat packet {p:?}");
197    }
198
199    pub fn store_cookie(&mut self, p: &ClientboundStoreCookie) {
200        debug!("Got store cookie packet {p:?}");
201    }
202
203    pub fn transfer(&mut self, p: &ClientboundTransfer) {
204        debug!("Got transfer packet {p:?}");
205    }
206
207    pub fn select_known_packs(&mut self, p: &ClientboundSelectKnownPacks) {
208        debug!("Got select known packs packet {p:?}");
209
210        as_system::<Commands>(self.ecs, |mut commands| {
211            // resource pack management isn't implemented
212            commands.trigger(SendConfigPacketEvent::new(
213                self.player,
214                ServerboundSelectKnownPacks {
215                    known_packs: vec![],
216                },
217            ));
218        });
219    }
220
221    pub fn server_links(&mut self, p: &ClientboundServerLinks) {
222        debug!("Got server links packet {p:?}");
223    }
224
225    pub fn custom_report_details(&mut self, p: &ClientboundCustomReportDetails) {
226        debug!("Got custom report details packet {p:?}");
227    }
228
229    pub fn clear_dialog(&mut self, p: &ClientboundClearDialog) {
230        debug!("Got clear dialog packet {p:?}");
231    }
232    pub fn show_dialog(&mut self, p: &ClientboundShowDialog) {
233        debug!("Got show dialog packet {p:?}");
234    }
235    pub fn code_of_conduct(&mut self, p: &ClientboundCodeOfConduct) {
236        debug!("Got code of conduct packet {p:?}");
237    }
238}