summaryrefslogtreecommitdiff
path: root/ecs/src/lib.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-08-14 20:05:30 +0200
committerHampusM <hampus@hampusmat.com>2024-08-14 20:05:30 +0200
commit07aa59a122cc5e14d2fb2e2c6e3d8f82e4397bde (patch)
tree0ac63f5262d97d3d7f50ab1c72d1ace61935608c /ecs/src/lib.rs
parente9074af15cae7b3c354e524e9fa78cbddb20ff84 (diff)
feat(ecs): add component added event
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r--ecs/src/lib.rs124
1 files changed, 104 insertions, 20 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 04c9b9f..ed2ccef 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -1,18 +1,21 @@
#![deny(clippy::all, clippy::pedantic)]
use std::any::{type_name, TypeId};
+use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Debug;
use std::mem::ManuallyDrop;
-use std::ops::RangeBounds;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
-use std::vec::Drain;
use crate::actions::Action;
use crate::component::storage::Storage as ComponentStorage;
use crate::component::{Component, Id as ComponentId, Sequence as ComponentSequence};
use crate::entity::Uid as EntityUid;
+use crate::event::component::{
+ create_added_id as create_component_added_event_id,
+ ComponentToAddedEvent,
+};
use crate::event::start::Start as StartEvent;
use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence};
use crate::extension::{Collector as ExtensionCollector, Extension};
@@ -20,6 +23,7 @@ use crate::lock::Lock;
use crate::query::options::Options as QueryOptions;
use crate::sole::Sole;
use crate::system::{System, TypeErased as TypeErasedSystem};
+use crate::tuple::Reduce as TupleReduce;
use crate::type_name::TypeName;
pub mod actions;
@@ -64,7 +68,8 @@ impl World
/// Will panic if mutable internal lock cannot be acquired.
pub fn create_entity<Comps>(&mut self, components: Comps) -> EntityUid
where
- Comps: ComponentSequence,
+ Comps: ComponentSequence + TupleReduce<ComponentToAddedEvent>,
+ Comps::Out: EventSequence,
{
let (_, entity_uid) = self
.data
@@ -73,6 +78,10 @@ impl World
.expect("Failed to acquire read-write component storage lock")
.push_entity(EntityUid::new_unique(), components.into_vec());
+ for component_added_event_id in <Comps::Out as EventSequence>::ids().iter() {
+ self.emit_event_by_id(*component_added_event_id);
+ }
+
entity_uid
}
@@ -98,7 +107,7 @@ impl World
self.data
.events
- .entry(EventId::of::<EventT>())
+ .entry(EventT::id())
.or_default()
.push(self.systems.len() - 1);
@@ -125,7 +134,7 @@ impl World
where
EventT: Event,
{
- self.emit_event_by_id(EventId::of::<EventT>());
+ self.emit_event_by_id(EventT::id());
drop(event);
}
@@ -144,13 +153,22 @@ impl World
/// Will panic if a mutable internal lock cannot be acquired.
pub fn perform_queued_actions(&self)
{
- for action in self
- .data
- .action_queue
- .write_nonblock()
- .expect("Failed to aquire read-write action queue lock")
- .drain(..)
+ let mut active_action_queue = match *self.data.action_queue.active_queue.borrow()
{
+ ActiveActionQueue::A => &self.data.action_queue.queue_a,
+ ActiveActionQueue::B => &self.data.action_queue.queue_b,
+ }
+ .write_nonblock()
+ .unwrap_or_else(|err| {
+ panic!(
+ "Failed to take read-write action queue lock {:?}: {err}",
+ self.data.action_queue.active_queue
+ );
+ });
+
+ let mut has_swapped_active_queue = false;
+
+ for action in active_action_queue.drain(..) {
match action {
Action::Spawn(components) => {
let mut component_storage_lock =
@@ -158,8 +176,33 @@ impl World
"Failed to acquire read-write component storage lock",
);
+ let component_ids = components
+ .iter()
+ .map(|component| component.id())
+ .collect::<Vec<_>>();
+
component_storage_lock
.push_entity(EntityUid::new_unique(), components);
+
+ drop(component_storage_lock);
+
+ if !has_swapped_active_queue {
+ let mut active_queue =
+ self.data.action_queue.active_queue.borrow_mut();
+
+ *active_queue = match *active_queue {
+ ActiveActionQueue::A => ActiveActionQueue::B,
+ ActiveActionQueue::B => ActiveActionQueue::A,
+ };
+
+ has_swapped_active_queue = true;
+ }
+
+ for component_id in component_ids {
+ self.emit_event_by_id(create_component_added_event_id(
+ component_id,
+ ));
+ }
}
Action::AddComponents(entity_uid, components) => {
let mut component_storage_lock =
@@ -167,8 +210,33 @@ impl World
"Failed to acquire read-write component storage lock",
);
+ let component_ids = components
+ .iter()
+ .map(|component| component.id())
+ .collect::<Vec<_>>();
+
component_storage_lock
.add_components_to_entity(entity_uid, components);
+
+ drop(component_storage_lock);
+
+ if !has_swapped_active_queue {
+ let mut active_queue =
+ self.data.action_queue.active_queue.borrow_mut();
+
+ *active_queue = match *active_queue {
+ ActiveActionQueue::A => ActiveActionQueue::B,
+ ActiveActionQueue::B => ActiveActionQueue::A,
+ };
+
+ has_swapped_active_queue = true;
+ }
+
+ for component_id in component_ids {
+ self.emit_event_by_id(create_component_added_event_id(
+ component_id,
+ ));
+ }
}
Action::RemoveComponents(entity_uid, component_ids) => {
let mut component_storage_lock =
@@ -237,7 +305,7 @@ pub struct WorldData
events: HashMap<EventId, Vec<usize>>,
component_storage: Arc<Lock<ComponentStorage>>,
sole_storage: SoleStorage,
- action_queue: Arc<Lock<ActionQueue>>,
+ action_queue: Arc<ActionQueue>,
}
#[derive(Debug)]
@@ -261,22 +329,38 @@ impl From<Box<dyn Component>> for EntityComponent
}
}
+#[derive(Debug, Default, Clone, Copy)]
+enum ActiveActionQueue
+{
+ #[default]
+ A,
+ B,
+}
+
#[derive(Debug, Default)]
struct ActionQueue
{
- queue: Vec<Action>,
+ queue_a: Lock<Vec<Action>>,
+ queue_b: Lock<Vec<Action>>,
+ active_queue: RefCell<ActiveActionQueue>,
}
impl ActionQueue
{
- fn push(&mut self, action: Action)
+ fn push(&self, action: Action)
{
- self.queue.push(action);
- }
-
- fn drain(&mut self, range: impl RangeBounds<usize>) -> Drain<Action>
- {
- self.queue.drain(range)
+ match *self.active_queue.borrow() {
+ ActiveActionQueue::A => self
+ .queue_a
+ .write_nonblock()
+ .expect("Failed to aquire read-write action queue A lock")
+ .push(action),
+ ActiveActionQueue::B => self
+ .queue_b
+ .write_nonblock()
+ .expect("Failed to aquire read-write action queue A lock")
+ .push(action),
+ }
}
}