Save some progress towards derive macro
This commit is contained in:
parent
d384ed2814
commit
f43592c01f
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)?
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user