First macro
This commit is contained in:
parent
fa1d8a80ed
commit
90f2270c78
|
|
@ -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()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue