Save some progress towards derive macro

This commit is contained in:
vagola 2020-01-02 04:52:46 +03:00
parent d384ed2814
commit f43592c01f
6 changed files with 327 additions and 407 deletions

View File

@ -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"

View File

@ -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 {
match input.data {
Data::Struct(data) => {
let fields = &data.fields;
let encoder = impl_encoder_trait(name, fields);
let decoder = impl_decoder_trait(name, fields);
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<W: std::io::Write>(&self, writer: &mut W) -> Result<(), crate::EncodeError> {
#encode
Ok(())
}
}
}
}
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 encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
todo!();
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
todo!();
fn decode<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> {
#decode
}
}
}
};
TokenStream::from(output)
}
fn quote_field<F: Fn(&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
}

View File

@ -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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_string(&self.message, SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH)
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_chat_message(&self.message)?;
writer.write_enum(&self.position)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u32::<BigEndian>(self.entity_id)?;
writer.write_enum(&self.game_mode)?;
writer.write_i32::<BigEndian>(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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let entity_id = reader.read_u32::<BigEndian>()?;
let game_mode = reader.read_enum()?;
let dimension = reader.read_i32::<BigEndian>()?;
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u64::<BigEndian>(self.id)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let id = reader.read_u64::<BigEndian>()?;
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u64::<BigEndian>(self.id)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let id = reader.read_u64::<BigEndian>()?;
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_i32::<BigEndian>(self.x)?;
writer.write_i32::<BigEndian>(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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let x = reader.read_i32::<BigEndian>()?;
let z = reader.read_i32::<BigEndian>()?;
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;

View File

@ -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<TagDecodeError> for DecodeError {
}
}
trait PacketParser {
type Output;
trait Encoder {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError>;
}
trait Decoder {
type Output;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>;
}
@ -261,3 +265,208 @@ impl<W: Write> PacketWrite for W {
Ok(())
}
}
// TODO: Replace primitive impls with macros.
impl Encoder for u8 {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_u8(*self)?)
}
}
impl Decoder for u8 {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_u8()?)
}
}
impl Encoder for i32 {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_i32::<BigEndian>(*self)?)
}
}
impl Decoder for i32 {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_i32::<BigEndian>()?)
}
}
impl Encoder for u32 {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_u32::<BigEndian>(*self)?)
}
}
impl Decoder for u32 {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_u32::<BigEndian>()?)
}
}
impl Encoder for i64 {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_i64::<BigEndian>(*self)?)
}
}
impl Decoder for i64 {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_i64::<BigEndian>()?)
}
}
impl Encoder for u64 {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_u64::<BigEndian>(*self)?)
}
}
impl Decoder for u64 {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_u64::<BigEndian>()?)
}
}
impl Encoder for String {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_string(self, STRING_MAX_LENGTH)?)
}
}
impl Decoder for String {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_string(STRING_MAX_LENGTH)?)
}
}
impl Encoder for bool {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_bool(*self)?)
}
}
impl Decoder for bool {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_bool()?)
}
}
impl<T: ToPrimitive> Encoder for T {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_enum(self)?)
}
}
impl<T: ToPrimitive> Decoder for T {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_enum())
}
}
impl Encoder for Vec<u8> {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_byte_array(self)?)
}
}
impl Decoder for Vec<u8> {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_byte_array()?)
}
}
impl Encoder for Uuid {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_all(self.as_bytes())?)
}
}
impl Decoder for Uuid {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let buf = [0; 16];
reader.read_exact(&buf)?;
Ok(Uuid::from_bytes(buf))
}
}
impl Encoder for CompoundTag {
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
Ok(writer.write_compound_tag(self)?)
}
}
impl Decoder for CompoundTag {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
Ok(reader.read_compound_tag()?)
}
}
impl Encoder for Vec<CompoundTag> {
fn encode<W: Write>(&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<CompoundTag> {
type Output = Self;
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<T: Serialize> Encoder for T {
fn encode<W: Write>(&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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let json = reader.read_string(STRING_MAX_LENGTH)?;
serde_json::from_str(&json)?
}
}

View File

@ -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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_string(&self.name, LOGIN_MAX_LENGTH)
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let name = reader.read_string(LOGIN_MAX_LENGTH)?;
Ok(LoginStart { name })
}
}
#[derive(Packet, Debug)]
pub struct EncryptionResponse {
pub shared_secret: Vec<u8>,
pub verify_token: Vec<u8>,
@ -148,27 +137,7 @@ impl EncryptionResponse {
}
}
impl PacketParser for EncryptionResponse {
type Output = Self;
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_byte_array(&self.shared_secret)?;
writer.write_byte_array(&self.verify_token)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_chat_message(&self.reason)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let reason = reader.read_chat_message()?;
Ok(LoginDisconnect { reason })
}
}
#[derive(Packet, Debug)]
pub struct EncryptionRequest {
pub server_id: String,
pub public_key: Vec<u8>,
@ -263,30 +192,7 @@ impl EncryptionRequest {
}
}
impl PacketParser for EncryptionRequest {
type Output = Self;
fn encode<W: Write>(&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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_var_i32(self.threshold)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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<W: Write>(&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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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;

View File

@ -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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u64::<BigEndian>(self.time)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let time = reader.read_u64::<BigEndian>()?;
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<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
writer.write_u64::<BigEndian>(self.time)?;
Ok(())
}
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
let time = reader.read_u64::<BigEndian>()?;
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<W: Write>(&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<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
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;