Skip to content

Commit ee88d79

Browse files
authored
Simplify run conditions (#14441)
# Objective Simplify Bevy-provided functions that return a condition-satisfying closure instead of just being the condition. ## Solution Become the condition. ## Testing I did not test. Game jamming. Hopefully CI passes. --- ## Migration Guide Some run conditions have been simplified. ```rust // Before: app.add_systems(Update, ( system_0.run_if(run_once()), system_1.run_if(resource_changed_or_removed::<T>()), system_2.run_if(resource_removed::<T>()), system_3.run_if(on_event::<T>()), system_4.run_if(any_component_removed::<T>()), )); // After: app.add_systems(Update, ( system_0.run_if(run_once), system_1.run_if(resource_changed_or_removed::<T>), system_2.run_if(resource_removed::<T>), system_3.run_if(on_event::<T>), system_4.run_if(any_component_removed::<T>), )); ```
1 parent cd49715 commit ee88d79

File tree

2 files changed

+45
-54
lines changed

2 files changed

+45
-54
lines changed

crates/bevy_ecs/src/change_detection.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ pub trait DetectChangesMut: DetectChanges {
226226
/// # score_changed.initialize(&mut world);
227227
/// # score_changed.run((), &mut world);
228228
/// #
229-
/// # let mut score_changed_event = IntoSystem::into_system(on_event::<ScoreChanged>());
229+
/// # let mut score_changed_event = IntoSystem::into_system(on_event::<ScoreChanged>);
230230
/// # score_changed_event.initialize(&mut world);
231231
/// # score_changed_event.run((), &mut world);
232232
/// #

crates/bevy_ecs/src/schedule/condition.rs

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -496,11 +496,11 @@ pub mod common_conditions {
496496
event::{Event, EventReader},
497497
prelude::{Component, Query, With},
498498
removal_detection::RemovedComponents,
499-
system::{IntoSystem, Res, Resource, System},
499+
system::{IntoSystem, Local, Res, Resource, System},
500500
};
501501

502-
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
503-
/// if the first time the condition is run and false every time after
502+
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
503+
/// on the first time the condition is run and false every time after.
504504
///
505505
/// # Example
506506
///
@@ -513,7 +513,7 @@ pub mod common_conditions {
513513
/// # world.init_resource::<Counter>();
514514
/// app.add_systems(
515515
/// // `run_once` will only return true the first time it's evaluated
516-
/// my_system.run_if(run_once()),
516+
/// my_system.run_if(run_once),
517517
/// );
518518
///
519519
/// fn my_system(mut counter: ResMut<Counter>) {
@@ -528,15 +528,12 @@ pub mod common_conditions {
528528
/// app.run(&mut world);
529529
/// assert_eq!(world.resource::<Counter>().0, 1);
530530
/// ```
531-
pub fn run_once() -> impl FnMut() -> bool + Clone {
532-
let mut has_run = false;
533-
move || {
534-
if !has_run {
535-
has_run = true;
536-
true
537-
} else {
538-
false
539-
}
531+
pub fn run_once(mut has_run: Local<bool>) -> bool {
532+
if !*has_run {
533+
*has_run = true;
534+
true
535+
} else {
536+
false
540537
}
541538
}
542539

@@ -815,7 +812,7 @@ pub mod common_conditions {
815812
}
816813
}
817814

818-
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
815+
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
819816
/// if the resource of the given type has had its value changed since the condition
820817
/// was last checked.
821818
///
@@ -841,7 +838,7 @@ pub mod common_conditions {
841838
/// // `resource_changed_or_removed` will only return true if the
842839
/// // given resource was just changed or removed (or added)
843840
/// my_system.run_if(
844-
/// resource_changed_or_removed::<Counter>()
841+
/// resource_changed_or_removed::<Counter>
845842
/// // By default detecting changes will also trigger if the resource was
846843
/// // just added, this won't work with my example so I will add a second
847844
/// // condition to make sure the resource wasn't just added
@@ -877,25 +874,22 @@ pub mod common_conditions {
877874
/// app.run(&mut world);
878875
/// assert_eq!(world.contains_resource::<MyResource>(), true);
879876
/// ```
880-
pub fn resource_changed_or_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
877+
pub fn resource_changed_or_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
881878
where
882879
T: Resource,
883880
{
884-
let mut existed = false;
885-
move |res: Option<Res<T>>| {
886-
if let Some(value) = res {
887-
existed = true;
888-
value.is_changed()
889-
} else if existed {
890-
existed = false;
891-
true
892-
} else {
893-
false
894-
}
881+
if let Some(value) = res {
882+
*existed = true;
883+
value.is_changed()
884+
} else if *existed {
885+
*existed = false;
886+
true
887+
} else {
888+
false
895889
}
896890
}
897891

898-
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
892+
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
899893
/// if the resource of the given type has been removed since the condition was last checked.
900894
///
901895
/// # Example
@@ -910,7 +904,7 @@ pub mod common_conditions {
910904
/// app.add_systems(
911905
/// // `resource_removed` will only return true if the
912906
/// // given resource was just removed
913-
/// my_system.run_if(resource_removed::<MyResource>()),
907+
/// my_system.run_if(resource_removed::<MyResource>),
914908
/// );
915909
///
916910
/// #[derive(Resource, Default)]
@@ -932,25 +926,22 @@ pub mod common_conditions {
932926
/// app.run(&mut world);
933927
/// assert_eq!(world.resource::<Counter>().0, 1);
934928
/// ```
935-
pub fn resource_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
929+
pub fn resource_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
936930
where
937931
T: Resource,
938932
{
939-
let mut existed = false;
940-
move |res: Option<Res<T>>| {
941-
if res.is_some() {
942-
existed = true;
943-
false
944-
} else if existed {
945-
existed = false;
946-
true
947-
} else {
948-
false
949-
}
933+
if res.is_some() {
934+
*existed = true;
935+
false
936+
} else if *existed {
937+
*existed = false;
938+
true
939+
} else {
940+
false
950941
}
951942
}
952943

953-
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
944+
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
954945
/// if there are any new events of the given type since it was last called.
955946
///
956947
/// # Example
@@ -966,7 +957,7 @@ pub mod common_conditions {
966957
/// # app.add_systems(bevy_ecs::event::event_update_system.before(my_system));
967958
///
968959
/// app.add_systems(
969-
/// my_system.run_if(on_event::<MyEvent>()),
960+
/// my_system.run_if(on_event::<MyEvent>),
970961
/// );
971962
///
972963
/// #[derive(Event)]
@@ -986,12 +977,12 @@ pub mod common_conditions {
986977
/// app.run(&mut world);
987978
/// assert_eq!(world.resource::<Counter>().0, 1);
988979
/// ```
989-
pub fn on_event<T: Event>() -> impl FnMut(EventReader<T>) -> bool + Clone {
980+
pub fn on_event<T: Event>(mut reader: EventReader<T>) -> bool {
990981
// The events need to be consumed, so that there are no false positives on subsequent
991982
// calls of the run condition. Simply checking `is_empty` would not be enough.
992983
// PERF: note that `count` is efficient (not actually looping/iterating),
993984
// due to Bevy having a specialized implementation for events.
994-
move |mut reader: EventReader<T>| reader.read().count() > 0
985+
reader.read().count() > 0
995986
}
996987

997988
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
@@ -1031,15 +1022,15 @@ pub mod common_conditions {
10311022
!query.is_empty()
10321023
}
10331024

1034-
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
1025+
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
10351026
/// if there are any entity with a component of the given type removed.
1036-
pub fn any_component_removed<T: Component>() -> impl FnMut(RemovedComponents<T>) -> bool {
1027+
pub fn any_component_removed<T: Component>(mut removals: RemovedComponents<T>) -> bool {
10371028
// `RemovedComponents` based on events and therefore events need to be consumed,
10381029
// so that there are no false positives on subsequent calls of the run condition.
10391030
// Simply checking `is_empty` would not be enough.
10401031
// PERF: note that `count` is efficient (not actually looping/iterating),
10411032
// due to Bevy having a specialized implementation for events.
1042-
move |mut removals: RemovedComponents<T>| removals.read().count() != 0
1033+
removals.read().count() > 0
10431034
}
10441035

10451036
/// Generates a [`Condition`](super::Condition) that inverses the result of passed one.
@@ -1384,16 +1375,16 @@ mod tests {
13841375
fn distributive_run_if_compiles() {
13851376
Schedule::default().add_systems(
13861377
(test_system, test_system)
1387-
.distributive_run_if(run_once())
1378+
.distributive_run_if(run_once)
13881379
.distributive_run_if(resource_exists::<TestResource>)
13891380
.distributive_run_if(resource_added::<TestResource>)
13901381
.distributive_run_if(resource_changed::<TestResource>)
13911382
.distributive_run_if(resource_exists_and_changed::<TestResource>)
1392-
.distributive_run_if(resource_changed_or_removed::<TestResource>())
1393-
.distributive_run_if(resource_removed::<TestResource>())
1394-
.distributive_run_if(on_event::<TestEvent>())
1383+
.distributive_run_if(resource_changed_or_removed::<TestResource>)
1384+
.distributive_run_if(resource_removed::<TestResource>)
1385+
.distributive_run_if(on_event::<TestEvent>)
13951386
.distributive_run_if(any_with_component::<TestComponent>)
1396-
.distributive_run_if(not(run_once())),
1387+
.distributive_run_if(not(run_once)),
13971388
);
13981389
}
13991390
}

0 commit comments

Comments
 (0)