//! This module contains various tools to allow you to react to component insertion or removal,1//! as well as entity spawning and despawning.2//!3//! There are four main ways to react to these lifecycle events:4//!5//! 1. Using component hooks, which act as inherent constructors and destructors for components.6//! 2. Using [observers], which are a user-extensible way to respond to events, including component lifecycle events.7//! 3. Using the [`RemovedComponents`] system parameter, which offers an event-style interface.8//! 4. Using the [`Added`] query filter, which checks each component to see if it has been added since the last time a system ran.9//!10//! [observers]: crate::observer11//! [`Added`]: crate::query::Added12//!13//! # Types of lifecycle events14//!15//! There are five types of lifecycle events, split into two categories. First, we have lifecycle events that are triggered16//! when a component is added to an entity:17//!18//! - [`Add`]: Triggered when a component is added to an entity that did not already have it.19//! - [`Insert`]: Triggered when a component is added to an entity, regardless of whether it already had it.20//!21//! When both events occur, [`Add`] hooks are evaluated before [`Insert`].22//!23//! Next, we have lifecycle events that are triggered when a component is removed from an entity:24//!25//! - [`Replace`]: Triggered when a component is removed from an entity, regardless if it is then replaced with a new value.26//! - [`Remove`]: Triggered when a component is removed from an entity and not replaced, before the component is removed.27//! - [`Despawn`]: Triggered for each component on an entity when it is despawned.28//!29//! [`Replace`] hooks are evaluated before [`Remove`], then finally [`Despawn`] hooks are evaluated.30//!31//! [`Add`] and [`Remove`] are counterparts: they are only triggered when a component is added or removed32//! from an entity in such a way as to cause a change in the component's presence on that entity.33//! Similarly, [`Insert`] and [`Replace`] are counterparts: they are triggered when a component is added or replaced34//! on an entity, regardless of whether this results in a change in the component's presence on that entity.35//!36//! To reliably synchronize data structures using with component lifecycle events,37//! you can combine [`Insert`] and [`Replace`] to fully capture any changes to the data.38//! This is particularly useful in combination with immutable components,39//! to avoid any lifecycle-bypassing mutations.40//!41//! ## Lifecycle events and component types42//!43//! Despite the absence of generics, each lifecycle event is associated with a specific component.44//! When defining a component hook for a [`Component`] type, that component is used.45//! When observers watch lifecycle events, the `B: Bundle` generic is used.46//!47//! Each of these lifecycle events also corresponds to a fixed [`ComponentId`],48//! which are assigned during [`World`] initialization.49//! For example, [`Add`] corresponds to [`ADD`].50//! This is used to skip [`TypeId`](core::any::TypeId) lookups in hot paths.51use crate::{52change_detection::MaybeLocation,53component::{Component, ComponentId, ComponentIdFor, Tick},54entity::Entity,55event::{EntityComponentsTrigger, EntityEvent, EventKey},56message::{57Message, MessageCursor, MessageId, MessageIterator, MessageIteratorWithId, Messages,58},59query::FilteredAccessSet,60relationship::RelationshipHookMode,61storage::SparseSet,62system::{Local, ReadOnlySystemParam, SystemMeta, SystemParam},63world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},64};6566use derive_more::derive::Into;6768#[cfg(feature = "bevy_reflect")]69use bevy_reflect::Reflect;70use core::{71fmt::Debug,72iter,73marker::PhantomData,74ops::{Deref, DerefMut},75option,76};7778/// The type used for [`Component`] lifecycle hooks such as `on_add`, `on_insert` or `on_remove`.79pub type ComponentHook = for<'w> fn(DeferredWorld<'w>, HookContext);8081/// Context provided to a [`ComponentHook`].82#[derive(Clone, Copy, Debug)]83pub struct HookContext {84/// The [`Entity`] this hook was invoked for.85pub entity: Entity,86/// The [`ComponentId`] this hook was invoked for.87pub component_id: ComponentId,88/// The caller location is `Some` if the `track_caller` feature is enabled.89pub caller: MaybeLocation,90/// Configures how relationship hooks will run91pub relationship_hook_mode: RelationshipHookMode,92}9394/// [`World`]-mutating functions that run as part of lifecycle events of a [`Component`].95///96/// Hooks are functions that run when a component is added, overwritten, or removed from an entity.97/// These are intended to be used for structural side effects that need to happen when a component is added or removed,98/// and are not intended for general-purpose logic.99///100/// For example, you might use a hook to update a cached index when a component is added,101/// to clean up resources when a component is removed,102/// or to keep hierarchical data structures across entities in sync.103///104/// This information is stored in the [`ComponentInfo`](crate::component::ComponentInfo) of the associated component.105///106/// There are two ways of configuring hooks for a component:107/// 1. Defining the relevant hooks on the [`Component`] implementation108/// 2. Using the [`World::register_component_hooks`] method109///110/// # Example111///112/// ```113/// use bevy_ecs::prelude::*;114/// use bevy_platform::collections::HashSet;115///116/// #[derive(Component)]117/// struct MyTrackedComponent;118///119/// #[derive(Resource, Default)]120/// struct TrackedEntities(HashSet<Entity>);121///122/// let mut world = World::new();123/// world.init_resource::<TrackedEntities>();124///125/// // No entities with `MyTrackedComponent` have been added yet, so we can safely add component hooks126/// let mut tracked_component_query = world.query::<&MyTrackedComponent>();127/// assert!(tracked_component_query.iter(&world).next().is_none());128///129/// world.register_component_hooks::<MyTrackedComponent>().on_add(|mut world, context| {130/// let mut tracked_entities = world.resource_mut::<TrackedEntities>();131/// tracked_entities.0.insert(context.entity);132/// });133///134/// world.register_component_hooks::<MyTrackedComponent>().on_remove(|mut world, context| {135/// let mut tracked_entities = world.resource_mut::<TrackedEntities>();136/// tracked_entities.0.remove(&context.entity);137/// });138///139/// let entity = world.spawn(MyTrackedComponent).id();140/// let tracked_entities = world.resource::<TrackedEntities>();141/// assert!(tracked_entities.0.contains(&entity));142///143/// world.despawn(entity);144/// let tracked_entities = world.resource::<TrackedEntities>();145/// assert!(!tracked_entities.0.contains(&entity));146/// ```147#[derive(Debug, Clone, Default)]148pub struct ComponentHooks {149pub(crate) on_add: Option<ComponentHook>,150pub(crate) on_insert: Option<ComponentHook>,151pub(crate) on_replace: Option<ComponentHook>,152pub(crate) on_remove: Option<ComponentHook>,153pub(crate) on_despawn: Option<ComponentHook>,154}155156impl ComponentHooks {157pub(crate) fn update_from_component<C: Component + ?Sized>(&mut self) -> &mut Self {158if let Some(hook) = C::on_add() {159self.on_add(hook);160}161if let Some(hook) = C::on_insert() {162self.on_insert(hook);163}164if let Some(hook) = C::on_replace() {165self.on_replace(hook);166}167if let Some(hook) = C::on_remove() {168self.on_remove(hook);169}170if let Some(hook) = C::on_despawn() {171self.on_despawn(hook);172}173174self175}176177/// Register a [`ComponentHook`] that will be run when this component is added to an entity.178/// An `on_add` hook will always run before `on_insert` hooks. Spawning an entity counts as179/// adding all of its components.180///181/// # Panics182///183/// Will panic if the component already has an `on_add` hook184pub fn on_add(&mut self, hook: ComponentHook) -> &mut Self {185self.try_on_add(hook)186.expect("Component already has an on_add hook")187}188189/// Register a [`ComponentHook`] that will be run when this component is added (with `.insert`)190/// or replaced.191///192/// An `on_insert` hook always runs after any `on_add` hooks (if the entity didn't already have the component).193///194/// # Warning195///196/// The hook won't run if the component is already present and is only mutated, such as in a system via a query.197/// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.198///199/// # Panics200///201/// Will panic if the component already has an `on_insert` hook202pub fn on_insert(&mut self, hook: ComponentHook) -> &mut Self {203self.try_on_insert(hook)204.expect("Component already has an on_insert hook")205}206207/// Register a [`ComponentHook`] that will be run when this component is about to be dropped,208/// such as being replaced (with `.insert`) or removed.209///210/// If this component is inserted onto an entity that already has it, this hook will run before the value is replaced,211/// allowing access to the previous data just before it is dropped.212/// This hook does *not* run if the entity did not already have this component.213///214/// An `on_replace` hook always runs before any `on_remove` hooks (if the component is being removed from the entity).215///216/// # Warning217///218/// The hook won't run if the component is already present and is only mutated, such as in a system via a query.219/// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.220///221/// # Panics222///223/// Will panic if the component already has an `on_replace` hook224pub fn on_replace(&mut self, hook: ComponentHook) -> &mut Self {225self.try_on_replace(hook)226.expect("Component already has an on_replace hook")227}228229/// Register a [`ComponentHook`] that will be run when this component is removed from an entity.230/// Despawning an entity counts as removing all of its components.231///232/// # Panics233///234/// Will panic if the component already has an `on_remove` hook235pub fn on_remove(&mut self, hook: ComponentHook) -> &mut Self {236self.try_on_remove(hook)237.expect("Component already has an on_remove hook")238}239240/// Register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.241///242/// # Panics243///244/// Will panic if the component already has an `on_despawn` hook245pub fn on_despawn(&mut self, hook: ComponentHook) -> &mut Self {246self.try_on_despawn(hook)247.expect("Component already has an on_despawn hook")248}249250/// Attempt to register a [`ComponentHook`] that will be run when this component is added to an entity.251///252/// This is a fallible version of [`Self::on_add`].253///254/// Returns `None` if the component already has an `on_add` hook.255pub fn try_on_add(&mut self, hook: ComponentHook) -> Option<&mut Self> {256if self.on_add.is_some() {257return None;258}259self.on_add = Some(hook);260Some(self)261}262263/// Attempt to register a [`ComponentHook`] that will be run when this component is added (with `.insert`)264///265/// This is a fallible version of [`Self::on_insert`].266///267/// Returns `None` if the component already has an `on_insert` hook.268pub fn try_on_insert(&mut self, hook: ComponentHook) -> Option<&mut Self> {269if self.on_insert.is_some() {270return None;271}272self.on_insert = Some(hook);273Some(self)274}275276/// Attempt to register a [`ComponentHook`] that will be run when this component is replaced (with `.insert`) or removed277///278/// This is a fallible version of [`Self::on_replace`].279///280/// Returns `None` if the component already has an `on_replace` hook.281pub fn try_on_replace(&mut self, hook: ComponentHook) -> Option<&mut Self> {282if self.on_replace.is_some() {283return None;284}285self.on_replace = Some(hook);286Some(self)287}288289/// Attempt to register a [`ComponentHook`] that will be run when this component is removed from an entity.290///291/// This is a fallible version of [`Self::on_remove`].292///293/// Returns `None` if the component already has an `on_remove` hook.294pub fn try_on_remove(&mut self, hook: ComponentHook) -> Option<&mut Self> {295if self.on_remove.is_some() {296return None;297}298self.on_remove = Some(hook);299Some(self)300}301302/// Attempt to register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.303///304/// This is a fallible version of [`Self::on_despawn`].305///306/// Returns `None` if the component already has an `on_despawn` hook.307pub fn try_on_despawn(&mut self, hook: ComponentHook) -> Option<&mut Self> {308if self.on_despawn.is_some() {309return None;310}311self.on_despawn = Some(hook);312Some(self)313}314}315316/// [`EventKey`] for [`Add`]317pub const ADD: EventKey = EventKey(ComponentId::new(0));318/// [`EventKey`] for [`Insert`]319pub const INSERT: EventKey = EventKey(ComponentId::new(1));320/// [`EventKey`] for [`Replace`]321pub const REPLACE: EventKey = EventKey(ComponentId::new(2));322/// [`EventKey`] for [`Remove`]323pub const REMOVE: EventKey = EventKey(ComponentId::new(3));324/// [`EventKey`] for [`Despawn`]325pub const DESPAWN: EventKey = EventKey(ComponentId::new(4));326327/// Trigger emitted when a component is inserted onto an entity that does not already have that328/// component. Runs before `Insert`.329/// See [`ComponentHooks::on_add`](`crate::lifecycle::ComponentHooks::on_add`) for more information.330#[derive(Debug, Clone, EntityEvent)]331#[entity_event(trigger = EntityComponentsTrigger<'a>)]332#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]333#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]334#[doc(alias = "OnAdd")]335pub struct Add {336/// The entity this component was added to.337pub entity: Entity,338}339340/// Trigger emitted when a component is inserted, regardless of whether or not the entity already341/// had that component. Runs after `Add`, if it ran.342/// See [`ComponentHooks::on_insert`](`crate::lifecycle::ComponentHooks::on_insert`) for more information.343#[derive(Debug, Clone, EntityEvent)]344#[entity_event(trigger = EntityComponentsTrigger<'a>)]345#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]346#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]347#[doc(alias = "OnInsert")]348pub struct Insert {349/// The entity this component was inserted into.350pub entity: Entity,351}352353/// Trigger emitted when a component is removed from an entity, regardless354/// of whether or not it is later replaced.355///356/// Runs before the value is replaced, so you can still access the original component data.357/// See [`ComponentHooks::on_replace`](`crate::lifecycle::ComponentHooks::on_replace`) for more information.358#[derive(Debug, Clone, EntityEvent)]359#[entity_event(trigger = EntityComponentsTrigger<'a>)]360#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]361#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]362#[doc(alias = "OnReplace")]363pub struct Replace {364/// The entity that held this component before it was replaced.365pub entity: Entity,366}367368/// Trigger emitted when a component is removed from an entity, and runs before the component is369/// removed, so you can still access the component data.370/// See [`ComponentHooks::on_remove`](`crate::lifecycle::ComponentHooks::on_remove`) for more information.371#[derive(Debug, Clone, EntityEvent)]372#[entity_event(trigger = EntityComponentsTrigger<'a>)]373#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]374#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]375#[doc(alias = "OnRemove")]376pub struct Remove {377/// The entity this component was removed from.378pub entity: Entity,379}380381/// [`EntityEvent`] emitted for each component on an entity when it is despawned.382/// See [`ComponentHooks::on_despawn`](`crate::lifecycle::ComponentHooks::on_despawn`) for more information.383#[derive(Debug, Clone, EntityEvent)]384#[entity_event(trigger = EntityComponentsTrigger<'a>)]385#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]386#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]387#[doc(alias = "OnDespawn")]388pub struct Despawn {389/// The entity that held this component before it was despawned.390pub entity: Entity,391}392393/// Deprecated in favor of [`Add`].394#[deprecated(since = "0.17.0", note = "Renamed to `Add`.")]395pub type OnAdd = Add;396397/// Deprecated in favor of [`Insert`].398#[deprecated(since = "0.17.0", note = "Renamed to `Insert`.")]399pub type OnInsert = Insert;400401/// Deprecated in favor of [`Replace`].402#[deprecated(since = "0.17.0", note = "Renamed to `Replace`.")]403pub type OnReplace = Replace;404405/// Deprecated in favor of [`Remove`].406#[deprecated(since = "0.17.0", note = "Renamed to `Remove`.")]407pub type OnRemove = Remove;408409/// Deprecated in favor of [`Despawn`].410#[deprecated(since = "0.17.0", note = "Renamed to `Despawn`.")]411pub type OnDespawn = Despawn;412413/// Wrapper around [`Entity`] for [`RemovedComponents`].414/// Internally, `RemovedComponents` uses these as an [`Messages<RemovedComponentEntity>`].415#[derive(Message, Debug, Clone, Into)]416#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]417#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Clone))]418pub struct RemovedComponentEntity(Entity);419420/// Wrapper around a [`MessageCursor<RemovedComponentEntity>`] so that we421/// can differentiate messages between components.422#[derive(Debug)]423pub struct RemovedComponentReader<T>424where425T: Component,426{427reader: MessageCursor<RemovedComponentEntity>,428marker: PhantomData<T>,429}430431impl<T: Component> Default for RemovedComponentReader<T> {432fn default() -> Self {433Self {434reader: Default::default(),435marker: PhantomData,436}437}438}439440impl<T: Component> Deref for RemovedComponentReader<T> {441type Target = MessageCursor<RemovedComponentEntity>;442fn deref(&self) -> &Self::Target {443&self.reader444}445}446447impl<T: Component> DerefMut for RemovedComponentReader<T> {448fn deref_mut(&mut self) -> &mut Self::Target {449&mut self.reader450}451}452/// Renamed to [`RemovedComponentMessages`].453#[deprecated(since = "0.17.0", note = "Use `RemovedComponentMessages` instead.")]454pub type RemovedComponentEvents = RemovedComponentMessages;455456/// Stores the [`RemovedComponents`] event buffers for all types of component in a given [`World`].457#[derive(Default, Debug)]458pub struct RemovedComponentMessages {459event_sets: SparseSet<ComponentId, Messages<RemovedComponentEntity>>,460}461462impl RemovedComponentMessages {463/// Creates an empty storage buffer for component removal messages.464pub fn new() -> Self {465Self::default()466}467468/// For each type of component, swaps the event buffers and clears the oldest event buffer.469/// In general, this should be called once per frame/update.470pub fn update(&mut self) {471for (_component_id, messages) in self.event_sets.iter_mut() {472messages.update();473}474}475476/// Returns an iterator over components and their entity messages.477pub fn iter(&self) -> impl Iterator<Item = (&ComponentId, &Messages<RemovedComponentEntity>)> {478self.event_sets.iter()479}480481/// Gets the event storage for a given component.482pub fn get(483&self,484component_id: impl Into<ComponentId>,485) -> Option<&Messages<RemovedComponentEntity>> {486self.event_sets.get(component_id.into())487}488489/// Sends a removal message for the specified component.490#[deprecated(491since = "0.17.0",492note = "Use `RemovedComponentMessages:write` instead."493)]494pub fn send(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {495self.write(component_id, entity);496}497498/// Writes a removal message for the specified component.499pub fn write(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {500self.event_sets501.get_or_insert_with(component_id.into(), Default::default)502.write(RemovedComponentEntity(entity));503}504}505506/// A [`SystemParam`] that yields entities that had their `T` [`Component`]507/// removed or have been despawned with it.508///509/// This acts effectively the same as a [`MessageReader`](crate::message::MessageReader).510///511/// Unlike hooks or observers (see the [lifecycle](crate) module docs),512/// this does not allow you to see which data existed before removal.513///514/// If you are using `bevy_ecs` as a standalone crate,515/// note that the [`RemovedComponents`] list will not be automatically cleared for you,516/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).517///518/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is519/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.520/// For the main world, this is delayed until after all `SubApp`s have run.521///522/// # Examples523///524/// Basic usage:525///526/// ```527/// # use bevy_ecs::component::Component;528/// # use bevy_ecs::system::IntoSystem;529/// # use bevy_ecs::lifecycle::RemovedComponents;530/// #531/// # #[derive(Component)]532/// # struct MyComponent;533/// fn react_on_removal(mut removed: RemovedComponents<MyComponent>) {534/// removed.read().for_each(|removed_entity| println!("{}", removed_entity));535/// }536/// # bevy_ecs::system::assert_is_system(react_on_removal);537/// ```538#[derive(SystemParam)]539pub struct RemovedComponents<'w, 's, T: Component> {540component_id: ComponentIdFor<'s, T>,541reader: Local<'s, RemovedComponentReader<T>>,542message_sets: &'w RemovedComponentMessages,543}544545/// Iterator over entities that had a specific component removed.546///547/// See [`RemovedComponents`].548pub type RemovedIter<'a> = iter::Map<549iter::Flatten<option::IntoIter<iter::Cloned<MessageIterator<'a, RemovedComponentEntity>>>>,550fn(RemovedComponentEntity) -> Entity,551>;552553/// Iterator over entities that had a specific component removed.554///555/// See [`RemovedComponents`].556pub type RemovedIterWithId<'a> = iter::Map<557iter::Flatten<option::IntoIter<MessageIteratorWithId<'a, RemovedComponentEntity>>>,558fn(559(&RemovedComponentEntity, MessageId<RemovedComponentEntity>),560) -> (Entity, MessageId<RemovedComponentEntity>),561>;562563fn map_id_messages(564(entity, id): (&RemovedComponentEntity, MessageId<RemovedComponentEntity>),565) -> (Entity, MessageId<RemovedComponentEntity>) {566(entity.clone().into(), id)567}568569// For all practical purposes, the api surface of `RemovedComponents<T>`570// should be similar to `MessageReader<T>` to reduce confusion.571impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> {572/// Fetch underlying [`MessageCursor`].573pub fn reader(&self) -> &MessageCursor<RemovedComponentEntity> {574&self.reader575}576577/// Fetch underlying [`MessageCursor`] mutably.578pub fn reader_mut(&mut self) -> &mut MessageCursor<RemovedComponentEntity> {579&mut self.reader580}581582/// Fetch underlying [`Messages`].583#[deprecated(since = "0.17.0", note = "Renamed to `messages`.")]584pub fn events(&self) -> Option<&Messages<RemovedComponentEntity>> {585self.messages()586}587588/// Fetch underlying [`Messages`].589pub fn messages(&self) -> Option<&Messages<RemovedComponentEntity>> {590self.message_sets.get(self.component_id.get())591}592593/// Destructures to get a mutable reference to the `MessageCursor`594/// and a reference to `Messages`.595///596/// This is necessary since Rust can't detect destructuring through methods and most597/// usecases of the reader uses the `Messages` as well.598pub fn reader_mut_with_messages(599&mut self,600) -> Option<(601&mut RemovedComponentReader<T>,602&Messages<RemovedComponentEntity>,603)> {604self.message_sets605.get(self.component_id.get())606.map(|messages| (&mut *self.reader, messages))607}608609/// Destructures to get a reference to the `MessageCursor`610/// and a reference to `Messages`.611#[deprecated(since = "0.17.0", note = "Renamed to `reader_mut_with_messages`.")]612pub fn reader_mut_with_events(613&mut self,614) -> Option<(615&mut RemovedComponentReader<T>,616&Messages<RemovedComponentEntity>,617)> {618self.reader_mut_with_messages()619}620621/// Iterates over the messages this [`RemovedComponents`] has not seen yet. This updates the622/// [`RemovedComponents`]'s message counter, which means subsequent message reads will not include messages623/// that happened before now.624pub fn read(&mut self) -> RemovedIter<'_> {625self.reader_mut_with_messages()626.map(|(reader, messages)| reader.read(messages).cloned())627.into_iter()628.flatten()629.map(RemovedComponentEntity::into)630}631632/// Like [`read`](Self::read), except also returning the [`MessageId`] of the messages.633pub fn read_with_id(&mut self) -> RemovedIterWithId<'_> {634self.reader_mut_with_messages()635.map(|(reader, messages)| reader.read_with_id(messages))636.into_iter()637.flatten()638.map(map_id_messages)639}640641/// Determines the number of removal messages available to be read from this [`RemovedComponents`] without consuming any.642pub fn len(&self) -> usize {643self.messages()644.map(|messages| self.reader.len(messages))645.unwrap_or(0)646}647648/// Returns `true` if there are no messages available to read.649pub fn is_empty(&self) -> bool {650self.messages()651.is_none_or(|messages| self.reader.is_empty(messages))652}653654/// Consumes all available messages.655///656/// This means these messages will not appear in calls to [`RemovedComponents::read()`] or657/// [`RemovedComponents::read_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`.658pub fn clear(&mut self) {659if let Some((reader, messages)) = self.reader_mut_with_messages() {660reader.clear(messages);661}662}663}664665// SAFETY: Only reads World removed component messages666unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentMessages {}667668// SAFETY: no component value access.669unsafe impl<'a> SystemParam for &'a RemovedComponentMessages {670type State = ();671type Item<'w, 's> = &'w RemovedComponentMessages;672673fn init_state(_world: &mut World) -> Self::State {}674675fn init_access(676_state: &Self::State,677_system_meta: &mut SystemMeta,678_component_access_set: &mut FilteredAccessSet,679_world: &mut World,680) {681}682683#[inline]684unsafe fn get_param<'w, 's>(685_state: &'s mut Self::State,686_system_meta: &SystemMeta,687world: UnsafeWorldCell<'w>,688_change_tick: Tick,689) -> Self::Item<'w, 's> {690world.removed_components()691}692}693694695