summaryrefslogtreecommitdiff
path: root/ecs/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2025-04-10 17:39:21 +0200
committerHampusM <hampus@hampusmat.com>2025-04-10 17:39:38 +0200
commit7d25c21cdf4b46cdab680f11110fb23676c6141b (patch)
treecc953dbbb5cc4f2da36b9b5ad7c569ee0aa5fcd7 /ecs/src
parent3ba82dd26869dad69f686d38bb70caefeaa25bfc (diff)
feat(ecs): re-add support for component events
Diffstat (limited to 'ecs/src')
-rw-r--r--ecs/src/component.rs4
-rw-r--r--ecs/src/component/storage.rs2
-rw-r--r--ecs/src/component/storage/archetype.rs13
-rw-r--r--ecs/src/event/component.rs98
-rw-r--r--ecs/src/lib.rs122
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(),
);