diff options
Diffstat (limited to 'ecs/src/lib.rs')
| -rw-r--r-- | ecs/src/lib.rs | 486 |
1 files changed, 252 insertions, 234 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 53abc6b..f6fba64 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,7 +1,6 @@ #![deny(clippy::all, clippy::pedantic)] use std::any::{type_name, Any, TypeId}; -use std::cell::RefCell; use std::fmt::Debug; use std::mem::ManuallyDrop; use std::rc::Rc; @@ -15,31 +14,36 @@ use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComp use crate::component::storage::Storage as ComponentStorage; use crate::component::{ Component, + IntoParts as IntoComponentParts, Parts as ComponentParts, Sequence as ComponentSequence, }; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::{ - Added as ComponentAddedEvent, - Removed as ComponentRemovedEvent, -}; +use crate::entity::{Declaration as EntityDeclaration, Handle as EntityHandle}; +use crate::event::component::Added; +use crate::event::{Emitted as EmittedEvent, NewEvents, Submitter as EventSubmitter}; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::Lock; use crate::pair::{ChildOf, DependsOn, Pair}; -use crate::phase::{Phase, START as START_PHASE}; +use crate::phase::{ + Phase, + POST_UPDATE as POST_UPDATE_PHASE, + PRE_UPDATE as PRE_UPDATE_PHASE, + START as START_PHASE, + UPDATE as UPDATE_PHASE, +}; use crate::query::flexible::Query as FlexibleQuery; -use crate::query::term::Without; use crate::query::{ - Iter as QueryIter, TermWithFieldTuple as QueryTermWithFieldTuple, TermWithoutFieldTuple as QueryTermWithoutFieldTuple, Terms as QueryTerms, TermsBuilderInterface, + MAX_TERM_CNT as QUERY_MAX_TERM_CNT, }; -use crate::sole::Sole; +use crate::sole::{Single, Sole}; use crate::stats::Stats; -use crate::system::{System, SystemComponent}; -use crate::uid::{Kind as UidKind, Uid, Wildcard}; +use crate::system::observer::{Observer, WrapperComponent as ObserverWrapperComponent}; +use crate::system::{Callbacks, Metadata as SystemMetadata, System, SystemComponent}; +use crate::uid::{Kind as UidKind, Uid}; pub mod actions; pub mod component; @@ -56,9 +60,6 @@ pub mod tuple; pub mod uid; pub mod util; -#[doc(hidden)] -pub mod private; - mod lock; pub use ecs_macros::{Component, Sole}; @@ -84,49 +85,49 @@ impl World is_first_tick: AtomicBool::new(false), }; - world.add_sole(Stats::default()).ok(); + crate::phase::spawn_entities(&mut world); - for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(&mut world); - } + world.add_sole(Stats::default()).ok(); world } - /// Creates a new entity with the given components. + /// Creates a entity with the given components. A new unique [`Uid`] will be generated + /// for this entity. pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid where Comps: ComponentSequence, { let entity_uid = Uid::new_unique(UidKind::Entity); - self.create_entity_with_uid(components, entity_uid); + self.create_entity_with_uid(entity_uid, components); entity_uid } + /// Creates a entity with the given components. The entity will have the specified + /// [`Uid`]. #[tracing::instrument(skip_all)] - #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&mut self, components: Comps, entity_uid: Uid) + pub fn create_entity_with_uid<Comps>(&mut self, entity_uid: Uid, components: Comps) where Comps: ComponentSequence, { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - if let Err(err) = self.data.component_storage.create_entity(entity_uid) { - tracing::warn!("Failed to create entity: {err}"); - return; - } + self.create_ent(entity_uid, components.into_parts_array()); + } - let added_component_ids = Self::add_entity_components( - entity_uid, - components.into_parts_array(), + pub fn add_component(&mut self, entity_id: Uid, component_parts: ComponentParts) + { + Self::add_entity_components( + entity_id, + [component_parts], &mut self.data.component_storage, + &EventSubmitter::new(&self.data.new_events), ); + } - for comp_id in added_component_ids { - self.emit_event_by_id::<ComponentAddedEvent>(comp_id); - } + pub fn create_declared_entity(&mut self, entity_decl: &EntityDeclaration) + { + entity_decl.create(self); } /// Adds a globally shared singleton value. @@ -140,28 +141,45 @@ impl World self.data.sole_storage.insert(sole) } - pub fn register_system<'this, SystemImpl>( + pub fn register_observer<'this, SystemImpl, ObserverT>( &'this mut self, - phase_euid: Uid, - system: impl System<'this, SystemImpl>, - ) + observer: ObserverT, + ) where + ObserverT: Observer<'this, SystemImpl>, { - self.create_entity(( - SystemComponent { system: system.into_type_erased() }, - Pair::new::<DependsOn>(phase_euid), - )); + let (wrapper_comp, mut system_callbacks) = observer.finish_observer(); + + let ent_id = Uid::new_unique(UidKind::Entity); + + self.create_ent( + ent_id, + [wrapper_comp.into_parts()].into_iter().chain( + ObserverT::observed_events() + .into_iter() + .map(IntoComponentParts::into_parts), + ), + ); + + system_callbacks.on_created(self, SystemMetadata { ent_id }); } - pub fn register_observer_system<'this, SystemImpl>( + pub fn register_system<'this, SystemImpl>( &'this mut self, + phase_euid: Uid, system: impl System<'this, SystemImpl>, - event: Pair<Uid, Uid>, ) { - self.create_entity(( - SystemComponent { system: system.into_type_erased() }, - event, + let (type_erased_system, mut system_callbacks) = system.finish(); + + let system_ent_id = self.create_entity(( + SystemComponent { system: type_erased_system }, + Pair::builder() + .relation::<DependsOn>() + .target_id(phase_euid) + .build(), )); + + system_callbacks.on_created(self, SystemMetadata { ent_id: system_ent_id }); } /// Adds a extensions. @@ -172,7 +190,9 @@ impl World extension.collect(extension_collector); } - pub fn query<FieldTerms, FieldlessTerms>(&self) -> Query<FieldTerms, FieldlessTerms> + pub fn query<FieldTerms, FieldlessTerms>( + &self, + ) -> Query<'_, FieldTerms, FieldlessTerms> where FieldTerms: QueryTermWithFieldTuple, FieldlessTerms: QueryTermWithoutFieldTuple, @@ -188,6 +208,30 @@ impl World FlexibleQuery::new(self, terms) } + pub fn get_entity(&self, entity_id: Uid) -> Option<EntityHandle<'_>> + { + let archetype = self + .data + .component_storage + .get_entity_archetype(entity_id)?; + + let Some(entity) = archetype.get_entity_by_id(entity_id) else { + unreachable!("Should exist since archetype was found by entity id"); + }; + + Some(EntityHandle::new(archetype, entity, self)) + } + + pub fn get_sole<SoleT: Sole>(&self) -> Option<Single<'_, SoleT>> + { + Some(Single::new(self.data.sole_storage.get::<SoleT>()?)) + } + + pub fn event_submitter(&self) -> EventSubmitter<'_> + { + EventSubmitter::new(&self.data.new_events) + } + /// Performs a single tick. /// # Panics /// Will panic if mutable internal lock cannot be acquired. @@ -207,6 +251,8 @@ impl World self.perform_phases(); + self.emit_new_events(); + self.data.component_storage.create_imaginary_archetypes(); self.perform_queued_actions(); @@ -215,17 +261,9 @@ impl World return StepResult::Stop; } - let mut stats_lock = self - .data - .sole_storage - .get::<Stats>() - .expect("No stats sole found") - .write_nonblock() - .expect("Failed to aquire read-write stats sole lock"); - - let stats = stats_lock - .downcast_mut::<Stats>() - .expect("Casting stats sole to Stats type failed"); + let Some(mut stats) = self.get_sole::<Stats>() else { + unreachable!(); // Reason: is added in World::new + }; stats.current_tick += 1; @@ -285,23 +323,51 @@ impl World ) } + #[tracing::instrument(skip_all)] + fn create_ent( + &mut self, + entity_uid: Uid, + components: impl IntoIterator<Item = ComponentParts>, + ) + { + debug_assert_eq!(entity_uid.kind(), UidKind::Entity); + + if let Err(err) = self.data.component_storage.create_entity(entity_uid) { + tracing::warn!("Failed to create entity: {err}"); + return; + } + + Self::add_entity_components( + entity_uid, + components, + &mut self.data.component_storage, + &EventSubmitter::new(&self.data.new_events), + ); + } + fn query_and_run_systems(&self, phase_euid: Uid) { - let system_query = self.flexible_query( - QueryTerms::<2>::builder() - .with_required([ - SystemComponent::id(), - Pair::new::<DependsOn>(phase_euid).id(), - ]) - .build(), + let system_query = Query::<(&SystemComponent,)>::from_flexible_query( + self.flexible_query( + QueryTerms::<QUERY_MAX_TERM_CNT>::builder() + .with_required([ + SystemComponent::id(), + Pair::builder() + .relation::<DependsOn>() + .target_id(phase_euid) + .build() + .id(), + ]) + .build(), + ), ); - for (system_component,) in - QueryIter::<(&SystemComponent,), _>::new(self, system_query.iter()) - { + for (system_ent_id, (system_component,)) in system_query.iter_with_euids() { // SAFETY: The world lives long enough unsafe { - system_component.system.run(self); + system_component + .system + .run(self, SystemMetadata { ent_id: system_ent_id }); } } } @@ -312,7 +378,11 @@ impl World QueryTerms::<2>::builder() .with_required([ Phase::id(), - Pair::new::<ChildOf>(parent_phase_euid).id(), + Pair::builder() + .relation::<ChildOf>() + .target_id(parent_phase_euid) + .build() + .id(), ]) .build(), ); @@ -323,43 +393,63 @@ impl World } } + fn perform_single_phase(&self, phase_entity_id: Uid) + { + self.query_and_run_systems(phase_entity_id); + self.perform_child_phases(phase_entity_id); + } + fn perform_phases(&self) { - let phase_query = self.query::<(&Phase,), (Without<Pair<ChildOf, Wildcard>>,)>(); + self.perform_single_phase(*PRE_UPDATE_PHASE); + self.perform_single_phase(*UPDATE_PHASE); + self.perform_single_phase(*POST_UPDATE_PHASE); + } - for (phase_entity_id, _) in phase_query.iter_with_euids() { - if phase_entity_id == *START_PHASE { - continue; - } + fn emit_new_events(&self) + { + loop { + let new_events = { + let mut new_events_lock = self + .data + .new_events + .write_nonblock() + .expect("Failed to acquire read-write lock to new events"); + + if new_events_lock.is_empty() { + break; + } - self.query_and_run_systems(phase_entity_id); - self.perform_child_phases(phase_entity_id); + new_events_lock.take() + }; + + for (event_id, event_matches) in new_events { + self.emit_event_observers( + event_id, + &EmittedEvent { + event: event_id, + match_ids: &event_matches.match_ids, + }, + ); + } } } #[tracing::instrument(skip_all)] fn perform_queued_actions(&mut self) { - let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() - { - ActiveActionQueue::A => &self.data.action_queue.queue_a, - ActiveActionQueue::B => &self.data.action_queue.queue_b, - } - .write_nonblock() - .unwrap_or_else(|err| { - panic!( - "Failed to take read-write action queue lock {:?}: {err}", - self.data.action_queue.active_queue - ); - }); - - let mut has_swapped_active_queue = false; + let mut action_queue_lock = self + .data + .action_queue + .queue + .write_nonblock() + .unwrap_or_else(|err| { + panic!("Failed to take read-write action queue lock: {err}",); + }); - for action in active_action_queue.drain(..) { + for action in action_queue_lock.drain(..) { match action { - Action::Spawn(components) => { - let new_entity_uid = Uid::new_unique(UidKind::Entity); - + Action::Spawn(new_entity_uid, components) => { if let Err(err) = self.data.component_storage.create_entity(new_entity_uid) { @@ -367,69 +457,34 @@ impl World continue; } - let added_component_ids = Self::add_entity_components( + Self::add_entity_components( new_entity_uid, components, &mut self.data.component_storage, + &EventSubmitter::new(&self.data.new_events), ); - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_id in added_component_ids { - self.emit_event_by_id::<ComponentAddedEvent>(comp_id); - } } Action::Despawn(entity_uid) => { - let removed_entity = - match self.data.component_storage.remove_entity(entity_uid) { - Ok(components) => components, - Err(err) => { - tracing::error!("Failed to despawn entity: {err}"); - return; - } - }; - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for removed_ent_comp in removed_entity.components() { - self.emit_event_by_id::<ComponentRemovedEvent>( - removed_ent_comp.id(), - ); + if let Err(err) = + self.data.component_storage.remove_entity(entity_uid) + { + tracing::error!("Failed to despawn entity: {err}"); } } Action::AddComponents(entity_uid, components) => { - let added_component_ids = Self::add_entity_components( + Self::add_entity_components( entity_uid, components, &mut self.data.component_storage, + &EventSubmitter::new(&self.data.new_events), ); - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_id in added_component_ids { - self.emit_event_by_id::<ComponentAddedEvent>(comp_id); - } } Action::RemoveComponents(entity_uid, component_ids) => { - let removed_component_ids = Self::remove_entity_components( + Self::remove_entity_components( entity_uid, component_ids, &mut self.data.component_storage, ); - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_id in removed_component_ids { - self.emit_event_by_id::<ComponentRemovedEvent>(comp_id); - } } Action::Stop => { self.stop.store(true, Ordering::Relaxed); @@ -442,85 +497,77 @@ impl World entity_uid: Uid, components: impl IntoIterator<Item = ComponentParts>, component_storage: &mut ComponentStorage, - ) -> Vec<Uid> + event_submitter: &EventSubmitter<'_>, + ) { 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(); + let comp_name = component_parts.name(); + if let Err(err) = component_storage.add_entity_component( entity_uid, - (comp_id, component_parts.name(), component_parts.into_data()), + (comp_id, comp_name, component_parts.into_data()), ) { - tracing::error!("Failed to add component to entity: {err}"); + tracing::error!("Failed to add component {comp_name} to entity: {err}"); continue; } - added_component_ids.push(comp_id); - } + if comp_id.kind() == UidKind::Pair { + continue; + } - added_component_ids + event_submitter.submit_event( + &Pair::builder() + .relation::<Added>() + .target_id(comp_id) + .build(), + entity_uid, + ); + } } fn remove_entity_components( entity_uid: Uid, component_ids: impl IntoIterator<Item = Uid>, component_storage: &mut ComponentStorage, - ) -> Vec<Uid> + ) { 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<Event: Component>(&self, target: Uid) + fn emit_event_observers(&self, event_id: Uid, emitted_event: &EmittedEvent<'_>) { - if target.kind() == UidKind::Pair { - return; - } - - let query = self.flexible_query( - QueryTerms::<2>::builder() - .with_required([SystemComponent::id(), Pair::new::<Event>(target).id()]) - .build(), + assert_eq!(event_id.kind(), UidKind::Pair); + + let query = Query::<(&ObserverWrapperComponent,)>::from_flexible_query( + self.flexible_query( + QueryTerms::<QUERY_MAX_TERM_CNT>::builder() + .with_required([ObserverWrapperComponent::id(), event_id]) + .build(), + ), ); - for (system,) in QueryIter::<(&SystemComponent,), _>::new(self, query.iter()) { + for (observer_ent_id, (observer,)) in query.iter_with_euids() { unsafe { - system.system.run(self); + observer.run( + self, + SystemMetadata { ent_id: observer_ent_id }, + emitted_event.clone(), + ); } } } - - fn swap_event_queue(&self, has_swapped_active_queue: &mut bool) - { - let mut active_queue = self.data.action_queue.active_queue.borrow_mut(); - - *active_queue = match *active_queue { - ActiveActionQueue::A => ActiveActionQueue::B, - ActiveActionQueue::B => ActiveActionQueue::A, - }; - - *has_swapped_active_queue = true; - } } impl Default for World @@ -541,31 +588,21 @@ pub enum StepResult Stop, } -#[derive(Debug)] -pub struct WorldData +#[derive(Debug, Default)] +struct WorldData { component_storage: ComponentStorage, sole_storage: SoleStorage, action_queue: Rc<ActionQueue>, + new_events: Lock<NewEvents>, } -impl Default for WorldData -{ - fn default() -> Self - { - Self { - component_storage: ComponentStorage::default(), - sole_storage: SoleStorage::default(), - action_queue: Rc::new(ActionQueue::default()), - } - } -} - -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct EntityComponentRef<'a> { component_id: Uid, component: &'a ArchetypeEntityComponent, + entity_id: Uid, } impl<'a> EntityComponentRef<'a> @@ -581,56 +618,37 @@ impl<'a> EntityComponentRef<'a> self.component_id } - fn new(component_id: Uid, comp: &'a ArchetypeEntityComponent) -> Self + #[must_use] + pub fn entity_id(&self) -> Uid { - Self { component_id, component: comp } + self.entity_id } -} -#[derive(Debug, Default, Clone, Copy)] -enum ActiveActionQueue -{ - #[default] - A, - B, + fn new(component_id: Uid, comp: &'a ArchetypeEntityComponent, entity_id: Uid) + -> Self + { + Self { + component_id, + component: comp, + entity_id, + } + } } -#[derive(Debug)] +#[derive(Debug, Default)] struct ActionQueue { - queue_a: Lock<Vec<Action>>, - queue_b: Lock<Vec<Action>>, - active_queue: RefCell<ActiveActionQueue>, + queue: Lock<Vec<Action>>, } impl ActionQueue { fn push(&self, action: Action) { - match *self.active_queue.borrow() { - ActiveActionQueue::A => self - .queue_a - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - ActiveActionQueue::B => self - .queue_b - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - } - } -} - -impl Default for ActionQueue -{ - fn default() -> 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()), - } + self.queue + .write_nonblock() + .expect("Failed to aquire read-write lock to action queue") + .push(action); } } |
