First macro

This commit is contained in:
Kyler Olsen 2025-09-13 01:53:20 -06:00
parent fa1d8a80ed
commit 90f2270c78
2 changed files with 116 additions and 48 deletions

View File

@ -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::<i32>().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<u8>) -> Result<Self> {
Ok(Self {
#(#read_fields),*
})
}
fn convert(&self) -> Vec<u8> {
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<T: ProtocolRead + Send>(conn: &mut T) -> Result<Self> {
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()
}

View File

@ -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<T: mc_types::ProtocolRead>(
conn: &mut T,
) -> Result<Self> {
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<u8>) -> Result<Self> {
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<u8> {
let mut data: Vec<u8> = 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,
}
}