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:
parent
c9a18bc6a1
commit
31206701b9
4 changed files with 985 additions and 936 deletions
3
azalea-block/.gitignore
vendored
Normal file
3
azalea-block/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# cargo expand generated -p azalea-block > azalea-block/out.rs
|
||||
/out.rs
|
||||
|
|
@ -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
|
@ -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'])
|
||||
|
|
Loading…
Add table
Reference in a new issue