bevy_ecs/schedule/
condition.rs

1use std::borrow::Cow;
2use std::ops::Not;
3
4use crate::system::{
5    Adapt, AdapterSystem, CombinatorSystem, Combine, IntoSystem, ReadOnlySystem, System,
6};
7
8/// A type-erased run condition stored in a [`Box`].
9pub type BoxedCondition<In = ()> = Box<dyn ReadOnlySystem<In = In, Out = bool>>;
10
11/// A system that determines if one or more scheduled systems should run.
12///
13/// Implemented for functions and closures that convert into [`System<Out=bool>`](System)
14/// with [read-only](crate::system::ReadOnlySystemParam) parameters.
15///
16/// # Marker type parameter
17///
18/// `Condition` trait has `Marker` type parameter, which has no special meaning,
19/// but exists to work around the limitation of Rust's trait system.
20///
21/// Type parameter in return type can be set to `<()>` by calling [`IntoSystem::into_system`],
22/// but usually have to be specified when passing a condition to a function.
23///
24/// ```
25/// # use bevy_ecs::schedule::Condition;
26/// # use bevy_ecs::system::IntoSystem;
27/// fn not_condition<Marker>(a: impl Condition<Marker>) -> impl Condition<()> {
28///    IntoSystem::into_system(a.map(|x| !x))
29/// }
30/// ```
31///
32/// # Examples
33/// A condition that returns true every other time it's called.
34/// ```
35/// # use bevy_ecs::prelude::*;
36/// fn every_other_time() -> impl Condition<()> {
37///     IntoSystem::into_system(|mut flag: Local<bool>| {
38///         *flag = !*flag;
39///         *flag
40///     })
41/// }
42///
43/// # #[derive(Resource)] struct DidRun(bool);
44/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
45/// # let mut schedule = Schedule::default();
46/// schedule.add_systems(my_system.run_if(every_other_time()));
47/// # let mut world = World::new();
48/// # world.insert_resource(DidRun(false));
49/// # schedule.run(&mut world);
50/// # assert!(world.resource::<DidRun>().0);
51/// # world.insert_resource(DidRun(false));
52/// # schedule.run(&mut world);
53/// # assert!(!world.resource::<DidRun>().0);
54/// ```
55///
56/// A condition that takes a bool as an input and returns it unchanged.
57///
58/// ```
59/// # use bevy_ecs::prelude::*;
60/// fn identity() -> impl Condition<(), bool> {
61///     IntoSystem::into_system(|In(x)| x)
62/// }
63///
64/// # fn always_true() -> bool { true }
65/// # let mut app = Schedule::default();
66/// # #[derive(Resource)] struct DidRun(bool);
67/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
68/// app.add_systems(my_system.run_if(always_true.pipe(identity())));
69/// # let mut world = World::new();
70/// # world.insert_resource(DidRun(false));
71/// # app.run(&mut world);
72/// # assert!(world.resource::<DidRun>().0);
73pub trait Condition<Marker, In = ()>: sealed::Condition<Marker, In> {
74    /// Returns a new run condition that only returns `true`
75    /// if both this one and the passed `and_then` return `true`.
76    ///
77    /// The returned run condition is short-circuiting, meaning
78    /// `and_then` will only be invoked if `self` returns `true`.
79    ///
80    /// # Examples
81    ///
82    /// ```should_panic
83    /// use bevy_ecs::prelude::*;
84    ///
85    /// #[derive(Resource, PartialEq)]
86    /// struct R(u32);
87    ///
88    /// # let mut app = Schedule::default();
89    /// # let mut world = World::new();
90    /// # fn my_system() {}
91    /// app.add_systems(
92    ///     // The `resource_equals` run condition will panic since we don't initialize `R`,
93    ///     // just like if we used `Res<R>` in a system.
94    ///     my_system.run_if(resource_equals(R(0))),
95    /// );
96    /// # app.run(&mut world);
97    /// ```
98    ///
99    /// Use `.and_then()` to avoid checking the condition.
100    ///
101    /// ```
102    /// # use bevy_ecs::prelude::*;
103    /// # #[derive(Resource, PartialEq)]
104    /// # struct R(u32);
105    /// # let mut app = Schedule::default();
106    /// # let mut world = World::new();
107    /// # fn my_system() {}
108    /// app.add_systems(
109    ///     // `resource_equals` will only get run if the resource `R` exists.
110    ///     my_system.run_if(resource_exists::<R>.and_then(resource_equals(R(0)))),
111    /// );
112    /// # app.run(&mut world);
113    /// ```
114    ///
115    /// Note that in this case, it's better to just use the run condition [`resource_exists_and_equals`].
116    ///
117    /// [`resource_exists_and_equals`]: common_conditions::resource_exists_and_equals
118    fn and_then<M, C: Condition<M, In>>(self, and_then: C) -> AndThen<Self::System, C::System> {
119        let a = IntoSystem::into_system(self);
120        let b = IntoSystem::into_system(and_then);
121        let name = format!("{} && {}", a.name(), b.name());
122        CombinatorSystem::new(a, b, Cow::Owned(name))
123    }
124
125    /// Returns a new run condition that returns `true`
126    /// if either this one or the passed `or_else` return `true`.
127    ///
128    /// The returned run condition is short-circuiting, meaning
129    /// `or_else` will only be invoked if `self` returns `false`.
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// use bevy_ecs::prelude::*;
135    ///
136    /// #[derive(Resource, PartialEq)]
137    /// struct A(u32);
138    ///
139    /// #[derive(Resource, PartialEq)]
140    /// struct B(u32);
141    ///
142    /// # let mut app = Schedule::default();
143    /// # let mut world = World::new();
144    /// # #[derive(Resource)] struct C(bool);
145    /// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
146    /// app.add_systems(
147    ///     // Only run the system if either `A` or `B` exist.
148    ///     my_system.run_if(resource_exists::<A>.or_else(resource_exists::<B>)),
149    /// );
150    /// #
151    /// # world.insert_resource(C(false));
152    /// # app.run(&mut world);
153    /// # assert!(!world.resource::<C>().0);
154    /// #
155    /// # world.insert_resource(A(0));
156    /// # app.run(&mut world);
157    /// # assert!(world.resource::<C>().0);
158    /// #
159    /// # world.remove_resource::<A>();
160    /// # world.insert_resource(B(0));
161    /// # world.insert_resource(C(false));
162    /// # app.run(&mut world);
163    /// # assert!(world.resource::<C>().0);
164    /// ```
165    fn or_else<M, C: Condition<M, In>>(self, or_else: C) -> OrElse<Self::System, C::System> {
166        let a = IntoSystem::into_system(self);
167        let b = IntoSystem::into_system(or_else);
168        let name = format!("{} || {}", a.name(), b.name());
169        CombinatorSystem::new(a, b, Cow::Owned(name))
170    }
171}
172
173impl<Marker, In, F> Condition<Marker, In> for F where F: sealed::Condition<Marker, In> {}
174
175mod sealed {
176    use crate::system::{IntoSystem, ReadOnlySystem};
177
178    pub trait Condition<Marker, In>:
179        IntoSystem<In, bool, Marker, System = Self::ReadOnlySystem>
180    {
181        // This associated type is necessary to let the compiler
182        // know that `Self::System` is `ReadOnlySystem`.
183        type ReadOnlySystem: ReadOnlySystem<In = In, Out = bool>;
184    }
185
186    impl<Marker, In, F> Condition<Marker, In> for F
187    where
188        F: IntoSystem<In, bool, Marker>,
189        F::System: ReadOnlySystem,
190    {
191        type ReadOnlySystem = F::System;
192    }
193}
194
195/// A collection of [run conditions](Condition) that may be useful in any bevy app.
196pub mod common_conditions {
197    use super::NotSystem;
198    use crate::{
199        change_detection::DetectChanges,
200        event::{Event, EventReader},
201        prelude::{Component, Query, With},
202        removal_detection::RemovedComponents,
203        system::{IntoSystem, Res, Resource, System},
204    };
205
206    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
207    /// if the first time the condition is run and false every time after
208    ///
209    /// # Example
210    ///
211    /// ```
212    /// # use bevy_ecs::prelude::*;
213    /// # #[derive(Resource, Default)]
214    /// # struct Counter(u8);
215    /// # let mut app = Schedule::default();
216    /// # let mut world = World::new();
217    /// # world.init_resource::<Counter>();
218    /// app.add_systems(
219    ///     // `run_once` will only return true the first time it's evaluated
220    ///     my_system.run_if(run_once()),
221    /// );
222    ///
223    /// fn my_system(mut counter: ResMut<Counter>) {
224    ///     counter.0 += 1;
225    /// }
226    ///
227    /// // This is the first time the condition will be evaluated so `my_system` will run
228    /// app.run(&mut world);
229    /// assert_eq!(world.resource::<Counter>().0, 1);
230    ///
231    /// // This is the seconds time the condition will be evaluated so `my_system` won't run
232    /// app.run(&mut world);
233    /// assert_eq!(world.resource::<Counter>().0, 1);
234    /// ```
235    pub fn run_once() -> impl FnMut() -> bool + Clone {
236        let mut has_run = false;
237        move || {
238            if !has_run {
239                has_run = true;
240                true
241            } else {
242                false
243            }
244        }
245    }
246
247    /// A [`Condition`](super::Condition)-satisfying system that returns `true`
248    /// if the resource exists.
249    ///
250    /// # Example
251    ///
252    /// ```
253    /// # use bevy_ecs::prelude::*;
254    /// # #[derive(Resource, Default)]
255    /// # struct Counter(u8);
256    /// # let mut app = Schedule::default();
257    /// # let mut world = World::new();
258    /// app.add_systems(
259    ///     // `resource_exists` will only return true if the given resource exists in the world
260    ///     my_system.run_if(resource_exists::<Counter>),
261    /// );
262    ///
263    /// fn my_system(mut counter: ResMut<Counter>) {
264    ///     counter.0 += 1;
265    /// }
266    ///
267    /// // `Counter` hasn't been added so `my_system` won't run
268    /// app.run(&mut world);
269    /// world.init_resource::<Counter>();
270    ///
271    /// // `Counter` has now been added so `my_system` can run
272    /// app.run(&mut world);
273    /// assert_eq!(world.resource::<Counter>().0, 1);
274    /// ```
275    pub fn resource_exists<T>(res: Option<Res<T>>) -> bool
276    where
277        T: Resource,
278    {
279        res.is_some()
280    }
281
282    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
283    /// if the resource is equal to `value`.
284    ///
285    /// # Panics
286    ///
287    /// The condition will panic if the resource does not exist.
288    ///
289    /// # Example
290    ///
291    /// ```
292    /// # use bevy_ecs::prelude::*;
293    /// # #[derive(Resource, Default, PartialEq)]
294    /// # struct Counter(u8);
295    /// # let mut app = Schedule::default();
296    /// # let mut world = World::new();
297    /// # world.init_resource::<Counter>();
298    /// app.add_systems(
299    ///     // `resource_equals` will only return true if the given resource equals the given value
300    ///     my_system.run_if(resource_equals(Counter(0))),
301    /// );
302    ///
303    /// fn my_system(mut counter: ResMut<Counter>) {
304    ///     counter.0 += 1;
305    /// }
306    ///
307    /// // `Counter` is `0` so `my_system` can run
308    /// app.run(&mut world);
309    /// assert_eq!(world.resource::<Counter>().0, 1);
310    ///
311    /// // `Counter` is no longer `0` so `my_system` won't run
312    /// app.run(&mut world);
313    /// assert_eq!(world.resource::<Counter>().0, 1);
314    /// ```
315    pub fn resource_equals<T>(value: T) -> impl FnMut(Res<T>) -> bool
316    where
317        T: Resource + PartialEq,
318    {
319        move |res: Res<T>| *res == value
320    }
321
322    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
323    /// if the resource exists and is equal to `value`.
324    ///
325    /// The condition will return `false` if the resource does not exist.
326    ///
327    /// # Example
328    ///
329    /// ```
330    /// # use bevy_ecs::prelude::*;
331    /// # #[derive(Resource, Default, PartialEq)]
332    /// # struct Counter(u8);
333    /// # let mut app = Schedule::default();
334    /// # let mut world = World::new();
335    /// app.add_systems(
336    ///     // `resource_exists_and_equals` will only return true
337    ///     // if the given resource exists and equals the given value
338    ///     my_system.run_if(resource_exists_and_equals(Counter(0))),
339    /// );
340    ///
341    /// fn my_system(mut counter: ResMut<Counter>) {
342    ///     counter.0 += 1;
343    /// }
344    ///
345    /// // `Counter` hasn't been added so `my_system` can't run
346    /// app.run(&mut world);
347    /// world.init_resource::<Counter>();
348    ///
349    /// // `Counter` is `0` so `my_system` can run
350    /// app.run(&mut world);
351    /// assert_eq!(world.resource::<Counter>().0, 1);
352    ///
353    /// // `Counter` is no longer `0` so `my_system` won't run
354    /// app.run(&mut world);
355    /// assert_eq!(world.resource::<Counter>().0, 1);
356    /// ```
357    pub fn resource_exists_and_equals<T>(value: T) -> impl FnMut(Option<Res<T>>) -> bool
358    where
359        T: Resource + PartialEq,
360    {
361        move |res: Option<Res<T>>| match res {
362            Some(res) => *res == value,
363            None => false,
364        }
365    }
366
367    /// A [`Condition`](super::Condition)-satisfying system that returns `true`
368    /// if the resource of the given type has been added since the condition was last checked.
369    ///
370    /// # Example
371    ///
372    /// ```
373    /// # use bevy_ecs::prelude::*;
374    /// # #[derive(Resource, Default)]
375    /// # struct Counter(u8);
376    /// # let mut app = Schedule::default();
377    /// # let mut world = World::new();
378    /// app.add_systems(
379    ///     // `resource_added` will only return true if the
380    ///     // given resource was just added
381    ///     my_system.run_if(resource_added::<Counter>),
382    /// );
383    ///
384    /// fn my_system(mut counter: ResMut<Counter>) {
385    ///     counter.0 += 1;
386    /// }
387    ///
388    /// world.init_resource::<Counter>();
389    ///
390    /// // `Counter` was just added so `my_system` will run
391    /// app.run(&mut world);
392    /// assert_eq!(world.resource::<Counter>().0, 1);
393    ///
394    /// // `Counter` was not just added so `my_system` will not run
395    /// app.run(&mut world);
396    /// assert_eq!(world.resource::<Counter>().0, 1);
397    /// ```
398    pub fn resource_added<T>(res: Option<Res<T>>) -> bool
399    where
400        T: Resource,
401    {
402        match res {
403            Some(res) => res.is_added(),
404            None => false,
405        }
406    }
407
408    /// A [`Condition`](super::Condition)-satisfying system that returns `true`
409    /// if the resource of the given type has had its value changed since the condition
410    /// was last checked.
411    ///
412    /// The value is considered changed when it is added. The first time this condition
413    /// is checked after the resource was added, it will return `true`.
414    /// Change detection behaves like this everywhere in Bevy.
415    ///
416    /// # Panics
417    ///
418    /// The condition will panic if the resource does not exist.
419    ///
420    /// # Example
421    ///
422    /// ```
423    /// # use bevy_ecs::prelude::*;
424    /// # #[derive(Resource, Default)]
425    /// # struct Counter(u8);
426    /// # let mut app = Schedule::default();
427    /// # let mut world = World::new();
428    /// # world.init_resource::<Counter>();
429    /// app.add_systems(
430    ///     // `resource_changed` will only return true if the
431    ///     // given resource was just changed (or added)
432    ///     my_system.run_if(
433    ///         resource_changed::<Counter>
434    ///         // By default detecting changes will also trigger if the resource was
435    ///         // just added, this won't work with my example so I will add a second
436    ///         // condition to make sure the resource wasn't just added
437    ///         .and_then(not(resource_added::<Counter>))
438    ///     ),
439    /// );
440    ///
441    /// fn my_system(mut counter: ResMut<Counter>) {
442    ///     counter.0 += 1;
443    /// }
444    ///
445    /// // `Counter` hasn't been changed so `my_system` won't run
446    /// app.run(&mut world);
447    /// assert_eq!(world.resource::<Counter>().0, 0);
448    ///
449    /// world.resource_mut::<Counter>().0 = 50;
450    ///
451    /// // `Counter` was just changed so `my_system` will run
452    /// app.run(&mut world);
453    /// assert_eq!(world.resource::<Counter>().0, 51);
454    /// ```
455    pub fn resource_changed<T>(res: Res<T>) -> bool
456    where
457        T: Resource,
458    {
459        res.is_changed()
460    }
461
462    /// A [`Condition`](super::Condition)-satisfying system that returns `true`
463    /// if the resource of the given type has had its value changed since the condition
464    /// was last checked.
465    ///
466    /// The value is considered changed when it is added. The first time this condition
467    /// is checked after the resource was added, it will return `true`.
468    /// Change detection behaves like this everywhere in Bevy.
469    ///
470    /// This run condition does not detect when the resource is removed.
471    ///
472    /// The condition will return `false` if the resource does not exist.
473    ///
474    /// # Example
475    ///
476    /// ```
477    /// # use bevy_ecs::prelude::*;
478    /// # #[derive(Resource, Default)]
479    /// # struct Counter(u8);
480    /// # let mut app = Schedule::default();
481    /// # let mut world = World::new();
482    /// app.add_systems(
483    ///     // `resource_exists_and_changed` will only return true if the
484    ///     // given resource exists and was just changed (or added)
485    ///     my_system.run_if(
486    ///         resource_exists_and_changed::<Counter>
487    ///         // By default detecting changes will also trigger if the resource was
488    ///         // just added, this won't work with my example so I will add a second
489    ///         // condition to make sure the resource wasn't just added
490    ///         .and_then(not(resource_added::<Counter>))
491    ///     ),
492    /// );
493    ///
494    /// fn my_system(mut counter: ResMut<Counter>) {
495    ///     counter.0 += 1;
496    /// }
497    ///
498    /// // `Counter` doesn't exist so `my_system` won't run
499    /// app.run(&mut world);
500    /// world.init_resource::<Counter>();
501    ///
502    /// // `Counter` hasn't been changed so `my_system` won't run
503    /// app.run(&mut world);
504    /// assert_eq!(world.resource::<Counter>().0, 0);
505    ///
506    /// world.resource_mut::<Counter>().0 = 50;
507    ///
508    /// // `Counter` was just changed so `my_system` will run
509    /// app.run(&mut world);
510    /// assert_eq!(world.resource::<Counter>().0, 51);
511    /// ```
512    pub fn resource_exists_and_changed<T>(res: Option<Res<T>>) -> bool
513    where
514        T: Resource,
515    {
516        match res {
517            Some(res) => res.is_changed(),
518            None => false,
519        }
520    }
521
522    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
523    /// if the resource of the given type has had its value changed since the condition
524    /// was last checked.
525    ///
526    /// The value is considered changed when it is added. The first time this condition
527    /// is checked after the resource was added, it will return `true`.
528    /// Change detection behaves like this everywhere in Bevy.
529    ///
530    /// This run condition also detects removal. It will return `true` if the resource
531    /// has been removed since the run condition was last checked.
532    ///
533    /// The condition will return `false` if the resource does not exist.
534    ///
535    /// # Example
536    ///
537    /// ```
538    /// # use bevy_ecs::prelude::*;
539    /// # #[derive(Resource, Default)]
540    /// # struct Counter(u8);
541    /// # let mut app = Schedule::default();
542    /// # let mut world = World::new();
543    /// # world.init_resource::<Counter>();
544    /// app.add_systems(
545    ///     // `resource_changed_or_removed` will only return true if the
546    ///     // given resource was just changed or removed (or added)
547    ///     my_system.run_if(
548    ///         resource_changed_or_removed::<Counter>()
549    ///         // By default detecting changes will also trigger if the resource was
550    ///         // just added, this won't work with my example so I will add a second
551    ///         // condition to make sure the resource wasn't just added
552    ///         .and_then(not(resource_added::<Counter>))
553    ///     ),
554    /// );
555    ///
556    /// #[derive(Resource, Default)]
557    /// struct MyResource;
558    ///
559    /// // If `Counter` exists, increment it, otherwise insert `MyResource`
560    /// fn my_system(mut commands: Commands, mut counter: Option<ResMut<Counter>>) {
561    ///     if let Some(mut counter) = counter {
562    ///         counter.0 += 1;
563    ///     } else {
564    ///         commands.init_resource::<MyResource>();
565    ///     }
566    /// }
567    ///
568    /// // `Counter` hasn't been changed so `my_system` won't run
569    /// app.run(&mut world);
570    /// assert_eq!(world.resource::<Counter>().0, 0);
571    ///
572    /// world.resource_mut::<Counter>().0 = 50;
573    ///
574    /// // `Counter` was just changed so `my_system` will run
575    /// app.run(&mut world);
576    /// assert_eq!(world.resource::<Counter>().0, 51);
577    ///
578    /// world.remove_resource::<Counter>();
579    ///
580    /// // `Counter` was just removed so `my_system` will run
581    /// app.run(&mut world);
582    /// assert_eq!(world.contains_resource::<MyResource>(), true);
583    /// ```
584    pub fn resource_changed_or_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
585    where
586        T: Resource,
587    {
588        let mut existed = false;
589        move |res: Option<Res<T>>| {
590            if let Some(value) = res {
591                existed = true;
592                value.is_changed()
593            } else if existed {
594                existed = false;
595                true
596            } else {
597                false
598            }
599        }
600    }
601
602    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
603    /// if the resource of the given type has been removed since the condition was last checked.
604    ///
605    /// # Example
606    ///
607    /// ```
608    /// # use bevy_ecs::prelude::*;
609    /// # #[derive(Resource, Default)]
610    /// # struct Counter(u8);
611    /// # let mut app = Schedule::default();
612    /// # let mut world = World::new();
613    /// # world.init_resource::<Counter>();
614    /// app.add_systems(
615    ///     // `resource_removed` will only return true if the
616    ///     // given resource was just removed
617    ///     my_system.run_if(resource_removed::<MyResource>()),
618    /// );
619    ///
620    /// #[derive(Resource, Default)]
621    /// struct MyResource;
622    ///
623    /// fn my_system(mut counter: ResMut<Counter>) {
624    ///     counter.0 += 1;
625    /// }
626    ///
627    /// world.init_resource::<MyResource>();
628    ///
629    /// // `MyResource` hasn't just been removed so `my_system` won't run
630    /// app.run(&mut world);
631    /// assert_eq!(world.resource::<Counter>().0, 0);
632    ///
633    /// world.remove_resource::<MyResource>();
634    ///
635    /// // `MyResource` was just removed so `my_system` will run
636    /// app.run(&mut world);
637    /// assert_eq!(world.resource::<Counter>().0, 1);
638    /// ```
639    pub fn resource_removed<T>() -> impl FnMut(Option<Res<T>>) -> bool + Clone
640    where
641        T: Resource,
642    {
643        let mut existed = false;
644        move |res: Option<Res<T>>| {
645            if res.is_some() {
646                existed = true;
647                false
648            } else if existed {
649                existed = false;
650                true
651            } else {
652                false
653            }
654        }
655    }
656
657    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
658    /// if there are any new events of the given type since it was last called.
659    ///
660    /// # Example
661    ///
662    /// ```
663    /// # use bevy_ecs::prelude::*;
664    /// # #[derive(Resource, Default)]
665    /// # struct Counter(u8);
666    /// # let mut app = Schedule::default();
667    /// # let mut world = World::new();
668    /// # world.init_resource::<Counter>();
669    /// # world.init_resource::<Events<MyEvent>>();
670    /// # app.add_systems(bevy_ecs::event::event_update_system.before(my_system));
671    ///
672    /// app.add_systems(
673    ///     my_system.run_if(on_event::<MyEvent>()),
674    /// );
675    ///
676    /// #[derive(Event)]
677    /// struct MyEvent;
678    ///
679    /// fn my_system(mut counter: ResMut<Counter>) {
680    ///     counter.0 += 1;
681    /// }
682    ///
683    /// // No new `MyEvent` events have been push so `my_system` won't run
684    /// app.run(&mut world);
685    /// assert_eq!(world.resource::<Counter>().0, 0);
686    ///
687    /// world.resource_mut::<Events<MyEvent>>().send(MyEvent);
688    ///
689    /// // A `MyEvent` event has been pushed so `my_system` will run
690    /// app.run(&mut world);
691    /// assert_eq!(world.resource::<Counter>().0, 1);
692    /// ```
693    pub fn on_event<T: Event>() -> impl FnMut(EventReader<T>) -> bool + Clone {
694        // The events need to be consumed, so that there are no false positives on subsequent
695        // calls of the run condition. Simply checking `is_empty` would not be enough.
696        // PERF: note that `count` is efficient (not actually looping/iterating),
697        // due to Bevy having a specialized implementation for events.
698        move |mut reader: EventReader<T>| reader.read().count() > 0
699    }
700
701    /// A [`Condition`](super::Condition)-satisfying system that returns `true`
702    /// if there are any entities with the given component type.
703    ///
704    /// # Example
705    ///
706    /// ```
707    /// # use bevy_ecs::prelude::*;
708    /// # #[derive(Resource, Default)]
709    /// # struct Counter(u8);
710    /// # let mut app = Schedule::default();
711    /// # let mut world = World::new();
712    /// # world.init_resource::<Counter>();
713    /// app.add_systems(
714    ///     my_system.run_if(any_with_component::<MyComponent>),
715    /// );
716    ///
717    /// #[derive(Component)]
718    /// struct MyComponent;
719    ///
720    /// fn my_system(mut counter: ResMut<Counter>) {
721    ///     counter.0 += 1;
722    /// }
723    ///
724    /// // No entities exist yet with a `MyComponent` component so `my_system` won't run
725    /// app.run(&mut world);
726    /// assert_eq!(world.resource::<Counter>().0, 0);
727    ///
728    /// world.spawn(MyComponent);
729    ///
730    /// // An entities with `MyComponent` now exists so `my_system` will run
731    /// app.run(&mut world);
732    /// assert_eq!(world.resource::<Counter>().0, 1);
733    /// ```
734    pub fn any_with_component<T: Component>(query: Query<(), With<T>>) -> bool {
735        !query.is_empty()
736    }
737
738    /// Generates a [`Condition`](super::Condition)-satisfying closure that returns `true`
739    /// if there are any entity with a component of the given type removed.
740    pub fn any_component_removed<T: Component>() -> impl FnMut(RemovedComponents<T>) -> bool {
741        // `RemovedComponents` based on events and therefore events need to be consumed,
742        // so that there are no false positives on subsequent calls of the run condition.
743        // Simply checking `is_empty` would not be enough.
744        // PERF: note that `count` is efficient (not actually looping/iterating),
745        // due to Bevy having a specialized implementation for events.
746        move |mut removals: RemovedComponents<T>| removals.read().count() != 0
747    }
748
749    /// Generates a [`Condition`](super::Condition) that inverses the result of passed one.
750    ///
751    /// # Example
752    ///
753    /// ```
754    /// # use bevy_ecs::prelude::*;
755    /// # #[derive(Resource, Default)]
756    /// # struct Counter(u8);
757    /// # let mut app = Schedule::default();
758    /// # let mut world = World::new();
759    /// # world.init_resource::<Counter>();
760    /// app.add_systems(
761    ///     // `not` will inverse any condition you pass in.
762    ///     // Since the condition we choose always returns true
763    ///     // this system will never run
764    ///     my_system.run_if(not(always)),
765    /// );
766    ///
767    /// fn my_system(mut counter: ResMut<Counter>) {
768    ///     counter.0 += 1;
769    /// }
770    ///
771    /// fn always() -> bool {
772    ///     true
773    /// }
774    ///
775    /// app.run(&mut world);
776    /// assert_eq!(world.resource::<Counter>().0, 0);
777    /// ```
778    pub fn not<Marker, TOut, T>(condition: T) -> NotSystem<T::System>
779    where
780        TOut: std::ops::Not,
781        T: IntoSystem<(), TOut, Marker>,
782    {
783        let condition = IntoSystem::into_system(condition);
784        let name = format!("!{}", condition.name());
785        NotSystem::new(super::NotMarker, condition, name.into())
786    }
787}
788
789/// Invokes [`Not`] with the output of another system.
790///
791/// See [`common_conditions::not`] for examples.
792pub type NotSystem<T> = AdapterSystem<NotMarker, T>;
793
794/// Used with [`AdapterSystem`] to negate the output of a system via the [`Not`] operator.
795#[doc(hidden)]
796#[derive(Clone, Copy)]
797pub struct NotMarker;
798
799impl<T: System> Adapt<T> for NotMarker
800where
801    T::Out: Not,
802{
803    type In = T::In;
804    type Out = <T::Out as Not>::Output;
805
806    fn adapt(&mut self, input: Self::In, run_system: impl FnOnce(T::In) -> T::Out) -> Self::Out {
807        !run_system(input)
808    }
809}
810
811/// Combines the outputs of two systems using the `&&` operator.
812pub type AndThen<A, B> = CombinatorSystem<AndThenMarker, A, B>;
813
814/// Combines the outputs of two systems using the `||` operator.
815pub type OrElse<A, B> = CombinatorSystem<OrElseMarker, A, B>;
816
817#[doc(hidden)]
818pub struct AndThenMarker;
819
820impl<In, A, B> Combine<A, B> for AndThenMarker
821where
822    In: Copy,
823    A: System<In = In, Out = bool>,
824    B: System<In = In, Out = bool>,
825{
826    type In = In;
827    type Out = bool;
828
829    fn combine(
830        input: Self::In,
831        a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
832        b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
833    ) -> Self::Out {
834        a(input) && b(input)
835    }
836}
837
838#[doc(hidden)]
839pub struct OrElseMarker;
840
841impl<In, A, B> Combine<A, B> for OrElseMarker
842where
843    In: Copy,
844    A: System<In = In, Out = bool>,
845    B: System<In = In, Out = bool>,
846{
847    type In = In;
848    type Out = bool;
849
850    fn combine(
851        input: Self::In,
852        a: impl FnOnce(<A as System>::In) -> <A as System>::Out,
853        b: impl FnOnce(<B as System>::In) -> <B as System>::Out,
854    ) -> Self::Out {
855        a(input) || b(input)
856    }
857}
858
859#[cfg(test)]
860mod tests {
861    use super::{common_conditions::*, Condition};
862    use crate as bevy_ecs;
863    use crate::component::Component;
864    use crate::schedule::IntoSystemConfigs;
865    use crate::system::Local;
866    use crate::{change_detection::ResMut, schedule::Schedule, world::World};
867    use bevy_ecs_macros::Event;
868    use bevy_ecs_macros::Resource;
869
870    #[derive(Resource, Default)]
871    struct Counter(usize);
872
873    fn increment_counter(mut counter: ResMut<Counter>) {
874        counter.0 += 1;
875    }
876
877    fn every_other_time(mut has_ran: Local<bool>) -> bool {
878        *has_ran = !*has_ran;
879        *has_ran
880    }
881
882    #[test]
883    fn run_condition() {
884        let mut world = World::new();
885        world.init_resource::<Counter>();
886        let mut schedule = Schedule::default();
887
888        // Run every other cycle
889        schedule.add_systems(increment_counter.run_if(every_other_time));
890
891        schedule.run(&mut world);
892        schedule.run(&mut world);
893        assert_eq!(world.resource::<Counter>().0, 1);
894        schedule.run(&mut world);
895        schedule.run(&mut world);
896        assert_eq!(world.resource::<Counter>().0, 2);
897
898        // Run every other cycle opposite to the last one
899        schedule.add_systems(increment_counter.run_if(not(every_other_time)));
900
901        schedule.run(&mut world);
902        schedule.run(&mut world);
903        assert_eq!(world.resource::<Counter>().0, 4);
904        schedule.run(&mut world);
905        schedule.run(&mut world);
906        assert_eq!(world.resource::<Counter>().0, 6);
907    }
908
909    #[test]
910    fn run_condition_combinators() {
911        let mut world = World::new();
912        world.init_resource::<Counter>();
913        let mut schedule = Schedule::default();
914
915        // Always run
916        schedule.add_systems(increment_counter.run_if(every_other_time.or_else(|| true)));
917        // Run every other cycle
918        schedule.add_systems(increment_counter.run_if(every_other_time.and_then(|| true)));
919
920        schedule.run(&mut world);
921        assert_eq!(world.resource::<Counter>().0, 2);
922        schedule.run(&mut world);
923        assert_eq!(world.resource::<Counter>().0, 3);
924    }
925
926    #[test]
927    fn multiple_run_conditions() {
928        let mut world = World::new();
929        world.init_resource::<Counter>();
930        let mut schedule = Schedule::default();
931
932        // Run every other cycle
933        schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| true));
934        // Never run
935        schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| false));
936
937        schedule.run(&mut world);
938        assert_eq!(world.resource::<Counter>().0, 1);
939        schedule.run(&mut world);
940        assert_eq!(world.resource::<Counter>().0, 1);
941    }
942
943    #[test]
944    fn multiple_run_conditions_is_and_operation() {
945        let mut world = World::new();
946        world.init_resource::<Counter>();
947
948        let mut schedule = Schedule::default();
949
950        // This should never run, if multiple run conditions worked
951        // like an OR condition then it would always run
952        schedule.add_systems(
953            increment_counter
954                .run_if(every_other_time)
955                .run_if(not(every_other_time)),
956        );
957
958        schedule.run(&mut world);
959        assert_eq!(world.resource::<Counter>().0, 0);
960        schedule.run(&mut world);
961        assert_eq!(world.resource::<Counter>().0, 0);
962    }
963    #[derive(Component)]
964    struct TestComponent;
965
966    #[derive(Event)]
967    struct TestEvent;
968
969    #[derive(Resource)]
970    struct TestResource(());
971
972    fn test_system() {}
973
974    // Ensure distributive_run_if compiles with the common conditions.
975    #[test]
976    fn distributive_run_if_compiles() {
977        Schedule::default().add_systems(
978            (test_system, test_system)
979                .distributive_run_if(run_once())
980                .distributive_run_if(resource_exists::<TestResource>)
981                .distributive_run_if(resource_added::<TestResource>)
982                .distributive_run_if(resource_changed::<TestResource>)
983                .distributive_run_if(resource_exists_and_changed::<TestResource>)
984                .distributive_run_if(resource_changed_or_removed::<TestResource>())
985                .distributive_run_if(resource_removed::<TestResource>())
986                .distributive_run_if(on_event::<TestEvent>())
987                .distributive_run_if(any_with_component::<TestComponent>)
988                .distributive_run_if(not(run_once())),
989        );
990    }
991}