azalea_client/plugins/packet/config/
mod.rs

1mod events;
2
3use azalea_entity::LocalEntity;
4use azalea_protocol::packets::ConnectionProtocol;
5use azalea_protocol::packets::config::*;
6use bevy_ecs::prelude::*;
7use bevy_ecs::system::SystemState;
8pub use events::*;
9use tracing::{debug, warn};
10
11use super::as_system;
12use crate::client::InConfigState;
13use crate::disconnect::DisconnectEvent;
14use crate::packet::game::KeepAliveEvent;
15use crate::packet::game::ResourcePackEvent;
16use crate::raw_connection::RawConnection;
17use crate::{InstanceHolder, declare_packet_handlers};
18
19pub fn process_packet_events(ecs: &mut World) {
20    let mut events_owned = Vec::new();
21    let mut system_state: SystemState<EventReader<ReceiveConfigPacketEvent>> =
22        SystemState::new(ecs);
23    let mut events = system_state.get_mut(ecs);
24    for ReceiveConfigPacketEvent {
25        entity: player_entity,
26        packet,
27    } in events.read()
28    {
29        // we do this so `ecs` isn't borrowed for the whole loop
30        events_owned.push((*player_entity, packet.clone()));
31    }
32    for (player_entity, packet) in events_owned {
33        let mut handler = ConfigPacketHandler {
34            player: player_entity,
35            ecs,
36        };
37
38        declare_packet_handlers!(
39            ClientboundConfigPacket,
40            packet,
41            handler,
42            [
43                cookie_request,
44                custom_payload,
45                disconnect,
46                finish_configuration,
47                keep_alive,
48                ping,
49                reset_chat,
50                registry_data,
51                resource_pack_pop,
52                resource_pack_push,
53                store_cookie,
54                transfer,
55                update_enabled_features,
56                update_tags,
57                select_known_packs,
58                custom_report_details,
59                server_links,
60            ]
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<&mut 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.registries.append(p.registry_id, p.entries);
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.send(DisconnectEvent {
88                entity: self.player,
89                reason: Some(p.reason),
90            });
91        });
92    }
93
94    pub fn finish_configuration(&mut self, p: ClientboundFinishConfiguration) {
95        debug!("got FinishConfiguration packet: {p:?}");
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
102                raw_conn
103                    .write_packet(ServerboundFinishConfiguration)
104                    .expect(
105                        "we should be in the right state and encoding this packet shouldn't fail",
106                    );
107                raw_conn.set_state(ConnectionProtocol::Game);
108
109                // these components are added now that we're going to be in the Game state
110                commands
111                    .entity(self.player)
112                    .remove::<InConfigState>()
113                    .insert((
114                        crate::JoinedClientBundle::default(),
115                        // localentity should already be added, but in case the user forgot or
116                        // something we also add it here
117                        LocalEntity,
118                    ));
119            },
120        );
121    }
122
123    pub fn keep_alive(&mut self, p: ClientboundKeepAlive) {
124        debug!(
125            "Got keep alive packet (in configuration) {p:?} for {:?}",
126            self.player
127        );
128
129        as_system::<(Query<&RawConnection>, EventWriter<_>)>(self.ecs, |(query, mut events)| {
130            let raw_conn = query.get(self.player).unwrap();
131
132            events.send(KeepAliveEvent {
133                entity: self.player,
134                id: p.id,
135            });
136            raw_conn
137                .write_packet(ServerboundKeepAlive { id: p.id })
138                .unwrap();
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), 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.send(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::<Query<&RawConnection>>(self.ecs, |query| {
181            let raw_conn = query.get(self.player).unwrap();
182
183            raw_conn
184                .write_packet(ServerboundCookieResponse {
185                    key: p.key,
186                    // cookies aren't implemented
187                    payload: None,
188                })
189                .unwrap();
190        });
191    }
192
193    pub fn reset_chat(&mut self, p: ClientboundResetChat) {
194        debug!("Got reset chat packet {p:?}");
195    }
196
197    pub fn store_cookie(&mut self, p: ClientboundStoreCookie) {
198        debug!("Got store cookie packet {p:?}");
199    }
200
201    pub fn transfer(&mut self, p: ClientboundTransfer) {
202        debug!("Got transfer packet {p:?}");
203    }
204
205    pub fn select_known_packs(&mut self, p: ClientboundSelectKnownPacks) {
206        debug!("Got select known packs packet {p:?}");
207
208        as_system::<Query<&RawConnection>>(self.ecs, |query| {
209            let raw_conn = query.get(self.player).unwrap();
210
211            // resource pack management isn't implemented
212            raw_conn
213                .write_packet(ServerboundSelectKnownPacks {
214                    known_packs: vec![],
215                })
216                .unwrap();
217        });
218    }
219
220    pub fn server_links(&mut self, p: ClientboundServerLinks) {
221        debug!("Got server links packet {p:?}");
222    }
223
224    pub fn custom_report_details(&mut self, p: ClientboundCustomReportDetails) {
225        debug!("Got custom report details packet {p:?}");
226    }
227}