diff options
author | HampusM <hampus@hampusmat.com> | 2024-12-09 14:05:33 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2024-12-09 14:05:33 +0100 |
commit | dcc40c9205e5f4cf484523f97eb12a561d7b2b22 (patch) | |
tree | 2908b6ca3b2fa390a45b383b91edf7a72c42ef4b /ecs/src/lib.rs | |
parent | 158e36bf6bfcbc2ed0ffc670788ed8c0abd3f282 (diff) |
refactor(ecs): use phases for system ordering
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r-- | ecs/src/lib.rs | 311 |
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>, |