mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Make the Condition
trait generic (#8721)
# Objective The `Condition` trait is only implemented for systems and system functions that take no input. This can make it awkward to write conditions that are intended to be used with system piping. ## Solution Add an `In` generic to the trait. It defaults to `()`. --- ## Changelog - Made the `Condition` trait generic over system inputs.
This commit is contained in:
parent
5b0f21c773
commit
233b26cc17
1 changed files with 53 additions and 11 deletions
|
@ -8,13 +8,55 @@ use crate::system::{CombinatorSystem, Combine, IntoSystem, ReadOnlySystem, Syste
|
|||
use crate::world::unsafe_world_cell::UnsafeWorldCell;
|
||||
use crate::world::World;
|
||||
|
||||
pub type BoxedCondition = Box<dyn ReadOnlySystem<In = (), Out = bool>>;
|
||||
pub type BoxedCondition<In = ()> = Box<dyn ReadOnlySystem<In = In, Out = bool>>;
|
||||
|
||||
/// A system that determines if one or more scheduled systems should run.
|
||||
///
|
||||
/// Implemented for functions and closures that convert into [`System<In=(), Out=bool>`](crate::system::System)
|
||||
/// Implemented for functions and closures that convert into [`System<Out=bool>`](crate::system::System)
|
||||
/// with [read-only](crate::system::ReadOnlySystemParam) parameters.
|
||||
pub trait Condition<Marker>: sealed::Condition<Marker> {
|
||||
///
|
||||
/// # 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; }
|
||||
/// # let mut schedule = Schedule::new();
|
||||
/// 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 }
|
||||
/// # let mut schedule = Schedule::new();
|
||||
/// # #[derive(Resource)] struct DidRun(bool);
|
||||
/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
|
||||
/// schedule.add_systems(my_system.run_if(always_true.pipe(identity())));
|
||||
/// # let mut world = World::new();
|
||||
/// # world.insert_resource(DidRun(false));
|
||||
/// # schedule.run(&mut world);
|
||||
/// # assert!(world.resource::<DidRun>().0);
|
||||
pub trait Condition<Marker, In = ()>: sealed::Condition<Marker, In> {
|
||||
/// Returns a new run condition that only returns `true`
|
||||
/// if both this one and the passed `and_then` return `true`.
|
||||
///
|
||||
|
@ -59,7 +101,7 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
|||
/// 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_then<M, C: Condition<M>>(self, and_then: C) -> AndThen<Self::System, C::System> {
|
||||
fn and_then<M, C: Condition<M, In>>(self, and_then: C) -> AndThen<Self::System, C::System> {
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(and_then);
|
||||
let name = format!("{} && {}", a.name(), b.name());
|
||||
|
@ -106,7 +148,7 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
|||
/// # app.run(&mut world);
|
||||
/// # assert!(world.resource::<C>().0);
|
||||
/// ```
|
||||
fn or_else<M, C: Condition<M>>(self, or_else: C) -> OrElse<Self::System, C::System> {
|
||||
fn or_else<M, C: Condition<M, In>>(self, or_else: C) -> OrElse<Self::System, C::System> {
|
||||
let a = IntoSystem::into_system(self);
|
||||
let b = IntoSystem::into_system(or_else);
|
||||
let name = format!("{} || {}", a.name(), b.name());
|
||||
|
@ -114,22 +156,22 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<Marker, F> Condition<Marker> for F where F: sealed::Condition<Marker> {}
|
||||
impl<Marker, In, F> Condition<Marker, In> for F where F: sealed::Condition<Marker, In> {}
|
||||
|
||||
mod sealed {
|
||||
use crate::system::{IntoSystem, ReadOnlySystem};
|
||||
|
||||
pub trait Condition<Marker>:
|
||||
IntoSystem<(), bool, Marker, System = Self::ReadOnlySystem>
|
||||
pub trait Condition<Marker, In>:
|
||||
IntoSystem<In, bool, Marker, System = Self::ReadOnlySystem>
|
||||
{
|
||||
// This associated type is necessary to let the compiler
|
||||
// know that `Self::System` is `ReadOnlySystem`.
|
||||
type ReadOnlySystem: ReadOnlySystem<In = (), Out = bool>;
|
||||
type ReadOnlySystem: ReadOnlySystem<In = In, Out = bool>;
|
||||
}
|
||||
|
||||
impl<Marker, F> Condition<Marker> for F
|
||||
impl<Marker, In, F> Condition<Marker, In> for F
|
||||
where
|
||||
F: IntoSystem<(), bool, Marker>,
|
||||
F: IntoSystem<In, bool, Marker>,
|
||||
F::System: ReadOnlySystem,
|
||||
{
|
||||
type ReadOnlySystem = F::System;
|
||||
|
|
Loading…
Reference in a new issue