bevy_ecs/system/commands/
command.rs

1//! Contains the definition of the [`Command`] trait,
2//! as well as the blanket implementation of the trait for closures.
3//!
4//! It also contains functions that return closures for use with
5//! [`Commands`](crate::system::Commands).
6
7use crate::{
8    bundle::{Bundle, InsertMode, NoBundleEffect},
9    change_detection::MaybeLocation,
10    entity::Entity,
11    error::Result,
12    event::{Event, Events},
13    observer::TriggerTargets,
14    resource::Resource,
15    schedule::ScheduleLabel,
16    system::{IntoSystem, SystemId, SystemInput},
17    world::{FromWorld, SpawnBatchIter, World},
18};
19
20/// A [`World`] mutation.
21///
22/// Should be used with [`Commands::queue`](crate::system::Commands::queue).
23///
24/// The `Out` generic parameter is the returned "output" of the command.
25///
26/// # Usage
27///
28/// ```
29/// # use bevy_ecs::prelude::*;
30/// // Our world resource
31/// #[derive(Resource, Default)]
32/// struct Counter(u64);
33///
34/// // Our custom command
35/// struct AddToCounter(u64);
36///
37/// impl Command for AddToCounter {
38///     fn apply(self, world: &mut World) {
39///         let mut counter = world.get_resource_or_insert_with(Counter::default);
40///         counter.0 += self.0;
41///     }
42/// }
43///
44/// fn some_system(mut commands: Commands) {
45///     commands.queue(AddToCounter(42));
46/// }
47/// ```
48pub trait Command<Out = ()>: Send + 'static {
49    /// Applies this command, causing it to mutate the provided `world`.
50    ///
51    /// This method is used to define what a command "does" when it is ultimately applied.
52    /// Because this method takes `self`, you can store data or settings on the type that implements this trait.
53    /// This data is set by the system or other source of the command, and then ultimately read in this method.
54    fn apply(self, world: &mut World) -> Out;
55}
56
57impl<F, Out> Command<Out> for F
58where
59    F: FnOnce(&mut World) -> Out + Send + 'static,
60{
61    fn apply(self, world: &mut World) -> Out {
62        self(world)
63    }
64}
65
66/// A [`Command`] that consumes an iterator of [`Bundles`](Bundle) to spawn a series of entities.
67///
68/// This is more efficient than spawning the entities individually.
69#[track_caller]
70pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
71where
72    I: IntoIterator + Send + Sync + 'static,
73    I::Item: Bundle<Effect: NoBundleEffect>,
74{
75    let caller = MaybeLocation::caller();
76    move |world: &mut World| {
77        SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);
78    }
79}
80
81/// A [`Command`] that consumes an iterator to add a series of [`Bundles`](Bundle) to a set of entities.
82///
83/// If any entities do not exist in the world, this command will return a
84/// [`TryInsertBatchError`](crate::world::error::TryInsertBatchError).
85///
86/// This is more efficient than inserting the bundles individually.
87#[track_caller]
88pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>
89where
90    I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
91    B: Bundle<Effect: NoBundleEffect>,
92{
93    let caller = MaybeLocation::caller();
94    move |world: &mut World| -> Result {
95        world.try_insert_batch_with_caller(batch, insert_mode, caller)?;
96        Ok(())
97    }
98}
99
100/// A [`Command`] that inserts a [`Resource`] into the world using a value
101/// created with the [`FromWorld`] trait.
102#[track_caller]
103pub fn init_resource<R: Resource + FromWorld>() -> impl Command {
104    move |world: &mut World| {
105        world.init_resource::<R>();
106    }
107}
108
109/// A [`Command`] that inserts a [`Resource`] into the world.
110#[track_caller]
111pub fn insert_resource<R: Resource>(resource: R) -> impl Command {
112    let caller = MaybeLocation::caller();
113    move |world: &mut World| {
114        world.insert_resource_with_caller(resource, caller);
115    }
116}
117
118/// A [`Command`] that removes a [`Resource`] from the world.
119pub fn remove_resource<R: Resource>() -> impl Command {
120    move |world: &mut World| {
121        world.remove_resource::<R>();
122    }
123}
124
125/// A [`Command`] that runs the system corresponding to the given [`SystemId`].
126pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command<Result> {
127    move |world: &mut World| -> Result {
128        world.run_system(id)?;
129        Ok(())
130    }
131}
132
133/// A [`Command`] that runs the system corresponding to the given [`SystemId`]
134/// and provides the given input value.
135pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command<Result>
136where
137    I: SystemInput<Inner<'static>: Send> + 'static,
138{
139    move |world: &mut World| -> Result {
140        world.run_system_with(id, input)?;
141        Ok(())
142    }
143}
144
145/// A [`Command`] that runs the given system,
146/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
147pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>
148where
149    M: 'static,
150    S: IntoSystem<(), (), M> + Send + 'static,
151{
152    move |world: &mut World| -> Result {
153        world.run_system_cached(system)?;
154        Ok(())
155    }
156}
157
158/// A [`Command`] that runs the given system with the given input value,
159/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
160pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>
161where
162    I: SystemInput<Inner<'static>: Send> + Send + 'static,
163    M: 'static,
164    S: IntoSystem<I, (), M> + Send + 'static,
165{
166    move |world: &mut World| -> Result {
167        world.run_system_cached_with(system, input)?;
168        Ok(())
169    }
170}
171
172/// A [`Command`] that removes a system previously registered with
173/// [`Commands::register_system`](crate::system::Commands::register_system) or
174/// [`World::register_system`].
175pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>
176where
177    I: SystemInput + Send + 'static,
178    O: Send + 'static,
179{
180    move |world: &mut World| -> Result {
181        world.unregister_system(system_id)?;
182        Ok(())
183    }
184}
185
186/// A [`Command`] that removes a system previously registered with one of the following:
187/// - [`Commands::run_system_cached`](crate::system::Commands::run_system_cached)
188/// - [`World::run_system_cached`]
189/// - [`World::register_system_cached`]
190pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command<Result>
191where
192    I: SystemInput + Send + 'static,
193    O: 'static,
194    M: 'static,
195    S: IntoSystem<I, O, M> + Send + 'static,
196{
197    move |world: &mut World| -> Result {
198        world.unregister_system_cached(system)?;
199        Ok(())
200    }
201}
202
203/// A [`Command`] that runs the schedule corresponding to the given [`ScheduleLabel`].
204pub fn run_schedule(label: impl ScheduleLabel) -> impl Command<Result> {
205    move |world: &mut World| -> Result {
206        world.try_run_schedule(label)?;
207        Ok(())
208    }
209}
210
211/// A [`Command`] that sends a global [`Trigger`](crate::observer::Trigger) without any targets.
212#[track_caller]
213pub fn trigger(event: impl Event) -> impl Command {
214    let caller = MaybeLocation::caller();
215    move |world: &mut World| {
216        world.trigger_with_caller(event, caller);
217    }
218}
219
220/// A [`Command`] that sends a [`Trigger`](crate::observer::Trigger) for the given targets.
221pub fn trigger_targets(
222    event: impl Event,
223    targets: impl TriggerTargets + Send + Sync + 'static,
224) -> impl Command {
225    let caller = MaybeLocation::caller();
226    move |world: &mut World| {
227        world.trigger_targets_with_caller(event, targets, caller);
228    }
229}
230
231/// A [`Command`] that sends an arbitrary [`Event`].
232#[track_caller]
233pub fn send_event<E: Event>(event: E) -> impl Command {
234    let caller = MaybeLocation::caller();
235    move |world: &mut World| {
236        let mut events = world.resource_mut::<Events<E>>();
237        events.send_with_caller(event, caller);
238    }
239}