From 3aa5438fed005be5cf7e04a05138b65d3b485bf4 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Tue, 8 Apr 2025 19:15:27 +0200 Subject: [PATCH] Create new update interface --- ecs/src/update_testing.rs | 20 +++- ecs/src/updates.rs | 192 ++++++++++++++++++++++++-------------- ecs/src/world.rs | 6 +- 3 files changed, 143 insertions(+), 75 deletions(-) diff --git a/ecs/src/update_testing.rs b/ecs/src/update_testing.rs index 36ff4ad..215d86d 100644 --- a/ecs/src/update_testing.rs +++ b/ecs/src/update_testing.rs @@ -129,7 +129,7 @@ macro_rules! impl_query_singleton_update { }; } -impl_query_singleton_update!(R); +impl_query_singleton_update!(R, U); struct T {} @@ -145,10 +145,24 @@ impl ComponentDebug for T { } } -fn system(_commands: &mut Commands, mut _query: Query<&mut T>) -> Result<()> { +struct U {} + +impl EntityComponent for U { + fn name(&self) -> &str { + Self::debug_name() + } +} + +impl ComponentDebug for U { + fn debug_name() -> &'static str { + "U" + } +} + +fn system(_commands: &mut Commands, mut _query: Query<(&mut T, &mut U)>) -> Result<()> { Ok(()) } fn test() { - // let q = QueryArchetype::create(system); + let q = QueryArchetype::create(system); } diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs index 55ffdba..0b656c8 100644 --- a/ecs/src/updates.rs +++ b/ecs/src/updates.rs @@ -1,6 +1,7 @@ #![allow(clippy::type_complexity)] -use std::any::TypeId; +use std::ops::{Deref, DerefMut}; +use std::{any::TypeId, marker::PhantomData}; use std::collections::HashMap; #[cfg(feature = "timings")] @@ -21,16 +22,16 @@ macro_rules! impl_singleton_update { ( $($var:ident $(,)?)+ ) => { impl CreateArchetype<( $( $var, )+ ), (), Func, Filter> for Archetype where - Func: Fn(&mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(&mut Commands, Query<( $( &mut $var, )+ ), Filter>) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static, $( $var: EntityComponent + ComponentDebug, )+ { paste::item! { - fn create(f: Func, filter: Filter) -> Self { + fn create(f: Func) -> Self { $( - filter.verify_dedup::<$var>(); + Filter::verify_dedup::<$var>(); )+ Self { @@ -42,7 +43,7 @@ macro_rules! impl_singleton_update { } )+ - if !filter.check(entity) { + if !Filter::check(entity) { return false; } @@ -57,10 +58,17 @@ macro_rules! impl_singleton_update { ); )+ + let e = entity.as_entity(); let f = f.clone(); - Ok(Box::new(move |e, commands, _world| { - unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+) } + Ok(Box::new(move |commands, _world| { + let query = Query { + entity: e, + c: unsafe { ($([< $var:lower >].as_mut(),)+) }, + filter: PhantomData, + }; + + f(commands, query) })) }), @@ -75,7 +83,7 @@ macro_rules! impl_singleton_update { $( $var: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(& mut Commands, Query<( $( &mut $var, )+ ), Filter>) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static { fn add_update( @@ -83,10 +91,9 @@ macro_rules! impl_singleton_update { name: &str, priority: u32, func: Func, - filter: Filter ) -> Result<()> { paste::item! { - self.add(name, priority, Update::Single(Archetype::create(func, filter))) + self.add(name, priority, Update::Single(Archetype::create(func))) } } } @@ -96,7 +103,7 @@ macro_rules! impl_singleton_update { $( $var: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut Commands, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(& mut Commands, Query<( $( &mut $var, )+ ), Filter>) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static { fn add_update( @@ -104,9 +111,8 @@ macro_rules! impl_singleton_update { name: &str, priority: u32, func: Func, - filter: Filter, ) -> Result<()> { - self.updates.add_update(name, priority, func, filter) + self.updates.add_update(name, priority, func) } } }; @@ -114,7 +120,7 @@ macro_rules! impl_singleton_update { ( $($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, + Func: Fn(&mut Commands, Query<( $( &mut $var, )+ ), Filter>, $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static, $( $var: EntityComponent + ComponentDebug, @@ -124,9 +130,9 @@ macro_rules! impl_singleton_update { )+ { paste::item! { - fn create(f: Func, filter: Filter) -> Self { + fn create(f: Func) -> Self { $( - filter.verify_dedup::<$var>(); + Filter::verify_dedup::<$var>(); )+ Self { @@ -138,7 +144,7 @@ macro_rules! impl_singleton_update { } )+ - if !filter.check(entity) { + if !Filter::check(entity) { return false; } @@ -153,9 +159,10 @@ macro_rules! impl_singleton_update { ); )+ + let e = entity.as_entity(); let f = f.clone(); - Ok(Box::new(move |e, commands, world| { + Ok(Box::new(move |commands, world| { let ( $( @@ -167,7 +174,13 @@ macro_rules! impl_singleton_update { )+ ) = world.resources.get_mut()?; - unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+ $([< $res:lower _var >],)+) } + let query = Query { + entity: e, + c: unsafe { ($([< $var:lower >].as_mut(),)+) }, + filter: PhantomData, + }; + + f(commands, query, $([< $res:lower _var >],)+) })) }), @@ -185,7 +198,7 @@ macro_rules! impl_singleton_update { $( $res: ResourceTrait, )+ - Func: Fn(& mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(& mut Commands, Query<( $( &mut $var, )+ ), Filter>, $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static { fn add_update( @@ -193,10 +206,9 @@ macro_rules! impl_singleton_update { name: &str, priority: u32, func: Func, - filter: Filter ) -> Result<()> { paste::item! { - self.add(name, priority, Update::Single(Archetype::create(func, filter))) + self.add(name, priority, Update::Single(Archetype::create(func))) } } } @@ -209,7 +221,7 @@ macro_rules! impl_singleton_update { $( $res: ResourceTrait, )+ - Func: Fn(& mut Commands, Entity, $(&mut $var,)+ $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(& mut Commands, Query<( $( &mut $var, )+ ), Filter>, $(&mut $res,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static { fn add_update( @@ -217,9 +229,8 @@ macro_rules! impl_singleton_update { name: &str, priority: u32, func: Func, - filter: Filter, ) -> Result<()> { - self.updates.add_update(name, priority, func, filter) + self.updates.add_update(name, priority, func) } } }; @@ -235,9 +246,9 @@ macro_rules! impl_pair_update { impl ArchetypePair { paste::item! { pub fn [] - (f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self + (f: F) -> Self where - F: Fn(&mut Commands, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, + F: Fn(&mut Commands, Query<( $( &mut $lhs_big, )+ ), LeftFilter>, Query<( $( &mut $rhs_big, )+ ), RightFilter>) -> Result<()> + Send + Sync + Clone + 'static, LeftFilter: CheckFilter + 'static, RightFilter: CheckFilter + 'static, $( @@ -248,11 +259,11 @@ macro_rules! impl_pair_update { )+ { $( - left_filter.verify_dedup::<$lhs_big>(); + LeftFilter::verify_dedup::<$lhs_big>(); )+ $( - right_filter.verify_dedup::<$rhs_big>(); + RightFilter::verify_dedup::<$rhs_big>(); )+ Self { @@ -264,7 +275,7 @@ macro_rules! impl_pair_update { } )+ - if !left_filter.check(entity) { + if !LeftFilter::check(entity) { return false; } @@ -279,7 +290,7 @@ macro_rules! impl_pair_update { } )+ - if !right_filter.check(entity) { + if !RightFilter::check(entity) { return false; } @@ -300,10 +311,24 @@ macro_rules! impl_pair_update { ); )+ + let lhs_e = lhs_entity.as_entity(); + let rhs_e = rhs_entity.as_entity(); let f = f.clone(); - Ok(Box::new(move |lhs_e, rhs_e, commands| { - unsafe { f(commands, (lhs_e, $($lhs_little.as_mut(),)+), (rhs_e, $($rhs_little.as_mut(),)+) ) } + Ok(Box::new(move |commands| { + let lhs_query = Query { + entity: lhs_e, + c: unsafe { ($($lhs_little.as_mut(),)+) }, + filter: PhantomData, + }; + + let rhs_query = Query { + entity: rhs_e, + c: unsafe { ($($rhs_little.as_mut(),)+) }, + filter: PhantomData, + }; + + f(commands, lhs_query, rhs_query ) })) }), @@ -321,7 +346,7 @@ macro_rules! impl_pair_update { $( $lhs_big: EntityComponent + ComponentDebug, )+ - Func: Fn(&mut Commands, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(&mut Commands, Query<( $( &mut $lhs_big, )+ ), LhsFilter>, Query<( $( &mut $rhs_big, )+ ), RhsFilter>) -> Result<()> + Send + Sync + Clone + 'static, LhsFilter: CheckFilter + 'static, RhsFilter: CheckFilter + 'static { @@ -330,10 +355,9 @@ macro_rules! impl_pair_update { name: &str, priority: u32, func: Func, - filter: (LhsFilter, RhsFilter) ) -> Result<()> { paste::item! { - self.add(name, priority, Update::Pair(ArchetypePair::[](func, filter.0, filter.1)))?; + self.add(name, priority, Update::Pair(ArchetypePair::[](func)))?; } Ok(()) @@ -348,7 +372,7 @@ macro_rules! impl_pair_update { $( $lhs_big: EntityComponent + ComponentDebug, )+ - Func: Fn(& mut Commands, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, + Func: Fn(& mut Commands, Query<( $( &mut $lhs_big, )+ ), LhsFilter>, Query<( $( &mut $rhs_big, )+ ), RhsFilter>) -> Result<()> + Send + Sync + Clone + 'static, LhsFilter: CheckFilter + 'static, RhsFilter: CheckFilter + 'static { @@ -357,9 +381,8 @@ macro_rules! impl_pair_update { name: &str, priority: u32, func: Func, - filter: (LhsFilter, RhsFilter), ) -> Result<()> { - self.updates.add_update(name, priority, func, filter) + self.updates.add_update(name, priority, func) } } }; @@ -385,7 +408,7 @@ macro_rules! impl_update_filter { } impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> { - fn check(&self, entity: &EntityObject) -> bool { + fn check(entity: &EntityObject) -> bool { $( if entity.contains_component::<$big>() { return false; @@ -395,7 +418,7 @@ macro_rules! impl_update_filter { true } - fn verify_dedup(&self) { + fn verify_dedup() { $( if TypeId::of::() == TypeId::of::<$big>() { panic!("Type is used as input and filter at the same time"); @@ -417,28 +440,58 @@ macro_rules! impl_update_filter { }; } +#[derive(Copy, Clone)] +pub struct Query +where + F: CheckFilter, +{ + entity: Entity, + c: C, + filter: PhantomData, +} + +impl Query { + pub fn entity(&self) -> Entity { + self.entity + } +} + +impl Deref for Query { + type Target = C; + + fn deref(&self) -> &Self::Target { + &self.c + } +} + +impl DerefMut for Query { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.c + } +} + pub trait AddUpdates { - fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>; + fn add_update(&mut self, name: &str, priority: u32, func: Func) -> Result<()>; } trait CreateArchetype { - fn create(f: Func, filter: Filter) -> Self; + fn create(f: Func) -> Self; } pub trait CheckFilter: Send + Sync + Default + Clone { - fn check(&self, entity: &EntityObject) -> bool; - fn verify_dedup(&self); + fn check(entity: &EntityObject) -> bool; + fn verify_dedup(); } #[derive(Default, Clone)] pub struct EmptyFilter; impl CheckFilter for EmptyFilter { - fn check(&self, _entity: &EntityObject) -> bool { + fn check(_entity: &EntityObject) -> bool { true } - fn verify_dedup(&self) {} + fn verify_dedup() {} } #[derive(Default, Clone, Debug)] @@ -466,15 +519,12 @@ pub struct Archetype { dyn Fn( &EntityObject, ) - -> Result Result<()> + Send + Sync>> + -> Result Result<()> + Send + Sync>> + Send + Sync, >, - entities: IndexMap< - Entity, - Box Result<()> + Send + Sync>, - >, + entities: IndexMap Result<()> + Send + Sync>>, } impl Archetype { @@ -495,8 +545,8 @@ impl Archetype { pub fn execute(&self, world: &mut World) -> Result<()> { let mut commands = Commands::new(world.now()); - for (entity, callback) in self.entities.iter() { - callback(*entity, &mut commands, world)?; + for callback in self.entities.values() { + callback(&mut commands, world)?; } commands.apply_deferred(world)?; @@ -506,9 +556,13 @@ impl Archetype { pub fn entities( &self, - ) -> &IndexMap Result<()> + Send + Sync>> - { - &self.entities + ) -> impl Iterator< + Item = ( + &Entity, + &Box Result<()> + Send + Sync>, + ), + > { + self.entities.iter() } } @@ -520,16 +574,12 @@ pub struct ArchetypePair { dyn Fn( &EntityObject, &EntityObject, - ) - -> Result Result<()> + Send + Sync>> + ) -> Result Result<()> + Send + Sync>> + Send + Sync, >, - entities: IndexMap< - (Entity, Entity), - Box Result<()> + Send + Sync>, - >, + entities: IndexMap<(Entity, Entity), Box Result<()> + Send + Sync>>, } impl ArchetypePair { @@ -549,8 +599,10 @@ impl ArchetypePair { { let cb = (self.create_callback)(entity_object, other_entity_object)?; - self.entities - .insert((entity_object.as_entity(), *other_entity), cb); + self.entities.insert( + (entity_object.as_entity(), other_entity_object.as_entity()), + cb, + ); } if (self.check_left_entity)(other_entity_object) @@ -558,8 +610,10 @@ impl ArchetypePair { { let cb = (self.create_callback)(other_entity_object, entity_object)?; - self.entities - .insert((*other_entity, entity_object.as_entity()), cb); + self.entities.insert( + (other_entity_object.as_entity(), entity_object.as_entity()), + cb, + ); } } @@ -580,8 +634,8 @@ impl ArchetypePair { pub(crate) fn execute(&self, world: &mut World) -> Result<()> { let mut commands = Commands::new(world.now()); - for ((left_entity, right_entity), callback) in self.entities.iter() { - callback(*left_entity, *right_entity, &mut commands)?; + for callback in self.entities.values() { + callback(&mut commands)?; } commands.apply_deferred(world)?; diff --git a/ecs/src/world.rs b/ecs/src/world.rs index b1e4926..a52705b 100644 --- a/ecs/src/world.rs +++ b/ecs/src/world.rs @@ -278,14 +278,14 @@ impl World { let mut entities = Vec::new(); - for entity in archetype.entities().keys() { + for (&entity, _) in archetype.entities() { #[cfg(debug_assertions)] - let debug_name = self.entity(*entity)?.debug_name.clone(); + let debug_name = self.entity(entity)?.debug_name.clone(); #[cfg(not(debug_assertions))] let debug_name = None; - entities.push((*entity, debug_name)); + entities.push((entity, debug_name)); } Ok(ArchetypeInfo::new(entities))