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
6849 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::Event,
13
message::{Message, Messages},
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
/// ```
48
pub 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
57
impl<F, Out> Command<Out> for F
58
where
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]
70
pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
71
where
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]
88
pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command<Result>
89
where
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]
103
pub 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]
111
pub 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.
119
pub 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`].
126
pub 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.
135
pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command<Result>
136
where
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.
147
pub fn run_system_cached<M, S>(system: S) -> impl Command<Result>
148
where
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.
160
pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command<Result>
161
where
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`].
175
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command<Result>
176
where
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`]
190
pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command<Result>
191
where
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`].
204
pub 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
/// Triggers the given [`Event`], which will run any [`Observer`]s watching for it.
212
///
213
/// [`Observer`]: crate::observer::Observer
214
#[track_caller]
215
pub fn trigger<'a, E: Event<Trigger<'a>: Default>>(mut event: E) -> impl Command {
216
let caller = MaybeLocation::caller();
217
move |world: &mut World| {
218
world.trigger_ref_with_caller(
219
&mut event,
220
&mut <E::Trigger<'_> as Default>::default(),
221
caller,
222
);
223
}
224
}
225
226
/// Triggers the given [`Event`] using the given [`Trigger`], which will run any [`Observer`]s watching for it.
227
///
228
/// [`Trigger`]: crate::event::Trigger
229
/// [`Observer`]: crate::observer::Observer
230
#[track_caller]
231
pub fn trigger_with<E: Event<Trigger<'static>: Send + Sync>>(
232
mut event: E,
233
mut trigger: E::Trigger<'static>,
234
) -> impl Command {
235
let caller = MaybeLocation::caller();
236
move |world: &mut World| {
237
world.trigger_ref_with_caller(&mut event, &mut trigger, caller);
238
}
239
}
240
241
/// A [`Command`] that writes an arbitrary [`Message`].
242
#[track_caller]
243
pub fn write_message<M: Message>(message: M) -> impl Command {
244
let caller = MaybeLocation::caller();
245
move |world: &mut World| {
246
let mut messages = world.resource_mut::<Messages<M>>();
247
messages.write_with_caller(message, caller);
248
}
249
}
250
251
/// A [`Command`] that writes an arbitrary [`Message`].
252
#[track_caller]
253
#[deprecated(since = "0.17.0", note = "Use `write_message` instead.")]
254
pub fn send_event<E: Message>(event: E) -> impl Command {
255
write_message(event)
256
}
257
258