summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-12-09 18:16:50 +0100
committerHampusM <hampus@hampusmat.com>2024-12-09 18:16:50 +0100
commita318a32eba91cacd71c8f0cb09b49a10d12e96ca (patch)
treea76848818496a0e22c0f5f061c33ed89ab944999
parent3553a24c86791f6f4501e3d19fb85f267435cf70 (diff)
feat(ecs): add action to despawn entity
-rw-r--r--ecs/src/actions.rs9
-rw-r--r--ecs/src/component.rs11
-rw-r--r--ecs/src/component/storage.rs21
-rw-r--r--ecs/src/event/component.rs12
-rw-r--r--ecs/src/lib.rs50
5 files changed, 102 insertions, 1 deletions
diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs
index 35e9569..0878067 100644
--- a/ecs/src/actions.rs
+++ b/ecs/src/actions.rs
@@ -29,6 +29,14 @@ impl<'world> Actions<'world>
));
}
+ /// Queues up despawning a entity at the end of the current tick.
+ pub fn despawn(&mut self, entity_uid: Uid)
+ {
+ debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
+
+ self.action_queue.push(Action::Despawn(entity_uid));
+ }
+
/// Queues up adding component(s) to a entity at the end of the current tick.
pub fn add_components<Comps>(&mut self, entity_uid: Uid, components: Comps)
where
@@ -155,6 +163,7 @@ pub(crate) struct EventIds
pub(crate) enum Action
{
Spawn(Vec<Box<dyn Component>>, EventIds),
+ Despawn(Uid),
AddComponents(Uid, Vec<Box<dyn Component>>, EventIds),
RemoveComponents(Uid, Vec<ComponentMetadata>, EventIds),
Stop,
diff --git a/ecs/src/component.rs b/ecs/src/component.rs
index 0f64695..5da510a 100644
--- a/ecs/src/component.rs
+++ b/ecs/src/component.rs
@@ -5,6 +5,7 @@ use seq_macro::seq;
use crate::event::component::{
Added as ComponentAddedEvent,
+ Kind as ComponentEventKind,
Removed as ComponentRemovedEvent,
};
use crate::lock::{ReadGuard, WriteGuard};
@@ -40,6 +41,9 @@ pub trait Component: SystemInput + Any + TypeName
/// The ID of the component `self`. Returns the same value as [`Component::id`].
fn self_id(&self) -> Uid;
+ /// Returns the component UID of a component event for this component.
+ fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid;
+
#[doc(hidden)]
fn as_any_mut(&mut self) -> &mut dyn Any;
@@ -115,6 +119,13 @@ where
Self::id()
}
+ fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid
+ {
+ match event_kind {
+ ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(),
+ }
+ }
+
fn as_any_mut(&mut self) -> &mut dyn Any
{
self
diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs
index ffd682e..54fa834 100644
--- a/ecs/src/component/storage.rs
+++ b/ecs/src/component/storage.rs
@@ -79,6 +79,27 @@ impl Storage
self.archetypes.get(archetype_index)
}
+ pub fn remove_entity(&mut self, entity_uid: Uid)
+ {
+ let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else {
+ return;
+ };
+
+ let Some(archetype_index) =
+ self.find_archetype_index_with_entity(*archetype_id, entity_uid)
+ else {
+ return;
+ };
+
+ let Some(archetype) = self.archetypes.get_mut(archetype_index) else {
+ return;
+ };
+
+ archetype.take_entity(entity_uid);
+
+ self.entity_archetype_lookup.remove(&entity_uid);
+ }
+
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
pub fn push_entity(
&mut self,
diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs
index 5b40c39..b4edffc 100644
--- a/ecs/src/event/component.rs
+++ b/ecs/src/event/component.rs
@@ -41,7 +41,9 @@ where
}
}
-/// Event emitted when a `ComponentT` component is removed from a entity.
+/// 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
@@ -72,3 +74,11 @@ where
Self { _pd: PhantomData }
}
}
+
+/// Specifies a kind of component event UID.
+#[derive(Debug, Clone, Copy)]
+#[non_exhaustive]
+pub enum Kind
+{
+ Removed,
+}
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 01e0cde..334fe69 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -17,6 +17,7 @@ use crate::component::{
Sequence as ComponentSequence,
};
use crate::entity::CREATE_STATIC_ENTITIES;
+use crate::event::component::Kind as ComponentEventKind;
use crate::extension::{Collector as ExtensionCollector, Extension};
use crate::lock::{Lock, WriteGuard};
use crate::phase::{Phase, START as START_PHASE};
@@ -331,6 +332,9 @@ impl World
self.emit_event_by_id(comp_added_event_id);
}
}
+ Action::Despawn(entity_uid) => {
+ self.despawn_entity(entity_uid, &mut has_swapped_active_queue);
+ }
Action::AddComponents(
entity_uid,
components,
@@ -382,6 +386,52 @@ impl World
}
}
+ fn despawn_entity(&self, entity_uid: Uid, has_swapped_active_queue: &mut bool)
+ {
+ let mut component_storage_lock = self.lock_component_storage_rw();
+
+ let Some(archetype) = component_storage_lock.get_entity_archetype(entity_uid)
+ else {
+ #[cfg(feature = "debug")]
+ tracing::error!("No archetype for entity {entity_uid:?} was found");
+
+ return;
+ };
+
+ let entity = archetype
+ .get_entity(entity_uid)
+ .expect("Entity archetype was found but the entity is not in the archetype");
+
+ let component_removed_event_uids = 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<_>>();
+
+ component_storage_lock.remove_entity(entity_uid);
+
+ drop(component_storage_lock);
+
+ if !*has_swapped_active_queue {
+ self.swap_event_queue(has_swapped_active_queue);
+ }
+
+ for comp_removed_event_id in component_removed_event_uids {
+ self.emit_event_by_id(comp_removed_event_id);
+ }
+ }
+
fn emit_event_by_id(&self, event_id: Uid)
{
for (system,) in self