bevy_ecs/system/commands/
command.rs1use bevy_utils::prelude::DebugName;
8
9use crate::{
10 bundle::{Bundle, InsertMode, NoBundleEffect},
11 change_detection::MaybeLocation,
12 entity::Entity,
13 error::{BevyError, CommandOutput, ErrorContext, Result},
14 event::Event,
15 message::{Message, Messages},
16 query::{QueryData, QueryFilter},
17 resource::Resource,
18 schedule::ScheduleLabel,
19 system::{IntoSystem, SystemId, SystemInput},
20 world::{FromWorld, SpawnBatchIter, World},
21};
22
23pub trait Command: Send + 'static {
54 type Out: CommandOutput;
56
57 fn apply(self, world: &mut World) -> Self::Out;
63
64 #[inline]
67 fn handle_error_with(
68 self,
69 error_handler: impl FnOnce(BevyError, ErrorContext) + Send + 'static,
70 ) -> impl Command<Out = ()>
71 where
72 Self: Sized,
73 {
74 move |world: &mut World| {
75 if let Some(error) = self.apply(world).to_err() {
76 error_handler(
77 error,
78 ErrorContext::Command {
79 name: DebugName::type_name::<Self>(),
80 },
81 );
82 }
83 }
84 }
85
86 #[inline]
89 fn handle_error(self) -> impl Command<Out = ()>
90 where
91 Self: Sized,
92 {
93 move |world: &mut World| {
94 if let Some(error) = self.apply(world).to_err() {
95 world.fallback_error_handler()(
96 error,
97 ErrorContext::Command {
98 name: DebugName::type_name::<Self>(),
99 },
100 );
101 }
102 }
103 }
104
105 #[inline]
107 fn ignore_error(self) -> impl Command<Out = ()>
108 where
109 Self: Sized,
110 {
111 move |world: &mut World| {
112 let _ = self.apply(world);
113 }
114 }
115}
116
117impl<F, Out> Command for F
118where
119 F: FnOnce(&mut World) -> Out + Send + 'static,
120 Out: CommandOutput,
121{
122 type Out = Out;
123
124 fn apply(self, world: &mut World) -> Out {
125 self(world)
126 }
127}
128
129#[track_caller]
133pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
134where
135 I: IntoIterator + Send + Sync + 'static,
136 I::Item: Bundle<Effect: NoBundleEffect>,
137{
138 let caller = MaybeLocation::caller();
139 move |world: &mut World| {
140 SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);
141 }
142}
143
144#[track_caller]
151pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command
152where
153 I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
154 B: Bundle<Effect: NoBundleEffect>,
155{
156 let caller = MaybeLocation::caller();
157 move |world: &mut World| -> Result {
158 world.try_insert_batch_with_caller(batch, insert_mode, caller)?;
159 Ok(())
160 }
161}
162
163#[track_caller]
166pub fn init_resource<R: Resource + FromWorld>() -> impl Command {
167 move |world: &mut World| {
168 world.init_resource::<R>();
169 }
170}
171
172#[track_caller]
174pub fn insert_resource<R: Resource>(resource: R) -> impl Command {
175 let caller = MaybeLocation::caller();
176 move |world: &mut World| {
177 world.insert_resource_with_caller(resource, caller);
178 }
179}
180
181pub fn remove_resource<R: Resource>() -> impl Command {
183 move |world: &mut World| {
184 world.remove_resource::<R>();
185 }
186}
187
188pub fn run_system<O: 'static>(id: impl Into<SystemId<(), O>> + Send) -> impl Command {
190 let id = id.into();
191 move |world: &mut World| -> Result {
192 world.run_system(id)?;
193 Ok(())
194 }
195}
196
197pub fn run_system_with<I>(
200 id: impl Into<SystemId<I>> + Send,
201 input: I::Inner<'static>,
202) -> impl Command
203where
204 I: SystemInput<Inner<'static>: Send> + 'static,
205{
206 let id = id.into();
207 move |world: &mut World| -> Result {
208 world.run_system_with(id, input)?;
209 Ok(())
210 }
211}
212
213pub fn run_system_cached<M, S>(system: S) -> impl Command
216where
217 M: 'static,
218 S: IntoSystem<(), (), M> + Send + 'static,
219{
220 move |world: &mut World| -> Result {
221 world.run_system_cached(system)?;
222 Ok(())
223 }
224}
225
226pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command
231where
232 I: SystemInput<Inner<'static>: Send> + Send + 'static,
233 M: 'static,
234 S: IntoSystem<I, (), M> + Send + 'static,
235{
236 move |world: &mut World| -> Result {
237 world.run_system_cached_with(system, input)?;
238 Ok(())
239 }
240}
241
242pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command
246where
247 I: SystemInput + Send + 'static,
248 O: Send + 'static,
249{
250 move |world: &mut World| -> Result {
251 world.unregister_system(system_id)?;
252 Ok(())
253 }
254}
255
256pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command
261where
262 I: SystemInput + Send + 'static,
263 O: 'static,
264 M: 'static,
265 S: IntoSystem<I, O, M> + Send + 'static,
266{
267 move |world: &mut World| -> Result {
268 world.unregister_system_cached(system)?;
269 Ok(())
270 }
271}
272
273pub fn run_schedule(label: impl ScheduleLabel) -> impl Command {
275 move |world: &mut World| -> Result {
276 world.try_run_schedule(label)?;
277 Ok(())
278 }
279}
280
281#[track_caller]
285pub fn trigger<'a, E: Event<Trigger<'a>: Default>>(mut event: E) -> impl Command {
286 let caller = MaybeLocation::caller();
287 move |world: &mut World| {
288 world.trigger_ref_with_caller(
289 &mut event,
290 &mut <E::Trigger<'_> as Default>::default(),
291 caller,
292 );
293 }
294}
295
296#[track_caller]
301pub fn trigger_with<E: Event<Trigger<'static>: Send + Sync>>(
302 mut event: E,
303 mut trigger: E::Trigger<'static>,
304) -> impl Command {
305 let caller = MaybeLocation::caller();
306 move |world: &mut World| {
307 world.trigger_ref_with_caller(&mut event, &mut trigger, caller);
308 }
309}
310
311#[track_caller]
313pub fn write_message<M: Message>(message: M) -> impl Command {
314 let caller = MaybeLocation::caller();
315 move |world: &mut World| {
316 let mut messages = world.resource_mut::<Messages<M>>();
317 messages.write_with_caller(message, caller);
318 }
319}
320
321#[track_caller]
323pub fn despawn_all<F: QueryFilter>() -> impl Command {
324 let caller = MaybeLocation::caller();
325 move |world: &mut World| {
326 world.despawn_all_with_caller::<F>(caller);
327 }
328}
329
330#[track_caller]
332pub fn despawn_all_where<D: QueryData, F: QueryFilter>(
333 cond: impl FnMut(D::Item<'_, '_>) -> bool + Send + 'static,
334) -> impl Command {
335 let caller = MaybeLocation::caller();
336 move |world: &mut World| {
337 world.despawn_all_where_with_caller::<D, F>(cond, caller);
338 }
339}