Replace packets with a macro
This commit is contained in:
parent
6a58f58cc0
commit
28f1656c81
@ -8,12 +8,8 @@ pub mod error;
|
|||||||
pub mod inventory;
|
pub mod inventory;
|
||||||
/// Network packets.
|
/// Network packets.
|
||||||
///
|
///
|
||||||
/// The packet naming convention used is "DSIDName" where
|
/// Packet names are as found on [wiki.vg](https://wiki.vg/Protocol)
|
||||||
/// 'D' is either 'S' for serverbound or 'C' for clientbound,
|
/// in PascalCase, with some exceptions for uniqueness.
|
||||||
/// '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".
|
|
||||||
pub mod packets;
|
pub mod packets;
|
||||||
/// Useful shared parsing functions.
|
/// Useful shared parsing functions.
|
||||||
pub mod parsing;
|
pub mod parsing;
|
||||||
@ -27,13 +23,14 @@ use types::VarInt;
|
|||||||
///
|
///
|
||||||
/// Parsing packets requires knowing which state the connection is in.
|
/// 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)
|
/// [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 {
|
pub enum ClientState {
|
||||||
/// The connection is freshly established.
|
/// The connection is freshly established.
|
||||||
///
|
///
|
||||||
/// The only packet in this state is `SH00Handshake`.
|
/// The only packet in this state is `SH00Handshake`.
|
||||||
/// After this packet is sent, the connection immediately
|
/// After this packet is sent, the connection immediately
|
||||||
/// transitions to `Status` or `Login`.
|
/// transitions to `Status` or `Login`.
|
||||||
|
#[default]
|
||||||
Handshake,
|
Handshake,
|
||||||
/// The client is performing [server list ping](https://wiki.vg/Server_List_Ping).
|
/// The client is performing [server list ping](https://wiki.vg/Server_List_Ping).
|
||||||
Status,
|
Status,
|
||||||
@ -59,8 +56,8 @@ impl parsing::Parsable for ClientState {
|
|||||||
}
|
}
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let byte = match &self {
|
let byte = match &self {
|
||||||
&ClientState::Status => 1,
|
ClientState::Status => 1,
|
||||||
&ClientState::Login => 2,
|
ClientState::Login => 2,
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
vec![byte]
|
vec![byte]
|
||||||
|
232
src/protocol/packets.rs
Normal file
232
src/protocol/packets.rs
Normal file
@ -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<T: TryFrom<Packet, Error = Packet>>(client_state: ClientState, direction: PacketDirection, input: &[u8]) -> IResult<&[u8], Result<T, Self>> {
|
||||||
|
nom::combinator::map(Self::parser(client_state, direction), T::try_from)(input)
|
||||||
|
}
|
||||||
|
pub fn serialize(&self) -> (VarInt, Vec<u8>) {
|
||||||
|
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<u8>,)?
|
||||||
|
}
|
||||||
|
impl TryFrom<Packet> for $name {
|
||||||
|
type Error = Packet;
|
||||||
|
fn try_from(value: Packet) -> Result<Self, Self::Error> {
|
||||||
|
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<u8> {
|
||||||
|
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<Uuid>,
|
||||||
|
}
|
||||||
|
packet EncryptionResponse 0x01 {
|
||||||
|
field shared_secret: Vec<u8>,
|
||||||
|
field verify_token: Vec<u8>,
|
||||||
|
}
|
||||||
|
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<u8>,
|
||||||
|
field verify_token: Vec<u8>,
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
@ -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<u8> { packet.reason.serialize() }
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct CL01EncryptionRequest {
|
|
||||||
pub server_id: String,
|
|
||||||
pub public_key: Vec<u8>,
|
|
||||||
pub verify_token: Vec<u8>,
|
|
||||||
}
|
|
||||||
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<u8> {
|
|
||||||
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<CL02LoginSuccessProperty>,
|
|
||||||
}
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct CL02LoginSuccessProperty {
|
|
||||||
pub name: String,
|
|
||||||
pub value: String,
|
|
||||||
pub signature: Option<String>,
|
|
||||||
}
|
|
||||||
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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
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<u8> { packet.threshold.serialize() }
|
|
||||||
);
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct CL04LoginPluginRequest {
|
|
||||||
pub message_id: VarInt,
|
|
||||||
pub channel: String,
|
|
||||||
pub data: Vec<u8>,
|
|
||||||
}
|
|
||||||
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<u8> {
|
|
||||||
let mut output = vec![];
|
|
||||||
output.extend(packet.message_id.serialize());
|
|
||||||
output.extend(packet.channel.serialize());
|
|
||||||
output.extend(&packet.data);
|
|
||||||
output
|
|
||||||
}
|
|
||||||
);
|
|
@ -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::*;
|
|
@ -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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
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<u8> { 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<u8> { 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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
);
|
|
@ -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<u8> { 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<u8> { packet.payload.serialize() }
|
|
||||||
);
|
|
@ -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<GenericPacket> + Into<GenericPacket> + 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::<GenericPacket>::into(packet))),
|
|
||||||
)*
|
|
||||||
_ => Ok((data, Self::UnimplementedPacket(UnimplementedPacket(packet_id)))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub fn serialize(&self) -> (crate::protocol::packets::PacketId, Vec<u8>) {
|
|
||||||
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<u8> { 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<u8> {
|
|
||||||
$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<crate::protocol::packets::GenericPacket> for $packet_type {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(
|
|
||||||
value: crate::protocol::packets::GenericPacket,
|
|
||||||
) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
crate::protocol::packets::GenericPacket::$packet_type(packet) => Ok(packet),
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use packet;
|
|
@ -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<u8> {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
);
|
|
@ -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<Uuid>,
|
|
||||||
}
|
|
||||||
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<u8> {
|
|
||||||
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<u8>,
|
|
||||||
pub verify_token: Vec<u8>,
|
|
||||||
}
|
|
||||||
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<u8> {
|
|
||||||
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<u8>,
|
|
||||||
}
|
|
||||||
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<u8> {
|
|
||||||
let mut output = vec![];
|
|
||||||
output.extend(packet.message_id.serialize());
|
|
||||||
output.extend(packet.successful.serialize());
|
|
||||||
if packet.successful {
|
|
||||||
output.extend(&packet.data);
|
|
||||||
}
|
|
||||||
output
|
|
||||||
}
|
|
||||||
);
|
|
@ -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::*;
|
|
@ -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<u8> {
|
|
||||||
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<u8> { 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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
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<u8> {
|
|
||||||
let mut output = vec![];
|
|
||||||
output.extend(packet.rotation.serialize());
|
|
||||||
output.extend(packet.on_ground.serialize());
|
|
||||||
output
|
|
||||||
}
|
|
||||||
);
|
|
@ -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<u8> { 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<u8> { packet.payload.serialize() }
|
|
||||||
);
|
|
@ -2,7 +2,8 @@ pub use nom::IResult;
|
|||||||
use nom::{
|
use nom::{
|
||||||
bytes::streaming::{take, take_while_m_n},
|
bytes::streaming::{take, take_while_m_n},
|
||||||
combinator::map_res,
|
combinator::map_res,
|
||||||
number::streaming as nom_nums, Parser,
|
number::streaming as nom_nums,
|
||||||
|
Parser,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Implementation of the protocol's VarInt type.
|
/// Implementation of the protocol's VarInt type.
|
||||||
@ -11,6 +12,11 @@ use nom::{
|
|||||||
/// When the original i32 value is needed, simply `Deref` it.
|
/// When the original i32 value is needed, simply `Deref` it.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
pub struct VarInt(i32);
|
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 {
|
impl std::ops::Deref for VarInt {
|
||||||
type Target = i32;
|
type Target = i32;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -37,6 +43,12 @@ impl From<usize> for VarInt {
|
|||||||
(value as i32).into()
|
(value as i32).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl TryFrom<VarInt> for usize {
|
||||||
|
type Error = <usize as TryFrom<i32>>::Error;
|
||||||
|
fn try_from(value: VarInt) -> Result<Self, Self::Error> {
|
||||||
|
usize::try_from(*value)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for VarInt {
|
impl std::fmt::Display for VarInt {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{:?}", self)
|
write!(f, "{:?}", self)
|
||||||
|
@ -37,17 +37,10 @@ impl ProxyConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ProxyArgs {
|
pub struct ProxyArgs {
|
||||||
upstream: String,
|
upstream: String,
|
||||||
}
|
}
|
||||||
impl Default for ProxyArgs {
|
|
||||||
fn default() -> Self {
|
|
||||||
ProxyArgs {
|
|
||||||
upstream: String::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ProxyArgs {
|
impl ProxyArgs {
|
||||||
pub fn instance() -> Option<&'static Self> {
|
pub fn instance() -> Option<&'static Self> {
|
||||||
Args::instance().proxy.as_ref()
|
Args::instance().proxy.as_ref()
|
||||||
|
@ -199,7 +199,8 @@ impl Server {
|
|||||||
.filter(|client| matches!(client.state, NetworkClientState::Play))
|
.filter(|client| matches!(client.state, NetworkClientState::Play))
|
||||||
.count();
|
.count();
|
||||||
'clients: for client in clients.iter_mut() {
|
'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() {
|
'packets: while !client.incoming_packet_queue.is_empty() {
|
||||||
// client.read_packet()
|
// client.read_packet()
|
||||||
// None: The client doesn't have any more packets.
|
// None: The client doesn't have any more packets.
|
||||||
@ -207,7 +208,9 @@ impl Server {
|
|||||||
// Some(Ok(_)): The client read the expected packet.
|
// Some(Ok(_)): The client read the expected packet.
|
||||||
match client.state.clone() {
|
match client.state.clone() {
|
||||||
NetworkClientState::Handshake => {
|
NetworkClientState::Handshake => {
|
||||||
let handshake = match client.read_packet::<SH00Handshake>() {
|
use packets::handshake::serverbound::Handshake;
|
||||||
|
|
||||||
|
let handshake = match client.read_packet::<Handshake>() {
|
||||||
None => continue 'packets,
|
None => continue 'packets,
|
||||||
Some(Err(_)) => continue 'clients,
|
Some(Err(_)) => continue 'clients,
|
||||||
Some(Ok(handshake)) => handshake,
|
Some(Ok(handshake)) => handshake,
|
||||||
@ -235,7 +238,11 @@ impl Server {
|
|||||||
received_request,
|
received_request,
|
||||||
received_ping,
|
received_ping,
|
||||||
} if !received_request => {
|
} if !received_request => {
|
||||||
let _status_request = match client.read_packet::<SS00StatusRequest>() {
|
use packets::status::{
|
||||||
|
clientbound::StatusResponse, serverbound::StatusRequest,
|
||||||
|
};
|
||||||
|
|
||||||
|
let _status_request = match client.read_packet::<StatusRequest>() {
|
||||||
None => continue 'packets,
|
None => continue 'packets,
|
||||||
Some(Err(_)) => continue 'clients,
|
Some(Err(_)) => continue 'clients,
|
||||||
Some(Ok(p)) => p,
|
Some(Ok(p)) => p,
|
||||||
@ -246,7 +253,7 @@ impl Server {
|
|||||||
};
|
};
|
||||||
let config = Config::instance();
|
let config = Config::instance();
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
client.queue_packet(CS00StatusResponse {
|
client.queue_packet(StatusResponse {
|
||||||
response: serde_json::json!({
|
response: serde_json::json!({
|
||||||
"version": {
|
"version": {
|
||||||
"name": config.global.game_version,
|
"name": config.global.game_version,
|
||||||
@ -267,19 +274,25 @@ impl Server {
|
|||||||
}
|
}
|
||||||
// Status !received_ping: Read SS00StatusRequest and respond with CS00StatusResponse
|
// Status !received_ping: Read SS00StatusRequest and respond with CS00StatusResponse
|
||||||
NetworkClientState::Status { received_ping, .. } if !received_ping => {
|
NetworkClientState::Status { received_ping, .. } if !received_ping => {
|
||||||
let ping = match client.read_packet::<SS01PingRequest>() {
|
use packets::status::{
|
||||||
|
clientbound::PingResponse, serverbound::PingRequest,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ping = match client.read_packet::<PingRequest>() {
|
||||||
None => continue 'packets,
|
None => continue 'packets,
|
||||||
Some(Err(_)) => continue 'clients,
|
Some(Err(_)) => continue 'clients,
|
||||||
Some(Ok(p)) => p,
|
Some(Ok(p)) => p,
|
||||||
};
|
};
|
||||||
client.queue_packet(CS01PingResponse {
|
client.queue_packet(PingResponse {
|
||||||
payload: ping.payload,
|
payload: ping.payload,
|
||||||
});
|
});
|
||||||
client.state = NetworkClientState::Disconnected;
|
client.state = NetworkClientState::Disconnected;
|
||||||
}
|
}
|
||||||
NetworkClientState::Status { .. } => unreachable!(),
|
NetworkClientState::Status { .. } => unreachable!(),
|
||||||
NetworkClientState::Login { received_start, .. } if !received_start.0 => {
|
NetworkClientState::Login { received_start, .. } if !received_start.0 => {
|
||||||
let login_start = match client.read_packet::<SL00LoginStart>() {
|
use packets::login::{clientbound::*, serverbound::*};
|
||||||
|
|
||||||
|
let login_start = match client.read_packet::<LoginStart>() {
|
||||||
None => continue 'packets,
|
None => continue 'packets,
|
||||||
Some(Err(_)) => continue 'clients,
|
Some(Err(_)) => continue 'clients,
|
||||||
Some(Ok(p)) => p,
|
Some(Ok(p)) => p,
|
||||||
@ -287,7 +300,7 @@ impl Server {
|
|||||||
// TODO: Authenticate the user.
|
// TODO: Authenticate the user.
|
||||||
// TODO: Get the user from the stored database.
|
// TODO: Get the user from the stored database.
|
||||||
// TODO: Encryption/compression.
|
// TODO: Encryption/compression.
|
||||||
client.queue_packet(CL02LoginSuccess {
|
client.queue_packet(LoginSuccess {
|
||||||
uuid: login_start.uuid.unwrap_or(0u128),
|
uuid: login_start.uuid.unwrap_or(0u128),
|
||||||
username: login_start.name.clone(),
|
username: login_start.name.clone(),
|
||||||
properties: vec![],
|
properties: vec![],
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::protocol::{
|
use crate::protocol::{
|
||||||
packets::{serverbound::SL00LoginStart, GenericPacket},
|
packets::{self, Packet, PacketDirection},
|
||||||
parsing::Parsable,
|
parsing::Parsable,
|
||||||
ClientState,
|
ClientState,
|
||||||
};
|
};
|
||||||
@ -30,7 +30,7 @@ pub(crate) enum NetworkClientState {
|
|||||||
/// The client sent `SH00Handshake` with `next_state = ClientState::Login`
|
/// The client sent `SH00Handshake` with `next_state = ClientState::Login`
|
||||||
/// and is attempting to join the server.
|
/// and is attempting to join the server.
|
||||||
Login {
|
Login {
|
||||||
received_start: (bool, Option<SL00LoginStart>),
|
received_start: (bool, Option<packets::login::serverbound::LoginStart>),
|
||||||
},
|
},
|
||||||
/// The server sent `CL02LoginSuccess` and transitioned to `Play`.
|
/// The server sent `CL02LoginSuccess` and transitioned to `Play`.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -76,13 +76,13 @@ pub(crate) struct NetworkClient {
|
|||||||
incoming_data: VecDeque<u8>,
|
incoming_data: VecDeque<u8>,
|
||||||
/// Packets get appended to the back as they get read,
|
/// Packets get appended to the back as they get read,
|
||||||
/// and popped from the front as they get handled.
|
/// and popped from the front as they get handled.
|
||||||
pub incoming_packet_queue: VecDeque<GenericPacket>,
|
pub incoming_packet_queue: VecDeque<Packet>,
|
||||||
/// Keeps track of the last time the client sent data.
|
/// Keeps track of the last time the client sent data.
|
||||||
///
|
///
|
||||||
/// This is useful for removing clients that have timed out.
|
/// This is useful for removing clients that have timed out.
|
||||||
pub last_received_data_time: Instant,
|
pub last_received_data_time: Instant,
|
||||||
/// Packets get appended to the back and get popped from the front as they get sent.
|
/// Packets get appended to the back and get popped from the front as they get sent.
|
||||||
pub outgoing_packet_queue: VecDeque<GenericPacket>,
|
pub outgoing_packet_queue: VecDeque<Packet>,
|
||||||
}
|
}
|
||||||
impl NetworkClient {
|
impl NetworkClient {
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
@ -139,7 +139,11 @@ impl NetworkClient {
|
|||||||
|
|
||||||
let mut bytes_consumed = 0;
|
let mut bytes_consumed = 0;
|
||||||
while !data.is_empty() {
|
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);
|
trace!("{} got {:?}", self.id, p);
|
||||||
match p {
|
match p {
|
||||||
Ok((d, packet)) => {
|
Ok((d, packet)) => {
|
||||||
@ -166,9 +170,9 @@ impl NetworkClient {
|
|||||||
// Some(Err(())): The packet was the wrong type.
|
// Some(Err(())): The packet was the wrong type.
|
||||||
// Some(Ok(_)): The packet was successfully read.
|
// Some(Ok(_)): The packet was successfully read.
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn read_packet<P: std::fmt::Debug + TryFrom<GenericPacket>>(
|
pub fn read_packet<P: std::fmt::Debug + TryFrom<Packet>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Option<std::result::Result<P, GenericPacket>> {
|
) -> Option<std::result::Result<P, Packet>> {
|
||||||
if let Some(generic_packet) = self.incoming_packet_queue.pop_back() {
|
if let Some(generic_packet) = self.incoming_packet_queue.pop_back() {
|
||||||
if let Ok(packet) = TryInto::<P>::try_into(generic_packet.clone()) {
|
if let Ok(packet) = TryInto::<P>::try_into(generic_packet.clone()) {
|
||||||
Some(Ok(packet))
|
Some(Ok(packet))
|
||||||
@ -181,7 +185,7 @@ impl NetworkClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn queue_packet<P: std::fmt::Debug + Into<GenericPacket>>(&mut self, packet: P) {
|
pub fn queue_packet<P: std::fmt::Debug + Into<Packet>>(&mut self, packet: P) {
|
||||||
self.outgoing_packet_queue.push_back(packet.into());
|
self.outgoing_packet_queue.push_back(packet.into());
|
||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
@ -195,11 +199,11 @@ impl NetworkClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn send_packet<P: std::fmt::Debug + Into<GenericPacket>>(
|
pub async fn send_packet<P: std::fmt::Debug + Into<Packet>>(
|
||||||
&self,
|
&self,
|
||||||
packet: P,
|
packet: P,
|
||||||
) -> tokio::io::Result<()> {
|
) -> tokio::io::Result<()> {
|
||||||
let packet: GenericPacket = packet.into();
|
let packet: Packet = packet.into();
|
||||||
|
|
||||||
debug!("Sending packet {:?} to client {}", packet, self.id);
|
debug!("Sending packet {:?} to client {}", packet, self.id);
|
||||||
let (packet_id, mut packet_body) = packet.serialize();
|
let (packet_id, mut packet_body) = packet.serialize();
|
||||||
@ -219,7 +223,8 @@ impl NetworkClient {
|
|||||||
}
|
}
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn disconnect(&mut self, reason: Option<crate::protocol::types::Chat>) {
|
pub async fn disconnect(&mut self, reason: Option<crate::protocol::types::Chat>) {
|
||||||
use crate::protocol::packets::clientbound::{CL00Disconnect, CP17Disconnect};
|
use packets::{login::clientbound::LoginDisconnect, play::clientbound::PlayDisconnect};
|
||||||
|
|
||||||
let reason = reason.unwrap_or(serde_json::json!({
|
let reason = reason.unwrap_or(serde_json::json!({
|
||||||
"text": "You have been disconnected!"
|
"text": "You have been disconnected!"
|
||||||
}));
|
}));
|
||||||
@ -229,10 +234,10 @@ impl NetworkClient {
|
|||||||
// Impossible to send a disconnect in these states.
|
// Impossible to send a disconnect in these states.
|
||||||
}
|
}
|
||||||
ClientState::Login => {
|
ClientState::Login => {
|
||||||
let _ = self.send_packet(CL00Disconnect { reason }).await;
|
let _ = self.send_packet(LoginDisconnect { reason }).await;
|
||||||
}
|
}
|
||||||
ClientState::Play => {
|
ClientState::Play => {
|
||||||
let _ = self.send_packet(CP17Disconnect { reason }).await;
|
let _ = self.send_packet(PlayDisconnect { reason }).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user