diff options
| author | HampusM <hampus@hampusmat.com> | 2026-05-02 18:47:18 +0200 |
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2026-05-02 18:47:18 +0200 |
| commit | 9dfd0a9ef9a54dab5fb88ed9158bd4184212008e (patch) | |
| tree | e40cbfb018c487d78ef1c570258a87a1d2245e98 /ecs | |
| parent | e698922e86c217a261db114ce0392060503f0013 (diff) | |
fix(ecs): make system with local comps not low/high priority in run order
Diffstat (limited to 'ecs')
| -rw-r--r-- | ecs/src/lib.rs | 68 | ||||
| -rw-r--r-- | ecs/src/pair.rs | 4 | ||||
| -rw-r--r-- | ecs/src/phase.rs | 5 | ||||
| -rw-r--r-- | ecs/tests/phase.rs | 36 |
4 files changed, 81 insertions, 32 deletions
diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 7a2178e..32ade13 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -2,6 +2,7 @@ use std::any::{Any, TypeId, type_name}; use std::fmt::Debug; +use std::hint::cold_path; use std::mem::ManuallyDrop; use std::rc::Rc; use std::sync::Arc; @@ -23,8 +24,9 @@ use crate::event::component::Added; use crate::event::{Emitted as EmittedEvent, NewEvents, Submitter as EventSubmitter}; use crate::extension::{Collector as ExtensionCollector, Extension}; use crate::lock::Lock; -use crate::pair::{ChildOf, DependsOn, Pair}; +use crate::pair::{ChildOf, Pair, Wildcard}; use crate::phase::{ + HasSystem as PhaseHasSystem, POST_UPDATE as POST_UPDATE_PHASE, PRE_UPDATE as PRE_UPDATE_PHASE, Phase, @@ -171,15 +173,18 @@ impl World { let (type_erased_system, mut system_callbacks) = system.finish(); - let system_ent_id = self.create_entity(( - SystemComponent { system: type_erased_system }, - Pair::builder() - .relation::<DependsOn>() - .target_id(phase_euid) - .build(), - )); + let system_ent_id = + self.create_entity((SystemComponent { system: type_erased_system },)); system_callbacks.on_created(self, SystemMetadata { ent_id: system_ent_id }); + + self.create_entity_with_uid( + phase_euid, + (Pair::builder() + .relation::<PhaseHasSystem>() + .target_id(system_ent_id) + .build(),), + ); } /// Adds a extensions. @@ -246,7 +251,11 @@ impl World .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) .is_ok() { - self.query_and_run_systems(*START_PHASE); + let Some(start_phase_entity) = self.get_entity(*START_PHASE) else { + unreachable!(); + }; + + self.run_phase_systems(&start_phase_entity); } self.perform_phases(); @@ -346,29 +355,26 @@ impl World ); } - fn query_and_run_systems(&self, phase_euid: Uid) + fn run_phase_systems(&self, phase_entity: &EntityHandle<'_>) { - let system_query = Query::<(&SystemComponent,)>::from_flexible_query( - self.flexible_query( - QueryTerms::<QUERY_MAX_TERM_CNT>::builder() - .with_required([ - SystemComponent::id(), - Pair::builder() - .relation::<DependsOn>() - .target_id(phase_euid) - .build() - .id(), - ]) - .build(), - ), - ); + // The phase's systems are retrieved this way so that the order they are + // run is the same order as they were registered, even if they have local + // components. + for system_entity in phase_entity + .get_wildcard_pair_matches::<PhaseHasSystem, Wildcard>() + .into_iter() + .filter_map(|phase_has_system| phase_has_system.get_target_ent()) + { + let Some(system) = system_entity.get::<SystemComponent>() else { + cold_path(); + continue; + }; - for (system_ent_id, (system_component,)) in system_query.iter_with_euids() { // SAFETY: The world lives long enough unsafe { - system_component + system .system - .run(self, SystemMetadata { ent_id: system_ent_id }); + .run(self, SystemMetadata { ent_id: system_entity.uid() }); } } } @@ -389,14 +395,18 @@ impl World ); for child_phase_entity in &phase_query { - self.query_and_run_systems(child_phase_entity.uid()); + self.run_phase_systems(&child_phase_entity); self.perform_child_phases(child_phase_entity.uid()); } } fn perform_single_phase(&self, phase_entity_id: Uid) { - self.query_and_run_systems(phase_entity_id); + let Some(phase_entity) = self.get_entity(phase_entity_id) else { + unreachable!(); + }; + + self.run_phase_systems(&phase_entity); self.perform_child_phases(phase_entity_id); } diff --git a/ecs/src/pair.rs b/ecs/src/pair.rs index b4bfa57..0d353e3 100644 --- a/ecs/src/pair.rs +++ b/ecs/src/pair.rs @@ -460,13 +460,13 @@ impl<'world, Relation, Target> WithWildcard<'world, Relation, Target> } } -impl<Relation> WithWildcard<'_, Relation, Wildcard> +impl<'world, Relation> WithWildcard<'world, Relation, Wildcard> where Relation: Component, { /// Attempts to retrieve the target as a entity, returning `None` if not found. #[must_use] - pub fn get_target_ent(&self) -> Option<EntityHandle<'_>> + pub fn get_target_ent(&self) -> Option<EntityHandle<'world>> { let archetype = self .world diff --git a/ecs/src/phase.rs b/ecs/src/phase.rs index 39f2a08..e8d9b71 100644 --- a/ecs/src/phase.rs +++ b/ecs/src/phase.rs @@ -1,6 +1,6 @@ use ecs_macros::Component; -use crate::{declare_entity, World}; +use crate::{World, declare_entity}; #[derive(Debug, Default, Clone, Copy, Component)] pub struct Phase; @@ -17,3 +17,6 @@ pub(crate) fn spawn_entities(world: &mut World) world.create_declared_entity(&UPDATE); world.create_declared_entity(&POST_UPDATE); } + +#[derive(Debug, Component)] +pub(crate) struct HasSystem; diff --git a/ecs/tests/phase.rs b/ecs/tests/phase.rs new file mode 100644 index 0000000..af2646b --- /dev/null +++ b/ecs/tests/phase.rs @@ -0,0 +1,36 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +use ecs::component::local::Local; +use ecs::phase::UPDATE; +use ecs::system::Into; +use ecs::system::initializable::Initializable; +use ecs::{Component, World}; + +#[derive(Component)] +struct Thing; + +#[test] +fn system_run_order_correct_when_one_has_local_comp() +{ + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + fn first_system(_thing: Local<Thing>) + { + assert_eq!(COUNTER.fetch_add(1, Ordering::Relaxed), 0); + } + + fn second_system() + { + assert_eq!(COUNTER.fetch_add(1, Ordering::Relaxed), 1); + } + + let mut world = World::new(); + + world.register_system(*UPDATE, first_system.into_system().initialize((Thing,))); + + world.register_system(*UPDATE, second_system); + + world.step(); + + assert_eq!(COUNTER.load(Ordering::Relaxed), 2); +} |
