bevy_ecs/
removal_detection.rs

1//! Alerting events when a component is removed from an entity.
2
3use crate::{
4    component::{Component, ComponentId, ComponentIdFor, Tick},
5    entity::Entity,
6    event::{Event, EventCursor, EventId, EventIterator, EventIteratorWithId, Events},
7    prelude::Local,
8    storage::SparseSet,
9    system::{ReadOnlySystemParam, SystemMeta, SystemParam},
10    world::{unsafe_world_cell::UnsafeWorldCell, World},
11};
12
13use derive_more::derive::Into;
14
15#[cfg(feature = "bevy_reflect")]
16use bevy_reflect::Reflect;
17use core::{
18    fmt::Debug,
19    iter,
20    marker::PhantomData,
21    ops::{Deref, DerefMut},
22    option,
23};
24
25/// Wrapper around [`Entity`] for [`RemovedComponents`].
26/// Internally, `RemovedComponents` uses these as an `Events<RemovedComponentEntity>`.
27#[derive(Event, Debug, Clone, Into)]
28#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
29#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Clone))]
30pub struct RemovedComponentEntity(Entity);
31
32/// Wrapper around a [`EventCursor<RemovedComponentEntity>`] so that we
33/// can differentiate events between components.
34#[derive(Debug)]
35pub struct RemovedComponentReader<T>
36where
37    T: Component,
38{
39    reader: EventCursor<RemovedComponentEntity>,
40    marker: PhantomData<T>,
41}
42
43impl<T: Component> Default for RemovedComponentReader<T> {
44    fn default() -> Self {
45        Self {
46            reader: Default::default(),
47            marker: PhantomData,
48        }
49    }
50}
51
52impl<T: Component> Deref for RemovedComponentReader<T> {
53    type Target = EventCursor<RemovedComponentEntity>;
54    fn deref(&self) -> &Self::Target {
55        &self.reader
56    }
57}
58
59impl<T: Component> DerefMut for RemovedComponentReader<T> {
60    fn deref_mut(&mut self) -> &mut Self::Target {
61        &mut self.reader
62    }
63}
64
65/// Stores the [`RemovedComponents`] event buffers for all types of component in a given [`World`].
66#[derive(Default, Debug)]
67pub struct RemovedComponentEvents {
68    event_sets: SparseSet<ComponentId, Events<RemovedComponentEntity>>,
69}
70
71impl RemovedComponentEvents {
72    /// Creates an empty storage buffer for component removal events.
73    pub fn new() -> Self {
74        Self::default()
75    }
76
77    /// For each type of component, swaps the event buffers and clears the oldest event buffer.
78    /// In general, this should be called once per frame/update.
79    pub fn update(&mut self) {
80        for (_component_id, events) in self.event_sets.iter_mut() {
81            events.update();
82        }
83    }
84
85    /// Returns an iterator over components and their entity events.
86    pub fn iter(&self) -> impl Iterator<Item = (&ComponentId, &Events<RemovedComponentEntity>)> {
87        self.event_sets.iter()
88    }
89
90    /// Gets the event storage for a given component.
91    pub fn get(
92        &self,
93        component_id: impl Into<ComponentId>,
94    ) -> Option<&Events<RemovedComponentEntity>> {
95        self.event_sets.get(component_id.into())
96    }
97
98    /// Sends a removal event for the specified component.
99    pub fn send(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
100        self.event_sets
101            .get_or_insert_with(component_id.into(), Default::default)
102            .send(RemovedComponentEntity(entity));
103    }
104}
105
106/// A [`SystemParam`] that yields entities that had their `T` [`Component`]
107/// removed or have been despawned with it.
108///
109/// This acts effectively the same as an [`EventReader`](crate::event::EventReader).
110///
111/// Note that this does not allow you to see which data existed before removal.
112/// If you need this, you will need to track the component data value on your own,
113/// using a regularly scheduled system that requests `Query<(Entity, &T), Changed<T>>`
114/// and stores the data somewhere safe to later cross-reference.
115///
116/// If you are using `bevy_ecs` as a standalone crate,
117/// note that the `RemovedComponents` list will not be automatically cleared for you,
118/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).
119///
120/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is
121/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.
122/// For the main world, this is delayed until after all `SubApp`s have run.
123///
124/// # Examples
125///
126/// Basic usage:
127///
128/// ```
129/// # use bevy_ecs::component::Component;
130/// # use bevy_ecs::system::IntoSystem;
131/// # use bevy_ecs::removal_detection::RemovedComponents;
132/// #
133/// # #[derive(Component)]
134/// # struct MyComponent;
135/// fn react_on_removal(mut removed: RemovedComponents<MyComponent>) {
136///     removed.read().for_each(|removed_entity| println!("{}", removed_entity));
137/// }
138/// # bevy_ecs::system::assert_is_system(react_on_removal);
139/// ```
140#[derive(SystemParam)]
141pub struct RemovedComponents<'w, 's, T: Component> {
142    component_id: ComponentIdFor<'s, T>,
143    reader: Local<'s, RemovedComponentReader<T>>,
144    event_sets: &'w RemovedComponentEvents,
145}
146
147/// Iterator over entities that had a specific component removed.
148///
149/// See [`RemovedComponents`].
150pub type RemovedIter<'a> = iter::Map<
151    iter::Flatten<option::IntoIter<iter::Cloned<EventIterator<'a, RemovedComponentEntity>>>>,
152    fn(RemovedComponentEntity) -> Entity,
153>;
154
155/// Iterator over entities that had a specific component removed.
156///
157/// See [`RemovedComponents`].
158pub type RemovedIterWithId<'a> = iter::Map<
159    iter::Flatten<option::IntoIter<EventIteratorWithId<'a, RemovedComponentEntity>>>,
160    fn(
161        (&RemovedComponentEntity, EventId<RemovedComponentEntity>),
162    ) -> (Entity, EventId<RemovedComponentEntity>),
163>;
164
165fn map_id_events(
166    (entity, id): (&RemovedComponentEntity, EventId<RemovedComponentEntity>),
167) -> (Entity, EventId<RemovedComponentEntity>) {
168    (entity.clone().into(), id)
169}
170
171// For all practical purposes, the api surface of `RemovedComponents<T>`
172// should be similar to `EventReader<T>` to reduce confusion.
173impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> {
174    /// Fetch underlying [`EventCursor`].
175    pub fn reader(&self) -> &EventCursor<RemovedComponentEntity> {
176        &self.reader
177    }
178
179    /// Fetch underlying [`EventCursor`] mutably.
180    pub fn reader_mut(&mut self) -> &mut EventCursor<RemovedComponentEntity> {
181        &mut self.reader
182    }
183
184    /// Fetch underlying [`Events`].
185    pub fn events(&self) -> Option<&Events<RemovedComponentEntity>> {
186        self.event_sets.get(self.component_id.get())
187    }
188
189    /// Destructures to get a mutable reference to the `EventCursor`
190    /// and a reference to `Events`.
191    ///
192    /// This is necessary since Rust can't detect destructuring through methods and most
193    /// usecases of the reader uses the `Events` as well.
194    pub fn reader_mut_with_events(
195        &mut self,
196    ) -> Option<(
197        &mut RemovedComponentReader<T>,
198        &Events<RemovedComponentEntity>,
199    )> {
200        self.event_sets
201            .get(self.component_id.get())
202            .map(|events| (&mut *self.reader, events))
203    }
204
205    /// Iterates over the events this [`RemovedComponents`] has not seen yet. This updates the
206    /// [`RemovedComponents`]'s event counter, which means subsequent event reads will not include events
207    /// that happened before now.
208    pub fn read(&mut self) -> RemovedIter<'_> {
209        self.reader_mut_with_events()
210            .map(|(reader, events)| reader.read(events).cloned())
211            .into_iter()
212            .flatten()
213            .map(RemovedComponentEntity::into)
214    }
215
216    /// Like [`read`](Self::read), except also returning the [`EventId`] of the events.
217    pub fn read_with_id(&mut self) -> RemovedIterWithId<'_> {
218        self.reader_mut_with_events()
219            .map(|(reader, events)| reader.read_with_id(events))
220            .into_iter()
221            .flatten()
222            .map(map_id_events)
223    }
224
225    /// Determines the number of removal events available to be read from this [`RemovedComponents`] without consuming any.
226    pub fn len(&self) -> usize {
227        self.events()
228            .map(|events| self.reader.len(events))
229            .unwrap_or(0)
230    }
231
232    /// Returns `true` if there are no events available to read.
233    pub fn is_empty(&self) -> bool {
234        self.events()
235            .is_none_or(|events| self.reader.is_empty(events))
236    }
237
238    /// Consumes all available events.
239    ///
240    /// This means these events will not appear in calls to [`RemovedComponents::read()`] or
241    /// [`RemovedComponents::read_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`.
242    pub fn clear(&mut self) {
243        if let Some((reader, events)) = self.reader_mut_with_events() {
244            reader.clear(events);
245        }
246    }
247}
248
249// SAFETY: Only reads World removed component events
250unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentEvents {}
251
252// SAFETY: no component value access.
253unsafe impl<'a> SystemParam for &'a RemovedComponentEvents {
254    type State = ();
255    type Item<'w, 's> = &'w RemovedComponentEvents;
256
257    fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {}
258
259    #[inline]
260    unsafe fn get_param<'w, 's>(
261        _state: &'s mut Self::State,
262        _system_meta: &SystemMeta,
263        world: UnsafeWorldCell<'w>,
264        _change_tick: Tick,
265    ) -> Self::Item<'w, 's> {
266        world.removed_components()
267    }
268}