diff options
Diffstat (limited to 'ecs')
-rw-r--r-- | ecs/src/actions.rs | 9 | ||||
-rw-r--r-- | ecs/src/component.rs | 11 | ||||
-rw-r--r-- | ecs/src/component/storage.rs | 21 | ||||
-rw-r--r-- | ecs/src/event/component.rs | 12 | ||||
-rw-r--r-- | ecs/src/lib.rs | 50 |
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 |