Path: blob/main/crates/bevy_ecs/src/world/deferred_world.rs
6604 views
use core::ops::Deref;12use bevy_utils::prelude::DebugName;34use crate::{5archetype::Archetype,6change_detection::{MaybeLocation, MutUntyped},7component::{ComponentId, Mutable},8entity::Entity,9event::{10BufferedEvent, EntityComponentsTrigger, Event, EventId, EventKey, Events, Trigger,11WriteBatchIds,12},13lifecycle::{HookContext, Insert, Replace, INSERT, REPLACE},14observer::TriggerContext,15prelude::{Component, QueryState},16query::{QueryData, QueryFilter},17relationship::RelationshipHookMode,18resource::Resource,19system::{Commands, Query},20world::{error::EntityMutableFetchError, EntityFetcher, WorldEntityFetch},21};2223use super::{unsafe_world_cell::UnsafeWorldCell, Mut, World};2425/// A [`World`] reference that disallows structural ECS changes.26/// This includes initializing resources, registering components or spawning entities.27///28/// This means that in order to add entities, for example, you will need to use commands instead of the world directly.29pub struct DeferredWorld<'w> {30// SAFETY: Implementers must not use this reference to make structural changes31world: UnsafeWorldCell<'w>,32}3334impl<'w> Deref for DeferredWorld<'w> {35type Target = World;3637fn deref(&self) -> &Self::Target {38// SAFETY: Structural changes cannot be made through &World39unsafe { self.world.world() }40}41}4243impl<'w> UnsafeWorldCell<'w> {44/// Turn self into a [`DeferredWorld`]45///46/// # Safety47/// Caller must ensure there are no outstanding mutable references to world and no48/// outstanding references to the world's command queue, resource or component data49#[inline]50pub unsafe fn into_deferred(self) -> DeferredWorld<'w> {51DeferredWorld { world: self }52}53}5455impl<'w> From<&'w mut World> for DeferredWorld<'w> {56fn from(world: &'w mut World) -> DeferredWorld<'w> {57DeferredWorld {58world: world.as_unsafe_world_cell(),59}60}61}6263impl<'w> DeferredWorld<'w> {64/// Reborrow self as a new instance of [`DeferredWorld`]65#[inline]66pub fn reborrow(&mut self) -> DeferredWorld<'_> {67DeferredWorld { world: self.world }68}6970/// Creates a [`Commands`] instance that pushes to the world's command queue71#[inline]72pub fn commands(&mut self) -> Commands<'_, '_> {73// SAFETY: &mut self ensure that there are no outstanding accesses to the queue74let command_queue = unsafe { self.world.get_raw_command_queue() };75// SAFETY: command_queue is stored on world and always valid while the world exists76unsafe { Commands::new_raw_from_entities(command_queue, self.world.entities()) }77}7879/// Retrieves a mutable reference to the given `entity`'s [`Component`] of the given type.80/// Returns `None` if the `entity` does not have a [`Component`] of the given type.81#[inline]82pub fn get_mut<T: Component<Mutability = Mutable>>(83&mut self,84entity: Entity,85) -> Option<Mut<'_, T>> {86self.get_entity_mut(entity).ok()?.into_mut()87}8889/// Temporarily removes a [`Component`] `T` from the provided [`Entity`] and90/// runs the provided closure on it, returning the result if `T` was available.91/// This will trigger the `Remove` and `Replace` component hooks without92/// causing an archetype move.93///94/// This is most useful with immutable components, where removal and reinsertion95/// is the only way to modify a value.96///97/// If you do not need to ensure the above hooks are triggered, and your component98/// is mutable, prefer using [`get_mut`](DeferredWorld::get_mut).99#[inline]100#[track_caller]101pub(crate) fn modify_component_with_relationship_hook_mode<T: Component, R>(102&mut self,103entity: Entity,104relationship_hook_mode: RelationshipHookMode,105f: impl FnOnce(&mut T) -> R,106) -> Result<Option<R>, EntityMutableFetchError> {107// If the component is not registered, then it doesn't exist on this entity, so no action required.108let Some(component_id) = self.component_id::<T>() else {109return Ok(None);110};111112self.modify_component_by_id_with_relationship_hook_mode(113entity,114component_id,115relationship_hook_mode,116move |component| {117// SAFETY: component matches the component_id collected in the above line118let mut component = unsafe { component.with_type::<T>() };119120f(&mut component)121},122)123}124125/// Temporarily removes a [`Component`] identified by the provided126/// [`ComponentId`] from the provided [`Entity`] and runs the provided127/// closure on it, returning the result if the component was available.128/// This will trigger the `Remove` and `Replace` component hooks without129/// causing an archetype move.130///131/// This is most useful with immutable components, where removal and reinsertion132/// is the only way to modify a value.133///134/// If you do not need to ensure the above hooks are triggered, and your component135/// is mutable, prefer using [`get_mut_by_id`](DeferredWorld::get_mut_by_id).136///137/// You should prefer the typed [`modify_component_with_relationship_hook_mode`](DeferredWorld::modify_component_with_relationship_hook_mode)138/// whenever possible.139#[inline]140#[track_caller]141pub(crate) fn modify_component_by_id_with_relationship_hook_mode<R>(142&mut self,143entity: Entity,144component_id: ComponentId,145relationship_hook_mode: RelationshipHookMode,146f: impl for<'a> FnOnce(MutUntyped<'a>) -> R,147) -> Result<Option<R>, EntityMutableFetchError> {148let entity_cell = self.get_entity_mut(entity)?;149150if !entity_cell.contains_id(component_id) {151return Ok(None);152}153154let archetype = &raw const *entity_cell.archetype();155156// SAFETY:157// - DeferredWorld ensures archetype pointer will remain valid as no158// relocations will occur.159// - component_id exists on this world and this entity160// - REPLACE is able to accept ZST events161unsafe {162let archetype = &*archetype;163self.trigger_on_replace(164archetype,165entity,166[component_id].into_iter(),167MaybeLocation::caller(),168relationship_hook_mode,169);170if archetype.has_replace_observer() {171// SAFETY: the REPLACE event_key corresponds to the Replace event's type172self.trigger_raw(173REPLACE,174&mut Replace { entity },175&mut EntityComponentsTrigger {176components: &[component_id],177},178MaybeLocation::caller(),179);180}181}182183let mut entity_cell = self184.get_entity_mut(entity)185.expect("entity access confirmed above");186187// SAFETY: we will run the required hooks to simulate removal/replacement.188let mut component = unsafe {189entity_cell190.get_mut_assume_mutable_by_id(component_id)191.expect("component access confirmed above")192};193194let result = f(component.reborrow());195196// Simulate adding this component by updating the relevant ticks197*component.ticks.added = *component.ticks.changed;198199// SAFETY:200// - DeferredWorld ensures archetype pointer will remain valid as no201// relocations will occur.202// - component_id exists on this world and this entity203// - REPLACE is able to accept ZST events204unsafe {205let archetype = &*archetype;206self.trigger_on_insert(207archetype,208entity,209[component_id].into_iter(),210MaybeLocation::caller(),211relationship_hook_mode,212);213if archetype.has_insert_observer() {214// SAFETY: the INSERT event_key corresponds to the Insert event's type215self.trigger_raw(216INSERT,217&mut Insert { entity },218&mut EntityComponentsTrigger {219components: &[component_id],220},221MaybeLocation::caller(),222);223}224}225226Ok(Some(result))227}228229/// Returns [`EntityMut`]s that expose read and write operations for the230/// given `entities`, returning [`Err`] if any of the given entities do not231/// exist. Instead of immediately unwrapping the value returned from this232/// function, prefer [`World::entity_mut`].233///234/// This function supports fetching a single entity or multiple entities:235/// - Pass an [`Entity`] to receive a single [`EntityMut`].236/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].237/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.238/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].239///240/// **As [`DeferredWorld`] does not allow structural changes, all returned241/// references are [`EntityMut`]s, which do not allow structural changes242/// (i.e. adding/removing components or despawning the entity).**243///244/// # Errors245///246/// - Returns [`EntityMutableFetchError::EntityDoesNotExist`] if any of the given `entities` do not exist in the world.247/// - Only the first entity found to be missing will be returned.248/// - Returns [`EntityMutableFetchError::AliasedMutability`] if the same entity is requested multiple times.249///250/// # Examples251///252/// For examples, see [`DeferredWorld::entity_mut`].253///254/// [`EntityMut`]: crate::world::EntityMut255/// [`&EntityHashSet`]: crate::entity::EntityHashSet256/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap257/// [`Vec<EntityMut>`]: alloc::vec::Vec258#[inline]259pub fn get_entity_mut<F: WorldEntityFetch>(260&mut self,261entities: F,262) -> Result<F::DeferredMut<'_>, EntityMutableFetchError> {263let cell = self.as_unsafe_world_cell();264// SAFETY: `&mut self` gives mutable access to the entire world,265// and prevents any other access to the world.266unsafe { entities.fetch_deferred_mut(cell) }267}268269/// Returns [`EntityMut`]s that expose read and write operations for the270/// given `entities`. This will panic if any of the given entities do not271/// exist. Use [`DeferredWorld::get_entity_mut`] if you want to check for272/// entity existence instead of implicitly panicking.273///274/// This function supports fetching a single entity or multiple entities:275/// - Pass an [`Entity`] to receive a single [`EntityMut`].276/// - Pass a slice of [`Entity`]s to receive a [`Vec<EntityMut>`].277/// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s.278/// - Pass an [`&EntityHashSet`] to receive an [`EntityHashMap<EntityMut>`].279///280/// **As [`DeferredWorld`] does not allow structural changes, all returned281/// references are [`EntityMut`]s, which do not allow structural changes282/// (i.e. adding/removing components or despawning the entity).**283///284/// # Panics285///286/// If any of the given `entities` do not exist in the world.287///288/// # Examples289///290/// ## Single [`Entity`]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 entity = world.spawn(Position { x: 0.0, y: 0.0 }).id();302/// let mut world: DeferredWorld = // ...303/// # DeferredWorld::from(&mut world);304///305/// let mut entity_mut = world.entity_mut(entity);306/// let mut position = entity_mut.get_mut::<Position>().unwrap();307/// position.y = 1.0;308/// assert_eq!(position.x, 0.0);309/// ```310///311/// ## Array of [`Entity`]s312///313/// ```314/// # use bevy_ecs::{prelude::*, world::DeferredWorld};315/// #[derive(Component)]316/// struct Position {317/// x: f32,318/// y: f32,319/// }320///321/// # let mut world = World::new();322/// # let e1 = world.spawn(Position { x: 0.0, y: 0.0 }).id();323/// # let e2 = world.spawn(Position { x: 1.0, y: 1.0 }).id();324/// let mut world: DeferredWorld = // ...325/// # DeferredWorld::from(&mut world);326///327/// let [mut e1_ref, mut e2_ref] = world.entity_mut([e1, e2]);328/// let mut e1_position = e1_ref.get_mut::<Position>().unwrap();329/// e1_position.x = 1.0;330/// assert_eq!(e1_position.x, 1.0);331/// let mut e2_position = e2_ref.get_mut::<Position>().unwrap();332/// e2_position.x = 2.0;333/// assert_eq!(e2_position.x, 2.0);334/// ```335///336/// ## Slice of [`Entity`]s337///338/// ```339/// # use bevy_ecs::{prelude::*, world::DeferredWorld};340/// #[derive(Component)]341/// struct Position {342/// x: f32,343/// y: f32,344/// }345///346/// # let mut world = World::new();347/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();348/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();349/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();350/// let mut world: DeferredWorld = // ...351/// # DeferredWorld::from(&mut world);352///353/// let ids = vec![e1, e2, e3];354/// for mut eref in world.entity_mut(&ids[..]) {355/// let mut pos = eref.get_mut::<Position>().unwrap();356/// pos.y = 2.0;357/// assert_eq!(pos.y, 2.0);358/// }359/// ```360///361/// ## [`&EntityHashSet`]362///363/// ```364/// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld};365/// #[derive(Component)]366/// struct Position {367/// x: f32,368/// y: f32,369/// }370///371/// # let mut world = World::new();372/// # let e1 = world.spawn(Position { x: 0.0, y: 1.0 }).id();373/// # let e2 = world.spawn(Position { x: 0.0, y: 1.0 }).id();374/// # let e3 = world.spawn(Position { x: 0.0, y: 1.0 }).id();375/// let mut world: DeferredWorld = // ...376/// # DeferredWorld::from(&mut world);377///378/// let ids = EntityHashSet::from_iter([e1, e2, e3]);379/// for (_id, mut eref) in world.entity_mut(&ids) {380/// let mut pos = eref.get_mut::<Position>().unwrap();381/// pos.y = 2.0;382/// assert_eq!(pos.y, 2.0);383/// }384/// ```385///386/// [`EntityMut`]: crate::world::EntityMut387/// [`&EntityHashSet`]: crate::entity::EntityHashSet388/// [`EntityHashMap<EntityMut>`]: crate::entity::EntityHashMap389/// [`Vec<EntityMut>`]: alloc::vec::Vec390#[inline]391pub fn entity_mut<F: WorldEntityFetch>(&mut self, entities: F) -> F::DeferredMut<'_> {392self.get_entity_mut(entities).unwrap()393}394395/// Simultaneously provides access to entity data and a command queue, which396/// will be applied when the [`World`] is next flushed.397///398/// This allows using borrowed entity data to construct commands where the399/// borrow checker would otherwise prevent it.400///401/// See [`World::entities_and_commands`] for the non-deferred version.402///403/// # Example404///405/// ```rust406/// # use bevy_ecs::{prelude::*, world::DeferredWorld};407/// #[derive(Component)]408/// struct Targets(Vec<Entity>);409/// #[derive(Component)]410/// struct TargetedBy(Entity);411///412/// # let mut _world = World::new();413/// # let e1 = _world.spawn_empty().id();414/// # let e2 = _world.spawn_empty().id();415/// # let eid = _world.spawn(Targets(vec![e1, e2])).id();416/// let mut world: DeferredWorld = // ...417/// # DeferredWorld::from(&mut _world);418/// let (entities, mut commands) = world.entities_and_commands();419///420/// let entity = entities.get(eid).unwrap();421/// for &target in entity.get::<Targets>().unwrap().0.iter() {422/// commands.entity(target).insert(TargetedBy(eid));423/// }424/// # _world.flush();425/// # assert_eq!(_world.get::<TargetedBy>(e1).unwrap().0, eid);426/// # assert_eq!(_world.get::<TargetedBy>(e2).unwrap().0, eid);427/// ```428pub fn entities_and_commands(&mut self) -> (EntityFetcher<'_>, Commands<'_, '_>) {429let cell = self.as_unsafe_world_cell();430// SAFETY: `&mut self` gives mutable access to the entire world, and prevents simultaneous access.431let fetcher = unsafe { EntityFetcher::new(cell) };432// SAFETY:433// - `&mut self` gives mutable access to the entire world, and prevents simultaneous access.434// - Command queue access does not conflict with entity access.435let raw_queue = unsafe { cell.get_raw_command_queue() };436// SAFETY: `&mut self` ensures the commands does not outlive the world.437let commands = unsafe { Commands::new_raw_from_entities(raw_queue, cell.entities()) };438439(fetcher, commands)440}441442/// Returns [`Query`] for the given [`QueryState`], which is used to efficiently443/// run queries on the [`World`] by storing and reusing the [`QueryState`].444///445/// # Panics446/// If state is from a different world then self447#[inline]448pub fn query<'s, D: QueryData, F: QueryFilter>(449&mut self,450state: &'s mut QueryState<D, F>,451) -> Query<'_, 's, D, F> {452// SAFETY: We have mutable access to the entire world453unsafe { state.query_unchecked(self.world) }454}455456/// Gets a mutable reference to the resource of the given type457///458/// # Panics459///460/// Panics if the resource does not exist.461/// Use [`get_resource_mut`](DeferredWorld::get_resource_mut) instead if you want to handle this case.462#[inline]463#[track_caller]464pub fn resource_mut<R: Resource>(&mut self) -> Mut<'_, R> {465match self.get_resource_mut() {466Some(x) => x,467None => panic!(468"Requested resource {} does not exist in the `World`.469Did you forget to add it using `app.insert_resource` / `app.init_resource`?470Resources are also implicitly added via `app.add_event`,471and can be added by plugins.",472DebugName::type_name::<R>()473),474}475}476477/// Gets a mutable reference to the resource of the given type if it exists478#[inline]479pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {480// SAFETY: &mut self ensure that there are no outstanding accesses to the resource481unsafe { self.world.get_resource_mut() }482}483484/// Gets a mutable reference to the non-send resource of the given type, if it exists.485///486/// # Panics487///488/// Panics if the resource does not exist.489/// Use [`get_non_send_resource_mut`](World::get_non_send_resource_mut) instead if you want to handle this case.490///491/// This function will panic if it isn't called from the same thread that the resource was inserted from.492#[inline]493#[track_caller]494pub fn non_send_resource_mut<R: 'static>(&mut self) -> Mut<'_, R> {495match self.get_non_send_resource_mut() {496Some(x) => x,497None => panic!(498"Requested non-send resource {} does not exist in the `World`.499Did you forget to add it using `app.insert_non_send_resource` / `app.init_non_send_resource`?500Non-send resources can also be added by plugins.",501DebugName::type_name::<R>()502),503}504}505506/// Gets a mutable reference to the non-send resource of the given type, if it exists.507/// Otherwise returns `None`.508///509/// # Panics510/// This function will panic if it isn't called from the same thread that the resource was inserted from.511#[inline]512pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {513// SAFETY: &mut self ensure that there are no outstanding accesses to the resource514unsafe { self.world.get_non_send_resource_mut() }515}516517/// Writes a [`BufferedEvent`].518/// This method returns the [ID](`EventId`) of the written `event`,519/// or [`None`] if the `event` could not be written.520#[inline]521pub fn write_event<E: BufferedEvent>(&mut self, event: E) -> Option<EventId<E>> {522self.write_event_batch(core::iter::once(event))?.next()523}524525/// Writes a [`BufferedEvent`].526/// This method returns the [ID](`EventId`) of the written `event`,527/// or [`None`] if the `event` could not be written.528#[inline]529#[deprecated(since = "0.17.0", note = "Use `DeferredWorld::write_event` instead.")]530pub fn send_event<E: BufferedEvent>(&mut self, event: E) -> Option<EventId<E>> {531self.write_event(event)532}533534/// Writes the default value of the [`BufferedEvent`] of type `E`.535/// This method returns the [ID](`EventId`) of the written `event`,536/// or [`None`] if the `event` could not be written.537#[inline]538pub fn write_event_default<E: BufferedEvent + Default>(&mut self) -> Option<EventId<E>> {539self.write_event(E::default())540}541542/// Writes the default value of the [`BufferedEvent`] of type `E`.543/// This method returns the [ID](`EventId`) of the written `event`,544/// or [`None`] if the `event` could not be written.545#[inline]546#[deprecated(547since = "0.17.0",548note = "Use `DeferredWorld::write_event_default` instead."549)]550pub fn send_event_default<E: BufferedEvent + Default>(&mut self) -> Option<EventId<E>> {551self.write_event_default::<E>()552}553554/// Writes a batch of [`BufferedEvent`]s from an iterator.555/// This method returns the [IDs](`EventId`) of the written `events`,556/// or [`None`] if the `event` could not be written.557#[inline]558pub fn write_event_batch<E: BufferedEvent>(559&mut self,560events: impl IntoIterator<Item = E>,561) -> Option<WriteBatchIds<E>> {562let Some(mut events_resource) = self.get_resource_mut::<Events<E>>() else {563log::error!(564"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 ",565DebugName::type_name::<E>()566);567return None;568};569Some(events_resource.write_batch(events))570}571572/// Writes a batch of [`BufferedEvent`]s from an iterator.573/// This method returns the [IDs](`EventId`) of the written `events`,574/// or [`None`] if the `event` could not be written.575#[inline]576#[deprecated(577since = "0.17.0",578note = "Use `DeferredWorld::write_event_batch` instead."579)]580pub fn send_event_batch<E: BufferedEvent>(581&mut self,582events: impl IntoIterator<Item = E>,583) -> Option<WriteBatchIds<E>> {584self.write_event_batch(events)585}586587/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.588/// The returned pointer may be used to modify the resource, as long as the mutable borrow589/// of the [`World`] is still valid.590///591/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only592/// use this in cases where the actual types are not known at compile time.**593#[inline]594pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {595// SAFETY: &mut self ensure that there are no outstanding accesses to the resource596unsafe { self.world.get_resource_mut_by_id(component_id) }597}598599/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.600/// The returned pointer may be used to modify the resource, as long as the mutable borrow601/// of the [`World`] is still valid.602///603/// **You should prefer to use the typed API [`World::get_resource_mut`] where possible and only604/// use this in cases where the actual types are not known at compile time.**605///606/// # Panics607/// This function will panic if it isn't called from the same thread that the resource was inserted from.608#[inline]609pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {610// SAFETY: &mut self ensure that there are no outstanding accesses to the resource611unsafe { self.world.get_non_send_resource_mut_by_id(component_id) }612}613614/// Retrieves a mutable untyped reference to the given `entity`'s [`Component`] of the given [`ComponentId`].615/// Returns `None` if the `entity` does not have a [`Component`] of the given type.616///617/// **You should prefer to use the typed API [`World::get_mut`] where possible and only618/// use this in cases where the actual types are not known at compile time.**619#[inline]620pub fn get_mut_by_id(621&mut self,622entity: Entity,623component_id: ComponentId,624) -> Option<MutUntyped<'_>> {625self.get_entity_mut(entity)626.ok()?627.into_mut_by_id(component_id)628.ok()629}630631/// Triggers all `on_add` hooks for [`ComponentId`] in target.632///633/// # Safety634/// Caller must ensure [`ComponentId`] in target exist in self.635#[inline]636pub(crate) unsafe fn trigger_on_add(637&mut self,638archetype: &Archetype,639entity: Entity,640targets: impl Iterator<Item = ComponentId>,641caller: MaybeLocation,642) {643if archetype.has_add_hook() {644for component_id in targets {645// SAFETY: Caller ensures that these components exist646let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();647if let Some(hook) = hooks.on_add {648hook(649DeferredWorld { world: self.world },650HookContext {651entity,652component_id,653caller,654relationship_hook_mode: RelationshipHookMode::Run,655},656);657}658}659}660}661662/// Triggers all `on_insert` hooks for [`ComponentId`] in target.663///664/// # Safety665/// Caller must ensure [`ComponentId`] in target exist in self.666#[inline]667pub(crate) unsafe fn trigger_on_insert(668&mut self,669archetype: &Archetype,670entity: Entity,671targets: impl Iterator<Item = ComponentId>,672caller: MaybeLocation,673relationship_hook_mode: RelationshipHookMode,674) {675if archetype.has_insert_hook() {676for component_id in targets {677// SAFETY: Caller ensures that these components exist678let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();679if let Some(hook) = hooks.on_insert {680hook(681DeferredWorld { world: self.world },682HookContext {683entity,684component_id,685caller,686relationship_hook_mode,687},688);689}690}691}692}693694/// Triggers all `on_replace` hooks for [`ComponentId`] in target.695///696/// # Safety697/// Caller must ensure [`ComponentId`] in target exist in self.698#[inline]699pub(crate) unsafe fn trigger_on_replace(700&mut self,701archetype: &Archetype,702entity: Entity,703targets: impl Iterator<Item = ComponentId>,704caller: MaybeLocation,705relationship_hook_mode: RelationshipHookMode,706) {707if archetype.has_replace_hook() {708for component_id in targets {709// SAFETY: Caller ensures that these components exist710let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();711if let Some(hook) = hooks.on_replace {712hook(713DeferredWorld { world: self.world },714HookContext {715entity,716component_id,717caller,718relationship_hook_mode,719},720);721}722}723}724}725726/// Triggers all `on_remove` hooks for [`ComponentId`] in target.727///728/// # Safety729/// Caller must ensure [`ComponentId`] in target exist in self.730#[inline]731pub(crate) unsafe fn trigger_on_remove(732&mut self,733archetype: &Archetype,734entity: Entity,735targets: impl Iterator<Item = ComponentId>,736caller: MaybeLocation,737) {738if archetype.has_remove_hook() {739for component_id in targets {740// SAFETY: Caller ensures that these components exist741let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();742if let Some(hook) = hooks.on_remove {743hook(744DeferredWorld { world: self.world },745HookContext {746entity,747component_id,748caller,749relationship_hook_mode: RelationshipHookMode::Run,750},751);752}753}754}755}756757/// Triggers all `on_despawn` hooks for [`ComponentId`] in target.758///759/// # Safety760/// Caller must ensure [`ComponentId`] in target exist in self.761#[inline]762pub(crate) unsafe fn trigger_on_despawn(763&mut self,764archetype: &Archetype,765entity: Entity,766targets: impl Iterator<Item = ComponentId>,767caller: MaybeLocation,768) {769if archetype.has_despawn_hook() {770for component_id in targets {771// SAFETY: Caller ensures that these components exist772let hooks = unsafe { self.components().get_info_unchecked(component_id) }.hooks();773if let Some(hook) = hooks.on_despawn {774hook(775DeferredWorld { world: self.world },776HookContext {777entity,778component_id,779caller,780relationship_hook_mode: RelationshipHookMode::Run,781},782);783}784}785}786}787788/// Triggers all `event` observers for the given `targets`789///790/// # Safety791/// - Caller must ensure `E` is accessible as the type represented by `event_key`792#[inline]793pub unsafe fn trigger_raw<'a, E: Event>(794&mut self,795event_key: EventKey,796event: &mut E,797trigger: &mut E::Trigger<'a>,798caller: MaybeLocation,799) {800// SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`801let (mut world, observers) = unsafe {802let world = self.as_unsafe_world_cell();803let observers = world.observers();804let Some(observers) = observers.try_get_observers(event_key) else {805return;806};807// SAFETY: The only outstanding reference to world is `observers`808(world.into_deferred(), observers)809};810let context = TriggerContext { event_key, caller };811812// SAFETY:813// - `observers` comes from `world`, and corresponds to the `event_key`, as it was looked up above814// - trigger_context contains the correct event_key for `event`, as enforced by the call to `trigger_raw`815// - This method is being called for an `event` whose `Event::Trigger` matches, as the input trigger is E::Trigger.816unsafe {817trigger.trigger(world.reborrow(), observers, &context, event);818}819}820821/// Sends a global [`Event`] without any targets.822///823/// This will run any [`Observer`] of the given [`Event`] that isn't scoped to specific targets.824///825/// [`Observer`]: crate::observer::Observer826pub fn trigger<'a>(&mut self, event: impl Event<Trigger<'a>: Default>) {827self.commands().trigger(event);828}829830/// Gets an [`UnsafeWorldCell`] containing the underlying world.831///832/// # Safety833/// - must only be used to make non-structural ECS changes834#[inline]835pub(crate) fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {836self.world837}838}839840841