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