1#![allow(clippy::redundant_field_names, reason = "Triggered by `Error` derive")]
2
3use std::{
4 fmt::Debug,
5 io::Cursor,
6 mem,
7 sync::{
8 Arc,
9 atomic::{self, AtomicBool},
10 },
11};
12
13use azalea_crypto::Aes128CfbEnc;
14use azalea_protocol::{
15 connect::{RawReadConnection, RawWriteConnection},
16 packets::{
17 ConnectionProtocol, Packet, ProtocolPacket, config::ClientboundConfigPacket,
18 game::ClientboundGamePacket, login::ClientboundLoginPacket,
19 },
20 read::{ReadPacketError, deserialize_packet},
21 write::serialize_packet,
22};
23use bevy_app::prelude::*;
24use bevy_ecs::prelude::*;
25use bevy_tasks::{IoTaskPool, futures_lite::future};
26use thiserror::Error;
27use tokio::{
28 io::AsyncWriteExt,
29 net::tcp::OwnedWriteHalf,
30 sync::mpsc::{self},
31};
32use tracing::{debug, error, info, trace};
33
34use super::packet::{
35 config::ReceiveConfigPacketEvent, game::ReceiveGamePacketEvent, login::ReceiveLoginPacketEvent,
36};
37use crate::packet::{config, game, login};
38
39pub struct ConnectionPlugin;
40impl Plugin for ConnectionPlugin {
41 fn build(&self, app: &mut App) {
42 app.add_systems(PreUpdate, (read_packets, poll_all_writer_tasks).chain());
43 }
44}
45
46pub fn read_packets(ecs: &mut World) {
47 let mut entity_and_conn_query = ecs.query::<(Entity, &mut RawConnection)>();
48 let mut conn_query = ecs.query::<&mut RawConnection>();
49
50 let mut entities_handling_packets = Vec::new();
51 let mut entities_with_injected_packets = Vec::new();
52 for (entity, mut raw_conn) in entity_and_conn_query.iter_mut(ecs) {
53 if !raw_conn.injected_clientbound_packets.is_empty() {
54 entities_with_injected_packets.push((
55 entity,
56 mem::take(&mut raw_conn.injected_clientbound_packets),
57 ));
58 }
59
60 if raw_conn.network.is_none() {
61 continue;
63 }
64
65 entities_handling_packets.push(entity);
66 }
67
68 let mut queued_packet_events = QueuedPacketEvents::default();
69
70 for (entity, raw_packets) in entities_with_injected_packets {
73 for raw_packet in raw_packets {
74 let conn = conn_query.get(ecs, entity).unwrap();
75 let state = conn.state;
76
77 trace!("Received injected packet with bytes: {raw_packet:?}");
78 if let Err(e) =
79 handle_raw_packet(ecs, &raw_packet, entity, state, &mut queued_packet_events)
80 {
81 error!("Error reading injected packet: {e}");
82 }
83 }
84 }
85
86 for entity in entities_handling_packets {
87 loop {
88 let mut conn = conn_query.get_mut(ecs, entity).unwrap();
89 let net_conn = conn.net_conn().unwrap();
90 let read_res = net_conn.reader.try_read();
91 let state = conn.state;
92 match read_res {
93 Ok(Some(raw_packet)) => {
94 let raw_packet = Arc::<[u8]>::from(raw_packet);
95 if let Err(e) = handle_raw_packet(
96 ecs,
97 &raw_packet,
98 entity,
99 state,
100 &mut queued_packet_events,
101 ) {
102 error!("Error reading packet: {e}");
103 }
104 }
105 Ok(None) => {
106 break;
108 }
109 Err(err) => {
110 log_for_error(&err);
111
112 if matches!(
113 &*err,
114 ReadPacketError::IoError { .. } | ReadPacketError::ConnectionClosed
115 ) {
116 info!("Server closed connection");
117 conn.network = None;
119 conn.is_alive = false;
121 }
122
123 break;
124 }
125 }
126 }
127 }
128
129 queued_packet_events.write_messages(ecs);
130}
131
132fn poll_all_writer_tasks(mut conn_query: Query<&mut RawConnection>) {
133 for mut conn in conn_query.iter_mut() {
134 if let Some(net_conn) = &mut conn.network {
135 if net_conn.poll_writer().is_some() {
139 conn.network = None;
141 conn.is_alive = false;
142 }
143 }
144 }
145}
146
147#[derive(Default)]
148pub struct QueuedPacketEvents {
149 login: Vec<ReceiveLoginPacketEvent>,
150 config: Vec<ReceiveConfigPacketEvent>,
151 game: Vec<ReceiveGamePacketEvent>,
152}
153impl QueuedPacketEvents {
154 fn write_messages(&mut self, ecs: &mut World) {
155 ecs.write_message_batch(self.login.drain(..));
156 ecs.write_message_batch(self.config.drain(..));
157 ecs.write_message_batch(self.game.drain(..));
158 }
159}
160
161fn log_for_error(error: &ReadPacketError) {
162 if !matches!(*error, ReadPacketError::ConnectionClosed) {
163 error!("Error reading packet from Client: {error:?}");
164 }
165}
166
167#[derive(Component)]
169pub struct RawConnection {
170 pub(crate) network: Option<NetworkConnection>,
183 pub state: ConnectionProtocol,
184 pub(crate) is_alive: bool,
185
186 pub injected_clientbound_packets: Vec<Box<[u8]>>,
192}
193impl RawConnection {
194 pub fn new(
195 reader: RawReadConnection,
196 writer: RawWriteConnection,
197 state: ConnectionProtocol,
198 ) -> Self {
199 let task_pool = IoTaskPool::get();
200
201 let (network_packet_writer_tx, network_packet_writer_rx) =
202 mpsc::unbounded_channel::<Box<[u8]>>();
203
204 let writer_task =
205 task_pool.spawn(write_task(network_packet_writer_rx, writer.write_stream));
206
207 let mut conn = Self::new_networkless(state);
208 conn.network = Some(NetworkConnection {
209 reader,
210 enc_cipher: writer.enc_cipher,
211 network_packet_writer_tx,
212 writer_task,
213 });
214
215 conn
216 }
217
218 pub fn new_networkless(state: ConnectionProtocol) -> Self {
219 Self {
220 network: None,
221 state,
222 is_alive: true,
223 injected_clientbound_packets: Vec::new(),
224 }
225 }
226
227 pub fn is_alive(&self) -> bool {
228 self.is_alive
229 }
230
231 pub fn write<P: ProtocolPacket + Debug>(
240 &mut self,
241 packet: impl Packet<P>,
242 ) -> Result<(), WritePacketError> {
243 if let Some(network) = &mut self.network {
244 network.write(packet)?;
245 } else {
246 static WARNED: AtomicBool = AtomicBool::new(false);
247 if !WARNED.swap(true, atomic::Ordering::Relaxed) {
248 debug!(
249 "tried to write packet to the network but there is no NetworkConnection. if you're trying to send a packet from the handler function, use self.write instead"
250 );
251 }
252 }
253 Ok(())
254 }
255
256 pub fn net_conn(&mut self) -> Option<&mut NetworkConnection> {
257 self.network.as_mut()
258 }
259}
260
261pub fn handle_raw_packet(
262 ecs: &mut World,
263 raw_packet: &[u8],
264 entity: Entity,
265 state: ConnectionProtocol,
266 queued_packet_events: &mut QueuedPacketEvents,
267) -> Result<(), Box<ReadPacketError>> {
268 let stream = &mut Cursor::new(raw_packet);
269 match state {
270 ConnectionProtocol::Handshake => {
271 unreachable!()
272 }
273 ConnectionProtocol::Game => {
274 let packet = Arc::new(deserialize_packet::<ClientboundGamePacket>(stream)?);
275 trace!("Packet: {packet:?}");
276 game::process_packet(ecs, entity, packet.as_ref());
277 queued_packet_events
278 .game
279 .push(ReceiveGamePacketEvent { entity, packet });
280 }
281 ConnectionProtocol::Status => {
282 unreachable!()
283 }
284 ConnectionProtocol::Login => {
285 let packet = Arc::new(deserialize_packet::<ClientboundLoginPacket>(stream)?);
286 trace!("Packet: {packet:?}");
287 login::process_packet(ecs, entity, &packet);
288 queued_packet_events
289 .login
290 .push(ReceiveLoginPacketEvent { entity, packet });
291 }
292 ConnectionProtocol::Configuration => {
293 let packet = Arc::new(deserialize_packet::<ClientboundConfigPacket>(stream)?);
294 trace!("Packet: {packet:?}");
295 config::process_packet(ecs, entity, &packet);
296 queued_packet_events
297 .config
298 .push(ReceiveConfigPacketEvent { entity, packet });
299 }
300 };
301
302 Ok(())
303}
304
305pub struct NetworkConnection {
306 reader: RawReadConnection,
307 pub enc_cipher: Option<Aes128CfbEnc>,
309
310 pub writer_task: bevy_tasks::Task<()>,
311 network_packet_writer_tx: mpsc::UnboundedSender<Box<[u8]>>,
316}
317impl NetworkConnection {
318 pub fn write<P: ProtocolPacket + Debug>(
319 &mut self,
320 packet: impl Packet<P>,
321 ) -> Result<(), WritePacketError> {
322 let packet = packet.into_variant();
323 let raw_packet = serialize_packet(&packet)?;
324 self.write_raw(&raw_packet)?;
325
326 Ok(())
327 }
328
329 pub fn write_raw(&mut self, raw_packet: &[u8]) -> Result<(), WritePacketError> {
330 let network_packet = azalea_protocol::write::encode_to_network_packet(
331 raw_packet,
332 self.reader.compression_threshold,
333 &mut self.enc_cipher,
334 );
335 self.network_packet_writer_tx
336 .send(network_packet.into_boxed_slice())?;
337 Ok(())
338 }
339
340 pub fn poll_writer(&mut self) -> Option<()> {
343 let poll_once_res = future::poll_once(&mut self.writer_task);
344 future::block_on(poll_once_res)
345 }
346
347 pub fn set_compression_threshold(&mut self, threshold: Option<u32>) {
348 trace!("Set compression threshold to {threshold:?}");
349 self.reader.compression_threshold = threshold;
350 }
351 pub fn set_encryption_key(&mut self, key: [u8; 16]) {
355 trace!("Enabled protocol encryption");
356 let (enc_cipher, dec_cipher) = azalea_crypto::create_cipher(&key);
357 self.reader.dec_cipher = Some(dec_cipher);
358 self.enc_cipher = Some(enc_cipher);
359 }
360}
361
362async fn write_task(
363 mut network_packet_writer_rx: mpsc::UnboundedReceiver<Box<[u8]>>,
364 mut write_half: OwnedWriteHalf,
365) {
366 while let Some(network_packet) = network_packet_writer_rx.recv().await {
367 if let Err(e) = write_half.write_all(&network_packet).await {
368 debug!("Error writing packet to server: {e}");
369 break;
370 };
371 }
372
373 trace!("write task is done");
374}
375
376#[derive(Debug, Error)]
377pub enum WritePacketError {
378 #[error("Wrong protocol state: expected {expected:?}, got {got:?}")]
379 WrongState {
380 expected: ConnectionProtocol,
381 got: ConnectionProtocol,
382 },
383 #[error(transparent)]
384 Encoding(#[from] azalea_protocol::write::PacketEncodeError),
385 #[error(transparent)]
386 SendError {
387 #[from]
388 #[backtrace]
389 source: mpsc::error::SendError<Box<[u8]>>,
390 },
391}