Path: blob/main/crates/bevy_ecs/src/observer/distributed_storage.rs
6604 views
//! Information about observers that is stored on the entities themselves.1//!2//! This allows for easier cleanup, better inspection, and more flexible querying.3//!4//! Each observer is associated with an entity, defined by the [`Observer`] component.5//! The [`Observer`] component contains the system that will be run when the observer is triggered,6//! and the [`ObserverDescriptor`] which contains information about what the observer is observing.7//!8//! When we watch entities, we add the [`ObservedBy`] component to those entities,9//! which links back to the observer entity.1011use core::any::Any;1213use crate::{14component::{15ComponentCloneBehavior, ComponentId, Mutable, RequiredComponentsRegistrator, StorageType,16},17entity::Entity,18entity_disabling::Internal,19error::{ErrorContext, ErrorHandler},20event::Event,21lifecycle::{ComponentHook, HookContext},22observer::{observer_system_runner, ObserverRunner},23prelude::*,24system::{IntoObserverSystem, ObserverSystem},25world::DeferredWorld,26};27use alloc::boxed::Box;28use alloc::vec::Vec;29use bevy_utils::prelude::DebugName;3031#[cfg(feature = "bevy_reflect")]32use crate::prelude::ReflectComponent;3334/// An [`Observer`] system. Add this [`Component`] to an [`Entity`] to turn it into an "observer".35///36/// Observers watch for a "trigger" of a specific [`Event`]. An event can be triggered on the [`World`]37/// by calling [`World::trigger`]. It can also be queued up as a [`Command`] using [`Commands::trigger`].38///39/// When a [`World`] triggers an [`Event`], it will immediately run every [`Observer`] that watches for that [`Event`].40///41/// # Usage42///43/// The simplest usage of the observer pattern looks like this:44///45/// ```46/// # use bevy_ecs::prelude::*;47/// # let mut world = World::default();48/// #[derive(Event)]49/// struct Speak {50/// message: String,51/// }52///53/// world.add_observer(|event: On<Speak>| {54/// println!("{}", event.message);55/// });56///57/// world.trigger(Speak {58/// message: "Hello!".into(),59/// });60/// ```61///62/// Notice that we used [`World::add_observer`]. This is just a shorthand for spawning an [`Entity`] with an [`Observer`] manually:63///64/// ```65/// # use bevy_ecs::prelude::*;66/// # let mut world = World::default();67/// # #[derive(Event)]68/// # struct Speak;69/// // These are functionally the same:70/// world.add_observer(|event: On<Speak>| {});71/// world.spawn(Observer::new(|event: On<Speak>| {}));72/// ```73///74/// Observers are a specialized [`System`] called an [`ObserverSystem`]. The first parameter must be [`On`], which provides access75/// to the [`Event`], the [`Trigger`], and some additional execution context.76///77/// Because they are systems, they can access arbitrary [`World`] data by adding [`SystemParam`]s:78///79/// ```80/// # use bevy_ecs::prelude::*;81/// # let mut world = World::default();82/// # #[derive(Event)]83/// # struct PrintNames;84/// # #[derive(Component, Debug)]85/// # struct Name;86/// world.add_observer(|event: On<PrintNames>, names: Query<&Name>| {87/// for name in &names {88/// println!("{name:?}");89/// }90/// });91/// ```92///93/// You can also add [`Commands`], which means you can spawn new entities, insert new components, etc:94///95/// ```96/// # use bevy_ecs::prelude::*;97/// # let mut world = World::default();98/// # #[derive(Event)]99/// # struct SpawnThing;100/// # #[derive(Component, Debug)]101/// # struct Thing;102/// world.add_observer(|event: On<SpawnThing>, mut commands: Commands| {103/// commands.spawn(Thing);104/// });105/// ```106///107/// Observers can also trigger new events:108///109/// ```110/// # use bevy_ecs::prelude::*;111/// # let mut world = World::default();112/// # #[derive(Event)]113/// # struct A;114/// # #[derive(Event)]115/// # struct B;116/// world.add_observer(|event: On<A>, mut commands: Commands| {117/// commands.trigger(B);118/// });119/// ```120///121/// When the commands are flushed (including these "nested triggers") they will be122/// recursively evaluated until there are no commands left, meaning nested triggers all123/// evaluate at the same time!124///125/// ## Event [`Trigger`] behavior126///127/// Each [`Event`] defines a [`Trigger`] behavior, which determines _which_ observers will run for the given [`Event`] and _how_ they will be run.128///129/// [`Event`] by default (when derived) uses [`GlobalTrigger`](crate::event::GlobalTrigger). When it is triggered any [`Observer`] watching for it will be run.130///131/// ## Event sub-types132///133/// There are some built-in specialized [`Event`] types with custom [`Trigger`] logic:134///135/// - [`EntityEvent`] / [`EntityTrigger`](crate::event::EntityTrigger): An [`Event`] that targets a _specific_ entity. This also has opt-in support for136/// "event bubbling" behavior. See [`EntityEvent`] for details.137/// - [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger): An [`Event`] that targets an entity _and_ one or more components on that entity.138/// This is used for [component lifecycle events](crate::lifecycle).139///140/// You can also define your own!141///142/// ## Observer execution timing143///144/// Observers triggered via [`World::trigger`] are evaluated immediately, as are all commands they queue up.145///146/// Observers triggered via [`Commands::trigger`] are evaluated at the next sync point in the ECS schedule, just like any other [`Command`].147///148/// To control the relative ordering of observer trigger commands sent from different systems,149/// order the systems in the schedule relative to each other.150///151/// Currently, Bevy does not provide [a way to specify the relative ordering of observers](https://github.com/bevyengine/bevy/issues/14890)152/// watching for the same event. Their ordering is considered to be arbitrary. It is recommended to make no153/// assumptions about their execution order.154///155/// Commands sent by observers are [currently not immediately applied](https://github.com/bevyengine/bevy/issues/19569).156/// Instead, all queued observers will run, and then all of the commands from those observers will be applied.157///158/// ## [`ObservedBy`]159///160/// When entities are observed, they will receive an [`ObservedBy`] component,161/// which will be updated to track the observers that are currently observing them.162///163/// ## Manual [`Observer`] target configuration164///165/// You can manually control the targets that an observer is watching by calling builder methods like [`Observer::with_entity`]166/// _before_ inserting the [`Observer`] component.167///168/// In general, it is better to use the [`EntityWorldMut::observe`] or [`EntityCommands::observe`] methods,169/// which spawns a new observer, and configures it to watch the entity it is called on.170///171/// ## Cleaning up observers172///173/// If an [`EntityEvent`] [`Observer`] targets specific entities, and all of those entities are despawned, the [`Observer`] entity will also be despawned.174/// This protects against observer "garbage" building up over time.175///176/// ## Component lifecycle events: Observers vs Hooks177///178/// It is important to note that observers, just like [hooks](crate::lifecycle::ComponentHooks),179/// can watch for and respond to [lifecycle](crate::lifecycle) events.180/// Unlike hooks, observers are not treated as an "innate" part of component behavior:181/// they can be added or removed at runtime, and multiple observers182/// can be registered for the same lifecycle event for the same component.183///184/// The ordering of hooks versus observers differs based on the lifecycle event in question:185///186/// - when adding components, hooks are evaluated first, then observers187/// - when removing components, observers are evaluated first, then hooks188///189/// This allows hooks to act as constructors and destructors for components,190/// as they always have the first and final say in the component's lifecycle.191///192/// ## Observer re-targeting193///194/// Currently, [observers cannot be retargeted after spawning](https://github.com/bevyengine/bevy/issues/19587):195/// despawn and respawn an observer as a workaround.196///197/// ## Internal observer cache198///199/// For more efficient observer triggering, Observers make use of the internal [`CachedObservers`](crate::observer::CachedObservers) storage.200/// In general, this is an implementation detail developers don't need to worry about, but it can be used when implementing custom [`Trigger`](crate::event::Trigger)201/// types, or to add "dynamic" observers for cases like scripting / modding.202///203/// [`SystemParam`]: crate::system::SystemParam204/// [`Trigger`]: crate::event::Trigger205pub struct Observer {206hook_on_add: ComponentHook,207pub(crate) error_handler: Option<ErrorHandler>,208pub(crate) system: Box<dyn AnyNamedSystem>,209pub(crate) descriptor: ObserverDescriptor,210pub(crate) last_trigger_id: u32,211pub(crate) despawned_watched_entities: u32,212pub(crate) runner: ObserverRunner,213}214215impl Observer {216/// Creates a new [`Observer`], which defaults to a "global" observer. This means it will run _whenever_ an event of type `E` is triggered.217///218/// # Panics219///220/// Panics if the given system is an exclusive system.221pub fn new<E: Event, B: Bundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {222let system = Box::new(IntoObserverSystem::into_system(system));223assert!(224!system.is_exclusive(),225concat!(226"Exclusive system `{}` may not be used as observer.\n",227"Instead of `&mut World`, use either `DeferredWorld` if you do not need structural changes, or `Commands` if you do."228),229system.name()230);231Self {232system,233descriptor: Default::default(),234hook_on_add: hook_on_add::<E, B, I::System>,235error_handler: None,236runner: observer_system_runner::<E, B, I::System>,237despawned_watched_entities: 0,238last_trigger_id: 0,239}240}241242/// Creates a new [`Observer`] with custom runner, this is mostly used for dynamic event observers243pub fn with_dynamic_runner(runner: ObserverRunner) -> Self {244Self {245system: Box::new(IntoSystem::into_system(|| {})),246descriptor: Default::default(),247hook_on_add: |mut world, hook_context| {248let default_error_handler = world.default_error_handler();249world.commands().queue(move |world: &mut World| {250let entity = hook_context.entity;251if let Some(mut observe) = world.get_mut::<Observer>(entity) {252if observe.descriptor.event_keys.is_empty() {253return;254}255if observe.error_handler.is_none() {256observe.error_handler = Some(default_error_handler);257}258world.register_observer(entity);259}260});261},262error_handler: None,263runner,264despawned_watched_entities: 0,265last_trigger_id: 0,266}267}268269/// Observes the given `entity` (in addition to any entity already being observed).270/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is the given `entity`.271/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.272pub fn with_entity(mut self, entity: Entity) -> Self {273self.watch_entity(entity);274self275}276277/// Observes the given `entities` (in addition to any entity already being observed).278/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is any of the `entities`.279/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.280pub fn with_entities<I: IntoIterator<Item = Entity>>(mut self, entities: I) -> Self {281self.watch_entities(entities);282self283}284285/// Observes the given `entity` (in addition to any entity already being observed).286/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is the given `entity`.287/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.288pub fn watch_entity(&mut self, entity: Entity) {289self.descriptor.entities.push(entity);290}291292/// Observes the given `entity` (in addition to any entity already being observed).293/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is any of the `entities`.294/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.295pub fn watch_entities<I: IntoIterator<Item = Entity>>(&mut self, entities: I) {296self.descriptor.entities.extend(entities);297}298299/// Observes the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] has300/// an [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger) that targets the given `component`.301pub fn with_component(mut self, component: ComponentId) -> Self {302self.descriptor.components.push(component);303self304}305306/// Observes the given `event_key`. This will cause the [`Observer`] to run whenever an event with the given [`EventKey`]307/// is triggered.308/// # Safety309/// The type of the `event_key` [`EventKey`] _must_ match the actual value310/// of the event passed into the observer system.311pub unsafe fn with_event_key(mut self, event_key: EventKey) -> Self {312self.descriptor.event_keys.push(event_key);313self314}315316/// Sets the error handler to use for this observer.317///318/// See the [`error` module-level documentation](crate::error) for more information.319pub fn with_error_handler(mut self, error_handler: fn(BevyError, ErrorContext)) -> Self {320self.error_handler = Some(error_handler);321self322}323324/// Returns the [`ObserverDescriptor`] for this [`Observer`].325pub fn descriptor(&self) -> &ObserverDescriptor {326&self.descriptor327}328329/// Returns the name of the [`Observer`]'s system .330pub fn system_name(&self) -> DebugName {331self.system.system_name()332}333}334335impl Component for Observer {336const STORAGE_TYPE: StorageType = StorageType::SparseSet;337type Mutability = Mutable;338fn on_add() -> Option<ComponentHook> {339Some(|world, context| {340let Some(observe) = world.get::<Self>(context.entity) else {341return;342};343let hook = observe.hook_on_add;344hook(world, context);345})346}347fn on_remove() -> Option<ComponentHook> {348Some(|mut world, HookContext { entity, .. }| {349let descriptor = core::mem::take(350&mut world351.entity_mut(entity)352.get_mut::<Self>()353.unwrap()354.as_mut()355.descriptor,356);357world.commands().queue(move |world: &mut World| {358world.unregister_observer(entity, descriptor);359});360})361}362363fn register_required_components(364_component_id: ComponentId,365required_components: &mut RequiredComponentsRegistrator,366) {367required_components.register_required(Internal::default);368}369}370371/// Store information about what an [`Observer`] observes.372///373/// This information is stored inside of the [`Observer`] component,374#[derive(Default, Clone)]375pub struct ObserverDescriptor {376/// The event keys the observer is watching.377pub(super) event_keys: Vec<EventKey>,378379/// The components the observer is watching.380pub(super) components: Vec<ComponentId>,381382/// The entities the observer is watching.383pub(super) entities: Vec<Entity>,384}385386impl ObserverDescriptor {387/// Add the given `event_keys` to the descriptor.388/// # Safety389/// The type of each [`EventKey`] in `event_keys` _must_ match the actual value390/// of the event passed into the observer.391pub unsafe fn with_event_keys(mut self, event_keys: Vec<EventKey>) -> Self {392self.event_keys = event_keys;393self394}395396/// Add the given `components` to the descriptor.397pub fn with_components(mut self, components: Vec<ComponentId>) -> Self {398self.components = components;399self400}401402/// Add the given `entities` to the descriptor.403pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {404self.entities = entities;405self406}407408/// Returns the `event_keys` that the observer is watching.409pub fn event_keys(&self) -> &[EventKey] {410&self.event_keys411}412413/// Returns the `components` that the observer is watching.414pub fn components(&self) -> &[ComponentId] {415&self.components416}417418/// Returns the `entities` that the observer is watching.419pub fn entities(&self) -> &[Entity] {420&self.entities421}422}423424/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::lifecycle::ComponentHooks::on_add`).425///426/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters427/// erased.428///429/// The type parameters of this function _must_ match those used to create the [`Observer`].430/// As such, it is recommended to only use this function within the [`Observer::new`] method to431/// ensure type parameters match.432fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(433mut world: DeferredWorld<'_>,434HookContext { entity, .. }: HookContext,435) {436world.commands().queue(move |world: &mut World| {437let event_key = world.register_event_key::<E>();438let mut components = alloc::vec![];439B::component_ids(&mut world.components_registrator(), &mut |id| {440components.push(id);441});442if let Some(mut observer) = world.get_mut::<Observer>(entity) {443observer.descriptor.event_keys.push(event_key);444observer.descriptor.components.extend(components);445446let system: &mut dyn Any = observer.system.as_mut();447let system: *mut dyn ObserverSystem<E, B> = system.downcast_mut::<S>().unwrap();448// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias449unsafe {450(*system).initialize(world);451}452world.register_observer(entity);453}454});455}456457/// Tracks a list of entity observers for the [`Entity`] [`ObservedBy`] is added to.458#[derive(Default, Debug)]459#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]460#[cfg_attr(feature = "bevy_reflect", reflect(Component, Debug))]461pub struct ObservedBy(pub(crate) Vec<Entity>);462463impl ObservedBy {464/// Provides a read-only reference to the list of entities observing this entity.465pub fn get(&self) -> &[Entity] {466&self.0467}468}469470impl Component for ObservedBy {471const STORAGE_TYPE: StorageType = StorageType::SparseSet;472type Mutability = Mutable;473474fn on_remove() -> Option<ComponentHook> {475Some(|mut world, HookContext { entity, .. }| {476let observed_by = {477let mut component = world.get_mut::<ObservedBy>(entity).unwrap();478core::mem::take(&mut component.0)479};480for e in observed_by {481let (total_entities, despawned_watched_entities) = {482let Ok(mut entity_mut) = world.get_entity_mut(e) else {483continue;484};485let Some(mut state) = entity_mut.get_mut::<Observer>() else {486continue;487};488state.despawned_watched_entities += 1;489(490state.descriptor.entities.len(),491state.despawned_watched_entities as usize,492)493};494495// Despawn Observer if it has no more active sources.496if total_entities == despawned_watched_entities {497world.commands().entity(e).despawn();498}499}500})501}502503fn clone_behavior() -> ComponentCloneBehavior {504ComponentCloneBehavior::Ignore505}506}507508pub(crate) trait AnyNamedSystem: Any + Send + Sync + 'static {509fn system_name(&self) -> DebugName;510}511512impl<T: Any + System> AnyNamedSystem for T {513fn system_name(&self) -> DebugName {514self.name()515}516}517518519