diff --git a/protocol-derive/Cargo.toml b/protocol-derive/Cargo.toml index 458b140..0d689e2 100644 --- a/protocol-derive/Cargo.toml +++ b/protocol-derive/Cargo.toml @@ -10,5 +10,7 @@ publish = false proc-macro = true [dependencies] -syn = "1.0" -quote = "1.0" +# Versions match serde crate to reduce compile time. +proc-macro2 = "0.4.30" +syn = "0.15.44" +quote = "0.6.13" diff --git a/protocol-derive/src/lib.rs b/protocol-derive/src/lib.rs index cba3466..1d416ac 100644 --- a/protocol-derive/src/lib.rs +++ b/protocol-derive/src/lib.rs @@ -1,27 +1,80 @@ extern crate proc_macro; -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput}; +use proc_macro::TokenStream as TokenStream1; +use proc_macro2::Ident; +use proc_macro2::TokenStream as TokenStream2; +use quote::{quote, TokenStreamExt}; +use syn::{parse_macro_input, Data, DeriveInput, Field, Fields}; #[proc_macro_derive(Packet)] -pub fn derive_packet(input: TokenStream) -> TokenStream { +pub fn derive_packet(input: proc_macro::TokenStream) -> TokenStream1 { let input = parse_macro_input!(input as DeriveInput); - let name = input.ident; + let name = &input.ident; - let output = quote! { - impl crate::PacketParser for #name { - type Output = Self; + match input.data { + Data::Struct(data) => { + let fields = &data.fields; - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - todo!(); - } + let encoder = impl_encoder_trait(name, fields); + let decoder = impl_decoder_trait(name, fields); - fn decode(reader: &mut R) -> Result { - todo!(); + TokenStream1::from(quote! { + #encoder + + #decoder + }) + } + _ => panic!("Packet derive are available only for structures"), + } +} + +fn impl_encoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { + let encode = quote_field(fields, |field| { + let name = &field.ident; + + quote! { + Encoder::encode(&self.#name, writer); + } + }); + + quote! { + impl crate::Encoder for #name { + fn encode(&self, writer: &mut W) -> Result<(), crate::EncodeError> { + #encode + + Ok(()) } } - }; - - TokenStream::from(output) + } +} + +fn impl_decoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 { + let decode = quote_field(fields, |field| { + quote! { + todo!(); + } + }); + + quote! { + impl crate::Decoder for #name { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + #decode + } + } + } +} + +fn quote_field TokenStream2>(fields: &Fields, func: F) -> TokenStream2 { + let mut output = quote!(); + + match fields { + Fields::Named(named_fields) => { + output.append_all(named_fields.named.iter().map(|f| func(f))) + } + _ => panic!("Packet derive are available only for named fields"), + } + + output } diff --git a/protocol/src/game.rs b/protocol/src/game.rs index fc8efe4..298fa18 100644 --- a/protocol/src/game.rs +++ b/protocol/src/game.rs @@ -1,12 +1,12 @@ -use std::io::{Read, Write}; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use num_derive::{FromPrimitive, ToPrimitive}; use crate::chat::Message; -use crate::{DecodeError, EncodeError, PacketParser, PacketRead, PacketWrite}; -use mc_varint::{VarIntRead, VarIntWrite}; +use crate::DecodeError; +use crate::Decoder; +use crate::Encoder; +use minecraft_protocol_derive::Packet; use nbt::CompoundTag; +use std::io::Read; const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256; const LEVEL_TYPE_MAX_LENGTH: u32 = 16; @@ -85,6 +85,7 @@ impl GameClientBoundPacket { } } +#[derive(Packet, Debug)] pub struct ServerBoundChatMessage { pub message: String, } @@ -97,20 +98,7 @@ impl ServerBoundChatMessage { } } -impl PacketParser for ServerBoundChatMessage { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_string(&self.message, SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH) - } - - fn decode(reader: &mut R) -> Result { - let message = reader.read_string(SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH)?; - - Ok(ServerBoundChatMessage { message }) - } -} - +#[derive(Packet, Debug)] pub struct ClientBoundChatMessage { pub message: Message, pub position: MessagePosition, @@ -131,27 +119,7 @@ impl ClientBoundChatMessage { } } -impl PacketParser for ClientBoundChatMessage { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_chat_message(&self.message)?; - writer.write_enum(&self.position)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let message = reader.read_chat_message()?; - let position = reader.read_enum()?; - - let chat_message = ClientBoundChatMessage { message, position }; - - Ok(chat_message) - } -} - -#[derive(Debug)] +#[derive(Packet, Debug)] pub struct JoinGame { pub entity_id: u32, pub game_mode: GameMode, @@ -195,42 +163,7 @@ impl JoinGame { } } -impl PacketParser for JoinGame { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_u32::(self.entity_id)?; - writer.write_enum(&self.game_mode)?; - writer.write_i32::(self.dimension)?; - writer.write_u8(self.max_players)?; - writer.write_string(&self.level_type, LEVEL_TYPE_MAX_LENGTH)?; - writer.write_var_i32(self.view_distance as i32)?; - writer.write_bool(self.reduced_debug_info)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let entity_id = reader.read_u32::()?; - let game_mode = reader.read_enum()?; - let dimension = reader.read_i32::()?; - let max_players = reader.read_u8()?; - let level_type = reader.read_string(LEVEL_TYPE_MAX_LENGTH)?; - let view_distance = reader.read_var_i32()? as u8; - let reduced_debug_info = reader.read_bool()?; - - Ok(JoinGame { - entity_id, - game_mode, - dimension, - max_players, - level_type, - view_distance, - reduced_debug_info, - }) - } -} - +#[derive(Packet)] pub struct ServerBoundKeepAlive { pub id: u64, } @@ -243,22 +176,7 @@ impl ServerBoundKeepAlive { } } -impl PacketParser for ServerBoundKeepAlive { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_u64::(self.id)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let id = reader.read_u64::()?; - - Ok(ServerBoundKeepAlive { id }) - } -} - +#[derive(Packet)] pub struct ClientBoundKeepAlive { pub id: u64, } @@ -271,22 +189,7 @@ impl ClientBoundKeepAlive { } } -impl PacketParser for ClientBoundKeepAlive { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_u64::(self.id)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let id = reader.read_u64::()?; - - Ok(ClientBoundKeepAlive { id }) - } -} - +#[derive(Packet, Debug)] pub struct ChunkData { pub x: i32, pub z: i32, @@ -321,53 +224,6 @@ impl ChunkData { } } -impl PacketParser for ChunkData { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_i32::(self.x)?; - writer.write_i32::(self.z)?; - writer.write_bool(self.full)?; - writer.write_var_i32(self.primary_mask)?; - writer.write_compound_tag(&self.heights)?; - writer.write_byte_array(&self.data)?; - writer.write_var_i32(self.tiles.len() as i32)?; - - for tile_compound_tag in self.tiles.iter() { - writer.write_compound_tag(&tile_compound_tag)?; - } - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let x = reader.read_i32::()?; - let z = reader.read_i32::()?; - let full = reader.read_bool()?; - let primary_mask = reader.read_var_i32()?; - let heights = reader.read_compound_tag()?; - let data = reader.read_byte_array()?; - - let tiles_length = reader.read_var_i32()?; - let mut tiles = Vec::new(); - - for _ in 0..tiles_length { - let tile_compound_tag = reader.read_compound_tag()?; - tiles.push(tile_compound_tag); - } - - Ok(ChunkData { - x, - z, - full, - primary_mask, - heights, - data, - tiles, - }) - } -} - #[cfg(test)] mod tests { use crate::chat::{Message, Payload}; @@ -375,7 +231,8 @@ mod tests { ChunkData, ClientBoundChatMessage, ClientBoundKeepAlive, GameMode, JoinGame, MessagePosition, ServerBoundChatMessage, ServerBoundKeepAlive, }; - use crate::PacketParser; + use crate::Decoder; + use crate::Encoder; use nbt::CompoundTag; use std::io::Cursor; diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index af20277..ec8bc98 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -6,8 +6,8 @@ use std::io; use std::io::{Read, Write}; use std::string::FromUtf8Error; -use byteorder::ReadBytesExt; use byteorder::WriteBytesExt; +use byteorder::{BigEndian, ReadBytesExt}; use mc_varint::{VarIntRead, VarIntWrite}; use serde_json::error::Error as JsonError; use uuid::parser::ParseError as UuidParseError; @@ -16,6 +16,8 @@ use crate::chat::Message; use nbt::decode::TagDecodeError; use nbt::CompoundTag; use num_traits::{FromPrimitive, ToPrimitive}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; pub mod chat; pub mod game; @@ -125,10 +127,12 @@ impl From for DecodeError { } } -trait PacketParser { - type Output; - +trait Encoder { fn encode(&self, writer: &mut W) -> Result<(), EncodeError>; +} + +trait Decoder { + type Output; fn decode(reader: &mut R) -> Result; } @@ -261,3 +265,208 @@ impl PacketWrite for W { Ok(()) } } + +// TODO: Replace primitive impls with macros. + +impl Encoder for u8 { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u8(*self)?) + } +} + +impl Decoder for u8 { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_u8()?) + } +} + +impl Encoder for i32 { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_i32::(*self)?) + } +} + +impl Decoder for i32 { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_i32::()?) + } +} + +impl Encoder for u32 { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u32::(*self)?) + } +} + +impl Decoder for u32 { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_u32::()?) + } +} + +impl Encoder for i64 { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_i64::(*self)?) + } +} + +impl Decoder for i64 { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_i64::()?) + } +} + +impl Encoder for u64 { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_u64::(*self)?) + } +} + +impl Decoder for u64 { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_u64::()?) + } +} + +impl Encoder for String { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_string(self, STRING_MAX_LENGTH)?) + } +} + +impl Decoder for String { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_string(STRING_MAX_LENGTH)?) + } +} + +impl Encoder for bool { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_bool(*self)?) + } +} + +impl Decoder for bool { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_bool()?) + } +} + +impl Encoder for T { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_enum(self)?) + } +} + +impl Decoder for T { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_enum()) + } +} + +impl Encoder for Vec { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_byte_array(self)?) + } +} + +impl Decoder for Vec { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_byte_array()?) + } +} + +impl Encoder for Uuid { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_all(self.as_bytes())?) + } +} + +impl Decoder for Uuid { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + let buf = [0; 16]; + reader.read_exact(&buf)?; + + Ok(Uuid::from_bytes(buf)) + } +} + +impl Encoder for CompoundTag { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + Ok(writer.write_compound_tag(self)?) + } +} + +impl Decoder for CompoundTag { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + Ok(reader.read_compound_tag()?) + } +} + +impl Encoder for Vec { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + writer.write_var_i32(self.len() as i32)?; + + for compound_tag in self { + writer.write_compound_tag(&compound_tag)?; + } + + Ok(()) + } +} + +impl Decoder for Vec { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + let length = reader.read_var_i32()? as usize; + let mut vec = Vec::with_capacity(length); + + for _ in 0..length { + let compound_tag = reader.read_compound_tag()?; + vec.push(compound_tag); + } + + Ok(vec) + } +} + +impl Encoder for T { + fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { + let json = serde_json::to_string(self)?; + writer.write_string(&json, STRING_MAX_LENGTH)?; + + Ok(()) + } +} + +impl<'de, T: Deserialize<'de>> Decoder for T { + type Output = Self; + + fn decode(reader: &mut R) -> Result { + let json = reader.read_string(STRING_MAX_LENGTH)?; + serde_json::from_str(&json)? + } +} diff --git a/protocol/src/login.rs b/protocol/src/login.rs index aed614a..e78130e 100644 --- a/protocol/src/login.rs +++ b/protocol/src/login.rs @@ -1,10 +1,11 @@ -use std::io::{Read, Write}; - -use mc_varint::{VarIntRead, VarIntWrite}; +use crate::chat::Message; +use crate::DecodeError; +use crate::Decoder; +use crate::Encoder; +use std::io::Read; use uuid::Uuid; -use crate::chat::Message; -use crate::{DecodeError, EncodeError, PacketParser, PacketRead, PacketWrite, STRING_MAX_LENGTH}; +use minecraft_protocol_derive::Packet; const LOGIN_MAX_LENGTH: u32 = 16; const SERVER_ID_MAX_LENGTH: u32 = 20; @@ -106,6 +107,7 @@ impl LoginClientBoundPacket { } } +#[derive(Packet, Debug)] pub struct LoginStart { pub name: String, } @@ -118,20 +120,7 @@ impl LoginStart { } } -impl PacketParser for LoginStart { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_string(&self.name, LOGIN_MAX_LENGTH) - } - - fn decode(reader: &mut R) -> Result { - let name = reader.read_string(LOGIN_MAX_LENGTH)?; - - Ok(LoginStart { name }) - } -} - +#[derive(Packet, Debug)] pub struct EncryptionResponse { pub shared_secret: Vec, pub verify_token: Vec, @@ -148,27 +137,7 @@ impl EncryptionResponse { } } -impl PacketParser for EncryptionResponse { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_byte_array(&self.shared_secret)?; - writer.write_byte_array(&self.verify_token)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let shared_secret = reader.read_byte_array()?; - let verify_token = reader.read_byte_array()?; - - Ok(EncryptionResponse { - shared_secret, - verify_token, - }) - } -} - +#[derive(Packet, Debug)] pub struct LoginPluginResponse { pub message_id: i32, pub successful: bool, @@ -187,32 +156,7 @@ impl LoginPluginResponse { } } -impl PacketParser for LoginPluginResponse { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i32(self.message_id)?; - writer.write_bool(self.successful)?; - writer.write_all(&self.data)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let message_id = reader.read_var_i32()?; - let successful = reader.read_bool()?; - - let mut data = Vec::new(); - reader.read_to_end(data.as_mut())?; - - Ok(LoginPluginResponse { - message_id, - successful, - data, - }) - } -} - +#[derive(Packet, Debug)] pub struct LoginDisconnect { pub reason: Message, } @@ -225,22 +169,7 @@ impl LoginDisconnect { } } -impl PacketParser for LoginDisconnect { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_chat_message(&self.reason)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let reason = reader.read_chat_message()?; - - Ok(LoginDisconnect { reason }) - } -} - +#[derive(Packet, Debug)] pub struct EncryptionRequest { pub server_id: String, pub public_key: Vec, @@ -263,30 +192,7 @@ impl EncryptionRequest { } } -impl PacketParser for EncryptionRequest { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_string(&self.server_id, SERVER_ID_MAX_LENGTH)?; - writer.write_byte_array(&self.public_key)?; - writer.write_byte_array(&self.verify_token)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let server_id = reader.read_string(SERVER_ID_MAX_LENGTH)?; - let public_key = reader.read_byte_array()?; - let verify_token = reader.read_byte_array()?; - - Ok(EncryptionRequest { - server_id, - public_key, - verify_token, - }) - } -} - +#[derive(Packet, Debug)] pub struct LoginSuccess { pub uuid: Uuid, pub username: String, @@ -300,28 +206,7 @@ impl LoginSuccess { } } -impl PacketParser for LoginSuccess { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - let uuid_hyphenated_string = self.uuid.to_hyphenated().to_string(); - - writer.write_string(&uuid_hyphenated_string, HYPHENATED_UUID_LENGTH)?; - writer.write_string(&self.username, LOGIN_MAX_LENGTH)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let uuid_hyphenated_string = reader.read_string(HYPHENATED_UUID_LENGTH)?; - - let uuid = Uuid::parse_str(&uuid_hyphenated_string)?; - let username = reader.read_string(LOGIN_MAX_LENGTH)?; - - Ok(LoginSuccess { uuid, username }) - } -} - +#[derive(Packet, Debug)] pub struct SetCompression { pub threshold: i32, } @@ -334,22 +219,7 @@ impl SetCompression { } } -impl PacketParser for SetCompression { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i32(self.threshold)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let threshold = reader.read_var_i32()?; - - Ok(SetCompression { threshold }) - } -} - +#[derive(Packet, Debug)] pub struct LoginPluginRequest { pub message_id: i32, pub channel: String, @@ -368,38 +238,14 @@ impl LoginPluginRequest { } } -impl PacketParser for LoginPluginRequest { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_var_i32(self.message_id)?; - writer.write_string(&self.channel, STRING_MAX_LENGTH)?; - writer.write_all(&self.data)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let message_id = reader.read_var_i32()?; - let channel = reader.read_string(STRING_MAX_LENGTH)?; - let mut data = Vec::new(); - reader.read_to_end(data.as_mut())?; - - Ok(LoginPluginRequest { - message_id, - channel, - data, - }) - } -} - #[cfg(test)] mod tests { use crate::chat::{Message, Payload}; use crate::login::{EncryptionRequest, LoginDisconnect, LoginPluginRequest, SetCompression}; use crate::login::{EncryptionResponse, LoginPluginResponse}; use crate::login::{LoginStart, LoginSuccess}; - use crate::PacketParser; + use crate::Decoder; + use crate::Encoder; use std::io::Cursor; use uuid::Uuid; diff --git a/protocol/src/status.rs b/protocol/src/status.rs index 8a5cacc..eddb865 100644 --- a/protocol/src/status.rs +++ b/protocol/src/status.rs @@ -1,11 +1,11 @@ -use std::io::{Read, Write}; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::chat::Message; -use crate::{DecodeError, EncodeError, PacketParser, PacketRead, PacketWrite, STRING_MAX_LENGTH}; +use crate::DecodeError; +use crate::Decoder; +use minecraft_protocol_derive::Packet; +use std::io::Read; pub enum StatusServerBoundPacket { StatusRequest, @@ -47,6 +47,7 @@ impl StatusClientBoundPacket { } } +#[derive(Packet, Debug)] pub struct PingRequest { pub time: u64, } @@ -59,22 +60,7 @@ impl PingRequest { } } -impl PacketParser for PingRequest { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_u64::(self.time)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let time = reader.read_u64::()?; - - Ok(PingRequest { time }) - } -} - +#[derive(Packet, Debug)] pub struct PingResponse { pub time: u64, } @@ -87,36 +73,20 @@ impl PingResponse { } } -impl PacketParser for PingResponse { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - writer.write_u64::(self.time)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let time = reader.read_u64::()?; - - Ok(PingResponse { time }) - } -} - -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct ServerStatus { pub version: ServerVersion, pub players: OnlinePlayers, pub description: Message, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct ServerVersion { pub name: String, pub protocol: u32, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub struct OnlinePlayers { pub max: u32, pub online: u32, @@ -129,6 +99,7 @@ pub struct OnlinePlayer { pub id: Uuid, } +#[derive(Packet, Debug)] pub struct StatusResponse { pub server_status: ServerStatus, } @@ -141,25 +112,6 @@ impl StatusResponse { } } -impl PacketParser for StatusResponse { - type Output = Self; - - fn encode(&self, writer: &mut W) -> Result<(), EncodeError> { - let json = serde_json::to_string(&self.server_status)?; - writer.write_string(&json, STRING_MAX_LENGTH)?; - - Ok(()) - } - - fn decode(reader: &mut R) -> Result { - let json = reader.read_string(STRING_MAX_LENGTH)?; - let server_status = serde_json::from_str(&json)?; - let status_response = StatusResponse { server_status }; - - Ok(status_response) - } -} - #[cfg(test)] mod tests { use crate::chat::{Message, Payload}; @@ -167,7 +119,8 @@ mod tests { OnlinePlayer, OnlinePlayers, PingRequest, PingResponse, ServerStatus, ServerVersion, StatusResponse, }; - use crate::PacketParser; + use crate::Decoder; + use crate::Encoder; use std::io::Cursor; use uuid::Uuid;