#![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 World, 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<( $( $var, )+ ), Func, Filter> for Updates where $( $var: EntityComponent + ComponentDebug, )+ Func: Fn(& mut World, Entity, $(&mut $var,)+) -> 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::[](func, filter))) } } } impl AddUpdates<( $( $var, )+ ), Func, Filter> for WorldBuilder where $( $var: EntityComponent + ComponentDebug, )+ Func: Fn(& mut World, Entity, $(&mut $var,)+) -> 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 { ( $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 World, (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<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for Updates where $( $rhs_big: EntityComponent + ComponentDebug, )+ $( $lhs_big: EntityComponent + ComponentDebug, )+ Func: Fn(& mut World, (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) ) -> Result<()> { paste::item! { self.add(name, priority, Update::Pair(ArchetypePair::[](func, filter.0, filter.1)))?; } Ok(()) } } impl AddUpdates<( ($( $lhs_big, )+), ($($rhs_big,)+) ), Func, (LhsFilter, RhsFilter)> for WorldBuilder where $( $rhs_big: EntityComponent + ComponentDebug, )+ $( $lhs_big: EntityComponent + ComponentDebug, )+ Func: Fn(& mut World, (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), ) -> Result<()> { self.updates.add_update(name, priority, func, filter) } } }; } macro_rules! impl_update_filter { ( $name: ident, $([$big: ident, $little: ident]$(,)?)+ ) => { paste::item! { pub struct [<$name Filter>]<$($big: EntityComponent,)+> { $( $little: std::marker::PhantomData<$big>, )+ } impl<$($big: EntityComponent,)+> Default for [<$name Filter>]<$($big,)+> { fn default() -> Self { Self { $( $little: std::marker::PhantomData, )+ } } } impl<$($big: EntityComponent,)+> CheckFilter for [<$name Filter>]<$($big,)+> { 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<$($big: EntityComponent,)+> Clone for [<$name Filter>]<$($big,)+> { fn clone(&self) -> Self { Self { $( $little: self.$little.clone(), )+ } } } } }; } pub struct Query where F: CheckFilter, { pub components: T, d: 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) -> 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 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 World) -> Result<()> { for (entity, callback) in self.entities.iter() { callback(*entity, scene_contents)?; } Ok(()) } pub 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 World) -> Result<()> { for ((left_entity, right_entity), callback) in self.entities.iter() { callback(*left_entity, *right_entity, scene_contents)?; } 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, world: &mut World) -> Result<()> { #[cfg(feature = "timings")] if let Some(timings) = self.timings.check_timing(world.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(world)?; } Update::Pair(archetype_pair) => { archetype_pair.execute(world)?; } } #[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, update: Update) -> Result<()> { #[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]);