#![allow(clippy::type_complexity)] use std::any::TypeId; use std::marker::PhantomData; #[cfg(feature = "timings")] use std::time::Instant; use anyhow::Result; use indexmap::IndexMap; #[cfg(feature = "timings")] use super::super::timings::Timings; use crate::*; use scene_update_macros::implement_pair_update; macro_rules! impl_singleton_update { ( $name: ident, $([$var: ident]$(,)?)+ ) => { impl Archetype { paste::item! { pub fn [](f: F, filter: Filter) -> Self where F: Fn(&mut C, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static, $( $var: EntityComponent + ComponentDebug, )+ { $( 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, scene_contents| { unsafe { f(scene_contents, e, $([< $var:lower >].as_mut(),)+) } })) }), entities: IndexMap::new(), } } } } impl AddUpdates2 for Updates where $( $var: EntityComponent + ComponentDebug, )+ Func: Fn(& mut C, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static { fn add_update( &mut self, name: &str, priority: u32, func: Func, filter: Filter, entities: &IndexMap> ) -> Result<()> { paste::item! { self.add(name, priority, Update::Single(Archetype::[](func, filter)), entities) } } } impl AddUpdates<( $( $var, )+ ), Func, Filter> for World where $( $var: EntityComponent + ComponentDebug, )+ Func: Fn(& mut C, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, Filter: CheckFilter + 'static, C: Send + Sync { fn add_update( &mut self, name: &str, priority: u32, func: Func, filter: Filter, ) -> Result<()> { self.updates.add_update(name, priority, func, filter, &self.entities) } } // impl Scene { // paste::item! { // pub fn [](&mut self, name: impl ToString, f: F, filter: Filter) -> Result<()> // where // F: Fn(&mut SceneContents<'_>, Entity, $(&mut $var,)+) -> Result<()> + Send + Sync + Clone + 'static, // Filter: CheckFilter + 'static, // $( // $var: EntityComponent + ComponentDebug, // )+ // { // let mut archetype = Archetype::[](f, filter); // archetype.setup(&self.entities)?; // self.archetypes.insert(name.to_string(), archetype); // Ok(()) // } // } // } }; } macro_rules! impl_pair_update { ( $lhs_id: expr, ( $([$lhs_little: ident: $lhs_big: ident]$(,)?)+ ), $rhs_id: expr, ( $([$rhs_little: ident: $rhs_big: ident]$(,)?)+ ) ) => { impl ArchetypePair { paste::item! { pub fn [] (f: F, left_filter: LeftFilter, right_filter: RightFilter) -> Self where F: Fn(&mut C, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, LeftFilter: CheckFilter + 'static, RightFilter: CheckFilter + 'static, $( $rhs_big: EntityComponent + ComponentDebug, )+ $( $lhs_big: EntityComponent + ComponentDebug, )+ { $( left_filter.verify_dedup::<$lhs_big>(); )+ $( right_filter.verify_dedup::<$rhs_big>(); )+ Self { check_left_entity: Box::new({ move |entity| { $( if !entity.components.contains::<$lhs_big>() { return false; } )+ if !left_filter.check(entity) { return false; } true } }), check_right_entity: Box::new({ move |entity| { $( if !entity.components.contains::<$rhs_big>() { return false; } )+ if !right_filter.check(entity) { return false; } true } }), create_callback: Box::new(move |lhs_entity, rhs_entity| { $( let $lhs_little = UnsafeComponentStore::from( lhs_entity.get_component::<$lhs_big>()? ); )+ $( let $rhs_little = UnsafeComponentStore::from( rhs_entity.get_component::<$rhs_big>()? ); )+ let f = f.clone(); Ok(Box::new(move |lhs_e, rhs_e, scene_contents| { unsafe { f(scene_contents, (lhs_e, $($lhs_little.as_mut(),)+), (rhs_e, $($rhs_little.as_mut(),)+) ) } })) }), entities: IndexMap::new(), } } } } impl AddUpdates2 for Updates where $( $rhs_big: EntityComponent + ComponentDebug, )+ $( $lhs_big: EntityComponent + ComponentDebug, )+ Func: Fn(& mut C, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, LhsFilter: CheckFilter + 'static, RhsFilter: CheckFilter + 'static { fn add_update( &mut self, name: &str, priority: u32, func: Func, filter: (LhsFilter, RhsFilter), entities: &IndexMap> ) -> Result<()> { paste::item! { self.add(name, priority, Update::Pair(ArchetypePair::[](func, filter.0, filter.1)), entities)?; } Ok(()) } } impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for World where $( $rhs_big: EntityComponent + ComponentDebug, )+ $( $lhs_big: EntityComponent + ComponentDebug, )+ Func: Fn(& mut C, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> Result<()> + Send + Sync + Clone + 'static, LhsFilter: CheckFilter + 'static, RhsFilter: CheckFilter + 'static, C: Send + Sync { fn add_update( &mut self, name: &str, priority: u32, func: Func, filter: (LhsFilter, RhsFilter), ) -> Result<()> { self.updates.add_update(name, priority, func, filter, &self.entities) } } // impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, Filter> for Scene // where // $( // $rhs_big: EntityComponent + ComponentDebug, // )+ // $( // $lhs_big: EntityComponent + ComponentDebug, // )+ // Func: Fn(& mut SceneContents<'_>, (Entity, $(&mut $lhs_big,)+), (Entity, $(&mut $rhs_big,)+)) -> 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.updates.add_update(name, priority, func, (filter.clone(), filter), &self.entities)?; // } // Ok(()) // } // } }; } macro_rules! impl_update_filter { ( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => { paste::item! { pub struct [<$name Filter>],)+> where C: Send + Sync { c: std::marker::PhantomData, $( $little: std::marker::PhantomData<$big>, )+ } impl,)+> Default for [<$name Filter>] where C: Send + Sync { fn default() -> Self { Self { c: std::marker::PhantomData, $( $little: std::marker::PhantomData, )+ } } } impl,)+> CheckFilter for [<$name Filter>] where C: Send + Sync { fn check(&self, entity: &EntityObject) -> bool { $( if entity.contains_component::<$big>() { return false; } )+ true } fn verify_dedup>(&self) { $( if TypeId::of::() == TypeId::of::<$big>() { panic!("Type is used as input and filter at the same time"); } )+ } } impl,)+> Clone for [<$name Filter>] where C: Send + Sync { fn clone(&self) -> Self { Self { c: self.c.clone(), $( $little: self.$little.clone(), )+ } } } } }; } pub struct Query where F: CheckFilter, { pub components: T, d: PhantomData, c: PhantomData, } pub trait AddUpdates { fn add_update(&mut self, name: &str, priority: u32, func: Func, filter: Filter) -> Result<()>; } trait AddUpdates2 { fn add_update( &mut self, name: &str, priority: u32, func: Func, filter: Filter, entities: &IndexMap>, ) -> Result<()>; } pub trait CheckFilter: Send + Sync + Default + Clone { fn check(&self, entity: &EntityObject) -> bool; fn verify_dedup>(&self); } #[derive(Default, Clone)] pub struct EmptyFilter; impl CheckFilter for EmptyFilter { fn check(&self, _entity: &EntityObject) -> bool { true } fn verify_dedup(&self) {} } #[derive(Default, Clone, Debug)] pub struct ArchetypeInfo { entities: Vec<(Entity, Option)>, } impl ArchetypeInfo { pub(crate) fn new(entities: Vec<(Entity, Option)>) -> Self { Self { entities } } pub fn entities(&self) -> &[(Entity, Option)] { &self.entities } pub fn count(&self) -> usize { self.entities.len() } } pub struct Archetype { check_entity: Box) -> bool + Send + Sync>, create_callback: Box< dyn Fn(&EntityObject) -> Result Result<()> + Send + Sync>> + Send + Sync, >, entities: IndexMap Result<()> + Send + Sync>>, } impl Archetype { pub fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> { if (self.check_entity)(entity_object) { let cb = (self.create_callback)(entity_object)?; self.entities.insert(entity_object.as_entity(), cb); } Ok(()) } pub fn remove_entity(&mut self, entity: Entity) { self.entities.swap_remove(&entity); } pub fn execute(&self, scene_contents: &mut C) -> Result<()> { for (entity, callback) in self.entities.iter() { callback(*entity, scene_contents)?; } Ok(()) } pub fn setup(&mut self, entities: &IndexMap>) -> Result<()> { for (entity, entity_object) in entities.iter() { if (self.check_entity)(entity_object) { let cb = (self.create_callback)(entity_object)?; self.entities.insert(entity.clone(), cb); } } Ok(()) } pub(crate) fn entities( &self, ) -> &IndexMap Result<()> + Send + Sync>> { &self.entities } } pub struct ArchetypePair { check_left_entity: Box) -> bool + Send + Sync>, check_right_entity: Box) -> bool + Send + Sync>, create_callback: Box< dyn Fn( &EntityObject, &EntityObject, ) -> Result Result<()> + Send + Sync>> + Send + Sync, >, entities: IndexMap<(Entity, Entity), Box Result<()> + Send + Sync>>, } impl ArchetypePair { pub(crate) fn add_entity( &mut self, entity_object: &EntityObject, entities: &IndexMap>, ) -> Result<()> { for (other_entity, other_entity_object) in entities.iter() { if entity_object.as_entity() == *other_entity { continue; } // check if the entities can be on both sides if (self.check_left_entity)(entity_object) && (self.check_right_entity)(other_entity_object) { let cb = (self.create_callback)(entity_object, other_entity_object)?; self.entities .insert((entity_object.as_entity(), *other_entity), cb); } if (self.check_left_entity)(other_entity_object) && (self.check_right_entity)(entity_object) { let cb = (self.create_callback)(other_entity_object, entity_object)?; self.entities .insert((*other_entity, entity_object.as_entity()), cb); } } Ok(()) } pub(crate) fn remove_entity(&mut self, entity: Entity) { while let Some((left_entity, right_entity)) = self .entities .keys() .find(|(left_entity, right_entity)| *left_entity == entity || *right_entity == entity) .cloned() { self.entities.swap_remove(&(left_entity, right_entity)); } } pub(crate) fn execute(&self, scene_contents: &mut C) -> Result<()> { for ((left_entity, right_entity), callback) in self.entities.iter() { callback(*left_entity, *right_entity, scene_contents)?; } Ok(()) } pub(crate) fn setup(&mut self, entities: &IndexMap>) -> Result<()> { for (lhs_entity, lhs_entity_object) in entities.iter() { for (rhs_entity, rhs_entity_object) in entities.iter() { if lhs_entity != rhs_entity && (self.check_left_entity)(lhs_entity_object) && (self.check_right_entity)(rhs_entity_object) { let cb = (self.create_callback)(lhs_entity_object, rhs_entity_object)?; self.entities.insert((*lhs_entity, *rhs_entity), cb); } } } Ok(()) } } pub enum Update { Single(Archetype), Pair(ArchetypePair), } impl From> for Update { fn from(archetype: Archetype) -> Self { Self::Single(archetype) } } impl From> for Update { fn from(pair: ArchetypePair) -> Self { Self::Pair(pair) } } pub struct Updates { #[cfg(feature = "timings")] timings: Timings, updates: Vec<(String, u32, Update)>, } impl Default for Updates { fn default() -> Self { Self { #[cfg(feature = "timings")] timings: Timings::default, updates: Vec::new(), } } } impl Updates { pub(crate) fn update(&mut self, scene_contents: &mut C) -> Result<()> { #[cfg(feature = "timings")] if let Some(timings) = self.timings.check_timing(scene_contents.now(), None) { if !timings.is_empty() { println!("timings: {:#?}", timings); } } #[cfg(feature = "timings")] let timings = &mut self.timings; self.updates .iter() .try_for_each(|(_name, _, update)| -> Result<()> { #[cfg(feature = "timings")] let before = Instant::now(); match update { Update::Single(archetype) => { archetype.execute(scene_contents)?; } Update::Pair(archetype_pair) => { archetype_pair.execute(scene_contents)?; } } #[cfg(feature = "timings")] timings.add(_name, Instant::now().duration_since(before)); Ok(()) })?; Ok(()) } pub(crate) fn add_entity( &mut self, entity_object: &EntityObject, entities: &IndexMap>, ) -> Result<()> { for (_, _, update) in self.updates.iter_mut() { match update { Update::Single(archetype) => { archetype.add_entity(entity_object)?; } Update::Pair(archetype_pair) => { archetype_pair.add_entity(entity_object, entities)?; } } } Ok(()) } pub(crate) fn remove_entity(&mut self, entity: Entity) { for (_, _, update) in self.updates.iter_mut() { match update { Update::Single(archetype) => { archetype.remove_entity(entity); } Update::Pair(archetype_pair) => { archetype_pair.remove_entity(entity); } } } } pub(crate) fn clear(&mut self) { self.updates.clear(); #[cfg(feature = "timings")] self.timings.clear(); } pub(crate) fn add( &mut self, name: &str, priority: u32, mut update: Update, entities: &IndexMap>, ) -> Result<()> { match &mut update { Update::Single(archetype) => archetype.setup(entities)?, Update::Pair(archetype_pair) => archetype_pair.setup(entities)?, } #[cfg(feature = "timings")] self.timings.add_timing_afterwards(name); self.updates.push((name.to_string(), priority, update)); self.updates .sort_by(|(_, lhs_prio, _), (_, rhs_prio, _)| lhs_prio.cmp(rhs_prio)); Ok(()) } } // #[derive(Default)] // pub struct Archetypes { // archetypes: HashMap, // } // impl Archetypes { // pub(crate) fn add_entity(&mut self, entity_object: &EntityObject) -> Result<()> { // for archetype in self.archetypes.values_mut() { // archetype.add_entity(entity_object)?; // } // Ok(()) // } // pub(crate) fn remove_entity(&mut self, entity: Entity) { // for archetype in self.archetypes.values_mut() { // archetype.remove_entity(entity); // } // } // pub(crate) fn clear(&mut self) { // self.archetypes.clear(); // } // pub(crate) fn insert(&mut self, name: String, archetype: Archetype) { // assert!(self.archetypes.insert(name, archetype).is_none()); // } // pub(crate) fn get(&self, name: &String) -> Option<&Archetype> { // self.archetypes.get(name) // } // pub(crate) fn execute( // &self, // name: &String, // scene_contents: &mut SceneContents<'_>, // ) -> Result<()> { // self.archetypes[name].execute(scene_contents) // } // } #[rustfmt::skip] impl_singleton_update!(single, [R]); #[rustfmt::skip] impl_singleton_update!(double, [R], [S]); #[rustfmt::skip] impl_singleton_update!(triple, [R], [S], [T]); #[rustfmt::skip] impl_singleton_update!(quadruple, [R], [S], [T], [U]); #[rustfmt::skip] impl_singleton_update!(quintuple, [R], [S], [T], [U], [V]); #[rustfmt::skip] impl_singleton_update!(sextuple, [R], [S], [T], [U], [V], [W]); #[rustfmt::skip] impl_singleton_update!(septuple, [R], [S], [T], [U], [V], [W], [X]); #[rustfmt::skip] impl_singleton_update!(octuple, [R], [S], [T], [U], [V], [W], [X], [Y]); #[rustfmt::skip] impl_singleton_update!(ninetuple, [R], [S], [T], [U], [V], [W], [X], [Y], [Z]); implement_pair_update!(impl_pair_update, 1, 10); #[rustfmt::skip] impl_update_filter!(Monuple, [R, r]); #[rustfmt::skip] impl_update_filter!(Couple, [R, r], [S, s]); #[rustfmt::skip] impl_update_filter!(Triple, [R, r], [S, s], [T, t]); #[rustfmt::skip] impl_update_filter!(Quadruple, [R, r], [S, s], [T, t], [U, u]); #[rustfmt::skip] impl_update_filter!(Quintuple, [R, r], [S, s], [T, t], [U, u], [V, v]); #[rustfmt::skip] impl_update_filter!(Sextuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w]); #[rustfmt::skip] impl_update_filter!(Septuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x]); #[rustfmt::skip] impl_update_filter!(Octuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y]); #[rustfmt::skip] impl_update_filter!(Nonuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z]); #[rustfmt::skip] impl_update_filter!(Decuple, [R, r], [S, s], [T, t], [U, u], [V, v], [W, w], [X, x], [Y, y], [Z, z], [A, a]);