1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

add unit structs for every bool property

This commit is contained in:
mat 2023-12-09 18:32:13 -06:00
parent c9a18bc6a1
commit 31206701b9
4 changed files with 985 additions and 936 deletions

3
azalea-block/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# cargo expand generated -p azalea-block > azalea-block/out.rs
/out.rs

View file

@ -10,35 +10,36 @@ use std::fmt::Write;
use syn::{
self, braced,
ext::IdentExt,
parenthesized,
parse::{Parse, ParseStream, Result},
parse_macro_input,
punctuated::Punctuated,
Expr, Ident, LitStr, Token,
token, Expr, Ident, LitStr, Token,
};
use utils::{combinations_of, to_pascal_case};
enum PropertyType {
/// `Axis { X, Y, Z }`
Enum {
type_name: Ident,
enum_name: Ident,
variants: Punctuated<Ident, Token![,]>,
},
/// `bool`
Boolean,
/// `Snowy(bool)`
Boolean { struct_name: Ident },
}
/// `"snowy" => bool`
/// `"snowy" => Snowy(bool)`
struct PropertyDefinition {
name: LitStr,
property_type: PropertyType,
}
/// Comma separated PropertyDefinitions (`"snowy" => bool,`)
/// Comma separated PropertyDefinitions (`"snowy" => Snowy(bool),`)
struct PropertyDefinitions {
properties: Vec<PropertyDefinition>,
}
/// `snowy: false` or `axis: properties::Axis::Y`
/// `snowy: Snowy(false)` or `axis: properties::Axis::Y`
#[derive(Debug)]
struct PropertyWithNameAndDefault {
name: Ident,
@ -64,21 +65,32 @@ impl Parse for PropertyWithNameAndDefault {
input.parse::<Token![:]>()?;
let first_ident = input.call(Ident::parse_any)?;
let first_ident_string = first_ident.to_string();
let mut property_default = quote! { #first_ident };
let property_type: Ident;
let mut is_enum = false;
if input.parse::<Token![::]>().is_ok() {
// enum
is_enum = true;
property_type = first_ident;
let variant = input.parse::<Ident>()?;
property_default = quote! { properties::#property_default::#variant };
} else if first_ident_string == "true" || first_ident_string == "false" {
property_type = Ident::new("bool", first_ident.span());
} else {
return Err(input.error("Expected a boolean or an enum variant"));
// must be a unit struct if it's not an enum
let content;
let _paren_token: token::Paren = parenthesized!(content in input);
// we use this instead of .parse so it works with rust keywords like true and
// false
let unit_struct_inner = content.call(Ident::parse_any)?;
let unit_struct_inner_string = unit_struct_inner.to_string();
if matches!(unit_struct_inner_string.as_str(), "true" | "false") {
property_type = Ident::new("bool", first_ident.span());
property_default = quote! { #unit_struct_inner };
} else {
return Err(input.error("Expected a boolean or an enum variant"));
}
};
Ok(PropertyWithNameAndDefault {
@ -100,20 +112,40 @@ struct MakeBlockStates {
impl Parse for PropertyType {
fn parse(input: ParseStream) -> Result<Self> {
// like `Axis { X, Y, Z }` or `bool`
// like `Axis { X, Y, Z }` or `Waterlogged(bool)`
let keyword = Ident::parse(input)?;
let keyword_string = keyword.to_string();
if keyword_string == "bool" {
Ok(Self::Boolean)
} else {
fn parse_braced(input: ParseStream) -> Result<Punctuated<Ident, Token![,]>> {
let content;
braced!(content in input);
let variants = content.parse_terminated(Ident::parse, Token![,])?;
Ok(variants)
}
fn parse_paren(input: ParseStream) -> Result<Ident> {
let content;
parenthesized!(content in input);
let inner = content.parse::<Ident>()?;
Ok(inner)
}
if let Ok(variants) = parse_braced(input) {
Ok(Self::Enum {
type_name: keyword,
enum_name: keyword,
variants,
})
} else if let Ok(inner) = parse_paren(input) {
assert_eq!(
inner.to_string(),
"bool",
"Currently only bool unit structs are supported"
);
Ok(Self::Boolean {
struct_name: keyword,
})
} else {
Err(input.error("Expected a unit struct or an enum"))
}
}
}
@ -238,21 +270,24 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
let mut state_id: u32 = 0;
for property in &input.property_definitions.properties {
let property_type_name: Ident;
let property_struct_name: Ident;
// this is usually the same as property_struct_name except for bool
let property_value_name: Ident;
let mut property_variant_types = Vec::new();
match &property.property_type {
PropertyType::Enum {
type_name,
enum_name,
variants,
} => {
let mut property_enum_variants = quote! {};
let mut property_from_number_variants = quote! {};
property_type_name = type_name.clone();
property_value_name = enum_name.clone();
property_struct_name = enum_name.clone();
property_struct_names_to_names.insert(
property_type_name.to_string(),
property_struct_name.to_string(),
property.name.clone().value(),
);
@ -271,7 +306,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
// 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_type_name::#variant,
#i_lit => #property_struct_name::#variant,
});
property_variant_types.push(variant.to_string());
@ -279,11 +314,11 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
property_enums.extend(quote! {
#[derive(Debug, Clone, Copy)]
pub enum #property_type_name {
pub enum #property_struct_name {
#property_enum_variants
}
impl From<u32> for #property_type_name {
impl From<u32> for #property_struct_name {
fn from(value: u32) -> Self {
match value {
#property_from_number_variants
@ -293,15 +328,28 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
}
});
}
PropertyType::Boolean => {
property_type_name = Ident::new("bool", proc_macro2::Span::call_site());
// property_type_name =
// Ident::new(&property.name.value(), proc_macro2::Span::call_site());
PropertyType::Boolean { struct_name } => {
property_value_name = Ident::new("bool", proc_macro2::Span::call_site());
property_struct_name = struct_name.clone();
property_variant_types = vec!["true".to_string(), "false".to_string()];
property_enums.extend(quote! {
#[derive(Debug, Clone, Copy)]
pub struct #property_struct_name(pub bool);
impl From<u32> for #property_struct_name {
fn from(value: u32) -> Self {
match value {
0 => Self(false),
1 => Self(true),
_ => panic!("Invalid property value: {}", value),
}
}
}
});
}
}
properties_map.insert(property_type_name.to_string(), property_variant_types);
// properties_map.insert(property.name.value(), property_variant_types);
properties_map.insert(property_value_name.to_string(), property_variant_types);
}
let mut block_state_enum_variants = quote! {};

File diff suppressed because it is too large Load diff

View file

@ -71,9 +71,9 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, pixlyzer_block_dat
# },
property_name = property_struct_names_to_names[property_struct_name]
# if the only variants are true and false, we can just make it a normal boolean
# if the only variants are true and false, we make it unit struct with a boolean instead of an enum
if property_variants == ['true', 'false']:
property_shape_code = 'bool'
property_shape_code = f'{property_struct_name}(bool)'
else:
property_shape_code = f'{property_struct_name} {{\n'
for variant in property_variants:
@ -119,7 +119,7 @@ def generate_blocks(blocks_burger: dict, blocks_report: dict, pixlyzer_block_dat
if is_boolean_property:
# if it's a boolean, keep the type lowercase
# (so it's either `true` or `false`)
property_default_type = property_default
property_default_type = f'{property_struct_name}({property_default})'
else:
property_default_type = f'{property_struct_name}::{to_camel_case(property_default)}'
@ -208,6 +208,10 @@ def get_property_struct_name(property: Optional[dict], block_data_burger: dict,
if property is None:
return ''.join(map(to_camel_case, property_variants))
if property_variants == ['true', 'false']:
# booleans are weird, so just return the string name minecraft uses
return to_camel_case(property['name'])
for class_name in [block_data_burger['class']] + block_data_burger['super']:
property_name = mappings.get_field(
class_name, property['field_name'])