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::{CommandOutput, ErrorContext, ErrorHandler, Result},
14 event::Event,
15 message::{Message, Messages},
16 resource::Resource,
17 schedule::ScheduleLabel,
18 system::{IntoSystem, SystemId, SystemInput},
19 world::{FromWorld, SpawnBatchIter, World},
20};
21
22pub trait Command: Send + 'static {
53 type Out: CommandOutput;
55
56 fn apply(self, world: &mut World) -> Self::Out;
62
63 #[inline]
66 fn handle_error_with(self, error_handler: ErrorHandler) -> impl Command<Out = ()>
67 where
68 Self: Sized,
69 {
70 move |world: &mut World| {
71 if let Some(error) = self.apply(world).to_err() {
72 error_handler(
73 error,
74 ErrorContext::Command {
75 name: DebugName::type_name::<Self>(),
76 },
77 );
78 }
79 }
80 }
81
82 #[inline]
85 fn handle_error(self) -> impl Command<Out = ()>
86 where
87 Self: Sized,
88 {
89 move |world: &mut World| {
90 if let Some(error) = self.apply(world).to_err() {
91 world.fallback_error_handler()(
92 error,
93 ErrorContext::Command {
94 name: DebugName::type_name::<Self>(),
95 },
96 );
97 }
98 }
99 }
100
101 #[inline]
103 fn ignore_error(self) -> impl Command<Out = ()>
104 where
105 Self: Sized,
106 {
107 move |world: &mut World| {
108 let _ = self.apply(world);
109 }
110 }
111}
112
113impl<F, Out> Command for F
114where
115 F: FnOnce(&mut World) -> Out + Send + 'static,
116 Out: CommandOutput,
117{
118 type Out = Out;
119
120 fn apply(self, world: &mut World) -> Out {
121 self(world)
122 }
123}
124
125#[track_caller]
129pub fn spawn_batch<I>(bundles_iter: I) -> impl Command
130where
131 I: IntoIterator + Send + Sync + 'static,
132 I::Item: Bundle<Effect: NoBundleEffect>,
133{
134 let caller = MaybeLocation::caller();
135 move |world: &mut World| {
136 SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);
137 }
138}
139
140#[track_caller]
147pub fn insert_batch<I, B>(batch: I, insert_mode: InsertMode) -> impl Command
148where
149 I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
150 B: Bundle<Effect: NoBundleEffect>,
151{
152 let caller = MaybeLocation::caller();
153 move |world: &mut World| -> Result {
154 world.try_insert_batch_with_caller(batch, insert_mode, caller)?;
155 Ok(())
156 }
157}
158
159#[track_caller]
162pub fn init_resource<R: Resource + FromWorld>() -> impl Command {
163 move |world: &mut World| {
164 world.init_resource::<R>();
165 }
166}
167
168#[track_caller]
170pub fn insert_resource<R: Resource>(resource: R) -> impl Command {
171 let caller = MaybeLocation::caller();
172 move |world: &mut World| {
173 world.insert_resource_with_caller(resource, caller);
174 }
175}
176
177pub fn remove_resource<R: Resource>() -> impl Command {
179 move |world: &mut World| {
180 world.remove_resource::<R>();
181 }
182}
183
184pub fn run_system<O: 'static>(id: impl Into<SystemId<(), O>> + Send) -> impl Command {
186 let id = id.into();
187 move |world: &mut World| -> Result {
188 world.run_system(id)?;
189 Ok(())
190 }
191}
192
193pub fn run_system_with<I>(
196 id: impl Into<SystemId<I>> + Send,
197 input: I::Inner<'static>,
198) -> impl Command
199where
200 I: SystemInput<Inner<'static>: Send> + 'static,
201{
202 let id = id.into();
203 move |world: &mut World| -> Result {
204 world.run_system_with(id, input)?;
205 Ok(())
206 }
207}
208
209pub fn run_system_cached<M, S>(system: S) -> impl Command
212where
213 M: 'static,
214 S: IntoSystem<(), (), M> + Send + 'static,
215{
216 move |world: &mut World| -> Result {
217 world.run_system_cached(system)?;
218 Ok(())
219 }
220}
221
222pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command
227where
228 I: SystemInput<Inner<'static>: Send> + Send + 'static,
229 M: 'static,
230 S: IntoSystem<I, (), M> + Send + 'static,
231{
232 move |world: &mut World| -> Result {
233 world.run_system_cached_with(system, input)?;
234 Ok(())
235 }
236}
237
238pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command
242where
243 I: SystemInput + Send + 'static,
244 O: Send + 'static,
245{
246 move |world: &mut World| -> Result {
247 world.unregister_system(system_id)?;
248 Ok(())
249 }
250}
251
252pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command
257where
258 I: SystemInput + Send + 'static,
259 O: 'static,
260 M: 'static,
261 S: IntoSystem<I, O, M> + Send + 'static,
262{
263 move |world: &mut World| -> Result {
264 world.unregister_system_cached(system)?;
265 Ok(())
266 }
267}
268
269pub fn run_schedule(label: impl ScheduleLabel) -> impl Command {
271 move |world: &mut World| -> Result {
272 world.try_run_schedule(label)?;
273 Ok(())
274 }
275}
276
277#[track_caller]
281pub fn trigger<'a, E: Event<Trigger<'a>: Default>>(mut event: E) -> impl Command {
282 let caller = MaybeLocation::caller();
283 move |world: &mut World| {
284 world.trigger_ref_with_caller(
285 &mut event,
286 &mut <E::Trigger<'_> as Default>::default(),
287 caller,
288 );
289 }
290}
291
292#[track_caller]
297pub fn trigger_with<E: Event<Trigger<'static>: Send + Sync>>(
298 mut event: E,
299 mut trigger: E::Trigger<'static>,
300) -> impl Command {
301 let caller = MaybeLocation::caller();
302 move |world: &mut World| {
303 world.trigger_ref_with_caller(&mut event, &mut trigger, caller);
304 }
305}
306
307#[track_caller]
309pub fn write_message<M: Message>(message: M) -> impl Command {
310 let caller = MaybeLocation::caller();
311 move |world: &mut World| {
312 let mut messages = world.resource_mut::<Messages<M>>();
313 messages.write_with_caller(message, caller);
314 }
315}