default block properties

This commit is contained in:
mat 2022-05-28 20:59:22 -05:00
parent 8cd0ff2aac
commit 9c1c286236
4 changed files with 123 additions and 37 deletions

View file

@ -20,10 +20,14 @@ struct PropertyDefinitions {
properties: Vec<PropertyDefinition>, properties: Vec<PropertyDefinition>,
} }
struct PropertyAndDefault {
name: Ident,
default: Ident,
}
struct BlockDefinition { struct BlockDefinition {
name: Ident, name: Ident,
behavior: Expr, behavior: Expr,
properties: Punctuated<Ident, Token![,]>, properties_and_defaults: Vec<PropertyAndDefault>,
} }
struct BlockDefinitions { struct BlockDefinitions {
blocks: Vec<BlockDefinition>, blocks: Vec<BlockDefinition>,
@ -39,14 +43,14 @@ impl Parse for PropertyDefinition {
// Floor, // Floor,
// Wall, // Wall,
// Ceiling // Ceiling
// }; // },
let name = input.parse()?; let name = input.parse()?;
let content; let content;
braced!(content in input); braced!(content in input);
let variants = content.parse_terminated(Ident::parse)?; let variants = content.parse_terminated(Ident::parse)?;
input.parse::<Token![;]>()?; input.parse::<Token![,]>()?;
Ok(PropertyDefinition { name, variants }) Ok(PropertyDefinition { name, variants })
} }
} }
@ -66,11 +70,11 @@ impl Parse for PropertyDefinitions {
impl Parse for BlockDefinition { impl Parse for BlockDefinition {
fn parse(input: ParseStream) -> Result<Self> { fn parse(input: ParseStream) -> Result<Self> {
// acacia_button => BlockBehavior { has_collision: false }, { // acacia_button => BlockBehavior::default().no_collision(), {
// Face, // Face,
// Facing, // Facing,
// Powered // Powered
// }; // },
let name = input.parse()?; let name = input.parse()?;
input.parse::<Token![=>]>()?; input.parse::<Token![=>]>()?;
let behavior = input.parse()?; let behavior = input.parse()?;
@ -78,12 +82,29 @@ impl Parse for BlockDefinition {
input.parse::<Token![,]>()?; input.parse::<Token![,]>()?;
let content; let content;
braced!(content in input); braced!(content in input);
let properties = content.parse_terminated(Ident::parse)?;
input.parse::<Token![;]>()?; let mut properties_and_defaults = Vec::new();
loop {
let property = match content.parse() {
Ok(property) => property,
Err(_) => break,
};
content.parse::<Token![=]>()?;
let property_default = content.parse()?;
properties_and_defaults.push(PropertyAndDefault {
name: property,
default: property_default,
});
if content.parse::<Token![,]>().is_err() {
break;
}
}
input.parse::<Token![,]>()?;
Ok(BlockDefinition { Ok(BlockDefinition {
name, name,
behavior, behavior,
properties, properties_and_defaults,
}) })
} }
} }
@ -109,6 +130,8 @@ impl Parse for MakeBlockStates {
braced!(content in input); braced!(content in input);
let properties = content.parse()?; let properties = content.parse()?;
input.parse::<Token![,]>()?;
let blocks_ident = input.parse::<Ident>()?; let blocks_ident = input.parse::<Ident>()?;
assert_eq!(blocks_ident.to_string(), "Blocks"); assert_eq!(blocks_ident.to_string(), "Blocks");
input.parse::<Token![=>]>()?; input.parse::<Token![=>]>()?;
@ -183,9 +206,9 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
let mut from_state_to_block_match = quote! {}; let mut from_state_to_block_match = quote! {};
for block in &input.block_definitions.blocks { for block in &input.block_definitions.blocks {
let block_property_names = &block let block_property_names = &block
.properties .properties_and_defaults
.iter() .iter()
.map(|p| p.to_string()) .map(|p| p.name.to_string())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut block_properties_vec = Vec::new(); let mut block_properties_vec = Vec::new();
for property_name in block_property_names { for property_name in block_property_names {
@ -200,7 +223,7 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
// pub facing: properties::Facing, // pub facing: properties::Facing,
// pub powered: properties::Powered, // pub powered: properties::Powered,
let mut block_struct_fields = quote! {}; let mut block_struct_fields = quote! {};
for property in &block.properties { for PropertyAndDefault { name: property, .. } in &block.properties_and_defaults {
let property_name_snake = let property_name_snake =
Ident::new(&property.to_string(), proc_macro2::Span::call_site()); Ident::new(&property.to_string(), proc_macro2::Span::call_site());
block_struct_fields.extend(quote! { block_struct_fields.extend(quote! {
@ -268,12 +291,16 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
// } // }
let mut from_state_to_block_inner = quote! {}; let mut from_state_to_block_inner = quote! {};
let mut division = 1usize; let mut division = 1usize;
for i in (0..block.properties.len()).rev() { for i in (0..block.properties_and_defaults.len()).rev() {
let property = &block.properties[i]; let PropertyAndDefault {
name: property_name,
..
} = &block.properties_and_defaults[i];
let property_variants = &block_properties_vec[i]; let property_variants = &block_properties_vec[i];
let property_variants_count = property_variants.len(); let property_variants_count = property_variants.len();
from_state_to_block_inner.extend(quote! { from_state_to_block_inner.extend(quote! {
#property: #property::from((b / #division) % #property_variants_count), #property_name: #property_name::from((b / #division) % #property_variants_count),
}); });
division *= property_variants_count; division *= property_variants_count;
@ -289,6 +316,17 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
}, },
}); });
let mut block_default_fields = quote! {};
for PropertyAndDefault {
name: property,
default: property_default,
} in &block.properties_and_defaults
{
block_default_fields.extend(quote! {
#property: #property::#property_default,
})
}
let block_behavior = &block.behavior; let block_behavior = &block.behavior;
let block_id = block.name.to_string(); let block_id = block.name.to_string();
let block_struct = quote! { let block_struct = quote! {
@ -314,6 +352,13 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
} }
} }
impl Default for #block_struct_name {
fn default() -> Self {
Self {
#block_default_fields
}
}
}
}; };
block_structs.extend(block_struct); block_structs.extend(block_struct);

View file

@ -12,43 +12,43 @@ make_block_states! {
Floor, Floor,
Wall, Wall,
Ceiling Ceiling
}; },
Facing { Facing {
North, North,
South, South,
West, West,
East East
}; },
Powered { Powered {
True, True,
False False
}; },
Half { Half {
Upper, Upper,
Lower Lower
}; },
Hinge { Hinge {
Left, Left,
Right Right
}; },
Open { Open {
True, True,
False False
}; },
} },
Blocks => { Blocks => {
acacia_button => BlockBehavior::default().no_collision(), { acacia_button => BlockBehavior::default().no_collision(), {
Face, Face=Floor,
Facing, Facing=North,
Powered Powered=True
}; },
acacia_door => BlockBehavior::default(), { acacia_door => BlockBehavior::default(), {
Facing, Facing=North,
Half, Half=Upper,
Hinge, Hinge=Left,
Open, Open=True,
Powered Powered=True
}; },
} }
} }

View file

@ -1,5 +1,6 @@
from lib.utils import to_camel_case
from lib.utils import get_dir_location from lib.utils import get_dir_location
import json
BLOCKS_RS_DIR = get_dir_location('../azalea-block/src/blocks.rs') BLOCKS_RS_DIR = get_dir_location('../azalea-block/src/blocks.rs')
@ -11,10 +12,45 @@ def generate_blocks(blocks: dict):
new_make_block_states_macro_code = [] new_make_block_states_macro_code = []
new_make_block_states_macro_code.append('make_block_states! {') new_make_block_states_macro_code.append('make_block_states! {')
# Find properties
properties = {} properties = {}
for block_name, block_data in blocks.items(): for block_data in blocks.values():
block_properties = block_data['properties'] block_properties = block_data.get('properties', {})
properties.update(block_properties) properties.update(block_properties)
print(properties) # Property codegen
new_make_block_states_macro_code.append(' Properties => {')
for property_name, property_variants in properties.items():
new_make_block_states_macro_code.append(
f' {to_camel_case(property_name)} => {{')
for variant in property_variants:
new_make_block_states_macro_code.append(
f' {to_camel_case(variant)},')
new_make_block_states_macro_code.append(
f' }},')
new_make_block_states_macro_code.append(' },')
# Block codegen
new_make_block_states_macro_code.append(' Blocks => {')
for block_id, block_data in blocks.items():
block_id = block_id.split(':')[1]
block_states = block_data['states']
default_property_variants = {}
for state in block_states:
if state.get('default'):
default_property_variants = state.get('properties', {})
# TODO: use burger to generate the blockbehavior
new_make_block_states_macro_code.append(
f' {block_id} => BlockBehavior::default(), {{')
for property in block_data.get('properties', {}):
property_default = default_property_variants.get(property)
new_make_block_states_macro_code.append(
f' {to_camel_case(property)}={to_camel_case(property_default)},')
new_make_block_states_macro_code.append(' },')
new_make_block_states_macro_code.append(' },')
print('\n'.join(new_make_block_states_macro_code))

View file

@ -11,7 +11,12 @@ def to_snake_case(name: str):
def to_camel_case(name: str): def to_camel_case(name: str):
s = re.sub('_([a-z])', lambda m: m.group(1).upper(), name) s = re.sub('_([a-z])', lambda m: m.group(1).upper(), name)
return s[0].upper() + s[1:] s = s[0].upper() + s[1:]
# if the first character is a number, we need to add an underscore
# maybe we could convert it to the number name (like 2 would become "two")?
if s[0].isdigit():
s = f'_{s}'
return s
def padded_hex(n: int): def padded_hex(n: int):