From 28f1656c81aadbb56ff8e12a8c49ffeccb3feb3d Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Thu, 5 Dec 2024 16:04:40 -0700 Subject: [PATCH] Replace packets with a macro --- src/protocol/mod.rs | 15 +- src/protocol/packets.rs | 232 ++++++++++++++ src/protocol/packets/clientbound/login.rs | 164 ---------- src/protocol/packets/clientbound/mod.rs | 10 - src/protocol/packets/clientbound/play.rs | 283 ------------------ src/protocol/packets/clientbound/status.rs | 33 -- src/protocol/packets/mod.rs | 178 ----------- src/protocol/packets/serverbound/handshake.rs | 40 --- src/protocol/packets/serverbound/login.rs | 118 -------- src/protocol/packets/serverbound/mod.rs | 13 - src/protocol/packets/serverbound/play.rs | 134 --------- src/protocol/packets/serverbound/status.rs | 28 -- src/protocol/parsing.rs | 14 +- src/proxy/config.rs | 9 +- src/server/mod.rs | 29 +- src/server/net.rs | 31 +- 16 files changed, 291 insertions(+), 1040 deletions(-) create mode 100644 src/protocol/packets.rs delete mode 100644 src/protocol/packets/clientbound/login.rs delete mode 100644 src/protocol/packets/clientbound/mod.rs delete mode 100644 src/protocol/packets/clientbound/play.rs delete mode 100644 src/protocol/packets/clientbound/status.rs delete mode 100644 src/protocol/packets/mod.rs delete mode 100644 src/protocol/packets/serverbound/handshake.rs delete mode 100644 src/protocol/packets/serverbound/login.rs delete mode 100644 src/protocol/packets/serverbound/mod.rs delete mode 100644 src/protocol/packets/serverbound/play.rs delete mode 100644 src/protocol/packets/serverbound/status.rs diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 1d4852b..7532f22 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -8,12 +8,8 @@ pub mod error; pub mod inventory; /// Network packets. /// -/// The packet naming convention used is "DSIDName" where -/// 'D' is either 'S' for serverbound or 'C' for clientbound, -/// 'S' is the current connection state (**H**andshake, **S**tatus, **L**ogin, or **P**lay), -/// "ID" is the packet id in uppercase hexadecimal (ex. 1B, 05, 3A), -/// and "Name" is the packet's name as found on [wiki.vg](https://wiki.vg/Protocol) in PascalCase. -/// Examples include "SH00Handshake", "CP00SpawnEntity", and "SP11KeepAlive". +/// Packet names are as found on [wiki.vg](https://wiki.vg/Protocol) +/// in PascalCase, with some exceptions for uniqueness. pub mod packets; /// Useful shared parsing functions. pub mod parsing; @@ -27,13 +23,14 @@ use types::VarInt; /// /// Parsing packets requires knowing which state the connection is in. /// [Relevant wiki.vg page](https://wiki.vg/How_to_Write_a_Server#FSM_example_of_handling_new_TCP_connections) -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] pub enum ClientState { /// The connection is freshly established. /// /// The only packet in this state is `SH00Handshake`. /// After this packet is sent, the connection immediately /// transitions to `Status` or `Login`. + #[default] Handshake, /// The client is performing [server list ping](https://wiki.vg/Server_List_Ping). Status, @@ -59,8 +56,8 @@ impl parsing::Parsable for ClientState { } fn serialize(&self) -> Vec { let byte = match &self { - &ClientState::Status => 1, - &ClientState::Login => 2, + ClientState::Status => 1, + ClientState::Login => 2, _ => 0, }; vec![byte] diff --git a/src/protocol/packets.rs b/src/protocol/packets.rs new file mode 100644 index 0000000..520ecb9 --- /dev/null +++ b/src/protocol/packets.rs @@ -0,0 +1,232 @@ +#![allow(dead_code)] + +// Inspired by https://github.com/iceiix/stevenarella. + +/// Enum representation of a packet's direction. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum PacketDirection { + Serverbound, + Clientbound, +} + +#[macro_export] +macro_rules! packets { + ($($state:ident $state_name:ident { + $($dir:ident $dir_name:ident { + $( + $(#[$attr:meta])* + packet $name:ident $id:literal { + $($(#[$fattr:meta])* field $field:ident: $field_type:ty,)* + $($(#[$rattr:meta])* rest $rest:ident,)? + } + )* + })+ + })+) => { + use $crate::protocol::{ClientState, parsing::{VarInt, Parsable, IResult}}; + + #[derive(Debug, Clone, PartialEq)] + pub enum Packet { + $($($( + $name($state::$dir::$name), + )*)+)+ + } + $($($( + impl From<$state::$dir::$name> for Packet { + fn from(value: $state::$dir::$name) -> Packet { + Packet::$name(value) + } + } + )*)+)+ + impl Packet { + fn parser(client_state: ClientState, direction: PacketDirection) -> impl Fn(&[u8]) -> IResult<&[u8], Self> { + move |input: &[u8]| { + use nom::{combinator::verify, bytes::streaming::take}; + + if client_state == ClientState::Disconnected { + return nom::combinator::fail(input); + } + + let (input, packet_len) = VarInt::parse_usize(input)?; + let (packet_body, packet_id) = verify(VarInt::parse, |v| { + match client_state { + $(ClientState::$state_name => { + match direction { + $(PacketDirection::$dir_name => { + match **v { + $($id => true,)* + _ => false, + } + })* + } + })* + ClientState::Disconnected => false, + } + })(input)?; + let (input, packet_body) = take(packet_len)(packet_body)?; + let (_, packet) = Packet::body_parser(client_state, direction, packet_id)(packet_body)?; + Ok((input, packet)) + } + } + fn body_parser(client_state: ClientState, direction: PacketDirection, packet_id: VarInt) -> impl Fn(&[u8]) -> IResult<&[u8], Self> { + move |input: &[u8]| { + match client_state { + $(ClientState::$state_name => { + match direction { + $(PacketDirection::$dir_name => { + match *packet_id { + $($id => { + let (rest, inner) = $state::$dir::$name::parse(input)?; + // The packet should have consumed all of the input specified by packet_len. + nom::combinator::eof(rest)?; + Ok((rest, Packet::$name(inner))) + },)* + // Invalid packet id. + _ => Ok(nom::combinator::fail(input)?), + } + })* + } + })* + // Invalid client state. + _ => Ok(nom::combinator::fail(input)?), + } + } + } + pub fn parse(client_state: ClientState, direction: PacketDirection, input: &[u8]) -> IResult<&[u8], Self> { + Packet::parser(client_state, direction)(input) + } + pub fn parse_as>(client_state: ClientState, direction: PacketDirection, input: &[u8]) -> IResult<&[u8], Result> { + nom::combinator::map(Self::parser(client_state, direction), T::try_from)(input) + } + pub fn serialize(&self) -> (VarInt, Vec) { + match &self { + $($($( + Packet::$name(inner) => (VarInt::from($id), inner.serialize()), + )*)*)* + } + } + } + + $(pub mod $state { + $(pub mod $dir { + #![allow(unused_imports)] + + use $crate::protocol::{ClientState, parsing::{VarInt, Parsable, IResult}, types::*}; + use super::super::Packet; + + $( + $(#[$attr])* + #[derive(Default, Debug, Clone, PartialEq)] + pub struct $name { + $($(#[$fattr])* pub $field: $field_type,)* + $($(#[$rattr])* pub $rest: Vec,)? + } + impl TryFrom for $name { + type Error = Packet; + fn try_from(value: Packet) -> Result { + match value { + Packet::$name(inner) => Ok(inner), + _ => Err(value), + } + } + } + impl Parsable for $name { + fn parse(input: &[u8]) -> IResult<&[u8], Self> { + $(let (input, $field) = <$field_type>::parse(input)?;)* + $(let (input, $rest) = nom::combinator::rest(input)?;)? + Ok((input, $name { + $($field: $field,)* + $($rest: $rest.to_vec(),)? + })) + } + #[allow(unused_mut)] + fn serialize(&self) -> Vec { + let mut output = vec![]; + $(output.extend(self.$field.serialize());)* + $(output.extend(&self.$rest);)? + output + } + } + )* + })+ + })+ + }; +} + +packets!( + handshake Handshake { + serverbound Serverbound { + packet Handshake 0x00 { + field protocol_version: VarInt, + field host: String, + field port: u16, + field next_state: ClientState, + } + } + clientbound Clientbound {} + } + status Status { + serverbound Serverbound { + packet StatusRequest 0x00 {} + packet PingRequest 0x01 { + field payload: i64, + } + } + clientbound Clientbound { + packet StatusResponse 0x00 { + field response: Json, + } + packet PingResponse 0x01 { + field payload: i64, + } + } + } + login Login { + serverbound Serverbound { + packet LoginStart 0x00 { + field name: String, + field uuid: Option, + } + packet EncryptionResponse 0x01 { + field shared_secret: Vec, + field verify_token: Vec, + } + packet LoginPluginResponse 0x02 { + field message_id: VarInt, + field successful: bool, + rest data, + } + } + clientbound Clientbound { + packet LoginDisconnect 0x00 { + field reason: Chat, + } + packet EncryptionRequest 0x01 { + field server_id: String, + field public_key: Vec, + field verify_token: Vec, + } + packet LoginSuccess 0x02 { + field uuid: Uuid, + field username: String, + // TODO: Re-implement CL02LoginSuccessProperty + rest properties, + } + packet SetCompression 0x03 { + field threshold: VarInt, + } + packet LoginPluginRequest 0x04 { + field message_id: VarInt, + field channel: String, + rest data, + } + } + } + play Play { + serverbound Serverbound {} + clientbound Clientbound { + packet PlayDisconnect 0x17 { + field reason: Chat, + } + } + } +); diff --git a/src/protocol/packets/clientbound/login.rs b/src/protocol/packets/clientbound/login.rs deleted file mode 100644 index 2086db3..0000000 --- a/src/protocol/packets/clientbound/login.rs +++ /dev/null @@ -1,164 +0,0 @@ -use crate::protocol::parsing::Parsable; -use crate::protocol::types::{Chat, Json, Uuid, VarInt}; - -#[derive(Clone, Debug, PartialEq)] -pub struct CL00Disconnect { - pub reason: Chat, -} -crate::protocol::packets::packet!( - CL00Disconnect, - 0x00, - crate::protocol::ClientState::Login, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL00Disconnect> { - let (data, reason) = Json::parse(data)?; - Ok((data, CL00Disconnect { reason })) - }, - |packet: &CL00Disconnect| -> Vec { packet.reason.serialize() } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct CL01EncryptionRequest { - pub server_id: String, - pub public_key: Vec, - pub verify_token: Vec, -} -crate::protocol::packets::packet!( - CL01EncryptionRequest, - 0x01, - crate::protocol::ClientState::Login, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL01EncryptionRequest> { - let (data, server_id) = String::parse(data)?; - let (data, public_key) = u8::parse_vec(data)?; - let (data, verify_token) = u8::parse_vec(data)?; - - Ok(( - data, - CL01EncryptionRequest { - server_id, - public_key, - verify_token, - }, - )) - }, - |packet: &CL01EncryptionRequest| -> Vec { - let mut output = vec![]; - output.extend(packet.server_id.serialize()); - output.extend(packet.public_key.serialize()); - output.extend(packet.verify_token.serialize()); - output - } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct CL02LoginSuccess { - pub uuid: Uuid, - pub username: String, - pub properties: Vec, -} -#[derive(Clone, Debug, PartialEq)] -pub struct CL02LoginSuccessProperty { - pub name: String, - pub value: String, - pub signature: Option, -} -impl Parsable for CL02LoginSuccessProperty { - #[tracing::instrument] - fn parse(data: &[u8]) -> crate::protocol::parsing::IResult<&[u8], Self> { - let (data, name) = String::parse(data)?; - let (data, value) = String::parse(data)?; - let (data, signature) = String::parse_optional(data)?; - Ok(( - data, - CL02LoginSuccessProperty { - name, - value, - signature, - }, - )) - } - #[tracing::instrument] - fn serialize(&self) -> Vec { - let mut output = vec![]; - output.extend(self.name.serialize()); - output.extend(self.value.serialize()); - output.extend(self.signature.serialize()); - output - } -} -crate::protocol::packets::packet!( - CL02LoginSuccess, - 0x02, - crate::protocol::ClientState::Login, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL02LoginSuccess> { - let (data, uuid) = Uuid::parse(data)?; - let (data, username) = String::parse(data)?; - let (data, properties) = CL02LoginSuccessProperty::parse_vec(data)?; - - Ok(( - data, - CL02LoginSuccess { - uuid, - username, - properties, - }, - )) - }, - |packet: &CL02LoginSuccess| -> Vec { - let mut output = vec![]; - output.extend(packet.uuid.serialize()); - output.extend(packet.username.serialize()); - output.extend(packet.properties.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CL03SetCompression { - pub threshold: VarInt, -} -crate::protocol::packets::packet!( - CL03SetCompression, - 0x03, - crate::protocol::ClientState::Login, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL03SetCompression> { - let (data, threshold) = VarInt::parse(data)?; - Ok((data, CL03SetCompression { threshold })) - }, - |packet: &CL03SetCompression| -> Vec { packet.threshold.serialize() } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct CL04LoginPluginRequest { - pub message_id: VarInt, - pub channel: String, - pub data: Vec, -} -crate::protocol::packets::packet!( - CL04LoginPluginRequest, - 0x04, - crate::protocol::ClientState::Login, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CL04LoginPluginRequest> { - let (data, message_id) = VarInt::parse(data)?; - let (data, channel) = String::parse(data)?; - Ok(( - data, - CL04LoginPluginRequest { - message_id, - channel, - data: data.to_vec(), - }, - )) - }, - |packet: &CL04LoginPluginRequest| -> Vec { - let mut output = vec![]; - output.extend(packet.message_id.serialize()); - output.extend(packet.channel.serialize()); - output.extend(&packet.data); - output - } -); diff --git a/src/protocol/packets/clientbound/mod.rs b/src/protocol/packets/clientbound/mod.rs deleted file mode 100644 index f061b42..0000000 --- a/src/protocol/packets/clientbound/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -/// Packets for the `ClientState::Login` state. -pub mod login; -/// Packets for the `ClientState::Play` state. -pub mod play; -/// Packets for the `ClientState::Status` state. -pub mod status; - -pub use login::*; -pub use play::*; -pub use status::*; diff --git a/src/protocol/packets/clientbound/play.rs b/src/protocol/packets/clientbound/play.rs deleted file mode 100644 index 4a340c0..0000000 --- a/src/protocol/packets/clientbound/play.rs +++ /dev/null @@ -1,283 +0,0 @@ -use crate::protocol::{ - entities::{EntityPosition, EntityRotation, EntityVelocity}, - types::{Chat, Difficulty, Position, Uuid, VarInt}, -}; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CP00SpawnEntity { - pub id: VarInt, - pub uuid: Uuid, - pub kind: VarInt, - pub position: EntityPosition, - pub rotation: EntityRotation, - pub head_yaw: u8, - pub data: VarInt, - pub velocity: EntityVelocity, -} -crate::protocol::packets::packet!( - CP00SpawnEntity, - 0x00, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP00SpawnEntity> { - let (data, id) = VarInt::parse(data)?; - let (data, uuid) = Uuid::parse(data)?; - let (data, kind) = VarInt::parse(data)?; - let (data, position) = EntityPosition::parse(data)?; - let (data, rotation) = EntityRotation::parse(data)?; - let (data, head_yaw) = u8::parse(data)?; - let (data, d) = VarInt::parse(data)?; - let (data, velocity) = EntityVelocity::parse(data)?; - - Ok(( - data, - CP00SpawnEntity { - id, - uuid, - kind, - position, - rotation, - head_yaw, - data: d, - velocity, - }, - )) - }, - |packet: &CP00SpawnEntity| -> Vec { - let mut output = vec![]; - output.extend(packet.id.serialize()); - output.extend(packet.uuid.serialize()); - output.extend(packet.kind.serialize()); - output.extend(packet.position.serialize()); - output.extend(packet.rotation.serialize()); - output.extend(packet.head_yaw.serialize()); - output.extend(packet.data.serialize()); - output.extend(packet.velocity.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CP0BChangeDifficulty { - pub difficulty: Difficulty, - pub is_locked: bool, -} -crate::protocol::packets::packet!( - CP0BChangeDifficulty, - 0x0b, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP0BChangeDifficulty> { - let (data, difficulty) = Difficulty::parse(data)?; - let (data, is_locked) = bool::parse(data)?; - Ok(( - data, - CP0BChangeDifficulty { - difficulty, - is_locked, - }, - )) - }, - |packet: &CP0BChangeDifficulty| -> Vec { - let mut output = vec![]; - output.extend(packet.difficulty.serialize()); - output.extend(packet.is_locked.serialize()); - output - } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct CP17Disconnect { - pub reason: Chat, -} -crate::protocol::packets::packet!( - CP17Disconnect, - 0x17, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP17Disconnect> { - let (data, reason) = Chat::parse(data)?; - Ok((data, CP17Disconnect { reason })) - }, - |packet: &CP17Disconnect| -> Vec { packet.reason.serialize() } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CP1FKeepAlive { - pub payload: i64, -} -crate::protocol::packets::packet!( - CP1FKeepAlive, - 0x1f, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP1FKeepAlive> { - let (data, payload) = i64::parse(data)?; - Ok((data, CP1FKeepAlive { payload })) - }, - |packet: &CP1FKeepAlive| -> Vec { packet.payload.serialize() } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CP21WorldEvent { - pub event: i32, - pub location: Position, - pub data: i32, - pub disable_relative_volume: bool, -} -crate::protocol::packets::packet!( - CP21WorldEvent, - 0x21, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP21WorldEvent> { - let (data, event) = i32::parse(data)?; - let (data, location) = Position::parse(data)?; - let (data, d) = i32::parse(data)?; - let (data, disable_relative_volume) = bool::parse(data)?; - Ok(( - data, - CP21WorldEvent { - event, - location, - data: d, - disable_relative_volume, - }, - )) - }, - |packet: &CP21WorldEvent| -> Vec { - let mut output = vec![]; - output.extend(packet.event.serialize()); - output.extend(packet.location.serialize()); - output.extend(packet.data.serialize()); - output.extend(packet.disable_relative_volume.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CP50SetEntityVelocity { - pub entity_id: VarInt, - pub entity_velocity: EntityVelocity, -} -crate::protocol::packets::packet!( - CP50SetEntityVelocity, - 0x50, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP50SetEntityVelocity> { - let (data, entity_id) = VarInt::parse(data)?; - let (data, entity_velocity) = EntityVelocity::parse(data)?; - Ok(( - data, - CP50SetEntityVelocity { - entity_id, - entity_velocity, - }, - )) - }, - |packet: &CP50SetEntityVelocity| -> Vec { - let mut output = vec![]; - output.extend(packet.entity_id.serialize()); - output.extend(packet.entity_velocity.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CP52SetExperience { - pub experience_bar: f32, - pub total_experience: VarInt, - pub level: VarInt, -} -crate::protocol::packets::packet!( - CP52SetExperience, - 0x52, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP52SetExperience> { - let (data, experience_bar) = f32::parse(data)?; - let (data, total_experience) = VarInt::parse(data)?; - let (data, level) = VarInt::parse(data)?; - Ok(( - data, - CP52SetExperience { - experience_bar, - total_experience, - level, - }, - )) - }, - |packet: &CP52SetExperience| -> Vec { - let mut output = vec![]; - output.extend(packet.experience_bar.serialize()); - output.extend(packet.total_experience.serialize()); - output.extend(packet.level.serialize()); - output - } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct CP68EntityEffect { - pub entity_id: VarInt, - pub effect_id: VarInt, - pub amplifier: i8, - pub duration: VarInt, - pub is_ambient: bool, - pub show_particles: bool, - pub show_icon: bool, - pub has_factor_data: bool, - // TODO: pub factor_codec: NBT -} -crate::protocol::packets::packet!( - CP68EntityEffect, - 0x68, - crate::protocol::ClientState::Play, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CP68EntityEffect> { - let (data, entity_id) = VarInt::parse(data)?; - let (data, effect_id) = VarInt::parse(data)?; - let (data, amplifier) = i8::parse(data)?; - let (data, duration) = VarInt::parse(data)?; - let (data, flags) = u8::parse(data)?; - let is_ambient = flags & 0x01 > 0; - let show_particles = flags & 0x02 > 0; - let show_icon = flags & 0x04 > 0; - let (data, has_factor_data) = bool::parse(data)?; - // TODO: factor_codec - - Ok(( - data, - CP68EntityEffect { - entity_id, - effect_id, - amplifier, - duration, - is_ambient, - show_particles, - show_icon, - has_factor_data, - }, - )) - }, - |packet: &CP68EntityEffect| -> Vec { - let mut output = vec![]; - output.extend(packet.entity_id.serialize()); - output.extend(packet.effect_id.serialize()); - output.extend(packet.amplifier.serialize()); - output.extend(packet.duration.serialize()); - let mut flags = 0x00u8; - if packet.is_ambient { - flags |= 0x01; - } - if packet.show_particles { - flags |= 0x02; - } - if packet.show_icon { - flags |= 0x04; - } - output.extend(flags.serialize()); - // TODO: factor_codec - output - } -); diff --git a/src/protocol/packets/clientbound/status.rs b/src/protocol/packets/clientbound/status.rs deleted file mode 100644 index a817348..0000000 --- a/src/protocol/packets/clientbound/status.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::protocol::types::Json; - -#[derive(Clone, Debug, PartialEq)] -pub struct CS00StatusResponse { - pub response: Json, -} -crate::protocol::packets::packet!( - CS00StatusResponse, - 0x00, - crate::protocol::ClientState::Status, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CS00StatusResponse> { - let (data, response) = Json::parse(data)?; - Ok((data, CS00StatusResponse { response })) - }, - |packet: &CS00StatusResponse| -> Vec { packet.response.serialize() } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct CS01PingResponse { - pub payload: i64, -} -crate::protocol::packets::packet!( - CS01PingResponse, - 0x01, - crate::protocol::ClientState::Status, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], CS01PingResponse> { - let (data, payload) = i64::parse(data)?; - Ok((data, CS01PingResponse { payload })) - }, - |packet: &CS01PingResponse| -> Vec { packet.payload.serialize() } -); diff --git a/src/protocol/packets/mod.rs b/src/protocol/packets/mod.rs deleted file mode 100644 index 39737e4..0000000 --- a/src/protocol/packets/mod.rs +++ /dev/null @@ -1,178 +0,0 @@ -/// Packets that are heading to the client. -pub mod clientbound; -/// Packets that are heading to the server. -pub mod serverbound; - -use crate::protocol::parsing::{Parsable, VarInt}; - -/// Alias for a `VarInt`. -pub type PacketId = VarInt; - -pub trait Packet: - std::fmt::Debug + Clone + TryFrom + Into + Parsable -{ - const ID: i32; - const CLIENT_STATE: crate::protocol::ClientState; - const IS_SERVERBOUND: bool; -} - -macro_rules! generic_packet { - ($($packet_type: ident),*) => { - #[derive(Clone, Debug, PartialEq)] - pub enum GenericPacket { - $( - $packet_type($packet_type), - )* - } - impl GenericPacket { - #[tracing::instrument] - pub fn parse_uncompressed<'data>( - client_state: crate::protocol::ClientState, - is_serverbound: bool, - data: &'data [u8] - ) -> crate::protocol::parsing::IResult<&'data [u8], Self> { - use crate::protocol::parsing::Parsable; - tracing::trace!( - "GenericPacket::parse_uncompressed: {:?} {} {:?}", - client_state, - is_serverbound, - data - ); - let (data, packet_length) = crate::protocol::types::VarInt::parse(data)?; - let (data, packet_data) = nom::bytes::streaming::take(*packet_length as usize)(data)?; - - let (packet_data, packet_id) = PacketId::parse(packet_data)?; - let (_packet_data, packet_body) = - Self::parse_body(client_state, packet_id, is_serverbound, packet_data)?; - - // if !packet_data.is_empty() { - // println!("Packet data not empty after parsing!"); - // } - - Ok((data, packet_body)) - } - - #[tracing::instrument] - pub fn parse_body<'data>( - client_state: crate::protocol::ClientState, - packet_id: crate::protocol::packets::PacketId, - is_serverbound: bool, - data: &'data [u8], - ) -> crate::protocol::parsing::IResult<&'data [u8], Self> { - use crate::protocol::parsing::Parsable; - tracing::trace!( - "GenericPacket::parse_body: {:?} {} {}", - client_state, - packet_id, - is_serverbound - ); - match (client_state, *packet_id, is_serverbound) { - $( - ($packet_type::CLIENT_STATE, $packet_type::ID, $packet_type::IS_SERVERBOUND) => $packet_type::parse(data).map(|(data, packet)| (data, Into::::into(packet))), - )* - _ => Ok((data, Self::UnimplementedPacket(UnimplementedPacket(packet_id)))), - } - } - - #[tracing::instrument] - pub fn serialize(&self) -> (crate::protocol::packets::PacketId, Vec) { - use crate::protocol::parsing::Parsable; - tracing::trace!("GenericPacket::serialize: {:?}", self); - match self { - $( - Self::$packet_type(packet) => (PacketId::from($packet_type::ID), packet.serialize()), - )* - } - } - } - }; -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct UnimplementedPacket(VarInt); -packet!( - UnimplementedPacket, - 0x00, - crate::protocol::ClientState::Disconnected, - false, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], UnimplementedPacket> { - Ok((data, UnimplementedPacket(0i32.into()))) - }, - |_packet: &UnimplementedPacket| -> Vec { vec![] } -); - -use clientbound::*; -use serverbound::*; -generic_packet!( - UnimplementedPacket, - // Handshake - SH00Handshake, - // Status - SS00StatusRequest, - SS01PingRequest, - CS00StatusResponse, - CS01PingResponse, - // Login - SL00LoginStart, - SL01EncryptionResponse, - SL02LoginPluginResponse, - CL00Disconnect, - CL01EncryptionRequest, - CL02LoginSuccess, - CL03SetCompression, - CL04LoginPluginRequest, - // Play - SP08CommandSuggestionsRequest, - SP11KeepAlive, - SP13SetPlayerPosition, - SP14SetPlayerPositionAndRotation, - SP15SetPlayerRotation, - CP00SpawnEntity, - CP0BChangeDifficulty, - CP17Disconnect, - CP1FKeepAlive, - CP21WorldEvent, - CP50SetEntityVelocity, - CP52SetExperience, - CP68EntityEffect -); - -macro_rules! packet { - ($packet_type: ident, $id: literal, $client_state: expr, $serverbound: literal, $parse_body: expr, $serialize_body: expr) => { - impl crate::protocol::packets::Packet for $packet_type { - const ID: i32 = $id; - const CLIENT_STATE: crate::protocol::ClientState = $client_state; - const IS_SERVERBOUND: bool = $serverbound; - } - impl crate::protocol::parsing::Parsable for $packet_type { - #[tracing::instrument] - fn parse<'data>( - data: &'data [u8], - ) -> crate::protocol::parsing::IResult<&'data [u8], Self> { - $parse_body(data) - } - #[tracing::instrument] - fn serialize(&self) -> Vec { - $serialize_body(self) - } - } - impl From<$packet_type> for crate::protocol::packets::GenericPacket { - fn from(value: $packet_type) -> Self { - crate::protocol::packets::GenericPacket::$packet_type(value) - } - } - impl TryFrom for $packet_type { - type Error = (); - - fn try_from( - value: crate::protocol::packets::GenericPacket, - ) -> Result { - match value { - crate::protocol::packets::GenericPacket::$packet_type(packet) => Ok(packet), - _ => Err(()), - } - } - } - }; -} -pub(crate) use packet; diff --git a/src/protocol/packets/serverbound/handshake.rs b/src/protocol/packets/serverbound/handshake.rs deleted file mode 100644 index f1d4102..0000000 --- a/src/protocol/packets/serverbound/handshake.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::protocol::{types::VarInt, ClientState}; - -#[derive(Clone, Debug, PartialEq)] -pub struct SH00Handshake { - pub protocol_version: VarInt, - pub server_address: String, - pub server_port: u16, - pub next_state: ClientState, -} -crate::protocol::packets::packet!( - SH00Handshake, - 0x00, - ClientState::Handshake, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SH00Handshake> { - let (data, protocol_version) = VarInt::parse(data)?; - let (data, server_address) = String::parse(data)?; - let (data, server_port) = u16::parse(data)?; - let (data, next_state) = ClientState::parse(data)?; - // let (data, next_state) = VarInt::parse(data)?; - - Ok(( - data, - SH00Handshake { - protocol_version, - server_address, - server_port, - next_state, - }, - )) - }, - |packet: &SH00Handshake| -> Vec { - let mut output = vec![]; - output.extend(packet.protocol_version.serialize()); - output.extend(packet.server_address.serialize()); - output.extend(packet.server_port.serialize()); - output.extend(packet.next_state.serialize()); - output - } -); diff --git a/src/protocol/packets/serverbound/login.rs b/src/protocol/packets/serverbound/login.rs deleted file mode 100644 index cb2f1fb..0000000 --- a/src/protocol/packets/serverbound/login.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::protocol::types::{Uuid, VarInt}; -use nom::bytes::streaming::take; - -#[derive(Clone, Debug, PartialEq)] -pub struct SL00LoginStart { - pub name: String, - pub uuid: Option, -} -crate::protocol::packets::packet!( - SL00LoginStart, - 0x00, - crate::protocol::ClientState::Login, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SL00LoginStart> { - let (data, name) = String::parse(data)?; - let (data, has_uuid) = bool::parse(data)?; - if has_uuid { - let (data, uuid) = Uuid::parse(data)?; - Ok(( - data, - SL00LoginStart { - name, - uuid: Some(uuid), - }, - )) - } else { - Ok((data, SL00LoginStart { name, uuid: None })) - } - }, - |packet: &SL00LoginStart| -> Vec { - let mut output = vec![]; - output.extend(packet.name.serialize()); - output.extend(packet.uuid.is_some().serialize()); - if let Some(uuid) = packet.uuid { - output.extend(uuid.serialize()); - } - output - } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct SL01EncryptionResponse { - pub shared_secret: Vec, - pub verify_token: Vec, -} -crate::protocol::packets::packet!( - SL01EncryptionResponse, - 0x01, - crate::protocol::ClientState::Login, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SL01EncryptionResponse> { - let (data, shared_secret_len) = VarInt::parse(data)?; - let (data, shared_secret) = take(*shared_secret_len as usize)(data)?; - let (data, verify_token_len) = VarInt::parse(data)?; - let (data, verify_token) = take(*verify_token_len as usize)(data)?; - - Ok(( - data, - SL01EncryptionResponse { - shared_secret: shared_secret.to_vec(), - verify_token: verify_token.to_vec(), - }, - )) - }, - |packet: &SL01EncryptionResponse| -> Vec { - let mut output = vec![]; - output.extend(VarInt::from(packet.shared_secret.len() as i32).serialize()); - output.extend(&packet.shared_secret); - output.extend(VarInt::from(packet.verify_token.len() as i32).serialize()); - output.extend(&packet.verify_token); - output - } -); - -#[derive(Clone, Debug, PartialEq)] -pub struct SL02LoginPluginResponse { - pub message_id: VarInt, - pub successful: bool, - pub data: Vec, -} -crate::protocol::packets::packet!( - SL02LoginPluginResponse, - 0x02, - crate::protocol::ClientState::Login, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SL02LoginPluginResponse> { - let (data, message_id) = VarInt::parse(data)?; - let (data, successful) = bool::parse(data)?; - if successful { - Ok(( - &[], - SL02LoginPluginResponse { - message_id, - successful, - data: data.to_vec(), - }, - )) - } else { - Ok(( - data, - SL02LoginPluginResponse { - message_id, - successful, - data: vec![], - }, - )) - } - }, - |packet: &SL02LoginPluginResponse| -> Vec { - let mut output = vec![]; - output.extend(packet.message_id.serialize()); - output.extend(packet.successful.serialize()); - if packet.successful { - output.extend(&packet.data); - } - output - } -); diff --git a/src/protocol/packets/serverbound/mod.rs b/src/protocol/packets/serverbound/mod.rs deleted file mode 100644 index c393240..0000000 --- a/src/protocol/packets/serverbound/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -/// Packets for the `ClientState::Handshake` state. -pub mod handshake; -/// Packets for the `ClientState::Login` state. -pub mod login; -/// Packets for the `ClientState::Play` state. -pub mod play; -/// Packets for the `ClientState::Status` state. -pub mod status; - -pub use handshake::*; -pub use login::*; -pub use play::*; -pub use status::*; diff --git a/src/protocol/packets/serverbound/play.rs b/src/protocol/packets/serverbound/play.rs deleted file mode 100644 index 44e6fc3..0000000 --- a/src/protocol/packets/serverbound/play.rs +++ /dev/null @@ -1,134 +0,0 @@ -use crate::protocol::{ - entities::{EntityPosition, EntityRotation}, - types::VarInt, -}; - -#[derive(Clone, Debug, PartialEq)] -pub struct SP08CommandSuggestionsRequest { - pub transaction_id: VarInt, - pub text: String, -} -crate::protocol::packets::packet!( - SP08CommandSuggestionsRequest, - 0x08, - crate::protocol::ClientState::Play, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP08CommandSuggestionsRequest> { - let (data, transaction_id) = VarInt::parse(data)?; - let (data, text) = String::parse(data)?; - Ok((data, SP08CommandSuggestionsRequest { - transaction_id, - text, - })) - }, - |packet: &SP08CommandSuggestionsRequest| -> Vec { - let mut output = vec![]; - output.extend(packet.transaction_id.serialize()); - output.extend(packet.text.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SP11KeepAlive { - pub payload: i64, -} -crate::protocol::packets::packet!( - SP11KeepAlive, - 0x11, - crate::protocol::ClientState::Play, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP11KeepAlive> { - let (data, payload) = i64::parse(data)?; - Ok((data, SP11KeepAlive { payload })) - }, - |packet: &SP11KeepAlive| -> Vec { packet.payload.serialize() } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SP13SetPlayerPosition { - pub position: EntityPosition, - pub on_ground: bool, -} -crate::protocol::packets::packet!( - SP13SetPlayerPosition, - 0x13, - crate::protocol::ClientState::Play, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP13SetPlayerPosition> { - let (data, position) = EntityPosition::parse(data)?; - let (data, on_ground) = bool::parse(data)?; - Ok(( - data, - SP13SetPlayerPosition { - position, - on_ground, - }, - )) - }, - |packet: &SP13SetPlayerPosition| -> Vec { - let mut output = vec![]; - output.extend(packet.position.serialize()); - output.extend(packet.on_ground.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SP14SetPlayerPositionAndRotation { - pub position: EntityPosition, - pub rotation: EntityRotation, - pub on_ground: bool, -} -crate::protocol::packets::packet!( - SP14SetPlayerPositionAndRotation, - 0x14, - crate::protocol::ClientState::Play, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP14SetPlayerPositionAndRotation> { - let (data, position) = EntityPosition::parse(data)?; - let (data, rotation) = EntityRotation::parse(data)?; - let (data, on_ground) = bool::parse(data)?; - Ok((data, SP14SetPlayerPositionAndRotation { - position, - rotation, - on_ground, - })) - }, - |packet: &SP14SetPlayerPositionAndRotation| -> Vec { - let mut output = vec![]; - output.extend(packet.position.serialize()); - output.extend(packet.rotation.serialize()); - output.extend(packet.on_ground.serialize()); - output - } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SP15SetPlayerRotation { - pub rotation: EntityRotation, - pub on_ground: bool, -} -crate::protocol::packets::packet!( - SP15SetPlayerRotation, - 0x15, - crate::protocol::ClientState::Play, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SP15SetPlayerRotation> { - let (data, rotation) = EntityRotation::parse(data)?; - let (data, on_ground) = bool::parse(data)?; - Ok(( - data, - SP15SetPlayerRotation { - rotation, - on_ground, - }, - )) - }, - |packet: &SP15SetPlayerRotation| -> Vec { - let mut output = vec![]; - output.extend(packet.rotation.serialize()); - output.extend(packet.on_ground.serialize()); - output - } -); diff --git a/src/protocol/packets/serverbound/status.rs b/src/protocol/packets/serverbound/status.rs deleted file mode 100644 index c4b3b8d..0000000 --- a/src/protocol/packets/serverbound/status.rs +++ /dev/null @@ -1,28 +0,0 @@ -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SS00StatusRequest; -crate::protocol::packets::packet!( - SS00StatusRequest, - 0x00, - crate::protocol::ClientState::Status, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SS00StatusRequest> { - Ok((data, SS00StatusRequest)) - }, - |_packet: &SS00StatusRequest| -> Vec { vec![] } -); - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct SS01PingRequest { - pub payload: i64, -} -crate::protocol::packets::packet!( - SS01PingRequest, - 0x01, - crate::protocol::ClientState::Status, - true, - |data: &'data [u8]| -> crate::protocol::parsing::IResult<&'data [u8], SS01PingRequest> { - let (data, payload) = i64::parse(data)?; - Ok((data, SS01PingRequest { payload })) - }, - |packet: &SS01PingRequest| -> Vec { packet.payload.serialize() } -); diff --git a/src/protocol/parsing.rs b/src/protocol/parsing.rs index c756a0a..fa5f2e1 100644 --- a/src/protocol/parsing.rs +++ b/src/protocol/parsing.rs @@ -2,7 +2,8 @@ pub use nom::IResult; use nom::{ bytes::streaming::{take, take_while_m_n}, combinator::map_res, - number::streaming as nom_nums, Parser, + number::streaming as nom_nums, + Parser, }; /// Implementation of the protocol's VarInt type. @@ -11,6 +12,11 @@ use nom::{ /// When the original i32 value is needed, simply `Deref` it. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] pub struct VarInt(i32); +impl VarInt { + pub fn parse_usize(data: &[u8]) -> IResult<&[u8], usize> { + nom::combinator::map_res(Self::parse, usize::try_from)(data) + } +} impl std::ops::Deref for VarInt { type Target = i32; fn deref(&self) -> &Self::Target { @@ -37,6 +43,12 @@ impl From for VarInt { (value as i32).into() } } +impl TryFrom for usize { + type Error = >::Error; + fn try_from(value: VarInt) -> Result { + usize::try_from(*value) + } +} impl std::fmt::Display for VarInt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) diff --git a/src/proxy/config.rs b/src/proxy/config.rs index 2b8cdc3..1d5f9cf 100644 --- a/src/proxy/config.rs +++ b/src/proxy/config.rs @@ -37,17 +37,10 @@ impl ProxyConfig { } } -#[derive(Debug)] +#[derive(Debug, Default)] pub struct ProxyArgs { upstream: String, } -impl Default for ProxyArgs { - fn default() -> Self { - ProxyArgs { - upstream: String::new(), - } - } -} impl ProxyArgs { pub fn instance() -> Option<&'static Self> { Args::instance().proxy.as_ref() diff --git a/src/server/mod.rs b/src/server/mod.rs index 2430831..2598d1b 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -199,7 +199,8 @@ impl Server { .filter(|client| matches!(client.state, NetworkClientState::Play)) .count(); 'clients: for client in clients.iter_mut() { - use crate::protocol::packets::{clientbound::*, serverbound::*}; + use crate::protocol::packets; + 'packets: while !client.incoming_packet_queue.is_empty() { // client.read_packet() // None: The client doesn't have any more packets. @@ -207,7 +208,9 @@ impl Server { // Some(Ok(_)): The client read the expected packet. match client.state.clone() { NetworkClientState::Handshake => { - let handshake = match client.read_packet::() { + use packets::handshake::serverbound::Handshake; + + let handshake = match client.read_packet::() { None => continue 'packets, Some(Err(_)) => continue 'clients, Some(Ok(handshake)) => handshake, @@ -235,7 +238,11 @@ impl Server { received_request, received_ping, } if !received_request => { - let _status_request = match client.read_packet::() { + use packets::status::{ + clientbound::StatusResponse, serverbound::StatusRequest, + }; + + let _status_request = match client.read_packet::() { None => continue 'packets, Some(Err(_)) => continue 'clients, Some(Ok(p)) => p, @@ -246,7 +253,7 @@ impl Server { }; let config = Config::instance(); use base64::Engine; - client.queue_packet(CS00StatusResponse { + client.queue_packet(StatusResponse { response: serde_json::json!({ "version": { "name": config.global.game_version, @@ -267,19 +274,25 @@ impl Server { } // Status !received_ping: Read SS00StatusRequest and respond with CS00StatusResponse NetworkClientState::Status { received_ping, .. } if !received_ping => { - let ping = match client.read_packet::() { + use packets::status::{ + clientbound::PingResponse, serverbound::PingRequest, + }; + + let ping = match client.read_packet::() { None => continue 'packets, Some(Err(_)) => continue 'clients, Some(Ok(p)) => p, }; - client.queue_packet(CS01PingResponse { + client.queue_packet(PingResponse { payload: ping.payload, }); client.state = NetworkClientState::Disconnected; } NetworkClientState::Status { .. } => unreachable!(), NetworkClientState::Login { received_start, .. } if !received_start.0 => { - let login_start = match client.read_packet::() { + use packets::login::{clientbound::*, serverbound::*}; + + let login_start = match client.read_packet::() { None => continue 'packets, Some(Err(_)) => continue 'clients, Some(Ok(p)) => p, @@ -287,7 +300,7 @@ impl Server { // TODO: Authenticate the user. // TODO: Get the user from the stored database. // TODO: Encryption/compression. - client.queue_packet(CL02LoginSuccess { + client.queue_packet(LoginSuccess { uuid: login_start.uuid.unwrap_or(0u128), username: login_start.name.clone(), properties: vec![], diff --git a/src/server/net.rs b/src/server/net.rs index ff35999..b4b68f0 100644 --- a/src/server/net.rs +++ b/src/server/net.rs @@ -1,5 +1,5 @@ use crate::protocol::{ - packets::{serverbound::SL00LoginStart, GenericPacket}, + packets::{self, Packet, PacketDirection}, parsing::Parsable, ClientState, }; @@ -30,7 +30,7 @@ pub(crate) enum NetworkClientState { /// The client sent `SH00Handshake` with `next_state = ClientState::Login` /// and is attempting to join the server. Login { - received_start: (bool, Option), + received_start: (bool, Option), }, /// The server sent `CL02LoginSuccess` and transitioned to `Play`. #[allow(dead_code)] @@ -76,13 +76,13 @@ pub(crate) struct NetworkClient { incoming_data: VecDeque, /// Packets get appended to the back as they get read, /// and popped from the front as they get handled. - pub incoming_packet_queue: VecDeque, + pub incoming_packet_queue: VecDeque, /// Keeps track of the last time the client sent data. /// /// This is useful for removing clients that have timed out. pub last_received_data_time: Instant, /// Packets get appended to the back and get popped from the front as they get sent. - pub outgoing_packet_queue: VecDeque, + pub outgoing_packet_queue: VecDeque, } impl NetworkClient { #[tracing::instrument] @@ -139,7 +139,11 @@ impl NetworkClient { let mut bytes_consumed = 0; while !data.is_empty() { - let p = GenericPacket::parse_uncompressed(self.state.clone().into(), true, data); + let p = Packet::parse( + self.state.clone().into(), + PacketDirection::Serverbound, + data, + ); trace!("{} got {:?}", self.id, p); match p { Ok((d, packet)) => { @@ -166,9 +170,9 @@ impl NetworkClient { // Some(Err(())): The packet was the wrong type. // Some(Ok(_)): The packet was successfully read. #[tracing::instrument] - pub fn read_packet>( + pub fn read_packet>( &mut self, - ) -> Option> { + ) -> Option> { if let Some(generic_packet) = self.incoming_packet_queue.pop_back() { if let Ok(packet) = TryInto::

::try_into(generic_packet.clone()) { Some(Ok(packet)) @@ -181,7 +185,7 @@ impl NetworkClient { } } #[tracing::instrument] - pub fn queue_packet>(&mut self, packet: P) { + pub fn queue_packet>(&mut self, packet: P) { self.outgoing_packet_queue.push_back(packet.into()); } #[tracing::instrument] @@ -195,11 +199,11 @@ impl NetworkClient { Ok(()) } #[tracing::instrument] - pub async fn send_packet>( + pub async fn send_packet>( &self, packet: P, ) -> tokio::io::Result<()> { - let packet: GenericPacket = packet.into(); + let packet: Packet = packet.into(); debug!("Sending packet {:?} to client {}", packet, self.id); let (packet_id, mut packet_body) = packet.serialize(); @@ -219,7 +223,8 @@ impl NetworkClient { } #[tracing::instrument] pub async fn disconnect(&mut self, reason: Option) { - use crate::protocol::packets::clientbound::{CL00Disconnect, CP17Disconnect}; + use packets::{login::clientbound::LoginDisconnect, play::clientbound::PlayDisconnect}; + let reason = reason.unwrap_or(serde_json::json!({ "text": "You have been disconnected!" })); @@ -229,10 +234,10 @@ impl NetworkClient { // Impossible to send a disconnect in these states. } ClientState::Login => { - let _ = self.send_packet(CL00Disconnect { reason }).await; + let _ = self.send_packet(LoginDisconnect { reason }).await; } ClientState::Play => { - let _ = self.send_packet(CP17Disconnect { reason }).await; + let _ = self.send_packet(PlayDisconnect { reason }).await; } }