From 90f2270c7872fa808a56904de5a47b8633141883 Mon Sep 17 00:00:00 2001 From: Kyler Date: Sat, 13 Sep 2025 01:53:20 -0600 Subject: [PATCH] First macro --- purple_cello_mc_derive/src/lib.rs | 108 ++++++++++++++++++++++++++++++ src/handshake.rs | 56 +++------------- 2 files changed, 116 insertions(+), 48 deletions(-) diff --git a/purple_cello_mc_derive/src/lib.rs b/purple_cello_mc_derive/src/lib.rs index c626487..b89f595 100644 --- a/purple_cello_mc_derive/src/lib.rs +++ b/purple_cello_mc_derive/src/lib.rs @@ -1 +1,109 @@ // Yeahbut September 2025 + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, DeriveInput, Data, Fields, Meta, Lit}; + +#[proc_macro_derive(Packet, attributes(packet))] +pub fn derive_packet(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = &input.ident; + + let packet_id = input.attrs.iter().find_map(|attr| { + if attr.path.is_ident("packet") { + if let Ok(Meta::List(list)) = attr.parse_meta() { + for nested in list.nested.iter() { + if let syn::NestedMeta::Meta(Meta::NameValue(nv)) = nested { + if nv.path.is_ident("id") { + if let Lit::Int(litint) = &nv.lit { + return Some(litint.base10_parse::().unwrap()); + } + } + } + } + } + } + None + }).expect("Missing #[packet(id = …)] attribute"); + + let enum_variant = input.attrs.iter().find_map(|attr| { + if attr.path.is_ident("packet") { + if let Ok(Meta::List(list)) = attr.parse_meta() { + for nested in list.nested.iter() { + if let syn::NestedMeta::Meta(Meta::NameValue(nv)) = nested { + if nv.path.is_ident("name") { + if let Lit::Str(litstr) = &nv.lit { + return Some(litstr.value()); + } + } + } + } + } + } + None + }).expect("Missing #[packet(name = …)] attribute"); + + let Data::Struct(data_struct) = input.data else { + return syn::Error::new_spanned(name, "Packet can only be derived for structs") + .to_compile_error() + .into(); + }; + + let Fields::Named(fields) = data_struct.fields else { + return syn::Error::new_spanned(name, "Packet requires named fields") + .to_compile_error() + .into(); + }; + + // build field accessors + let read_fields = fields.named.iter().map(|f| { + let fname = &f.ident; + let fty = &f.ty; + quote! { #fname: <#fty as McType>::get(data)? } + }); + + let write_fields = fields.named.iter().map(|f| { + let fname = &f.ident; + quote! { out.extend(self.#fname.convert()); } + }); + + let enum_name = syn::Ident::new(&format!("{}Enum", name), name.span()); + let enum_variant_ident = syn::Ident::new(&enum_variant, name.span()); + + let expanded = quote! { + impl Packet for #name { + fn packet_id() -> i32 { #packet_id } + + fn get(data: &mut Vec) -> Result { + Ok(Self { + #(#read_fields),* + }) + } + + fn convert(&self) -> Vec { + let mut out = Vec::new(); + out.extend(convert_var_int(Self::packet_id())); + #(#write_fields)* + out + } + } + + pub enum #enum_name { + #enum_variant_ident(#name), + } + + impl #enum_name { + pub async fn read(conn: &mut T) -> Result { + let mut data = conn.read_data().await?; + let packet_id = get_var_int(&mut data)?; + if packet_id == #name::packet_id() { + Ok(Self::#enum_variant_ident(#name::get(&mut data)?)) + } else { + Err(Box::new(PacketError::InvalidPacketId(packet_id))) + } + } + } + }; + + expanded.into() +} diff --git a/src/handshake.rs b/src/handshake.rs index bbb7325..a5fd876 100644 --- a/src/handshake.rs +++ b/src/handshake.rs @@ -1,57 +1,17 @@ // Yeahbut December 2023 +// Refactored September 2025 pub mod serverbound { - use crate::mc_types::{self, Result, Packet, PacketError}; + use mc_derive::Packet; + use crate::mc_types::{McType, VarInt, Packet, Result}; - pub enum HandshakeEnum { - Handshake(Handshake), - } - - impl HandshakeEnum { - pub async fn read( - conn: &mut T, - ) -> Result { - let mut data = conn.read_data().await?; - let packet_id = mc_types::get_var_int(&mut data)?; - if packet_id == Handshake::packet_id() { - return Ok(Self::Handshake(Handshake::get(&mut data)?)) - } else { - return Err(Box::new(PacketError::InvalidPacketId(packet_id))) - } - } - } - - pub struct Handshake { - pub protocol_version: i32, + #[derive(Packet)] + #[packet(id = 0, name = "Handshake")] + pub struct HandshakePacket { + pub protocol_version: VarInt, pub server_address: String, pub server_port: u16, - pub next_state: i32, - } - - impl Packet for Handshake { - - 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 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)); - - data - } - + pub next_state: VarInt, } }