//! Alerting events when a component is removed from an entity. use crate::{ self as bevy_ecs, component::{Component, ComponentId, ComponentIdFor}, entity::Entity, event::{EventId, Events, ManualEventIterator, ManualEventIteratorWithId, ManualEventReader}, prelude::Local, storage::SparseSet, system::{ReadOnlySystemParam, SystemMeta, SystemParam}, world::World, }; use std::{ fmt::Debug, iter, marker::PhantomData, ops::{Deref, DerefMut}, option, }; /// Wrapper around [`Entity`] for [`RemovedComponents`]. /// Internally, `RemovedComponents` uses these as an `Events`. #[derive(Debug, Clone)] pub struct RemovedComponentEntity(Entity); impl From for Entity { fn from(value: RemovedComponentEntity) -> Self { value.0 } } /// Wrapper around a [`ManualEventReader`] so that we /// can differentiate events between components. #[derive(Debug)] pub struct RemovedComponentReader where T: Component, { reader: ManualEventReader, marker: PhantomData, } impl Default for RemovedComponentReader { fn default() -> Self { Self { reader: Default::default(), marker: PhantomData, } } } impl Deref for RemovedComponentReader { type Target = ManualEventReader; fn deref(&self) -> &Self::Target { &self.reader } } impl DerefMut for RemovedComponentReader { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.reader } } /// Wrapper around a map of components to [`Events`]. /// So that we can find the events without naming the type directly. #[derive(Default, Debug)] pub struct RemovedComponentEvents { event_sets: SparseSet>, } impl RemovedComponentEvents { pub fn new() -> Self { Self::default() } pub fn update(&mut self) { for (_component_id, events) in self.event_sets.iter_mut() { events.update(); } } pub fn get( &self, component_id: impl Into, ) -> Option<&Events> { self.event_sets.get(component_id.into()) } pub fn send(&mut self, component_id: impl Into, entity: Entity) { self.event_sets .get_or_insert_with(component_id.into(), Default::default) .send(RemovedComponentEntity(entity)); } } /// A [`SystemParam`] that grants access to the entities that had their `T` [`Component`] removed. /// /// This acts effectively the same as an [`EventReader`](crate::event::EventReader). /// /// Note that this does not allow you to see which data existed before removal. /// If you need this, you will need to track the component data value on your own, /// using a regularly scheduled system that requests `Query<(Entity, &T), Changed>` /// and stores the data somewhere safe to later cross-reference. /// /// If you are using `bevy_ecs` as a standalone crate, /// note that the `RemovedComponents` list will not be automatically cleared for you, /// and will need to be manually flushed using [`World::clear_trackers`](crate::world::World::clear_trackers) /// /// For users of `bevy` and `bevy_app`, this is automatically done in `bevy_app::App::update`. /// For the main world, [`World::clear_trackers`](crate::world::World::clear_trackers) is run after the main schedule is run and after /// `SubApp`'s have run. /// /// # Examples /// /// Basic usage: /// /// ``` /// # use bevy_ecs::component::Component; /// # use bevy_ecs::system::IntoSystem; /// # use bevy_ecs::removal_detection::RemovedComponents; /// # /// # #[derive(Component)] /// # struct MyComponent; /// fn react_on_removal(mut removed: RemovedComponents) { /// removed.iter().for_each(|removed_entity| println!("{:?}", removed_entity)); /// } /// # bevy_ecs::system::assert_is_system(react_on_removal); /// ``` #[derive(SystemParam)] pub struct RemovedComponents<'w, 's, T: Component> { component_id: Local<'s, ComponentIdFor>, reader: Local<'s, RemovedComponentReader>, event_sets: &'w RemovedComponentEvents, } /// Iterator over entities that had a specific component removed. /// /// See [`RemovedComponents`]. pub type RemovedIter<'a> = iter::Map< iter::Flatten>>>, fn(RemovedComponentEntity) -> Entity, >; /// Iterator over entities that had a specific component removed. /// /// See [`RemovedComponents`]. pub type RemovedIterWithId<'a> = iter::Map< iter::Flatten>>, fn( (&RemovedComponentEntity, EventId), ) -> (Entity, EventId), >; fn map_id_events( (entity, id): (&RemovedComponentEntity, EventId), ) -> (Entity, EventId) { (entity.clone().into(), id) } // For all practical purposes, the api surface of `RemovedComponents` // should be similar to `EventReader` to reduce confusion. impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> { /// Fetch underlying [`ManualEventReader`]. pub fn reader(&self) -> &ManualEventReader { &self.reader } /// Fetch underlying [`ManualEventReader`] mutably. pub fn reader_mut(&mut self) -> &mut ManualEventReader { &mut self.reader } /// Fetch underlying [`Events`]. pub fn events(&self) -> Option<&Events> { self.event_sets.get(**self.component_id) } /// Destructures to get a mutable reference to the `ManualEventReader` /// and a reference to `Events`. /// /// This is necessary since Rust can't detect destructuring through methods and most /// usecases of the reader uses the `Events` as well. pub fn reader_mut_with_events( &mut self, ) -> Option<( &mut RemovedComponentReader, &Events, )> { self.event_sets .get(**self.component_id) .map(|events| (&mut *self.reader, events)) } /// Iterates over the events this [`RemovedComponents`] has not seen yet. This updates the /// [`RemovedComponents`]'s event counter, which means subsequent event reads will not include events /// that happened before now. pub fn iter(&mut self) -> RemovedIter<'_> { self.reader_mut_with_events() .map(|(reader, events)| reader.iter(events).cloned()) .into_iter() .flatten() .map(RemovedComponentEntity::into) } /// Like [`iter`](Self::iter), except also returning the [`EventId`] of the events. pub fn iter_with_id(&mut self) -> RemovedIterWithId<'_> { self.reader_mut_with_events() .map(|(reader, events)| reader.iter_with_id(events)) .into_iter() .flatten() .map(map_id_events) } /// Determines the number of removal events available to be read from this [`RemovedComponents`] without consuming any. pub fn len(&self) -> usize { self.events() .map(|events| self.reader.len(events)) .unwrap_or(0) } /// Returns `true` if there are no events available to read. pub fn is_empty(&self) -> bool { self.events() .map(|events| self.reader.is_empty(events)) .unwrap_or(true) } /// Consumes all available events. /// /// This means these events will not appear in calls to [`RemovedComponents::iter()`] or /// [`RemovedComponents::iter_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`. pub fn clear(&mut self) { if let Some((reader, events)) = self.reader_mut_with_events() { reader.clear(events); } } } impl<'a, 'w, 's: 'a, T> IntoIterator for &'a mut RemovedComponents<'w, 's, T> where T: Component, { type Item = Entity; type IntoIter = RemovedIter<'a>; fn into_iter(self) -> Self::IntoIter { self.iter() } } // SAFETY: Only reads World removed component events unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentEvents {} // SAFETY: no component value access, removed component events can be read in parallel and are // never mutably borrowed during system execution unsafe impl<'a> SystemParam for &'a RemovedComponentEvents { type State = (); type Item<'w, 's> = &'w RemovedComponentEvents; fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {} #[inline] unsafe fn get_param<'w, 's>( _state: &'s mut Self::State, _system_meta: &SystemMeta, world: &'w World, _change_tick: u32, ) -> Self::Item<'w, 's> { world.removed_components() } }