Path: blob/main/crates/bevy_ecs/src/world/deferred_world.rs
6849 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::{HookContext, Insert, Replace, INSERT, REPLACE},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 { Commands::new_raw_from_entities(command_queue, self.world.entities()) }75}7677/// Retrieves a mutable reference to the given `entity`'s [`Component`] of the given type.78/// Returns `None` if the `entity` does not have a [`Component`] of the given type.79#[inline]80pub fn get_mut<T: Component<Mutability = Mutable>>(81&mut self,82entity: Entity,83) -> Option<Mut<'_, T>> {84self.get_entity_mut(entity).ok()?.into_mut()85}8687/// Temporarily removes a [`Component`] `T` from the provided [`Entity`] and88/// runs the provided closure on it, returning the result if `T` was available.89/// This will trigger the `Remove` and `Replace` component hooks without90/// causing an archetype move.91///92/// This is most useful with immutable components, where removal and reinsertion93/// is the only way to modify a value.94///95/// If you do not need to ensure the above hooks are triggered, and your component96/// is mutable, prefer using [`get_mut`](DeferredWorld::get_mut).97#[inline]98#[track_caller]99pub(crate) fn modify_component_with_relationship_hook_mode<T: Component, R>(100&mut self,101entity: Entity,102relationship_hook_mode: RelationshipHookMode,103f: impl FnOnce(&mut T) -> R,104) -> Result<Option<R>, EntityMutableFetchError> {105// If the component is not registered, then it doesn't exist on this entity, so no action required.106let Some(component_id) = self.component_id::<T>() else {107return Ok(None);108};109110self.modify_component_by_id_with_relationship_hook_mode(111entity,112component_id,113relationship_hook_mode,114move |component| {115// SAFETY: component matches the component_id collected in the above line116let mut component = unsafe { component.with_type::<T>() };117118f(&mut component)119},120)121}122123/// Temporarily removes a [`Component`] identified by the provided124/// [`ComponentId`] from the provided [`Entity`] and runs the provided125/// closure on it, returning the result if the component was available.126/// This will trigger the `Remove` and `Replace` component hooks without127/// causing an archetype move.128///129/// This is most useful with immutable components, where removal and reinsertion130/// is the only way to modify a value.131///132/// If you do not need to ensure the above hooks are triggered, and your component133/// is mutable, prefer using [`get_mut_by_id`](DeferredWorld::get_mut_by_id).134///135/// You should prefer the typed [`modify_component_with_relationship_hook_mode`](DeferredWorld::modify_component_with_relationship_hook_mode)136/// whenever possible.137#[inline]138#[track_caller]139pub(crate) fn modify_component_by_id_with_relationship_hook_mode<R>(140&mut self,141entity: Entity,142component_id: ComponentId,143relationship_hook_mode: RelationshipHookMode,144f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,145) -> Result<Option<R>, EntityMutableFetchError> {146let entity_cell = self.get_entity_mut(entity)?;147148if !entity_cell.contains_id(component_id) {149return Ok(None);150}151152let archetype = &raw const *entity_cell.archetype();153154// SAFETY:155// - DeferredWorld ensures archetype pointer will remain valid as no156// relocations will occur.157// - component_id exists on this world and this entity158// - REPLACE is able to accept ZST events159unsafe {160let archetype = &*archetype;161self.trigger_on_replace(162archetype,163entity,164[component_id].into_iter(),165MaybeLocation::caller(),166relationship_hook_mode,167);168if archetype.has_replace_observer() {169// SAFETY: the REPLACE event_key corresponds to the Replace event's type170self.trigger_raw(171REPLACE,172&mut Replace { entity },173&mut EntityComponentsTrigger {174components: &[component_id],175},176MaybeLocation::caller(),177);178}179}180181let mut entity_cell = self182.get_entity_mut(entity)183.expect("entity access confirmed above");184185// SAFETY: we will run the required hooks to simulate removal/replacement.186let mut component = unsafe {187entity_cell188.get_mut_assume_mutable_by_id(component_id)189.expect("component access confirmed above")190};191192let result = f(component.reborrow());193194// Simulate adding this component by updating the relevant ticks195*component.ticks.added = *component.ticks.changed;196197// SAFETY:198// - DeferredWorld ensures archetype pointer will remain valid as no199// relocations will occur.200// - component_id exists on this world and this entity201// - REPLACE is able to accept ZST events202unsafe {203let archetype = &*archetype;204self.trigger_on_insert(205archetype,206entity,207[component_id].into_iter(),208MaybeLocation::caller(),209relationship_hook_mode,210);211if archetype.has_insert_observer() {212// SAFETY: the INSERT event_key corresponds to the Insert event's type213self.trigger_raw(214INSERT,215&mut Insert { entity },216&mut EntityComponentsTrigger {217components: &[component_id],218},219MaybeLocation::caller(),220);221}222}223224Ok(Some(result))225}226227/// Returns [`EntityMut`]s that expose read and write operations for the228/// given `entities`, returning [`Err`] if any of the given entities do not229/// exist. Instead of immediately unwrapping the value returned from this230/// function, prefer [`World::entity_mut`].231///232/// This function supports fetching a single entity or multiple entities:233/// - Pass an [`Entity`] to receive a single [`EntityMut`].234/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].235/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.236/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].237///238/// **As [`DeferredWorld`] does not allow structural changes, all returned239/// references are [`EntityMut`]s, which do not allow structural changes240/// (i.e. adding/removing components or despawning the entity).**241///242/// # Errors243///244/// - Returns [`EntityMutableFetchError::EntityDoesNotExist`] if any of the given `entities` do not exist in the world.245/// - Only the first entity found to be missing will be returned.246/// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times.247///248/// # Examples249///250/// For examples, see [`DeferredWorld::entity_mut`].251///252/// [`EntityMut`]: crate::world::EntityMut253/// [`&EntityHashSet`]: crate::entity::EntityHashSet254/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap255/// [`Vec<EntityMut>`]: alloc::vec::Vec256#[inline]257pub fn get_entity_mut<F: WorldEntityFetch>(258&mut self,259entities: F,260) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {261let cell = self.as_unsafe_world_cell();262// SAFETY: `&mut self` gives mutable access to the entire world,263// and prevents any other access to the world.264unsafe { entities.fetch_deferred_mut(cell) }265}266267/// Returns [`EntityMut`]s that expose read and write operations for the268/// given `entities`. This will panic if any of the given entities do not269/// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for270/// entity existence instead of implicitly panicking.271///272/// This function supports fetching a single entity or multiple entities:273/// - Pass an [`Entity`] to receive a single [`EntityMut`].274/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].275/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.276/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].277///278/// **As [`DeferredWorld`] does not allow structural changes, all returned279/// references are [`EntityMut`]s, which do not allow structural changes280/// (i.e. adding/removing components or despawning the entity).**281///282/// # Panics283///284/// If any of the given `entities` do not exist in the world.285///286/// # Examples287///288/// ## Single [`Entity`]289///290/// ```291/// # use bevy_ecs::{prelude::*, world::DeferredWorld};292/// #[derive(Component)]293/// struct Position {294/// x: f32,295/// y: f32,296/// }297///298/// # let mut world = World::new();299/// # let entity = world.spawn(Position { x: 0.0, y: 0.0 }).id();300/// let mut world: DeferredWorld = // ...301/// # DeferredWorld::from(&mut world);302///303/// let mut entity_mut = world.entity_mut(entity);304/// let mut position = entity_mut.get_mut::<Position>().unwrap();305/// position.y = 1.0;306/// assert_eq!(position.x, 0.0);307/// ```308///309/// ## Array of [`Entity`]s310///311/// ```312/// # use bevy_ecs::{prelude::*, world::DeferredWorld};313/// #[derive(Component)]314/// struct Position {315/// x: f32,316/// y: f32,317/// }318///319/// # let mut world = World::new();320/// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id();321/// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id();322/// let mut world: DeferredWorld = // ...323/// # DeferredWorld::from(&mut world);324///325/// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]);326/// let mut e1_position = e1_ref.get_mut::<Position>().unwrap();327/// e1_position.x = 1.0;328/// assert_eq!(e1_position.x, 1.0);329/// let mut e2_position = e2_ref.get_mut::<Position>().unwrap();330/// e2_position.x = 2.0;331/// assert_eq!(e2_position.x, 2.0);332/// ```333///334/// ## Slice of [`Entity`]s335///336/// ```337/// # use bevy_ecs::{prelude::*, world::DeferredWorld};338/// #[derive(Component)]339/// struct Position {340/// x: f32,341/// y: f32,342/// }343///344/// # let mut world = World::new();345/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();346/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();347/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();348/// let mut world: DeferredWorld = // ...349/// # DeferredWorld::from(&mut world);350///351/// let ids = vec![e1, e2, e3];352/// for mut eref in world.entity_mut(&ids[..]) {353/// let mut pos = eref.get_mut::<Position>().unwrap();354/// pos.y = 2.0;355/// assert_eq!(pos.y, 2.0);356/// }357/// ```358///359/// ## [`&EntityHashSet`]360///361/// ```362/// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};363/// #[derive(Component)]364/// struct Position {365/// x: f32,366/// y: f32,367/// }368///369/// # let mut world = World::new();370/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();371/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();372/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();373/// let mut world: DeferredWorld = // ...374/// # DeferredWorld::from(&mut world);375///376/// let ids = EntityHashSet::from_iter([e1, e2, e3]);377/// for (_id, mut eref) in world.entity_mut(&ids) {378/// let mut pos = eref.get_mut::<Position>().unwrap();379/// pos.y = 2.0;380/// assert_eq!(pos.y, 2.0);381/// }382/// ```383///384/// [`EntityMut`]: crate::world::EntityMut385/// [`&EntityHashSet`]: crate::entity::EntityHashSet386/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap387/// [`Vec<EntityMut>`]: alloc::vec::Vec388#[inline]389pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {390self.get_entity_mut(entities).unwrap()391}392393/// Simultaneously provides access to entity data and a command queue, which394/// will be applied when the [`World`] is next flushed.395///396/// This allows using borrowed entity data to construct commands where the397/// borrow checker would otherwise prevent it.398///399/// See [`World::entities_and_commands`] for the non-deferred version.400///401/// # Example402///403/// ```rust404/// # use bevy_ecs::{prelude::*, world::DeferredWorld};405/// #[derive(Component)]406/// struct Targets(Vec<Entity>);407/// #[derive(Component)]408/// struct TargetedBy(Entity);409///410/// # let mut _world = World::new();411/// # let e1 = _world.spawn_empty().id();412/// # let e2 = _world.spawn_empty().id();413/// # let eid = _world.spawn(Targets(vec![e1, e2])).id();414/// let mut world: DeferredWorld = // ...415/// # DeferredWorld::from(&mut _world);416/// let (entities, mut commands) = world.entities_and_commands();417///418/// let entity = entities.get(eid).unwrap();419/// for &target in entity.get::<Targets>().unwrap().0.iter() {420/// commands.entity(target).insert(TargetedBy(eid));421/// }422/// # _world.flush();423/// # assert_eq!(_world.get::<TargetedBy>(e1).unwrap().0, eid);424/// # assert_eq!(_world.get::<TargetedBy>(e2).unwrap().0, eid);425/// ```426pub fn entities_and_commands(&mut self) -> (EntityFetcher<'_>, Commands<'_, '_>) {427let cell = self.as_unsafe_world_cell();428// SAFETY: `&mut self` gives mutable access to the entire world, and prevents simultaneous access.429let fetcher = unsafe { EntityFetcher::new(cell) };430// SAFETY:431// - `&mut self` gives mutable access to the entire world, and prevents simultaneous access.432// - Command queue access does not conflict with entity access.433let raw_queue = unsafe { cell.get_raw_command_queue() };434// SAFETY: `&mut self` ensures the commands does not outlive the world.435let commands = unsafe { Commands::new_raw_from_entities(raw_queue, cell.entities()) };436437(fetcher, commands)438}439440/// Returns [`Query`] for the given [`QueryState`], which is used to efficiently441/// run queries on the [`World`] by storing and reusing the [`QueryState`].442///443/// # Panics444/// If state is from a different world then self445#[inline]446pub fn query<'s, D: QueryData, F: QueryFilter>(447&mut self,448state: &'s mut QueryState<D, F>,449) -> Query<'_, 's, D, F> {450// SAFETY: We have mutable access to the entire world451unsafe { state.query_unchecked(self.world) }452}453454/// Gets a mutable reference to the resource of the given type455///456/// # Panics457///458/// Panics if the resource does not exist.459/// Use [`get_resource_mut`](DeferredWorld::get_resource_mut) instead if you want to handle this case.460#[inline]461#[track_caller]462pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {463match self.get_resource_mut() {464Some(x) => x,465None => panic!(466"Requested resource {} does not exist in the `World`.467Did you forget to add it using `app.insert_resource` / `app.init_resource`?468Resources are also implicitly added via `app.add_message`,469and can be added by plugins.",470DebugName::type_name::<R>()471),472}473}474475/// Gets a mutable reference to the resource of the given type if it exists476#[inline]477pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {478// SAFETY: &mut self ensure that there are no outstanding accesses to the resource479unsafe { self.world.get_resource_mut() }480}481482/// Gets a mutable reference to the non-send resource of the given type, if it exists.483///484/// # Panics485///486/// Panics if the resource does not exist.487/// Use [`get_non_send_resource_mut`](World::get_non_send_resource_mut) instead if you want to handle this case.488///489/// This function will panic if it isn't called from the same thread that the resource was inserted from.490#[inline]491#[track_caller]492pub fn non_send_resource_mut<R: 'static>(&mut self) -> Mut<'_, R> {493match self.get_non_send_resource_mut() {494Some(x) => x,495None => panic!(496"Requested non-send resource {} does not exist in the `World`.497Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?498Non-send resources can also be added by plugins.",499DebugName::type_name::<R>()500),501}502}503504/// Gets a mutable reference to the non-send resource of the given type, if it exists.505/// Otherwise returns `None`.506///507/// # Panics508/// This function will panic if it isn't called from the same thread that the resource was inserted from.509#[inline]510pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {511// SAFETY: &mut self ensure that there are no outstanding accesses to the resource512unsafe { self.world.get_non_send_resource_mut() }513}514515/// Writes a [`Message`].516/// This method returns the [`MessageId`] of the written `message`,517/// or [`None`] if the `message` could not be written.518#[inline]519pub fn write_message<M: Message>(&mut self, message: M) -> Option<MessageId<M>> {520self.write_message_batch(core::iter::once(message))?.next()521}522523/// Writes a [`Message`].524/// This method returns the [ID](`MessageId`) of the written `event`,525/// or [`None`] if the `event` could not be written.526#[inline]527#[deprecated(since = "0.17.0", note = "Use `DeferredWorld::write_message` instead.")]528pub fn send_event<E: Message>(&mut self, event: E) -> Option<MessageId<E>> {529self.write_message(event)530}531532/// 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]536pub fn write_message_default<E: Message + Default>(&mut self) -> Option<MessageId<E>> {537self.write_message(E::default())538}539540/// Writes the default value of the [`Message`] of type `E`.541/// This method returns the [ID](`MessageId`) of the written `event`,542/// or [`None`] if the `event` could not be written.543#[inline]544#[deprecated(545since = "0.17.0",546note = "Use `DeferredWorld::write_message_default` instead."547)]548pub fn send_event_default<E: Message + Default>(&mut self) -> Option<MessageId<E>> {549self.write_message_default::<E>()550}551552/// Writes a batch of [`Message`]s from an iterator.553/// This method returns the [IDs](`MessageId`) of the written `events`,554/// or [`None`] if the `event` could not be written.555#[inline]556pub fn write_message_batch<E: Message>(557&mut self,558events: impl IntoIterator<Item = E>,559) -> Option<WriteBatchIds<E>> {560let Some(mut events_resource) = self.get_resource_mut::<Messages<E>>() else {561log::error!(562"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 ",563DebugName::type_name::<E>()564);565return None;566};567Some(events_resource.write_batch(events))568}569570/// Writes a batch of [`Message`]s from an iterator.571/// This method returns the [IDs](`MessageId`) of the written `events`,572/// or [`None`] if the `event` could not be written.573#[inline]574#[deprecated(575since = "0.17.0",576note = "Use `DeferredWorld::write_message_batch` instead."577)]578pub fn send_event_batch<E: Message>(579&mut self,580events: impl IntoIterator<Item = E>,581) -> Option<WriteBatchIds<E>> {582self.write_message_batch(events)583}584585/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.586/// The returned pointer may be used to modify the resource, as long as the mutable borrow587/// of the [`World`] is still valid.588///589/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only590/// use this in cases where the actual types are not known at compile time.**591#[inline]592pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {593// SAFETY: &mut self ensure that there are no outstanding accesses to the resource594unsafe { self.world.get_resource_mut_by_id(component_id) }595}596597/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.598/// The returned pointer may be used to modify the resource, as long as the mutable borrow599/// of the [`World`] is still valid.600///601/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only602/// use this in cases where the actual types are not known at compile time.**603///604/// # Panics605/// This function will panic if it isn't called from the same thread that the resource was inserted from.606#[inline]607pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {608// SAFETY: &mut self ensure that there are no outstanding accesses to the resource609unsafe { self.world.get_non_send_resource_mut_by_id(component_id) }610}611612/// Retrieves a mutable untyped reference to the given `entity`'s [`Component`] of the given [`ComponentId`].613/// Returns `None` if the `entity` does not have a [`Component`] of the given type.614///615/// **You should prefer to use the typed API [`World::get_mut`] where possible and only616/// use this in cases where the actual types are not known at compile time.**617#[inline]618pub fn get_mut_by_id(619&mut self,620entity: Entity,621component_id: ComponentId,622) -> Option<MutUntyped<'_>> {623self.get_entity_mut(entity)624.ok()?625.into_mut_by_id(component_id)626.ok()627}628629/// Triggers all `on_add` hooks for [`ComponentId`] in target.630///631/// # Safety632/// Caller must ensure [`ComponentId`] in target exist in self.633#[inline]634pub(crate) unsafe fn trigger_on_add(635&mut self,636archetype: &Archetype,637entity: Entity,638targets: impl Iterator<Item = ComponentId>,639caller: MaybeLocation,640) {641if archetype.has_add_hook() {642for component_id in targets {643// SAFETY: Caller ensures that these components exist644let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();645if let Some(hook) = hooks.on_add {646hook(647DeferredWorld { world: self.world },648HookContext {649entity,650component_id,651caller,652relationship_hook_mode: RelationshipHookMode::Run,653},654);655}656}657}658}659660/// Triggers all `on_insert` hooks for [`ComponentId`] in target.661///662/// # Safety663/// Caller must ensure [`ComponentId`] in target exist in self.664#[inline]665pub(crate) unsafe fn trigger_on_insert(666&mut self,667archetype: &Archetype,668entity: Entity,669targets: impl Iterator<Item = ComponentId>,670caller: MaybeLocation,671relationship_hook_mode: RelationshipHookMode,672) {673if archetype.has_insert_hook() {674for component_id in targets {675// SAFETY: Caller ensures that these components exist676let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();677if let Some(hook) = hooks.on_insert {678hook(679DeferredWorld { world: self.world },680HookContext {681entity,682component_id,683caller,684relationship_hook_mode,685},686);687}688}689}690}691692/// Triggers all `on_replace` hooks for [`ComponentId`] in target.693///694/// # Safety695/// Caller must ensure [`ComponentId`] in target exist in self.696#[inline]697pub(crate) unsafe fn trigger_on_replace(698&mut self,699archetype: &Archetype,700entity: Entity,701targets: impl Iterator<Item = ComponentId>,702caller: MaybeLocation,703relationship_hook_mode: RelationshipHookMode,704) {705if archetype.has_replace_hook() {706for component_id in targets {707// SAFETY: Caller ensures that these components exist708let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();709if let Some(hook) = hooks.on_replace {710hook(711DeferredWorld { world: self.world },712HookContext {713entity,714component_id,715caller,716relationship_hook_mode,717},718);719}720}721}722}723724/// Triggers all `on_remove` hooks for [`ComponentId`] in target.725///726/// # Safety727/// Caller must ensure [`ComponentId`] in target exist in self.728#[inline]729pub(crate) unsafe fn trigger_on_remove(730&mut self,731archetype: &Archetype,732entity: Entity,733targets: impl Iterator<Item = ComponentId>,734caller: MaybeLocation,735) {736if archetype.has_remove_hook() {737for component_id in targets {738// SAFETY: Caller ensures that these components exist739let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();740if let Some(hook) = hooks.on_remove {741hook(742DeferredWorld { world: self.world },743HookContext {744entity,745component_id,746caller,747relationship_hook_mode: RelationshipHookMode::Run,748},749);750}751}752}753}754755/// Triggers all `on_despawn` hooks for [`ComponentId`] in target.756///757/// # Safety758/// Caller must ensure [`ComponentId`] in target exist in self.759#[inline]760pub(crate) unsafe fn trigger_on_despawn(761&mut self,762archetype: &Archetype,763entity: Entity,764targets: impl Iterator<Item = ComponentId>,765caller: MaybeLocation,766) {767if archetype.has_despawn_hook() {768for component_id in targets {769// SAFETY: Caller ensures that these components exist770let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();771if let Some(hook) = hooks.on_despawn {772hook(773DeferredWorld { world: self.world },774HookContext {775entity,776component_id,777caller,778relationship_hook_mode: RelationshipHookMode::Run,779},780);781}782}783}784}785786/// Triggers all `event` observers for the given `targets`787///788/// # Safety789/// - Caller must ensure `E` is accessible as the type represented by `event_key`790#[inline]791pub unsafe fn trigger_raw<'a, E: Event>(792&mut self,793event_key: EventKey,794event: &mut E,795trigger: &mut E::Trigger<'a>,796caller: MaybeLocation,797) {798// SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`799let (mut world, observers) = unsafe {800let world = self.as_unsafe_world_cell();801let observers = world.observers();802let Some(observers) = observers.try_get_observers(event_key) else {803return;804};805// SAFETY: The only outstanding reference to world is `observers`806(world.into_deferred(), observers)807};808let context = TriggerContext { event_key, caller };809810// SAFETY:811// - `observers` comes from `world`, and corresponds to the `event_key`, as it was looked up above812// - trigger_context contains the correct event_key for `event`, as enforced by the call to `trigger_raw`813// - This method is being called for an `event` whose `Event::Trigger` matches, as the input trigger is E::Trigger.814unsafe {815trigger.trigger(world.reborrow(), observers, &context, event);816}817}818819/// Sends a global [`Event`] without any targets.820///821/// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets.822///823/// [`Observer`]: crate::observer::Observer824pub fn trigger<'a>(&mut self, event: impl Event<Trigger<'a>: Default>) {825self.commands().trigger(event);826}827828/// Gets an [`UnsafeWorldCell`] containing the underlying world.829///830/// # Safety831/// - must only be used to make non-structural ECS changes832#[inline]833pub(crate) fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {834self.world835}836}837838839