From 0085f8a565563ecb6a9f4f87be8b336157aa1e55 Mon Sep 17 00:00:00 2001 From: mat Date: Tue, 30 Aug 2022 21:42:40 -0500 Subject: make some stuff publishable on crates.io --- Cargo.lock | 20 +- azalea-auth/Cargo.toml | 6 +- azalea-auth/README.md | 3 + azalea-block/Cargo.toml | 4 +- azalea-block/azalea-block-macros/Cargo.toml | 16 + azalea-block/azalea-block-macros/src/lib.rs | 496 ++++++++++++++++++++++++++ azalea-block/azalea-block-macros/src/utils.rs | 39 ++ azalea-block/block-macros/Cargo.toml | 14 - azalea-block/block-macros/src/lib.rs | 496 -------------------------- azalea-block/block-macros/src/utils.rs | 39 -- azalea-block/src/blocks.rs | 2 +- azalea-buf/Cargo.toml | 4 +- azalea-chat/Cargo.toml | 8 +- azalea-core/Cargo.toml | 8 +- azalea-language/Cargo.toml | 2 + azalea-nbt/Cargo.toml | 10 +- 16 files changed, 593 insertions(+), 574 deletions(-) create mode 100644 azalea-auth/README.md create mode 100644 azalea-block/azalea-block-macros/Cargo.toml create mode 100644 azalea-block/azalea-block-macros/src/lib.rs create mode 100644 azalea-block/azalea-block-macros/src/utils.rs delete mode 100644 azalea-block/block-macros/Cargo.toml delete mode 100644 azalea-block/block-macros/src/lib.rs delete mode 100644 azalea-block/block-macros/src/utils.rs diff --git a/Cargo.lock b/Cargo.lock index 128056ce..97f5d086 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,7 +101,16 @@ dependencies = [ name = "azalea-block" version = "0.1.0" dependencies = [ - "block-macros", + "azalea-block-macros", +] + +[[package]] +name = "azalea-block-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -277,15 +286,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-macros" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "bot" version = "0.1.0" diff --git a/azalea-auth/Cargo.toml b/azalea-auth/Cargo.toml index 1bef8c57..2f817354 100755 --- a/azalea-auth/Cargo.toml +++ b/azalea-auth/Cargo.toml @@ -1,10 +1,12 @@ [package] +description = "A port of Mojang's Authlib, except authentication isn't actually implemented yet." edition = "2021" +license = "MIT" name = "azalea-auth" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -azalea-buf = {path = "../azalea-buf"} -uuid = "1.1.2" +azalea-buf = {path = "../azalea-buf", version = "^0.1.0"} +uuid = "^1.1.2" diff --git a/azalea-auth/README.md b/azalea-auth/README.md new file mode 100644 index 00000000..fa87afca --- /dev/null +++ b/azalea-auth/README.md @@ -0,0 +1,3 @@ +# Azalea Auth + +A port of Mojang's Authlib, except authentication isn't actually implemented yet. diff --git a/azalea-block/Cargo.toml b/azalea-block/Cargo.toml index edeba385..e23eea4d 100644 --- a/azalea-block/Cargo.toml +++ b/azalea-block/Cargo.toml @@ -1,5 +1,7 @@ [package] +description = "Representation of Minecraft block states." edition = "2021" +license = "MIT" name = "azalea-block" version = "0.1.0" @@ -8,4 +10,4 @@ version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -block-macros = {path = "./block-macros"} +azalea-block-macros = {path = "./azalea-block-macros", version = "^0.1.0"} diff --git a/azalea-block/azalea-block-macros/Cargo.toml b/azalea-block/azalea-block-macros/Cargo.toml new file mode 100644 index 00000000..ecac98d2 --- /dev/null +++ b/azalea-block/azalea-block-macros/Cargo.toml @@ -0,0 +1,16 @@ +[package] +description = "Proc macros used by azalea-block." +edition = "2021" +license = "MIT" +name = "azalea-block-macros" +version = "0.1.0" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +proc-macro2 = "1.0.39" +quote = "1.0.18" +syn = "1.0.95" diff --git a/azalea-block/azalea-block-macros/src/lib.rs b/azalea-block/azalea-block-macros/src/lib.rs new file mode 100644 index 00000000..ac61912f --- /dev/null +++ b/azalea-block/azalea-block-macros/src/lib.rs @@ -0,0 +1,496 @@ +mod utils; + +use proc_macro::TokenStream; +use quote::quote; +use std::collections::HashMap; +use std::fmt::Write; +use syn::{ + self, braced, + parse::{Parse, ParseStream, Result}, + parse_macro_input, + punctuated::Punctuated, + Expr, Ident, LitStr, Token, +}; +use utils::{combinations_of, to_pascal_case}; + +struct PropertyDefinition { + name: LitStr, + struct_name: Ident, + variants: Punctuated, +} +struct PropertyDefinitions { + properties: Vec, +} + +struct PropertyAndDefault { + struct_name: Ident, + default: Ident, +} +struct PropertyWithNameAndDefault { + name: String, + struct_name: Ident, + default: Ident, +} +struct BlockDefinition { + name: Ident, + behavior: Expr, + properties_and_defaults: Vec, +} +impl PropertyAndDefault { + fn as_property_with_name_and_default(&self, name: String) -> PropertyWithNameAndDefault { + PropertyWithNameAndDefault { + name, + struct_name: self.struct_name.clone(), + default: self.default.clone(), + } + } +} +struct BlockDefinitions { + blocks: Vec, +} +struct MakeBlockStates { + property_definitions: PropertyDefinitions, + block_definitions: BlockDefinitions, +} + +impl Parse for PropertyDefinition { + fn parse(input: ParseStream) -> Result { + // "face" => Face { + // Floor, + // Wall, + // Ceiling + // }, + + // if you're wondering, the reason it's in quotes is because `type` is + // a keyword in rust so if we don't put it in quotes it results in a + // syntax error + let name = input.parse()?; + input.parse::]>()?; + let struct_name = input.parse()?; + + let content; + braced!(content in input); + let variants = content.parse_terminated(Ident::parse)?; + + input.parse::()?; + Ok(PropertyDefinition { + name, + struct_name, + variants, + }) + } +} + +impl Parse for PropertyDefinitions { + fn parse(input: ParseStream) -> Result { + let mut property_definitions = Vec::new(); + while !input.is_empty() { + property_definitions.push(input.parse()?); + } + + Ok(PropertyDefinitions { + properties: property_definitions, + }) + } +} + +impl Parse for BlockDefinition { + fn parse(input: ParseStream) -> Result { + // acacia_button => BlockBehavior::default(), { + // Facing=North, + // Powered=False, + // Face=Wall, + // }, + let name = input.parse()?; + input.parse::]>()?; + let behavior = input.parse()?; + + input.parse::()?; + let content; + braced!(content in input); + + let mut properties_and_defaults = Vec::new(); + + while let Ok(property) = content.parse() { + content.parse::()?; + let property_default = content.parse()?; + properties_and_defaults.push(PropertyAndDefault { + struct_name: property, + default: property_default, + }); + if content.parse::().is_err() { + break; + } + } + input.parse::()?; + Ok(BlockDefinition { + name, + behavior, + properties_and_defaults, + }) + } +} + +impl Parse for BlockDefinitions { + fn parse(input: ParseStream) -> Result { + let mut blocks = Vec::new(); + while !input.is_empty() { + blocks.push(input.parse()?); + } + + Ok(BlockDefinitions { blocks }) + } +} + +impl Parse for MakeBlockStates { + fn parse(input: ParseStream) -> Result { + // Properties => { ... } Blocks => { ... } + let properties_ident = input.parse::()?; + assert_eq!(properties_ident.to_string(), "Properties"); + input.parse::]>()?; + let content; + braced!(content in input); + let properties = content.parse()?; + + input.parse::()?; + + let blocks_ident = input.parse::()?; + assert_eq!(blocks_ident.to_string(), "Blocks"); + input.parse::]>()?; + let content; + braced!(content in input); + let blocks = content.parse()?; + + Ok(MakeBlockStates { + property_definitions: properties, + block_definitions: blocks, + }) + } +} + +#[proc_macro] +pub fn make_block_states(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as MakeBlockStates); + + let mut property_enums = quote! {}; + let mut properties_map = HashMap::new(); + let mut property_struct_names_to_names = HashMap::new(); + + let mut state_id: usize = 0; + + for property in &input.property_definitions.properties { + let mut property_enum_variants = quote! {}; + let mut property_from_number_variants = quote! {}; + let mut property_enum_variant_names = Vec::new(); + + let property_struct_name = &property.struct_name; + + property_struct_names_to_names.insert( + property_struct_name.to_string(), + property.name.clone().value(), + ); + + for i in 0..property.variants.len() { + let variant = &property.variants[i]; + + let i_lit = syn::Lit::Int(syn::LitInt::new( + &i.to_string(), + proc_macro2::Span::call_site(), + )); + + property_enum_variants.extend(quote! { + #variant = #i_lit, + }); + + // i_lit is used here instead of i because otherwise it says 0size + // in the expansion and that looks uglier + property_from_number_variants.extend(quote! { + #i_lit => #property_struct_name::#variant, + }); + + property_enum_variant_names.push(variant.to_string()); + } + + property_enums.extend(quote! { + #[derive(Debug, Clone, Copy)] + pub enum #property_struct_name { + #property_enum_variants + } + + impl From for #property_struct_name { + fn from(value: usize) -> Self { + match value { + #property_from_number_variants + _ => panic!("Invalid property value: {}", value), + } + } + } + }); + properties_map.insert( + property_struct_name.to_string(), + property_enum_variant_names, + ); + } + + let mut block_state_enum_variants = quote! {}; + let mut block_structs = quote! {}; + let mut from_state_to_block_match = quote! {}; + for block in &input.block_definitions.blocks { + let block_property_names = &block + .properties_and_defaults + .iter() + .map(|p| p.struct_name.to_string()) + .collect::>(); + let mut block_properties_vec = Vec::new(); + for property_name in block_property_names { + let property_variants = properties_map + .get(property_name) + .unwrap_or_else(|| panic!("Property '{}' not found", property_name)) + .clone(); + block_properties_vec.push(property_variants); + } + + let mut properties_with_name: Vec = + Vec::with_capacity(block.properties_and_defaults.len()); + for property in &block.properties_and_defaults { + let index: Option = if block + .properties_and_defaults + .iter() + .filter(|p| p.struct_name == property.struct_name) + .count() + > 1 + { + Some( + properties_with_name + .iter() + .filter(|p| p.struct_name == property.struct_name) + .count(), + ) + } else { + None + }; + let mut property_name = property_struct_names_to_names + .get(&property.struct_name.to_string()) + .unwrap_or_else(|| panic!("Property '{}' is bad", property.struct_name)) + .clone(); + if let Some(index) = index { + // property_name.push_str(&format!("_{}", &index.to_string())); + write!(property_name, "_{}", index).unwrap(); + } + properties_with_name + .push(property.as_property_with_name_and_default(property_name.clone())); + } + + // pub face: properties::Face, + // pub facing: properties::Facing, + // pub powered: properties::Powered, + // or + // pub has_bottle_0: HasBottle, + // pub has_bottle_1: HasBottle, + // pub has_bottle_2: HasBottle, + let mut block_struct_fields = quote! {}; + for PropertyWithNameAndDefault { + struct_name, name, .. + } in &properties_with_name + { + // let property_name_snake = + // Ident::new(&property.to_string(), proc_macro2::Span::call_site()); + let name_ident = Ident::new(name, proc_macro2::Span::call_site()); + block_struct_fields.extend(quote! { + pub #name_ident: #struct_name, + }) + } + + let block_name_pascal_case = Ident::new( + &to_pascal_case(&block.name.to_string()), + proc_macro2::Span::call_site(), + ); + let block_struct_name = Ident::new( + &format!("{}Block", block_name_pascal_case), + proc_macro2::Span::call_site(), + ); + + let mut from_block_to_state_match_inner = quote! {}; + + let first_state_id = state_id; + + // if there's no properties, then the block is just a single state + if block_properties_vec.is_empty() { + block_state_enum_variants.extend(quote! { + #block_name_pascal_case, + }); + state_id += 1; + } + for combination in combinations_of(&block_properties_vec) { + state_id += 1; + let variant_name = Ident::new( + &format!( + "{}_{}", + block_name_pascal_case, + combination + .iter() + .map(|v| v.to_string()) + .collect::>() + .join("") + ), + proc_macro2::Span::call_site(), + ); + block_state_enum_variants.extend(quote! { + #variant_name, + }); + + // face: properties::Face::Floor, + // facing: properties::Facing::North, + // powered: properties::Powered::True, + let mut from_block_to_state_combination_match_inner = quote! {}; + for i in 0..properties_with_name.len() { + let property = &properties_with_name[i]; + let property_name = &property.name; + let property_name_ident = Ident::new(property_name, proc_macro2::Span::call_site()); + let property_struct_name_ident = &property.struct_name; + let variant = + Ident::new(&combination[i].to_string(), proc_macro2::Span::call_site()); + + from_block_to_state_combination_match_inner.extend(quote! { + #property_name_ident: #property_struct_name_ident::#variant, + }); + } + + from_block_to_state_match_inner.extend(quote! { + #block_struct_name { + #from_block_to_state_combination_match_inner + } => BlockState::#variant_name, + }); + } + + // 7035..=7058 => { + // let b = b - 7035; + // &AcaciaButtonBlock { + // powered: Powered::from((b / 1) % 2), + // facing: Facing::from((b / 2) % 4), + // face: Face::from((b / 8) % 3), + // } + // } + let mut from_state_to_block_inner = quote! {}; + let mut division = 1usize; + for i in (0..properties_with_name.len()).rev() { + let PropertyWithNameAndDefault { + struct_name: property_struct_name_ident, + name: property_name, + .. + } = &properties_with_name[i]; + + let property_variants = &block_properties_vec[i]; + let property_variants_count = property_variants.len(); + let property_name_ident = Ident::new(property_name, proc_macro2::Span::call_site()); + from_state_to_block_inner.extend(quote! { + #property_name_ident: #property_struct_name_ident::from((b / #division) % #property_variants_count), + }); + + division *= property_variants_count; + } + + let last_state_id = state_id - 1; + from_state_to_block_match.extend(quote! { + #first_state_id..=#last_state_id => { + let b = b - #first_state_id; + Box::new(#block_struct_name { + #from_state_to_block_inner + }) + }, + }); + + let mut block_default_fields = quote! {}; + for PropertyWithNameAndDefault { + struct_name: struct_name_ident, + name, + default: property_default, + } in properties_with_name + { + let name_ident = Ident::new(&name, proc_macro2::Span::call_site()); + block_default_fields.extend(quote! { + #name_ident: #struct_name_ident::#property_default, + }) + } + + let block_behavior = &block.behavior; + let block_id = block.name.to_string(); + + let from_block_to_state_match = if !block.properties_and_defaults.is_empty() { + quote! { + match b { + #from_block_to_state_match_inner + } + } + } else { + quote! { BlockState::#block_name_pascal_case } + }; + + let block_struct = quote! { + #[derive(Debug)] + pub struct #block_struct_name { + #block_struct_fields + } + + impl Block for #block_struct_name { + fn behavior(&self) -> BlockBehavior { + #block_behavior + } + fn id(&self) -> &'static str { + #block_id + } + } + + impl From<#block_struct_name> for BlockState { + fn from(b: #block_struct_name) -> Self { + #from_block_to_state_match + } + } + + impl Default for #block_struct_name { + fn default() -> Self { + Self { + #block_default_fields + } + } + } + }; + + block_structs.extend(block_struct); + } + + let last_state_id = (state_id - 1) as u32; + let mut generated = quote! { + #property_enums + + #[repr(u32)] + #[derive(Copy, Clone, PartialEq, Eq, Debug)] + pub enum BlockState { + #block_state_enum_variants + } + + impl BlockState { + /// Returns the highest possible state + #[inline] + pub fn max_state() -> u32 { + #last_state_id + } + } + }; + + generated.extend(quote! { + #block_structs + + impl From for Box { + fn from(b: BlockState) -> Self { + let b = b as usize; + match b { + #from_state_to_block_match + _ => panic!("Invalid block state: {}", b), + } + } + } + }); + + generated.into() +} diff --git a/azalea-block/azalea-block-macros/src/utils.rs b/azalea-block/azalea-block-macros/src/utils.rs new file mode 100644 index 00000000..82095d86 --- /dev/null +++ b/azalea-block/azalea-block-macros/src/utils.rs @@ -0,0 +1,39 @@ +pub fn combinations_of(items: &[Vec]) -> Vec> { + let mut combinations = Vec::new(); + if items.is_empty() { + return combinations; + }; + if items.len() == 1 { + for item in &items[0] { + combinations.push(vec![item.clone()]); + } + return combinations; + }; + + for i in 0..items[0].len() { + let item = &items[0][i]; + for other_combinations in combinations_of(&items[1..]) { + let mut combination = vec![item.clone()]; + combination.extend(other_combinations); + combinations.push(combination); + } + } + + combinations +} + +pub fn to_pascal_case(s: &str) -> String { + let mut result = String::new(); + let mut prev_was_underscore = true; // set to true by default so the first character is capitalized + for c in s.chars() { + if c == '_' { + prev_was_underscore = true; + } else if prev_was_underscore { + result.push(c.to_ascii_uppercase()); + prev_was_underscore = false; + } else { + result.push(c); + } + } + result +} diff --git a/azalea-block/block-macros/Cargo.toml b/azalea-block/block-macros/Cargo.toml deleted file mode 100644 index 03b19e1d..00000000 --- a/azalea-block/block-macros/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -edition = "2021" -name = "block-macros" -version = "0.1.0" - -[lib] -proc-macro = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -proc-macro2 = "1.0.39" -quote = "1.0.18" -syn = "1.0.95" diff --git a/azalea-block/block-macros/src/lib.rs b/azalea-block/block-macros/src/lib.rs deleted file mode 100644 index ac61912f..00000000 --- a/azalea-block/block-macros/src/lib.rs +++ /dev/null @@ -1,496 +0,0 @@ -mod utils; - -use proc_macro::TokenStream; -use quote::quote; -use std::collections::HashMap; -use std::fmt::Write; -use syn::{ - self, braced, - parse::{Parse, ParseStream, Result}, - parse_macro_input, - punctuated::Punctuated, - Expr, Ident, LitStr, Token, -}; -use utils::{combinations_of, to_pascal_case}; - -struct PropertyDefinition { - name: LitStr, - struct_name: Ident, - variants: Punctuated, -} -struct PropertyDefinitions { - properties: Vec, -} - -struct PropertyAndDefault { - struct_name: Ident, - default: Ident, -} -struct PropertyWithNameAndDefault { - name: String, - struct_name: Ident, - default: Ident, -} -struct BlockDefinition { - name: Ident, - behavior: Expr, - properties_and_defaults: Vec, -} -impl PropertyAndDefault { - fn as_property_with_name_and_default(&self, name: String) -> PropertyWithNameAndDefault { - PropertyWithNameAndDefault { - name, - struct_name: self.struct_name.clone(), - default: self.default.clone(), - } - } -} -struct BlockDefinitions { - blocks: Vec, -} -struct MakeBlockStates { - property_definitions: PropertyDefinitions, - block_definitions: BlockDefinitions, -} - -impl Parse for PropertyDefinition { - fn parse(input: ParseStream) -> Result { - // "face" => Face { - // Floor, - // Wall, - // Ceiling - // }, - - // if you're wondering, the reason it's in quotes is because `type` is - // a keyword in rust so if we don't put it in quotes it results in a - // syntax error - let name = input.parse()?; - input.parse::]>()?; - let struct_name = input.parse()?; - - let content; - braced!(content in input); - let variants = content.parse_terminated(Ident::parse)?; - - input.parse::()?; - Ok(PropertyDefinition { - name, - struct_name, - variants, - }) - } -} - -impl Parse for PropertyDefinitions { - fn parse(input: ParseStream) -> Result { - let mut property_definitions = Vec::new(); - while !input.is_empty() { - property_definitions.push(input.parse()?); - } - - Ok(PropertyDefinitions { - properties: property_definitions, - }) - } -} - -impl Parse for BlockDefinition { - fn parse(input: ParseStream) -> Result { - // acacia_button => BlockBehavior::default(), { - // Facing=North, - // Powered=False, - // Face=Wall, - // }, - let name = input.parse()?; - input.parse::]>()?; - let behavior = input.parse()?; - - input.parse::()?; - let content; - braced!(content in input); - - let mut properties_and_defaults = Vec::new(); - - while let Ok(property) = content.parse() { - content.parse::()?; - let property_default = content.parse()?; - properties_and_defaults.push(PropertyAndDefault { - struct_name: property, - default: property_default, - }); - if content.parse::().is_err() { - break; - } - } - input.parse::()?; - Ok(BlockDefinition { - name, - behavior, - properties_and_defaults, - }) - } -} - -impl Parse for BlockDefinitions { - fn parse(input: ParseStream) -> Result { - let mut blocks = Vec::new(); - while !input.is_empty() { - blocks.push(input.parse()?); - } - - Ok(BlockDefinitions { blocks }) - } -} - -impl Parse for MakeBlockStates { - fn parse(input: ParseStream) -> Result { - // Properties => { ... } Blocks => { ... } - let properties_ident = input.parse::()?; - assert_eq!(properties_ident.to_string(), "Properties"); - input.parse::]>()?; - let content; - braced!(content in input); - let properties = content.parse()?; - - input.parse::()?; - - let blocks_ident = input.parse::()?; - assert_eq!(blocks_ident.to_string(), "Blocks"); - input.parse::]>()?; - let content; - braced!(content in input); - let blocks = content.parse()?; - - Ok(MakeBlockStates { - property_definitions: properties, - block_definitions: blocks, - }) - } -} - -#[proc_macro] -pub fn make_block_states(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as MakeBlockStates); - - let mut property_enums = quote! {}; - let mut properties_map = HashMap::new(); - let mut property_struct_names_to_names = HashMap::new(); - - let mut state_id: usize = 0; - - for property in &input.property_definitions.properties { - let mut property_enum_variants = quote! {}; - let mut property_from_number_variants = quote! {}; - let mut property_enum_variant_names = Vec::new(); - - let property_struct_name = &property.struct_name; - - property_struct_names_to_names.insert( - property_struct_name.to_string(), - property.name.clone().value(), - ); - - for i in 0..property.variants.len() { - let variant = &property.variants[i]; - - let i_lit = syn::Lit::Int(syn::LitInt::new( - &i.to_string(), - proc_macro2::Span::call_site(), - )); - - property_enum_variants.extend(quote! { - #variant = #i_lit, - }); - - // i_lit is used here instead of i because otherwise it says 0size - // in the expansion and that looks uglier - property_from_number_variants.extend(quote! { - #i_lit => #property_struct_name::#variant, - }); - - property_enum_variant_names.push(variant.to_string()); - } - - property_enums.extend(quote! { - #[derive(Debug, Clone, Copy)] - pub enum #property_struct_name { - #property_enum_variants - } - - impl From for #property_struct_name { - fn from(value: usize) -> Self { - match value { - #property_from_number_variants - _ => panic!("Invalid property value: {}", value), - } - } - } - }); - properties_map.insert( - property_struct_name.to_string(), - property_enum_variant_names, - ); - } - - let mut block_state_enum_variants = quote! {}; - let mut block_structs = quote! {}; - let mut from_state_to_block_match = quote! {}; - for block in &input.block_definitions.blocks { - let block_property_names = &block - .properties_and_defaults - .iter() - .map(|p| p.struct_name.to_string()) - .collect::>(); - let mut block_properties_vec = Vec::new(); - for property_name in block_property_names { - let property_variants = properties_map - .get(property_name) - .unwrap_or_else(|| panic!("Property '{}' not found", property_name)) - .clone(); - block_properties_vec.push(property_variants); - } - - let mut properties_with_name: Vec = - Vec::with_capacity(block.properties_and_defaults.len()); - for property in &block.properties_and_defaults { - let index: Option = if block - .properties_and_defaults - .iter() - .filter(|p| p.struct_name == property.struct_name) - .count() - > 1 - { - Some( - properties_with_name - .iter() - .filter(|p| p.struct_name == property.struct_name) - .count(), - ) - } else { - None - }; - let mut property_name = property_struct_names_to_names - .get(&property.struct_name.to_string()) - .unwrap_or_else(|| panic!("Property '{}' is bad", property.struct_name)) - .clone(); - if let Some(index) = index { - // property_name.push_str(&format!("_{}", &index.to_string())); - write!(property_name, "_{}", index).unwrap(); - } - properties_with_name - .push(property.as_property_with_name_and_default(property_name.clone())); - } - - // pub face: properties::Face, - // pub facing: properties::Facing, - // pub powered: properties::Powered, - // or - // pub has_bottle_0: HasBottle, - // pub has_bottle_1: HasBottle, - // pub has_bottle_2: HasBottle, - let mut block_struct_fields = quote! {}; - for PropertyWithNameAndDefault { - struct_name, name, .. - } in &properties_with_name - { - // let property_name_snake = - // Ident::new(&property.to_string(), proc_macro2::Span::call_site()); - let name_ident = Ident::new(name, proc_macro2::Span::call_site()); - block_struct_fields.extend(quote! { - pub #name_ident: #struct_name, - }) - } - - let block_name_pascal_case = Ident::new( - &to_pascal_case(&block.name.to_string()), - proc_macro2::Span::call_site(), - ); - let block_struct_name = Ident::new( - &format!("{}Block", block_name_pascal_case), - proc_macro2::Span::call_site(), - ); - - let mut from_block_to_state_match_inner = quote! {}; - - let first_state_id = state_id; - - // if there's no properties, then the block is just a single state - if block_properties_vec.is_empty() { - block_state_enum_variants.extend(quote! { - #block_name_pascal_case, - }); - state_id += 1; - } - for combination in combinations_of(&block_properties_vec) { - state_id += 1; - let variant_name = Ident::new( - &format!( - "{}_{}", - block_name_pascal_case, - combination - .iter() - .map(|v| v.to_string()) - .collect::>() - .join("") - ), - proc_macro2::Span::call_site(), - ); - block_state_enum_variants.extend(quote! { - #variant_name, - }); - - // face: properties::Face::Floor, - // facing: properties::Facing::North, - // powered: properties::Powered::True, - let mut from_block_to_state_combination_match_inner = quote! {}; - for i in 0..properties_with_name.len() { - let property = &properties_with_name[i]; - let property_name = &property.name; - let property_name_ident = Ident::new(property_name, proc_macro2::Span::call_site()); - let property_struct_name_ident = &property.struct_name; - let variant = - Ident::new(&combination[i].to_string(), proc_macro2::Span::call_site()); - - from_block_to_state_combination_match_inner.extend(quote! { - #property_name_ident: #property_struct_name_ident::#variant, - }); - } - - from_block_to_state_match_inner.extend(quote! { - #block_struct_name { - #from_block_to_state_combination_match_inner - } => BlockState::#variant_name, - }); - } - - // 7035..=7058 => { - // let b = b - 7035; - // &AcaciaButtonBlock { - // powered: Powered::from((b / 1) % 2), - // facing: Facing::from((b / 2) % 4), - // face: Face::from((b / 8) % 3), - // } - // } - let mut from_state_to_block_inner = quote! {}; - let mut division = 1usize; - for i in (0..properties_with_name.len()).rev() { - let PropertyWithNameAndDefault { - struct_name: property_struct_name_ident, - name: property_name, - .. - } = &properties_with_name[i]; - - let property_variants = &block_properties_vec[i]; - let property_variants_count = property_variants.len(); - let property_name_ident = Ident::new(property_name, proc_macro2::Span::call_site()); - from_state_to_block_inner.extend(quote! { - #property_name_ident: #property_struct_name_ident::from((b / #division) % #property_variants_count), - }); - - division *= property_variants_count; - } - - let last_state_id = state_id - 1; - from_state_to_block_match.extend(quote! { - #first_state_id..=#last_state_id => { - let b = b - #first_state_id; - Box::new(#block_struct_name { - #from_state_to_block_inner - }) - }, - }); - - let mut block_default_fields = quote! {}; - for PropertyWithNameAndDefault { - struct_name: struct_name_ident, - name, - default: property_default, - } in properties_with_name - { - let name_ident = Ident::new(&name, proc_macro2::Span::call_site()); - block_default_fields.extend(quote! { - #name_ident: #struct_name_ident::#property_default, - }) - } - - let block_behavior = &block.behavior; - let block_id = block.name.to_string(); - - let from_block_to_state_match = if !block.properties_and_defaults.is_empty() { - quote! { - match b { - #from_block_to_state_match_inner - } - } - } else { - quote! { BlockState::#block_name_pascal_case } - }; - - let block_struct = quote! { - #[derive(Debug)] - pub struct #block_struct_name { - #block_struct_fields - } - - impl Block for #block_struct_name { - fn behavior(&self) -> BlockBehavior { - #block_behavior - } - fn id(&self) -> &'static str { - #block_id - } - } - - impl From<#block_struct_name> for BlockState { - fn from(b: #block_struct_name) -> Self { - #from_block_to_state_match - } - } - - impl Default for #block_struct_name { - fn default() -> Self { - Self { - #block_default_fields - } - } - } - }; - - block_structs.extend(block_struct); - } - - let last_state_id = (state_id - 1) as u32; - let mut generated = quote! { - #property_enums - - #[repr(u32)] - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub enum BlockState { - #block_state_enum_variants - } - - impl BlockState { - /// Returns the highest possible state - #[inline] - pub fn max_state() -> u32 { - #last_state_id - } - } - }; - - generated.extend(quote! { - #block_structs - - impl From for Box { - fn from(b: BlockState) -> Self { - let b = b as usize; - match b { - #from_state_to_block_match - _ => panic!("Invalid block state: {}", b), - } - } - } - }); - - generated.into() -} diff --git a/azalea-block/block-macros/src/utils.rs b/azalea-block/block-macros/src/utils.rs deleted file mode 100644 index 82095d86..00000000 --- a/azalea-block/block-macros/src/utils.rs +++ /dev/null @@ -1,39 +0,0 @@ -pub fn combinations_of(items: &[Vec]) -> Vec> { - let mut combinations = Vec::new(); - if items.is_empty() { - return combinations; - }; - if items.len() == 1 { - for item in &items[0] { - combinations.push(vec![item.clone()]); - } - return combinations; - }; - - for i in 0..items[0].len() { - let item = &items[0][i]; - for other_combinations in combinations_of(&items[1..]) { - let mut combination = vec![item.clone()]; - combination.extend(other_combinations); - combinations.push(combination); - } - } - - combinations -} - -pub fn to_pascal_case(s: &str) -> String { - let mut result = String::new(); - let mut prev_was_underscore = true; // set to true by default so the first character is capitalized - for c in s.chars() { - if c == '_' { - prev_was_underscore = true; - } else if prev_was_underscore { - result.push(c.to_ascii_uppercase()); - prev_was_underscore = false; - } else { - result.push(c); - } - } - result -} diff --git a/azalea-block/src/blocks.rs b/azalea-block/src/blocks.rs index 05973797..f9130f30 100644 --- a/azalea-block/src/blocks.rs +++ b/azalea-block/src/blocks.rs @@ -1,5 +1,5 @@ use crate::BlockBehavior; -use block_macros::make_block_states; +use azalea_block_macros::make_block_states; pub trait Block { fn behavior(&self) -> BlockBehavior; diff --git a/azalea-buf/Cargo.toml b/azalea-buf/Cargo.toml index 51b9c2fe..6f21e697 100644 --- a/azalea-buf/Cargo.toml +++ b/azalea-buf/Cargo.toml @@ -1,12 +1,14 @@ [package] +description = "Serialize and deserialize buffers from Minecraft." edition = "2021" +license = "MIT" name = "azalea-buf" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -azalea-buf-macros = {path = "./azalea-buf-macros", version = "0.1.0"} +azalea-buf-macros = {path = "./azalea-buf-macros", version = "^0.1.0"} byteorder = "^1.4.3" serde_json = {version = "^1.0", optional = true} thiserror = "^1.0.31" diff --git a/azalea-chat/Cargo.toml b/azalea-chat/Cargo.toml index 2da86829..9894b49d 100755 --- a/azalea-chat/Cargo.toml +++ b/azalea-chat/Cargo.toml @@ -1,13 +1,15 @@ [package] +description = "Parse Minecraft chat messages." edition = "2021" +license = "MIT" name = "azalea-chat" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -azalea-buf = {path = "../azalea-buf", features = ["serde_json"]} -azalea-language = {path = "../azalea-language"} -lazy_static = "1.4.0" +azalea-buf = {path = "../azalea-buf", features = ["serde_json"], version = "^0.1.0"} +azalea-language = {path = "../azalea-language", version = "^0.1.0"} +lazy_static = "^1.4.0" serde = "^1.0.130" serde_json = "^1.0.72" diff --git a/azalea-core/Cargo.toml b/azalea-core/Cargo.toml index 470bc998..52669af5 100755 --- a/azalea-core/Cargo.toml +++ b/azalea-core/Cargo.toml @@ -1,12 +1,14 @@ [package] +description = "Miscellaneous things in Azalea." edition = "2021" +license = "MIT" name = "azalea-core" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -azalea-buf = {path = "../azalea-buf"} -azalea-chat = {path = "../azalea-chat"} -azalea-nbt = {path = "../azalea-nbt"} +azalea-buf = {path = "../azalea-buf", version = "^0.1.0"} +azalea-chat = {path = "../azalea-chat", version = "^0.1.0"} +azalea-nbt = {path = "../azalea-nbt", version = "^0.1.0"} uuid = "^1.1.2" diff --git a/azalea-language/Cargo.toml b/azalea-language/Cargo.toml index dea9aa27..ac190311 100644 --- a/azalea-language/Cargo.toml +++ b/azalea-language/Cargo.toml @@ -1,5 +1,7 @@ [package] +description = "Translate Minecraft strings from their id." edition = "2021" +license = "MIT" name = "azalea-language" version = "0.1.0" diff --git a/azalea-nbt/Cargo.toml b/azalea-nbt/Cargo.toml index 4a03880c..2179c11d 100755 --- a/azalea-nbt/Cargo.toml +++ b/azalea-nbt/Cargo.toml @@ -1,15 +1,17 @@ [package] +description = "A fast NBT serializer and deserializer." edition = "2021" +license = "MIT" name = "azalea-nbt" version = "0.1.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ahash = "0.8.0" -azalea-buf = {path = "../azalea-buf"} -byteorder = "1.4.3" -flate2 = "1.0.23" +ahash = "^0.8.0" +azalea-buf = {path = "../azalea-buf", version = "^0.1.0"} +byteorder = "^1.4.3" +flate2 = "^1.0.23" num-derive = "^0.3.3" num-traits = "^0.2.14" -- cgit v1.2.3