Save some progress towards derive macro
This commit is contained in:
parent
d384ed2814
commit
f43592c01f
@ -10,5 +10,7 @@ publish = false
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syn = "1.0"
|
# Versions match serde crate to reduce compile time.
|
||||||
quote = "1.0"
|
proc-macro2 = "0.4.30"
|
||||||
|
syn = "0.15.44"
|
||||||
|
quote = "0.6.13"
|
||||||
|
@ -1,27 +1,80 @@
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream as TokenStream1;
|
||||||
use quote::quote;
|
use proc_macro2::Ident;
|
||||||
use syn::{parse_macro_input, DeriveInput};
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
|
use quote::{quote, TokenStreamExt};
|
||||||
|
use syn::{parse_macro_input, Data, DeriveInput, Field, Fields};
|
||||||
|
|
||||||
#[proc_macro_derive(Packet)]
|
#[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 input = parse_macro_input!(input as DeriveInput);
|
||||||
let name = input.ident;
|
let name = &input.ident;
|
||||||
|
|
||||||
let output = quote! {
|
match input.data {
|
||||||
impl crate::PacketParser for #name {
|
Data::Struct(data) => {
|
||||||
type Output = Self;
|
let fields = &data.fields;
|
||||||
|
|
||||||
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
|
let encoder = impl_encoder_trait(name, fields);
|
||||||
todo!();
|
let decoder = impl_decoder_trait(name, fields);
|
||||||
}
|
|
||||||
|
|
||||||
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError> {
|
TokenStream1::from(quote! {
|
||||||
todo!();
|
#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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
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<R: std::io::Read>(reader: &mut R) -> Result<Self::Output, crate::DecodeError> {
|
||||||
|
#decode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
|
||||||
use crate::chat::Message;
|
use crate::chat::Message;
|
||||||
use crate::{DecodeError, EncodeError, PacketParser, PacketRead, PacketWrite};
|
use crate::DecodeError;
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
use crate::Decoder;
|
||||||
|
use crate::Encoder;
|
||||||
|
use minecraft_protocol_derive::Packet;
|
||||||
use nbt::CompoundTag;
|
use nbt::CompoundTag;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256;
|
const SERVER_BOUND_CHAT_MESSAGE_MAX_LENGTH: u32 = 256;
|
||||||
const LEVEL_TYPE_MAX_LENGTH: u32 = 16;
|
const LEVEL_TYPE_MAX_LENGTH: u32 = 16;
|
||||||
@ -85,6 +85,7 @@ impl GameClientBoundPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Packet, Debug)]
|
||||||
pub struct ServerBoundChatMessage {
|
pub struct ServerBoundChatMessage {
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
@ -97,20 +98,7 @@ impl ServerBoundChatMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for ServerBoundChatMessage {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ClientBoundChatMessage {
|
pub struct ClientBoundChatMessage {
|
||||||
pub message: Message,
|
pub message: Message,
|
||||||
pub position: MessagePosition,
|
pub position: MessagePosition,
|
||||||
@ -131,27 +119,7 @@ impl ClientBoundChatMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for ClientBoundChatMessage {
|
#[derive(Packet, Debug)]
|
||||||
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)]
|
|
||||||
pub struct JoinGame {
|
pub struct JoinGame {
|
||||||
pub entity_id: u32,
|
pub entity_id: u32,
|
||||||
pub game_mode: GameMode,
|
pub game_mode: GameMode,
|
||||||
@ -195,42 +163,7 @@ impl JoinGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for JoinGame {
|
#[derive(Packet)]
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ServerBoundKeepAlive {
|
pub struct ServerBoundKeepAlive {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
}
|
}
|
||||||
@ -243,22 +176,7 @@ impl ServerBoundKeepAlive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for ServerBoundKeepAlive {
|
#[derive(Packet)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ClientBoundKeepAlive {
|
pub struct ClientBoundKeepAlive {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
}
|
}
|
||||||
@ -271,22 +189,7 @@ impl ClientBoundKeepAlive {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for ClientBoundKeepAlive {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ChunkData {
|
pub struct ChunkData {
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub z: 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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::chat::{Message, Payload};
|
use crate::chat::{Message, Payload};
|
||||||
@ -375,7 +231,8 @@ mod tests {
|
|||||||
ChunkData, ClientBoundChatMessage, ClientBoundKeepAlive, GameMode, JoinGame,
|
ChunkData, ClientBoundChatMessage, ClientBoundKeepAlive, GameMode, JoinGame,
|
||||||
MessagePosition, ServerBoundChatMessage, ServerBoundKeepAlive,
|
MessagePosition, ServerBoundChatMessage, ServerBoundKeepAlive,
|
||||||
};
|
};
|
||||||
use crate::PacketParser;
|
use crate::Decoder;
|
||||||
|
use crate::Encoder;
|
||||||
use nbt::CompoundTag;
|
use nbt::CompoundTag;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ use std::io;
|
|||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::string::FromUtf8Error;
|
use std::string::FromUtf8Error;
|
||||||
|
|
||||||
use byteorder::ReadBytesExt;
|
|
||||||
use byteorder::WriteBytesExt;
|
use byteorder::WriteBytesExt;
|
||||||
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
use mc_varint::{VarIntRead, VarIntWrite};
|
||||||
use serde_json::error::Error as JsonError;
|
use serde_json::error::Error as JsonError;
|
||||||
use uuid::parser::ParseError as UuidParseError;
|
use uuid::parser::ParseError as UuidParseError;
|
||||||
@ -16,6 +16,8 @@ use crate::chat::Message;
|
|||||||
use nbt::decode::TagDecodeError;
|
use nbt::decode::TagDecodeError;
|
||||||
use nbt::CompoundTag;
|
use nbt::CompoundTag;
|
||||||
use num_traits::{FromPrimitive, ToPrimitive};
|
use num_traits::{FromPrimitive, ToPrimitive};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub mod chat;
|
pub mod chat;
|
||||||
pub mod game;
|
pub mod game;
|
||||||
@ -125,10 +127,12 @@ impl From<TagDecodeError> for DecodeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PacketParser {
|
trait Encoder {
|
||||||
type Output;
|
|
||||||
|
|
||||||
fn encode<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError>;
|
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>;
|
fn decode<R: Read>(reader: &mut R) -> Result<Self::Output, DecodeError>;
|
||||||
}
|
}
|
||||||
@ -261,3 +265,208 @@ impl<W: Write> PacketWrite for W {
|
|||||||
Ok(())
|
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 crate::chat::Message;
|
||||||
|
use crate::DecodeError;
|
||||||
use mc_varint::{VarIntRead, VarIntWrite};
|
use crate::Decoder;
|
||||||
|
use crate::Encoder;
|
||||||
|
use std::io::Read;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::chat::Message;
|
use minecraft_protocol_derive::Packet;
|
||||||
use crate::{DecodeError, EncodeError, PacketParser, PacketRead, PacketWrite, STRING_MAX_LENGTH};
|
|
||||||
|
|
||||||
const LOGIN_MAX_LENGTH: u32 = 16;
|
const LOGIN_MAX_LENGTH: u32 = 16;
|
||||||
const SERVER_ID_MAX_LENGTH: u32 = 20;
|
const SERVER_ID_MAX_LENGTH: u32 = 20;
|
||||||
@ -106,6 +107,7 @@ impl LoginClientBoundPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Packet, Debug)]
|
||||||
pub struct LoginStart {
|
pub struct LoginStart {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
@ -118,20 +120,7 @@ impl LoginStart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for LoginStart {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EncryptionResponse {
|
pub struct EncryptionResponse {
|
||||||
pub shared_secret: Vec<u8>,
|
pub shared_secret: Vec<u8>,
|
||||||
pub verify_token: Vec<u8>,
|
pub verify_token: Vec<u8>,
|
||||||
@ -148,27 +137,7 @@ impl EncryptionResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for EncryptionResponse {
|
#[derive(Packet, Debug)]
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LoginPluginResponse {
|
pub struct LoginPluginResponse {
|
||||||
pub message_id: i32,
|
pub message_id: i32,
|
||||||
pub successful: bool,
|
pub successful: bool,
|
||||||
@ -187,32 +156,7 @@ impl LoginPluginResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for LoginPluginResponse {
|
#[derive(Packet, Debug)]
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LoginDisconnect {
|
pub struct LoginDisconnect {
|
||||||
pub reason: Message,
|
pub reason: Message,
|
||||||
}
|
}
|
||||||
@ -225,22 +169,7 @@ impl LoginDisconnect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for LoginDisconnect {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EncryptionRequest {
|
pub struct EncryptionRequest {
|
||||||
pub server_id: String,
|
pub server_id: String,
|
||||||
pub public_key: Vec<u8>,
|
pub public_key: Vec<u8>,
|
||||||
@ -263,30 +192,7 @@ impl EncryptionRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for EncryptionRequest {
|
#[derive(Packet, Debug)]
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LoginSuccess {
|
pub struct LoginSuccess {
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
@ -300,28 +206,7 @@ impl LoginSuccess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for LoginSuccess {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SetCompression {
|
pub struct SetCompression {
|
||||||
pub threshold: i32,
|
pub threshold: i32,
|
||||||
}
|
}
|
||||||
@ -334,22 +219,7 @@ impl SetCompression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for SetCompression {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct LoginPluginRequest {
|
pub struct LoginPluginRequest {
|
||||||
pub message_id: i32,
|
pub message_id: i32,
|
||||||
pub channel: String,
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::chat::{Message, Payload};
|
use crate::chat::{Message, Payload};
|
||||||
use crate::login::{EncryptionRequest, LoginDisconnect, LoginPluginRequest, SetCompression};
|
use crate::login::{EncryptionRequest, LoginDisconnect, LoginPluginRequest, SetCompression};
|
||||||
use crate::login::{EncryptionResponse, LoginPluginResponse};
|
use crate::login::{EncryptionResponse, LoginPluginResponse};
|
||||||
use crate::login::{LoginStart, LoginSuccess};
|
use crate::login::{LoginStart, LoginSuccess};
|
||||||
use crate::PacketParser;
|
use crate::Decoder;
|
||||||
|
use crate::Encoder;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use std::io::{Read, Write};
|
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::chat::Message;
|
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 {
|
pub enum StatusServerBoundPacket {
|
||||||
StatusRequest,
|
StatusRequest,
|
||||||
@ -47,6 +47,7 @@ impl StatusClientBoundPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Packet, Debug)]
|
||||||
pub struct PingRequest {
|
pub struct PingRequest {
|
||||||
pub time: u64,
|
pub time: u64,
|
||||||
}
|
}
|
||||||
@ -59,22 +60,7 @@ impl PingRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for PingRequest {
|
#[derive(Packet, Debug)]
|
||||||
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 })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PingResponse {
|
pub struct PingResponse {
|
||||||
pub time: u64,
|
pub time: u64,
|
||||||
}
|
}
|
||||||
@ -87,36 +73,20 @@ impl PingResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketParser for PingResponse {
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
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)]
|
|
||||||
pub struct ServerStatus {
|
pub struct ServerStatus {
|
||||||
pub version: ServerVersion,
|
pub version: ServerVersion,
|
||||||
pub players: OnlinePlayers,
|
pub players: OnlinePlayers,
|
||||||
pub description: Message,
|
pub description: Message,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct ServerVersion {
|
pub struct ServerVersion {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub protocol: u32,
|
pub protocol: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct OnlinePlayers {
|
pub struct OnlinePlayers {
|
||||||
pub max: u32,
|
pub max: u32,
|
||||||
pub online: u32,
|
pub online: u32,
|
||||||
@ -129,6 +99,7 @@ pub struct OnlinePlayer {
|
|||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Packet, Debug)]
|
||||||
pub struct StatusResponse {
|
pub struct StatusResponse {
|
||||||
pub server_status: ServerStatus,
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::chat::{Message, Payload};
|
use crate::chat::{Message, Payload};
|
||||||
@ -167,7 +119,8 @@ mod tests {
|
|||||||
OnlinePlayer, OnlinePlayers, PingRequest, PingResponse, ServerStatus, ServerVersion,
|
OnlinePlayer, OnlinePlayers, PingRequest, PingResponse, ServerStatus, ServerVersion,
|
||||||
StatusResponse,
|
StatusResponse,
|
||||||
};
|
};
|
||||||
use crate::PacketParser;
|
use crate::Decoder;
|
||||||
|
use crate::Encoder;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user