Add field custom encoder decoder support

This commit is contained in:
vagola 2020-01-03 18:31:44 +03:00
parent 0a0500239b
commit 61fff6fcf7
4 changed files with 104 additions and 15 deletions

View File

@ -5,6 +5,7 @@ use proc_macro2::Ident;
use proc_macro2::TokenStream as TokenStream2;
use quote::{quote, TokenStreamExt};
use std::iter::FromIterator;
use syn::export::Span;
use syn::{parse_macro_input, Data, DeriveInput, Field, Fields, Lit, Meta, NestedMeta};
#[proc_macro_derive(Packet, attributes(packet))]
@ -34,11 +35,22 @@ fn impl_encoder_trait(name: &Ident, fields: &Fields) -> TokenStream2 {
let name = &field.ident;
let unparsed_meta = get_packet_field_meta(field);
let parsed_meta = parse_field_meta(&unparsed_meta);
let parsed_meta = parse_packet_field_meta(&unparsed_meta);
match parsed_meta.module {
Some(module) => {
let module_ident = Ident::new(&module, Span::call_site());
quote! {
crate::#module_ident::encode(&self.#name, writer)?;
}
}
None => {
quote! {
crate::Encoder::encode(&self.#name, writer)?;
}
}
}
});
quote! {
@ -76,7 +88,7 @@ struct PacketFieldMeta {
max_length: Option<u16>,
}
fn parse_field_meta(meta_list: &Vec<NestedMeta>) -> PacketFieldMeta {
fn parse_packet_field_meta(meta_list: &Vec<NestedMeta>) -> PacketFieldMeta {
let mut module = None;
let mut max_length = None;

View File

@ -8,9 +8,6 @@ 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;
pub enum GameServerBoundPacket {
ServerBoundChatMessage(ServerBoundChatMessage),
ServerBoundKeepAlive(ServerBoundKeepAlive),
@ -87,6 +84,7 @@ impl GameClientBoundPacket {
#[derive(Packet, Debug)]
pub struct ServerBoundChatMessage {
#[packet(max_length = 256)]
pub message: String,
}
@ -127,8 +125,10 @@ pub struct JoinGame {
pub game_mode: GameMode,
pub dimension: i32,
pub max_players: u8,
#[packet(max_length = 16)]
pub level_type: String,
pub view_distance: u8,
#[packet(with = "var_int")]
pub view_distance: i32,
pub reduced_debug_info: bool,
}
@ -150,7 +150,7 @@ impl JoinGame {
dimension: i32,
max_players: u8,
level_type: String,
view_distance: u8,
view_distance: i32,
reduced_debug_info: bool,
) -> GameClientBoundPacket {
let join_game = JoinGame {
@ -198,6 +198,7 @@ pub struct ChunkData {
pub x: i32,
pub z: i32,
pub full: bool,
#[packet(with = "var_int")]
pub primary_mask: i32,
pub heights: CompoundTag,
pub data: Vec<u8>,

View File

@ -24,8 +24,9 @@ pub mod status;
/// Current supported protocol version.
pub const PROTOCOL_VERSION: u32 = 498;
/// String maximum length.
/// Protocol limits maximum string length.
const STRING_MAX_LENGTH: u32 = 32_768;
const HYPHENATED_UUID_LENGTH: u32 = 36;
/// Possible errors while encoding packet.
#[derive(Debug)]
@ -477,3 +478,76 @@ macro_rules! impl_json_encoder_decoder (
}
);
);
mod var_int {
use crate::{DecodeError, EncodeError, Encoder};
use mc_varint::{VarIntRead, VarIntWrite};
use std::io::{Read, Write};
pub fn encode<W: Write>(value: &i32, writer: &mut W) -> Result<(), EncodeError> {
writer.write_var_i32(*value)?;
Ok(())
}
pub fn decode<R: Read>(reader: &mut R) -> Result<i32, DecodeError> {
Ok(reader.read_var_i32()?)
}
}
mod var_long {
use crate::{DecodeError, EncodeError, Encoder};
use mc_varint::{VarIntRead, VarIntWrite};
use std::io::{Read, Write};
pub fn encode<W: Write>(value: &i64, writer: &mut W) -> Result<(), EncodeError> {
writer.write_var_i64(*value)?;
Ok(())
}
pub fn decode<R: Read>(reader: &mut R) -> Result<i64, DecodeError> {
Ok(reader.read_var_i64()?)
}
}
mod rest {
use crate::{DecodeError, Decoder, EncodeError, Encoder};
use std::io::{Read, Write};
pub fn encode<W: Write>(value: &[u8], writer: &mut W) -> Result<(), EncodeError> {
writer.write_all(value)?;
Ok(())
}
pub fn decode<R: Read>(reader: &mut R) -> Result<Vec<u8>, DecodeError> {
let mut data = Vec::new();
reader.read_to_end(data.as_mut())?;
Ok(data)
}
}
mod uuid_hyp_str {
use crate::{
DecodeError, Decoder, DecoderReadExt, EncodeError, Encoder, EncoderWriteExt,
HYPHENATED_UUID_LENGTH,
};
use std::io::{Read, Write};
use uuid::Uuid;
pub fn encode<W: Write>(value: &Uuid, writer: &mut W) -> Result<(), EncodeError> {
let uuid_hyphenated_string = value.to_hyphenated().to_string();
writer.write_string(&uuid_hyphenated_string, HYPHENATED_UUID_LENGTH)?;
Ok(())
}
pub fn decode<R: Read>(reader: &mut R) -> Result<Uuid, DecodeError> {
let uuid_hyphenated_string = reader.read_string(HYPHENATED_UUID_LENGTH)?;
let uuid = Uuid::parse_str(&uuid_hyphenated_string)?;
Ok(uuid)
}
}

View File

@ -6,10 +6,6 @@ use uuid::Uuid;
use minecraft_protocol_derive::Packet;
const LOGIN_MAX_LENGTH: u32 = 16;
const SERVER_ID_MAX_LENGTH: u32 = 20;
const HYPHENATED_UUID_LENGTH: u32 = 36;
pub enum LoginServerBoundPacket {
LoginStart(LoginStart),
EncryptionResponse(EncryptionResponse),
@ -138,8 +134,10 @@ impl EncryptionResponse {
#[derive(Packet, Debug)]
pub struct LoginPluginResponse {
#[packet(with = "var_int")]
pub message_id: i32,
pub successful: bool,
#[packet(with = "rest")]
pub data: Vec<u8>,
}
@ -194,7 +192,9 @@ impl EncryptionRequest {
#[derive(Packet, Debug)]
pub struct LoginSuccess {
#[packet(with = "uuid_hyp_str")]
pub uuid: Uuid,
#[packet(max_length = 16)]
pub username: String,
}
@ -208,7 +208,7 @@ impl LoginSuccess {
#[derive(Packet, Debug)]
pub struct SetCompression {
#[packet(with = "varint")]
#[packet(with = "var_int")]
pub threshold: i32,
}
@ -222,8 +222,10 @@ impl SetCompression {
#[derive(Packet, Debug)]
pub struct LoginPluginRequest {
#[packet(with = "var_int")]
pub message_id: i32,
pub channel: String,
#[packet(with = "rest")]
pub data: Vec<u8>,
}