aboutsummaryrefslogtreecommitdiff
path: root/azalea-protocol
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-protocol')
-rw-r--r--azalea-protocol/azalea-protocol-macros/src/lib.rs108
-rw-r--r--azalea-protocol/azalea-protocol-macros/src/utils.rs29
-rw-r--r--azalea-protocol/src/lib.rs3
3 files changed, 104 insertions, 36 deletions
diff --git a/azalea-protocol/azalea-protocol-macros/src/lib.rs b/azalea-protocol/azalea-protocol-macros/src/lib.rs
index fcac9c91..a815a86d 100644
--- a/azalea-protocol/azalea-protocol-macros/src/lib.rs
+++ b/azalea-protocol/azalea-protocol-macros/src/lib.rs
@@ -1,11 +1,15 @@
+mod utils;
+
use proc_macro::TokenStream;
use quote::quote;
use syn::{
- DeriveInput, Ident, Token, bracketed,
+ DeriveInput, Expr, Ident, Token, bracketed,
parse::{Parse, ParseStream, Result},
parse_macro_input,
};
+use crate::utils::{to_camel_case, to_snake_case};
+
fn as_packet_derive(input: TokenStream, state: proc_macro2::TokenStream) -> TokenStream {
let DeriveInput { ident, data, .. } = parse_macro_input!(input);
@@ -194,17 +198,17 @@ pub fn declare_state_packets(input: TokenStream) -> TokenStream {
let has_clientbound_packets = !input.clientbound.packets.is_empty();
let has_serverbound_packets = !input.serverbound.packets.is_empty();
- let mut mod_and_use_statements_contents = quote!();
- let mut clientbound_enum_contents = quote!();
- let mut serverbound_enum_contents = quote!();
- let mut clientbound_id_match_contents = quote!();
- let mut serverbound_id_match_contents = quote!();
- let mut clientbound_name_match_contents = quote!();
- let mut serverbound_name_match_contents = quote!();
- let mut clientbound_write_match_contents = quote!();
- let mut serverbound_write_match_contents = quote!();
- let mut clientbound_read_match_contents = quote!();
- let mut serverbound_read_match_contents = quote!();
+ let mut mod_and_use_statements_contents = quote! {};
+ let mut clientbound_enum_contents = quote! {};
+ let mut serverbound_enum_contents = quote! {};
+ let mut clientbound_id_match_contents = quote! {};
+ let mut serverbound_id_match_contents = quote! {};
+ let mut clientbound_name_match_contents = quote! {};
+ let mut serverbound_name_match_contents = quote! {};
+ let mut clientbound_write_match_contents = quote! {};
+ let mut serverbound_write_match_contents = quote! {};
+ let mut clientbound_read_match_contents = quote! {};
+ let mut serverbound_read_match_contents = quote! {};
for (id, packet_name) in input.clientbound.packets.iter().enumerate() {
let id = id as u32;
@@ -463,32 +467,64 @@ fn packet_name_to_variant_name(name: &syn::Ident) -> syn::Ident {
syn::Ident::new(&variant_name, name.span())
}
-fn to_camel_case(snake_case: &str) -> String {
- let mut camel_case = String::new();
- let mut capitalize_next = true;
- for c in snake_case.chars() {
- if c == '_' {
- capitalize_next = true;
- } else {
- if capitalize_next {
- camel_case.push(c.to_ascii_uppercase());
- } else {
- camel_case.push(c);
- }
- capitalize_next = false;
- }
+struct DeclarePacketHandlers {
+ packet_enum: Ident,
+ packet_var: Expr,
+ handler: Ident,
+ packets: Box<[syn::Path]>,
+}
+impl Parse for DeclarePacketHandlers {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let packet_enum = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let packet_var = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let handler = input.parse()?;
+ input.parse::<Token![,]>()?;
+
+ let packets_inner;
+ bracketed!(packets_inner in input);
+ let packets = packets_inner
+ .parse_terminated(syn::Path::parse, Token![,])?
+ .into_iter()
+ .collect::<Box<[_]>>();
+
+ Ok(Self {
+ packet_enum,
+ packet_var,
+ handler,
+ packets,
+ })
}
- camel_case
}
-fn to_snake_case(camel_case: &str) -> String {
- let mut snake_case = String::new();
- for c in camel_case.chars() {
- if c.is_ascii_uppercase() {
- snake_case.push('_');
- snake_case.push(c.to_ascii_lowercase());
- } else {
- snake_case.push(c);
+#[proc_macro]
+pub fn declare_packet_handlers(input: TokenStream) -> TokenStream {
+ let DeclarePacketHandlers {
+ packet_enum,
+ packet_var,
+ handler,
+ packets,
+ } = parse_macro_input!(input as DeclarePacketHandlers);
+ // needs to be a proc macro to be able to convert snake_case to camelCase
+
+ let mut inner = quote! {};
+ for packet in packets {
+ let mut packet_camel = packet.clone();
+ let packet_last_ident = &mut packet_camel.segments.last_mut().unwrap().ident;
+ *packet_last_ident = Ident::new(
+ &to_camel_case(&packet_last_ident.to_string()),
+ packet_last_ident.span(),
+ );
+
+ inner.extend(quote! {
+ #packet_enum::#packet_camel(p) => #handler.#packet(p),
+ });
+ }
+
+ quote! {
+ match #packet_var {
+ #inner
}
}
- snake_case
+ .into()
}
diff --git a/azalea-protocol/azalea-protocol-macros/src/utils.rs b/azalea-protocol/azalea-protocol-macros/src/utils.rs
new file mode 100644
index 00000000..cdfe0412
--- /dev/null
+++ b/azalea-protocol/azalea-protocol-macros/src/utils.rs
@@ -0,0 +1,29 @@
+pub fn to_camel_case(snake_case: &str) -> String {
+ let mut camel_case = String::new();
+ let mut capitalize_next = true;
+ for c in snake_case.chars() {
+ if c == '_' {
+ capitalize_next = true;
+ } else {
+ if capitalize_next {
+ camel_case.push(c.to_ascii_uppercase());
+ } else {
+ camel_case.push(c);
+ }
+ capitalize_next = false;
+ }
+ }
+ camel_case
+}
+pub fn to_snake_case(camel_case: &str) -> String {
+ let mut snake_case = String::new();
+ for c in camel_case.chars() {
+ if c.is_ascii_uppercase() {
+ snake_case.push('_');
+ snake_case.push(c.to_ascii_lowercase());
+ } else {
+ snake_case.push(c);
+ }
+ }
+ snake_case
+}
diff --git a/azalea-protocol/src/lib.rs b/azalea-protocol/src/lib.rs
index b269fba8..806bfdfc 100644
--- a/azalea-protocol/src/lib.rs
+++ b/azalea-protocol/src/lib.rs
@@ -11,6 +11,9 @@ pub mod read;
pub mod resolve;
pub mod write;
+// re-export for internal use in azalea-client
+#[doc(hidden)]
+pub use azalea_protocol_macros;
// re-export to make it easier for users to have the correct version
pub use simdnbt;