Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

📝 Add documentation to packet_falcon_core #24

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/logic/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::time::Duration;
use bytes::Bytes;
use falcon_core::network::{ConnectionState, PacketHandlerState, UNKNOWN_PROTOCOL};
use falcon_core::ShutdownHandle;
use falcon_packet_core::special::PacketPrepare;
use falcon_packet_core::{ReadError, WriteError};
use ignore_result::Ignore;
use mc_chat::ChatComponent;
Expand Down
84 changes: 37 additions & 47 deletions crates/logic/src/connection/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,43 +35,6 @@ impl SocketWrite {
}
}

pub fn finish(&mut self) {
if self.ready_pos == self.output_buffer.len() {
return;
}

self.flush();

if self.compression_threshold >= 0 {
if self.next_is_compressed {
let offset = VarI32::from(self.compression.total_in() as usize).size();
let overall_len = self.next_len_size - offset;
write_fixed_varint((self.output_buffer.len() - self.ready_pos - overall_len) as i32, overall_len, &mut self.output_buffer[self.ready_pos..]);
write_fixed_varint(self.compression.total_in() as i32, offset, &mut self.output_buffer[self.ready_pos + overall_len..]);
} else {
let overall_len = self.next_len_size - 1;
write_fixed_varint((self.output_buffer.len() - self.ready_pos - overall_len) as i32, overall_len, &mut self.output_buffer[self.ready_pos..]);
}
} else {
let overall_len = self.next_len_size;
write_fixed_varint((self.output_buffer.len() - self.ready_pos - overall_len) as i32, self.next_len_size, &mut self.output_buffer[self.ready_pos..]);
}

// TODO: do encryption

self.compression.reset();
self.ready_pos = self.output_buffer.len();

if self.output_buffer.len() < COMPRESSION_BUFFER_LEN {
let capacity = self.output_buffer.capacity();
if capacity > COMPRESSION_BUFFER_LEN && capacity > 3 * self.output_buffer.len() {
let new_buffer = BytesMut::with_capacity(COMPRESSION_BUFFER_LEN);
let old_buffer = std::mem::replace(&mut self.output_buffer, new_buffer);
self.output_buffer.put(old_buffer);
}
}
}

fn flush(&mut self) {
self.write_all();
self.compression_position = 0;
Expand Down Expand Up @@ -154,16 +117,6 @@ fn write_fixed_varint(mut value: i32, size: usize, buf: &mut [u8]) {
}

impl PacketPrepare for SocketWrite {
/// # Important
/// This function optimizes allocations by assuming
/// a single call to this function spans an entire packet.
/// This is important because this is the function that determins
/// whether a packet gets compressed or not. It is also used
/// for marking the start of a new packet. Depending on
/// this, it may allocate up to 3-9 bytes extra.
///
/// As a result of the above, the packet should be written to
/// this writer immediately after calling this.
fn prepare(&mut self, additional: usize) {
let len_size = VarI32::from(additional).size();
let mut capacity = additional;
Expand All @@ -183,6 +136,43 @@ impl PacketPrepare for SocketWrite {
self.output_buffer.reserve(capacity + self.next_len_size);
self.output_buffer.put_bytes(0, self.next_len_size);
}

fn finish(&mut self) {
if self.ready_pos == self.output_buffer.len() {
return;
}

self.flush();

if self.compression_threshold >= 0 {
if self.next_is_compressed {
let offset = VarI32::from(self.compression.total_in() as usize).size();
let overall_len = self.next_len_size - offset;
write_fixed_varint((self.output_buffer.len() - self.ready_pos - overall_len) as i32, overall_len, &mut self.output_buffer[self.ready_pos..]);
write_fixed_varint(self.compression.total_in() as i32, offset, &mut self.output_buffer[self.ready_pos + overall_len..]);
} else {
let overall_len = self.next_len_size - 1;
write_fixed_varint((self.output_buffer.len() - self.ready_pos - overall_len) as i32, overall_len, &mut self.output_buffer[self.ready_pos..]);
}
} else {
let overall_len = self.next_len_size;
write_fixed_varint((self.output_buffer.len() - self.ready_pos - overall_len) as i32, self.next_len_size, &mut self.output_buffer[self.ready_pos..]);
}

// TODO: do encryption

self.compression.reset();
self.ready_pos = self.output_buffer.len();

if self.output_buffer.len() < COMPRESSION_BUFFER_LEN {
let capacity = self.output_buffer.capacity();
if capacity > COMPRESSION_BUFFER_LEN && capacity > 3 * self.output_buffer.len() {
let new_buffer = BytesMut::with_capacity(COMPRESSION_BUFFER_LEN);
let old_buffer = std::mem::replace(&mut self.output_buffer, new_buffer);
self.output_buffer.put(old_buffer);
}
}
}
}

// TODO: explain unsafe code
Expand Down
3 changes: 3 additions & 0 deletions crates/packet_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,6 @@ thiserror = "1.0.32"

uuid = "1.1.2"
fastnbt = "2.3.2"

[dev-dependencies]
pretty_assertions = "1.3.0"
27 changes: 27 additions & 0 deletions crates/packet_core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,55 @@ use std::string::FromUtf8Error;

use thiserror::Error;

/// Errors that can occur when writing types to a minecraft connection using
/// [`PacketWrite`](super::PacketWrite) or
/// [`PacketWriteSeed`](super::PacketWriteSeed).
#[derive(Debug, Error)]
pub enum WriteError {
/// Returned when a string was longer than the maximum length allowed by the
/// protocol.
///
/// The first argument is what was attempted to write, the
/// second argument is the maximum length.
#[error("String was longer than allowed: {1} > {0}")]
StringTooLong(usize, usize),
/// Returned by [`fastnbt`](fastnbt).
#[error("Couldn't serialize to NBT")]
FastNbtError(#[from] fastnbt::error::Error),
/// Returned when there is unsufficient space in the supplied
/// [`BufMut`](bytes::BufMut).
#[error("Buffer ran out of space")]
EndOfBuffer,
}

/// Errors that can occur when reading types from a minecraft connection using
/// [`PacketRead`](super::PacketRead) or
/// [`PacketReadSeed`](super::PacketReadSeed).
#[derive(Debug, Error)]
pub enum ReadError {
/// Returned when parsing UTF-8 fails.
#[error("Invalid UTF-8 received")]
FromUTF8Error(#[from] FromUtf8Error),
/// Returned when parsing [`Uuid`](uuid::Uuid) in invalid strinng
/// representation.
#[error("Invalid StrUuid received")]
UuidError(#[from] uuid::Error),
/// Returned by [`fastnbt`](fastnbt).
#[error("Couldn't deserialize from NBT")]
FastNbtError(#[from] fastnbt::error::Error),
/// Returned when a string was longer than the maximum length allowed by the
/// protocol.
///
/// The first argument is the length that was read, the
/// second argument is the maximum length.
#[error("String was longer than allowed: {1} > {0}")]
StringTooLong(usize, usize),
/// Returned when a [`VarI32`](super::VarI32) is larger in size than 5 bytes
/// or when a [`VarI64`](super::VarI64) is larger in size than 10 bytes.
#[error("VarInt was longer than allowed")]
VarTooLong,
/// Returned when there are unsufficient bytes remaining in
/// [`Buf`](bytes::Buf).
#[error("Reached EOF of input buffer")]
NoMoreBytes,
}
14 changes: 14 additions & 0 deletions crates/packet_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![doc(html_favicon_url = "https://wiki.falconmc.org/perm/icons/favicon.ico?v=1")]
#![doc(html_logo_url = "https://wiki.falconmc.org/perm/icons/android-chrome-512x512.png?v=1")]
//! ## **Packet Core**
//! This is the main component of [Falcon](https://github.com/FalconMC-Dev/FalconMC)'s
//! networking system. It defines how types should be read from and written to a
Expand Down Expand Up @@ -95,6 +97,7 @@ pub trait PacketRead {
///
/// [derive macros]: falcon_packet_core#derives
pub trait PacketWrite: PacketSize {
/// Write self to the buffer according to the minecraft protocol.
fn write<B>(&self, buffer: &mut B) -> Result<(), WriteError>
where
B: BufMut + ?Sized;
Expand All @@ -109,6 +112,8 @@ pub trait PacketWrite: PacketSize {
///
/// [derive macros]: falcon_packet_core#derives
pub trait PacketSize {
/// Determine the size Self would have if it was written to
/// a minecraft connection, this should be an exact value.
fn size(&self) -> usize;
}

Expand All @@ -120,8 +125,11 @@ pub trait PacketSize {
/// This trait should rarely be implemented manually, if you implement this for
/// a general type, please contribute it to this project.
pub trait PacketReadSeed {
/// The target type this struct will produce.
type Value;

/// Read [`Self::Value`](PacketReadSeed::Value) from the buffer using self,
/// according to the minecraft protocol.
fn read<B>(self, buffer: &mut B) -> Result<Self::Value, ReadError>
where
B: Buf + ?Sized;
Expand All @@ -135,6 +143,8 @@ pub trait PacketReadSeed {
/// This trait should rarely be implemented manually, if you implement this for
/// a general type, please contribute it to this project.
pub trait PacketWriteSeed<'a>: PacketSizeSeed<'a> {
/// Write [`Self::Value`](PacketSizeSeed::Value) to the buffer using self,
/// according to the minecraft protocol.
fn write<B>(self, value: &'a Self::Value, buffer: &'a mut B) -> Result<(), WriteError>
where
B: BufMut + ?Sized;
Expand All @@ -148,7 +158,11 @@ pub trait PacketWriteSeed<'a>: PacketSizeSeed<'a> {
/// This trait should rarely be implemented manually, if you implement this for
/// a general type, please contribute it to this project.
pub trait PacketSizeSeed<'a> {
/// The target type this struct will write.
type Value;

/// Determine the size [`Self::Value`](PacketReadSeed::Value) would have if
/// it was written to a minecraft connection, this should be an exact
/// value.
fn size(self, value: &'a Self::Value) -> usize;
}
1 change: 1 addition & 0 deletions crates/packet_core/src/primitives/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use bytes::{Buf, BufMut};
use crate::error::{ReadError, WriteError};
use crate::{PacketRead, PacketReadSeed, PacketSize, PacketSizeSeed, PacketWrite, PacketWriteSeed};

/// Helper type to write and read [`array`]s to and from a minecraft connection.
pub struct PacketArray<T>(PhantomData<T>);

impl<T> Default for PacketArray<T> {
Expand Down
5 changes: 5 additions & 0 deletions crates/packet_core/src/primitives/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use bytes::BufMut;
use crate::error::{ReadError, WriteError};
use crate::{PacketReadSeed, PacketSize, PacketSizeSeed, PacketWrite, PacketWriteSeed};

/// Helper type to write any type `T` that implements [`AsRef<[u8]>`](AsRef) to
/// a minecraft connection.
#[derive(Default)]
pub struct AsRefU8<T>(PhantomData<T>);

Expand Down Expand Up @@ -46,12 +48,15 @@ impl<'a, T: AsRef<[u8]>> PacketSizeSeed<'a> for AsRefU8<T> {
fn size(self, value: &Self::Value) -> usize { value.as_ref().len() }
}

/// Helper type to read any type `T` that implements [`From<Vec<u8>>`] from a
/// minecraft connection.
pub struct Bytes<T> {
size: usize,
_marker: PhantomData<T>,
}

impl<T> Bytes<T> {
/// Creates a new `Bytes`.
pub fn new(size: usize) -> Self {
Self {
size,
Expand Down
Loading