Skip to content

Commit

Permalink
Less heap allocations
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Dec 10, 2024
1 parent bab92b3 commit bd8bac1
Show file tree
Hide file tree
Showing 14 changed files with 50 additions and 72 deletions.
8 changes: 3 additions & 5 deletions pumpkin-core/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl serde::Serialize for TextComponent<'_> {
where
S: serde::Serializer,
{
serializer.serialize_bytes(self.encode().as_slice())
serializer.serialize_bytes(&self.encode())
}
}

Expand Down Expand Up @@ -181,7 +181,7 @@ impl<'a> TextComponent<'a> {
self
}

pub fn encode(&self) -> Vec<u8> {
pub fn encode(&self) -> bytes::BytesMut {
// TODO: Somehow fix this ugly mess
#[derive(serde::Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -215,9 +215,7 @@ impl<'a> TextComponent<'a> {
// dbg!(pumpkin_nbt::serializer::to_bytes_unnamed(&astruct).unwrap().to_vec());

// TODO
pumpkin_nbt::serializer::to_bytes_unnamed(&astruct)
.unwrap()
.to_vec()
pumpkin_nbt::serializer::to_bytes_unnamed(&astruct).unwrap()
}
}

Expand Down
4 changes: 2 additions & 2 deletions pumpkin-protocol/src/client/play/c_boss_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl ClientPacket for CBossEvent<'_> {
flags,
} => {
bytebuf.put_var_int(&VarInt::from(0u8));
bytebuf.put_slice(title.encode().as_slice());
bytebuf.put_slice(&title.encode());
bytebuf.put_f32(*health);
bytebuf.put_var_int(color);
bytebuf.put_var_int(division);
Expand All @@ -43,7 +43,7 @@ impl ClientPacket for CBossEvent<'_> {
}
BosseventAction::UpdateTile(title) => {
bytebuf.put_var_int(&VarInt::from(3u8));
bytebuf.put_slice(title.encode().as_slice());
bytebuf.put_slice(&title.encode());
}
BosseventAction::UpdateStyle { color, dividers } => {
bytebuf.put_var_int(&VarInt::from(4u8));
Expand Down
14 changes: 7 additions & 7 deletions pumpkin-protocol/src/packet_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ impl PacketDecoder {
pub fn decode(&mut self) -> Result<Option<RawPacket>, PacketDecodeError> {
let mut r = &self.buf[..];

let packet_len = match VarInt::decode_partial(&mut r) {
let packet_len = match VarInt::decode(&mut r) {
Ok(len) => len,
Err(VarIntDecodeError::Incomplete) => return Ok(None),
Err(VarIntDecodeError::TooLarge) => Err(PacketDecodeError::MalformedLength)?,
};
let packet_len = packet_len.0;

if !(0..=MAX_PACKET_SIZE).contains(&packet_len) {
Err(PacketDecodeError::OutOfBounds)?
Expand Down Expand Up @@ -222,11 +223,9 @@ mod tests {
}

/// Helper function to encrypt data using AES-128 CFB-8 mode
fn encrypt_aes128(data: &[u8], key: &[u8; 16], iv: &[u8; 16]) -> Vec<u8> {
fn encrypt_aes128(mut data: &mut [u8], key: &[u8; 16], iv: &[u8; 16]) {
let encryptor = Cfb8Encryptor::<Aes128>::new_from_slices(key, iv).expect("Invalid key/iv");
let mut encrypted = data.to_vec();
encryptor.encrypt(&mut encrypted);
encrypted
encryptor.encrypt(&mut data);
}

/// Helper function to build a packet with optional compression and encryption
Expand Down Expand Up @@ -274,7 +273,8 @@ mod tests {

// Encrypt if key and iv are provided
if let (Some(k), Some(v)) = (key, iv) {
encrypt_aes128(&packet, k, v)
encrypt_aes128(&mut packet, k, v);
packet
} else {
packet
}
Expand Down Expand Up @@ -416,7 +416,7 @@ mod tests {
packet_buffer.put_var_int(&packet_len_varint);
packet_buffer.put_slice(buffer.buf());

let packet_bytes = packet_buffer.buf().to_vec();
let packet_bytes = packet_buffer.buf();

// Initialize the decoder with compression enabled
let mut decoder = PacketDecoder::default();
Expand Down
25 changes: 12 additions & 13 deletions pumpkin-protocol/src/packet_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ impl Default for PacketEncoder {
impl PacketEncoder {
pub fn append_packet<P: ClientPacket>(&mut self, packet: &P) -> Result<(), PacketEncodeError> {
let start_len = self.buf.len();

let mut packet_buf = ByteBuffer::empty();
// Write the Packet ID first
VarInt(P::PACKET_ID).encode(&mut self.buf);
let mut packet_buf = ByteBuffer::empty();
// Now write the packet into an empty buffer
packet.write(&mut packet_buf);

self.buf.put(packet_buf.buf());

let data_len = self.buf.len() - start_len;
Expand Down Expand Up @@ -229,11 +229,9 @@ mod tests {
}

/// Helper function to decrypt data using AES-128 CFB-8 mode
fn decrypt_aes128(encrypted_data: &[u8], key: &[u8; 16], iv: &[u8; 16]) -> Vec<u8> {
fn decrypt_aes128(mut encrypted_data: &mut [u8], key: &[u8; 16], iv: &[u8; 16]) {
let decryptor = Cfb8Decryptor::<Aes128>::new_from_slices(key, iv).expect("Invalid key/iv");
let mut decrypted = encrypted_data.to_vec();
decryptor.decrypt(&mut decrypted);
decrypted
decryptor.decrypt(&mut encrypted_data);
}

/// Helper function to build a packet with optional compression and encryption
Expand Down Expand Up @@ -356,13 +354,13 @@ mod tests {
let key = [0x00u8; 16]; // Example key

// Build the packet with encryption enabled (no compression)
let packet_bytes = build_packet_with_encoder(&packet, None, Some(&key));
let mut packet_bytes = build_packet_with_encoder(&packet, None, Some(&key));

// Decrypt the packet
let decrypted_packet = decrypt_aes128(&packet_bytes, &key, &key);
decrypt_aes128(&mut packet_bytes, &key, &key);

// Decode the packet manually to verify correctness
let mut buffer = &decrypted_packet[..];
let mut buffer = &packet_bytes[..];

// Read packet length VarInt
let packet_length = decode_varint(&mut buffer).expect("Failed to decode packet length");
Expand Down Expand Up @@ -399,13 +397,14 @@ mod tests {
let key = [0x01u8; 16]; // Example key

// Build the packet with both compression and encryption enabled
let packet_bytes = build_packet_with_encoder(&packet, Some(compression_info), Some(&key));
let mut packet_bytes =
build_packet_with_encoder(&packet, Some(compression_info), Some(&key));

// Decrypt the packet
let decrypted_packet = decrypt_aes128(&packet_bytes, &key, &key);
decrypt_aes128(&mut packet_bytes, &key, &key);

// Decode the packet manually to verify correctness
let mut buffer = &decrypted_packet[..];
let mut buffer = &packet_bytes[..];

// Read packet length VarInt
let packet_length = decode_varint(&mut buffer).expect("Failed to decode packet length");
Expand Down
4 changes: 2 additions & 2 deletions pumpkin-protocol/src/server/config/s_cookie_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct SCookieResponse {
pub key: Identifier,
pub has_payload: bool,
pub payload_length: Option<VarInt>,
pub payload: Option<Vec<u8>>, // 5120,
pub payload: Option<bytes::Bytes>, // 5120,
}

const MAX_PAYLOAD_SIZE: i32 = 5120;
Expand Down Expand Up @@ -39,7 +39,7 @@ impl ServerPacket for SCookieResponse {
));
}

let payload = bytebuf.copy_to_bytes(length as usize)?.to_vec();
let payload = bytebuf.copy_to_bytes(length as usize)?;

Ok(Self {
key,
Expand Down
4 changes: 2 additions & 2 deletions pumpkin-protocol/src/server/config/s_plugin_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use crate::{
#[server_packet("config:custom_payload")]
pub struct SPluginMessage {
pub channel: Identifier,
pub data: Vec<u8>,
pub data: bytes::BytesMut,
}

impl ServerPacket for SPluginMessage {
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
Ok(Self {
channel: bytebuf.get_string()?,
data: bytebuf.get_slice().to_vec(),
data: bytebuf.get_slice(),
})
}
}
4 changes: 2 additions & 2 deletions pumpkin-protocol/src/server/login/s_cookie_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct SCookieResponse {
pub key: Identifier,
pub has_payload: bool,
pub payload_length: Option<VarInt>,
pub payload: Option<Vec<u8>>, // 5120,
pub payload: Option<bytes::Bytes>, // 5120,
}

const MAX_PAYLOAD_SIZE: i32 = 5120;
Expand Down Expand Up @@ -38,7 +38,7 @@ impl ServerPacket for SCookieResponse {
));
}

let payload = bytebuf.copy_to_bytes(length as usize)?.to_vec();
let payload = bytebuf.copy_to_bytes(length as usize)?;

Ok(Self {
key,
Expand Down
8 changes: 4 additions & 4 deletions pumpkin-protocol/src/server/login/s_encryption_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use crate::{
#[server_packet("login:key")]
pub struct SEncryptionResponse {
pub shared_secret_length: VarInt,
pub shared_secret: Vec<u8>,
pub shared_secret: bytes::Bytes,
pub verify_token_length: VarInt,
pub verify_token: Vec<u8>,
pub verify_token: bytes::Bytes,
}

impl ServerPacket for SEncryptionResponse {
Expand All @@ -21,9 +21,9 @@ impl ServerPacket for SEncryptionResponse {
let verify_token = bytebuf.copy_to_bytes(shared_secret_length.0 as usize)?;
Ok(Self {
shared_secret_length,
shared_secret: shared_secret.to_vec(),
shared_secret,
verify_token_length,
verify_token: verify_token.to_vec(),
verify_token,
})
}
}
4 changes: 2 additions & 2 deletions pumpkin-protocol/src/server/play/s_cookie_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub struct SCookieResponse {
pub key: Identifier,
pub has_payload: bool,
pub payload_length: Option<VarInt>,
pub payload: Option<Vec<u8>>, // 5120,
pub payload: Option<bytes::Bytes>, // 5120,
}

const MAX_PAYLOAD_SIZE: i32 = 5120;
Expand Down Expand Up @@ -38,7 +38,7 @@ impl ServerPacket for SCookieResponse {
));
}

let payload = bytebuf.copy_to_bytes(length as usize)?.to_vec();
let payload = bytebuf.copy_to_bytes(length as usize)?;

Ok(Self {
key,
Expand Down
29 changes: 5 additions & 24 deletions pumpkin-protocol/src/var_int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ use crate::VarIntType;
pub struct VarInt(pub VarIntType);

impl VarInt {
/// The maximum number of bytes a `VarInt` could occupy when read from and
/// written to the Minecraft protocol.
/// The maximum number of bytes a `VarInt`
pub const MAX_SIZE: usize = 5;

/// Returns the exact number of bytes this varint will write when
Expand All @@ -20,30 +19,12 @@ impl VarInt {
}
}

pub fn decode_partial(r: &mut impl Buf) -> Result<i32, VarIntDecodeError> {
let mut val = 0;
for i in 0..Self::MAX_SIZE {
if !r.has_remaining() {
return Err(VarIntDecodeError::Incomplete);
}
let byte = r.get_u8();
val |= (i32::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(val);
}
}
Err(VarIntDecodeError::TooLarge)
}

pub fn encode(&self, w: &mut impl BufMut) {
let mut val = self.0;
for _ in 0..Self::MAX_SIZE {
let mut b: u8 = val as u8 & 0b01111111;
let b: u8 = val as u8 & 0b01111111;
val >>= 7;
if val != 0 {
b |= 0b10000000;
}
w.put_u8(b);
w.put_u8(if val == 0 { b } else { b | 0b10000000 });
if val == 0 {
break;
}
Expand All @@ -57,8 +38,8 @@ impl VarInt {
return Err(VarIntDecodeError::Incomplete);
}
let byte = r.get_u8();
val |= (i32::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 {
return Ok(VarInt(val));
}
}
Expand Down
5 changes: 2 additions & 3 deletions pumpkin-protocol/src/var_long.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ use crate::VarLongType;
pub struct VarLong(pub VarLongType);

impl VarLong {
/// The maximum number of bytes a `VarInt` could occupy when read from and
/// written to the Minecraft protocol.
/// The maximum number of bytes a `VarLong`
pub const MAX_SIZE: usize = 10;

/// Returns the exact number of bytes this varint will write when
/// Returns the exact number of bytes this varlong will write when
/// [`Encode::encode`] is called, assuming no error occurs.
pub const fn written_size(self) -> usize {
match self.0 {
Expand Down
2 changes: 1 addition & 1 deletion pumpkin-world/src/chunk/anvil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl ChunkReader for AnvilChunkReader {
.decompress_data(chunk_data)
.map_err(ChunkReadingError::Compression)?;

ChunkData::from_bytes(decompressed_chunk, *at).map_err(ChunkReadingError::ParsingError)
ChunkData::from_bytes(&decompressed_chunk, *at).map_err(ChunkReadingError::ParsingError)
}
}

Expand Down
6 changes: 3 additions & 3 deletions pumpkin-world/src/chunk/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,15 @@ impl Index<ChunkRelativeBlockCoordinates> for ChunkBlocks {
}

impl ChunkData {
pub fn from_bytes(chunk_data: Vec<u8>, at: Vector2<i32>) -> Result<Self, ChunkParsingError> {
if fastnbt::from_bytes::<ChunkStatus>(&chunk_data)
pub fn from_bytes(chunk_data: &[u8], at: Vector2<i32>) -> Result<Self, ChunkParsingError> {
if fastnbt::from_bytes::<ChunkStatus>(chunk_data)
.map_err(|_| ChunkParsingError::FailedReadStatus)?
!= ChunkStatus::Full
{
return Err(ChunkParsingError::ChunkNotGenerated);
}

let chunk_data = fastnbt::from_bytes::<ChunkNbt>(chunk_data.as_slice())
let chunk_data = fastnbt::from_bytes::<ChunkNbt>(chunk_data)
.map_err(|e| ChunkParsingError::ErrorDeserializingChunk(e.to_string()))?;

// this needs to be boxed, otherwise it will cause a stack-overflow
Expand Down
5 changes: 3 additions & 2 deletions pumpkin/src/client/client_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
},
server::{Server, CURRENT_MC_VERSION},
};
use core::str;
use num_traits::FromPrimitive;
use pumpkin_config::{ADVANCED_CONFIG, BASIC_CONFIG};
use pumpkin_core::text::TextComponent;
Expand Down Expand Up @@ -412,8 +413,8 @@ impl Client {
|| plugin_message.channel.starts_with("MC|Brand")
{
log::debug!("got a client brand");
match String::from_utf8(plugin_message.data) {
Ok(brand) => *self.brand.lock().await = Some(brand),
match str::from_utf8(&plugin_message.data) {
Ok(brand) => *self.brand.lock().await = Some(brand.to_string()),
Err(e) => self.kick(&e.to_string()).await,
}
}
Expand Down

0 comments on commit bd8bac1

Please sign in to comment.