summaryrefslogtreecommitdiff
path: root/ecs/src/lib.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-12-09 14:05:33 +0100
committerHampusM <hampus@hampusmat.com>2024-12-09 14:05:33 +0100
commitdcc40c9205e5f4cf484523f97eb12a561d7b2b22 (patch)
tree2908b6ca3b2fa390a45b383b91edf7a72c42ef4b /ecs/src/lib.rs
parent158e36bf6bfcbc2ed0ffc670788ed8c0abd3f282 (diff)
refactor(ecs): use phases for system ordering
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r--ecs/src/lib.rs311
1 files changed, 187 insertions, 124 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs
index 78e526f..01e0cde 100644
--- a/ecs/src/lib.rs
+++ b/ecs/src/lib.rs
@@ -10,22 +10,21 @@ use std::sync::Arc;
use crate::actions::Action;
use crate::component::storage::Storage as ComponentStorage;
-use crate::component::{Component, Sequence as ComponentSequence};
-use crate::entity::CREATE_STATIC_ENTITIES;
-use crate::event::component::{
- create_added_id as create_component_added_event_id,
- create_removed_id as create_component_removed_event_id,
- TypeTransformComponentsToAddedEvents,
+use crate::component::{
+ Component,
+ IsOptional as ComponentIsOptional,
+ Metadata as ComponentMetadata,
+ Sequence as ComponentSequence,
};
-use crate::event::start::Start as StartEvent;
-use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence};
+use crate::entity::CREATE_STATIC_ENTITIES;
use crate::extension::{Collector as ExtensionCollector, Extension};
use crate::lock::{Lock, WriteGuard};
-use crate::query::options::Options as QueryOptions;
+use crate::phase::{Phase, START as START_PHASE};
+use crate::query::options::{Not, Options as QueryOptions, With};
+use crate::relationship::{ChildOf, DependsOn, Relationship};
use crate::sole::Sole;
use crate::stats::Stats;
-use crate::system::{System, TypeErased as TypeErasedSystem};
-use crate::tuple::Reduce as TupleReduce;
+use crate::system::{System, SystemComponent};
use crate::type_name::TypeName;
use crate::uid::{Kind as UidKind, Uid};
@@ -35,6 +34,7 @@ pub mod entity;
pub mod event;
pub mod extension;
pub mod lock;
+pub mod phase;
pub mod query;
pub mod relationship;
pub mod sole;
@@ -57,9 +57,9 @@ pub use crate::query::Query;
#[derive(Debug, Default)]
pub struct World
{
- systems: Vec<TypeErasedSystem>,
data: WorldData,
stop: AtomicBool,
+ is_first_tick: AtomicBool,
}
impl World
@@ -71,6 +71,10 @@ impl World
world.add_sole(Stats::default()).ok();
+ for create_static_entity in CREATE_STATIC_ENTITIES {
+ create_static_entity(&world);
+ }
+
world
}
@@ -80,8 +84,7 @@ impl World
/// Will panic if mutable internal lock cannot be acquired.
pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid
where
- Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>,
- Comps::Out: EventSequence,
+ Comps: ComponentSequence,
{
let entity_uid = Uid::new_unique(UidKind::Entity);
@@ -94,8 +97,7 @@ impl World
#[doc(hidden)]
pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid)
where
- Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>,
- Comps::Out: EventSequence,
+ Comps: ComponentSequence,
{
debug_assert_eq!(entity_uid.kind(), UidKind::Entity);
@@ -113,8 +115,8 @@ impl World
return;
};
- for component_added_event_id in <Comps::Out as EventSequence>::ids().iter() {
- self.emit_event_by_id(*component_added_event_id);
+ for added_event_id in Comps::added_event_ids() {
+ self.emit_event_by_id(added_event_id);
}
}
@@ -129,22 +131,29 @@ impl World
self.data.sole_storage.insert(sole)
}
- pub fn register_system<'this, EventT, SystemImpl>(
+ pub fn register_system<'this, SystemImpl>(
&'this mut self,
- event: EventT,
+ phase_euid: Uid,
system: impl System<'this, SystemImpl>,
- ) where
- EventT: Event,
+ )
{
- self.systems.push(system.into_type_erased());
-
- self.data
- .events
- .entry(EventT::id())
- .or_default()
- .push(self.systems.len() - 1);
+ self.create_entity((
+ SystemComponent { system: system.into_type_erased() },
+ Relationship::<DependsOn, Phase>::new(phase_euid),
+ ));
+ }
- drop(event);
+ pub fn register_observer_system<'this, SystemImpl, Event>(
+ &'this mut self,
+ system: impl System<'this, SystemImpl>,
+ event: Event,
+ ) where
+ Event: Component,
+ {
+ self.create_entity::<(SystemComponent, Event)>((
+ SystemComponent { system: system.into_type_erased() },
+ event,
+ ));
}
/// Adds a extensions.
@@ -158,20 +167,6 @@ impl World
extension.collect(extension_collector);
}
- /// Emits a event, running all systems listening to the event for each compatible
- /// entity.
- ///
- /// # Panics
- /// Will panic if a system has dissapeared.
- pub fn emit<EventT>(&self, event: EventT)
- where
- EventT: Event,
- {
- self.emit_event_by_id(EventT::id());
-
- drop(event);
- }
-
pub fn query<Comps, OptionsT>(&self) -> Query<Comps, OptionsT>
where
Comps: ComponentSequence,
@@ -180,12 +175,121 @@ impl World
Query::new(self)
}
- /// Peforms the actions that have been queued up using [`Actions`].
+ /// Performs a single tick.
+ ///
+ /// # Panics
+ /// Will panic if a internal lock cannot be acquired.
+ pub fn step(&self) -> StepResult
+ {
+ if self.stop.load(Ordering::Relaxed) {
+ return StepResult::Stop;
+ }
+
+ if self
+ .is_first_tick
+ .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
+ .is_ok()
+ {
+ self.query_and_run_systems(*START_PHASE);
+ }
+
+ self.perform_phases();
+
+ self.perform_queued_actions();
+
+ if self.stop.load(Ordering::Relaxed) {
+ return StepResult::Stop;
+ }
+
+ let mut stats_lock = self
+ .data
+ .sole_storage
+ .get::<Stats>()
+ .expect("No stats sole found")
+ .write_nonblock()
+ .expect("Failed to aquire read-write stats sole lock");
+
+ let stats = stats_lock
+ .downcast_mut::<Stats>()
+ .expect("Casting stats sole to Stats type failed");
+
+ stats.current_tick += 1;
+
+ StepResult::Continue
+ }
+
+ /// Starts a loop which calls [`Self::step`] until the world is stopped.
///
/// # Panics
- /// Will panic if a mutable internal lock cannot be acquired.
+ /// Will panic if a internal lock cannot be acquired.
+ pub fn start_loop(&self)
+ {
+ while let StepResult::Continue = self.step() {}
+ }
+
+ fn query_and_run_systems(&self, phase_euid: Uid)
+ {
+ let system_comps_query =
+ self.query::<(SystemComponent, Relationship<DependsOn, Phase>), ()>();
+
+ let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| {
+ phase_rel
+ .target_uids()
+ .any(|target_uid| target_uid == phase_euid)
+ });
+
+ for (system_component, _) in system_iter {
+ // SAFETY: The world lives long enough
+ unsafe {
+ system_component.system.run(self);
+ }
+ }
+ }
+
+ fn perform_child_phases(&self, parent_phase_euid: Uid)
+ {
+ let phase_query = self.query::<(Phase, Relationship<ChildOf, Phase>), ()>();
+
+ for (index, (_, phase_rel)) in phase_query.iter().enumerate() {
+ if !phase_rel
+ .target_uids()
+ .any(|phase_euid| phase_euid == parent_phase_euid)
+ {
+ continue;
+ }
+
+ let phase_euid = phase_query
+ .get_entity_uid(index)
+ .expect("Cannot get current query iteration entity UID");
+
+ self.query_and_run_systems(phase_euid);
+
+ self.perform_child_phases(phase_euid);
+ }
+ }
+
+ fn perform_phases(&self)
+ {
+ let phase_query =
+ self.query::<(Phase,), Not<With<Relationship<ChildOf, Phase>>>>();
+
+ for (index, (_,)) in phase_query.iter().enumerate() {
+ let child_phase_euid = phase_query
+ .get_entity_uid(index)
+ .expect("Cannot get current query iteration entity UID");
+
+ if child_phase_euid == *START_PHASE {
+ continue;
+ }
+
+ self.query_and_run_systems(child_phase_euid);
+
+ self.perform_child_phases(child_phase_euid);
+ }
+ }
+
#[cfg_attr(feature = "debug", tracing::instrument(skip_all))]
- pub fn perform_queued_actions(&self)
+ fn perform_queued_actions(&self)
{
let mut active_action_queue = match *self.data.action_queue.active_queue.borrow()
{
@@ -204,14 +308,9 @@ impl World
for action in active_action_queue.drain(..) {
match action {
- Action::Spawn(components) => {
+ Action::Spawn(components, component_added_event_ids) => {
let mut component_storage_lock = self.lock_component_storage_rw();
- let component_ids = components
- .iter()
- .map(|component| component.self_id())
- .collect::<Vec<_>>();
-
#[allow(unused_variables)]
if let Err(err) = component_storage_lock
.push_entity(Uid::new_unique(UidKind::Entity), components)
@@ -228,20 +327,17 @@ impl World
self.swap_event_queue(&mut has_swapped_active_queue);
}
- for component_id in component_ids {
- self.emit_event_by_id(create_component_added_event_id(
- component_id,
- ));
+ for comp_added_event_id in component_added_event_ids.ids {
+ self.emit_event_by_id(comp_added_event_id);
}
}
- Action::AddComponents(entity_uid, components) => {
+ Action::AddComponents(
+ entity_uid,
+ components,
+ component_added_event_ids,
+ ) => {
let mut component_storage_lock = self.lock_component_storage_rw();
- let component_ids = components
- .iter()
- .map(|component| component.self_id())
- .collect::<Vec<_>>();
-
component_storage_lock
.add_components_to_entity(entity_uid, components);
@@ -251,13 +347,15 @@ impl World
self.swap_event_queue(&mut has_swapped_active_queue);
}
- for component_id in component_ids {
- self.emit_event_by_id(create_component_added_event_id(
- component_id,
- ));
+ for comp_added_event_id in component_added_event_ids.ids {
+ self.emit_event_by_id(comp_added_event_id);
}
}
- Action::RemoveComponents(entity_uid, components_metadata) => {
+ Action::RemoveComponents(
+ entity_uid,
+ components_metadata,
+ component_removed_event_ids,
+ ) => {
let mut component_storage_lock = self.lock_component_storage_rw();
component_storage_lock.remove_components_from_entity(
@@ -273,10 +371,8 @@ impl World
self.swap_event_queue(&mut has_swapped_active_queue);
}
- for component_metadata in components_metadata {
- self.emit_event_by_id(create_component_removed_event_id(
- component_metadata.id,
- ));
+ for comp_removed_event_id in component_removed_event_ids.ids {
+ self.emit_event_by_id(comp_removed_event_id);
}
}
Action::Stop => {
@@ -286,60 +382,18 @@ impl World
}
}
- /// A event loop which runs until a stop is issued with [`Flags::stop`]. Before the
- /// loop begins, [`StartEvent`] is emitted.
- ///
- /// # Panics
- /// Will panic if a internal lock cannot be acquired.
- pub fn event_loop<EventSeq: EventSequence>(&self)
+ fn emit_event_by_id(&self, event_id: Uid)
{
- for create_static_entity in CREATE_STATIC_ENTITIES {
- create_static_entity(self);
- }
-
- self.emit(StartEvent);
-
- let event_seq = EventSeq::ids();
-
- loop {
- for event_id in event_seq.iter() {
- self.emit_event_by_id(*event_id);
- }
-
- self.perform_queued_actions();
-
- if self.stop.load(Ordering::Relaxed) {
- break;
- }
-
- let mut stats_lock = self
- .data
- .sole_storage
- .get::<Stats>()
- .expect("No stats sole found")
- .write_nonblock()
- .expect("Failed to aquire read-write stats sole lock");
-
- let stats = stats_lock
- .downcast_mut::<Stats>()
- .expect("Casting stats sole to Stats type failed");
-
- stats.current_tick += 1;
- }
- }
-
- fn emit_event_by_id(&self, event_id: EventId)
- {
- let Some(system_indices) = self.data.events.get(&event_id) else {
- return;
- };
-
- for system_index in system_indices {
- let system = self.systems.get(*system_index).unwrap();
-
+ for (system,) in self
+ .query::<(SystemComponent,), ()>()
+ .iter_with_extra_comps([ComponentMetadata {
+ id: event_id,
+ is_optional: ComponentIsOptional::No,
+ }])
+ {
// SAFETY: The world lives long enough
unsafe {
- system.run(self);
+ system.system.run(self);
}
}
}
@@ -365,10 +419,19 @@ impl World
}
}
+/// The result of calling [`World::step`].
+pub enum StepResult
+{
+ /// Another step can be made.
+ Continue,
+
+ /// The world have been stopped so no step can be made again.
+ Stop,
+}
+
#[derive(Debug, Default)]
pub struct WorldData
{
- events: HashMap<EventId, Vec<usize>>,
component_storage: Arc<Lock<ComponentStorage>>,
sole_storage: SoleStorage,
action_queue: Arc<ActionQueue>,