bevy_ecs/
removal_detection.rs

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