Simplify conditions (#11316)

# Objective

- Conditions don't have to be closures unless they have state or mutate.

## Solution

- Simplify conditions when possible.

---

## Changelog

The following run conditions are now regular systems:
- resource_exists<T>
- resource_added<T>
- resource_changed<T>
- resource_exists_and_changed<T>
- state_exists<S: States>
- state_changed<S: States>
- any_with_component<T: Component>

## Migration Guide

- resource_exists<T>() -> resource_exists<T>
- resource_added<T>() -> resource_added<T>
- resource_changed<T>() -> resource_changed<T>
- resource_exists_and_changed<T>() -> resource_exists_and_changed<T>
- state_exists<S: States>() -> state_exists<S: States>
- state_changed<S: States>() -> state_changed<S: States>
- any_with_component<T: Component>() -> any_with_component<T: Component>
This commit is contained in:
Ixentus 2024-01-13 14:22:17 +01:00 committed by GitHub
parent e6a324a11a
commit e2fd63104d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 48 additions and 48 deletions

View file

@ -146,7 +146,7 @@ pub trait DetectChangesMut: DetectChanges {
/// }
/// # let mut world = World::new();
/// # world.insert_resource(Score(1));
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>());
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
/// # score_changed.initialize(&mut world);
/// # score_changed.run((), &mut world);
/// #
@ -210,7 +210,7 @@ pub trait DetectChangesMut: DetectChanges {
/// # let mut world = World::new();
/// # world.insert_resource(Events::<ScoreChanged>::default());
/// # world.insert_resource(Score(1));
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>());
/// # let mut score_changed = IntoSystem::into_system(resource_changed::<Score>);
/// # score_changed.initialize(&mut world);
/// # score_changed.run((), &mut world);
/// #

View file

@ -107,7 +107,7 @@ pub trait Condition<Marker, In = ()>: sealed::Condition<Marker, In> {
/// # fn my_system() {}
/// app.add_systems(
/// // `resource_equals` will only get run if the resource `R` exists.
/// my_system.run_if(resource_exists::<R>().and_then(resource_equals(R(0)))),
/// my_system.run_if(resource_exists::<R>.and_then(resource_equals(R(0)))),
/// );
/// # app.run(&mut world);
/// ```
@ -145,7 +145,7 @@ pub trait Condition<Marker, In = ()>: sealed::Condition<Marker, In> {
/// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
/// app.add_systems(
/// // Only run the system if either `A` or `B` exist.
/// my_system.run_if(resource_exists::<A>().or_else(resource_exists::<B>())),
/// my_system.run_if(resource_exists::<A>.or_else(resource_exists::<B>)),
/// );
/// #
/// # world.insert_resource(C(false));
@ -245,7 +245,7 @@ pub mod common_conditions {
}
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the resource exists.
///
/// # Example
@ -258,7 +258,7 @@ pub mod common_conditions {
/// # let mut world = World::new();
/// app.add_systems(
/// // `resource_exists` will only return true if the given resource exists in the world
/// my_system.run_if(resource_exists::<Counter>()),
/// my_system.run_if(resource_exists::<Counter>),
/// );
///
/// fn my_system(mut counter: ResMut<Counter>) {
@ -273,11 +273,11 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1);
/// ```
pub fn resource_exists<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
pub fn resource_exists<T>(res: Option<Res<T>>) -> bool
where
T: Resource,
{
move |res: Option<Res<T>>| res.is_some()
res.is_some()
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
@ -365,7 +365,7 @@ pub mod common_conditions {
}
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the resource of the given type has been added since the condition was last checked.
///
/// # Example
@ -379,7 +379,7 @@ pub mod common_conditions {
/// app.add_systems(
/// // `resource_added` will only return true if the
/// // given resource was just added
/// my_system.run_if(resource_added::<Counter>()),
/// my_system.run_if(resource_added::<Counter>),
/// );
///
/// fn my_system(mut counter: ResMut<Counter>) {
@ -396,17 +396,17 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1);
/// ```
pub fn resource_added<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
pub fn resource_added<T>(res: Option<Res<T>>) -> bool
where
T: Resource,
{
move |res: Option<Res<T>>| match res {
match res {
Some(res) => res.is_added(),
None => false,
}
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the resource of the given type has had its value changed since the condition
/// was last checked.
///
@ -431,11 +431,11 @@ pub mod common_conditions {
/// // `resource_changed` will only return true if the
/// // given resource was just changed (or added)
/// my_system.run_if(
/// resource_changed::<Counter>()
/// resource_changed::<Counter>
/// // By default detecting changes will also trigger if the resource was
/// // just added, this won't work with my example so I will add a second
/// // condition to make sure the resource wasn't just added
/// .and_then(not(resource_added::<Counter>()))
/// .and_then(not(resource_added::<Counter>))
/// ),
/// );
///
@ -453,14 +453,14 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 51);
/// ```
pub fn resource_changed<T>() -> impl FnMut(Res<T>) -> bool + Clone
pub fn resource_changed<T>(res: Res<T>) -> bool
where
T: Resource,
{
move |res: Res<T>| res.is_changed()
res.is_changed()
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the resource of the given type has had its value changed since the condition
/// was last checked.
///
@ -484,11 +484,11 @@ pub mod common_conditions {
/// // `resource_exists_and_changed` will only return true if the
/// // given resource exists and was just changed (or added)
/// my_system.run_if(
/// resource_exists_and_changed::<Counter>()
/// resource_exists_and_changed::<Counter>
/// // By default detecting changes will also trigger if the resource was
/// // just added, this won't work with my example so I will add a second
/// // condition to make sure the resource wasn't just added
/// .and_then(not(resource_added::<Counter>()))
/// .and_then(not(resource_added::<Counter>))
/// ),
/// );
///
@ -510,11 +510,11 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 51);
/// ```
pub fn resource_exists_and_changed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
pub fn resource_exists_and_changed<T>(res: Option<Res<T>>) -> bool
where
T: Resource,
{
move |res: Option<Res<T>>| match res {
match res {
Some(res) => res.is_changed(),
None => false,
}
@ -550,7 +550,7 @@ pub mod common_conditions {
/// // By default detecting changes will also trigger if the resource was
/// // just added, this won't work with my example so I will add a second
/// // condition to make sure the resource wasn't just added
/// .and_then(not(resource_added::<Counter>()))
/// .and_then(not(resource_added::<Counter>))
/// ),
/// );
///
@ -655,7 +655,7 @@ pub mod common_conditions {
}
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the state machine exists.
///
/// # Example
@ -677,7 +677,7 @@ pub mod common_conditions {
/// app.add_systems(
/// // `state_exists` will only return true if the
/// // given state exists
/// my_system.run_if(state_exists::<GameState>()),
/// my_system.run_if(state_exists::<GameState>),
/// );
///
/// fn my_system(mut counter: ResMut<Counter>) {
@ -694,8 +694,8 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1);
/// ```
pub fn state_exists<S: States>() -> impl FnMut(Option<Res<State<S>>>) -> bool + Clone {
move |current_state: Option<Res<State<S>>>| current_state.is_some()
pub fn state_exists<S: States>(current_state: Option<Res<State<S>>>) -> bool {
current_state.is_some()
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
@ -813,7 +813,7 @@ pub mod common_conditions {
}
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if the state machine changed state.
///
/// To do things on transitions to/from specific states, use their respective OnEnter/OnExit
@ -845,7 +845,7 @@ pub mod common_conditions {
/// // `state_changed` will only return true if the
/// // given states value has just been updated or
/// // the state has just been added
/// my_system.run_if(state_changed::<GameState>()),
/// my_system.run_if(state_changed::<GameState>),
/// );
///
/// fn my_system(mut counter: ResMut<Counter>) {
@ -866,8 +866,8 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 2);
/// ```
pub fn state_changed<S: States>() -> impl FnMut(Res<State<S>>) -> bool + Clone {
move |current_state: Res<State<S>>| current_state.is_changed()
pub fn state_changed<S: States>(current_state: Res<State<S>>) -> bool {
current_state.is_changed()
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
@ -914,7 +914,7 @@ pub mod common_conditions {
move |mut reader: EventReader<T>| reader.read().count() > 0
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
/// A [`Condition`](super::Condition)-satisfying system that returns `true`
/// if there are any entities with the given component type.
///
/// # Example
@ -927,7 +927,7 @@ pub mod common_conditions {
/// # let mut world = World::new();
/// # world.init_resource::<Counter>();
/// app.add_systems(
/// my_system.run_if(any_with_component::<MyComponent>()),
/// my_system.run_if(any_with_component::<MyComponent>),
/// );
///
/// #[derive(Component)]
@ -947,8 +947,8 @@ pub mod common_conditions {
/// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1);
/// ```
pub fn any_with_component<T: Component>() -> impl FnMut(Query<(), With<T>>) -> bool + Clone {
move |query: Query<(), With<T>>| !query.is_empty()
pub fn any_with_component<T: Component>(query: Query<(), With<T>>) -> bool {
!query.is_empty()
}
/// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
@ -1199,17 +1199,17 @@ mod tests {
Schedule::default().add_systems(
(test_system, test_system)
.distributive_run_if(run_once())
.distributive_run_if(resource_exists::<State<TestState>>())
.distributive_run_if(resource_added::<State<TestState>>())
.distributive_run_if(resource_changed::<State<TestState>>())
.distributive_run_if(resource_exists_and_changed::<State<TestState>>())
.distributive_run_if(resource_exists::<State<TestState>>)
.distributive_run_if(resource_added::<State<TestState>>)
.distributive_run_if(resource_changed::<State<TestState>>)
.distributive_run_if(resource_exists_and_changed::<State<TestState>>)
.distributive_run_if(resource_changed_or_removed::<State<TestState>>())
.distributive_run_if(resource_removed::<State<TestState>>())
.distributive_run_if(state_exists::<TestState>())
.distributive_run_if(state_exists::<TestState>)
.distributive_run_if(in_state(TestState::A).or_else(in_state(TestState::B)))
.distributive_run_if(state_changed::<TestState>())
.distributive_run_if(state_changed::<TestState>)
.distributive_run_if(on_event::<TestEvent>())
.distributive_run_if(any_with_component::<TestComponent>())
.distributive_run_if(any_with_component::<TestComponent>)
.distributive_run_if(not(run_once())),
);
}

View file

@ -1740,7 +1740,7 @@ mod tests {
res.0 += 2;
},
)
.distributive_run_if(resource_exists::<A>().or_else(resource_exists::<B>())),
.distributive_run_if(resource_exists::<A>.or_else(resource_exists::<B>)),
);
sched.initialize(&mut world).unwrap();
sched.run(&mut world);

View file

@ -43,10 +43,10 @@ impl Plugin for WireframePlugin {
.add_systems(
Update,
(
global_color_changed.run_if(resource_changed::<WireframeConfig>()),
global_color_changed.run_if(resource_changed::<WireframeConfig>),
wireframe_color_changed,
apply_wireframe_material,
apply_global_wireframe_material.run_if(resource_changed::<WireframeConfig>()),
apply_global_wireframe_material.run_if(resource_changed::<WireframeConfig>),
),
);
}

View file

@ -17,12 +17,12 @@ fn main() {
increment_input_counter
// The common_conditions module has a few useful run conditions
// for checking resources and states. These are included in the prelude.
.run_if(resource_exists::<InputCounter>())
.run_if(resource_exists::<InputCounter>)
// `.or_else()` is a run condition combinator that only evaluates the second condition
// if the first condition returns `false`. This behavior is known as "short-circuiting",
// and is how the `||` operator works in Rust (as well as most C-family languages).
// In this case, the `has_user_input` run condition will be evaluated since the `Unused` resource has not been initialized.
.run_if(resource_exists::<Unused>().or_else(
.run_if(resource_exists::<Unused>.or_else(
// This is a custom run condition, defined using a system that returns
// a `bool` and which has read-only `SystemParam`s.
// Both run conditions must return `true` in order for the system to run.
@ -34,7 +34,7 @@ fn main() {
// if the first condition returns `true`, analogous to the `&&` operator.
// In this case, the short-circuiting behavior prevents the second run condition from
// panicking if the `InputCounter` resource has not been initialized.
.run_if(resource_exists::<InputCounter>().and_then(
.run_if(resource_exists::<InputCounter>.and_then(
// This is a custom run condition in the form of a closure.
// This is useful for small, simple run conditions you don't need to reuse.
// All the normal rules still apply: all parameters must be read only except for local parameters.