From f3f5de64ac10a63a8d147f48332849d6bb872c79 Mon Sep 17 00:00:00 2001 From: Kyler <59854022+KylerOlsen@users.noreply.github.com> Date: Sun, 24 Dec 2023 19:45:54 -0700 Subject: [PATCH] Started Macros --- Cargo.lock | 26 +++- Cargo.toml | 1 + purple_cello_mc_protocol_derive/src/lib.rs | 157 +++++++++++++++++++++ src/handshake.rs | 53 +++---- src/lib.rs | 6 +- src/login.rs | 12 +- src/mc_types.rs | 95 ++++++------- src/status.rs | 8 +- 8 files changed, 263 insertions(+), 95 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 987b558..b2bd383 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,7 +25,7 @@ checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.42", ] [[package]] @@ -198,11 +198,20 @@ name = "purple_cello_mc_protocol" version = "0.1.0" dependencies = [ "async-trait", + "purple_cello_mc_protocol_derive", "serde", "serde_json", "tokio", ] +[[package]] +name = "purple_cello_mc_protocol_derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "quote" version = "1.0.33" @@ -256,7 +265,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.42", ] [[package]] @@ -295,6 +304,17 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.42" @@ -333,7 +353,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.42", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 80b7900..e220db2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,4 @@ tokio = { version = "1", features = ["full"] } serde = { version = "1", features = ["derive"] } serde_json = "1" async-trait = "0.1.75" +purple_cello_mc_protocol_derive = { path = "./purple_cello_mc_protocol_derive" } diff --git a/purple_cello_mc_protocol_derive/src/lib.rs b/purple_cello_mc_protocol_derive/src/lib.rs index e69de29..ce55fd8 100644 --- a/purple_cello_mc_protocol_derive/src/lib.rs +++ b/purple_cello_mc_protocol_derive/src/lib.rs @@ -0,0 +1,157 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput}; + +#[proc_macro_derive(Packet)] +pub fn packet_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let struct_name = &input.ident; + + if let Data::Struct(DataStruct { fields, .. }) = &input.data { + let field_names: Vec<_> = fields + .iter() + .map(|field| field.ident.as_ref().unwrap()) + .collect(); + let field_types: Vec<_> = fields + .iter() + .map(|field| &field.ty) + .collect(); + + // let get_code = quote! { + // Ok(Self { + // #( #field_names: #{ + // let data_fn = #{ + // let field_ty_str = stringify!(#field_types).replace(" ", ""); + // TYPE_FUNCTION_GET_MAPPING + // .iter() + // .find(|(ty, _)| field_ty_str.contains(*ty)) + // .map(|(_, fn_name)| fn_name) + // .unwrap_or_else(|| panic!("Unknown type: {}", field_ty_str)) + // }; + // let fn_ident = syn::Ident::new(data_fn, proc_macro2::Span::call_site()); + // quote! { #fn_ident(data)? } + // }, )* + // }) + // }; + + // let convert_code = quote! { + // let mut data: Vec = vec![]; + // data.append(&mut mc_types::convert_var_int(Self::packet_id())); + // #( data.append(&mut #{ + // let data_fn = #{ + // let field_ty_str = stringify!(#field_types).replace(" ", ""); + // TYPE_FUNCTION_CONVERT_MAPPING + // .iter() + // .find(|(ty, _)| field_ty_str.contains(*ty)) + // .map(|(_, fn_name)| fn_name) + // .unwrap_or_else(|| panic!("Unknown type: {}", field_ty_str)) + // }; + // let fn_ident = syn::Ident::new(data_fn, proc_macro2::Span::call_site()); + // quote! { #fn_ident(self.#field_names) } + // }); )* + // }; + + let type_function_get_mapping: Vec<(&str, &str)> = vec![ + ("Boolean", "mc_types::get_boolean"), + ("Byte", "mc_types::get_byte"), + ("UnsignedByte", "mc_types::get_unsigned_byte"), + ("Short", "mc_types::get_short"), + ("UnsignedShort", "mc_types::get_unsigned_short"), + ("Int", "mc_types::get_int"), + ("Long", "mc_types::get_long"), + ("Float", "mc_types::get_float"), + ("Double", "mc_types::get_double"), + ("String", "mc_types::get_string"), + ("Json", "mc_types::get_string"), + ("Identifier", "mc_types::get_string"), + ("VarInt", "mc_types::get_var_int"), + ("VarLong", "mc_types::get_var_long"), + ("Position", "mc_types::get_position"), + ("Angle", "mc_types::get_unsigned_short"), + ("Uuid", "mc_types::get_uuid"), + ("ByteArray", "mc_types::get_byte_array"), + ]; + + let type_function_convert_mapping: Vec<(&str, &str)> = vec![ + ("Boolean", "mc_types::convert_boolean"), + ("Byte", "mc_types::convert_byte"), + ("UnsignedByte", "mc_types::convert_unsigned_byte"), + ("Short", "mc_types::convert_short"), + ("UnsignedShort", "mc_types::convert_unsigned_short"), + ("Int", "mc_types::convert_int"), + ("Long", "mc_types::convert_long"), + ("Float", "mc_types::convert_float"), + ("Double", "mc_types::convert_double"), + ("String", "mc_types::convert_string"), + ("Json", "mc_types::convert_string"), + ("Identifier", "mc_types::convert_string"), + ("VarInt", "mc_types::convert_var_int"), + ("VarLong", "mc_types::convert_var_long"), + ("Position", "mc_types::convert_position"), + ("Angle", "mc_types::convert_unsigned_short"), + ("Uuid", "mc_types::convert_uuid"), + ("ByteArray", "mc_types::convert_byte_array"), + ]; + + let get_code = { + let field_code: Vec<_> = field_names.iter().zip(field_types.iter()).map(|(name, ty)| { + let data_fn = { + let field_ty_str = stringify!(#ty).replace(" ", ""); + type_function_get_mapping + .iter() + .find(|(ty, _)| field_ty_str.contains(*ty)) + .map(|(_, fn_name)| fn_name) + .unwrap_or_else(|| panic!("Unknown type: {}", field_ty_str)) + }; + quote! { #name: #data_fn(data)?, } + }).collect::>(); + + quote! { + Ok(Self { + #( #field_code )* + }) + } + }; + + let convert_code = { + let field_code: Vec<_> = field_names.iter().zip(field_types.iter()).map(|(name, ty)| { + let data_fn = { + let field_ty_str = stringify!(#ty).replace(" ", ""); + type_function_convert_mapping + .iter() + .find(|(ty, _)| field_ty_str.contains(*ty)) + .map(|(_, fn_name)| fn_name) + .unwrap_or_else(|| panic!("Unknown type: {}", field_ty_str)) + }; + quote! { mc_types::#data_fn(self.#name), } + }).collect::>(); + + quote! { + let mut data: Vec = vec![]; + data.append(&mut mc_types::convert_var_int(Self::packet_id())); + #( data.append(&mut #field_code );)* + data + } + }; + + let gen = quote! { + impl Packet for #struct_name { + fn packet_id() -> i32 { 0 } + + fn get(data: &mut Vec) -> Result { + #get_code + } + + fn convert(&self) -> Vec { + #convert_code + } + } + }; + + return gen.into(); + } + + TokenStream::from(quote! { + compile_error!("Packet derive macro only supports named structs"); + }) +} diff --git a/src/handshake.rs b/src/handshake.rs index 8537dfb..f564cd8 100644 --- a/src/handshake.rs +++ b/src/handshake.rs @@ -4,7 +4,8 @@ pub mod serverbound { use tokio::net::tcp::OwnedReadHalf; - use crate::mc_types::{self, Result, Packet, PacketError}; + use crate::mc_types::{self, Result, Packet, PacketError, MCTypes}; + use purple_cello_mc_protocol_derive::packet_derive; pub enum HandshakeEnum { Handshake(Handshake), @@ -22,36 +23,38 @@ pub mod serverbound { } } + #[derive(packet_derive)] pub struct Handshake { - pub protocol_version: i32, - pub server_address: String, - pub server_port: u16, - pub next_state: i32, + pub protocol_version: MCTypes::VarInt, + pub server_address: MCTypes::String, + pub server_port: MCTypes::UnsignedShort, + pub next_state: MCTypes::VarInt, } - impl Packet for Handshake { + // impl Packet for Handshake { - fn packet_id() -> i32 {0} + // fn packet_id() -> i32 {0} - fn get(data: &mut Vec) -> Result { - Ok(Self { - protocol_version: mc_types::get_var_int(data)?, - server_address: mc_types::get_string(data)?, - server_port: mc_types::get_u16(data), - next_state: mc_types::get_var_int(data)?, - }) - } + // fn get(data: &mut Vec) -> Result { + // Ok(Self { + // protocol_version: mc_types::get_var_int(data)?, + // server_address: mc_types::get_string(data)?, + // server_port: mc_types::get_unsigned_short(data)?, + // next_state: mc_types::get_var_int(data)?, + // }) + // } - fn convert(&self) -> Vec { - let mut data: Vec = vec![]; - data.append(&mut mc_types::convert_var_int(Self::packet_id())); - data.append(&mut mc_types::convert_var_int(self.protocol_version)); - data.append(&mut mc_types::convert_string(&self.server_address)); - data.append(&mut mc_types::convert_u16(self.server_port)); - data.append(&mut mc_types::convert_var_int(self.next_state)); + // fn convert(&self) -> Vec { + // let mut data: Vec = vec![]; + // data.append(&mut mc_types::convert_var_int(Self::packet_id())); + // data.append(&mut mc_types::convert_var_int(self.protocol_version)); + // data.append(&mut mc_types::convert_string(&self.server_address)); + // data.append( + // &mut mc_types::convert_unsigned_short(self.server_port)); + // data.append(&mut mc_types::convert_var_int(self.next_state)); - data - } + // data + // } - } + // } } diff --git a/src/lib.rs b/src/lib.rs index 53d2ac1..b64644a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ // Yeahbut December 2023 pub mod mc_types; -// pub mod handshake; -// pub mod status; -// pub mod login; +pub mod handshake; +pub mod status; +pub mod login; diff --git a/src/login.rs b/src/login.rs index 95048aa..2d4bc42 100644 --- a/src/login.rs +++ b/src/login.rs @@ -4,7 +4,7 @@ pub mod clientbound { use tokio::net::tcp::OwnedReadHalf; - use crate::mc_types::{self, Result, Packet, PacketArray, PacketError}; + use crate::mc_types::{self, Result, Packet, MCTypeArray, PacketError}; pub enum Login { Disconnect(Disconnect), @@ -97,7 +97,7 @@ pub mod clientbound { fn get(mut data: &mut Vec) -> Result { Ok(Self { - uuid: mc_types::get_uuid(&mut data), + uuid: mc_types::get_uuid(&mut data)?, username: mc_types::get_string(&mut data)?, properties: LoginSuccessProperty::get_array(&mut data)?, }) @@ -132,12 +132,12 @@ pub mod clientbound { } } - impl PacketArray for LoginSuccessProperty { + impl MCTypeArray for LoginSuccessProperty { fn get(mut data: &mut Vec) -> Result { let name = mc_types::get_string(&mut data)?; let value = mc_types::get_string(&mut data)?; - let is_signed = mc_types::get_bool(&mut data); + let is_signed = mc_types::get_boolean(&mut data)?; let mut signature: Option = None; if is_signed { signature = Some(mc_types::get_string(&mut data)?); @@ -155,10 +155,10 @@ pub mod clientbound { data.append(&mut mc_types::convert_string(&self.value)); match &self.signature { Some(value) => { - data.append(&mut &mut mc_types::convert_bool(true)); + data.append(&mut &mut mc_types::convert_boolean(true)); data.append(&mut mc_types::convert_string(&value)); }, - None => data.append(&mut &mut mc_types::convert_bool(false)) + None => data.append(&mut &mut mc_types::convert_boolean(false)) } data diff --git a/src/mc_types.rs b/src/mc_types.rs index c8139d8..9fe3ae3 100644 --- a/src/mc_types.rs +++ b/src/mc_types.rs @@ -109,6 +109,25 @@ async fn read_var_int_stream(stream: &mut OwnedReadHalf) -> Result { // enum MCTypes +// pub enum MCTypes { +// Boolean, +// Byte, +// UnsignedByte, +// Short, +// UnsignedShort, +// Int, +// Long, +// Float, +// Double, +// String, +// VarInt, +// VarLong, +// Uuid, +// Optional, +// Array, +// ByteArray, +// } + pub enum MCTypes { Boolean, Byte, @@ -131,8 +150,8 @@ pub enum MCTypes { Position, Angle, Uuid, - Optional, - Array, + // Optional, + // Array, // Enum, ByteArray, } @@ -278,24 +297,6 @@ pub fn convert_string(s: &str) -> Vec { // convert_nbt_tag(value) // } -// fn get_json_chat <- string -pub fn get_json_chat(data: &mut Vec) -> Result { - get_string(data) -} -// fn convert_json_chat <- string -pub fn convert_json_chat(value: String) -> Vec { - convert_string(value) -} - -// fn get_identifier <- string -pub fn get_identifier(data: &mut Vec) -> Result { - get_string(data) -} -// fn convert_identifier <- string -pub fn convert_identifier(value: String) -> Vec { - convert_string(value) -} - // fn get_var_int pub fn get_var_int(data: &mut Vec) -> Result { Ok(get_var(data, 32)? as i32) @@ -374,48 +375,34 @@ pub struct MCPosition { z: i32, y: i16, } - -impl MCPosition { - - // fn get_position - pub fn get(data: &mut Vec) -> Result { - let pos = get_long(data)?; - Ok(MCPosition { - x: (pos >> 38) as i32, - z: (pos << 26 >> 38) as i32, - y: (pos << 52 >> 52) as i16, - }) - } - // fn convert_position - pub fn convert(&self) -> Vec { - let pos: u64 = - ((self.x as u64 & 0x3FFFFFF) << 38) | - ((self.z as u64 & 0x3FFFFFF) << 12) | - (self.y as u64 & 0xFFF); - convert_long(pos as i64) - } - +// fn get_position +pub fn get_position(data: &mut Vec) -> Result { + let pos = get_long(data)?; + Ok(MCPosition { + x: (pos >> 38) as i32, + z: (pos << 26 >> 38) as i32, + y: (pos << 52 >> 52) as i16, + }) } - -// fn get_angle <- u8 -pub fn get_angle(data: &mut Vec) -> Result { - get_unsigned_byte(data) -} -// fn convert_angle <- u8 -pub fn convert_angle(value: u8) -> Vec { - convert_unsigned_byte(value) +// fn convert_position +pub fn convert_position(value: MCPosition) -> Vec { + let pos: u64 = + ((value.x as u64 & 0x3FFFFFF) << 38) | + ((value.z as u64 & 0x3FFFFFF) << 12) | + (value.y as u64 & 0xFFF); + convert_long(pos as i64) } // fn get_uuid -pub fn get_uuid(data: &mut Vec) -> Result { - if data.len() < std::mem::size_of::() { +pub fn get_uuid(data: &mut Vec) -> Result { + if data.len() < std::mem::size_of::() { return Err(Box::new(PacketError::RanOutOfBytes)) } - Ok(i128::from_be_bytes( - data.drain(0..std::mem::size_of::()).as_slice().try_into()?)) + Ok(u128::from_be_bytes( + data.drain(0..std::mem::size_of::()).as_slice().try_into()?)) } // fn convert_uuid -pub fn convert_uuid(value: i128) -> Vec { +pub fn convert_uuid(value: u128) -> Vec { value.to_be_bytes().to_vec() } diff --git a/src/status.rs b/src/status.rs index efec893..f009063 100644 --- a/src/status.rs +++ b/src/status.rs @@ -107,14 +107,14 @@ pub mod clientbound { fn get(mut data: &mut Vec) -> Result { Ok(Self { - payload: mc_types::get_i64(&mut data) + payload: mc_types::get_long(&mut data)? }) } fn convert(&self) -> Vec { let mut data: Vec = vec![]; data.append(&mut mc_types::convert_var_int(Self::packet_id())); - data.append(&mut mc_types::convert_i64(self.payload)); + data.append(&mut mc_types::convert_long(self.payload)); data } @@ -177,14 +177,14 @@ pub mod serverbound { fn get(mut data: &mut Vec) -> Result { Ok(Self { - payload: mc_types::get_i64(&mut data) + payload: mc_types::get_long(&mut data)? }) } fn convert(&self) -> Vec { let mut data: Vec = vec![]; data.append(&mut mc_types::convert_var_int(Self::packet_id())); - data.append(&mut mc_types::convert_i64(self.payload)); + data.append(&mut mc_types::convert_long(self.payload)); data }