diff --git a/crawlspace-macro/src/lib.rs b/crawlspace-macro/src/lib.rs index a810ae2..fbf261c 100644 --- a/crawlspace-macro/src/lib.rs +++ b/crawlspace-macro/src/lib.rs @@ -1,6 +1,6 @@ use proc_macro::{Span, TokenStream}; use quote::quote; -use syn::{parse_macro_input, parse_quote, DeriveInput, Fields, Ident, Index, Lit}; +use syn::{parse_macro_input, parse_quote, DeriveInput, Fields, Ident, Index, Lit, Path}; #[proc_macro_derive(Packet, attributes(packet))] pub fn derive_packet(input: TokenStream) -> TokenStream { @@ -184,9 +184,9 @@ pub fn derive_encode(input: TokenStream) -> TokenStream { } /// Automatically implements "straight-across" decoding for the given struct, i.e. fields are -/// deserialized in order as is. Supports #[varint] and #[varlong] attributes on integer types to -/// deserialize as those formats instead. -#[proc_macro_derive(Decode, attributes(varint, varlong))] +/// deserialized in order as is. Supports #[decode_as(type)] to deserialize according to a different type. +/// uses TryInto to convert to the expected type where necessary. +#[proc_macro_derive(Decode, attributes(decode_as))] pub fn derive_decode(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); @@ -206,23 +206,17 @@ pub fn derive_decode(input: TokenStream) -> TokenStream { let wrapped = format!("for field {field_name} in {name}"); - if field - .attrs - .iter() - .any(|attr| attr.meta.path().is_ident("varint")) - { - field_tokens.extend(quote! { - #field_name: VarInt::decode(r) - .wrap_err(#wrapped)? - .try_into()?, - }); - } else if field + if let Some(attr) = field .attrs .iter() - .any(|attr| attr.meta.path().is_ident("varlong")) + .find(|attr| attr.meta.path().is_ident("decode_as")) { + let ty = attr + .parse_args::() + .expect("decode_as value must be a Path"); + field_tokens.extend(quote! { - #field_name: VarLong::decode(r) + #field_name: <#ty as Decode>::decode(r) .wrap_err(#wrapped)? .try_into()?, }); @@ -246,30 +240,23 @@ pub fn derive_decode(input: TokenStream) -> TokenStream { let wrapped = format!("for field {i} in {name}"); - if field + if let Some(attr) = field .attrs .iter() - .any(|attr| attr.meta.path().is_ident("varint")) - { - field_tokens.extend(quote! { - VarInt::decode(r) - .wrap_err(#wrapped)? - .try_into()?, - }); - } else if field - .attrs - .iter() - .any(|attr| attr.meta.path().is_ident("varlong")) + .find(|attr| attr.meta.path().is_ident("decode_as")) { + let ty = attr + .parse_args::() + .expect("decode_as value must be a Path"); + field_tokens.extend(quote! { - VarLong::decode(r) + <#ty as Decode>::decode(r) .wrap_err(#wrapped)? .try_into()?, }); } else { field_tokens.extend(quote! { - <#ty as Decode>::decode(r) - .wrap_err(#wrapped)?, + <#ty as Decode>::decode(r).wrap_err(#wrapped)?, }); } } diff --git a/crawlspace/src/protocol/packets/play/interactions.rs b/crawlspace/src/protocol/packets/play/interactions.rs index f1449ad..4903213 100644 --- a/crawlspace/src/protocol/packets/play/interactions.rs +++ b/crawlspace/src/protocol/packets/play/interactions.rs @@ -28,10 +28,10 @@ use crate::protocol::{ #[derive(Debug, Packet, Decode)] #[packet(id = "minecraft:use_item_on", serverbound, state = "PacketState::Play")] pub struct UseItemOnS { - #[varint] + #[decode_as(VarInt)] pub hand: Hand, pub location: Position, - #[varint] + #[decode_as(VarInt)] pub face: Face, pub cursor_x: f32, pub cursor_y: f32, diff --git a/crawlspace/src/protocol/packets/play/position.rs b/crawlspace/src/protocol/packets/play/position.rs index 7d42ad2..ff2136e 100644 --- a/crawlspace/src/protocol/packets/play/position.rs +++ b/crawlspace/src/protocol/packets/play/position.rs @@ -50,22 +50,15 @@ pub struct SetPlayerPositionAndRotationS { pub flags: PosRotFlags, } -#[derive(Clone, Debug)] -pub struct PosRotFlags { - on_ground: bool, - against_wall: bool, -} +#[derive(Clone, Debug, Decode)] +pub struct PosRotFlags(i32); -impl Decode<'_> for PosRotFlags { - fn decode(r: &mut &'_ [u8]) -> color_eyre::eyre::Result - where - Self: Sized, - { - let field = u8::decode(r)?; +impl PosRotFlags { + const fn is_on_ground(&self) -> bool { + self.0 & 0x01 == 1 + } - Ok(PosRotFlags { - on_ground: field & 0b00000001 != 0, - against_wall: field & 0b00000010 != 0, - }) + const fn is_touching_wall(&self) -> bool { + self.0 & 0x02 == 2 } } diff --git a/crawlspace/src/protocol/packets/play/teleport.rs b/crawlspace/src/protocol/packets/play/teleport.rs index 2307e55..9d36d9f 100644 --- a/crawlspace/src/protocol/packets/play/teleport.rs +++ b/crawlspace/src/protocol/packets/play/teleport.rs @@ -138,6 +138,6 @@ impl SynchronisePositionC { state = "PacketState::Play" )] pub struct ConfirmTeleportS { - #[varint] + #[decode_as(VarInt)] pub id: i32, }