add Clone to common conditions (#8060)

This commit is contained in:
Bruce Reif (Buswolley) 2023-03-13 12:38:04 -07:00 committed by GitHub
parent 884b9b62af
commit 7c4a0eb768
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 20 deletions

View File

@ -169,7 +169,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn run_once() -> impl FnMut() -> bool { pub fn run_once() -> impl FnMut() -> bool + Clone {
let mut has_run = false; let mut has_run = false;
move || { move || {
if !has_run { if !has_run {
@ -209,7 +209,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn resource_exists<T>() -> impl FnMut(Option<Res<T>>) -> bool pub fn resource_exists<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
where where
T: Resource, T: Resource,
{ {
@ -332,7 +332,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn resource_added<T>() -> impl FnMut(Option<Res<T>>) -> bool pub fn resource_added<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
where where
T: Resource, T: Resource,
{ {
@ -389,7 +389,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 51); /// assert_eq!(world.resource::<Counter>().0, 51);
/// ``` /// ```
pub fn resource_changed<T>() -> impl FnMut(Res<T>) -> bool pub fn resource_changed<T>() -> impl FnMut(Res<T>) -> bool + Clone
where where
T: Resource, T: Resource,
{ {
@ -446,7 +446,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 51); /// assert_eq!(world.resource::<Counter>().0, 51);
/// ``` /// ```
pub fn resource_exists_and_changed<T>() -> impl FnMut(Option<Res<T>>) -> bool pub fn resource_exists_and_changed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
where where
T: Resource, T: Resource,
{ {
@ -518,7 +518,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.contains_resource::<MyResource>(), true); /// assert_eq!(world.contains_resource::<MyResource>(), true);
/// ``` /// ```
pub fn resource_changed_or_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool pub fn resource_changed_or_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
where where
T: Resource, T: Resource,
{ {
@ -573,7 +573,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn resource_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool pub fn resource_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
where where
T: Resource, T: Resource,
{ {
@ -630,7 +630,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn state_exists<S: States>() -> impl FnMut(Option<Res<State<S>>>) -> bool { 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() move |current_state: Option<Res<State<S>>>| current_state.is_some()
} }
@ -684,7 +684,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 0); /// assert_eq!(world.resource::<Counter>().0, 0);
/// ``` /// ```
pub fn in_state<S: States>(state: S) -> impl FnMut(Res<State<S>>) -> bool { pub fn in_state<S: States>(state: S) -> impl FnMut(Res<State<S>>) -> bool + Clone {
move |current_state: Res<State<S>>| current_state.0 == state move |current_state: Res<State<S>>| current_state.0 == state
} }
@ -742,7 +742,7 @@ pub mod common_conditions {
/// ``` /// ```
pub fn state_exists_and_equals<S: States>( pub fn state_exists_and_equals<S: States>(
state: S, state: S,
) -> impl FnMut(Option<Res<State<S>>>) -> bool { ) -> impl FnMut(Option<Res<State<S>>>) -> bool + Clone {
move |current_state: Option<Res<State<S>>>| match current_state { move |current_state: Option<Res<State<S>>>| match current_state {
Some(current_state) => current_state.0 == state, Some(current_state) => current_state.0 == state,
None => false, None => false,
@ -802,7 +802,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 2); /// assert_eq!(world.resource::<Counter>().0, 2);
/// ``` /// ```
pub fn state_changed<S: States>() -> impl FnMut(Res<State<S>>) -> bool { pub fn state_changed<S: States>() -> impl FnMut(Res<State<S>>) -> bool + Clone {
move |current_state: Res<State<S>>| current_state.is_changed() move |current_state: Res<State<S>>| current_state.is_changed()
} }
@ -841,7 +841,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn on_event<T: Event>() -> impl FnMut(EventReader<T>) -> bool { pub fn on_event<T: Event>() -> impl FnMut(EventReader<T>) -> bool + Clone {
// The events need to be consumed, so that there are no false positives on subsequent // The events need to be consumed, so that there are no false positives on subsequent
// calls of the run condition. Simply checking `is_empty` would not be enough. // calls of the run condition. Simply checking `is_empty` would not be enough.
// PERF: note that `count` is efficient (not actually looping/iterating), // PERF: note that `count` is efficient (not actually looping/iterating),
@ -882,7 +882,7 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 1); /// assert_eq!(world.resource::<Counter>().0, 1);
/// ``` /// ```
pub fn any_with_component<T: Component>() -> impl FnMut(Query<(), With<T>>) -> bool { pub fn any_with_component<T: Component>() -> impl FnMut(Query<(), With<T>>) -> bool + Clone {
move |query: Query<(), With<T>>| !query.is_empty() move |query: Query<(), With<T>>| !query.is_empty()
} }
@ -915,7 +915,10 @@ pub mod common_conditions {
/// app.run(&mut world); /// app.run(&mut world);
/// assert_eq!(world.resource::<Counter>().0, 0); /// assert_eq!(world.resource::<Counter>().0, 0);
/// ``` /// ```
pub fn not<Marker>(condition: impl Condition<Marker>) -> impl Condition<()> { pub fn not<Marker, T>(condition: T) -> impl Condition<()>
where
T: Condition<Marker>,
{
condition.pipe(|In(val): In<bool>| !val) condition.pipe(|In(val): In<bool>| !val)
} }
} }

View File

@ -48,7 +48,7 @@ use std::hash::Hash;
/// } /// }
/// ///
/// ``` /// ```
pub fn input_toggle_active<T>(default: bool, input: T) -> impl FnMut(Res<Input<T>>) -> bool pub fn input_toggle_active<T>(default: bool, input: T) -> impl FnMut(Res<Input<T>>) -> bool + Clone
where where
T: Copy + Eq + Hash + Send + Sync + 'static, T: Copy + Eq + Hash + Send + Sync + 'static,
{ {
@ -60,7 +60,7 @@ where
} }
/// Run condition that is active if [`Input::pressed`] is true for the given input. /// Run condition that is active if [`Input::pressed`] is true for the given input.
pub fn input_pressed<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool pub fn input_pressed<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool + Clone
where where
T: Copy + Eq + Hash + Send + Sync + 'static, T: Copy + Eq + Hash + Send + Sync + 'static,
{ {
@ -81,7 +81,7 @@ where
/// ///
/// # fn jump() {} /// # fn jump() {}
/// ``` /// ```
pub fn input_just_pressed<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool pub fn input_just_pressed<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool + Clone
where where
T: Copy + Eq + Hash + Send + Sync + 'static, T: Copy + Eq + Hash + Send + Sync + 'static,
{ {
@ -89,9 +89,29 @@ where
} }
/// Run condition that is active if [`Input::just_released`] is true for the given input. /// Run condition that is active if [`Input::just_released`] is true for the given input.
pub fn input_just_released<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool pub fn input_just_released<T>(input: T) -> impl FnMut(Res<Input<T>>) -> bool + Clone
where where
T: Copy + Eq + Hash + Send + Sync + 'static, T: Copy + Eq + Hash + Send + Sync + 'static,
{ {
move |inputs: Res<Input<T>>| inputs.just_released(input) move |inputs: Res<Input<T>>| inputs.just_released(input)
} }
#[cfg(test)]
mod tests {
use super::*;
use bevy::prelude::{IntoSystemConfigs, KeyCode, Schedule};
fn test_system() {}
// Ensure distributive_run_if compiles with the common conditions.
#[test]
fn distributive_run_if_compiles() {
Schedule::default().add_systems(
(test_system, test_system)
.distributive_run_if(input_toggle_active(false, KeyCode::Escape))
.distributive_run_if(input_pressed(KeyCode::Escape))
.distributive_run_if(input_just_pressed(KeyCode::Escape))
.distributive_run_if(input_just_released(KeyCode::Escape)),
);
}
}

View File

@ -32,7 +32,7 @@ use bevy_utils::Duration;
/// For more accurate timers, use the [`Timer`] class directly (see /// For more accurate timers, use the [`Timer`] class directly (see
/// [`Timer::times_finished_this_tick`] to address the problem mentioned above), or /// [`Timer::times_finished_this_tick`] to address the problem mentioned above), or
/// use fixed timesteps that allow systems to run multiple times per frame. /// use fixed timesteps that allow systems to run multiple times per frame.
pub fn on_timer(duration: Duration) -> impl FnMut(Res<Time>) -> bool { pub fn on_timer(duration: Duration) -> impl FnMut(Res<Time>) -> bool + Clone {
let mut timer = Timer::new(duration, TimerMode::Repeating); let mut timer = Timer::new(duration, TimerMode::Repeating);
move |time: Res<Time>| { move |time: Res<Time>| {
timer.tick(time.delta()); timer.tick(time.delta());
@ -67,10 +67,28 @@ pub fn on_timer(duration: Duration) -> impl FnMut(Res<Time>) -> bool {
/// Note that this run condition may not behave as expected if `duration` is smaller /// Note that this run condition may not behave as expected if `duration` is smaller
/// than the fixed timestep period, since the timer may complete multiple times in /// than the fixed timestep period, since the timer may complete multiple times in
/// one fixed update. /// one fixed update.
pub fn on_fixed_timer(duration: Duration) -> impl FnMut(Res<FixedTime>) -> bool { pub fn on_fixed_timer(duration: Duration) -> impl FnMut(Res<FixedTime>) -> bool + Clone {
let mut timer = Timer::new(duration, TimerMode::Repeating); let mut timer = Timer::new(duration, TimerMode::Repeating);
move |time: Res<FixedTime>| { move |time: Res<FixedTime>| {
timer.tick(time.period); timer.tick(time.period);
timer.just_finished() timer.just_finished()
} }
} }
#[cfg(test)]
mod tests {
use super::*;
use bevy_ecs::schedule::{IntoSystemConfigs, Schedule};
fn test_system() {}
// Ensure distributive_run_if compiles with the common conditions.
#[test]
fn distributive_run_if_compiles() {
Schedule::default().add_systems(
(test_system, test_system)
.distributive_run_if(on_timer(Duration::new(1, 0)))
.distributive_run_if(on_fixed_timer(Duration::new(1, 0))),
);
}
}