bevy_ecs/world/deferred_world.rs
1use core::ops::Deref;
2
3use bevy_utils::prelude::DebugName;
4
5use crate::{
6 archetype::Archetype,
7 change_detection::{MaybeLocation, MutUntyped},
8 component::{ComponentId, Mutable},
9 entity::Entity,
10 event::{EntityComponentsTrigger, Event, EventKey, Trigger},
11 lifecycle::{HookContext, Insert, Replace, INSERT, REPLACE},
12 message::{Message, MessageId, Messages, WriteBatchIds},
13 observer::TriggerContext,
14 prelude::{Component, QueryState},
15 query::{QueryData, QueryFilter},
16 relationship::RelationshipHookMode,
17 resource::Resource,
18 system::{Commands, Query},
19 world::{error::EntityMutableFetchError, EntityFetcher, WorldEntityFetch},
20};
21
22use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World};
23
24/// A [`World`] reference that disallows structural ECS changes.
25/// This includes initializing resources, registering components or spawning entities.
26///
27/// This means that in order to add entities, for example, you will need to use commands instead of the world directly.
28pub struct DeferredWorld<'w> {
29 // SAFETY: Implementers must not use this reference to make structural changes
30 world: UnsafeWorldCell<'w>,
31}
32
33impl<'w> Deref for DeferredWorld<'w> {
34 type Target = World;
35
36 fn deref(&self) -> &Self::Target {
37 // SAFETY: Structural changes cannot be made through &World
38 unsafe { self.world.world() }
39 }
40}
41
42impl<'w> UnsafeWorldCell<'w> {
43 /// Turn self into a [`DeferredWorld`]
44 ///
45 /// # Safety
46 /// Caller must ensure there are no outstanding mutable references to world and no
47 /// outstanding references to the world's command queue, resource or component data
48 #[inline]
49 pub unsafe fn into_deferred(self) -> DeferredWorld<'w> {
50 DeferredWorld { world: self }
51 }
52}
53
54impl<'w> From<&'w mut World> for DeferredWorld<'w> {
55 fn from(world: &'w mut World) -> DeferredWorld<'w> {
56 DeferredWorld {
57 world: world.as_unsafe_world_cell(),
58 }
59 }
60}
61
62impl<'w> DeferredWorld<'w> {
63 /// Reborrow self as a new instance of [`DeferredWorld`]
64 #[inline]
65 pub fn reborrow(&mut self) -> DeferredWorld<'_> {
66 DeferredWorld { world: self.world }
67 }
68
69 /// Creates a [`Commands`] instance that pushes to the world's command queue
70 #[inline]
71 pub fn commands(&mut self) -> Commands<'_, '_> {
72 // SAFETY: &mut self ensure that there are no outstanding accesses to the queue
73 let command_queue = unsafe { self.world.get_raw_command_queue() };
74 // SAFETY: command_queue is stored on world and always valid while the world exists
75 unsafe {
76 Commands::new_raw_from_entities(
77 command_queue,
78 self.world.entities_allocator(),
79 self.world.entities(),
80 )
81 }
82 }
83
84 /// Retrieves a mutable reference to the given `entity`'s [`Component`] of the given type.
85 /// Returns `None` if the `entity` does not have a [`Component`] of the given type.
86 #[inline]
87 pub fn get_mut<T: Component<Mutability = Mutable>>(
88 &mut self,
89 entity: Entity,
90 ) -> Option<Mut<'_, T>> {
91 self.get_entity_mut(entity).ok()?.into_mut()
92 }
93
94 /// Temporarily removes a [`Component`] `T` from the provided [`Entity`] and
95 /// runs the provided closure on it, returning the result if `T` was available.
96 /// This will trigger the `Remove` and `Replace` component hooks without
97 /// causing an archetype move.
98 ///
99 /// This is most useful with immutable components, where removal and reinsertion
100 /// is the only way to modify a value.
101 ///
102 /// If you do not need to ensure the above hooks are triggered, and your component
103 /// is mutable, prefer using [`get_mut`](DeferredWorld::get_mut).
104 #[inline]
105 #[track_caller]
106 pub(crate) fn modify_component_with_relationship_hook_mode<T: Component, R>(
107 &mut self,
108 entity: Entity,
109 relationship_hook_mode: RelationshipHookMode,
110 f: impl FnOnce(&mut T) -> R,
111 ) -> Result<Option<R>, EntityMutableFetchError> {
112 // If the component is not registered, then it doesn't exist on this entity, so no action required.
113 let Some(component_id) = self.component_id::<T>() else {
114 return Ok(None);
115 };
116
117 self.modify_component_by_id_with_relationship_hook_mode(
118 entity,
119 component_id,
120 relationship_hook_mode,
121 move |component| {
122 // SAFETY: component matches the component_id collected in the above line
123 let mut component = unsafe { component.with_type::<T>() };
124
125 f(&mut component)
126 },
127 )
128 }
129
130 /// Temporarily removes a [`Component`] identified by the provided
131 /// [`ComponentId`] from the provided [`Entity`] and runs the provided
132 /// closure on it, returning the result if the component was available.
133 /// This will trigger the `Remove` and `Replace` component hooks without
134 /// causing an archetype move.
135 ///
136 /// This is most useful with immutable components, where removal and reinsertion
137 /// is the only way to modify a value.
138 ///
139 /// If you do not need to ensure the above hooks are triggered, and your component
140 /// is mutable, prefer using [`get_mut_by_id`](DeferredWorld::get_mut_by_id).
141 ///
142 /// You should prefer the typed [`modify_component_with_relationship_hook_mode`](DeferredWorld::modify_component_with_relationship_hook_mode)
143 /// whenever possible.
144 #[inline]
145 #[track_caller]
146 pub(crate) fn modify_component_by_id_with_relationship_hook_mode<R>(
147 &mut self,
148 entity: Entity,
149 component_id: ComponentId,
150 relationship_hook_mode: RelationshipHookMode,
151 f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,
152 ) -> Result<Option<R>, EntityMutableFetchError> {
153 let entity_cell = self.get_entity_mut(entity)?;
154
155 if !entity_cell.contains_id(component_id) {
156 return Ok(None);
157 }
158
159 let archetype = &raw const *entity_cell.archetype();
160
161 // SAFETY:
162 // - DeferredWorld ensures archetype pointer will remain valid as no
163 // relocations will occur.
164 // - component_id exists on this world and this entity
165 // - REPLACE is able to accept ZST events
166 unsafe {
167 let archetype = &*archetype;
168 self.trigger_on_replace(
169 archetype,
170 entity,
171 [component_id].into_iter(),
172 MaybeLocation::caller(),
173 relationship_hook_mode,
174 );
175 if archetype.has_replace_observer() {
176 // SAFETY: the REPLACE event_key corresponds to the Replace event's type
177 self.trigger_raw(
178 REPLACE,
179 &mut Replace { entity },
180 &mut EntityComponentsTrigger {
181 components: &[component_id],
182 },
183 MaybeLocation::caller(),
184 );
185 }
186 }
187
188 let mut entity_cell = self
189 .get_entity_mut(entity)
190 .expect("entity access confirmed above");
191
192 // SAFETY: we will run the required hooks to simulate removal/replacement.
193 let mut component = unsafe {
194 entity_cell
195 .get_mut_assume_mutable_by_id(component_id)
196 .expect("component access confirmed above")
197 };
198
199 let result = f(component.reborrow());
200
201 // Simulate adding this component by updating the relevant ticks
202 *component.ticks.added = *component.ticks.changed;
203
204 // SAFETY:
205 // - DeferredWorld ensures archetype pointer will remain valid as no
206 // relocations will occur.
207 // - component_id exists on this world and this entity
208 // - REPLACE is able to accept ZST events
209 unsafe {
210 let archetype = &*archetype;
211 self.trigger_on_insert(
212 archetype,
213 entity,
214 [component_id].into_iter(),
215 MaybeLocation::caller(),
216 relationship_hook_mode,
217 );
218 if archetype.has_insert_observer() {
219 // SAFETY: the INSERT event_key corresponds to the Insert event's type
220 self.trigger_raw(
221 INSERT,
222 &mut Insert { entity },
223 &mut EntityComponentsTrigger {
224 components: &[component_id],
225 },
226 MaybeLocation::caller(),
227 );
228 }
229 }
230
231 Ok(Some(result))
232 }
233
234 /// Returns [`EntityMut`]s that expose read and write operations for the
235 /// given `entities`, returning [`Err`] if any of the given entities do not
236 /// exist. Instead of immediately unwrapping the value returned from this
237 /// function, prefer [`World::entity_mut`].
238 ///
239 /// This function supports fetching a single entity or multiple entities:
240 /// - Pass an [`Entity`] to receive a single [`EntityMut`].
241 /// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
242 /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
243 /// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].
244 ///
245 /// **As [`DeferredWorld`] does not allow structural changes, all returned
246 /// references are [`EntityMut`]s, which do not allow structural changes
247 /// (i.e. adding/removing components or despawning the entity).**
248 ///
249 /// # Errors
250 ///
251 /// - Returns [`EntityMutableFetchError::NotSpawned`] if any of the given `entities` do not exist in the world.
252 /// - Only the first entity found to be missing will be returned.
253 /// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times.
254 ///
255 /// # Examples
256 ///
257 /// For examples, see [`DeferredWorld::entity_mut`].
258 ///
259 /// [`EntityMut`]: crate::world::EntityMut
260 /// [`&EntityHashSet`]: crate::entity::EntityHashSet
261 /// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
262 /// [`Vec<EntityMut>`]: alloc::vec::Vec
263 #[inline]
264 pub fn get_entity_mut<F: WorldEntityFetch>(
265 &mut self,
266 entities: F,
267 ) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {
268 let cell = self.as_unsafe_world_cell();
269 // SAFETY: `&mut self` gives mutable access to the entire world,
270 // and prevents any other access to the world.
271 unsafe { entities.fetch_deferred_mut(cell) }
272 }
273
274 /// Returns [`EntityMut`]s that expose read and write operations for the
275 /// given `entities`. This will panic if any of the given entities do not
276 /// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for
277 /// entity existence instead of implicitly panicking.
278 ///
279 /// This function supports fetching a single entity or multiple entities:
280 /// - Pass an [`Entity`] to receive a single [`EntityMut`].
281 /// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].
282 /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.
283 /// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].
284 ///
285 /// **As [`DeferredWorld`] does not allow structural changes, all returned
286 /// references are [`EntityMut`]s, which do not allow structural changes
287 /// (i.e. adding/removing components or despawning the entity).**
288 ///
289 /// # Panics
290 ///
291 /// If any of the given `entities` do not exist in the world.
292 ///
293 /// # Examples
294 ///
295 /// ## Single [`Entity`]
296 ///
297 /// ```
298 /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
299 /// #[derive(Component)]
300 /// struct Position {
301 /// x: f32,
302 /// y: f32,
303 /// }
304 ///
305 /// # let mut world = World::new();
306 /// # let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id();
307 /// let mut world: DeferredWorld = // ...
308 /// # DeferredWorld::from(&mut world);
309 ///
310 /// let mut entity_mut = world.entity_mut(entity);
311 /// let mut position = entity_mut.get_mut::<Position>().unwrap();
312 /// position.y = 1.0;
313 /// assert_eq!(position.x, 0.0);
314 /// ```
315 ///
316 /// ## Array of [`Entity`]s
317 ///
318 /// ```
319 /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
320 /// #[derive(Component)]
321 /// struct Position {
322 /// x: f32,
323 /// y: f32,
324 /// }
325 ///
326 /// # let mut world = World::new();
327 /// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id();
328 /// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id();
329 /// let mut world: DeferredWorld = // ...
330 /// # DeferredWorld::from(&mut world);
331 ///
332 /// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]);
333 /// let mut e1_position = e1_ref.get_mut::<Position>().unwrap();
334 /// e1_position.x = 1.0;
335 /// assert_eq!(e1_position.x, 1.0);
336 /// let mut e2_position = e2_ref.get_mut::<Position>().unwrap();
337 /// e2_position.x = 2.0;
338 /// assert_eq!(e2_position.x, 2.0);
339 /// ```
340 ///
341 /// ## Slice of [`Entity`]s
342 ///
343 /// ```
344 /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
345 /// #[derive(Component)]
346 /// struct Position {
347 /// x: f32,
348 /// y: f32,
349 /// }
350 ///
351 /// # let mut world = World::new();
352 /// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
353 /// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
354 /// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
355 /// let mut world: DeferredWorld = // ...
356 /// # DeferredWorld::from(&mut world);
357 ///
358 /// let ids = vec![e1, e2, e3];
359 /// for mut eref in world.entity_mut(&ids[..]) {
360 /// let mut pos = eref.get_mut::<Position>().unwrap();
361 /// pos.y = 2.0;
362 /// assert_eq!(pos.y, 2.0);
363 /// }
364 /// ```
365 ///
366 /// ## [`&EntityHashSet`]
367 ///
368 /// ```
369 /// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};
370 /// #[derive(Component)]
371 /// struct Position {
372 /// x: f32,
373 /// y: f32,
374 /// }
375 ///
376 /// # let mut world = World::new();
377 /// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
378 /// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
379 /// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();
380 /// let mut world: DeferredWorld = // ...
381 /// # DeferredWorld::from(&mut world);
382 ///
383 /// let ids = EntityHashSet::from_iter([e1, e2, e3]);
384 /// for (_id, mut eref) in world.entity_mut(&ids) {
385 /// let mut pos = eref.get_mut::<Position>().unwrap();
386 /// pos.y = 2.0;
387 /// assert_eq!(pos.y, 2.0);
388 /// }
389 /// ```
390 ///
391 /// [`EntityMut`]: crate::world::EntityMut
392 /// [`&EntityHashSet`]: crate::entity::EntityHashSet
393 /// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap
394 /// [`Vec<EntityMut>`]: alloc::vec::Vec
395 #[inline]
396 pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {
397 self.get_entity_mut(entities).unwrap()
398 }
399
400 /// Simultaneously provides access to entity data and a command queue, which
401 /// will be applied when the [`World`] is next flushed.
402 ///
403 /// This allows using borrowed entity data to construct commands where the
404 /// borrow checker would otherwise prevent it.
405 ///
406 /// See [`World::entities_and_commands`] for the non-deferred version.
407 ///
408 /// # Example
409 ///
410 /// ```rust
411 /// # use bevy_ecs::{prelude::*, world::DeferredWorld};
412 /// #[derive(Component)]
413 /// struct Targets(Vec<Entity>);
414 /// #[derive(Component)]
415 /// struct TargetedBy(Entity);
416 ///
417 /// # let mut _world = World::new();
418 /// # let e1 = _world.spawn_empty().id();
419 /// # let e2 = _world.spawn_empty().id();
420 /// # let eid = _world.spawn(Targets(vec![e1, e2])).id();
421 /// let mut world: DeferredWorld = // ...
422 /// # DeferredWorld::from(&mut _world);
423 /// let (entities, mut commands) = world.entities_and_commands();
424 ///
425 /// let entity = entities.get(eid).unwrap();
426 /// for &target in entity.get::<Targets>().unwrap().0.iter() {
427 /// commands.entity(target).insert(TargetedBy(eid));
428 /// }
429 /// # _world.flush();
430 /// # assert_eq!(_world.get::<TargetedBy>(e1).unwrap().0, eid);
431 /// # assert_eq!(_world.get::<TargetedBy>(e2).unwrap().0, eid);
432 /// ```
433 pub fn entities_and_commands(&mut self) -> (EntityFetcher<'_>, Commands<'_, '_>) {
434 let cell = self.as_unsafe_world_cell();
435 // SAFETY: `&mut self` gives mutable access to the entire world, and prevents simultaneous access.
436 let fetcher = unsafe { EntityFetcher::new(cell) };
437 // SAFETY:
438 // - `&mut self` gives mutable access to the entire world, and prevents simultaneous access.
439 // - Command queue access does not conflict with entity access.
440 let raw_queue = unsafe { cell.get_raw_command_queue() };
441 // SAFETY: `&mut self` ensures the commands does not outlive the world.
442 let commands = unsafe {
443 Commands::new_raw_from_entities(raw_queue, cell.entities_allocator(), cell.entities())
444 };
445
446 (fetcher, commands)
447 }
448
449 /// Returns [`Query`] for the given [`QueryState`], which is used to efficiently
450 /// run queries on the [`World`] by storing and reusing the [`QueryState`].
451 ///
452 /// # Panics
453 /// If state is from a different world then self
454 #[inline]
455 pub fn query<'s, D: QueryData, F: QueryFilter>(
456 &mut self,
457 state: &'s mut QueryState<D, F>,
458 ) -> Query<'_, 's, D, F> {
459 // SAFETY: We have mutable access to the entire world
460 unsafe { state.query_unchecked(self.world) }
461 }
462
463 /// Gets a mutable reference to the resource of the given type
464 ///
465 /// # Panics
466 ///
467 /// Panics if the resource does not exist.
468 /// Use [`get_resource_mut`](DeferredWorld::get_resource_mut) instead if you want to handle this case.
469 #[inline]
470 #[track_caller]
471 pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {
472 match self.get_resource_mut() {
473 Some(x) => x,
474 None => panic!(
475 "Requested resource {} does not exist in the `World`.
476 Did you forget to add it using `app.insert_resource` / `app.init_resource`?
477 Resources are also implicitly added via `app.add_message`,
478 and can be added by plugins.",
479 DebugName::type_name::<R>()
480 ),
481 }
482 }
483
484 /// Gets a mutable reference to the resource of the given type if it exists
485 #[inline]
486 pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
487 // SAFETY: &mut self ensure that there are no outstanding accesses to the resource
488 unsafe { self.world.get_resource_mut() }
489 }
490
491 /// Gets a mutable reference to the non-send resource of the given type, if it exists.
492 ///
493 /// # Panics
494 ///
495 /// Panics if the resource does not exist.
496 /// Use [`get_non_send_resource_mut`](World::get_non_send_resource_mut) instead if you want to handle this case.
497 ///
498 /// This function will panic if it isn't called from the same thread that the resource was inserted from.
499 #[inline]
500 #[track_caller]
501 pub fn non_send_resource_mut<R: 'static>(&mut self) -> Mut<'_, R> {
502 match self.get_non_send_resource_mut() {
503 Some(x) => x,
504 None => panic!(
505 "Requested non-send resource {} does not exist in the `World`.
506 Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?
507 Non-send resources can also be added by plugins.",
508 DebugName::type_name::<R>()
509 ),
510 }
511 }
512
513 /// Gets a mutable reference to the non-send resource of the given type, if it exists.
514 /// Otherwise returns `None`.
515 ///
516 /// # Panics
517 /// This function will panic if it isn't called from the same thread that the resource was inserted from.
518 #[inline]
519 pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
520 // SAFETY: &mut self ensure that there are no outstanding accesses to the resource
521 unsafe { self.world.get_non_send_resource_mut() }
522 }
523
524 /// Writes a [`Message`].
525 /// This method returns the [`MessageId`] of the written `message`,
526 /// or [`None`] if the `message` could not be written.
527 #[inline]
528 pub fn write_message<M: Message>(&mut self, message: M) -> Option<MessageId<M>> {
529 self.write_message_batch(core::iter::once(message))?.next()
530 }
531
532 /// Writes the default value of the [`Message`] of type `E`.
533 /// This method returns the [`MessageId`] of the written `event`,
534 /// or [`None`] if the `event` could not be written.
535 #[inline]
536 pub fn write_message_default<E: Message + Default>(&mut self) -> Option<MessageId<E>> {
537 self.write_message(E::default())
538 }
539
540 /// Writes a batch of [`Message`]s from an iterator.
541 /// This method returns the [IDs](`MessageId`) of the written `events`,
542 /// or [`None`] if the `event` could not be written.
543 #[inline]
544 pub fn write_message_batch<E: Message>(
545 &mut self,
546 events: impl IntoIterator<Item = E>,
547 ) -> Option<WriteBatchIds<E>> {
548 let Some(mut events_resource) = self.get_resource_mut::<Messages<E>>() else {
549 log::error!(
550 "Unable to send message `{}`\n\tMessages must be added to the app with `add_message()`\n\thttps://docs.rs/bevy/*/bevy/app/struct.App.html#method.add_message ",
551 DebugName::type_name::<E>()
552 );
553 return None;
554 };
555 Some(events_resource.write_batch(events))
556 }
557
558 /// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
559 /// The returned pointer may be used to modify the resource, as long as the mutable borrow
560 /// of the [`World`] is still valid.
561 ///
562 /// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only
563 /// use this in cases where the actual types are not known at compile time.**
564 #[inline]
565 pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
566 // SAFETY: &mut self ensure that there are no outstanding accesses to the resource
567 unsafe { self.world.get_resource_mut_by_id(component_id) }
568 }
569
570 /// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
571 /// The returned pointer may be used to modify the resource, as long as the mutable borrow
572 /// of the [`World`] is still valid.
573 ///
574 /// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only
575 /// use this in cases where the actual types are not known at compile time.**
576 ///
577 /// # Panics
578 /// This function will panic if it isn't called from the same thread that the resource was inserted from.
579 #[inline]
580 pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
581 // SAFETY: &mut self ensure that there are no outstanding accesses to the resource
582 unsafe { self.world.get_non_send_resource_mut_by_id(component_id) }
583 }
584
585 /// Retrieves a mutable untyped reference to the given `entity`'s [`Component`] of the given [`ComponentId`].
586 /// Returns `None` if the `entity` does not have a [`Component`] of the given type.
587 ///
588 /// **You should prefer to use the typed API [`World::get_mut`] where possible and only
589 /// use this in cases where the actual types are not known at compile time.**
590 #[inline]
591 pub fn get_mut_by_id(
592 &mut self,
593 entity: Entity,
594 component_id: ComponentId,
595 ) -> Option<MutUntyped<'_>> {
596 self.get_entity_mut(entity)
597 .ok()?
598 .into_mut_by_id(component_id)
599 .ok()
600 }
601
602 /// Triggers all `on_add` hooks for [`ComponentId`] in target.
603 ///
604 /// # Safety
605 /// Caller must ensure [`ComponentId`] in target exist in self.
606 #[inline]
607 pub(crate) unsafe fn trigger_on_add(
608 &mut self,
609 archetype: &Archetype,
610 entity: Entity,
611 targets: impl Iterator<Item = ComponentId>,
612 caller: MaybeLocation,
613 ) {
614 if archetype.has_add_hook() {
615 for component_id in targets {
616 // SAFETY: Caller ensures that these components exist
617 let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
618 if let Some(hook) = hooks.on_add {
619 hook(
620 DeferredWorld { world: self.world },
621 HookContext {
622 entity,
623 component_id,
624 caller,
625 relationship_hook_mode: RelationshipHookMode::Run,
626 },
627 );
628 }
629 }
630 }
631 }
632
633 /// Triggers all `on_insert` hooks for [`ComponentId`] in target.
634 ///
635 /// # Safety
636 /// Caller must ensure [`ComponentId`] in target exist in self.
637 #[inline]
638 pub(crate) unsafe fn trigger_on_insert(
639 &mut self,
640 archetype: &Archetype,
641 entity: Entity,
642 targets: impl Iterator<Item = ComponentId>,
643 caller: MaybeLocation,
644 relationship_hook_mode: RelationshipHookMode,
645 ) {
646 if archetype.has_insert_hook() {
647 for component_id in targets {
648 // SAFETY: Caller ensures that these components exist
649 let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
650 if let Some(hook) = hooks.on_insert {
651 hook(
652 DeferredWorld { world: self.world },
653 HookContext {
654 entity,
655 component_id,
656 caller,
657 relationship_hook_mode,
658 },
659 );
660 }
661 }
662 }
663 }
664
665 /// Triggers all `on_replace` hooks for [`ComponentId`] in target.
666 ///
667 /// # Safety
668 /// Caller must ensure [`ComponentId`] in target exist in self.
669 #[inline]
670 pub(crate) unsafe fn trigger_on_replace(
671 &mut self,
672 archetype: &Archetype,
673 entity: Entity,
674 targets: impl Iterator<Item = ComponentId>,
675 caller: MaybeLocation,
676 relationship_hook_mode: RelationshipHookMode,
677 ) {
678 if archetype.has_replace_hook() {
679 for component_id in targets {
680 // SAFETY: Caller ensures that these components exist
681 let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
682 if let Some(hook) = hooks.on_replace {
683 hook(
684 DeferredWorld { world: self.world },
685 HookContext {
686 entity,
687 component_id,
688 caller,
689 relationship_hook_mode,
690 },
691 );
692 }
693 }
694 }
695 }
696
697 /// Triggers all `on_remove` hooks for [`ComponentId`] in target.
698 ///
699 /// # Safety
700 /// Caller must ensure [`ComponentId`] in target exist in self.
701 #[inline]
702 pub(crate) unsafe fn trigger_on_remove(
703 &mut self,
704 archetype: &Archetype,
705 entity: Entity,
706 targets: impl Iterator<Item = ComponentId>,
707 caller: MaybeLocation,
708 ) {
709 if archetype.has_remove_hook() {
710 for component_id in targets {
711 // SAFETY: Caller ensures that these components exist
712 let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
713 if let Some(hook) = hooks.on_remove {
714 hook(
715 DeferredWorld { world: self.world },
716 HookContext {
717 entity,
718 component_id,
719 caller,
720 relationship_hook_mode: RelationshipHookMode::Run,
721 },
722 );
723 }
724 }
725 }
726 }
727
728 /// Triggers all `on_despawn` hooks for [`ComponentId`] in target.
729 ///
730 /// # Safety
731 /// Caller must ensure [`ComponentId`] in target exist in self.
732 #[inline]
733 pub(crate) unsafe fn trigger_on_despawn(
734 &mut self,
735 archetype: &Archetype,
736 entity: Entity,
737 targets: impl Iterator<Item = ComponentId>,
738 caller: MaybeLocation,
739 ) {
740 if archetype.has_despawn_hook() {
741 for component_id in targets {
742 // SAFETY: Caller ensures that these components exist
743 let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();
744 if let Some(hook) = hooks.on_despawn {
745 hook(
746 DeferredWorld { world: self.world },
747 HookContext {
748 entity,
749 component_id,
750 caller,
751 relationship_hook_mode: RelationshipHookMode::Run,
752 },
753 );
754 }
755 }
756 }
757 }
758
759 /// Triggers all `event` observers for the given `targets`
760 ///
761 /// # Safety
762 /// - Caller must ensure `E` is accessible as the type represented by `event_key`
763 #[inline]
764 pub unsafe fn trigger_raw<'a, E: Event>(
765 &mut self,
766 event_key: EventKey,
767 event: &mut E,
768 trigger: &mut E::Trigger<'a>,
769 caller: MaybeLocation,
770 ) {
771 // SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`
772 let (mut world, observers) = unsafe {
773 let world = self.as_unsafe_world_cell();
774 let observers = world.observers();
775 let Some(observers) = observers.try_get_observers(event_key) else {
776 return;
777 };
778 // SAFETY: The only outstanding reference to world is `observers`
779 (world.into_deferred(), observers)
780 };
781 let context = TriggerContext { event_key, caller };
782
783 // SAFETY:
784 // - `observers` comes from `world`, and corresponds to the `event_key`, as it was looked up above
785 // - trigger_context contains the correct event_key for `event`, as enforced by the call to `trigger_raw`
786 // - This method is being called for an `event` whose `Event::Trigger` matches, as the input trigger is E::Trigger.
787 unsafe {
788 trigger.trigger(world.reborrow(), observers, &context, event);
789 }
790 }
791
792 /// Sends a global [`Event`] without any targets.
793 ///
794 /// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets.
795 ///
796 /// [`Observer`]: crate::observer::Observer
797 pub fn trigger<'a>(&mut self, event: impl Event<Trigger<'a>: Default>) {
798 self.commands().trigger(event);
799 }
800
801 /// Gets an [`UnsafeWorldCell`] containing the underlying world.
802 ///
803 /// # Safety
804 /// - must only be used to make non-structural ECS changes
805 #[inline]
806 pub fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {
807 self.world
808 }
809}