Create new update interface

This commit is contained in:
hodasemi 2025-04-08 19:15:27 +02:00
parent 540be64f6a
commit 3aa5438fed
3 changed files with 143 additions and 75 deletions

View file

@ -129,7 +129,7 @@ macro_rules! impl_query_singleton_update {
}; };
} }
impl_query_singleton_update!(R); impl_query_singleton_update!(R, U);
struct T {} 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(()) Ok(())
} }
fn test() { fn test() {
// let q = QueryArchetype::create(system); let q = QueryArchetype::create(system);
} }

View file

@ -1,6 +1,7 @@
#![allow(clippy::type_complexity)] #![allow(clippy::type_complexity)]
use std::any::TypeId; use std::ops::{Deref, DerefMut};
use std::{any::TypeId, marker::PhantomData};
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "timings")] #[cfg(feature = "timings")]
@ -21,16 +22,16 @@ macro_rules! impl_singleton_update {
( $($var:ident $(,)?)+ ) => { ( $($var:ident $(,)?)+ ) => {
impl<Func, Filter, $( $var, )+> CreateArchetype<( $( $var, )+ ), (), Func, Filter> for Archetype impl<Func, Filter, $( $var, )+> CreateArchetype<( $( $var, )+ ), (), Func, Filter> for Archetype
where 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, Filter: CheckFilter + 'static,
$( $(
$var: EntityComponent + ComponentDebug, $var: EntityComponent + ComponentDebug,
)+ )+
{ {
paste::item! { paste::item! {
fn create(f: Func, filter: Filter) -> Self { fn create(f: Func) -> Self {
$( $(
filter.verify_dedup::<$var>(); Filter::verify_dedup::<$var>();
)+ )+
Self { Self {
@ -42,7 +43,7 @@ macro_rules! impl_singleton_update {
} }
)+ )+
if !filter.check(entity) { if !Filter::check(entity) {
return false; return false;
} }
@ -57,10 +58,17 @@ macro_rules! impl_singleton_update {
); );
)+ )+
let e = entity.as_entity();
let f = f.clone(); let f = f.clone();
Ok(Box::new(move |e, commands, _world| { Ok(Box::new(move |commands, _world| {
unsafe { f(commands, e, $([< $var:lower >].as_mut(),)+) } 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, $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 Filter: CheckFilter + 'static
{ {
fn add_update( fn add_update(
@ -83,10 +91,9 @@ macro_rules! impl_singleton_update {
name: &str, name: &str,
priority: u32, priority: u32,
func: Func, func: Func,
filter: Filter
) -> Result<()> { ) -> Result<()> {
paste::item! { 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, $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 Filter: CheckFilter + 'static
{ {
fn add_update( fn add_update(
@ -104,9 +111,8 @@ macro_rules! impl_singleton_update {
name: &str, name: &str,
priority: u32, priority: u32,
func: Func, func: Func,
filter: Filter,
) -> Result<()> { ) -> 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 $(,)?)+] ) => { ( $($var:ident $(,)?)+ [$($res:ident $(,)?)+] ) => {
impl<Func, Filter, $( $var, )+ $( $res, )+> CreateArchetype<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for Archetype impl<Func, Filter, $( $var, )+ $( $res, )+> CreateArchetype<( $( $var, )+ ), ( $( $res, )+ ), Func, Filter> for Archetype
where 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, Filter: CheckFilter + 'static,
$( $(
$var: EntityComponent + ComponentDebug, $var: EntityComponent + ComponentDebug,
@ -124,9 +130,9 @@ macro_rules! impl_singleton_update {
)+ )+
{ {
paste::item! { paste::item! {
fn create(f: Func, filter: Filter) -> Self { fn create(f: Func) -> Self {
$( $(
filter.verify_dedup::<$var>(); Filter::verify_dedup::<$var>();
)+ )+
Self { Self {
@ -138,7 +144,7 @@ macro_rules! impl_singleton_update {
} }
)+ )+
if !filter.check(entity) { if !Filter::check(entity) {
return false; return false;
} }
@ -153,9 +159,10 @@ macro_rules! impl_singleton_update {
); );
)+ )+
let e = entity.as_entity();
let f = f.clone(); let f = f.clone();
Ok(Box::new(move |e, commands, world| { Ok(Box::new(move |commands, world| {
let ( let (
$( $(
@ -167,7 +174,13 @@ macro_rules! impl_singleton_update {
)+ )+
) = world.resources.get_mut()?; ) = 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, $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 Filter: CheckFilter + 'static
{ {
fn add_update( fn add_update(
@ -193,10 +206,9 @@ macro_rules! impl_singleton_update {
name: &str, name: &str,
priority: u32, priority: u32,
func: Func, func: Func,
filter: Filter
) -> Result<()> { ) -> Result<()> {
paste::item! { 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, $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 Filter: CheckFilter + 'static
{ {
fn add_update( fn add_update(
@ -217,9 +229,8 @@ macro_rules! impl_singleton_update {
name: &str, name: &str,
priority: u32, priority: u32,
func: Func, func: Func,
filter: Filter,
) -> Result<()> { ) -> 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 { impl ArchetypePair {
paste::item! { paste::item! {
pub fn [<create_lhs_ $lhs_id _rhs_ $rhs_id>] <F, LeftFilter, RightFilter, $($lhs_big,)+ $($rhs_big,)+> pub fn [<create_lhs_ $lhs_id _rhs_ $rhs_id>] <F, LeftFilter, RightFilter, $($lhs_big,)+ $($rhs_big,)+>
(f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self (f: F) -> Self
where 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, LeftFilter: CheckFilter + 'static,
RightFilter: 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 { Self {
@ -264,7 +275,7 @@ macro_rules! impl_pair_update {
} }
)+ )+
if !left_filter.check(entity) { if !LeftFilter::check(entity) {
return false; return false;
} }
@ -279,7 +290,7 @@ macro_rules! impl_pair_update {
} }
)+ )+
if !right_filter.check(entity) { if !RightFilter::check(entity) {
return false; 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(); let f = f.clone();
Ok(Box::new(move |lhs_e, rhs_e, commands| { Ok(Box::new(move |commands| {
unsafe { f(commands, (lhs_e, $($lhs_little.as_mut(),)+), (rhs_e, $($rhs_little.as_mut(),)+) ) } 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, $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, LhsFilter: CheckFilter + 'static,
RhsFilter: CheckFilter + 'static RhsFilter: CheckFilter + 'static
{ {
@ -330,10 +355,9 @@ macro_rules! impl_pair_update {
name: &str, name: &str,
priority: u32, priority: u32,
func: Func, func: Func,
filter: (LhsFilter, RhsFilter)
) -> Result<()> { ) -> Result<()> {
paste::item! { paste::item! {
self.add(name, priority, Update::Pair(ArchetypePair::[<create_lhs_ $lhs_id _rhs_ $rhs_id>](func, filter.0, filter.1)))?; self.add(name, priority, Update::Pair(ArchetypePair::[<create_lhs_ $lhs_id _rhs_ $rhs_id>](func)))?;
} }
Ok(()) Ok(())
@ -348,7 +372,7 @@ macro_rules! impl_pair_update {
$( $(
$lhs_big: EntityComponent + ComponentDebug, $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, LhsFilter: CheckFilter + 'static,
RhsFilter: CheckFilter + 'static RhsFilter: CheckFilter + 'static
{ {
@ -357,9 +381,8 @@ macro_rules! impl_pair_update {
name: &str, name: &str,
priority: u32, priority: u32,
func: Func, func: Func,
filter: (LhsFilter, RhsFilter),
) -> Result<()> { ) -> 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,)+> { impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> {
fn check(&self, entity: &EntityObject) -> bool { fn check(entity: &EntityObject) -> bool {
$( $(
if entity.contains_component::<$big>() { if entity.contains_component::<$big>() {
return false; return false;
@ -395,7 +418,7 @@ macro_rules! impl_update_filter {
true true
} }
fn verify_dedup<O: EntityComponent>(&self) { fn verify_dedup<O: EntityComponent>() {
$( $(
if TypeId::of::<O>() == TypeId::of::<$big>() { if TypeId::of::<O>() == TypeId::of::<$big>() {
panic!("Type is used as input and filter at the same time"); 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<C, F = EmptyFilter>
where
F: CheckFilter,
{
entity: Entity,
c: C,
filter: PhantomData<F>,
}
impl<C, F: CheckFilter> Query<C, F> {
pub fn entity(&self) -> Entity {
self.entity
}
}
impl<C, F: CheckFilter> Deref for Query<C, F> {
type Target = C;
fn deref(&self) -> &Self::Target {
&self.c
}
}
impl<C, F: CheckFilter> DerefMut for Query<C, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.c
}
}
pub trait AddUpdates<T, R, Func, Filter> { pub trait AddUpdates<T, R, Func, Filter> {
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<T, R, Func, Filter> { trait CreateArchetype<T, R, Func, Filter> {
fn create(f: Func, filter: Filter) -> Self; fn create(f: Func) -> Self;
} }
pub trait CheckFilter: Send + Sync + Default + Clone { pub trait CheckFilter: Send + Sync + Default + Clone {
fn check(&self, entity: &EntityObject) -> bool; fn check(entity: &EntityObject) -> bool;
fn verify_dedup<O: EntityComponent>(&self); fn verify_dedup<O: EntityComponent>();
} }
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct EmptyFilter; pub struct EmptyFilter;
impl CheckFilter for EmptyFilter { impl CheckFilter for EmptyFilter {
fn check(&self, _entity: &EntityObject) -> bool { fn check(_entity: &EntityObject) -> bool {
true true
} }
fn verify_dedup<O>(&self) {} fn verify_dedup<O>() {}
} }
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
@ -466,15 +519,12 @@ pub struct Archetype {
dyn Fn( dyn Fn(
&EntityObject, &EntityObject,
) )
-> Result<Box<dyn Fn(Entity, &mut Commands, &mut World) -> Result<()> + Send + Sync>> -> Result<Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>>
+ Send + Send
+ Sync, + Sync,
>, >,
entities: IndexMap< entities: IndexMap<Entity, Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>>,
Entity,
Box<dyn Fn(Entity, &mut Commands, &mut World) -> Result<()> + Send + Sync>,
>,
} }
impl Archetype { impl Archetype {
@ -495,8 +545,8 @@ impl Archetype {
pub fn execute(&self, world: &mut World) -> Result<()> { pub fn execute(&self, world: &mut World) -> Result<()> {
let mut commands = Commands::new(world.now()); let mut commands = Commands::new(world.now());
for (entity, callback) in self.entities.iter() { for callback in self.entities.values() {
callback(*entity, &mut commands, world)?; callback(&mut commands, world)?;
} }
commands.apply_deferred(world)?; commands.apply_deferred(world)?;
@ -506,9 +556,13 @@ impl Archetype {
pub fn entities( pub fn entities(
&self, &self,
) -> &IndexMap<Entity, Box<dyn Fn(Entity, &mut Commands, &mut World) -> Result<()> + Send + Sync>> ) -> impl Iterator<
{ Item = (
&self.entities &Entity,
&Box<dyn Fn(&mut Commands, &mut World) -> Result<()> + Send + Sync>,
),
> {
self.entities.iter()
} }
} }
@ -520,16 +574,12 @@ pub struct ArchetypePair {
dyn Fn( dyn Fn(
&EntityObject, &EntityObject,
&EntityObject, &EntityObject,
) ) -> Result<Box<dyn Fn(&mut Commands) -> Result<()> + Send + Sync>>
-> Result<Box<dyn Fn(Entity, Entity, &mut Commands) -> Result<()> + Send + Sync>>
+ Send + Send
+ Sync, + Sync,
>, >,
entities: IndexMap< entities: IndexMap<(Entity, Entity), Box<dyn Fn(&mut Commands) -> Result<()> + Send + Sync>>,
(Entity, Entity),
Box<dyn Fn(Entity, Entity, &mut Commands) -> Result<()> + Send + Sync>,
>,
} }
impl ArchetypePair { impl ArchetypePair {
@ -549,8 +599,10 @@ impl ArchetypePair {
{ {
let cb = (self.create_callback)(entity_object, other_entity_object)?; let cb = (self.create_callback)(entity_object, other_entity_object)?;
self.entities self.entities.insert(
.insert((entity_object.as_entity(), *other_entity), cb); (entity_object.as_entity(), other_entity_object.as_entity()),
cb,
);
} }
if (self.check_left_entity)(other_entity_object) if (self.check_left_entity)(other_entity_object)
@ -558,8 +610,10 @@ impl ArchetypePair {
{ {
let cb = (self.create_callback)(other_entity_object, entity_object)?; let cb = (self.create_callback)(other_entity_object, entity_object)?;
self.entities self.entities.insert(
.insert((*other_entity, entity_object.as_entity()), cb); (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<()> { pub(crate) fn execute(&self, world: &mut World) -> Result<()> {
let mut commands = Commands::new(world.now()); let mut commands = Commands::new(world.now());
for ((left_entity, right_entity), callback) in self.entities.iter() { for callback in self.entities.values() {
callback(*left_entity, *right_entity, &mut commands)?; callback(&mut commands)?;
} }
commands.apply_deferred(world)?; commands.apply_deferred(world)?;

View file

@ -278,14 +278,14 @@ impl World {
let mut entities = Vec::new(); let mut entities = Vec::new();
for entity in archetype.entities().keys() { for (&entity, _) in archetype.entities() {
#[cfg(debug_assertions)] #[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))] #[cfg(not(debug_assertions))]
let debug_name = None; let debug_name = None;
entities.push((*entity, debug_name)); entities.push((entity, debug_name));
} }
Ok(ArchetypeInfo::new(entities)) Ok(ArchetypeInfo::new(entities))