Path: blob/main/crates/bevy_ecs/src/observer/distributed_storage.rs
9358 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 core::marker::PhantomData;1415use crate::{16component::{ComponentCloneBehavior, ComponentId, Mutable, StorageType},17error::{ErrorContext, ErrorHandler},18event::EventKey,19lifecycle::{ComponentHook, HookContext},20observer::{21condition::{ObserverCondition, ObserverWithCondition, ObserverWithConditionMarker},22observer_system_runner, ObserverRunner,23},24prelude::*,25system::{IntoObserverSystem, ObserverSystem},26world::DeferredWorld,27};28use alloc::boxed::Box;29use alloc::vec::Vec;30use bevy_utils::prelude::DebugName;3132#[cfg(feature = "bevy_reflect")]33use crate::prelude::ReflectComponent;3435/// An [`Observer`] system. Add this [`Component`] to an [`Entity`] to turn it into an "observer".36///37/// Observers watch for a "trigger" of a specific [`Event`]. An event can be triggered on the [`World`]38/// by calling [`World::trigger`]. It can also be queued up as a [`Command`] using [`Commands::trigger`].39///40/// When a [`World`] triggers an [`Event`], it will immediately run every [`Observer`] that watches for that [`Event`].41///42/// # Usage43///44/// The simplest usage of the observer pattern looks like this:45///46/// ```47/// # use bevy_ecs::prelude::*;48/// # let mut world = World::default();49/// #[derive(Event)]50/// struct Speak {51/// message: String,52/// }53///54/// world.add_observer(|event: On<Speak>| {55/// println!("{}", event.message);56/// });57///58/// world.trigger(Speak {59/// message: "Hello!".into(),60/// });61/// ```62///63/// Notice that we used [`World::add_observer`]. This is just a shorthand for spawning an [`Entity`] with an [`Observer`] manually:64///65/// ```66/// # use bevy_ecs::prelude::*;67/// # let mut world = World::default();68/// # #[derive(Event)]69/// # struct Speak;70/// // These are functionally the same:71/// world.add_observer(|event: On<Speak>| {});72/// world.spawn(Observer::new(|event: On<Speak>| {}));73/// ```74///75/// Observers are a specialized [`System`] called an [`ObserverSystem`]. The first parameter must be [`On`], which provides access76/// to the [`Event`], the [`Trigger`], and some additional execution context.77///78/// Because they are systems, they can access arbitrary [`World`] data by adding [`SystemParam`]s:79///80/// ```81/// # use bevy_ecs::prelude::*;82/// # let mut world = World::default();83/// # #[derive(Event)]84/// # struct PrintNames;85/// # #[derive(Component, Debug)]86/// # struct Name;87/// world.add_observer(|event: On<PrintNames>, names: Query<&Name>| {88/// for name in &names {89/// println!("{name:?}");90/// }91/// });92/// ```93///94/// You can also add [`Commands`], which means you can spawn new entities, insert new components, etc:95///96/// ```97/// # use bevy_ecs::prelude::*;98/// # let mut world = World::default();99/// # #[derive(Event)]100/// # struct SpawnThing;101/// # #[derive(Component, Debug)]102/// # struct Thing;103/// world.add_observer(|event: On<SpawnThing>, mut commands: Commands| {104/// commands.spawn(Thing);105/// });106/// ```107///108/// Observers can also trigger new events:109///110/// ```111/// # use bevy_ecs::prelude::*;112/// # let mut world = World::default();113/// # #[derive(Event)]114/// # struct A;115/// # #[derive(Event)]116/// # struct B;117/// world.add_observer(|event: On<A>, mut commands: Commands| {118/// commands.trigger(B);119/// });120/// ```121///122/// When the commands are flushed (including these "nested triggers") they will be123/// recursively evaluated until there are no commands left, meaning nested triggers all124/// evaluate at the same time!125///126/// ## Event [`Trigger`] behavior127///128/// Each [`Event`] defines a [`Trigger`] behavior, which determines _which_ observers will run for the given [`Event`] and _how_ they will be run.129///130/// [`Event`] by default (when derived) uses [`GlobalTrigger`](crate::event::GlobalTrigger). When it is triggered any [`Observer`] watching for it will be run.131///132/// ## Event sub-types133///134/// There are some built-in specialized [`Event`] types with custom [`Trigger`] logic:135///136/// - [`EntityEvent`] / [`EntityTrigger`](crate::event::EntityTrigger): An [`Event`] that targets a _specific_ entity. This also has opt-in support for137/// "event bubbling" behavior. See [`EntityEvent`] for details.138/// - [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger): An [`Event`] that targets an entity _and_ one or more components on that entity.139/// This is used for [component lifecycle events](crate::lifecycle).140///141/// You can also define your own!142///143/// ## Observer execution timing144///145/// Observers triggered via [`World::trigger`] are evaluated immediately, as are all commands they queue up.146///147/// Observers triggered via [`Commands::trigger`] are evaluated at the next sync point in the ECS schedule, just like any other [`Command`].148///149/// To control the relative ordering of observer trigger commands sent from different systems,150/// order the systems in the schedule relative to each other.151///152/// Currently, Bevy does not provide [a way to specify the relative ordering of observers](https://github.com/bevyengine/bevy/issues/14890)153/// watching for the same event. Their ordering is considered to be arbitrary. It is recommended to make no154/// assumptions about their execution order.155///156/// Commands sent by observers are [currently not immediately applied](https://github.com/bevyengine/bevy/issues/19569).157/// Instead, all queued observers will run, and then all of the commands from those observers will be applied.158///159/// ## [`ObservedBy`]160///161/// When entities are observed, they will receive an [`ObservedBy`] component,162/// which will be updated to track the observers that are currently observing them.163///164/// ## Manual [`Observer`] target configuration165///166/// You can manually control the targets that an observer is watching by calling builder methods like [`Observer::with_entity`]167/// _before_ inserting the [`Observer`] component.168///169/// In general, it is better to use the [`EntityWorldMut::observe`] or [`EntityCommands::observe`] methods,170/// which spawns a new observer, and configures it to watch the entity it is called on.171///172/// ## Cleaning up observers173///174/// If an [`EntityEvent`] [`Observer`] targets specific entities, and all of those entities are despawned, the [`Observer`] entity will also be despawned.175/// This protects against observer "garbage" building up over time.176///177/// ## Component lifecycle events: Observers vs Hooks178///179/// It is important to note that observers, just like [hooks](crate::lifecycle::ComponentHooks),180/// can watch for and respond to [lifecycle](crate::lifecycle) events.181/// Unlike hooks, observers are not treated as an "innate" part of component behavior:182/// they can be added or removed at runtime, and multiple observers183/// can be registered for the same lifecycle event for the same component.184///185/// The ordering of hooks versus observers differs based on the lifecycle event in question:186///187/// - when adding components, hooks are evaluated first, then observers188/// - when removing components, observers are evaluated first, then hooks189///190/// This allows hooks to act as constructors and destructors for components,191/// as they always have the first and final say in the component's lifecycle.192///193/// ## Observer re-targeting194///195/// Currently, [observers cannot be retargeted after spawning](https://github.com/bevyengine/bevy/issues/19587):196/// despawn and respawn an observer as a workaround.197///198/// ## Internal observer cache199///200/// For more efficient observer triggering, Observers make use of the internal [`CachedObservers`](crate::observer::CachedObservers) storage.201/// 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)202/// types, or to add "dynamic" observers for cases like scripting / modding.203///204/// [`SystemParam`]: crate::system::SystemParam205/// [`Trigger`]: crate::event::Trigger206pub struct Observer {207hook_on_add: ComponentHook,208pub(crate) error_handler: Option<ErrorHandler>,209pub(crate) system: Box<dyn AnyNamedSystem>,210pub(crate) descriptor: ObserverDescriptor,211pub(crate) last_trigger_id: u32,212pub(crate) despawned_watched_entities: u32,213pub(crate) runner: ObserverRunner,214pub(crate) conditions: Vec<ObserverCondition>,215}216217impl Observer {218/// Creates a new [`Observer`], which defaults to a "global" observer. This means it will run _whenever_ an event of type `E` is triggered.219///220/// # Panics221///222/// Panics if the given system is an exclusive system.223pub fn new<E: Event, B: Bundle, M, I: IntoObserverSystem<E, B, M>>(system: I) -> Self {224let system = Box::new(IntoObserverSystem::into_system(system));225assert!(226!system.is_exclusive(),227concat!(228"Exclusive system `{}` may not be used as observer.\n",229"Instead of `&mut World`, use either `DeferredWorld` if you do not need structural changes, or `Commands` if you do."230),231system.name()232);233Self {234system,235descriptor: Default::default(),236hook_on_add: hook_on_add::<E, B, I::System>,237error_handler: None,238runner: observer_system_runner::<E, B, I::System>,239despawned_watched_entities: 0,240last_trigger_id: 0,241conditions: Vec::new(),242}243}244245/// Creates a new [`Observer`] with custom runner, this is mostly used for dynamic event observers246pub fn with_dynamic_runner(runner: ObserverRunner) -> Self {247Self {248system: Box::new(IntoSystem::into_system(|| {})),249descriptor: Default::default(),250hook_on_add: |mut world, hook_context| {251let default_error_handler = world.default_error_handler();252world.commands().queue(move |world: &mut World| {253let entity = hook_context.entity;254let mut conditions = {255let Some(mut observe) = world.get_mut::<Observer>(entity) else {256return;257};258if observe.descriptor.event_keys.is_empty() {259return;260}261if observe.error_handler.is_none() {262observe.error_handler = Some(default_error_handler);263}264core::mem::take(&mut observe.conditions)265};266for condition in &mut conditions {267condition.initialize(world);268}269if let Some(mut observe) = world.get_mut::<Observer>(entity) {270observe.conditions = conditions;271}272world.register_observer(entity);273});274},275error_handler: None,276runner,277despawned_watched_entities: 0,278last_trigger_id: 0,279conditions: Vec::new(),280}281}282283/// Observes the given `entity` (in addition to any entity already being observed).284/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is the given `entity`.285/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.286pub fn with_entity(mut self, entity: Entity) -> Self {287self.watch_entity(entity);288self289}290291/// Observes the given `entities` (in addition to any entity already being observed).292/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is any of the `entities`.293/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.294pub fn with_entities<I: IntoIterator<Item = Entity>>(mut self, entities: I) -> Self {295self.watch_entities(entities);296self297}298299/// Observes the given `entity` (in addition to any entity already being observed).300/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is the given `entity`.301/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.302pub fn watch_entity(&mut self, entity: Entity) {303self.descriptor.entities.push(entity);304}305306/// Observes the given `entity` (in addition to any entity already being observed).307/// This will cause the [`Observer`] to run whenever an [`EntityEvent::event_target`] is any of the `entities`.308/// Note that if this is called _after_ an [`Observer`] is spawned, it will produce no effects.309pub fn watch_entities<I: IntoIterator<Item = Entity>>(&mut self, entities: I) {310self.descriptor.entities.extend(entities);311}312313/// Observes the given `component`. This will cause the [`Observer`] to run whenever the [`Event`] has314/// an [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger) that targets the given `component`.315pub fn with_component(mut self, component: ComponentId) -> Self {316self.descriptor.components.push(component);317self318}319320/// Observes the given `components`. This will cause the [`Observer`] to run whenever the [`Event`] has321/// an [`EntityComponentsTrigger`](crate::event::EntityComponentsTrigger) that targets any of the `components`.322pub fn with_components<I: IntoIterator<Item = ComponentId>>(mut self, components: I) -> Self {323self.descriptor.components.extend(components);324self325}326327/// Observes the given `event_key`. This will cause the [`Observer`] to run whenever an event with the given [`EventKey`]328/// is triggered.329/// # Safety330/// The type of the `event_key` [`EventKey`] _must_ match the actual value331/// of the event passed into the observer system.332pub unsafe fn with_event_key(mut self, event_key: EventKey) -> Self {333self.descriptor.event_keys.push(event_key);334self335}336337/// Sets the error handler to use for this observer.338///339/// See the [`error` module-level documentation](crate::error) for more information.340pub fn with_error_handler(mut self, error_handler: fn(BevyError, ErrorContext)) -> Self {341self.error_handler = Some(error_handler);342self343}344345/// Adds a run condition to this observer.346///347/// The observer will only run if all conditions return `true` (AND semantics).348/// Multiple conditions can be added by chaining `run_if` calls.349pub fn run_if<M>(mut self, condition: impl SystemCondition<M>) -> Self {350self.conditions.push(ObserverCondition::new(condition));351self352}353354/// Returns the [`ObserverDescriptor`] for this [`Observer`].355pub fn descriptor(&self) -> &ObserverDescriptor {356&self.descriptor357}358359/// Returns the name of the [`Observer`]'s system .360pub fn system_name(&self) -> DebugName {361self.system.system_name()362}363}364365impl Component for Observer {366const STORAGE_TYPE: StorageType = StorageType::SparseSet;367type Mutability = Mutable;368fn on_add() -> Option<ComponentHook> {369Some(|world, context| {370let Some(observe) = world.get::<Self>(context.entity) else {371return;372};373let hook = observe.hook_on_add;374hook(world, context);375})376}377fn on_remove() -> Option<ComponentHook> {378Some(|mut world, HookContext { entity, .. }| {379let descriptor = core::mem::take(380&mut world381.entity_mut(entity)382.get_mut::<Self>()383.unwrap()384.as_mut()385.descriptor,386);387world.commands().queue(move |world: &mut World| {388world.unregister_observer(entity, descriptor);389});390})391}392}393394/// Store information about what an [`Observer`] observes.395///396/// This information is stored inside of the [`Observer`] component,397#[derive(Default, Clone)]398pub struct ObserverDescriptor {399/// The event keys the observer is watching.400pub(super) event_keys: Vec<EventKey>,401402/// The components the observer is watching.403pub(super) components: Vec<ComponentId>,404405/// The entities the observer is watching.406pub(super) entities: Vec<Entity>,407}408409impl ObserverDescriptor {410/// Add the given `event_keys` to the descriptor.411/// # Safety412/// The type of each [`EventKey`] in `event_keys` _must_ match the actual value413/// of the event passed into the observer.414pub unsafe fn with_event_keys(mut self, event_keys: Vec<EventKey>) -> Self {415self.event_keys = event_keys;416self417}418419/// Add the given `components` to the descriptor.420pub fn with_components(mut self, components: Vec<ComponentId>) -> Self {421self.components = components;422self423}424425/// Add the given `entities` to the descriptor.426pub fn with_entities(mut self, entities: Vec<Entity>) -> Self {427self.entities = entities;428self429}430431/// Returns the `event_keys` that the observer is watching.432pub fn event_keys(&self) -> &[EventKey] {433&self.event_keys434}435436/// Returns the `components` that the observer is watching.437pub fn components(&self) -> &[ComponentId] {438&self.components439}440441/// Returns the `entities` that the observer is watching.442pub fn entities(&self) -> &[Entity] {443&self.entities444}445}446447/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::lifecycle::ComponentHooks::on_add`).448///449/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters450/// erased.451///452/// The type parameters of this function _must_ match those used to create the [`Observer`].453/// As such, it is recommended to only use this function within the [`Observer::new`] method to454/// ensure type parameters match.455fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(456mut world: DeferredWorld<'_>,457HookContext { entity, .. }: HookContext,458) {459world.commands().queue(move |world: &mut World| {460let event_key = world.register_event_key::<E>();461let components = B::component_ids(&mut world.components_registrator());462463let system_ptr: *mut dyn ObserverSystem<E, B> = {464let Some(mut observer) = world.get_mut::<Observer>(entity) else {465return;466};467observer.descriptor.event_keys.push(event_key);468observer.descriptor.components.extend(components);469470let system: &mut dyn Any = observer.system.as_mut();471system.downcast_mut::<S>().unwrap() as *mut dyn ObserverSystem<E, B>472};473474// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias475unsafe {476(*system_ptr).initialize(world);477}478479let mut conditions = {480let Some(mut observer) = world.get_mut::<Observer>(entity) else {481return;482};483core::mem::take(&mut observer.conditions)484};485486for condition in &mut conditions {487condition.initialize(world);488}489490if let Some(mut observer) = world.get_mut::<Observer>(entity) {491observer.conditions = conditions;492}493494world.register_observer(entity);495});496}497498/// Tracks a list of entity observers for the [`Entity`] [`ObservedBy`] is added to.499#[derive(Default, Debug)]500#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]501#[cfg_attr(feature = "bevy_reflect", reflect(Component, Debug))]502pub struct ObservedBy(pub(crate) Vec<Entity>);503504impl ObservedBy {505/// Provides a read-only reference to the list of entities observing this entity.506pub fn get(&self) -> &[Entity] {507&self.0508}509}510511impl Component for ObservedBy {512const STORAGE_TYPE: StorageType = StorageType::SparseSet;513type Mutability = Mutable;514515fn on_remove() -> Option<ComponentHook> {516Some(|mut world, HookContext { entity, .. }| {517let observed_by = {518let mut component = world.get_mut::<ObservedBy>(entity).unwrap();519core::mem::take(&mut component.0)520};521for e in observed_by {522let (total_entities, despawned_watched_entities) = {523let Ok(mut entity_mut) = world.get_entity_mut(e) else {524continue;525};526let Some(mut state) = entity_mut.get_mut::<Observer>() else {527continue;528};529state.despawned_watched_entities += 1;530(531state.descriptor.entities.len(),532state.despawned_watched_entities as usize,533)534};535536// Despawn Observer if it has no more active sources.537if total_entities == despawned_watched_entities {538world.commands().entity(e).despawn();539}540}541})542}543544fn clone_behavior() -> ComponentCloneBehavior {545ComponentCloneBehavior::Ignore546}547}548549pub(crate) trait AnyNamedSystem: Any + Send + Sync + 'static {550fn system_name(&self) -> DebugName;551}552553impl<T: Any + System> AnyNamedSystem for T {554fn system_name(&self) -> DebugName {555self.name()556}557}558559/// Trait for types that can be converted into an [`Observer`].560pub trait IntoObserver<Marker>: Send + 'static {561/// Converts this type into an [`Observer`].562fn into_observer(self) -> Observer;563}564565impl IntoObserver<()> for Observer {566fn into_observer(self) -> Observer {567self568}569}570571impl<E: Event, B: Bundle, M, T: IntoObserverSystem<E, B, M>> IntoObserver<(E, B, M)> for T {572fn into_observer(self) -> Observer {573Observer::new(self)574}575}576577impl<E: Event, B: Bundle, M: 'static, S: IntoObserverSystem<E, B, M>>578IntoObserver<ObserverWithConditionMarker> for ObserverWithCondition<E, B, M, S>579{580fn into_observer(self) -> Observer {581let (system, conditions) = self.take_conditions();582let mut observer = Observer::new(system);583observer.conditions = conditions;584observer585}586}587588/// Trait for types that can be converted into an entity-targeting [`Observer`].589///590/// This trait enforces that the event type implements [`EntityEvent`].591#[diagnostic::on_unimplemented(592message = "`{Self}` cannot be used as an entity observer",593note = "entity observers require the event type to implement `EntityEvent`"594)]595pub trait IntoEntityObserver<Marker>: Send + 'static {596/// Converts this type into an [`Observer`] that watches the given entity.597fn into_observer_for_entity(self, entity: Entity) -> Observer;598}599600impl<E: EntityEvent, B: Bundle, M, T: IntoObserverSystem<E, B, M>> IntoEntityObserver<(E, B, M)>601for T602{603fn into_observer_for_entity(self, entity: Entity) -> Observer {604Observer::new(self).with_entity(entity)605}606}607608impl<E: EntityEvent, B: Bundle, M: 'static, S: IntoObserverSystem<E, B, M>>609IntoEntityObserver<ObserverWithConditionMarker> for ObserverWithCondition<E, B, M, S>610{611fn into_observer_for_entity(self, entity: Entity) -> Observer {612let (system, conditions) = self.take_conditions();613let mut observer = Observer::new(system);614observer.conditions = conditions;615observer.with_entity(entity)616}617}618619/// Extension trait for adding run conditions to observer systems.620pub trait ObserverSystemExt<E: Event, B: Bundle, M>: IntoObserverSystem<E, B, M> + Sized {621/// Adds a run condition to this observer system.622///623/// The observer will only run if the condition returns `true`.624/// Multiple conditions can be chained (AND semantics).625fn run_if<C, CM>(self, condition: C) -> ObserverWithCondition<E, B, M, Self>626where627C: SystemCondition<CM>,628{629ObserverWithCondition {630system: self,631conditions: alloc::vec![Box::new(IntoSystem::into_system(condition))],632_marker: PhantomData,633}634}635}636637impl<E: Event, B: Bundle, M, T: IntoObserverSystem<E, B, M>> ObserverSystemExt<E, B, M> for T {}638639640