From a72a72f8c1c33a6a1e0d60bce057d858958b1c2a Mon Sep 17 00:00:00 2001 From: hodasemi Date: Tue, 8 Apr 2025 09:01:46 +0200 Subject: [PATCH] Generate resource updates --- ecs/src/resources.rs | 2 + ecs/src/updates.rs | 143 ++++++++++++++++++++++++++--- update_macros/src/lib.rs | 5 - update_macros/src/pair_update.rs | 8 +- update_macros/src/single_update.rs | 41 ++++++++- 5 files changed, 178 insertions(+), 21 deletions(-) diff --git a/ecs/src/resources.rs b/ecs/src/resources.rs index d441efc..4b1c62c 100644 --- a/ecs/src/resources.rs +++ b/ecs/src/resources.rs @@ -149,6 +149,7 @@ macro_rules! impl_get_disjoint_mut { }; } +impl_get_disjoint_mut!(Resources < T > { Error }); impl_get_disjoint_mut!(Resources < T, U > { Error }); impl_get_disjoint_mut!(Resources < T, U, V > { Error }); impl_get_disjoint_mut!(Resources < T, U, V, W > { Error }); @@ -157,3 +158,4 @@ impl_get_disjoint_mut!(Resources < T, U, V, W, X, Y > { Error }); impl_get_disjoint_mut!(Resources < T, U, V, W, X, Y, Z > { Error }); impl_get_disjoint_mut!(Resources < T, U, V, W, X, Y, Z, A > { Error }); impl_get_disjoint_mut!(Resources < T, U, V, W, X, Y, Z, A, B > { Error }); +impl_get_disjoint_mut!(Resources < T, U, V, W, X, Y, Z, A, B, C > { Error }); diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs index 3a8ba38..8385a13 100644 --- a/ecs/src/updates.rs +++ b/ecs/src/updates.rs @@ -13,12 +13,14 @@ use indexmap::IndexMap; #[cfg(feature = "timings")] use super::super::timings::Timings; +use crate::resources::Resource as ResourceTrait; use crate::*; use update_macros::{implement_pair_update, implement_single_update}; macro_rules! impl_singleton_update { + // without resources ( $($var:ident $(,)?)+ ) => { - impl CreateArchetype<( $( $var, )+ ), Func, Filter> for Archetype + impl CreateArchetype<( $( $var, )+ ), (), Func, Filter> for Archetype where Func: Fn(&mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static, @@ -58,7 +60,7 @@ macro_rules! impl_singleton_update { let f = f.clone(); - Ok(Box::new(move |e, commands| { + Ok(Box::new(move |e, commands, _world| { unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+) } })) }), @@ -69,7 +71,7 @@ macro_rules! impl_singleton_update { } } - impl AddUpdates<( $( $var, )+ ), Func, Filter> for Updates + impl AddUpdates<( $( $var, )+ ), (), Func, Filter> for Updates where $( $var: EntityComponent + ComponentDebug, @@ -90,7 +92,7 @@ macro_rules! impl_singleton_update { } } - impl AddUpdates<( $( $var, )+ ), Func, Filter> for WorldBuilder + impl AddUpdates<( $( $var, )+ ), (), Func, Filter> for WorldBuilder where $( $var: EntityComponent + ComponentDebug, @@ -109,6 +111,119 @@ macro_rules! impl_singleton_update { } } }; + // with resources + ( $($var:ident $(,)?)+ [$($res:ident $(,)?)+] ) => { + impl CreateArchetype<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for Archetype + where + Func: Fn(&mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, + Filter: CheckFilter + 'static, + $( + $var: EntityComponent + ComponentDebug, + )+ + $( + $res: ResourceTrait, + )+ + { + paste::item! { + fn create(f: Func, filter: Filter) -> Self { + $( + filter.verify_dedup::<$var>(); + )+ + + Self { + check_entity: Box::new({ + move |entity| { + $( + if !entity.components.contains::<$var>() { + return false; + } + )+ + + if !filter.check(entity) { + return false; + } + + true + } + }), + + create_callback: Box::new(move |entity| { + $( + let [< $var:lower >] = UnsafeComponentStore::from( + entity.get_component::<$var>()? + ); + )+ + + let f = f.clone(); + + Ok(Box::new(move |e, commands, world| { + + let ( + $( + [< $res:lower _var >], + )+ + ): ( + $( + &mut $res, + )+ + ) = world.resources.get_mut()?; + + unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+ $([< $res:lower _var >],)+) } + })) + }), + + entities: IndexMap::new(), + } + } + } + } + + impl AddUpdates<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for Updates + where + $( + $var: EntityComponent + ComponentDebug, + )+ + $( + $res: ResourceTrait, + )+ + Func: Fn(& mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, + Filter: CheckFilter + 'static + { + fn add_update( + &mut self, + name: &str, + priority: u32, + func: Func, + filter: Filter + ) -> Result<()> { + paste::item! { + self.add(name, priority, Update::Single(Archetype::create(func, filter))) + } + } + } + + impl AddUpdates<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for WorldBuilder + where + $( + $var: EntityComponent + ComponentDebug, + )+ + $( + $res: ResourceTrait, + )+ + Func: Fn(& mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, + Filter: CheckFilter + 'static + { + fn add_update( + &mut self, + name: &str, + priority: u32, + func: Func, + filter: Filter, + ) -> Result<()> { + self.updates.add_update(name, priority, func, filter) + } + } + }; } macro_rules! impl_pair_update { @@ -199,7 +314,7 @@ macro_rules! impl_pair_update { } } - impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for Updates + impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), (), Func, (LhsFilter, RhsFilter)> for Updates where $( $rhs_big: EntityComponent + ComponentDebug, @@ -226,7 +341,7 @@ macro_rules! impl_pair_update { } } - impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for WorldBuilder + impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), (), Func, (LhsFilter, RhsFilter)> for WorldBuilder where $( $rhs_big: EntityComponent + ComponentDebug, @@ -312,11 +427,11 @@ where d: PhantomData, } -pub trait AddUpdates { +pub trait AddUpdates { fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>; } -trait CreateArchetype { +trait CreateArchetype { fn create(f: Func, filter: Filter) -> Self; } @@ -361,12 +476,15 @@ pub struct Archetype { dyn Fn( &EntityObject, ) - -> Result Result<()> + Send + Sync>> + -> Result Result<()> + Send + Sync>> + Send + Sync, >, - entities: IndexMap Result<()> + Send + Sync>>, + entities: IndexMap< + Entity, + Box Result<()> + Send + Sync>, + >, } impl Archetype { @@ -387,7 +505,7 @@ impl Archetype { pub fn execute(&self, world: &mut World) -> Result<()> { for (entity, callback) in self.entities.iter() { let mut commands = Commands::default(); - callback(*entity, &mut commands)?; + callback(*entity, &mut commands, world)?; commands.apply_deferred(world)?; } @@ -396,7 +514,8 @@ impl Archetype { pub fn entities( &self, - ) -> &IndexMap Result<()> + Send + Sync>> { + ) -> &IndexMap Result<()> + Send + Sync>> + { &self.entities } } diff --git a/update_macros/src/lib.rs b/update_macros/src/lib.rs index 9a7c524..3479469 100644 --- a/update_macros/src/lib.rs +++ b/update_macros/src/lib.rs @@ -35,11 +35,6 @@ impl Parse for InputInfo { } } -struct TupleType { - little: Ident, - big: Ident, -} - #[proc_macro] pub fn implement_pair_update(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as InputInfo); diff --git a/update_macros/src/pair_update.rs b/update_macros/src/pair_update.rs index f9c90db..0471a6e 100644 --- a/update_macros/src/pair_update.rs +++ b/update_macros/src/pair_update.rs @@ -1,10 +1,14 @@ use proc_macro::TokenStream; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{format_ident, quote}; -use syn::LitInt; +use syn::{Ident, LitInt}; use crate::InputInfo; -use crate::TupleType; + +struct TupleType { + little: Ident, + big: Ident, +} pub fn pair_update(input: InputInfo) -> TokenStream { let mut generic_count = Vec::new(); diff --git a/update_macros/src/single_update.rs b/update_macros/src/single_update.rs index 6441606..d81866a 100644 --- a/update_macros/src/single_update.rs +++ b/update_macros/src/single_update.rs @@ -5,7 +5,43 @@ use syn::Ident; use crate::InputInfo; +const MIN_RESOURCE: usize = 1; + pub fn single_update(input: InputInfo) -> TokenStream { + let mut generic_counts = Vec::new(); + + for components in input.start..=input.end { + for resources in MIN_RESOURCE..=input.end { + generic_counts.push((components, resources)); + } + } + + let generics: Vec<(Vec, Vec)> = generic_counts + .into_iter() + .map(|(component_count, resource_count)| { + let components = (input.start..(input.start + component_count)) + .map(|i| format_ident!("t{}", i)) + .collect(); + + let resources = (MIN_RESOURCE..(MIN_RESOURCE + resource_count)) + .map(|i| format_ident!("r{}", i)) + .collect(); + + (components, resources) + }) + .collect(); + + let resource_invocations: Vec = generics + .iter() + .map(|(components, resources)| { + let macro_ident = &input.macro_ident; + + quote! { + #macro_ident!(#(#components,)* [#(#resources,)*]); + } + }) + .collect(); + let generate_inputs: Vec> = (input.start..=input.end) .map(|count| { (input.start..(input.start + count)) @@ -14,7 +50,7 @@ pub fn single_update(input: InputInfo) -> TokenStream { }) .collect(); - let invocations: Vec = generate_inputs + let empty_resource_invocations: Vec = generate_inputs .iter() .map(|t| { let macro_ident = &input.macro_ident; @@ -27,7 +63,8 @@ pub fn single_update(input: InputInfo) -> TokenStream { TokenStream::from(quote! { #( - #invocations + #empty_resource_invocations + #resource_invocations )* }) }