Skip to content

Commit 67a89e9

Browse files
committed
Add distributive_run_if to IntoSystemConfigs (#7724)
# Objective - Fixes #7659. ## Solution - This PR extracted the `distributive_run_if` part of #7676, because it does not require the controversial introduction of anonymous system sets. - The distinctive name should make the user aware about the differences between `IntoSystemConfig::run_if` and `IntoSystemConfigs::distributive_run_if`. - The documentation explains in detail the consequences of using the API and possible pit falls when using it. - A test demonstrates the possibility of changing the condition result, resulting in some of the systems not being run. --- ## Changelog ### Added - Add `distributive_run_if` to `IntoSystemConfigs` to enable adding a run condition to each system when using `add_systems`.
1 parent 609ad5a commit 67a89e9

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

crates/bevy_ecs/src/schedule/config.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,40 @@ where
520520
self.into_configs().after(set)
521521
}
522522

523+
/// Add a run condition to each contained system.
524+
///
525+
/// Each system will receive its own clone of the [`Condition`] and will only run
526+
/// if the `Condition` is true.
527+
///
528+
/// Each individual condition will be evaluated at most once (per schedule run),
529+
/// right before the corresponding system prepares to run.
530+
///
531+
/// This is equivalent to calling [`run_if`](IntoSystemConfig::run_if) on each individual
532+
/// system, as shown below:
533+
///
534+
/// ```
535+
/// # use bevy_ecs::prelude::*;
536+
/// # let mut app = Schedule::new();
537+
/// # fn a() {}
538+
/// # fn b() {}
539+
/// # fn condition() -> bool { true }
540+
/// app.add_systems((a, b).distributive_run_if(condition));
541+
/// app.add_systems((a.run_if(condition), b.run_if(condition)));
542+
/// ```
543+
///
544+
/// # Note
545+
///
546+
/// Because the conditions are evaluated separately for each system, there is no guarantee
547+
/// that all evaluations in a single schedule run will yield the same result. If another
548+
/// system is run inbetween two evaluations it could cause the result of the condition to change.
549+
///
550+
/// Use [`run_if`](IntoSystemSetConfig::run_if) on a [`SystemSet`] if you want to make sure
551+
/// that either all or none of the systems are run, or you don't want to evaluate the run
552+
/// condition for each contained system separately.
553+
fn distributive_run_if<P>(self, condition: impl Condition<P> + Clone) -> SystemConfigs {
554+
self.into_configs().distributive_run_if(condition)
555+
}
556+
523557
/// Suppress warnings and errors that would result from these systems having ambiguities
524558
/// (conflicting access but indeterminate order) with systems in `set`.
525559
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
@@ -603,6 +637,14 @@ impl IntoSystemConfigs<()> for SystemConfigs {
603637
self
604638
}
605639

640+
fn distributive_run_if<P>(mut self, condition: impl Condition<P> + Clone) -> SystemConfigs {
641+
for config in &mut self.systems {
642+
config.conditions.push(new_condition(condition.clone()));
643+
}
644+
645+
self
646+
}
647+
606648
fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
607649
let set = set.into_system_set();
608650
for config in &mut self.systems {

crates/bevy_ecs/src/schedule/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,32 @@ mod tests {
222222
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
223223
}
224224

225+
#[test]
226+
fn systems_with_distributive_condition() {
227+
let mut world = World::default();
228+
let mut schedule = Schedule::default();
229+
230+
world.insert_resource(RunConditionBool(true));
231+
world.init_resource::<SystemOrder>();
232+
233+
fn change_condition(mut condition: ResMut<RunConditionBool>) {
234+
condition.0 = false;
235+
}
236+
237+
schedule.add_systems(
238+
(
239+
make_function_system(0),
240+
change_condition,
241+
make_function_system(1),
242+
)
243+
.chain()
244+
.distributive_run_if(|condition: Res<RunConditionBool>| condition.0),
245+
);
246+
247+
schedule.run(&mut world);
248+
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
249+
}
250+
225251
#[test]
226252
fn run_exclusive_system_with_condition() {
227253
let mut world = World::default();

0 commit comments

Comments
 (0)