block macros

This commit is contained in:
mat 2022-05-27 23:10:34 -05:00
parent c0433b7d49
commit d56c44766e
4 changed files with 109 additions and 17 deletions

View file

@ -1,13 +1,16 @@
mod utils;
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use std::fmt::Debug;
use quote::quote;
use std::collections::HashMap;
use syn::{
self, braced,
parse::{Parse, ParseStream, Result},
parse_macro_input,
punctuated::Punctuated,
Data, DeriveInput, Expr, FieldsNamed, Ident, LitInt, Token,
Expr, Ident, Token,
};
use utils::{combinations_of, to_pascal_case};
struct PropertyDefinition {
name: Ident,
@ -71,6 +74,7 @@ impl Parse for BlockDefinition {
let name = input.parse()?;
input.parse::<Token![=>]>()?;
let behavior = input.parse()?;
input.parse::<Token![,]>()?;
let content;
braced!(content in input);
@ -124,14 +128,16 @@ 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();
for property in &input.property_definitions.properties {
let mut property_enum_variants = quote! {};
let mut property_enum_variant_names = Vec::new();
for variant in &property.variants {
property_enum_variants.extend(quote! {
#variant,
});
property_enum_variant_names.push(variant.to_string());
}
let property_name = &property.name;
@ -142,20 +148,46 @@ pub fn make_block_states(input: TokenStream) -> TokenStream {
#property_enum_variants
}
});
properties_map.insert(property_name.to_string(), property_enum_variant_names);
}
// let mut block_state_enum_variants = quote! {};
// for block in &input.block_definitions.blocks {
// let block_state_enum_variant = quote! {
// #block.name(#block.behavior, #block.properties)
// };
// block_state_enum_variants.extend(block_state_enum_variant);
// }
let mut block_state_enum_variants = quote! {};
for block in &input.block_definitions.blocks {
let block_properties = &block.properties;
let mut block_properties_vec = Vec::new();
for property in block_properties {
let property_name = &property.to_string();
let property_variants = properties_map
.get(property_name)
.expect(format!("Property '{}' not found", property_name).as_str())
.clone();
block_properties_vec.push(property_variants);
}
for combination in combinations_of(&block_properties_vec) {
let variant_name = Ident::new(
&format!(
"{}_{}",
to_pascal_case(&block.name.to_string()),
combination
.iter()
.map(|v| v.to_string())
.collect::<Vec<String>>()
.join("")
),
proc_macro2::Span::call_site(),
);
block_state_enum_variants.extend(quote! {
#variant_name,
});
}
}
quote! {
#property_enums
// #block_state_enum_variants
pub enum BlockState {
#block_state_enum_variants
}
}
.into()
}

View file

@ -0,0 +1,39 @@
pub fn combinations_of<T: Clone>(items: &[Vec<T>]) -> Vec<Vec<T>> {
let mut combinations = Vec::new();
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::new();
combination.push(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
}

View file

@ -1,4 +1,3 @@
use crate::behavior::BlockBehavior;
use block_macros::make_block_states;
make_block_states! {
@ -8,14 +7,36 @@ make_block_states! {
Wall,
Ceiling
};
Facing {
North,
South,
West,
East
};
Powered {
True,
False
};
Half {
Upper,
Lower
};
Hinge {
Left,
Right
};
Open {
True,
False
};
}
BLOCKS => {
acacia_button => BlockBehavior { has_collision: false }, {
acacia_button => BlockBehavior::new().no_collision(), {
Face,
Facing,
Powered
};
acacia_door => BlockBehavior { has_collision: true }, {
acacia_door => BlockBehavior::new(), {
Facing,
Half,
Hinge,

View file

@ -14,7 +14,7 @@ loop {
pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0))
).await;
let chest = bot.open_chest(&bot.world.find_one_block(|b| b.id == "minecraft:chest")).await.unwrap();
bot.take_amount(&chest, 3, |i| i.id == "#minecraft:planks").await;
bot.take_amount(&chest, 5, |i| i.id == "#minecraft:planks").await;
// when rust adds async drop this won't be necessary
chest.close().await;