summaryrefslogtreecommitdiff
path: root/ecs/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r--ecs/src/lib.rs140
1 files changed, 105 insertions, 35 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 53abc6b..07b1cba 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -15,14 +15,13 @@ use crate::component::storage::archetype::EntityComponent as ArchetypeEntityComp
use crate::component::storage::Storage as ComponentStorage;
use crate::component::{
Component,
+ IntoParts,
Parts as ComponentParts,
+ Removals as ComponentRemovals,
Sequence as ComponentSequence,
};
-use crate::entity::CREATE_STATIC_ENTITIES;
-use crate::event::component::{
- Added as ComponentAddedEvent,
- Removed as ComponentRemovedEvent,
-};
+use crate::entity::{Handle as EntityHandle, CREATE_STATIC_ENTITIES};
+use crate::event::component::Added as ComponentAddedEvent;
use crate::extension::{Collector as ExtensionCollector, Extension};
use crate::lock::Lock;
use crate::pair::{ChildOf, DependsOn, Pair};
@@ -209,8 +208,12 @@ impl World
self.data.component_storage.create_imaginary_archetypes();
+ let prev_pending_removals = std::mem::take(&mut self.data.pending_removals);
+
self.perform_queued_actions();
+ self.perform_removals(prev_pending_removals);
+
if self.stop.load(Ordering::Relaxed) {
return StepResult::Stop;
}
@@ -355,6 +358,8 @@ impl World
let mut has_swapped_active_queue = false;
+ // TODO: Figure out a good way to handle situations where there are multiple
+ // AddComponents/RemoveComponents actions that affect the same entity.
for action in active_action_queue.drain(..) {
match action {
Action::Spawn(components) => {
@@ -382,24 +387,12 @@ impl World
}
}
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(),
- );
- }
+ Self::schedule_removal(
+ &mut self.data.component_storage,
+ &mut self.data.pending_removals,
+ entity_uid,
+ PendingRemoval::Entity,
+ );
}
Action::AddComponents(entity_uid, components) => {
let added_component_ids = Self::add_entity_components(
@@ -417,19 +410,12 @@ impl World
}
}
Action::RemoveComponents(entity_uid, component_ids) => {
- let removed_component_ids = Self::remove_entity_components(
- entity_uid,
- component_ids,
+ Self::schedule_removal(
&mut self.data.component_storage,
+ &mut self.data.pending_removals,
+ entity_uid,
+ PendingRemoval::Components(component_ids),
);
-
- 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);
@@ -438,6 +424,66 @@ impl World
}
}
+ fn perform_removals(&mut self, removals: Vec<(Uid, PendingRemoval)>)
+ {
+ for (entity_id, removal) in removals {
+ match removal {
+ PendingRemoval::Components(component_ids) => {
+ Self::remove_entity_components(
+ entity_id,
+ component_ids.into_iter().chain([ComponentRemovals::id()]),
+ &mut self.data.component_storage,
+ );
+ }
+ PendingRemoval::Entity => {
+ if let Err(err) = self.data.component_storage.remove_entity(entity_id)
+ {
+ tracing::error!("Failed to remove entity {entity_id}: {err}");
+ }
+ }
+ }
+ }
+ }
+
+ #[tracing::instrument(skip(component_storage, pending_removals))]
+ fn schedule_removal(
+ component_storage: &mut ComponentStorage,
+ pending_removals: &mut Vec<(Uid, PendingRemoval)>,
+ entity_uid: Uid,
+ removal: PendingRemoval,
+ )
+ {
+ let Some(ent_handle) = Self::get_entity(component_storage, entity_uid) else {
+ tracing::warn!("Cannot schedule removal. Entity does not exist");
+ return;
+ };
+
+ let component_ids = match removal {
+ PendingRemoval::Components(ref component_ids) => component_ids,
+ PendingRemoval::Entity => &ent_handle.component_ids().collect::<Vec<_>>(),
+ };
+
+ let Some(mut component_removals) = ent_handle.get_mut::<ComponentRemovals>()
+ else {
+ Self::add_entity_components(
+ entity_uid,
+ [ComponentRemovals::from_iter(component_ids.iter().copied())
+ .into_parts()],
+ component_storage,
+ );
+
+ pending_removals.push((entity_uid, removal));
+
+ return;
+ };
+
+ component_removals.add_ids(component_ids.iter().copied());
+
+ drop(component_removals);
+
+ pending_removals.push((entity_uid, removal));
+ }
+
fn add_entity_components(
entity_uid: Uid,
components: impl IntoIterator<Item = ComponentParts>,
@@ -521,6 +567,21 @@ impl World
*has_swapped_active_queue = true;
}
+
+ fn get_entity(
+ component_storage: &mut ComponentStorage,
+ entity_uid: Uid,
+ ) -> Option<EntityHandle<'_>>
+ {
+ let archetype = component_storage.get_entity_archetype(entity_uid)?;
+
+ Some(EntityHandle::new(
+ archetype,
+ archetype
+ .get_entity_by_id(entity_uid)
+ .expect("Not possible"),
+ ))
+ }
}
impl Default for World
@@ -542,11 +603,12 @@ pub enum StepResult
}
#[derive(Debug)]
-pub struct WorldData
+struct WorldData
{
component_storage: ComponentStorage,
sole_storage: SoleStorage,
action_queue: Rc<ActionQueue>,
+ pending_removals: Vec<(Uid, PendingRemoval)>,
}
impl Default for WorldData
@@ -557,11 +619,19 @@ impl Default for WorldData
component_storage: ComponentStorage::default(),
sole_storage: SoleStorage::default(),
action_queue: Rc::new(ActionQueue::default()),
+ pending_removals: Vec::new(),
}
}
}
#[derive(Debug)]
+enum PendingRemoval
+{
+ Components(Vec<Uid>),
+ Entity,
+}
+
+#[derive(Debug)]
pub struct EntityComponentRef<'a>
{
component_id: Uid,