diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 426c045dce28e..4773ad80a54db 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -393,21 +393,14 @@ impl App { } /// Configures a system set in the default schedule, adding the set if it does not exist. + #[deprecated(since = "0.12.0", note = "Please use `configure_sets` instead.")] #[track_caller] pub fn configure_set( &mut self, schedule: impl ScheduleLabel, - set: impl IntoSystemSetConfig, + set: impl IntoSystemSetConfigs, ) -> &mut Self { - let mut schedules = self.world.resource_mut::(); - if let Some(schedule) = schedules.get_mut(&schedule) { - schedule.configure_set(set); - } else { - let mut new_schedule = Schedule::new(schedule); - new_schedule.configure_set(set); - schedules.insert(new_schedule); - } - self + self.configure_sets(schedule, set) } /// Configures a collection of system sets in the default schedule, adding any sets that do not exist. diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index 3b3c8de10a5e9..071042235b7b5 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -71,7 +71,7 @@ pub struct AudioPlugin { impl Plugin for AudioPlugin { fn build(&self, app: &mut App) { app.insert_resource(self.global_volume) - .configure_set(PostUpdate, AudioPlaySet.run_if(audio_output_available)) + .configure_sets(PostUpdate, AudioPlaySet.run_if(audio_output_available)) .init_resource::(); #[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))] diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index b9b8718094abe..ebc8b15fbb990 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -45,8 +45,8 @@ pub mod prelude { removal_detection::RemovedComponents, schedule::{ apply_deferred, apply_state_transition, common_conditions::*, Condition, - IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfig, IntoSystemSetConfigs, NextState, - OnEnter, OnExit, OnTransition, Schedule, Schedules, State, States, SystemSet, + IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfigs, NextState, OnEnter, OnExit, + OnTransition, Schedule, Schedules, State, States, SystemSet, }, system::{ Commands, Deferred, In, IntoSystem, Local, NonSend, NonSendMut, ParallelCommands, diff --git a/crates/bevy_ecs/src/schedule/config.rs b/crates/bevy_ecs/src/schedule/config.rs index 5ef4428ecc948..76ddc7fbafa32 100644 --- a/crates/bevy_ecs/src/schedule/config.rs +++ b/crates/bevy_ecs/src/schedule/config.rs @@ -47,21 +47,24 @@ impl IntoSystemConfigs<()> for BoxedSystem<(), ()> { } } -/// Stores configuration for a single system. -pub struct SystemConfig { - pub(crate) system: BoxedSystem, +/// Stores configuration for a single generic node. +pub struct NodeConfig { + pub(crate) node: T, pub(crate) graph_info: GraphInfo, pub(crate) conditions: Vec, } -/// A collection of [`SystemConfig`]. -pub enum SystemConfigs { - /// Configuration for a single system. - SystemConfig(SystemConfig), - /// Configuration for a tuple of nested `SystemConfigs` instances. +/// Stores configuration for a single system. +pub type SystemConfig = NodeConfig; + +/// A collections of generic [`NodeConfig`]s. +pub enum NodeConfigs { + /// Configuratin for a single node. + NodeConfig(NodeConfig), + /// Configuration for a tuple of nested `Configs` instances. Configs { /// Configuration for each element of the tuple. - configs: Vec, + configs: Vec>, /// Run conditions applied to everything in the tuple. collective_conditions: Vec, /// If `true`, adds `before -> after` ordering constraints between the successive elements. @@ -69,12 +72,15 @@ pub enum SystemConfigs { }, } +/// A collection of [`SystemConfig`]. +pub type SystemConfigs = NodeConfigs; + impl SystemConfigs { fn new_system(system: BoxedSystem) -> Self { // include system in its default sets let sets = system.default_system_sets().into_iter().collect(); - Self::SystemConfig(SystemConfig { - system, + Self::NodeConfig(SystemConfig { + node: system, graph_info: GraphInfo { sets, ..Default::default() @@ -82,14 +88,16 @@ impl SystemConfigs { conditions: Vec::new(), }) } +} +impl NodeConfigs { /// Adds a new boxed system set to the systems. pub fn in_set_dyn(&mut self, set: BoxedSystemSet) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { config.graph_info.sets.push(set); } - SystemConfigs::Configs { configs, .. } => { + Self::Configs { configs, .. } => { for config in configs { config.in_set_dyn(set.dyn_clone()); } @@ -99,13 +107,13 @@ impl SystemConfigs { fn before_inner(&mut self, set: BoxedSystemSet) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { config .graph_info .dependencies .push(Dependency::new(DependencyKind::Before, set)); } - SystemConfigs::Configs { configs, .. } => { + Self::Configs { configs, .. } => { for config in configs { config.before_inner(set.dyn_clone()); } @@ -115,13 +123,13 @@ impl SystemConfigs { fn after_inner(&mut self, set: BoxedSystemSet) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { config .graph_info .dependencies .push(Dependency::new(DependencyKind::After, set)); } - SystemConfigs::Configs { configs, .. } => { + Self::Configs { configs, .. } => { for config in configs { config.after_inner(set.dyn_clone()); } @@ -131,10 +139,10 @@ impl SystemConfigs { fn distributive_run_if_inner(&mut self, condition: impl Condition + Clone) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { config.conditions.push(new_condition(condition)); } - SystemConfigs::Configs { configs, .. } => { + Self::Configs { configs, .. } => { for config in configs { config.distributive_run_if_inner(condition.clone()); } @@ -144,10 +152,10 @@ impl SystemConfigs { fn ambiguous_with_inner(&mut self, set: BoxedSystemSet) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { ambiguous_with(&mut config.graph_info, set); } - SystemConfigs::Configs { configs, .. } => { + Self::Configs { configs, .. } => { for config in configs { config.ambiguous_with_inner(set.dyn_clone()); } @@ -157,10 +165,10 @@ impl SystemConfigs { fn ambiguous_with_all_inner(&mut self) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { config.graph_info.ambiguous_with = Ambiguity::IgnoreAll; } - SystemConfigs::Configs { configs, .. } => { + Self::Configs { configs, .. } => { for config in configs { config.ambiguous_with_all_inner(); } @@ -174,10 +182,10 @@ impl SystemConfigs { /// Prefer `run_if` for run conditions whose type is known at compile time. pub fn run_if_dyn(&mut self, condition: BoxedCondition) { match self { - SystemConfigs::SystemConfig(config) => { + Self::NodeConfig(config) => { config.conditions.push(condition); } - SystemConfigs::Configs { + Self::Configs { collective_conditions, .. } => { @@ -185,6 +193,16 @@ impl SystemConfigs { } } } + + fn chain_inner(mut self) -> Self { + match &mut self { + Self::NodeConfig(_) => { /* no op */ } + Self::Configs { chained, .. } => { + *chained = true; + } + } + self + } } /// Types that can convert into a [`SystemConfigs`]. @@ -239,7 +257,7 @@ where /// that all evaluations in a single schedule run will yield the same result. If another /// system is run inbetween two evaluations it could cause the result of the condition to change. /// - /// Use [`run_if`](IntoSystemSetConfig::run_if) on a [`SystemSet`] if you want to make sure + /// Use [`run_if`](IntoSystemSetConfigs::run_if) on a [`SystemSet`] if you want to make sure /// that either all or none of the systems are run, or you don't want to evaluate the run /// condition for each contained system separately. fn distributive_run_if(self, condition: impl Condition + Clone) -> SystemConfigs { @@ -265,7 +283,7 @@ where /// # #[derive(SystemSet, Debug, Eq, PartialEq, Hash, Clone, Copy)] /// # struct C; /// schedule.add_systems((a, b).run_if(condition)); - /// schedule.add_systems((a, b).in_set(C)).configure_set(C.run_if(condition)); + /// schedule.add_systems((a, b).in_set(C)).configure_sets(C.run_if(condition)); /// ``` /// /// # Note @@ -350,14 +368,8 @@ impl IntoSystemConfigs<()> for SystemConfigs { self } - fn chain(mut self) -> Self { - match &mut self { - SystemConfigs::SystemConfig(_) => { /* no op */ } - SystemConfigs::Configs { chained, .. } => { - *chained = true; - } - } - self + fn chain(self) -> Self { + self.chain_inner() } } @@ -386,15 +398,11 @@ macro_rules! impl_system_collection { all_tuples!(impl_system_collection, 1, 20, P, S); /// A [`SystemSet`] with scheduling metadata. -pub struct SystemSetConfig { - pub(super) set: BoxedSystemSet, - pub(super) graph_info: GraphInfo, - pub(super) conditions: Vec, -} +pub type SystemSetConfig = NodeConfig; impl SystemSetConfig { #[track_caller] - fn new(set: BoxedSystemSet) -> Self { + pub(super) fn new(set: BoxedSystemSet) -> Self { // system type sets are automatically populated // to avoid unintentionally broad changes, they cannot be configured assert!( @@ -403,118 +411,15 @@ impl SystemSetConfig { ); Self { - set, + node: set, graph_info: GraphInfo::default(), conditions: Vec::new(), } } } -/// Types that can be converted into a [`SystemSetConfig`]. -/// -/// This has been implemented for all types that implement [`SystemSet`] and boxed trait objects. -pub trait IntoSystemSetConfig: Sized { - /// Convert into a [`SystemSetConfig`]. - #[doc(hidden)] - fn into_config(self) -> SystemSetConfig; - /// Add to the provided `set`. - #[track_caller] - fn in_set(self, set: impl SystemSet) -> SystemSetConfig { - self.into_config().in_set(set) - } - /// Run before all systems in `set`. - fn before(self, set: impl IntoSystemSet) -> SystemSetConfig { - self.into_config().before(set) - } - /// Run after all systems in `set`. - fn after(self, set: impl IntoSystemSet) -> SystemSetConfig { - self.into_config().after(set) - } - /// Run the systems in this set only if the [`Condition`] is `true`. - /// - /// The `Condition` will be evaluated at most once (per schedule run), - /// the first time a system in this set prepares to run. - fn run_if(self, condition: impl Condition) -> SystemSetConfig { - self.into_config().run_if(condition) - } - /// Suppress warnings and errors that would result from systems in this set having ambiguities - /// (conflicting access but indeterminate order) with systems in `set`. - fn ambiguous_with(self, set: impl IntoSystemSet) -> SystemSetConfig { - self.into_config().ambiguous_with(set) - } - /// Suppress warnings and errors that would result from systems in this set having ambiguities - /// (conflicting access but indeterminate order) with any other system. - fn ambiguous_with_all(self) -> SystemSetConfig { - self.into_config().ambiguous_with_all() - } -} - -impl IntoSystemSetConfig for S { - #[track_caller] - fn into_config(self) -> SystemSetConfig { - SystemSetConfig::new(Box::new(self)) - } -} - -impl IntoSystemSetConfig for BoxedSystemSet { - fn into_config(self) -> SystemSetConfig { - SystemSetConfig::new(self) - } -} - -impl IntoSystemSetConfig for SystemSetConfig { - fn into_config(self) -> Self { - self - } - - #[track_caller] - fn in_set(mut self, set: impl SystemSet) -> Self { - assert!( - set.system_type().is_none(), - "adding arbitrary systems to a system type set is not allowed" - ); - self.graph_info.sets.push(Box::new(set)); - self - } - - fn before(mut self, set: impl IntoSystemSet) -> Self { - self.graph_info.dependencies.push(Dependency::new( - DependencyKind::Before, - Box::new(set.into_system_set()), - )); - self - } - - fn after(mut self, set: impl IntoSystemSet) -> Self { - self.graph_info.dependencies.push(Dependency::new( - DependencyKind::After, - Box::new(set.into_system_set()), - )); - self - } - - fn run_if(mut self, condition: impl Condition) -> Self { - self.conditions.push(new_condition(condition)); - self - } - - fn ambiguous_with(mut self, set: impl IntoSystemSet) -> Self { - ambiguous_with(&mut self.graph_info, Box::new(set.into_system_set())); - self - } - - fn ambiguous_with_all(mut self) -> Self { - self.graph_info.ambiguous_with = Ambiguity::IgnoreAll; - self - } -} - /// A collection of [`SystemSetConfig`]. -pub struct SystemSetConfigs { - pub(super) sets: Vec, - /// If `true`, adds `before -> after` ordering constraints between the successive elements. - pub(super) chained: bool, -} +pub type SystemSetConfigs = NodeConfigs; /// Types that can convert into a [`SystemSetConfigs`]. pub trait IntoSystemSetConfigs @@ -541,6 +446,14 @@ where self.into_configs().after(set) } + /// Run the systems in this set(s) only if the [`Condition`] is `true`. + /// + /// The `Condition` will be evaluated at most once (per schedule run), + /// the first time a system in this set(s) prepares to run. + fn run_if(self, condition: impl Condition) -> SystemSetConfigs { + self.into_configs().run_if(condition) + } + /// Suppress warnings and errors that would result from systems in these sets having ambiguities /// (conflicting access but indeterminate order) with systems in `set`. fn ambiguous_with(self, set: impl IntoSystemSet) -> SystemSetConfigs { @@ -572,69 +485,77 @@ impl IntoSystemSetConfigs for SystemSetConfigs { set.system_type().is_none(), "adding arbitrary systems to a system type set is not allowed" ); - for config in &mut self.sets { - config.graph_info.sets.push(set.dyn_clone()); - } + self.in_set_dyn(set.dyn_clone()); self } fn before(mut self, set: impl IntoSystemSet) -> Self { let set = set.into_system_set(); - for config in &mut self.sets { - config - .graph_info - .dependencies - .push(Dependency::new(DependencyKind::Before, set.dyn_clone())); - } + self.before_inner(set.dyn_clone()); self } fn after(mut self, set: impl IntoSystemSet) -> Self { let set = set.into_system_set(); - for config in &mut self.sets { - config - .graph_info - .dependencies - .push(Dependency::new(DependencyKind::After, set.dyn_clone())); - } + self.after_inner(set.dyn_clone()); + + self + } + + fn run_if(mut self, condition: impl Condition) -> SystemSetConfigs { + self.run_if_dyn(new_condition(condition)); self } fn ambiguous_with(mut self, set: impl IntoSystemSet) -> Self { let set = set.into_system_set(); - for config in &mut self.sets { - ambiguous_with(&mut config.graph_info, set.dyn_clone()); - } + self.ambiguous_with_inner(set.dyn_clone()); self } fn ambiguous_with_all(mut self) -> Self { - for config in &mut self.sets { - config.graph_info.ambiguous_with = Ambiguity::IgnoreAll; - } + self.ambiguous_with_all_inner(); self } - fn chain(mut self) -> Self { - self.chained = true; - self + fn chain(self) -> Self { + self.chain_inner() + } +} + +impl IntoSystemSetConfigs for S { + fn into_configs(self) -> SystemSetConfigs { + SystemSetConfigs::NodeConfig(SystemSetConfig::new(Box::new(self))) + } +} + +impl IntoSystemSetConfigs for BoxedSystemSet { + fn into_configs(self) -> SystemSetConfigs { + SystemSetConfigs::NodeConfig(SystemSetConfig::new(self)) + } +} + +impl IntoSystemSetConfigs for SystemSetConfig { + fn into_configs(self) -> SystemSetConfigs { + SystemSetConfigs::NodeConfig(self) } } macro_rules! impl_system_set_collection { ($($set: ident),*) => { - impl<$($set: IntoSystemSetConfig),*> IntoSystemSetConfigs for ($($set,)*) + impl<$($set: IntoSystemSetConfigs),*> IntoSystemSetConfigs for ($($set,)*) { #[allow(non_snake_case)] fn into_configs(self) -> SystemSetConfigs { let ($($set,)*) = self; - SystemSetConfigs { - sets: vec![$($set.into_config(),)*], + SystemSetConfigs::Configs { + configs: vec![$($set.into_configs(),)*], + collective_conditions: Vec::new(), chained: false, } } @@ -642,4 +563,4 @@ macro_rules! impl_system_set_collection { } } -all_tuples!(impl_system_set_collection, 0, 15, S); +all_tuples!(impl_system_set_collection, 1, 20, S); diff --git a/crates/bevy_ecs/src/schedule/mod.rs b/crates/bevy_ecs/src/schedule/mod.rs index 88671df5c3575..1d58a7d59fe72 100644 --- a/crates/bevy_ecs/src/schedule/mod.rs +++ b/crates/bevy_ecs/src/schedule/mod.rs @@ -25,7 +25,7 @@ mod tests { use std::sync::atomic::{AtomicU32, Ordering}; pub use crate as bevy_ecs; - pub use crate::schedule::{IntoSystemSetConfig, Schedule, SystemSet}; + pub use crate::schedule::{IntoSystemSetConfigs, Schedule, SystemSet}; pub use crate::system::{Res, ResMut}; pub use crate::{prelude::World, system::Resource}; @@ -145,7 +145,7 @@ mod tests { assert_eq!(world.resource::().0, vec![]); // modify the schedule after it's been initialized and test ordering with sets - schedule.configure_set(TestSet::A.after(named_system)); + schedule.configure_sets(TestSet::A.after(named_system)); schedule.add_systems(( make_function_system(3) .before(TestSet::A) @@ -339,13 +339,13 @@ mod tests { world.init_resource::(); - schedule.configure_set(TestSet::A.run_if(|| false).run_if(|| false)); + schedule.configure_sets(TestSet::A.run_if(|| false).run_if(|| false)); schedule.add_systems(counting_system.in_set(TestSet::A)); - schedule.configure_set(TestSet::B.run_if(|| true).run_if(|| false)); + schedule.configure_sets(TestSet::B.run_if(|| true).run_if(|| false)); schedule.add_systems(counting_system.in_set(TestSet::B)); - schedule.configure_set(TestSet::C.run_if(|| false).run_if(|| true)); + schedule.configure_sets(TestSet::C.run_if(|| false).run_if(|| true)); schedule.add_systems(counting_system.in_set(TestSet::C)); - schedule.configure_set(TestSet::D.run_if(|| true).run_if(|| true)); + schedule.configure_sets(TestSet::D.run_if(|| true).run_if(|| true)); schedule.add_systems(counting_system.in_set(TestSet::D)); schedule.run(&mut world); @@ -359,13 +359,13 @@ mod tests { world.init_resource::(); - schedule.configure_set(TestSet::A.run_if(|| false)); + schedule.configure_sets(TestSet::A.run_if(|| false)); schedule.add_systems(counting_system.in_set(TestSet::A).run_if(|| false)); - schedule.configure_set(TestSet::B.run_if(|| true)); + schedule.configure_sets(TestSet::B.run_if(|| true)); schedule.add_systems(counting_system.in_set(TestSet::B).run_if(|| false)); - schedule.configure_set(TestSet::C.run_if(|| false)); + schedule.configure_sets(TestSet::C.run_if(|| false)); schedule.add_systems(counting_system.in_set(TestSet::C).run_if(|| true)); - schedule.configure_set(TestSet::D.run_if(|| true)); + schedule.configure_sets(TestSet::D.run_if(|| true)); schedule.add_systems(counting_system.in_set(TestSet::D).run_if(|| true)); schedule.run(&mut world); @@ -431,7 +431,7 @@ mod tests { world.init_resource::(); let mut schedule = Schedule::default(); - schedule.configure_set( + schedule.configure_sets( TestSet::A .run_if(|res1: Res| res1.is_changed()) .run_if(|res2: Res| res2.is_changed()), @@ -482,7 +482,7 @@ mod tests { let mut schedule = Schedule::default(); schedule - .configure_set(TestSet::A.run_if(|res1: Res| res1.is_changed())); + .configure_sets(TestSet::A.run_if(|res1: Res| res1.is_changed())); schedule.add_systems( counting_system @@ -529,7 +529,7 @@ mod tests { #[should_panic] fn dependency_loop() { let mut schedule = Schedule::default(); - schedule.configure_set(TestSet::X.after(TestSet::X)); + schedule.configure_sets(TestSet::X.after(TestSet::X)); } #[test] @@ -537,8 +537,8 @@ mod tests { let mut world = World::new(); let mut schedule = Schedule::default(); - schedule.configure_set(TestSet::A.after(TestSet::B)); - schedule.configure_set(TestSet::B.after(TestSet::A)); + schedule.configure_sets(TestSet::A.after(TestSet::B)); + schedule.configure_sets(TestSet::B.after(TestSet::A)); let result = schedule.initialize(&mut world); assert!(matches!( @@ -564,7 +564,7 @@ mod tests { #[should_panic] fn hierarchy_loop() { let mut schedule = Schedule::default(); - schedule.configure_set(TestSet::X.in_set(TestSet::X)); + schedule.configure_sets(TestSet::X.in_set(TestSet::X)); } #[test] @@ -572,8 +572,8 @@ mod tests { let mut world = World::new(); let mut schedule = Schedule::default(); - schedule.configure_set(TestSet::A.in_set(TestSet::B)); - schedule.configure_set(TestSet::B.in_set(TestSet::A)); + schedule.configure_sets(TestSet::A.in_set(TestSet::B)); + schedule.configure_sets(TestSet::B.in_set(TestSet::A)); let result = schedule.initialize(&mut world); assert!(matches!(result, Err(ScheduleBuildError::HierarchyCycle(_)))); @@ -625,7 +625,7 @@ mod tests { fn configure_system_type_set() { fn foo() {} let mut schedule = Schedule::default(); - schedule.configure_set(foo.into_system_set()); + schedule.configure_sets(foo.into_system_set()); } #[test] @@ -639,13 +639,13 @@ mod tests { }); // Add `A`. - schedule.configure_set(TestSet::A); + schedule.configure_sets(TestSet::A); // Add `B` as child of `A`. - schedule.configure_set(TestSet::B.in_set(TestSet::A)); + schedule.configure_sets(TestSet::B.in_set(TestSet::A)); // Add `X` as child of both `A` and `B`. - schedule.configure_set(TestSet::X.in_set(TestSet::A).in_set(TestSet::B)); + schedule.configure_sets(TestSet::X.in_set(TestSet::A).in_set(TestSet::B)); // `X` cannot be the `A`'s child and grandchild at the same time. let result = schedule.initialize(&mut world); @@ -661,8 +661,8 @@ mod tests { let mut schedule = Schedule::default(); // Add `B` and give it both kinds of relationships with `A`. - schedule.configure_set(TestSet::B.in_set(TestSet::A)); - schedule.configure_set(TestSet::B.after(TestSet::A)); + schedule.configure_sets(TestSet::B.in_set(TestSet::A)); + schedule.configure_sets(TestSet::B.after(TestSet::A)); let result = schedule.initialize(&mut world); assert!(matches!( result, diff --git a/crates/bevy_ecs/src/schedule/schedule.rs b/crates/bevy_ecs/src/schedule/schedule.rs index f012cef7ffd3c..a70df83c011bc 100644 --- a/crates/bevy_ecs/src/schedule/schedule.rs +++ b/crates/bevy_ecs/src/schedule/schedule.rs @@ -192,15 +192,15 @@ impl Schedule { /// Add a collection of systems to the schedule. pub fn add_systems(&mut self, systems: impl IntoSystemConfigs) -> &mut Self { - self.graph.add_systems_inner(systems.into_configs(), false); + self.graph.process_configs(systems.into_configs(), false); self } /// Configures a system set in this schedule, adding it if it does not exist. + #[deprecated(since = "0.12.0", note = "Please use `configure_sets` instead.")] #[track_caller] - pub fn configure_set(&mut self, set: impl IntoSystemSetConfig) -> &mut Self { - self.graph.configure_set(set); - self + pub fn configure_set(&mut self, set: impl IntoSystemSetConfigs) -> &mut Self { + self.configure_sets(set) } /// Configures a collection of system sets in this schedule, adding them if they does not exist. @@ -522,30 +522,36 @@ impl ScheduleGraph { &self.conflicting_systems } - /// Adds the systems to the graph. Returns a vector of all node ids contained the nested `SystemConfigs` - /// if `ancestor_chained` is true. Also returns true if "densely chained", meaning that all nested items - /// are linearly chained in the order they are defined - fn add_systems_inner( + /// Adds the config nodes to the graph. + /// + /// `collect_nodes` controls whether the `NodeId`s of the processed config nodes are stored in the returned [`ProcessConfigsResult`]. + /// `process_config` is the function which processes each individual config node and returns a corresponding `NodeId`. + /// + /// The fields on the returned [`ProcessConfigsResult`] are: + /// - `nodes`: a vector of all node ids contained in the nested `NodeConfigs` + /// - `densely_chained`: a boolean that is true if all nested nodes are linearly chained (with successive `after` orderings) in the order they are defined + #[track_caller] + fn process_configs( &mut self, - configs: SystemConfigs, - ancestor_chained: bool, - ) -> AddSystemsInnerResult { + configs: NodeConfigs, + collect_nodes: bool, + ) -> ProcessConfigsResult { match configs { - SystemConfigs::SystemConfig(config) => { - let node_id = self.add_system_inner(config).unwrap(); - if ancestor_chained { - AddSystemsInnerResult { + NodeConfigs::NodeConfig(config) => { + let node_id = T::process_config(self, config); + if collect_nodes { + ProcessConfigsResult { densely_chained: true, nodes: vec![node_id], } } else { - AddSystemsInnerResult { + ProcessConfigsResult { densely_chained: true, nodes: Vec::new(), } } } - SystemConfigs::Configs { + NodeConfigs::Configs { mut configs, collective_conditions, chained, @@ -557,9 +563,9 @@ impl ScheduleGraph { for config in &mut configs { config.in_set_dyn(set.dyn_clone()); } - let mut set_config = set.into_config(); + let mut set_config = SystemSetConfig::new(set.dyn_clone()); set_config.conditions.extend(collective_conditions); - self.configure_set(set_config); + self.configure_set_inner(set_config).unwrap(); } else { for condition in collective_conditions { configs[0].run_if_dyn(condition); @@ -571,15 +577,15 @@ impl ScheduleGraph { let mut densely_chained = true; if chained { let Some(prev) = config_iter.next() else { - return AddSystemsInnerResult { + return ProcessConfigsResult { nodes: Vec::new(), densely_chained: true, }; }; - let mut previous_result = self.add_systems_inner(prev, true); + let mut previous_result = self.process_configs(prev, true); densely_chained = previous_result.densely_chained; for current in config_iter { - let current_result = self.add_systems_inner(current, true); + let current_result = self.process_configs(current, true); densely_chained = densely_chained && current_result.densely_chained; match ( previous_result.densely_chained, @@ -635,7 +641,7 @@ impl ScheduleGraph { } } - if ancestor_chained { + if collect_nodes { nodes_in_scope.append(&mut previous_result.nodes); } @@ -643,14 +649,14 @@ impl ScheduleGraph { } // ensure the last config's nodes are added - if ancestor_chained { + if collect_nodes { nodes_in_scope.append(&mut previous_result.nodes); } } else { for config in config_iter { - let result = self.add_systems_inner(config, ancestor_chained); + let result = self.process_configs(config, collect_nodes); densely_chained = densely_chained && result.densely_chained; - if ancestor_chained { + if collect_nodes { nodes_in_scope.extend(result.nodes); } } @@ -661,7 +667,7 @@ impl ScheduleGraph { } } - AddSystemsInnerResult { + ProcessConfigsResult { nodes: nodes_in_scope, densely_chained, } @@ -677,7 +683,7 @@ impl ScheduleGraph { // system init has to be deferred (need `&mut World`) self.uninit.push((id, 0)); - self.systems.push(SystemNode::new(config.system)); + self.systems.push(SystemNode::new(config.node)); self.system_conditions.push(config.conditions); Ok(id) @@ -685,46 +691,15 @@ impl ScheduleGraph { #[track_caller] fn configure_sets(&mut self, sets: impl IntoSystemSetConfigs) { - let SystemSetConfigs { sets, chained } = sets.into_configs(); - let mut set_iter = sets.into_iter(); - if chained { - let Some(prev) = set_iter.next() else { return }; - let mut prev_id = self.configure_set_inner(prev).unwrap(); - for next in set_iter { - let next_id = self.configure_set_inner(next).unwrap(); - self.dependency.graph.add_edge(prev_id, next_id, ()); - prev_id = next_id; - } - } else { - for set in set_iter { - if let Err(e) = self.configure_set_inner(set) { - // using `unwrap_or_else(panic!)` led to the error being reported - // from this line instead of in the user code - panic!("{e}"); - }; - } - } - } - - #[track_caller] - fn configure_set(&mut self, set: impl IntoSystemSetConfig) { - if let Err(e) = self.configure_set_inner(set) { - // using `unwrap_or_else(panic!)` led to the error being reported - // from this line instead of in the user code - panic!("{e}"); - }; + self.process_configs(sets.into_configs(), false); } - #[track_caller] - fn configure_set_inner( - &mut self, - set: impl IntoSystemSetConfig, - ) -> Result { + fn configure_set_inner(&mut self, set: SystemSetConfig) -> Result { let SystemSetConfig { - set, + node: set, graph_info, mut conditions, - } = set.into_config(); + } = set; let id = match self.system_set_ids.get(&set) { Some(&id) => id, @@ -1240,14 +1215,35 @@ impl ScheduleGraph { } } -/// Values returned by `ScheduleGraph::add_systems_inner` -struct AddSystemsInnerResult { - /// All nodes contained inside this add_systems_inner call's SystemConfigs hierarchy +/// Values returned by [`ScheduleGraph::process_configs`] +struct ProcessConfigsResult { + /// All nodes contained inside this process_configs call's [`NodeConfigs`] hierarchy, + /// if `ancestor_chained` is true nodes: Vec, - /// True if and only if all nodes are "densely chained" + /// True if and only if all nodes are "densely chained", meaning that all nested nodes + /// are linearly chained (as if `after` system ordering had been applied between each node) + /// in the order they are defined densely_chained: bool, } +/// Trait used by [`ScheduleGraph::process_configs`] to process a single [`NodeConfig`]. +trait ProcessNodeConfig: Sized { + /// Process a single [`NodeConfig`]. + fn process_config(schedule_graph: &mut ScheduleGraph, config: NodeConfig) -> NodeId; +} + +impl ProcessNodeConfig for BoxedSystem { + fn process_config(schedule_graph: &mut ScheduleGraph, config: NodeConfig) -> NodeId { + schedule_graph.add_system_inner(config).unwrap() + } +} + +impl ProcessNodeConfig for BoxedSystemSet { + fn process_config(schedule_graph: &mut ScheduleGraph, config: NodeConfig) -> NodeId { + schedule_graph.configure_set_inner(config).unwrap() + } +} + /// Used to select the appropriate reporting function. enum ReportCycles { Hierarchy, @@ -1718,7 +1714,7 @@ impl ScheduleBuildSettings { mod tests { use crate::{ self as bevy_ecs, - schedule::{IntoSystemConfigs, IntoSystemSetConfig, Schedule, SystemSet}, + schedule::{IntoSystemConfigs, IntoSystemSetConfigs, Schedule, SystemSet}, world::World, }; @@ -1731,7 +1727,7 @@ mod tests { let mut world = World::new(); let mut schedule = Schedule::default(); - schedule.configure_set(Set.run_if(|| false)); + schedule.configure_sets(Set.run_if(|| false)); schedule.add_systems( (|| panic!("This system must not run")) .ambiguous_with(|| ()) diff --git a/crates/bevy_ecs/src/schedule/set.rs b/crates/bevy_ecs/src/schedule/set.rs index bdbc16ff7d905..aa7ef806155f8 100644 --- a/crates/bevy_ecs/src/schedule/set.rs +++ b/crates/bevy_ecs/src/schedule/set.rs @@ -110,7 +110,8 @@ impl SystemSet for SystemTypeSet { } /// A [`SystemSet`] implicitly created when using -/// [`Schedule::add_systems`](super::Schedule::add_systems). +/// [`Schedule::add_systems`](super::Schedule::add_systems) or +/// [`Schedule::configure_sets`](super::Schedule::configure_sets). #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct AnonymousSet(usize); diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index fd4b3027c4b90..dab200f032bb5 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -46,7 +46,7 @@ //! You can **explicitly order** systems: //! //! - by calling the `.before(this_system)` or `.after(that_system)` methods when adding them to your schedule -//! - by adding them to a [`SystemSet`], and then using `.configure_set(ThisSet.before(ThatSet))` syntax to configure many systems at once +//! - by adding them to a [`SystemSet`], and then using `.configure_sets(ThisSet.before(ThatSet))` syntax to configure many systems at once //! - through the use of `.add_systems((system_a, system_b, system_c).chain())` //! //! [`SystemSet`]: crate::schedule::SystemSet diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 473f75fc3aba4..1b0652e104edf 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -161,7 +161,7 @@ impl Render { ); schedule.configure_sets((ExtractCommands, PrepareAssets, Prepare).chain()); - schedule.configure_set( + schedule.configure_sets( QueueMeshes .in_set(RenderSet::Queue) .after(prepare_assets::), diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 538b6a03ee7e4..ffa86031c8ab2 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -224,7 +224,7 @@ impl Plugin for VisibilityPlugin { app // We add an AABB component in CalculateBounds, which must be ready on the same frame. .add_systems(PostUpdate, apply_deferred.in_set(CalculateBoundsFlush)) - .configure_set(PostUpdate, CalculateBoundsFlush.after(CalculateBounds)) + .configure_sets(PostUpdate, CalculateBoundsFlush.after(CalculateBounds)) .add_systems( PostUpdate, ( diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 50444acd8b089..d4cec7b8fcf96 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -102,7 +102,7 @@ impl Plugin for TransformPlugin { app.register_type::() .register_type::() .add_plugins(ValidParentCheckPlugin::::default()) - .configure_set( + .configure_sets( PostStartup, PropagateTransformsSet.in_set(TransformSystem::TransformPropagate), ) @@ -119,7 +119,7 @@ impl Plugin for TransformPlugin { propagate_transforms.in_set(PropagateTransformsSet), ), ) - .configure_set( + .configure_sets( PostUpdate, PropagateTransformsSet.in_set(TransformSystem::TransformPropagate), )