Path: blob/main/crates/bevy_ecs/src/world/deferred_world.rs
9418 views
use core::ops::Deref;12use bevy_utils::prelude::DebugName;34use crate::{5archetype::Archetype,6change_detection::{MaybeLocation, MutUntyped},7component::{ComponentId, Mutable},8entity::Entity,9event::{EntityComponentsTrigger, Event, EventKey, Trigger},10lifecycle::{Discard, HookContext, Insert, DISCARD, INSERT},11message::{Message, MessageId, Messages, WriteBatchIds},12observer::TriggerContext,13prelude::{Component, QueryState},14query::{QueryData, QueryFilter},15relationship::RelationshipHookMode,16resource::Resource,17system::{Commands, Query},18world::{error::EntityMutableFetchError, EntityFetcher, WorldEntityFetch},19};2021use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World};2223/// A [`World`] reference that disallows structural ECS changes.24/// This includes initializing resources, registering components or spawning entities.25///26/// This means that in order to add entities, for example, you will need to use commands instead of the world directly.27pub struct DeferredWorld<'w> {28// SAFETY: Implementers must not use this reference to make structural changes29world: UnsafeWorldCell<'w>,30}3132impl<'w> Deref for DeferredWorld<'w> {33type Target = World;3435fn deref(&self) -> &Self::Target {36// SAFETY: Structural changes cannot be made through &World37unsafe { self.world.world() }38}39}4041impl<'w> UnsafeWorldCell<'w> {42/// Turn self into a [`DeferredWorld`]43///44/// # Safety45/// Caller must ensure there are no outstanding mutable references to world and no46/// outstanding references to the world's command queue, resource or component data47#[inline]48pub unsafe fn into_deferred(self) -> DeferredWorld<'w> {49DeferredWorld { world: self }50}51}5253impl<'w> From<&'w mut World> for DeferredWorld<'w> {54fn from(world: &'w mut World) -> DeferredWorld<'w> {55DeferredWorld {56world: world.as_unsafe_world_cell(),57}58}59}6061impl<'w> DeferredWorld<'w> {62/// Reborrow self as a new instance of [`DeferredWorld`]63#[inline]64pub fn reborrow(&mut self) -> DeferredWorld<'_> {65DeferredWorld { world: self.world }66}6768/// Creates a [`Commands`] instance that pushes to the world's command queue69#[inline]70pub fn commands(&mut self) -> Commands<'_, '_> {71// SAFETY: &mut self ensure that there are no outstanding accesses to the queue72let command_queue = unsafe { self.world.get_raw_command_queue() };73// SAFETY: command_queue is stored on world and always valid while the world exists74unsafe {75Commands::new_raw_from_entities(76command_queue,77self.world.entity_allocator(),78self.world.entities(),79)80}81}8283/// Retrieves a mutable reference to the given `entity`'s [`Component`] of the given type.84/// Returns `None` if the `entity` does not have a [`Component`] of the given type.85#[inline]86pub fn get_mut<T: Component<Mutability = Mutable>>(87&mut self,88entity: Entity,89) -> Option<Mut<'_, T>> {90self.get_entity_mut(entity).ok()?.into_mut()91}9293/// Temporarily removes a [`Component`] `T` from the provided [`Entity`] and94/// runs the provided closure on it, returning the result if `T` was available.95/// This will trigger the `Remove` and `Discard` component hooks without96/// causing an archetype move.97///98/// This is most useful with immutable components, where removal and reinsertion99/// is the only way to modify a value.100///101/// If you do not need to ensure the above hooks are triggered, and your component102/// is mutable, prefer using [`get_mut`](DeferredWorld::get_mut).103#[inline]104#[track_caller]105pub(crate) fn modify_component_with_relationship_hook_mode<T: Component, R>(106&mut self,107entity: Entity,108relationship_hook_mode: RelationshipHookMode,109f: impl FnOnce(&mut T) -> R,110) -> Result<Option<R>, EntityMutableFetchError> {111// If the component is not registered, then it doesn't exist on this entity, so no action required.112let Some(component_id) = self.component_id::<T>() else {113return Ok(None);114};115116self.modify_component_by_id_with_relationship_hook_mode(117entity,118component_id,119relationship_hook_mode,120move |component| {121// SAFETY: component matches the component_id collected in the above line122let mut component = unsafe { component.with_type::<T>() };123124f(&mut component)125},126)127}128129/// Temporarily removes a [`Component`] identified by the provided130/// [`ComponentId`] from the provided [`Entity`] and runs the provided131/// closure on it, returning the result if the component was available.132/// This will trigger the `Remove` and `Discard` component hooks without133/// causing an archetype move.134///135/// This is most useful with immutable components, where removal and reinsertion136/// is the only way to modify a value.137///138/// If you do not need to ensure the above hooks are triggered, and your component139/// is mutable, prefer using [`get_mut_by_id`](DeferredWorld::get_mut_by_id).140///141/// You should prefer the typed [`modify_component_with_relationship_hook_mode`](DeferredWorld::modify_component_with_relationship_hook_mode)142/// whenever possible.143#[inline]144#[track_caller]145pub(crate) fn modify_component_by_id_with_relationship_hook_mode<R>(146&mut self,147entity: Entity,148component_id: ComponentId,149relationship_hook_mode: RelationshipHookMode,150f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,151) -> Result<Option<R>, EntityMutableFetchError> {152let entity_cell = self.get_entity_mut(entity)?;153154if !entity_cell.contains_id(component_id) {155return Ok(None);156}157158let archetype = &raw const *entity_cell.archetype();159160// SAFETY:161// - DeferredWorld ensures archetype pointer will remain valid as no162// relocations will occur.163// - component_id exists on this world and this entity164// - DISCARD is able to accept ZST events165unsafe {166let archetype = &*archetype;167self.trigger_on_discard(168archetype,169entity,170[component_id].into_iter(),171MaybeLocation::caller(),172relationship_hook_mode,173);174if archetype.has_discard_observer() {175// SAFETY: the DISCARD event_key corresponds to the Discard event's type176self.trigger_raw(177DISCARD,178&mut Discard { entity },179&mut EntityComponentsTrigger {180components: &[component_id],181old_archetype: Some(archetype),182new_archetype: Some(archetype),183},184MaybeLocation::caller(),185);186}187}188189let mut entity_cell = self190.get_entity_mut(entity)191.expect("entity access confirmed above");192193// SAFETY: we will run the required hooks to simulate removal/replacement.194let mut component = unsafe {195entity_cell196.get_mut_assume_mutable_by_id(component_id)197.expect("component access confirmed above")198};199200let result = f(component.reborrow());201202// Simulate adding this component by updating the relevant ticks203*component.ticks.added = *component.ticks.changed;204205// SAFETY:206// - DeferredWorld ensures archetype pointer will remain valid as no207// relocations will occur.208// - component_id exists on this world and this entity209// - DISCARD is able to accept ZST events210unsafe {211let archetype = &*archetype;212self.trigger_on_insert(213archetype,214entity,215[component_id].into_iter(),216MaybeLocation::caller(),217relationship_hook_mode,218);219if archetype.has_insert_observer() {220// SAFETY: the INSERT event_key corresponds to the Insert event's type221self.trigger_raw(222INSERT,223&mut Insert { entity },224&mut EntityComponentsTrigger {225components: &[component_id],226old_archetype: Some(archetype),227new_archetype: Some(archetype),228},229MaybeLocation::caller(),230);231}232}233234Ok(Some(result))235}236237/// Returns [`EntityMut`]s that expose read and write operations for the238/// given `entities`, returning [`Err`] if any of the given entities do not239/// exist. Instead of immediately unwrapping the value returned from this240/// function, prefer [`World::entity_mut`].241///242/// This function supports fetching a single entity or multiple entities:243/// - Pass an [`Entity`] to receive a single [`EntityMut`].244/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].245/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.246/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].247///248/// **As [`DeferredWorld`] does not allow structural changes, all returned249/// references are [`EntityMut`]s, which do not allow structural changes250/// (i.e. adding/removing components or despawning the entity).**251///252/// # Errors253///254/// - Returns [`EntityMutableFetchError::NotSpawned`] if any of the given `entities` do not exist in the world.255/// - Only the first entity found to be missing will be returned.256/// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times.257///258/// # Examples259///260/// For examples, see [`DeferredWorld::entity_mut`].261///262/// [`EntityMut`]: crate::world::EntityMut263/// [`&EntityHashSet`]: crate::entity::EntityHashSet264/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap265/// [`Vec<EntityMut>`]: alloc::vec::Vec266#[inline]267pub fn get_entity_mut<F: WorldEntityFetch>(268&mut self,269entities: F,270) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {271let cell = self.as_unsafe_world_cell();272// SAFETY: `&mut self` gives mutable access to the entire world,273// and prevents any other access to the world.274unsafe { entities.fetch_deferred_mut(cell) }275}276277/// Returns [`EntityMut`]s that expose read and write operations for the278/// given `entities`. This will panic if any of the given entities do not279/// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for280/// entity existence instead of implicitly panicking.281///282/// This function supports fetching a single entity or multiple entities:283/// - Pass an [`Entity`] to receive a single [`EntityMut`].284/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].285/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.286/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].287///288/// **As [`DeferredWorld`] does not allow structural changes, all returned289/// references are [`EntityMut`]s, which do not allow structural changes290/// (i.e. adding/removing components or despawning the entity).**291///292/// # Panics293///294/// If any of the given `entities` do not exist in the world.295///296/// # Examples297///298/// ## Single [`Entity`]299///300/// ```301/// # use bevy_ecs::{prelude::*, world::DeferredWorld};302/// #[derive(Component)]303/// struct Position {304/// x: f32,305/// y: f32,306/// }307///308/// # let mut world = World::new();309/// # let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id();310/// let mut world: DeferredWorld = // ...311/// # DeferredWorld::from(&mut world);312///313/// let mut entity_mut = world.entity_mut(entity);314/// let mut position = entity_mut.get_mut::<Position>().unwrap();315/// position.y = 1.0;316/// assert_eq!(position.x, 0.0);317/// ```318///319/// ## Array of [`Entity`]s320///321/// ```322/// # use bevy_ecs::{prelude::*, world::DeferredWorld};323/// #[derive(Component)]324/// struct Position {325/// x: f32,326/// y: f32,327/// }328///329/// # let mut world = World::new();330/// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id();331/// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id();332/// let mut world: DeferredWorld = // ...333/// # DeferredWorld::from(&mut world);334///335/// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]);336/// let mut e1_position = e1_ref.get_mut::<Position>().unwrap();337/// e1_position.x = 1.0;338/// assert_eq!(e1_position.x, 1.0);339/// let mut e2_position = e2_ref.get_mut::<Position>().unwrap();340/// e2_position.x = 2.0;341/// assert_eq!(e2_position.x, 2.0);342/// ```343///344/// ## Slice of [`Entity`]s345///346/// ```347/// # use bevy_ecs::{prelude::*, world::DeferredWorld};348/// #[derive(Component)]349/// struct Position {350/// x: f32,351/// y: f32,352/// }353///354/// # let mut world = World::new();355/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();356/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();357/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();358/// let mut world: DeferredWorld = // ...359/// # DeferredWorld::from(&mut world);360///361/// let ids = vec![e1, e2, e3];362/// for mut eref in world.entity_mut(&ids[..]) {363/// let mut pos = eref.get_mut::<Position>().unwrap();364/// pos.y = 2.0;365/// assert_eq!(pos.y, 2.0);366/// }367/// ```368///369/// ## [`&EntityHashSet`]370///371/// ```372/// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};373/// #[derive(Component)]374/// struct Position {375/// x: f32,376/// y: f32,377/// }378///379/// # let mut world = World::new();380/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();381/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();382/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();383/// let mut world: DeferredWorld = // ...384/// # DeferredWorld::from(&mut world);385///386/// let ids = EntityHashSet::from_iter([e1, e2, e3]);387/// for (_id, mut eref) in world.entity_mut(&ids) {388/// let mut pos = eref.get_mut::<Position>().unwrap();389/// pos.y = 2.0;390/// assert_eq!(pos.y, 2.0);391/// }392/// ```393///394/// [`EntityMut`]: crate::world::EntityMut395/// [`&EntityHashSet`]: crate::entity::EntityHashSet396/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap397/// [`Vec<EntityMut>`]: alloc::vec::Vec398#[inline]399pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {400self.get_entity_mut(entities).unwrap()401}402403/// Simultaneously provides access to entity data and a command queue, which404/// will be applied when the [`World`] is next flushed.405///406/// This allows using borrowed entity data to construct commands where the407/// borrow checker would otherwise prevent it.408///409/// See [`World::entities_and_commands`] for the non-deferred version.410///411/// # Example412///413/// ```rust414/// # use bevy_ecs::{prelude::*, world::DeferredWorld};415/// #[derive(Component)]416/// struct Targets(Vec<Entity>);417/// #[derive(Component)]418/// struct TargetedBy(Entity);419///420/// # let mut _world = World::new();421/// # let e1 = _world.spawn_empty().id();422/// # let e2 = _world.spawn_empty().id();423/// # let eid = _world.spawn(Targets(vec![e1, e2])).id();424/// let mut world: DeferredWorld = // ...425/// # DeferredWorld::from(&mut _world);426/// let (entities, mut commands) = world.entities_and_commands();427///428/// let entity = entities.get(eid).unwrap();429/// for &target in entity.get::<Targets>().unwrap().0.iter() {430/// commands.entity(target).insert(TargetedBy(eid));431/// }432/// # _world.flush();433/// # assert_eq!(_world.get::<TargetedBy>(e1).unwrap().0, eid);434/// # assert_eq!(_world.get::<TargetedBy>(e2).unwrap().0, eid);435/// ```436pub fn entities_and_commands(&mut self) -> (EntityFetcher<'_>, Commands<'_, '_>) {437let cell = self.as_unsafe_world_cell();438// SAFETY: `&mut self` gives mutable access to the entire world, and prevents simultaneous access.439let fetcher = unsafe { EntityFetcher::new(cell) };440// SAFETY:441// - `&mut self` gives mutable access to the entire world, and prevents simultaneous access.442// - Command queue access does not conflict with entity access.443let raw_queue = unsafe { cell.get_raw_command_queue() };444// SAFETY: `&mut self` ensures the commands does not outlive the world.445let commands = unsafe {446Commands::new_raw_from_entities(raw_queue, cell.entity_allocator(), cell.entities())447};448449(fetcher, commands)450}451452/// Returns [`Query`] for the given [`QueryState`], which is used to efficiently453/// run queries on the [`World`] by storing and reusing the [`QueryState`].454///455/// # Panics456/// If state is from a different world then self457#[inline]458pub fn query<'s, D: QueryData, F: QueryFilter>(459&mut self,460state: &'s mut QueryState<D, F>,461) -> Query<'_, 's, D, F> {462// SAFETY: We have mutable access to the entire world463unsafe { state.query_unchecked(self.world) }464}465466/// Gets a mutable reference to the resource of the given type467///468/// # Panics469///470/// Panics if the resource does not exist.471/// Use [`get_resource_mut`](DeferredWorld::get_resource_mut) instead if you want to handle this case.472#[inline]473#[track_caller]474pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {475match self.get_resource_mut() {476Some(x) => x,477None => panic!(478"Requested resource {} does not exist in the `World`.479Did you forget to add it using `app.insert_resource` / `app.init_resource`?480Resources are also implicitly added via `app.add_message`,481and can be added by plugins.",482DebugName::type_name::<R>()483),484}485}486487/// Gets a mutable reference to the resource of the given type if it exists488#[inline]489pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {490// SAFETY: &mut self ensure that there are no outstanding accesses to the resource491unsafe { self.world.get_resource_mut() }492}493494/// Gets a mutable reference to a non-send resource of the given type, if it exists.495#[deprecated(since = "0.19.0", note = "use DeferredWorld::non_send_mut")]496pub fn non_send_resource_mut<R: 'static>(&mut self) -> Mut<'_, R> {497self.non_send_mut::<R>()498}499500/// Gets a mutable reference to the non-send data of the given type, if it exists.501///502/// # Panics503///504/// Panics if the data does not exist.505/// Use [`get_non_send_mut`](World::get_non_send_mut) instead if you want to handle this case.506///507/// This function will panic if it isn't called from the same thread that the data was inserted from.508#[inline]509#[track_caller]510pub fn non_send_mut<R: 'static>(&mut self) -> Mut<'_, R> {511match self.get_non_send_mut() {512Some(x) => x,513None => panic!(514"Requested non-send data {} does not exist in the `World`.515Did you forget to add it using `app.insert_non_send` / `app.init_non_send`?516Non-send data can also be added by plugins.",517DebugName::type_name::<R>()518),519}520}521522/// Gets a mutable reference to a non-send resource of the given type, if it exists.523/// Otherwise returns `None`.524#[deprecated(since = "0.19.0", note = "use DeferredWorld::get_non_send_mut")]525pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {526self.get_non_send_mut::<R>()527}528529/// Gets a mutable reference to non-send data of the given type, if it exists.530/// Otherwise returns `None`.531///532/// # Panics533/// This function will panic if it isn't called from the same thread that the data was inserted from.534#[inline]535pub fn get_non_send_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {536// SAFETY: &mut self ensure that there are no outstanding accesses to the data537unsafe { self.world.get_non_send_mut() }538}539540/// Writes a [`Message`].541/// This method returns the [`MessageId`] of the written `message`,542/// or [`None`] if the `message` could not be written.543#[inline]544pub fn write_message<M: Message>(&mut self, message: M) -> Option<MessageId<M>> {545self.write_message_batch(core::iter::once(message))?.next()546}547548/// Writes the default value of the [`Message`] of type `E`.549/// This method returns the [`MessageId`] of the written `event`,550/// or [`None`] if the `event` could not be written.551#[inline]552pub fn write_message_default<E: Message + Default>(&mut self) -> Option<MessageId<E>> {553self.write_message(E::default())554}555556/// Writes a batch of [`Message`]s from an iterator.557/// This method returns the [IDs](`MessageId`) of the written `events`,558/// or [`None`] if the `event` could not be written.559#[inline]560pub fn write_message_batch<E: Message>(561&mut self,562events: impl IntoIterator<Item = E>,563) -> Option<WriteBatchIds<E>> {564let Some(mut events_resource) = self.get_resource_mut::<Messages<E>>() else {565log::error!(566"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 ",567DebugName::type_name::<E>()568);569return None;570};571Some(events_resource.write_batch(events))572}573574/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.575/// The returned pointer may be used to modify the resource, as long as the mutable borrow576/// of the [`World`] is still valid.577///578/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only579/// use this in cases where the actual types are not known at compile time.**580#[inline]581pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {582// SAFETY: &mut self ensure that there are no outstanding accesses to the resource583unsafe { self.world.get_resource_mut_by_id(component_id) }584}585586/// Gets mutable access to `!Send` data with the id [`ComponentId`] if it exists.587/// The returned pointer may be used to modify the data, as long as the mutable borrow588/// of the [`World`] is still valid.589///590/// **You should prefer to use the typed API [`DeferredWorld::get_non_send_mut`] where possible591/// and only use this in cases where the actual types are not known at compile time.**592///593/// # Panics594/// This function will panic if it isn't called from the same thread that the data was inserted from.595#[inline]596pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {597// SAFETY: &mut self ensure that there are no outstanding accesses to the data598unsafe { self.world.get_non_send_mut_by_id(component_id) }599}600601/// Retrieves a mutable untyped reference to the given `entity`'s [`Component`] of the given [`ComponentId`].602/// Returns `None` if the `entity` does not have a [`Component`] of the given type.603///604/// **You should prefer to use the typed API [`World::get_mut`] where possible and only605/// use this in cases where the actual types are not known at compile time.**606#[inline]607pub fn get_mut_by_id(608&mut self,609entity: Entity,610component_id: ComponentId,611) -> Option<MutUntyped<'_>> {612self.get_entity_mut(entity)613.ok()?614.into_mut_by_id(component_id)615.ok()616}617618/// Triggers all `on_add` hooks for [`ComponentId`] in target.619///620/// # Safety621/// Caller must ensure [`ComponentId`] in target exist in self.622#[inline]623pub(crate) unsafe fn trigger_on_add(624&mut self,625archetype: &Archetype,626entity: Entity,627targets: impl Iterator<Item = ComponentId>,628caller: MaybeLocation,629) {630if archetype.has_add_hook() {631for component_id in targets {632// SAFETY: Caller ensures that these components exist633let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();634if let Some(hook) = hooks.on_add {635hook(636DeferredWorld { world: self.world },637HookContext {638entity,639component_id,640caller,641relationship_hook_mode: RelationshipHookMode::Run,642},643);644}645}646}647}648649/// Triggers all `on_insert` hooks for [`ComponentId`] in target.650///651/// # Safety652/// Caller must ensure [`ComponentId`] in target exist in self.653#[inline]654pub(crate) unsafe fn trigger_on_insert(655&mut self,656archetype: &Archetype,657entity: Entity,658targets: impl Iterator<Item = ComponentId>,659caller: MaybeLocation,660relationship_hook_mode: RelationshipHookMode,661) {662if archetype.has_insert_hook() {663for component_id in targets {664// SAFETY: Caller ensures that these components exist665let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();666if let Some(hook) = hooks.on_insert {667hook(668DeferredWorld { world: self.world },669HookContext {670entity,671component_id,672caller,673relationship_hook_mode,674},675);676}677}678}679}680681/// Triggers all `on_discard` hooks for [`ComponentId`] in target.682///683/// # Safety684/// Caller must ensure [`ComponentId`] in target exist in self.685#[inline]686pub(crate) unsafe fn trigger_on_discard(687&mut self,688archetype: &Archetype,689entity: Entity,690targets: impl Iterator<Item = ComponentId>,691caller: MaybeLocation,692relationship_hook_mode: RelationshipHookMode,693) {694if archetype.has_discard_hook() {695for component_id in targets {696// SAFETY: Caller ensures that these components exist697let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();698if let Some(hook) = hooks.on_discard {699hook(700DeferredWorld { world: self.world },701HookContext {702entity,703component_id,704caller,705relationship_hook_mode,706},707);708}709}710}711}712713/// Triggers all `on_remove` hooks for [`ComponentId`] in target.714///715/// # Safety716/// Caller must ensure [`ComponentId`] in target exist in self.717#[inline]718pub(crate) unsafe fn trigger_on_remove(719&mut self,720archetype: &Archetype,721entity: Entity,722targets: impl Iterator<Item = ComponentId>,723caller: MaybeLocation,724) {725if archetype.has_remove_hook() {726for component_id in targets {727// SAFETY: Caller ensures that these components exist728let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();729if let Some(hook) = hooks.on_remove {730hook(731DeferredWorld { world: self.world },732HookContext {733entity,734component_id,735caller,736relationship_hook_mode: RelationshipHookMode::Run,737},738);739}740}741}742}743744/// Triggers all `on_despawn` hooks for [`ComponentId`] in target.745///746/// # Safety747/// Caller must ensure [`ComponentId`] in target exist in self.748#[inline]749pub(crate) unsafe fn trigger_on_despawn(750&mut self,751archetype: &Archetype,752entity: Entity,753targets: impl Iterator<Item = ComponentId>,754caller: MaybeLocation,755) {756if archetype.has_despawn_hook() {757for component_id in targets {758// SAFETY: Caller ensures that these components exist759let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();760if let Some(hook) = hooks.on_despawn {761hook(762DeferredWorld { world: self.world },763HookContext {764entity,765component_id,766caller,767relationship_hook_mode: RelationshipHookMode::Run,768},769);770}771}772}773}774775/// Triggers all `event` observers for the given `targets`776///777/// # Safety778/// - Caller must ensure `E` is accessible as the type represented by `event_key`779#[inline]780pub unsafe fn trigger_raw<'a, E: Event>(781&mut self,782event_key: EventKey,783event: &mut E,784trigger: &mut E::Trigger<'a>,785caller: MaybeLocation,786) {787// SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`788let (mut world, observers) = unsafe {789let world = self.as_unsafe_world_cell();790let observers = world.observers();791let Some(observers) = observers.try_get_observers(event_key) else {792return;793};794// SAFETY: The only outstanding reference to world is `observers`795(world.into_deferred(), observers)796};797let context = TriggerContext { event_key, caller };798799// SAFETY:800// - `observers` comes from `world`, and corresponds to the `event_key`, as it was looked up above801// - trigger_context contains the correct event_key for `event`, as enforced by the call to `trigger_raw`802// - This method is being called for an `event` whose `Event::Trigger` matches, as the input trigger is E::Trigger.803unsafe {804trigger.trigger(world.reborrow(), observers, &context, event);805}806}807808/// Sends a global [`Event`] without any targets.809///810/// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets.811///812/// [`Observer`]: crate::observer::Observer813pub fn trigger<'a>(&mut self, event: impl Event<Trigger<'a>: Default>) {814self.commands().trigger(event);815}816817/// Gets an [`UnsafeWorldCell`] containing the underlying world.818///819/// # Safety820/// - must only be used to make non-structural ECS changes821#[inline]822pub fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {823self.world824}825}826827828