use crate::{mc_buf::Writable, packets::ProtocolPacket, read::MAXIMUM_UNCOMPRESSED_LENGTH}; use async_compression::tokio::bufread::ZlibEncoder; use azalea_crypto::Aes128CfbEnc; use std::fmt::Debug; use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; fn frame_prepender(data: &mut Vec) -> Result, String> { let mut buf = Vec::new(); buf.write_varint(data.len() as i32) .map_err(|e| e.to_string())?; buf.append(data); Ok(buf) } fn packet_encoder(packet: &P) -> Result, String> { let mut buf = Vec::new(); buf.write_varint(packet.id() as i32) .map_err(|e| e.to_string())?; packet.write(&mut buf).map_err(|e| e.to_string())?; if buf.len() > MAXIMUM_UNCOMPRESSED_LENGTH as usize { return Err(format!( "Packet too big (is {} bytes, should be less than {}): {:?}", buf.len(), MAXIMUM_UNCOMPRESSED_LENGTH, packet )); } Ok(buf) } async fn compression_encoder(data: &[u8], compression_threshold: u32) -> Result, String> { let n = data.len(); // if it's less than the compression threshold, don't compress if n < compression_threshold as usize { let mut buf = Vec::new(); buf.write_varint(0).map_err(|e| e.to_string())?; buf.write_all(data).await.map_err(|e| e.to_string())?; Ok(buf) } else { // otherwise, compress let mut deflater = ZlibEncoder::new(data); // write deflated data to buf let mut buf = Vec::new(); deflater .read_to_end(&mut buf) .await .map_err(|e| e.to_string())?; Ok(buf) } } pub async fn write_packet( packet: P, stream: &mut W, compression_threshold: Option, cipher: &mut Option, ) where P: ProtocolPacket + Debug, W: AsyncWrite + Unpin + Send, { let mut buf = packet_encoder(&packet).unwrap(); if let Some(threshold) = compression_threshold { buf = compression_encoder(&buf, threshold).await.unwrap(); } buf = frame_prepender(&mut buf).unwrap(); // if we were given a cipher, encrypt the packet if let Some(cipher) = cipher { azalea_crypto::encrypt_packet(cipher, &mut buf); } stream.write_all(&buf).await.unwrap(); }