diff options
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r-- | ecs/src/lib.rs | 494 |
1 files changed, 262 insertions, 232 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 3caaa6b..07b1cba 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,9 +1,10 @@ #![deny(clippy::all, clippy::pedantic)] -use std::any::{type_name, TypeId}; +use std::any::{type_name, Any, TypeId}; use std::cell::RefCell; use std::fmt::Debug; use std::mem::ManuallyDrop; +use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -12,11 +13,18 @@ use hashbrown::HashMap; use crate::actions::Action; use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComponent; use crate::component::storage::Storage as ComponentStorage; -use crate::component::{Component, Sequence as ComponentSequence}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::Kind as ComponentEventKind; +use crate::component::{ + Component, + IntoParts, + Parts as ComponentParts, + Removals as ComponentRemovals, + Sequence as ComponentSequence, +}; +use crate::entity::{Handle as EntityHandle, CREATE_STATIC_ENTITIES}; +use crate::event::component::Added as ComponentAddedEvent; use crate::extension::{Collector as ExtensionCollector, Extension}; -use crate::lock::{Lock, WriteGuard}; +use crate::lock::Lock; +use crate::pair::{ChildOf, DependsOn, Pair}; use crate::phase::{Phase, START as START_PHASE}; use crate::query::flexible::Query as FlexibleQuery; use crate::query::term::Without; @@ -27,33 +35,31 @@ use crate::query::{ Terms as QueryTerms, TermsBuilderInterface, }; -use crate::relationship::{ChildOf, DependsOn, Relationship}; use crate::sole::Sole; use crate::stats::Stats; use crate::system::{System, SystemComponent}; -use crate::type_name::TypeName; -use crate::uid::{Kind as UidKind, Uid}; +use crate::uid::{Kind as UidKind, Uid, Wildcard}; pub mod actions; pub mod component; pub mod entity; pub mod event; pub mod extension; -pub mod lock; +pub mod pair; pub mod phase; pub mod query; -pub mod relationship; pub mod sole; pub mod stats; pub mod system; pub mod tuple; -pub mod type_name; pub mod uid; pub mod util; #[doc(hidden)] pub mod private; +mod lock; + pub use ecs_macros::{Component, Sole}; pub use crate::query::Query; @@ -80,16 +86,13 @@ impl World world.add_sole(Stats::default()).ok(); for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(&world); + create_static_entity(&mut world); } world } /// Creates a new entity with the given components. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid where Comps: ComponentSequence, @@ -103,29 +106,25 @@ impl World #[tracing::instrument(skip_all)] #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) + pub fn create_entity_with_uid<Comps>(&mut self, components: Comps, entity_uid: Uid) where Comps: ComponentSequence, { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - if let Err(err) = component_storage_lock.create_entity(entity_uid) { - tracing::warn!("Failed to create entity: {err}"); - return; - }; - - Self::add_entity_components( - entity_uid, - components.into_array(), - &mut component_storage_lock, - ); + if let Err(err) = self.data.component_storage.create_entity(entity_uid) { + tracing::warn!("Failed to create entity: {err}"); + return; } - for added_event_id in Comps::added_event_ids() { - self.emit_event_by_id(added_event_id); + let added_component_ids = Self::add_entity_components( + entity_uid, + components.into_parts_array(), + &mut self.data.component_storage, + ); + + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); } } @@ -148,27 +147,23 @@ impl World { self.create_entity(( SystemComponent { system: system.into_type_erased() }, - Relationship::<DependsOn, Phase>::new(phase_euid), + Pair::new::<DependsOn>(phase_euid), )); } - pub fn register_observer_system<'this, SystemImpl, Event>( + pub fn register_observer_system<'this, SystemImpl>( &'this mut self, system: impl System<'this, SystemImpl>, - event: Event, - ) where - Event: Component, + event: Pair<Uid, Uid>, + ) { - self.create_entity::<(SystemComponent, Event)>(( + self.create_entity(( SystemComponent { system: system.into_type_erased() }, event, )); } /// Adds a extensions. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. pub fn add_extension(&mut self, extension: impl Extension) { let extension_collector = ExtensionCollector::new(self); @@ -184,19 +179,18 @@ impl World Query::new(self) } - pub fn flexible_query<'terms>( + pub fn flexible_query<const MAX_TERM_CNT: usize>( &self, - terms: QueryTerms<'terms>, - ) -> FlexibleQuery<'_, 'terms> + terms: QueryTerms<MAX_TERM_CNT>, + ) -> FlexibleQuery<'_, MAX_TERM_CNT> { FlexibleQuery::new(self, terms) } /// Performs a single tick. - /// /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn step(&self) -> StepResult + /// Will panic if mutable internal lock cannot be acquired. + pub fn step(&mut self) -> StepResult { if self.stop.load(Ordering::Relaxed) { return StepResult::Stop; @@ -212,11 +206,14 @@ impl World self.perform_phases(); - self.lock_component_storage_rw() - .create_imaginary_archetypes(); + self.data.component_storage.create_imaginary_archetypes(); + + let prev_pending_removals = std::mem::take(&mut self.data.pending_removals); self.perform_queued_actions(); + self.perform_removals(prev_pending_removals); + if self.stop.load(Ordering::Relaxed) { return StepResult::Stop; } @@ -239,10 +236,7 @@ impl World } /// Starts a loop which calls [`Self::step`] until the world is stopped. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn start_loop(&self) + pub fn start_loop(&mut self) { while let StepResult::Continue = self.step() {} } @@ -260,13 +254,7 @@ impl World VizoxideArchetypeGraphParams, }; - let component_storage_lock = self - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"); - - component_storage_lock.create_vizoxide_archetype_graph( + self.data.component_storage.create_vizoxide_archetype_graph( name, VizoxideArchetypeGraphParams { create_node_name: |archetype, _| { @@ -275,7 +263,7 @@ impl World archetype .component_ids_sorted() .into_iter() - .map(|comp_id| comp_id.id().to_string()) + .map(|comp_id| comp_id.to_string()) .collect::<Vec<_>>() .join(", ") )) @@ -302,16 +290,18 @@ impl World fn query_and_run_systems(&self, phase_euid: Uid) { - let system_comps_query = - self.query::<(&SystemComponent, &Relationship<DependsOn, Phase>), ()>(); - - let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { - phase_rel - .target_uids() - .any(|target_uid| target_uid == phase_euid) - }); + let system_query = self.flexible_query( + QueryTerms::<2>::builder() + .with_required([ + SystemComponent::id(), + Pair::new::<DependsOn>(phase_euid).id(), + ]) + .build(), + ); - for (system_component, _) in system_iter { + for (system_component,) in + QueryIter::<(&SystemComponent,), _>::new(self, system_query.iter()) + { // SAFETY: The world lives long enough unsafe { system_component.system.run(self); @@ -321,38 +311,37 @@ impl World fn perform_child_phases(&self, parent_phase_euid: Uid) { - let phase_query = self.query::<(&Phase, &Relationship<ChildOf, Phase>), ()>(); - - for (child_phase_euid, (_, phase_rel)) in phase_query.iter_with_euids() { - if !phase_rel - .target_uids() - .any(|phase_euid| phase_euid == parent_phase_euid) - { - continue; - } + let phase_query = self.flexible_query( + QueryTerms::<2>::builder() + .with_required([ + Phase::id(), + Pair::new::<ChildOf>(parent_phase_euid).id(), + ]) + .build(), + ); - self.query_and_run_systems(child_phase_euid); - self.perform_child_phases(child_phase_euid); + for child_phase_entity in &phase_query { + self.query_and_run_systems(child_phase_entity.uid()); + self.perform_child_phases(child_phase_entity.uid()); } } fn perform_phases(&self) { - let phase_query = - self.query::<(&Phase,), (Without<Relationship<ChildOf, Phase>>,)>(); + let phase_query = self.query::<(&Phase,), (Without<Pair<ChildOf, Wildcard>>,)>(); - for (phase_euid, (_,)) in phase_query.iter_with_euids() { - if phase_euid == *START_PHASE { + for (phase_entity_id, _) in phase_query.iter_with_euids() { + if phase_entity_id == *START_PHASE { continue; } - self.query_and_run_systems(phase_euid); - self.perform_child_phases(phase_euid); + self.query_and_run_systems(phase_entity_id); + self.perform_child_phases(phase_entity_id); } } #[tracing::instrument(skip_all)] - fn perform_queued_actions(&self) + fn perform_queued_actions(&mut self) { let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() { @@ -369,92 +358,64 @@ impl World let mut has_swapped_active_queue = false; + // TODO: Figure out a good way to handle situations where there are multiple + // AddComponents/RemoveComponents actions that affect the same entity. for action in active_action_queue.drain(..) { match action { - Action::Spawn(components, component_added_event_ids) => { + Action::Spawn(components) => { + let new_entity_uid = Uid::new_unique(UidKind::Entity); + + if let Err(err) = + self.data.component_storage.create_entity(new_entity_uid) { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let new_entity_uid = Uid::new_unique(UidKind::Entity); - - if let Err(err) = - component_storage_lock.create_entity(new_entity_uid) - { - tracing::warn!("Failed to create entity: {err}"); - continue; - }; - - Self::add_entity_components( - new_entity_uid, - components, - &mut component_storage_lock, - ); + tracing::warn!("Failed to create entity: {err}"); + continue; } + let added_component_ids = Self::add_entity_components( + new_entity_uid, + components, + &mut self.data.component_storage, + ); + if !has_swapped_active_queue { self.swap_event_queue(&mut has_swapped_active_queue); } - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); } } Action::Despawn(entity_uid) => { - self.despawn_entity(entity_uid, &mut has_swapped_active_queue); + Self::schedule_removal( + &mut self.data.component_storage, + &mut self.data.pending_removals, + entity_uid, + PendingRemoval::Entity, + ); } - Action::AddComponents( - entity_uid, - components, - component_added_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::add_entity_components( - entity_uid, - components, - &mut component_storage_lock, - ); - } + Action::AddComponents(entity_uid, components) => { + let added_component_ids = Self::add_entity_components( + entity_uid, + components, + &mut self.data.component_storage, + ); if !has_swapped_active_queue { self.swap_event_queue(&mut has_swapped_active_queue); } - // TODO: Fix that events are emitted for components that haven't been - // added because a error occurred (for example, the entity already has - // the component) - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); } } - Action::RemoveComponents( - entity_uid, - components_metadata, - component_removed_event_ids, - ) => { - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - Self::remove_entity_components( - entity_uid, - components_metadata - .iter() - .map(|comp_metadata| comp_metadata.id), - &mut component_storage_lock, - ); - } - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - // TODO: Fix that events are emitted for components that haven't been - // removed because a error occurred (for example, the entity does not - // have the component) - for comp_removed_event_id in component_removed_event_ids.ids { - self.emit_event_by_id(comp_removed_event_id); - } + Action::RemoveComponents(entity_uid, component_ids) => { + Self::schedule_removal( + &mut self.data.component_storage, + &mut self.data.pending_removals, + entity_uid, + PendingRemoval::Components(component_ids), + ); } Action::Stop => { self.stop.store(true, Ordering::Relaxed); @@ -463,84 +424,128 @@ impl World } } - #[tracing::instrument(skip_all)] - fn despawn_entity(&self, entity_uid: Uid, has_swapped_active_queue: &mut bool) + fn perform_removals(&mut self, removals: Vec<(Uid, PendingRemoval)>) { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let removed_entity = match component_storage_lock.remove_entity(entity_uid) { - Ok(components) => components, - Err(err) => { - tracing::error!("Failed to despawn entity: {err}"); - return; + for (entity_id, removal) in removals { + match removal { + PendingRemoval::Components(component_ids) => { + Self::remove_entity_components( + entity_id, + component_ids.into_iter().chain([ComponentRemovals::id()]), + &mut self.data.component_storage, + ); + } + PendingRemoval::Entity => { + if let Err(err) = self.data.component_storage.remove_entity(entity_id) + { + tracing::error!("Failed to remove entity {entity_id}: {err}"); + } + } } + } + } + + #[tracing::instrument(skip(component_storage, pending_removals))] + fn schedule_removal( + component_storage: &mut ComponentStorage, + pending_removals: &mut Vec<(Uid, PendingRemoval)>, + entity_uid: Uid, + removal: PendingRemoval, + ) + { + let Some(ent_handle) = Self::get_entity(component_storage, entity_uid) else { + tracing::warn!("Cannot schedule removal. Entity does not exist"); + return; }; - let component_removed_event_uids = removed_entity - .components() - .iter() - .map(|component| { - component - .component() - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-only {} component lock", - component.name() - ) - }) - .get_event_uid(ComponentEventKind::Removed) - }) - .collect::<Vec<_>>(); - - drop(component_storage_lock); - - if !*has_swapped_active_queue { - self.swap_event_queue(has_swapped_active_queue); - } + let component_ids = match removal { + PendingRemoval::Components(ref component_ids) => component_ids, + PendingRemoval::Entity => &ent_handle.component_ids().collect::<Vec<_>>(), + }; - for comp_removed_event_id in component_removed_event_uids { - self.emit_event_by_id(comp_removed_event_id); - } + let Some(mut component_removals) = ent_handle.get_mut::<ComponentRemovals>() + else { + Self::add_entity_components( + entity_uid, + [ComponentRemovals::from_iter(component_ids.iter().copied()) + .into_parts()], + component_storage, + ); + + pending_removals.push((entity_uid, removal)); + + return; + }; + + component_removals.add_ids(component_ids.iter().copied()); + + drop(component_removals); + + pending_removals.push((entity_uid, removal)); } fn add_entity_components( entity_uid: Uid, - components: impl IntoIterator<Item = (Uid, Box<dyn Component>)>, + components: impl IntoIterator<Item = ComponentParts>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for (component_id, component) in components { - if let Err(err) = component_storage - .add_entity_component(entity_uid, (component_id, component)) - { + let component_iter = components.into_iter(); + + let mut added_component_ids = + Vec::<Uid>::with_capacity(component_iter.size_hint().0); + + for component_parts in component_iter { + let comp_id = component_parts.id(); + + if let Err(err) = component_storage.add_entity_component( + entity_uid, + (comp_id, component_parts.name(), component_parts.into_data()), + ) { tracing::error!("Failed to add component to entity: {err}"); + continue; } + + added_component_ids.push(comp_id); } + + added_component_ids } fn remove_entity_components( entity_uid: Uid, component_ids: impl IntoIterator<Item = Uid>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for component_id in component_ids { + let component_id_iter = component_ids.into_iter(); + + let mut removed_component_ids = + Vec::<Uid>::with_capacity(component_id_iter.size_hint().0); + + for component_id in component_id_iter { if let Err(err) = component_storage.remove_entity_component(entity_uid, component_id) { tracing::error!("Failed to remove component to entity: {err}"); + continue; } + + removed_component_ids.push(component_id); } + + removed_component_ids } - fn emit_event_by_id(&self, event_id: Uid) + fn emit_event_by_id<Event: Component>(&self, target: Uid) { - let mut query_required_ids = [SystemComponent::id(), event_id]; + if target.kind() == UidKind::Pair { + return; + } let query = self.flexible_query( - QueryTerms::builder() - .with_required_ids(&mut query_required_ids) + QueryTerms::<2>::builder() + .with_required([SystemComponent::id(), Pair::new::<Event>(target).id()]) .build(), ); @@ -563,12 +568,19 @@ impl World *has_swapped_active_queue = true; } - fn lock_component_storage_rw(&self) -> WriteGuard<'_, ComponentStorage> + fn get_entity( + component_storage: &mut ComponentStorage, + entity_uid: Uid, + ) -> Option<EntityHandle<'_>> { - self.data - .component_storage - .write_nonblock() - .expect("Failed to acquire read-write component storage lock") + let archetype = component_storage.get_entity_archetype(entity_uid)?; + + Some(EntityHandle::new( + archetype, + archetype + .get_entity_by_id(entity_uid) + .expect("Not possible"), + )) } } @@ -590,30 +602,58 @@ pub enum StepResult Stop, } -#[derive(Debug, Default)] -pub struct WorldData +#[derive(Debug)] +struct WorldData { - component_storage: Arc<Lock<ComponentStorage>>, + component_storage: ComponentStorage, sole_storage: SoleStorage, - action_queue: Arc<ActionQueue>, + action_queue: Rc<ActionQueue>, + pending_removals: Vec<(Uid, PendingRemoval)>, +} + +impl Default for WorldData +{ + fn default() -> Self + { + Self { + component_storage: ComponentStorage::default(), + sole_storage: SoleStorage::default(), + action_queue: Rc::new(ActionQueue::default()), + pending_removals: Vec::new(), + } + } +} + +#[derive(Debug)] +enum PendingRemoval +{ + Components(Vec<Uid>), + Entity, } #[derive(Debug)] pub struct EntityComponentRef<'a> { - comp: &'a ArchetypeEntityComponent, + component_id: Uid, + component: &'a ArchetypeEntityComponent, } impl<'a> EntityComponentRef<'a> { - pub fn component(&self) -> &'a Lock<Box<dyn Component>> + fn component(&self) -> &'a Lock<Box<dyn Any>> { - self.comp.component() + self.component.component() } - fn new(comp: &'a ArchetypeEntityComponent) -> Self + #[must_use] + pub fn id(&self) -> Uid { - Self { comp } + self.component_id + } + + fn new(component_id: Uid, comp: &'a ArchetypeEntityComponent) -> Self + { + Self { component_id, component: comp } } } @@ -625,7 +665,7 @@ enum ActiveActionQueue B, } -#[derive(Debug, Default)] +#[derive(Debug)] struct ActionQueue { queue_a: Lock<Vec<Action>>, @@ -652,11 +692,15 @@ impl ActionQueue } } -impl TypeName for ActionQueue +impl Default for ActionQueue { - fn type_name(&self) -> &'static str + fn default() -> Self { - type_name::<Self>() + Self { + queue_a: Lock::new(Vec::new(), type_name::<Vec<Action>>()), + queue_b: Lock::new(Vec::new(), type_name::<Vec<Action>>()), + active_queue: RefCell::new(ActiveActionQueue::default()), + } } } @@ -701,7 +745,7 @@ impl SoleStorage self.storage.insert( sole_type_id, ManuallyDrop::new(StoredSole { - sole: Arc::new(Lock::new(Box::new(sole))), + sole: Arc::new(Lock::new(Box::new(sole), type_name::<SoleT>())), drop_last, }), ); @@ -718,18 +762,9 @@ impl Drop for SoleStorage for sole in self.storage.values_mut() { if sole.drop_last { - tracing::trace!( - "Sole {} pushed to dropping last queue", - sole.sole.read_nonblock().unwrap().type_name() - ); - soles_to_drop_last.push(sole); continue; } - tracing::trace!( - "Dropping sole {}", - sole.sole.read_nonblock().unwrap().type_name() - ); unsafe { ManuallyDrop::drop(sole); @@ -737,11 +772,6 @@ impl Drop for SoleStorage } for sole in &mut soles_to_drop_last { - tracing::trace!( - "Dropping sole {} last", - sole.sole.read_nonblock().unwrap().type_name() - ); - unsafe { ManuallyDrop::drop(sole); } |