diff options
author | HampusM <hampus@hampusmat.com> | 2025-04-10 17:39:21 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2025-04-10 17:39:38 +0200 |
commit | 7d25c21cdf4b46cdab680f11110fb23676c6141b (patch) | |
tree | cc953dbbb5cc4f2da36b9b5ad7c569ee0aa5fcd7 /ecs/src | |
parent | 3ba82dd26869dad69f686d38bb70caefeaa25bfc (diff) |
feat(ecs): re-add support for component events
Diffstat (limited to 'ecs/src')
-rw-r--r-- | ecs/src/component.rs | 4 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 2 | ||||
-rw-r--r-- | ecs/src/component/storage/archetype.rs | 13 | ||||
-rw-r--r-- | ecs/src/event/component.rs | 98 | ||||
-rw-r--r-- | ecs/src/lib.rs | 122 |
5 files changed, 98 insertions, 141 deletions
diff --git a/ecs/src/component.rs b/ecs/src/component.rs index 207c329..cc4b460 100644 --- a/ecs/src/component.rs +++ b/ecs/src/component.rs @@ -5,7 +5,6 @@ use std::ops::{Deref, DerefMut}; use seq_macro::seq; -use crate::event::component::Kind as ComponentEventKind; use crate::lock::{ Error as LockError, MappedReadGuard, @@ -39,9 +38,6 @@ pub trait Component: SystemInput + Any /// Returns the name of this component. fn name(&self) -> &'static str; - - /// Returns the component UID of a component event for this component. - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid; } impl dyn Component diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs index 9cf4433..14f3ea4 100644 --- a/ecs/src/component/storage.rs +++ b/ecs/src/component/storage.rs @@ -268,7 +268,7 @@ impl Storage entity.insert_component( component_id, - ArchetypeEntityComponent::new(component, component_name), + ArchetypeEntityComponent::new(component, component_id, component_name), add_edge_archetype, ); diff --git a/ecs/src/component/storage/archetype.rs b/ecs/src/component/storage/archetype.rs index 10a665e..f8c204b 100644 --- a/ecs/src/component/storage/archetype.rs +++ b/ecs/src/component/storage/archetype.rs @@ -314,18 +314,29 @@ impl Entity #[derive(Debug)] pub struct EntityComponent { + id: Uid, component: Lock<Box<dyn Any>>, } impl EntityComponent { - pub fn new(component: Box<dyn Any>, component_name: &'static str) -> Self + pub fn new( + component: Box<dyn Any>, + component_id: Uid, + component_name: &'static str, + ) -> Self { Self { + id: component_id, component: Lock::new(component, component_name), } } + pub fn id(&self) -> Uid + { + self.id + } + pub fn component(&self) -> &Lock<Box<dyn Any>> { &self.component diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs index b4edffc..ef09480 100644 --- a/ecs/src/event/component.rs +++ b/ecs/src/event/component.rs @@ -1,84 +1,18 @@ //! Component events. -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; - -use ecs_macros::Component; - -use crate::component::Component; - -/// Event emitted when: -/// a) A entity with component `ComponentT` is spawned. -/// b) A component `ComponentT` is added to a entity. -#[derive(Clone, Component)] -pub struct Added<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Debug for Added<ComponentT> -where - ComponentT: Component, -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Added") - .field("_pd", &self._pd) - .finish() - } -} - -impl<ComponentT> Default for Added<ComponentT> -where - ComponentT: Component, -{ - fn default() -> Self - { - Self { _pd: PhantomData } - } -} - -/// Event emitted when: -/// a) A `ComponentT` component is removed from a entity. -/// b) A entity with component `ComponentT` is despawned. -#[derive(Clone, Component)] -pub struct Removed<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Debug for Removed<ComponentT> -where - ComponentT: Component, -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Removed") - .field("_pd", &self._pd) - .finish() - } -} - -impl<ComponentT> Default for Removed<ComponentT> -where - ComponentT: Component, -{ - fn default() -> Self - { - Self { _pd: PhantomData } - } -} - -/// Specifies a kind of component event UID. -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub enum Kind -{ - Removed, -} +use std::convert::Infallible; +use std::fmt::Debug; + +use crate::Component; + +/// Pair relation for events emitted when: +/// a) A entity with the target component is spawned. +/// b) The target component is added to a entity. +#[derive(Debug, Component)] +pub struct Added(Infallible); + +/// Pair relation for events emitted when: +/// a) The target component is removed from a entity. +/// b) A entity with the target component is despawned. +#[derive(Debug, Component)] +pub struct Removed(Infallible); diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 3b89dac..dd43e0b 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -18,6 +18,10 @@ use crate::component::{ Sequence as ComponentSequence, }; use crate::entity::CREATE_STATIC_ENTITIES; +use crate::event::component::{ + Added as ComponentAddedEvent, + Removed as ComponentRemovedEvent, +}; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::{Lock, WriteGuard}; use crate::pair::{ChildOf, DependsOn, Pair}; @@ -111,6 +115,8 @@ impl World { debug_assert_eq!(entity_uid.kind(), UidKind::Entity); + let added_component_ids; + { let mut component_storage_lock = self.lock_component_storage_rw(); @@ -119,18 +125,16 @@ impl World return; }; - Self::add_entity_components( + added_component_ids = Self::add_entity_components( entity_uid, components.into_parts_array(), &mut component_storage_lock, ); } - // TODO: Emit component added events here - - // for added_event_id in Comps::added_event_ids() { - // self.emit_event_by_id(added_event_id); - // } + for comp_id in added_component_ids { + self.emit_event_by_id::<ComponentAddedEvent>(comp_id); + } } /// Adds a globally shared singleton value. @@ -156,14 +160,13 @@ impl World )); } - 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, )); @@ -377,6 +380,8 @@ impl World for action in active_action_queue.drain(..) { match action { Action::Spawn(components) => { + let added_component_ids; + { let mut component_storage_lock = self.lock_component_storage_rw(); @@ -389,7 +394,7 @@ impl World continue; }; - Self::add_entity_components( + added_component_ids = Self::add_entity_components( new_entity_uid, components, &mut component_storage_lock, @@ -400,20 +405,20 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - // TODO: Emit component added events here - - // 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); } Action::AddComponents(entity_uid, components) => { + let added_component_ids; + { let mut component_storage_lock = self.lock_component_storage_rw(); - Self::add_entity_components( + added_component_ids = Self::add_entity_components( entity_uid, components, &mut component_storage_lock, @@ -424,20 +429,17 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - // TODO: Emit component added events here - - // 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, component_ids) => { + let removed_component_ids; + { let mut component_storage_lock = self.lock_component_storage_rw(); - Self::remove_entity_components( + removed_component_ids = Self::remove_entity_components( entity_uid, component_ids, &mut component_storage_lock, @@ -448,14 +450,9 @@ impl World self.swap_event_queue(&mut has_swapped_active_queue); } - // TODO: Emit component removed events here - - // 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); - // } + for comp_id in removed_component_ids { + self.emit_event_by_id::<ComponentRemovedEvent>(comp_id); + } } Action::Stop => { self.stop.store(true, Ordering::Relaxed); @@ -469,7 +466,7 @@ impl World { let mut component_storage_lock = self.lock_component_storage_rw(); - let _removed_entity = match component_storage_lock.remove_entity(entity_uid) { + let removed_entity = match component_storage_lock.remove_entity(entity_uid) { Ok(components) => components, Err(err) => { tracing::error!("Failed to despawn entity: {err}"); @@ -483,54 +480,73 @@ impl World self.swap_event_queue(has_swapped_active_queue); } - // TODO: Emit component removed events here - - // for comp_removed_event_id in component_removed_event_uids { - // self.emit_event_by_id(comp_removed_event_id); - // } + for removed_ent_comp in removed_entity.components() { + self.emit_event_by_id::<ComponentRemovedEvent>(removed_ent_comp.id()); + } } fn add_entity_components( entity_uid: Uid, components: impl IntoIterator<Item = ComponentParts>, component_storage: &mut ComponentStorage, - ) + ) -> Vec<Uid> { - for component_parts in components { + 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, - ( - component_parts.id(), - component_parts.name(), - component_parts.into_data(), - ), + (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 } - #[allow(dead_code)] - fn emit_event_by_id(&self, event_id: Uid) + fn emit_event_by_id<Event: Component>(&self, target: Uid) { + if target.kind() == UidKind::Pair { + return; + } + let query = self.flexible_query( QueryTerms::<2>::builder() - .with_required([SystemComponent::id(), event_id]) + .with_required([SystemComponent::id(), Pair::new::<Event>(target).id()]) .build(), ); |