2023-02-20 18:16:11 +00:00
|
|
|
use std::borrow::Cow;
|
2023-03-17 21:37:16 +00:00
|
|
|
use std::ops::Not;
|
2023-02-20 18:16:11 +00:00
|
|
|
|
2023-08-28 16:36:46 +00:00
|
|
|
use crate::system::{
|
|
|
|
Adapt, AdapterSystem, CombinatorSystem, Combine, IntoSystem, ReadOnlySystem, System,
|
|
|
|
};
|
2023-01-17 01:39:17 +00:00
|
|
|
|
2023-06-10 23:23:48 +00:00
|
|
|
/// A type-erased run condition stored in a [`Box`].
|
2023-05-31 16:49:46 +00:00
|
|
|
pub type BoxedCondition<In = ()> = Box<dyn ReadOnlySystem<In = In, Out = bool>>;
|
2023-01-17 01:39:17 +00:00
|
|
|
|
|
|
|
/// A system that determines if one or more scheduled systems should run.
|
|
|
|
///
|
2023-11-28 23:43:40 +00:00
|
|
|
/// Implemented for functions and closures that convert into [`System<Out=bool>`](System)
|
2023-01-17 01:39:17 +00:00
|
|
|
/// with [read-only](crate::system::ReadOnlySystemParam) parameters.
|
2023-05-31 16:49:46 +00:00
|
|
|
///
|
2023-11-27 16:33:22 +00:00
|
|
|
/// # Marker type parameter
|
|
|
|
///
|
|
|
|
/// `Condition` trait has `Marker` type parameter, which has no special meaning,
|
|
|
|
/// but exists to work around the limitation of Rust's trait system.
|
|
|
|
///
|
|
|
|
/// Type parameter in return type can be set to `<()>` by calling [`IntoSystem::into_system`],
|
|
|
|
/// but usually have to be specified when passing a condition to a function.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::schedule::Condition;
|
|
|
|
/// # use bevy_ecs::system::IntoSystem;
|
|
|
|
/// fn not_condition<Marker>(a: impl Condition<Marker>) -> impl Condition<()> {
|
|
|
|
/// IntoSystem::into_system(a.map(|x| !x))
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
2023-05-31 16:49:46 +00:00
|
|
|
/// # Examples
|
|
|
|
/// A condition that returns true every other time it's called.
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// fn every_other_time() -> impl Condition<()> {
|
|
|
|
/// IntoSystem::into_system(|mut flag: Local<bool>| {
|
|
|
|
/// *flag = !*flag;
|
|
|
|
/// *flag
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # #[derive(Resource)] struct DidRun(bool);
|
|
|
|
/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut schedule = Schedule::default();
|
2023-05-31 16:49:46 +00:00
|
|
|
/// schedule.add_systems(my_system.run_if(every_other_time()));
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.insert_resource(DidRun(false));
|
|
|
|
/// # schedule.run(&mut world);
|
|
|
|
/// # assert!(world.resource::<DidRun>().0);
|
|
|
|
/// # world.insert_resource(DidRun(false));
|
|
|
|
/// # schedule.run(&mut world);
|
|
|
|
/// # assert!(!world.resource::<DidRun>().0);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// A condition that takes a bool as an input and returns it unchanged.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// fn identity() -> impl Condition<(), bool> {
|
|
|
|
/// IntoSystem::into_system(|In(x)| x)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # fn always_true() -> bool { true }
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-05-31 16:49:46 +00:00
|
|
|
/// # #[derive(Resource)] struct DidRun(bool);
|
|
|
|
/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
|
2023-08-28 20:44:48 +00:00
|
|
|
/// app.add_systems(my_system.run_if(always_true.pipe(identity())));
|
2023-05-31 16:49:46 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.insert_resource(DidRun(false));
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # app.run(&mut world);
|
2023-05-31 16:49:46 +00:00
|
|
|
/// # assert!(world.resource::<DidRun>().0);
|
|
|
|
pub trait Condition<Marker, In = ()>: sealed::Condition<Marker, In> {
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// Returns a new run condition that only returns `true`
|
|
|
|
/// if both this one and the passed `and` return `true`.
|
|
|
|
///
|
|
|
|
/// The returned run condition is short-circuiting, meaning
|
|
|
|
/// `and` will only be invoked if `self` returns `true`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```should_panic
|
|
|
|
/// use bevy_ecs::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, PartialEq)]
|
|
|
|
/// struct R(u32);
|
|
|
|
///
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn my_system() {}
|
|
|
|
/// app.add_systems(
|
|
|
|
/// // The `resource_equals` run condition will panic since we don't initialize `R`,
|
|
|
|
/// // just like if we used `Res<R>` in a system.
|
|
|
|
/// my_system.run_if(resource_equals(R(0))),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Use `.and()` to avoid checking the condition.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, PartialEq)]
|
|
|
|
/// # struct R(u32);
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # 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(resource_equals(R(0)))),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Note that in this case, it's better to just use the run condition [`resource_exists_and_equals`].
|
|
|
|
///
|
|
|
|
/// [`resource_exists_and_equals`]: common_conditions::resource_exists_and_equals
|
|
|
|
fn and<M, C: Condition<M, In>>(self, and: C) -> And<Self::System, C::System> {
|
|
|
|
let a = IntoSystem::into_system(self);
|
|
|
|
let b = IntoSystem::into_system(and);
|
|
|
|
let name = format!("{} && {}", a.name(), b.name());
|
|
|
|
CombinatorSystem::new(a, b, Cow::Owned(name))
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:16:11 +00:00
|
|
|
/// Returns a new run condition that only returns `true`
|
|
|
|
/// if both this one and the passed `and_then` return `true`.
|
|
|
|
///
|
|
|
|
/// The returned run condition is short-circuiting, meaning
|
|
|
|
/// `and_then` will only be invoked if `self` returns `true`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```should_panic
|
|
|
|
/// use bevy_ecs::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, PartialEq)]
|
|
|
|
/// struct R(u32);
|
|
|
|
///
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-02-20 18:16:11 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn my_system() {}
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-02-20 18:16:11 +00:00
|
|
|
/// // The `resource_equals` run condition will panic since we don't initialize `R`,
|
|
|
|
/// // just like if we used `Res<R>` in a system.
|
|
|
|
/// my_system.run_if(resource_equals(R(0))),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Use `.and_then()` to avoid checking the condition.
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, PartialEq)]
|
|
|
|
/// # struct R(u32);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-02-20 18:16:11 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn my_system() {}
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-02-20 18:16:11 +00:00
|
|
|
/// // `resource_equals` will only get run if the resource `R` exists.
|
2024-01-13 13:22:17 +00:00
|
|
|
/// my_system.run_if(resource_exists::<R>.and_then(resource_equals(R(0)))),
|
2023-02-20 18:16:11 +00:00
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Note that in this case, it's better to just use the run condition [`resource_exists_and_equals`].
|
|
|
|
///
|
|
|
|
/// [`resource_exists_and_equals`]: common_conditions::resource_exists_and_equals
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
#[deprecated(
|
|
|
|
note = "Users should use the `.and(condition)` method in lieu of `.and_then(condition)`"
|
|
|
|
)]
|
|
|
|
fn and_then<M, C: Condition<M, In>>(self, and_then: C) -> And<Self::System, C::System> {
|
|
|
|
self.and(and_then)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a new run condition that only returns `false`
|
|
|
|
/// if both this one and the passed `nand` return `true`.
|
|
|
|
///
|
|
|
|
/// The returned run condition is short-circuiting, meaning
|
|
|
|
/// `nand` will only be invoked if `self` returns `true`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// use bevy::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum PlayerState {
|
|
|
|
/// Alive,
|
|
|
|
/// Dead,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum EnemyState {
|
|
|
|
/// Alive,
|
|
|
|
/// Dead,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn game_over_credits() {}
|
|
|
|
/// app.add_systems(
|
|
|
|
/// // The game_over_credits system will only execute if either the `in_state(PlayerState::Alive)`
|
|
|
|
/// // run condition or `in_state(EnemyState::Alive)` run condition evaluates to `false`.
|
|
|
|
/// game_over_credits.run_if(
|
|
|
|
/// in_state(PlayerState::Alive).nand(in_state(EnemyState::Alive))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Equivalent logic can be achieved by using `not` in concert with `and`:
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// app.add_systems(
|
|
|
|
/// game_over_credits.run_if(
|
|
|
|
/// not(in_state(PlayerState::Alive).and(in_state(EnemyState::Alive)))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// ```
|
|
|
|
fn nand<M, C: Condition<M, In>>(self, nand: C) -> Nand<Self::System, C::System> {
|
2023-02-20 18:16:11 +00:00
|
|
|
let a = IntoSystem::into_system(self);
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
let b = IntoSystem::into_system(nand);
|
|
|
|
let name = format!("!({} && {})", a.name(), b.name());
|
|
|
|
CombinatorSystem::new(a, b, Cow::Owned(name))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a new run condition that only returns `true`
|
|
|
|
/// if both this one and the passed `nor` return `false`.
|
|
|
|
///
|
|
|
|
/// The returned run condition is short-circuiting, meaning
|
|
|
|
/// `nor` will only be invoked if `self` returns `false`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// use bevy::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum WeatherState {
|
|
|
|
/// Sunny,
|
|
|
|
/// Cloudy,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum SoilState {
|
|
|
|
/// Fertilized,
|
|
|
|
/// NotFertilized,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn slow_plant_growth() {}
|
|
|
|
/// app.add_systems(
|
|
|
|
/// // The slow_plant_growth system will only execute if both the `in_state(WeatherState::Sunny)`
|
|
|
|
/// // run condition and `in_state(SoilState::Fertilized)` run condition evaluate to `false`.
|
|
|
|
/// slow_plant_growth.run_if(
|
|
|
|
/// in_state(WeatherState::Sunny).nor(in_state(SoilState::Fertilized))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Equivalent logic can be achieved by using `not` in concert with `or`:
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// app.add_systems(
|
|
|
|
/// slow_plant_growth.run_if(
|
|
|
|
/// not(in_state(WeatherState::Sunny).or(in_state(SoilState::Fertilized)))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// ```
|
|
|
|
fn nor<M, C: Condition<M, In>>(self, nor: C) -> Nor<Self::System, C::System> {
|
|
|
|
let a = IntoSystem::into_system(self);
|
|
|
|
let b = IntoSystem::into_system(nor);
|
|
|
|
let name = format!("!({} || {})", a.name(), b.name());
|
2023-02-20 18:16:11 +00:00
|
|
|
CombinatorSystem::new(a, b, Cow::Owned(name))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a new run condition that returns `true`
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// if either this one or the passed `or` return `true`.
|
2023-02-20 18:16:11 +00:00
|
|
|
///
|
|
|
|
/// The returned run condition is short-circuiting, meaning
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// `or` will only be invoked if `self` returns `false`.
|
2023-02-20 18:16:11 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bevy_ecs::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, PartialEq)]
|
|
|
|
/// struct A(u32);
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, PartialEq)]
|
|
|
|
/// struct B(u32);
|
|
|
|
///
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-02-20 18:16:11 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # #[derive(Resource)] struct C(bool);
|
|
|
|
/// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-02-20 18:16:11 +00:00
|
|
|
/// // Only run the system if either `A` or `B` exist.
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// my_system.run_if(resource_exists::<A>.or(resource_exists::<B>)),
|
2023-02-20 18:16:11 +00:00
|
|
|
/// );
|
|
|
|
/// #
|
|
|
|
/// # world.insert_resource(C(false));
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// # assert!(!world.resource::<C>().0);
|
|
|
|
/// #
|
|
|
|
/// # world.insert_resource(A(0));
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// # assert!(world.resource::<C>().0);
|
|
|
|
/// #
|
|
|
|
/// # world.remove_resource::<A>();
|
|
|
|
/// # world.insert_resource(B(0));
|
|
|
|
/// # world.insert_resource(C(false));
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// # assert!(world.resource::<C>().0);
|
|
|
|
/// ```
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
fn or<M, C: Condition<M, In>>(self, or: C) -> Or<Self::System, C::System> {
|
2023-02-20 18:16:11 +00:00
|
|
|
let a = IntoSystem::into_system(self);
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
let b = IntoSystem::into_system(or);
|
2023-02-20 18:16:11 +00:00
|
|
|
let name = format!("{} || {}", a.name(), b.name());
|
|
|
|
CombinatorSystem::new(a, b, Cow::Owned(name))
|
|
|
|
}
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
|
|
|
|
/// Returns a new run condition that returns `true`
|
|
|
|
/// if either this one or the passed `or` return `true`.
|
|
|
|
///
|
|
|
|
/// The returned run condition is short-circuiting, meaning
|
|
|
|
/// `or` will only be invoked if `self` returns `false`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// use bevy_ecs::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, PartialEq)]
|
|
|
|
/// struct A(u32);
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, PartialEq)]
|
|
|
|
/// struct B(u32);
|
|
|
|
///
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # #[derive(Resource)] struct C(bool);
|
|
|
|
/// # 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(resource_exists::<B>)),
|
|
|
|
/// );
|
|
|
|
/// #
|
|
|
|
/// # world.insert_resource(C(false));
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// # assert!(!world.resource::<C>().0);
|
|
|
|
/// #
|
|
|
|
/// # world.insert_resource(A(0));
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// # assert!(world.resource::<C>().0);
|
|
|
|
/// #
|
|
|
|
/// # world.remove_resource::<A>();
|
|
|
|
/// # world.insert_resource(B(0));
|
|
|
|
/// # world.insert_resource(C(false));
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// # assert!(world.resource::<C>().0);
|
|
|
|
/// ```
|
|
|
|
#[deprecated(
|
|
|
|
note = "Users should use the `.or(condition)` method in lieu of `.or_else(condition)`"
|
|
|
|
)]
|
|
|
|
fn or_else<M, C: Condition<M, In>>(self, or_else: C) -> Or<Self::System, C::System> {
|
|
|
|
self.or(or_else)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a new run condition that only returns `true`
|
|
|
|
/// if `self` and `xnor` **both** return `false` or **both** return `true`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// use bevy::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum CoffeeMachineState {
|
|
|
|
/// Heating,
|
|
|
|
/// Brewing,
|
|
|
|
/// Inactive,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum TeaKettleState {
|
|
|
|
/// Heating,
|
|
|
|
/// Steeping,
|
|
|
|
/// Inactive,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn take_drink_orders() {}
|
|
|
|
/// app.add_systems(
|
|
|
|
/// // The take_drink_orders system will only execute if the `in_state(CoffeeMachineState::Inactive)`
|
|
|
|
/// // run condition and `in_state(TeaKettleState::Inactive)` run conditions both evaluate to `false`,
|
|
|
|
/// // or both evaluate to `true`.
|
|
|
|
/// take_drink_orders.run_if(
|
|
|
|
/// in_state(CoffeeMachineState::Inactive).xnor(in_state(TeaKettleState::Inactive))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Equivalent logic can be achieved by using `not` in concert with `xor`:
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// app.add_systems(
|
|
|
|
/// take_drink_orders.run_if(
|
|
|
|
/// not(in_state(CoffeeMachineState::Inactive).xor(in_state(TeaKettleState::Inactive)))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// ```
|
|
|
|
fn xnor<M, C: Condition<M, In>>(self, xnor: C) -> Xnor<Self::System, C::System> {
|
|
|
|
let a = IntoSystem::into_system(self);
|
|
|
|
let b = IntoSystem::into_system(xnor);
|
|
|
|
let name = format!("!({} ^ {})", a.name(), b.name());
|
|
|
|
CombinatorSystem::new(a, b, Cow::Owned(name))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a new run condition that only returns `true`
|
|
|
|
/// if either `self` or `xor` return `true`, but not both.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```compile_fail
|
|
|
|
/// use bevy::prelude::*;
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum CoffeeMachineState {
|
|
|
|
/// Heating,
|
|
|
|
/// Brewing,
|
|
|
|
/// Inactive,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
/// pub enum TeaKettleState {
|
|
|
|
/// Heating,
|
|
|
|
/// Steeping,
|
|
|
|
/// Inactive,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # fn prepare_beverage() {}
|
|
|
|
/// app.add_systems(
|
|
|
|
/// // The prepare_beverage system will only execute if either the `in_state(CoffeeMachineState::Inactive)`
|
|
|
|
/// // run condition or `in_state(TeaKettleState::Inactive)` run condition evaluates to `true`,
|
|
|
|
/// // but not both.
|
|
|
|
/// prepare_beverage.run_if(
|
|
|
|
/// in_state(CoffeeMachineState::Inactive).xor(in_state(TeaKettleState::Inactive))
|
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
/// # app.run(&mut world);
|
|
|
|
/// ```
|
|
|
|
fn xor<M, C: Condition<M, In>>(self, xor: C) -> Xor<Self::System, C::System> {
|
|
|
|
let a = IntoSystem::into_system(self);
|
|
|
|
let b = IntoSystem::into_system(xor);
|
|
|
|
let name = format!("({} ^ {})", a.name(), b.name());
|
|
|
|
CombinatorSystem::new(a, b, Cow::Owned(name))
|
|
|
|
}
|
2023-02-20 18:16:11 +00:00
|
|
|
}
|
2023-01-17 01:39:17 +00:00
|
|
|
|
2023-05-31 16:49:46 +00:00
|
|
|
impl<Marker, In, F> Condition<Marker, In> for F where F: sealed::Condition<Marker, In> {}
|
2023-01-17 01:39:17 +00:00
|
|
|
|
|
|
|
mod sealed {
|
2023-02-07 22:22:16 +00:00
|
|
|
use crate::system::{IntoSystem, ReadOnlySystem};
|
2023-01-17 01:39:17 +00:00
|
|
|
|
2023-05-31 16:49:46 +00:00
|
|
|
pub trait Condition<Marker, In>:
|
|
|
|
IntoSystem<In, bool, Marker, System = Self::ReadOnlySystem>
|
2023-02-16 16:45:48 +00:00
|
|
|
{
|
|
|
|
// This associated type is necessary to let the compiler
|
|
|
|
// know that `Self::System` is `ReadOnlySystem`.
|
2023-05-31 16:49:46 +00:00
|
|
|
type ReadOnlySystem: ReadOnlySystem<In = In, Out = bool>;
|
2023-02-16 16:45:48 +00:00
|
|
|
}
|
2023-01-17 01:39:17 +00:00
|
|
|
|
2023-05-31 16:49:46 +00:00
|
|
|
impl<Marker, In, F> Condition<Marker, In> for F
|
2023-01-17 01:39:17 +00:00
|
|
|
where
|
2023-05-31 16:49:46 +00:00
|
|
|
F: IntoSystem<In, bool, Marker>,
|
2023-02-07 22:22:16 +00:00
|
|
|
F::System: ReadOnlySystem,
|
2023-01-17 01:39:17 +00:00
|
|
|
{
|
2023-02-16 16:45:48 +00:00
|
|
|
type ReadOnlySystem = F::System;
|
2023-01-17 01:39:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-10 23:23:48 +00:00
|
|
|
/// A collection of [run conditions](Condition) that may be useful in any bevy app.
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
pub mod common_conditions {
|
2024-08-26 18:32:44 +00:00
|
|
|
use super::{Condition, NotSystem};
|
2023-02-08 23:24:36 +00:00
|
|
|
use crate::{
|
2023-02-20 22:56:56 +00:00
|
|
|
change_detection::DetectChanges,
|
|
|
|
event::{Event, EventReader},
|
|
|
|
prelude::{Component, Query, With},
|
2023-04-18 14:18:09 +00:00
|
|
|
removal_detection::RemovedComponents,
|
2024-08-26 18:32:44 +00:00
|
|
|
system::{In, IntoSystem, Local, Res, Resource, System},
|
2023-02-08 23:24:36 +00:00
|
|
|
};
|
2023-01-17 01:39:17 +00:00
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
/// on the first time the condition is run and false every time after.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `run_once` will only return true the first time it's evaluated
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
/// my_system.run_if(run_once),
|
2023-03-13 15:39:25 +00:00
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // This is the first time the condition will be evaluated so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // This is the seconds time the condition will be evaluated so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
pub fn run_once(mut has_run: Local<bool>) -> bool {
|
|
|
|
if !*has_run {
|
|
|
|
*has_run = true;
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-01-17 01:39:17 +00:00
|
|
|
/// if the resource exists.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-07-10 00:11:51 +00:00
|
|
|
/// // `resource_exists` will only return true if the given resource exists in the world
|
2024-01-13 13:22:17 +00:00
|
|
|
/// my_system.run_if(resource_exists::<Counter>),
|
2023-03-13 15:39:25 +00:00
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `Counter` hasn't been added so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// world.init_resource::<Counter>();
|
|
|
|
///
|
|
|
|
/// // `Counter` has now been added so `my_system` can run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
2024-01-13 13:22:17 +00:00
|
|
|
pub fn resource_exists<T>(res: Option<Res<T>>) -> bool
|
2023-01-17 01:39:17 +00:00
|
|
|
where
|
|
|
|
T: Resource,
|
|
|
|
{
|
2024-01-13 13:22:17 +00:00
|
|
|
res.is_some()
|
2023-01-17 01:39:17 +00:00
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// Generates a [`Condition`]-satisfying closure that returns `true`
|
2023-01-17 01:39:17 +00:00
|
|
|
/// if the resource is equal to `value`.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// The condition will panic if the resource does not exist.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default, PartialEq)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_equals` will only return true if the given resource equals the given value
|
|
|
|
/// my_system.run_if(resource_equals(Counter(0))),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `Counter` is `0` so `my_system` can run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // `Counter` is no longer `0` so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
2023-01-17 01:39:17 +00:00
|
|
|
pub fn resource_equals<T>(value: T) -> impl FnMut(Res<T>) -> bool
|
|
|
|
where
|
|
|
|
T: Resource + PartialEq,
|
|
|
|
{
|
|
|
|
move |res: Res<T>| *res == value
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// Generates a [`Condition`]-satisfying closure that returns `true`
|
2023-01-17 01:39:17 +00:00
|
|
|
/// if the resource exists and is equal to `value`.
|
|
|
|
///
|
|
|
|
/// The condition will return `false` if the resource does not exist.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default, PartialEq)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_exists_and_equals` will only return true
|
2023-07-10 00:11:51 +00:00
|
|
|
/// // if the given resource exists and equals the given value
|
2023-03-13 15:39:25 +00:00
|
|
|
/// my_system.run_if(resource_exists_and_equals(Counter(0))),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `Counter` hasn't been added so `my_system` can't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// world.init_resource::<Counter>();
|
|
|
|
///
|
|
|
|
/// // `Counter` is `0` so `my_system` can run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // `Counter` is no longer `0` so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
2023-01-17 01:39:17 +00:00
|
|
|
pub fn resource_exists_and_equals<T>(value: T) -> impl FnMut(Option<Res<T>>) -> bool
|
|
|
|
where
|
|
|
|
T: Resource + PartialEq,
|
|
|
|
{
|
|
|
|
move |res: Option<Res<T>>| match res {
|
|
|
|
Some(res) => *res == value,
|
|
|
|
None => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if the resource of the given type has been added since the condition was last checked.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_added` will only return true if the
|
|
|
|
/// // given resource was just added
|
2024-01-13 13:22:17 +00:00
|
|
|
/// my_system.run_if(resource_added::<Counter>),
|
2023-03-13 15:39:25 +00:00
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// world.init_resource::<Counter>();
|
|
|
|
///
|
|
|
|
/// // `Counter` was just added so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // `Counter` was not just added so `my_system` will not run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
2024-01-13 13:22:17 +00:00
|
|
|
pub fn resource_added<T>(res: Option<Res<T>>) -> bool
|
2023-02-20 22:56:56 +00:00
|
|
|
where
|
|
|
|
T: Resource,
|
|
|
|
{
|
2024-01-13 13:22:17 +00:00
|
|
|
match res {
|
2023-02-20 22:56:56 +00:00
|
|
|
Some(res) => res.is_added(),
|
|
|
|
None => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if the resource of the given type has had its value changed since the condition
|
|
|
|
/// was last checked.
|
|
|
|
///
|
|
|
|
/// The value is considered changed when it is added. The first time this condition
|
|
|
|
/// is checked after the resource was added, it will return `true`.
|
|
|
|
/// Change detection behaves like this everywhere in Bevy.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// The condition will panic if the resource does not exist.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_changed` will only return true if the
|
|
|
|
/// // given resource was just changed (or added)
|
|
|
|
/// my_system.run_if(
|
2024-01-13 13:22:17 +00:00
|
|
|
/// resource_changed::<Counter>
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // By default detecting changes will also trigger if the resource was
|
2023-07-10 00:11:51 +00:00
|
|
|
/// // just added, this won't work with my example so I will add a second
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // condition to make sure the resource wasn't just added
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// .and(not(resource_added::<Counter>))
|
2023-03-13 15:39:25 +00:00
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `Counter` hasn't been changed so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
///
|
|
|
|
/// world.resource_mut::<Counter>().0 = 50;
|
|
|
|
///
|
|
|
|
/// // `Counter` was just changed so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 51);
|
|
|
|
/// ```
|
2024-01-13 13:22:17 +00:00
|
|
|
pub fn resource_changed<T>(res: Res<T>) -> bool
|
2023-02-20 22:56:56 +00:00
|
|
|
where
|
|
|
|
T: Resource,
|
|
|
|
{
|
2024-01-13 13:22:17 +00:00
|
|
|
res.is_changed()
|
2023-02-20 22:56:56 +00:00
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if the resource of the given type has had its value changed since the condition
|
|
|
|
/// was last checked.
|
|
|
|
///
|
|
|
|
/// The value is considered changed when it is added. The first time this condition
|
|
|
|
/// is checked after the resource was added, it will return `true`.
|
|
|
|
/// Change detection behaves like this everywhere in Bevy.
|
|
|
|
///
|
|
|
|
/// This run condition does not detect when the resource is removed.
|
|
|
|
///
|
|
|
|
/// The condition will return `false` if the resource does not exist.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_exists_and_changed` will only return true if the
|
2023-07-10 00:11:51 +00:00
|
|
|
/// // given resource exists and was just changed (or added)
|
2023-03-13 15:39:25 +00:00
|
|
|
/// my_system.run_if(
|
2024-01-13 13:22:17 +00:00
|
|
|
/// resource_exists_and_changed::<Counter>
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // By default detecting changes will also trigger if the resource was
|
2023-07-10 00:11:51 +00:00
|
|
|
/// // just added, this won't work with my example so I will add a second
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // condition to make sure the resource wasn't just added
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// .and(not(resource_added::<Counter>))
|
2023-03-13 15:39:25 +00:00
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `Counter` doesn't exist so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// world.init_resource::<Counter>();
|
|
|
|
///
|
|
|
|
/// // `Counter` hasn't been changed so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
///
|
|
|
|
/// world.resource_mut::<Counter>().0 = 50;
|
|
|
|
///
|
|
|
|
/// // `Counter` was just changed so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 51);
|
|
|
|
/// ```
|
2024-01-13 13:22:17 +00:00
|
|
|
pub fn resource_exists_and_changed<T>(res: Option<Res<T>>) -> bool
|
2023-02-20 22:56:56 +00:00
|
|
|
where
|
|
|
|
T: Resource,
|
|
|
|
{
|
2024-01-13 13:22:17 +00:00
|
|
|
match res {
|
2023-02-20 22:56:56 +00:00
|
|
|
Some(res) => res.is_changed(),
|
|
|
|
None => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if the resource of the given type has had its value changed since the condition
|
|
|
|
/// was last checked.
|
|
|
|
///
|
|
|
|
/// The value is considered changed when it is added. The first time this condition
|
|
|
|
/// is checked after the resource was added, it will return `true`.
|
|
|
|
/// Change detection behaves like this everywhere in Bevy.
|
|
|
|
///
|
|
|
|
/// This run condition also detects removal. It will return `true` if the resource
|
|
|
|
/// has been removed since the run condition was last checked.
|
|
|
|
///
|
|
|
|
/// The condition will return `false` if the resource does not exist.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_changed_or_removed` will only return true if the
|
|
|
|
/// // given resource was just changed or removed (or added)
|
|
|
|
/// my_system.run_if(
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
/// resource_changed_or_removed::<Counter>
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // By default detecting changes will also trigger if the resource was
|
2023-07-10 00:11:51 +00:00
|
|
|
/// // just added, this won't work with my example so I will add a second
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // condition to make sure the resource wasn't just added
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
/// .and(not(resource_added::<Counter>))
|
2023-03-13 15:39:25 +00:00
|
|
|
/// ),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, Default)]
|
|
|
|
/// struct MyResource;
|
|
|
|
///
|
|
|
|
/// // If `Counter` exists, increment it, otherwise insert `MyResource`
|
|
|
|
/// fn my_system(mut commands: Commands, mut counter: Option<ResMut<Counter>>) {
|
|
|
|
/// if let Some(mut counter) = counter {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// } else {
|
|
|
|
/// commands.init_resource::<MyResource>();
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `Counter` hasn't been changed so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
///
|
|
|
|
/// world.resource_mut::<Counter>().0 = 50;
|
|
|
|
///
|
|
|
|
/// // `Counter` was just changed so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 51);
|
|
|
|
///
|
|
|
|
/// world.remove_resource::<Counter>();
|
|
|
|
///
|
|
|
|
/// // `Counter` was just removed so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.contains_resource::<MyResource>(), true);
|
|
|
|
/// ```
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
pub fn resource_changed_or_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
|
2023-02-20 22:56:56 +00:00
|
|
|
where
|
|
|
|
T: Resource,
|
|
|
|
{
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
if let Some(value) = res {
|
|
|
|
*existed = true;
|
|
|
|
value.is_changed()
|
|
|
|
} else if *existed {
|
|
|
|
*existed = false;
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2023-02-20 22:56:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if the resource of the given type has been removed since the condition was last checked.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `resource_removed` will only return true if the
|
|
|
|
/// // given resource was just removed
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
/// my_system.run_if(resource_removed::<MyResource>),
|
2023-03-13 15:39:25 +00:00
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// #[derive(Resource, Default)]
|
|
|
|
/// struct MyResource;
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// world.init_resource::<MyResource>();
|
|
|
|
///
|
|
|
|
/// // `MyResource` hasn't just been removed so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
///
|
|
|
|
/// world.remove_resource::<MyResource>();
|
|
|
|
///
|
|
|
|
/// // `MyResource` was just removed so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
pub fn resource_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
|
2023-02-20 22:56:56 +00:00
|
|
|
where
|
|
|
|
T: Resource,
|
|
|
|
{
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
if res.is_some() {
|
|
|
|
*existed = true;
|
|
|
|
false
|
|
|
|
} else if *existed {
|
|
|
|
*existed = false;
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
2023-02-20 22:56:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if there are any new events of the given type since it was last called.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
|
|
|
/// # world.init_resource::<Events<MyEvent>>();
|
Optimize Event Updates (#12936)
# Objective
Improve performance scalability when adding new event types to a Bevy
app. Currently, just using Bevy in the default configuration, all apps
spend upwards of 100+us in the `First` schedule, every app tick,
evaluating if it should update events or not, even if events are not
being used for that particular frame, and this scales with the number of
Events registered in the app.
## Solution
As `Events::update` is guaranteed `O(1)` by just checking if a
resource's value, swapping two Vecs, and then clearing one of them, the
actual cost of running `event_update_system` is *very* cheap. The
overhead of doing system dependency injection, task scheduling ,and the
multithreaded executor outweighs the cost of running the system by a
large margin.
Create an `EventRegistry` resource that keeps a number of function
pointers that update each event. Replace the per-event type
`event_update_system` with a singular exclusive system uses the
`EventRegistry` to update all events instead. Update `SubApp::add_event`
to use `EventRegistry` instead.
## Performance
This speeds reduces the cost of the `First` schedule in both many_foxes
and many_cubes by over 80%. Note this is with system spans on. The
majority of this is now context-switching costs from launching
`time_system`, which should be mostly eliminated with #12869.
![image](https://github.com/bevyengine/bevy/assets/3137680/037624be-21a2-4dc2-a42f-9d0bfa3e9b4a)
The actual `event_update_system` is usually *very* short, using only a
few microseconds on average.
![image](https://github.com/bevyengine/bevy/assets/3137680/01ff1689-3595-49b6-8f09-5c44bcf903e8)
---
## Changelog
TODO
## Migration Guide
TODO
---------
Co-authored-by: Josh Matthews <josh@joshmatthews.net>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-04-13 14:11:28 +00:00
|
|
|
/// # app.add_systems(bevy_ecs::event::event_update_system.before(my_system));
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
/// my_system.run_if(on_event::<MyEvent>),
|
2023-03-13 15:39:25 +00:00
|
|
|
/// );
|
|
|
|
///
|
2023-06-06 14:44:32 +00:00
|
|
|
/// #[derive(Event)]
|
2023-03-13 15:39:25 +00:00
|
|
|
/// struct MyEvent;
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // No new `MyEvent` events have been push so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
///
|
|
|
|
/// world.resource_mut::<Events<MyEvent>>().send(MyEvent);
|
|
|
|
///
|
2023-03-28 17:03:39 +00:00
|
|
|
/// // A `MyEvent` event has been pushed so `my_system` will run
|
2023-03-13 15:39:25 +00:00
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
pub fn on_event<T: Event>(mut reader: EventReader<T>) -> bool {
|
2023-02-20 22:56:56 +00:00
|
|
|
// 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.
|
|
|
|
// PERF: note that `count` is efficient (not actually looping/iterating),
|
|
|
|
// due to Bevy having a specialized implementation for events.
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
reader.read().count() > 0
|
2023-02-20 22:56:56 +00:00
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-02-20 22:56:56 +00:00
|
|
|
/// if there are any entities with the given component type.
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2024-01-13 13:22:17 +00:00
|
|
|
/// my_system.run_if(any_with_component::<MyComponent>),
|
2023-03-13 15:39:25 +00:00
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// #[derive(Component)]
|
|
|
|
/// struct MyComponent;
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // No entities exist yet with a `MyComponent` component so `my_system` won't run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
///
|
|
|
|
/// world.spawn(MyComponent);
|
|
|
|
///
|
|
|
|
/// // An entities with `MyComponent` now exists so `my_system` will run
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// ```
|
2024-01-13 13:22:17 +00:00
|
|
|
pub fn any_with_component<T: Component>(query: Query<(), With<T>>) -> bool {
|
|
|
|
!query.is_empty()
|
2023-02-20 22:56:56 +00:00
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// A [`Condition`]-satisfying system that returns `true`
|
2023-04-18 14:18:09 +00:00
|
|
|
/// if there are any entity with a component of the given type removed.
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
pub fn any_component_removed<T: Component>(mut removals: RemovedComponents<T>) -> bool {
|
2023-04-18 14:18:09 +00:00
|
|
|
// `RemovedComponents` based on events and therefore 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.
|
|
|
|
// PERF: note that `count` is efficient (not actually looping/iterating),
|
|
|
|
// due to Bevy having a specialized implementation for events.
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
removals.read().count() > 0
|
2023-04-18 14:18:09 +00:00
|
|
|
}
|
|
|
|
|
2024-08-26 18:32:44 +00:00
|
|
|
/// Generates a [`Condition`] that inverses the result of passed one.
|
2023-02-08 23:24:36 +00:00
|
|
|
///
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # Example
|
2023-02-08 23:24:36 +00:00
|
|
|
///
|
|
|
|
/// ```
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
2023-08-28 20:44:48 +00:00
|
|
|
/// # let mut app = Schedule::default();
|
2023-02-08 23:24:36 +00:00
|
|
|
/// # let mut world = World::new();
|
2023-03-13 15:39:25 +00:00
|
|
|
/// # world.init_resource::<Counter>();
|
2023-03-18 01:45:34 +00:00
|
|
|
/// app.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
/// // `not` will inverse any condition you pass in.
|
|
|
|
/// // Since the condition we choose always returns true
|
|
|
|
/// // this system will never run
|
|
|
|
/// my_system.run_if(not(always)),
|
|
|
|
/// );
|
2023-02-08 23:24:36 +00:00
|
|
|
///
|
2023-03-13 15:39:25 +00:00
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
2023-02-08 23:24:36 +00:00
|
|
|
/// }
|
2023-03-13 15:39:25 +00:00
|
|
|
///
|
|
|
|
/// fn always() -> bool {
|
|
|
|
/// true
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 0);
|
2023-02-08 23:24:36 +00:00
|
|
|
/// ```
|
2023-03-17 21:37:16 +00:00
|
|
|
pub fn not<Marker, TOut, T>(condition: T) -> NotSystem<T::System>
|
2023-03-13 19:38:04 +00:00
|
|
|
where
|
2023-03-17 21:37:16 +00:00
|
|
|
TOut: std::ops::Not,
|
|
|
|
T: IntoSystem<(), TOut, Marker>,
|
2023-03-13 19:38:04 +00:00
|
|
|
{
|
2023-03-17 21:37:16 +00:00
|
|
|
let condition = IntoSystem::into_system(condition);
|
|
|
|
let name = format!("!{}", condition.name());
|
2023-08-28 16:36:46 +00:00
|
|
|
NotSystem::new(super::NotMarker, condition, name.into())
|
2023-03-17 21:37:16 +00:00
|
|
|
}
|
2024-08-26 18:32:44 +00:00
|
|
|
|
|
|
|
/// Generates a [`Condition`] that returns true when the passed one changes.
|
|
|
|
///
|
|
|
|
/// The first time this is called, the passed condition is assumed to have been previously false.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
|
|
|
/// app.add_systems(
|
|
|
|
/// my_system.run_if(condition_changed(resource_exists::<MyResource>)),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// #[derive(Resource)]
|
|
|
|
/// struct MyResource;
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `MyResource` is initially there, the inner condition is true, the system runs once
|
|
|
|
/// world.insert_resource(MyResource);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // We remove `MyResource`, the inner condition is now false, the system runs one more time.
|
|
|
|
/// world.remove_resource::<MyResource>();
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
|
|
|
/// ```
|
|
|
|
pub fn condition_changed<Marker, CIn, C: Condition<Marker, CIn>>(
|
|
|
|
condition: C,
|
|
|
|
) -> impl Condition<(), CIn> {
|
|
|
|
condition.pipe(|In(new): In<bool>, mut prev: Local<bool>| -> bool {
|
|
|
|
let changed = *prev != new;
|
|
|
|
*prev = new;
|
|
|
|
changed
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Generates a [`Condition`] that returns true when the result of
|
|
|
|
/// the passed one went from false to true since the last time this was called.
|
|
|
|
///
|
|
|
|
/// The first time this is called, the passed condition is assumed to have been previously false.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_ecs::prelude::*;
|
|
|
|
/// # #[derive(Resource, Default)]
|
|
|
|
/// # struct Counter(u8);
|
|
|
|
/// # let mut app = Schedule::default();
|
|
|
|
/// # let mut world = World::new();
|
|
|
|
/// # world.init_resource::<Counter>();
|
|
|
|
/// app.add_systems(
|
|
|
|
/// my_system.run_if(condition_changed_to(true, resource_exists::<MyResource>)),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// #[derive(Resource)]
|
|
|
|
/// struct MyResource;
|
|
|
|
///
|
|
|
|
/// fn my_system(mut counter: ResMut<Counter>) {
|
|
|
|
/// counter.0 += 1;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// // `MyResource` is initially there, the inner condition is true, the system runs once
|
|
|
|
/// world.insert_resource(MyResource);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // We remove `MyResource`, the inner condition is now false, the system doesn't run.
|
|
|
|
/// world.remove_resource::<MyResource>();
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
///
|
|
|
|
/// // We reinsert `MyResource` again, so the system will run one more time
|
|
|
|
/// world.insert_resource(MyResource);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
|
|
|
/// app.run(&mut world);
|
|
|
|
/// assert_eq!(world.resource::<Counter>().0, 2);
|
|
|
|
/// ```
|
|
|
|
pub fn condition_changed_to<Marker, CIn, C: Condition<Marker, CIn>>(
|
|
|
|
to: bool,
|
|
|
|
condition: C,
|
|
|
|
) -> impl Condition<(), CIn> {
|
|
|
|
condition.pipe(move |In(new): In<bool>, mut prev: Local<bool>| -> bool {
|
|
|
|
let now_true = *prev != new && new == to;
|
|
|
|
*prev = new;
|
|
|
|
now_true
|
|
|
|
})
|
|
|
|
}
|
2023-03-17 21:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Invokes [`Not`] with the output of another system.
|
|
|
|
///
|
|
|
|
/// See [`common_conditions::not`] for examples.
|
2023-08-28 16:36:46 +00:00
|
|
|
pub type NotSystem<T> = AdapterSystem<NotMarker, T>;
|
|
|
|
|
|
|
|
/// Used with [`AdapterSystem`] to negate the output of a system via the [`Not`] operator.
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct NotMarker;
|
|
|
|
|
|
|
|
impl<T: System> Adapt<T> for NotMarker
|
2023-03-17 21:37:16 +00:00
|
|
|
where
|
|
|
|
T::Out: Not,
|
|
|
|
{
|
|
|
|
type In = T::In;
|
|
|
|
type Out = <T::Out as Not>::Output;
|
|
|
|
|
2023-08-28 16:36:46 +00:00
|
|
|
fn adapt(&mut self, input: Self::In, run_system: impl FnOnce(T::In) -> T::Out) -> Self::Out {
|
|
|
|
!run_system(input)
|
2023-03-17 21:37:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-20 18:16:11 +00:00
|
|
|
/// Combines the outputs of two systems using the `&&` operator.
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
pub type And<A, B> = CombinatorSystem<AndMarker, A, B>;
|
|
|
|
|
|
|
|
/// Combines and inverts the outputs of two systems using the `&&` and `!` operators.
|
|
|
|
pub type Nand<A, B> = CombinatorSystem<NandMarker, A, B>;
|
|
|
|
|
|
|
|
/// Combines and inverts the outputs of two systems using the `&&` and `!` operators.
|
|
|
|
pub type Nor<A, B> = CombinatorSystem<NorMarker, A, B>;
|
2023-02-20 18:16:11 +00:00
|
|
|
|
|
|
|
/// Combines the outputs of two systems using the `||` operator.
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
pub type Or<A, B> = CombinatorSystem<OrMarker, A, B>;
|
|
|
|
|
|
|
|
/// Combines and inverts the outputs of two systems using the `^` and `!` operators.
|
|
|
|
pub type Xnor<A, B> = CombinatorSystem<XnorMarker, A, B>;
|
|
|
|
|
|
|
|
/// Combines the outputs of two systems using the `^` operator.
|
|
|
|
pub type Xor<A, B> = CombinatorSystem<XorMarker, A, B>;
|
2023-02-20 18:16:11 +00:00
|
|
|
|
|
|
|
#[doc(hidden)]
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
pub struct AndMarker;
|
2023-02-20 18:16:11 +00:00
|
|
|
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
impl<In, A, B> Combine<A, B> for AndMarker
|
2023-02-20 18:16:11 +00:00
|
|
|
where
|
|
|
|
In: Copy,
|
|
|
|
A: System<In = In, Out = bool>,
|
|
|
|
B: System<In = In, Out = bool>,
|
|
|
|
{
|
|
|
|
type In = In;
|
|
|
|
type Out = bool;
|
|
|
|
|
|
|
|
fn combine(
|
|
|
|
input: Self::In,
|
|
|
|
a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
|
|
|
|
b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
|
|
|
|
) -> Self::Out {
|
|
|
|
a(input) && b(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
pub struct NandMarker;
|
|
|
|
|
|
|
|
impl<In, A, B> Combine<A, B> for NandMarker
|
|
|
|
where
|
|
|
|
In: Copy,
|
|
|
|
A: System<In = In, Out = bool>,
|
|
|
|
B: System<In = In, Out = bool>,
|
|
|
|
{
|
|
|
|
type In = In;
|
|
|
|
type Out = bool;
|
|
|
|
|
|
|
|
fn combine(
|
|
|
|
input: Self::In,
|
|
|
|
a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
|
|
|
|
b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
|
|
|
|
) -> Self::Out {
|
|
|
|
!(a(input) && b(input))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct NorMarker;
|
2023-02-20 18:16:11 +00:00
|
|
|
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
impl<In, A, B> Combine<A, B> for NorMarker
|
|
|
|
where
|
|
|
|
In: Copy,
|
|
|
|
A: System<In = In, Out = bool>,
|
|
|
|
B: System<In = In, Out = bool>,
|
|
|
|
{
|
|
|
|
type In = In;
|
|
|
|
type Out = bool;
|
|
|
|
|
|
|
|
fn combine(
|
|
|
|
input: Self::In,
|
|
|
|
a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
|
|
|
|
b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
|
|
|
|
) -> Self::Out {
|
|
|
|
!(a(input) || b(input))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct OrMarker;
|
|
|
|
|
|
|
|
impl<In, A, B> Combine<A, B> for OrMarker
|
2023-02-20 18:16:11 +00:00
|
|
|
where
|
|
|
|
In: Copy,
|
|
|
|
A: System<In = In, Out = bool>,
|
|
|
|
B: System<In = In, Out = bool>,
|
|
|
|
{
|
|
|
|
type In = In;
|
|
|
|
type Out = bool;
|
|
|
|
|
|
|
|
fn combine(
|
|
|
|
input: Self::In,
|
|
|
|
a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
|
|
|
|
b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
|
|
|
|
) -> Self::Out {
|
|
|
|
a(input) || b(input)
|
|
|
|
}
|
|
|
|
}
|
2023-03-13 15:39:25 +00:00
|
|
|
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct XnorMarker;
|
|
|
|
|
|
|
|
impl<In, A, B> Combine<A, B> for XnorMarker
|
|
|
|
where
|
|
|
|
In: Copy,
|
|
|
|
A: System<In = In, Out = bool>,
|
|
|
|
B: System<In = In, Out = bool>,
|
|
|
|
{
|
|
|
|
type In = In;
|
|
|
|
type Out = bool;
|
|
|
|
|
|
|
|
fn combine(
|
|
|
|
input: Self::In,
|
|
|
|
a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
|
|
|
|
b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
|
|
|
|
) -> Self::Out {
|
|
|
|
!(a(input) ^ b(input))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct XorMarker;
|
|
|
|
|
|
|
|
impl<In, A, B> Combine<A, B> for XorMarker
|
|
|
|
where
|
|
|
|
In: Copy,
|
|
|
|
A: System<In = In, Out = bool>,
|
|
|
|
B: System<In = In, Out = bool>,
|
|
|
|
{
|
|
|
|
type In = In;
|
|
|
|
type Out = bool;
|
|
|
|
|
|
|
|
fn combine(
|
|
|
|
input: Self::In,
|
|
|
|
a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
|
|
|
|
b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
|
|
|
|
) -> Self::Out {
|
|
|
|
a(input) ^ b(input)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-13 15:39:25 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2023-03-17 21:37:16 +00:00
|
|
|
use super::{common_conditions::*, Condition};
|
2023-03-13 15:39:25 +00:00
|
|
|
use crate as bevy_ecs;
|
2023-03-18 01:45:34 +00:00
|
|
|
use crate::component::Component;
|
|
|
|
use crate::schedule::IntoSystemConfigs;
|
|
|
|
use crate::system::Local;
|
|
|
|
use crate::{change_detection::ResMut, schedule::Schedule, world::World};
|
2023-06-06 14:44:32 +00:00
|
|
|
use bevy_ecs_macros::Event;
|
2023-03-13 15:39:25 +00:00
|
|
|
use bevy_ecs_macros::Resource;
|
|
|
|
|
|
|
|
#[derive(Resource, Default)]
|
|
|
|
struct Counter(usize);
|
|
|
|
|
|
|
|
fn increment_counter(mut counter: ResMut<Counter>) {
|
|
|
|
counter.0 += 1;
|
|
|
|
}
|
|
|
|
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
fn double_counter(mut counter: ResMut<Counter>) {
|
|
|
|
counter.0 *= 2;
|
|
|
|
}
|
|
|
|
|
2023-03-13 15:39:25 +00:00
|
|
|
fn every_other_time(mut has_ran: Local<bool>) -> bool {
|
|
|
|
*has_ran = !*has_ran;
|
|
|
|
*has_ran
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn run_condition() {
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Counter>();
|
2023-08-28 20:44:48 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
// Run every other cycle
|
2023-03-18 01:45:34 +00:00
|
|
|
schedule.add_systems(increment_counter.run_if(every_other_time));
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
schedule.run(&mut world);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 2);
|
|
|
|
|
2023-09-26 19:46:24 +00:00
|
|
|
// Run every other cycle opposite to the last one
|
2023-03-18 01:45:34 +00:00
|
|
|
schedule.add_systems(increment_counter.run_if(not(every_other_time)));
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
schedule.run(&mut world);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 4);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 6);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
#[allow(deprecated)]
|
2023-03-13 15:39:25 +00:00
|
|
|
fn run_condition_combinators() {
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Counter>();
|
2023-08-28 20:44:48 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
schedule.add_systems(
|
|
|
|
(
|
|
|
|
increment_counter.run_if(every_other_time.and(|| true)), // Run every odd cycle.
|
|
|
|
increment_counter.run_if(every_other_time.and_then(|| true)), // Run every odd cycle.
|
|
|
|
increment_counter.run_if(every_other_time.nand(|| false)), // Always run.
|
|
|
|
double_counter.run_if(every_other_time.nor(|| false)), // Run every even cycle.
|
|
|
|
increment_counter.run_if(every_other_time.or(|| true)), // Always run.
|
|
|
|
increment_counter.run_if(every_other_time.or_else(|| true)), // Always run.
|
|
|
|
increment_counter.run_if(every_other_time.xnor(|| true)), // Run every odd cycle.
|
|
|
|
double_counter.run_if(every_other_time.xnor(|| false)), // Run every even cycle.
|
|
|
|
increment_counter.run_if(every_other_time.xor(|| false)), // Run every odd cycle.
|
|
|
|
double_counter.run_if(every_other_time.xor(|| true)), // Run every even cycle.
|
|
|
|
)
|
|
|
|
.chain(),
|
|
|
|
);
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
schedule.run(&mut world);
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
assert_eq!(world.resource::<Counter>().0, 7);
|
2023-03-13 15:39:25 +00:00
|
|
|
schedule.run(&mut world);
|
Re-name and Extend Run Conditions API (#13784)
# Objective
- My attempt at fulfilling #13629.
## Solution
Renames the `and_then` / `or_else` run condition methods to `and` /
`or`, respectively.
Extends the run conditions API to include a suite of binary logical
operators:
- `and`
- `or`
- `nand`
- `nor`
- `xor`
- `xnor`
## Testing
- Did you test these changes? If so, how?
- The test **run_condition_combinators** was extended to include the
added run condition combinators. A **double_counter** system was added
to test for combinators running on even count cycles.
- Are there any parts that need more testing?
- I'm not too sure how I feel about the "counter" style of testing but I
wanted to keep it consistent. If it's just a unit test I would prefer
simply to just assert `true` == _combinator output_ or `false` ==
_combinator output_ .
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- Nothing too specific. The added methods should be equivalent to the
logical operators they are analogous to (`&&` , `||`, `^`, `!`).
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
- Should not be relevant, I'm using Windows.
## Changelog
- What changed as a result of this PR?
- The run conditions API.
- If applicable, organize changes under "Added", "Changed", or "Fixed"
sub-headings
- Changed:
- `and_then` run condition combinator renamed to simply `and`
- `or_else` run condition combinator renamed to simply `or`
- Added:
- `nand` run condition combinator.
- `nor` run condition combinator.
- `xor` run condition combinator.
- `xnor` run condition combinator.
## Migration Guide
- The `and_then` run condition method has been replaced with the `and`
run condition method.
- The `or_else` run condition method has been replaced with the `or` run
condition method.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Andres O. Vela <andresovela@users.noreply.github.com>
2024-06-10 13:41:56 +00:00
|
|
|
assert_eq!(world.resource::<Counter>().0, 72);
|
2023-03-13 15:39:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiple_run_conditions() {
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Counter>();
|
2023-08-28 20:44:48 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
// Run every other cycle
|
2023-03-18 01:45:34 +00:00
|
|
|
schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| true));
|
2023-03-13 15:39:25 +00:00
|
|
|
// Never run
|
2023-03-18 01:45:34 +00:00
|
|
|
schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| false));
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiple_run_conditions_is_and_operation() {
|
|
|
|
let mut world = World::new();
|
|
|
|
world.init_resource::<Counter>();
|
|
|
|
|
2023-08-28 20:44:48 +00:00
|
|
|
let mut schedule = Schedule::default();
|
2023-03-13 15:39:25 +00:00
|
|
|
|
|
|
|
// This should never run, if multiple run conditions worked
|
|
|
|
// like an OR condition then it would always run
|
2023-03-18 01:45:34 +00:00
|
|
|
schedule.add_systems(
|
2023-03-13 15:39:25 +00:00
|
|
|
increment_counter
|
|
|
|
.run_if(every_other_time)
|
|
|
|
.run_if(not(every_other_time)),
|
|
|
|
);
|
|
|
|
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
schedule.run(&mut world);
|
|
|
|
assert_eq!(world.resource::<Counter>().0, 0);
|
|
|
|
}
|
2023-03-17 21:37:16 +00:00
|
|
|
#[derive(Component)]
|
|
|
|
struct TestComponent;
|
|
|
|
|
2023-06-06 14:44:32 +00:00
|
|
|
#[derive(Event)]
|
|
|
|
struct TestEvent;
|
|
|
|
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
#[derive(Resource)]
|
|
|
|
struct TestResource(());
|
|
|
|
|
2023-03-17 21:37:16 +00:00
|
|
|
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)
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
.distributive_run_if(run_once)
|
Separate state crate (#13216)
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
2024-05-09 18:06:05 +00:00
|
|
|
.distributive_run_if(resource_exists::<TestResource>)
|
|
|
|
.distributive_run_if(resource_added::<TestResource>)
|
|
|
|
.distributive_run_if(resource_changed::<TestResource>)
|
|
|
|
.distributive_run_if(resource_exists_and_changed::<TestResource>)
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
.distributive_run_if(resource_changed_or_removed::<TestResource>)
|
|
|
|
.distributive_run_if(resource_removed::<TestResource>)
|
|
|
|
.distributive_run_if(on_event::<TestEvent>)
|
2024-01-13 13:22:17 +00:00
|
|
|
.distributive_run_if(any_with_component::<TestComponent>)
|
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>),
));
```
2024-07-22 19:21:47 +00:00
|
|
|
.distributive_run_if(not(run_once)),
|
2023-03-17 21:37:16 +00:00
|
|
|
);
|
|
|
|
}
|
2023-03-13 15:39:25 +00:00
|
|
|
}
|