azalea_client/packet_handling/
configuration.rs1use std::io::Cursor;
2
3use azalea_entity::indexing::EntityIdIndex;
4use azalea_protocol::packets::config::s_finish_configuration::ServerboundFinishConfiguration;
5use azalea_protocol::packets::config::s_keep_alive::ServerboundKeepAlive;
6use azalea_protocol::packets::config::s_select_known_packs::ServerboundSelectKnownPacks;
7use azalea_protocol::packets::config::{
8 self, ClientboundConfigPacket, ServerboundConfigPacket, ServerboundCookieResponse,
9 ServerboundResourcePack,
10};
11use azalea_protocol::packets::{ConnectionProtocol, Packet};
12use azalea_protocol::read::deserialize_packet;
13use bevy_ecs::prelude::*;
14use bevy_ecs::system::SystemState;
15use tracing::{debug, error, warn};
16
17use crate::client::InConfigState;
18use crate::disconnect::DisconnectEvent;
19use crate::local_player::Hunger;
20use crate::packet_handling::game::KeepAliveEvent;
21use crate::raw_connection::RawConnection;
22use crate::InstanceHolder;
23
24#[derive(Event, Debug, Clone)]
25pub struct ConfigurationEvent {
26 pub entity: Entity,
28 pub packet: ClientboundConfigPacket,
30}
31
32pub fn send_packet_events(
33 query: Query<(Entity, &RawConnection), With<InConfigState>>,
34 mut packet_events: ResMut<Events<ConfigurationEvent>>,
35) {
36 packet_events.clear();
40 for (player_entity, raw_conn) in &query {
41 let packets_lock = raw_conn.incoming_packet_queue();
42 let mut packets = packets_lock.lock();
43 if !packets.is_empty() {
44 for raw_packet in packets.iter() {
45 let packet = match deserialize_packet::<ClientboundConfigPacket>(&mut Cursor::new(
46 raw_packet,
47 )) {
48 Ok(packet) => packet,
49 Err(err) => {
50 error!("failed to read packet: {err:?}");
51 debug!("packet bytes: {raw_packet:?}");
52 continue;
53 }
54 };
55 packet_events.send(ConfigurationEvent {
56 entity: player_entity,
57 packet,
58 });
59 }
60 packets.clear();
62 }
63 }
64}
65
66pub fn process_packet_events(ecs: &mut World) {
67 let mut events_owned = Vec::new();
68 let mut system_state: SystemState<EventReader<ConfigurationEvent>> = SystemState::new(ecs);
69 let mut events = system_state.get_mut(ecs);
70 for ConfigurationEvent {
71 entity: player_entity,
72 packet,
73 } in events.read()
74 {
75 events_owned.push((*player_entity, packet.clone()));
77 }
78 for (player_entity, packet) in events_owned {
79 match packet {
80 ClientboundConfigPacket::RegistryData(p) => {
81 let mut system_state: SystemState<Query<&mut InstanceHolder>> =
82 SystemState::new(ecs);
83 let mut query = system_state.get_mut(ecs);
84 let instance_holder = query.get_mut(player_entity).unwrap();
85 let mut instance = instance_holder.instance.write();
86
87 instance.registries.append(p.registry_id, p.entries);
89 }
90
91 ClientboundConfigPacket::CustomPayload(p) => {
92 debug!("Got custom payload packet {p:?}");
93 }
94 ClientboundConfigPacket::Disconnect(p) => {
95 warn!("Got disconnect packet {p:?}");
96 let mut system_state: SystemState<EventWriter<DisconnectEvent>> =
97 SystemState::new(ecs);
98 let mut disconnect_events = system_state.get_mut(ecs);
99 disconnect_events.send(DisconnectEvent {
100 entity: player_entity,
101 reason: Some(p.reason.clone()),
102 });
103 }
104 ClientboundConfigPacket::FinishConfiguration(p) => {
105 debug!("got FinishConfiguration packet: {p:?}");
106
107 let mut system_state: SystemState<Query<&mut RawConnection>> =
108 SystemState::new(ecs);
109 let mut query = system_state.get_mut(ecs);
110 let mut raw_conn = query.get_mut(player_entity).unwrap();
111
112 raw_conn
113 .write_packet(ServerboundFinishConfiguration)
114 .expect(
115 "we should be in the right state and encoding this packet shouldn't fail",
116 );
117 raw_conn.set_state(ConnectionProtocol::Game);
118
119 ecs.entity_mut(player_entity)
121 .remove::<InConfigState>()
122 .insert(crate::JoinedClientBundle {
123 physics_state: crate::PhysicsState::default(),
124 inventory: crate::inventory::Inventory::default(),
125 tab_list: crate::local_player::TabList::default(),
126 current_sequence_number: crate::interact::CurrentSequenceNumber::default(),
127 last_sent_direction: crate::movement::LastSentLookDirection::default(),
128 abilities: crate::local_player::PlayerAbilities::default(),
129 permission_level: crate::local_player::PermissionLevel::default(),
130 hunger: Hunger::default(),
131 chunk_batch_info: crate::chunks::ChunkBatchInfo::default(),
132
133 entity_id_index: EntityIdIndex::default(),
134
135 mining: crate::mining::MineBundle::default(),
136 attack: crate::attack::AttackBundle::default(),
137
138 _local_entity: azalea_entity::LocalEntity,
139 });
140 }
141 ClientboundConfigPacket::KeepAlive(p) => {
142 debug!("Got keep alive packet (in configuration) {p:?} for {player_entity:?}");
143
144 let mut system_state: SystemState<(
145 Query<&RawConnection>,
146 EventWriter<KeepAliveEvent>,
147 )> = SystemState::new(ecs);
148 let (query, mut keepalive_events) = system_state.get_mut(ecs);
149 let raw_conn = query.get(player_entity).unwrap();
150
151 keepalive_events.send(KeepAliveEvent {
152 entity: player_entity,
153 id: p.id,
154 });
155 raw_conn
156 .write_packet(ServerboundKeepAlive { id: p.id })
157 .unwrap();
158 }
159 ClientboundConfigPacket::Ping(p) => {
160 debug!("Got ping packet {p:?}");
161
162 let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
163 let mut query = system_state.get_mut(ecs);
164 let raw_conn = query.get_mut(player_entity).unwrap();
165
166 raw_conn
167 .write_packet(config::s_pong::ServerboundPong { id: p.id })
168 .unwrap();
169 }
170 ClientboundConfigPacket::ResourcePackPush(p) => {
171 debug!("Got resource pack packet {p:?}");
172
173 let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
174 let mut query = system_state.get_mut(ecs);
175 let raw_conn = query.get_mut(player_entity).unwrap();
176
177 raw_conn
179 .write_packet(ServerboundResourcePack {
180 id: p.id,
181 action: config::s_resource_pack::Action::Accepted,
182 })
183 .unwrap();
184 }
185 ClientboundConfigPacket::ResourcePackPop(_) => {
186 }
188 ClientboundConfigPacket::UpdateEnabledFeatures(p) => {
189 debug!("Got update enabled features packet {p:?}");
190 }
191 ClientboundConfigPacket::UpdateTags(_p) => {
192 debug!("Got update tags packet");
193 }
194 ClientboundConfigPacket::CookieRequest(p) => {
195 debug!("Got cookie request packet {p:?}");
196
197 let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
198 let mut query = system_state.get_mut(ecs);
199 let raw_conn = query.get_mut(player_entity).unwrap();
200
201 raw_conn
202 .write_packet(ServerboundCookieResponse {
203 key: p.key,
204 payload: None,
206 })
207 .unwrap();
208 }
209 ClientboundConfigPacket::ResetChat(p) => {
210 debug!("Got reset chat packet {p:?}");
211 }
212 ClientboundConfigPacket::StoreCookie(p) => {
213 debug!("Got store cookie packet {p:?}");
214 }
215 ClientboundConfigPacket::Transfer(p) => {
216 debug!("Got transfer packet {p:?}");
217 }
218 ClientboundConfigPacket::SelectKnownPacks(p) => {
219 debug!("Got select known packs packet {p:?}");
220
221 let mut system_state: SystemState<Query<&RawConnection>> = SystemState::new(ecs);
222 let mut query = system_state.get_mut(ecs);
223 let raw_conn = query.get_mut(player_entity).unwrap();
224
225 raw_conn
227 .write_packet(ServerboundSelectKnownPacks {
228 known_packs: vec![],
229 })
230 .unwrap();
231 }
232 ClientboundConfigPacket::ServerLinks(_) => {}
233 ClientboundConfigPacket::CustomReportDetails(_) => {}
234 }
235 }
236}
237
238#[derive(Event)]
241pub struct SendConfigurationEvent {
242 pub sent_by: Entity,
243 pub packet: ServerboundConfigPacket,
244}
245impl SendConfigurationEvent {
246 pub fn new(sent_by: Entity, packet: impl Packet<ServerboundConfigPacket>) -> Self {
247 let packet = packet.into_variant();
248 Self { sent_by, packet }
249 }
250}
251
252pub fn handle_send_packet_event(
253 mut send_packet_events: EventReader<SendConfigurationEvent>,
254 mut query: Query<(&mut RawConnection, Option<&InConfigState>)>,
255) {
256 for event in send_packet_events.read() {
257 if let Ok((raw_conn, in_configuration_state)) = query.get_mut(event.sent_by) {
258 if in_configuration_state.is_none() {
259 error!(
260 "Tried to send a configuration packet {:?} while not in configuration state",
261 event.packet
262 );
263 continue;
264 }
265 debug!("Sending packet: {:?}", event.packet);
266 if let Err(e) = raw_conn.write_packet(event.packet.clone()) {
267 error!("Failed to send packet: {e}");
268 }
269 }
270 }
271}