pumpkin-protocol: remove pumpkin-config
This commit is contained in:
parent
d833582c7b
commit
a0339728c7
@ -12,7 +12,6 @@ query = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pumpkin-nbt = { path = "../pumpkin-nbt" }
|
pumpkin-nbt = { path = "../pumpkin-nbt" }
|
||||||
pumpkin-config = { path = "../pumpkin-config" }
|
|
||||||
pumpkin-macros = { path = "../pumpkin-macros" }
|
pumpkin-macros = { path = "../pumpkin-macros" }
|
||||||
pumpkin-world = { path = "../pumpkin-world" }
|
pumpkin-world = { path = "../pumpkin-world" }
|
||||||
pumpkin-core = { path = "../pumpkin-core" }
|
pumpkin-core = { path = "../pumpkin-core" }
|
||||||
|
|||||||
@ -25,6 +25,21 @@ pub const MAX_PACKET_SIZE: i32 = 2097152;
|
|||||||
|
|
||||||
pub type FixedBitSet = bytes::Bytes;
|
pub type FixedBitSet = bytes::Bytes;
|
||||||
|
|
||||||
|
/// Represents a compression threshold.
|
||||||
|
///
|
||||||
|
/// The threshold determines the minimum size of data that should be compressed.
|
||||||
|
/// Data smaller than the threshold will not be compressed.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct CompressionThreshold(pub u32);
|
||||||
|
|
||||||
|
/// Represents a compression level.
|
||||||
|
///
|
||||||
|
/// The level controls the amount of compression applied to the data.
|
||||||
|
/// Higher levels generally result in higher compression ratios but also
|
||||||
|
/// increase CPU usage.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct CompressionLevel(pub u32);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum ConnectionState {
|
pub enum ConnectionState {
|
||||||
HandShake,
|
HandShake,
|
||||||
|
|||||||
@ -17,8 +17,7 @@ pub struct PacketDecoder {
|
|||||||
buf: BytesMut,
|
buf: BytesMut,
|
||||||
decompress_buf: BytesMut,
|
decompress_buf: BytesMut,
|
||||||
cipher: Option<Cipher>,
|
cipher: Option<Cipher>,
|
||||||
compression: bool,
|
decompressor: Option<Decompressor>,
|
||||||
decompressor: Decompressor,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manual implementation of Default trait for PacketDecoder
|
// Manual implementation of Default trait for PacketDecoder
|
||||||
@ -29,8 +28,7 @@ impl Default for PacketDecoder {
|
|||||||
buf: BytesMut::new(),
|
buf: BytesMut::new(),
|
||||||
decompress_buf: BytesMut::new(),
|
decompress_buf: BytesMut::new(),
|
||||||
cipher: None,
|
cipher: None,
|
||||||
compression: false,
|
decompressor: None,
|
||||||
decompressor: Decompressor::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,7 +56,7 @@ impl PacketDecoder {
|
|||||||
let packet_len_len = VarInt(packet_len).written_size();
|
let packet_len_len = VarInt(packet_len).written_size();
|
||||||
|
|
||||||
let mut data;
|
let mut data;
|
||||||
if self.compression {
|
if let Some(decompressor) = &mut self.decompressor {
|
||||||
r = &r[..packet_len as usize];
|
r = &r[..packet_len as usize];
|
||||||
|
|
||||||
let data_len = VarInt::decode(&mut r)
|
let data_len = VarInt::decode(&mut r)
|
||||||
@ -77,8 +75,7 @@ impl PacketDecoder {
|
|||||||
self.decompress_buf.resize(data_len as usize, 0);
|
self.decompress_buf.resize(data_len as usize, 0);
|
||||||
|
|
||||||
// Perform decompression using libdeflater
|
// Perform decompression using libdeflater
|
||||||
let decompressed_size = self
|
let decompressed_size = decompressor
|
||||||
.decompressor
|
|
||||||
.zlib_decompress(r, &mut self.decompress_buf)
|
.zlib_decompress(r, &mut self.decompress_buf)
|
||||||
.map_err(PacketDecodeError::from)?;
|
.map_err(PacketDecodeError::from)?;
|
||||||
|
|
||||||
@ -135,7 +132,11 @@ impl PacketDecoder {
|
|||||||
|
|
||||||
/// Sets ZLib Decompression
|
/// Sets ZLib Decompression
|
||||||
pub fn set_compression(&mut self, compression: bool) {
|
pub fn set_compression(&mut self, compression: bool) {
|
||||||
self.compression = compression;
|
if compression {
|
||||||
|
self.decompressor = Some(Decompressor::new());
|
||||||
|
} else {
|
||||||
|
self.decompressor = None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrypt_bytes(cipher: &mut Cipher, bytes: &mut [u8]) {
|
fn decrypt_bytes(cipher: &mut Cipher, bytes: &mut [u8]) {
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
|
use aes::cipher::{generic_array::GenericArray, BlockEncryptMut, BlockSizeUser, KeyIvInit};
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use pumpkin_config::compression::CompressionInfo;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use libdeflater::{CompressionLvl, Compressor};
|
use libdeflater::{CompressionLvl, Compressor};
|
||||||
|
|
||||||
use crate::{codec::Codec, ClientPacket, VarInt, MAX_PACKET_SIZE};
|
use crate::{
|
||||||
|
codec::Codec, ClientPacket, CompressionLevel, CompressionThreshold, VarInt, MAX_PACKET_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
type Cipher = cfb8::Encryptor<aes::Aes128>;
|
type Cipher = cfb8::Encryptor<aes::Aes128>;
|
||||||
|
|
||||||
@ -16,8 +17,8 @@ pub struct PacketEncoder {
|
|||||||
buf: BytesMut,
|
buf: BytesMut,
|
||||||
compress_buf: Vec<u8>,
|
compress_buf: Vec<u8>,
|
||||||
cipher: Option<Cipher>,
|
cipher: Option<Cipher>,
|
||||||
compression_threshold: Option<u32>,
|
// compression and compression threshold
|
||||||
compressor: Compressor, // Reuse the compressor for all packets
|
compression: Option<(Compressor, CompressionThreshold)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manual implementation of Default trait for PacketEncoder
|
// Manual implementation of Default trait for PacketEncoder
|
||||||
@ -28,8 +29,7 @@ impl Default for PacketEncoder {
|
|||||||
buf: BytesMut::with_capacity(1024),
|
buf: BytesMut::with_capacity(1024),
|
||||||
compress_buf: Vec::with_capacity(1024),
|
compress_buf: Vec::with_capacity(1024),
|
||||||
cipher: None,
|
cipher: None,
|
||||||
compression_threshold: None,
|
compression: None, // init compressor with fastest compression level
|
||||||
compressor: Compressor::new(CompressionLvl::fastest()), // init compressor with fastest compression level
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,8 +73,8 @@ impl PacketEncoder {
|
|||||||
packet.write(&mut self.buf);
|
packet.write(&mut self.buf);
|
||||||
let data_len = self.buf.len() - start_len;
|
let data_len = self.buf.len() - start_len;
|
||||||
|
|
||||||
if let Some(compression_threshold) = self.compression_threshold {
|
if let Some((compressor, compression_threshold)) = &mut self.compression {
|
||||||
if data_len > compression_threshold as usize {
|
if data_len > compression_threshold.0 as usize {
|
||||||
// Get the data to compress
|
// Get the data to compress
|
||||||
let data_to_compress = &self.buf[start_len..];
|
let data_to_compress = &self.buf[start_len..];
|
||||||
|
|
||||||
@ -82,15 +82,13 @@ impl PacketEncoder {
|
|||||||
self.compress_buf.clear();
|
self.compress_buf.clear();
|
||||||
|
|
||||||
// Compute the maximum size of compressed data
|
// Compute the maximum size of compressed data
|
||||||
let max_compressed_size =
|
let max_compressed_size = compressor.zlib_compress_bound(data_to_compress.len());
|
||||||
self.compressor.zlib_compress_bound(data_to_compress.len());
|
|
||||||
|
|
||||||
// Ensure compress_buf has enough capacity
|
// Ensure compress_buf has enough capacity
|
||||||
self.compress_buf.resize(max_compressed_size, 0);
|
self.compress_buf.resize(max_compressed_size, 0);
|
||||||
|
|
||||||
// Compress the data
|
// Compress the data
|
||||||
let compressed_size = self
|
let compressed_size = compressor
|
||||||
.compressor
|
|
||||||
.zlib_compress(data_to_compress, &mut self.compress_buf)
|
.zlib_compress(data_to_compress, &mut self.compress_buf)
|
||||||
.map_err(|e| PacketEncodeError::CompressionFailed(e.to_string()))?;
|
.map_err(|e| PacketEncodeError::CompressionFailed(e.to_string()))?;
|
||||||
|
|
||||||
@ -166,26 +164,30 @@ impl PacketEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables or disables Zlib compression with the given options.
|
/// Enables or disables Zlib compression.
|
||||||
///
|
///
|
||||||
/// If `compression` is `Some`, compression is enabled with the provided
|
/// If `compression` is `Some`, compression is enabled with the given `threshold`
|
||||||
/// options. If `compression` is `None`, compression is disabled.
|
/// for triggering compression and the specified `level`. If `compression` is
|
||||||
pub fn set_compression(&mut self, compression: Option<CompressionInfo>) {
|
/// `None`, compression is disabled.
|
||||||
// Reset the compressor with the new compression level
|
///
|
||||||
if let Some(compression) = &compression {
|
/// # Errors
|
||||||
self.compression_threshold = Some(compression.threshold);
|
///
|
||||||
let compression_level = compression.level as i32;
|
/// Returns an `CompressionLevelError` if an invalid compression level is provided.
|
||||||
let level = match CompressionLvl::new(compression_level) {
|
pub fn set_compression(
|
||||||
Ok(level) => level,
|
&mut self,
|
||||||
Err(error) => {
|
compression: Option<(CompressionThreshold, CompressionLevel)>,
|
||||||
log::error!("Invalid compression level {:?}", error);
|
) -> Result<(), CompressionLevelError> {
|
||||||
return;
|
match compression {
|
||||||
}
|
Some((threshold, level)) => {
|
||||||
};
|
let level =
|
||||||
self.compressor = Compressor::new(level);
|
CompressionLvl::new(level.0 as i32).map_err(|_| CompressionLevelError)?;
|
||||||
} else {
|
self.compression = Some((Compressor::new(level), threshold));
|
||||||
self.compression_threshold = None;
|
}
|
||||||
|
None => {
|
||||||
|
self.compression = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypts the data in the internal buffer and returns it as a `BytesMut`.
|
/// Encrypts the data in the internal buffer and returns it as a `BytesMut`.
|
||||||
@ -209,6 +211,10 @@ impl PacketEncoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
#[error("Invalid compression Level")]
|
||||||
|
pub struct CompressionLevelError;
|
||||||
|
|
||||||
/// Errors that can occur during packet encoding.
|
/// Errors that can occur during packet encoding.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum PacketEncodeError {
|
pub enum PacketEncodeError {
|
||||||
@ -268,15 +274,15 @@ mod tests {
|
|||||||
/// Helper function to build a packet with optional compression and encryption
|
/// Helper function to build a packet with optional compression and encryption
|
||||||
fn build_packet_with_encoder<T: ClientPacket>(
|
fn build_packet_with_encoder<T: ClientPacket>(
|
||||||
packet: &T,
|
packet: &T,
|
||||||
compression_info: Option<CompressionInfo>,
|
compression_info: Option<(CompressionThreshold, CompressionLevel)>,
|
||||||
key: Option<&[u8; 16]>,
|
key: Option<&[u8; 16]>,
|
||||||
) -> BytesMut {
|
) -> BytesMut {
|
||||||
let mut encoder = PacketEncoder::default();
|
let mut encoder = PacketEncoder::default();
|
||||||
|
|
||||||
if let Some(compression) = compression_info {
|
if let Some(compression) = compression_info {
|
||||||
encoder.set_compression(Some(compression));
|
encoder.set_compression(Some(compression)).unwrap();
|
||||||
} else {
|
} else {
|
||||||
encoder.set_compression(None);
|
encoder.set_compression(None).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(key) = key {
|
if let Some(key) = key {
|
||||||
@ -328,14 +334,12 @@ mod tests {
|
|||||||
// Create a CStatusResponse packet
|
// Create a CStatusResponse packet
|
||||||
let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}");
|
let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}");
|
||||||
|
|
||||||
// Compression threshold is set to 0 to force compression
|
|
||||||
let compression_info = CompressionInfo {
|
|
||||||
threshold: 0,
|
|
||||||
level: 6, // Standard compression level
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build the packet with compression enabled
|
// Build the packet with compression enabled
|
||||||
let packet_bytes = build_packet_with_encoder(&packet, Some(compression_info), None);
|
let packet_bytes = build_packet_with_encoder(
|
||||||
|
&packet,
|
||||||
|
Some((CompressionThreshold(0), CompressionLevel(6))),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
// Decode the packet manually to verify correctness
|
// Decode the packet manually to verify correctness
|
||||||
let mut buffer = &packet_bytes[..];
|
let mut buffer = &packet_bytes[..];
|
||||||
@ -418,18 +422,16 @@ mod tests {
|
|||||||
// Create a CStatusResponse packet
|
// Create a CStatusResponse packet
|
||||||
let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}");
|
let packet = CStatusResponse::new("{\"description\": \"A Minecraft Server\"}");
|
||||||
|
|
||||||
// Compression threshold is set to 0 to force compression
|
|
||||||
let compression_info = CompressionInfo {
|
|
||||||
threshold: 0,
|
|
||||||
level: 6, // Standard compression level
|
|
||||||
};
|
|
||||||
|
|
||||||
// Encryption key and IV (IV is the same as key in this case)
|
// Encryption key and IV (IV is the same as key in this case)
|
||||||
let key = [0x01u8; 16]; // Example key
|
let key = [0x01u8; 16]; // Example key
|
||||||
|
|
||||||
// Build the packet with both compression and encryption enabled
|
// Build the packet with both compression and encryption enabled
|
||||||
let mut packet_bytes =
|
// Compression threshold is set to 0 to force compression
|
||||||
build_packet_with_encoder(&packet, Some(compression_info), Some(&key));
|
let mut packet_bytes = build_packet_with_encoder(
|
||||||
|
&packet,
|
||||||
|
Some((CompressionThreshold(0), CompressionLevel(6))),
|
||||||
|
Some(&key),
|
||||||
|
);
|
||||||
|
|
||||||
// Decrypt the packet
|
// Decrypt the packet
|
||||||
decrypt_aes128(&mut packet_bytes, &key, &key);
|
decrypt_aes128(&mut packet_bytes, &key, &key);
|
||||||
@ -567,14 +569,13 @@ mod tests {
|
|||||||
// Create a CStatusResponse packet with small payload
|
// Create a CStatusResponse packet with small payload
|
||||||
let packet = CStatusResponse::new("Hi");
|
let packet = CStatusResponse::new("Hi");
|
||||||
|
|
||||||
// Compression threshold is set to a value higher than payload length
|
|
||||||
let compression_info = CompressionInfo {
|
|
||||||
threshold: 10,
|
|
||||||
level: 6, // Standard compression level
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build the packet with compression enabled
|
// Build the packet with compression enabled
|
||||||
let packet_bytes = build_packet_with_encoder(&packet, Some(compression_info), None);
|
// Compression threshold is set to a value higher than payload length
|
||||||
|
let packet_bytes = build_packet_with_encoder(
|
||||||
|
&packet,
|
||||||
|
Some((CompressionThreshold(10), CompressionLevel(6))),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
// Decode the packet manually to verify that it was not compressed
|
// Decode the packet manually to verify that it was not compressed
|
||||||
let mut buffer = &packet_bytes[..];
|
let mut buffer = &packet_bytes[..];
|
||||||
|
|||||||
@ -33,7 +33,8 @@ use pumpkin_protocol::{
|
|||||||
},
|
},
|
||||||
status::{SStatusPingRequest, SStatusRequest},
|
status::{SStatusPingRequest, SStatusRequest},
|
||||||
},
|
},
|
||||||
ClientPacket, ConnectionState, Property, RawPacket, ServerPacket,
|
ClientPacket, CompressionLevel, CompressionThreshold, ConnectionState, Property, RawPacket,
|
||||||
|
ServerPacket,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sha1::Digest;
|
use sha1::Digest;
|
||||||
@ -224,7 +225,13 @@ impl Client {
|
|||||||
/// * `compression`: An optional `CompressionInfo` struct containing the compression threshold and compression level.
|
/// * `compression`: An optional `CompressionInfo` struct containing the compression threshold and compression level.
|
||||||
pub async fn set_compression(&self, compression: Option<CompressionInfo>) {
|
pub async fn set_compression(&self, compression: Option<CompressionInfo>) {
|
||||||
self.dec.lock().await.set_compression(compression.is_some());
|
self.dec.lock().await.set_compression(compression.is_some());
|
||||||
self.enc.lock().await.set_compression(compression);
|
self.enc
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.set_compression(
|
||||||
|
compression.map(|s| (CompressionThreshold(s.threshold), CompressionLevel(s.level))),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|_| log::warn!("invalid compression level"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends a clientbound packet to the connected client.
|
/// Sends a clientbound packet to the connected client.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user