azalea_client/plugins/packet/config/
mod.rs

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