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