diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index c873530..b2ec2b1 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -6,7 +6,6 @@ pub mod get_disjoint_mut; pub mod resources; mod type_map; mod unsafe_component_store; -mod update_testing; mod updates; mod world; diff --git a/ecs/src/update_testing.rs b/ecs/src/update_testing.rs deleted file mode 100644 index 215d86d..0000000 --- a/ecs/src/update_testing.rs +++ /dev/null @@ -1,168 +0,0 @@ -#![allow(unused)] - -use anyhow::Result; -use std::marker::PhantomData; -use std::{ops::Deref, ops::DerefMut}; - -use crate::*; - -#[derive(Copy, Clone)] -pub struct Query -where - F: StaticCheckFilter, -{ - 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 - } -} - -trait CreateQueryArchetype { - fn create(f: Func) -> Self; -} - -pub trait StaticCheckFilter: Send + Sync + Default + Clone { - fn check(entity: &EntityObject) -> bool; - fn verify_dedup(); -} - -impl StaticCheckFilter for EmptyFilter { - fn check(_entity: &EntityObject) -> bool { - true - } - - fn verify_dedup() {} -} - -pub struct QueryArchetype { - check_entity: Box bool + Send + Sync>, - create_callback: Box< - dyn Fn( - &EntityObject, - ) - -> Result Result<()> + Send + Sync>> - + Send - + Sync, - >, - - entities: Vec Result<()> + Send + Sync>>, -} - -macro_rules! impl_query_singleton_update { - ( $($var:ident $(,)?)+ ) => { - impl CreateQueryArchetype<( $( $var, )+ ), (), Func, Filter> for QueryArchetype - where - Func: Fn(&mut Commands, Query<( $( &mut $var, )+ ), Filter>) -> Result<()> + Send + Sync + Clone + 'static, - Filter: StaticCheckFilter, - $( - $var: EntityComponent + ComponentDebug, - )+ - { - paste::item! { - fn create(f: Func) -> 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 e = entity.as_entity(); - let f = f.clone(); - - Ok(Box::new(move |commands, _world| { - let q = Query { - entity: e, - c: unsafe { ($([< $var:lower >].as_mut(),)+) }, - filter: PhantomData, - }; - - f(commands, q) - })) - }), - - entities: Vec::new(), - } - } - } - } - }; -} - -impl_query_singleton_update!(R, U); - -struct T {} - -impl EntityComponent for T { - fn name(&self) -> &str { - Self::debug_name() - } -} - -impl ComponentDebug for T { - fn debug_name() -> &'static str { - "T" - } -} - -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); -} diff --git a/ecs/src/updates.rs b/ecs/src/updates.rs index 985f76f..c822822 100644 --- a/ecs/src/updates.rs +++ b/ecs/src/updates.rs @@ -3,8 +3,6 @@ use std::ops::{Deref, DerefMut}; use std::{any::TypeId, marker::PhantomData}; -use std::collections::HashMap; - use anyhow::Result; use indexmap::IndexMap; use update_macros::implement_updates; @@ -95,7 +93,7 @@ impl DerefMut for Query { } pub trait AddUpdates { - fn add_update(&mut self, name: &str, priority: u32, func: Func) -> Result<()>; + fn add_update(&mut self, priority: u32, func: Func) -> Result<()>; } pub trait CreateArchetype { @@ -153,18 +151,31 @@ pub struct Archetype { } 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); + pub fn add_entities( + &mut self, + new_entity: &EntityObject, + entity_objects: &[&EntityObject], + ) -> Result<()> { + if !(self.check_entity)(entity_objects) { + return Ok(()); } + let cb = (self.create_callback)(entity_objects)?; + + self.entities + .insert(entity_objects.iter().map(|e| e.as_entity()).collect(), cb); + Ok(()) } pub fn remove_entity(&mut self, entity: Entity) { - self.entities.swap_remove(&entity); + while let Some(index) = self + .entities + .keys() + .position(|entities| entities.contains(&entity)) + { + self.entities.swap_remove_index(index); + } } pub fn execute(&self, world: &mut World) -> Result<()> { @@ -183,7 +194,7 @@ impl Archetype { &self, ) -> impl Iterator< Item = ( - &Entity, + &Vec, &Box Result<()> + Send + Sync>, ), > { @@ -191,103 +202,8 @@ impl Archetype { } } -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_object.as_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_object.as_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, world: &mut World) -> Result<()> { - let mut commands = Commands::new(world.now()); - - for callback in self.entities.values() { - callback(&mut commands)?; - } - - commands.apply_deferred(world)?; - - 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 { - updates: Vec<(u32, Update)>, + updates: Vec<(u32, Archetype)>, } impl Default for Updates { @@ -302,20 +218,7 @@ impl Updates { pub(crate) fn update(&mut self, world: &mut World) -> Result<()> { self.updates .iter() - .try_for_each(|(_, update)| -> Result<()> { - match update { - Update::Single(archetype) => { - archetype.execute(world)?; - } - Update::Pair(archetype_pair) => { - archetype_pair.execute(world)?; - } - } - - Ok(()) - })?; - - Ok(()) + .try_for_each(|(_, archetype)| archetype.execute(world)) } pub(crate) fn add_entity( @@ -323,101 +226,47 @@ impl Updates { 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)?; - } - } + for (_, archetype) in self.updates.iter_mut() { + todo!(); + // archetype.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, priority: u32, update: Update) -> Result<()> { - self.updates.push((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() { + for (_, archetype) in self.updates.iter_mut() { archetype.remove_entity(entity); } } - pub(crate) fn insert(&mut self, name: String, archetype: Archetype) { - assert!(self.archetypes.insert(name, archetype).is_none()); - } + pub(crate) fn add(&mut self, priority: u32, archetype: Archetype) -> Result<()> { + self.updates.push((priority, archetype)); + self.updates.sort_by_key(|(prio, _)| *prio); - pub(crate) fn get(&self, name: &String) -> Option<&Archetype> { - self.archetypes.get(name) - } - - pub(crate) fn execute(&self, name: &String, world: &mut World) -> Result<()> { - self.archetypes[name].execute(world) + Ok(()) } } -implement_updates!(10, 4); +#[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]); -// #[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]); +implement_updates!(8); diff --git a/ecs/src/world.rs b/ecs/src/world.rs index a52705b..dc2caad 100644 --- a/ecs/src/world.rs +++ b/ecs/src/world.rs @@ -4,7 +4,7 @@ use std::{ time::{Duration, Instant}, }; -use anyhow::{Error, Result, bail}; +use anyhow::{Result, bail}; use indexmap::IndexMap; use utilities::prelude::{remove_life_time, remove_life_time_mut}; @@ -14,7 +14,6 @@ pub struct WorldBuilder { pub(crate) updates: Updates, pub events: Events, pub resources: Resources, - archetypes: Archetypes, systems: Vec<( u32, Box Result + Send + Sync + 'static>, @@ -29,10 +28,6 @@ impl WorldBuilder { self.systems.push((priority, Box::new(f))); self.systems.sort_by_key(|(priority, _)| *priority); } - - pub fn add_archetype(&mut self, name: impl ToString, archetype: Archetype) { - self.archetypes.insert(name.to_string(), archetype); - } } impl WorldBuilder { @@ -42,7 +37,6 @@ impl WorldBuilder { events: self.events, resources: self.resources, entities: Default::default(), - archetypes: self.archetypes, entities_to_remove: Default::default(), entities_to_add: Default::default(), @@ -68,7 +62,6 @@ pub struct World { pub events: Events, pub resources: Resources, pub(crate) entities: IndexMap, - archetypes: Archetypes, entities_to_remove: Vec, entities_to_add: Vec, @@ -89,7 +82,6 @@ impl World { events: Default::default(), resources: Default::default(), systems: Default::default(), - archetypes: Default::default(), } } @@ -263,33 +255,6 @@ impl World { pub fn remove_entity(&mut self, entity: Entity) { self.entities_to_remove.push(entity); } - - pub fn execute_archetype(&mut self, name: impl ToString) -> Result<()> { - let archetypes = unsafe { remove_life_time_mut(&mut self.archetypes) }; - archetypes.execute(&name.to_string(), self) - } - - pub fn archetype_info(&self, name: impl ToString) -> Result { - let name = name.to_string(); - let archetype = self - .archetypes - .get(&name) - .ok_or_else(|| Error::msg(format!("requested archetype ({}) not found", name)))?; - - let mut entities = Vec::new(); - - for (&entity, _) in archetype.entities() { - #[cfg(debug_assertions)] - let debug_name = self.entity(entity)?.debug_name.clone(); - - #[cfg(not(debug_assertions))] - let debug_name = None; - - entities.push((entity, debug_name)); - } - - Ok(ArchetypeInfo::new(entities)) - } } // async application of changes @@ -305,7 +270,6 @@ impl World { let e = entity.as_entity(); self.updates.add_entity(&mut entity, &self.entities)?; - self.archetypes.add_entity(&entity)?; assert!(self.entities.insert(e, entity).is_none()); Ok(e) @@ -319,7 +283,6 @@ impl World { entity_object.activation_state.apply_change(); self.updates.remove_entity(entity); - self.archetypes.remove_entity(entity); return Ok(Some(entity_object)); } @@ -339,7 +302,6 @@ impl World { .ok_or_else(|| EntityNotFoundError::new(entity))?; self.updates.remove_entity(entity); - self.archetypes.remove_entity(entity); entity_object.activation_state.apply_change(); @@ -351,7 +313,6 @@ impl World { entity_object.activation_state.apply_change(); self.updates.add_entity(entity_object, &self.entities)?; - self.archetypes.add_entity(entity_object)?; Ok(()) } @@ -367,7 +328,6 @@ impl World { .ok_or_else(|| EntityNotFoundError::new(entity))?; self.updates.remove_entity(entity); - self.archetypes.remove_entity(entity); entity_object.activation_state.apply_change(); @@ -378,7 +338,6 @@ impl World { entity_object.activation_state.apply_change(); self.updates.add_entity(entity_object, &self.entities)?; - self.archetypes.add_entity(entity_object)?; Ok(()) } @@ -416,7 +375,6 @@ impl World { for (entity, changes) in core::mem::take(&mut self.entities_updates) { self.updates.remove_entity(entity); - self.archetypes.remove_entity(entity); if let Ok(entity_object) = unsafe { self.entity_mut_unchecked(entity) } { entity_object.activation_state.apply_change(); @@ -447,7 +405,6 @@ impl World { entity_object.activation_state.apply_change(); self.updates.add_entity(entity_object, &self.entities)?; - self.archetypes.add_entity(entity_object)?; } } diff --git a/update_macros/src/lib.rs b/update_macros/src/lib.rs index fc09f29..1ca0ef8 100644 --- a/update_macros/src/lib.rs +++ b/update_macros/src/lib.rs @@ -17,19 +17,13 @@ use syn::{ struct UpdateInfo { max_components: usize, - max_queries: usize, } impl Parse for UpdateInfo { fn parse(input: ParseStream) -> Result { let max_components = input.parse::()?.base10_parse()?; - input.parse::()?; - let max_queries = input.parse::()?.base10_parse()?; - Ok(Self { - max_components, - max_queries, - }) + Ok(Self { max_components }) } } @@ -37,7 +31,7 @@ impl Parse for UpdateInfo { pub fn implement_updates(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as UpdateInfo); - update(input.max_components, input.max_queries) + update(input.max_components) } struct InputInfo { diff --git a/update_macros/src/update.rs b/update_macros/src/update.rs index 189c844..d26c60b 100644 --- a/update_macros/src/update.rs +++ b/update_macros/src/update.rs @@ -66,7 +66,7 @@ impl Query { pub fn component_store_and_query(&self, index: usize) -> (TokenStream2, TokenStream2, Ident) { let components = &self.components; let entity_name = format_ident!("entity_{index}"); - let component_name = self + let component_names = self .components .iter() .map(|component| format_ident!("q_{index}_{component}")) @@ -80,17 +80,30 @@ impl Query { let #entity_ident = #entity_name.as_entity(); #( - let #component_name = UnsafeComponentStore::from( + #[allow(non_snake_case)] + let #component_names = UnsafeComponentStore::from( #entity_name.get_component::<#components>()? ); )* }, - quote! { - let #query_ident = Query { - entity: #entity_ident, - c: unsafe { ( #( #component_name.as_mut() )* ) }, - filter: PhantomData, - }; + if component_names.len() == 1 { + let component_name = &component_names[0]; + + quote! { + let #query_ident = Query { + entity: #entity_ident, + c: unsafe { #component_name.as_mut() }, + filter: PhantomData, + }; + } + } else { + quote! { + let #query_ident = Query { + entity: #entity_ident, + c: unsafe { ( #( #component_names.as_mut(), )* ) }, + filter: PhantomData, + }; + } }, query_ident, ) @@ -138,7 +151,6 @@ impl Update { const MIN_RESOURCE: usize = 0; const MAX_RESOURCE: usize = 10; const MIN_COMPONENTS: usize = 1; - const MIN_QUERIES: usize = 1; pub fn new(queries: impl Iterator, resources: usize) -> Self { Self { @@ -255,6 +267,7 @@ impl Update { ( quote! { + #[allow(non_snake_case)] let ( #( #resource_idents, )* ): ( @@ -378,7 +391,7 @@ impl ToTokens for Update { #( #query_structs )* #resource_store - f(commands, #( #query_idents, )* #( #resource_idents, )*) + f(commands, #( #query_idents, )* #( #resource_idents, )* ) })) }), @@ -423,19 +436,25 @@ impl ToTokens for Update { } } -pub fn update(max_components: usize, max_queries: usize) -> TokenStream { - // let updates = (Update::MIN_QUERIES..max_queries) - // .map(|query_count| { - // let queries = (1..query_count).map(|q| { +pub fn update(max_components: usize) -> TokenStream { + let mut queries: Vec> = Vec::new(); - // }) - // }) - // .collect::>(); + for c in Update::MIN_COMPONENTS..=max_components { + queries.push(vec![c]); + } - let mut query_counts = Vec::new(); + for x in Update::MIN_COMPONENTS..=max_components { + for y in Update::MIN_COMPONENTS..=max_components { + queries.push(vec![x, y]); + } + } - for components in Update::MIN_COMPONENTS..=max_components { - query_counts.push(components); + for x in Update::MIN_COMPONENTS..=max_components { + for y in Update::MIN_COMPONENTS..=max_components { + for z in Update::MIN_COMPONENTS..=max_components { + queries.push(vec![x, y, z]); + } + } } let mut resources = Vec::new(); @@ -444,7 +463,15 @@ pub fn update(max_components: usize, max_queries: usize) -> TokenStream { resources.push(resource); } - let updates = vec![Update::new(vec![2, 2].into_iter(), 1)]; + let mut updates = Vec::new(); + + for query in queries.iter() { + for resource_count in resources.iter() { + updates.push(Update::new(query.iter().cloned(), *resource_count)); + } + } + + // updates.push(Update::new(vec![1].into_iter(), 0)); TokenStream::from(quote! { #( #updates )*