use crate::{1component::ComponentId,2entity::Entity,3event::{EntityEvent, Event},4observer::{CachedObservers, TriggerContext},5traversal::Traversal,6world::DeferredWorld,7};8use bevy_ptr::PtrMut;9use core::{fmt, marker::PhantomData};1011/// [`Trigger`] determines _how_ an [`Event`] is triggered when [`World::trigger`](crate::world::World::trigger) is called.12/// This decides which [`Observer`](crate::observer::Observer)s will run, what data gets passed to them, and the order they will13/// be executed in.14///15/// Implementing [`Trigger`] is "advanced-level" territory, and is generally unnecessary unless you are developing highly specialized16/// [`Event`] trigger logic.17///18/// Bevy comes with a number of built-in [`Trigger`] implementations (see their documentation for more info):19/// - [`GlobalTrigger`]: The [`Event`] derive defaults to using this20/// - [`EntityTrigger`]: The [`EntityEvent`] derive defaults to using this21/// - [`PropagateEntityTrigger`]: The [`EntityEvent`] derive uses this when propagation is enabled.22/// - [`EntityComponentsTrigger`]: Used by Bevy's [component lifecycle events](crate::lifecycle).23///24/// # Safety25///26/// Implementing this properly is _advanced_ soundness territory! Implementers must abide by the following:27///28/// - The `E`' [`Event::Trigger`] must be constrained to the implemented [`Trigger`] type, as part of the implementation.29/// This prevents other [`Trigger`] implementations from directly deferring to your implementation, which is a very easy30/// soundness misstep, as most [`Trigger`] implementations will invoke observers that are developed _for their specific [`Trigger`] type_.31/// Without this constraint, something like [`GlobalTrigger`] could be called for _any_ [`Event`] type, even one that expects a different32/// [`Trigger`] type. This would result in an unsound cast of [`GlobalTrigger`] reference.33/// This is not expressed as an explicit type constraint,, as the `for<'a> Event::Trigger<'a>` lifetime can mismatch explicit lifetimes in34/// some impls.35pub unsafe trait Trigger<E: Event> {36/// Trigger the given `event`, running every [`Observer`](crate::observer::Observer) that matches the `event`, as defined by this37/// [`Trigger`] and the state stored on `self`.38///39/// # Safety40/// - The [`CachedObservers`] `observers` must come from the [`DeferredWorld`] `world`41/// - [`TriggerContext`] must contain an [`EventKey`](crate::event::EventKey) that matches the `E` [`Event`] type42/// - `observers` must correspond to observers compatible with the event type `E`43/// - Read and abide by the "Safety" section defined in the top-level [`Trigger`] docs. Calling this function is44/// unintuitively risky. _Do not use it directly unless you know what you are doing_. Importantly, this should only45/// be called for an `event` whose [`Event::Trigger`] matches this trigger.46unsafe fn trigger(47&mut self,48world: DeferredWorld,49observers: &CachedObservers,50trigger_context: &TriggerContext,51event: &mut E,52);53}5455/// A [`Trigger`] that runs _every_ "global" [`Observer`](crate::observer::Observer) (ex: registered via [`World::add_observer`](crate::world::World::add_observer))56/// that matches the given [`Event`].57///58/// The [`Event`] derive defaults to using this [`Trigger`], and it is usable for any [`Event`] type.59#[derive(Default, Debug)]60pub struct GlobalTrigger;6162// SAFETY:63// - `E`'s [`Event::Trigger`] is constrained to [`GlobalTrigger`]64// - The implementation abides by the other safety constraints defined in [`Trigger`]65unsafe impl<E: for<'a> Event<Trigger<'a> = Self>> Trigger<E> for GlobalTrigger {66unsafe fn trigger(67&mut self,68world: DeferredWorld,69observers: &CachedObservers,70trigger_context: &TriggerContext,71event: &mut E,72) {73// SAFETY:74// - The caller of `trigger` ensures that `observers` come from the `world`75// - The passed in event ptr comes from `event`, which is E: Event76// - E: Event::Trigger is constrained to GlobalTrigger77// - The caller of `trigger` ensures that `TriggerContext::event_key` matches `event`78unsafe {79self.trigger_internal(world, observers, trigger_context, event.into());80}81}82}8384impl GlobalTrigger {85/// # Safety86/// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type87/// - `event` must point to an [`Event`]88/// - The `event` [`Event::Trigger`] must be [`GlobalTrigger`]89/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.90unsafe fn trigger_internal(91&mut self,92mut world: DeferredWorld,93observers: &CachedObservers,94trigger_context: &TriggerContext,95mut event: PtrMut,96) {97// SAFETY: `observers` is the only active reference to something in `world`98unsafe {99world.as_unsafe_world_cell().increment_trigger_id();100}101for (observer, runner) in observers.global_observers() {102// SAFETY:103// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`104// - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`105// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `event`, enforced by `trigger_internal`106// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`107// - this abides by the nuances defined in the `Trigger` safety docs108unsafe {109(runner)(110world.reborrow(),111*observer,112trigger_context,113event.reborrow(),114self.into(),115);116}117}118}119}120121/// An [`EntityEvent`] [`Trigger`] that does two things:122/// - Runs all "global" [`Observer`] (ex: registered via [`World::add_observer`](crate::world::World::add_observer))123/// that matches the given [`Event`]. This is the same behavior as [`GlobalTrigger`].124/// - Runs every "entity scoped" [`Observer`] that watches the given [`EntityEvent::event_target`] entity.125///126/// The [`EntityEvent`] derive defaults to using this [`Trigger`], and it is usable for any [`EntityEvent`] type.127///128/// [`Observer`]: crate::observer::Observer129#[derive(Default, Debug)]130pub struct EntityTrigger;131132// SAFETY:133// - `E`'s [`Event::Trigger`] is constrained to [`EntityTrigger`]134// - The implementation abides by the other safety constraints defined in [`Trigger`]135unsafe impl<E: EntityEvent + for<'a> Event<Trigger<'a> = Self>> Trigger<E> for EntityTrigger {136unsafe fn trigger(137&mut self,138world: DeferredWorld,139observers: &CachedObservers,140trigger_context: &TriggerContext,141event: &mut E,142) {143let entity = event.event_target();144// SAFETY:145// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`146// - the passed in event pointer comes from `event`, which is an `Event`147// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`148// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`149unsafe {150trigger_entity_internal(151world,152observers,153event.into(),154self.into(),155entity,156trigger_context,157);158}159}160}161162/// Trigger observers watching for the given entity event.163/// The `target_entity` should match the [`EntityEvent::event_target`] on `event` for logical correctness.164///165/// # Safety166/// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type167/// - `event` must point to an [`Event`]168/// - `trigger` must correspond to the [`Event::Trigger`] type expected by the `event`169/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.170/// - Read, understand, and abide by the [`Trigger`] safety documentation171// Note: this is not an EntityTrigger method because we want to reuse this logic for the entity propagation trigger172#[inline(never)]173pub unsafe fn trigger_entity_internal(174mut world: DeferredWorld,175observers: &CachedObservers,176mut event: PtrMut,177mut trigger: PtrMut,178target_entity: Entity,179trigger_context: &TriggerContext,180) {181// SAFETY: there are no outstanding world references182unsafe {183world.as_unsafe_world_cell().increment_trigger_id();184}185for (observer, runner) in observers.global_observers() {186// SAFETY:187// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`188// - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`189// - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`190// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`191unsafe {192(runner)(193world.reborrow(),194*observer,195trigger_context,196event.reborrow(),197trigger.reborrow(),198);199}200}201202if let Some(map) = observers.entity_observers().get(&target_entity) {203for (observer, runner) in map {204// SAFETY:205// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`206// - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`207// - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`208// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`209unsafe {210(runner)(211world.reborrow(),212*observer,213trigger_context,214event.reborrow(),215trigger.reborrow(),216);217}218}219}220}221222/// An [`EntityEvent`] [`Trigger`] that behaves like [`EntityTrigger`], but "propagates" the event223/// using an [`Entity`] [`Traversal`]. At each step in the propagation, the [`EntityTrigger`] logic will224/// be run, until [`PropagateEntityTrigger::propagate`] is false, or there are no entities left to traverse.225///226/// This is used by the [`EntityEvent`] derive when `#[entity_event(propagate)]` is enabled. It is usable by every227/// [`EntityEvent`] type.228///229/// If `AUTO_PROPAGATE` is `true`, [`PropagateEntityTrigger::propagate`] will default to `true`.230pub struct PropagateEntityTrigger<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> {231/// The original [`Entity`] the [`Event`] was _first_ triggered for.232pub original_event_target: Entity,233234/// Whether or not to continue propagating using the `T` [`Traversal`]. If this is false,235/// The [`Traversal`] will stop on the current entity.236pub propagate: bool,237238_marker: PhantomData<(E, T)>,239}240241impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> Default242for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>243{244fn default() -> Self {245Self {246original_event_target: Entity::PLACEHOLDER,247propagate: AUTO_PROPAGATE,248_marker: Default::default(),249}250}251}252253impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> fmt::Debug254for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>255{256fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {257f.debug_struct("PropagateEntityTrigger")258.field("original_event_target", &self.original_event_target)259.field("propagate", &self.propagate)260.field("_marker", &self._marker)261.finish()262}263}264265// SAFETY:266// - `E`'s [`Event::Trigger`] is constrained to [`PropagateEntityTrigger<E>`]267unsafe impl<268const AUTO_PROPAGATE: bool,269E: EntityEvent + for<'a> Event<Trigger<'a> = Self>,270T: Traversal<E>,271> Trigger<E> for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>272{273unsafe fn trigger(274&mut self,275mut world: DeferredWorld,276observers: &CachedObservers,277trigger_context: &TriggerContext,278event: &mut E,279) {280let mut current_entity = event.event_target();281self.original_event_target = current_entity;282// SAFETY:283// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`284// - the passed in event pointer comes from `event`, which is an `Event`285// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`286// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`287unsafe {288trigger_entity_internal(289world.reborrow(),290observers,291event.into(),292self.into(),293current_entity,294trigger_context,295);296}297298loop {299if !self.propagate {300return;301}302if let Ok(entity) = world.get_entity(current_entity)303&& let Some(item) = entity.get_components::<T>()304&& let Some(traverse_to) = T::traverse(item, event)305{306current_entity = traverse_to;307} else {308break;309}310311*event.event_target_mut() = current_entity;312// SAFETY:313// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`314// - the passed in event pointer comes from `event`, which is an `Event`315// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`316// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`317unsafe {318trigger_entity_internal(319world.reborrow(),320observers,321event.into(),322self.into(),323current_entity,324trigger_context,325);326}327}328}329}330331/// An [`EntityEvent`] [`Trigger`] that, in addition to behaving like a normal [`EntityTrigger`], _also_ runs observers332/// that watch for components that match the slice of [`ComponentId`]s referenced in [`EntityComponentsTrigger`]. This includes333/// both _global_ observers of those components and "entity scoped" observers that watch the [`EntityEvent::event_target`].334///335/// This is used by Bevy's built-in [lifecycle events](crate::lifecycle).336#[derive(Default)]337pub struct EntityComponentsTrigger<'a> {338/// All of the components whose observers were triggered together for the target entity. For example,339/// if components `A` and `B` are added together, producing the [`Add`](crate::lifecycle::Add) event, this will340/// contain the [`ComponentId`] for both `A` and `B`.341pub components: &'a [ComponentId],342}343344// SAFETY:345// - `E`'s [`Event::Trigger`] is constrained to [`EntityComponentsTrigger`]346unsafe impl<'a, E: EntityEvent + Event<Trigger<'a> = EntityComponentsTrigger<'a>>> Trigger<E>347for EntityComponentsTrigger<'a>348{349unsafe fn trigger(350&mut self,351world: DeferredWorld,352observers: &CachedObservers,353trigger_context: &TriggerContext,354event: &mut E,355) {356let entity = event.event_target();357// SAFETY:358// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`359// - the passed in event pointer comes from `event`, which is an `Event`360// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`361unsafe {362self.trigger_internal(world, observers, event.into(), entity, trigger_context);363}364}365}366367impl<'a> EntityComponentsTrigger<'a> {368/// # Safety369/// - `observers` must come from the `world` [`DeferredWorld`]370/// - `event` must point to an [`Event`] whose [`Event::Trigger`] is [`EntityComponentsTrigger`]371/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.372#[inline(never)]373unsafe fn trigger_internal(374&mut self,375mut world: DeferredWorld,376observers: &CachedObservers,377mut event: PtrMut,378entity: Entity,379trigger_context: &TriggerContext,380) {381// SAFETY:382// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`383// - the passed in event pointer comes from `event`, which is an `Event`384// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`385// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`386unsafe {387trigger_entity_internal(388world.reborrow(),389observers,390event.reborrow(),391self.into(),392entity,393trigger_context,394);395}396397// Trigger observers watching for a specific component398for id in self.components {399if let Some(component_observers) = observers.component_observers().get(id) {400for (observer, runner) in component_observers.global_observers() {401// SAFETY:402// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`403// - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`404// - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`405// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`406unsafe {407(runner)(408world.reborrow(),409*observer,410trigger_context,411event.reborrow(),412self.into(),413);414}415}416417if let Some(map) = component_observers418.entity_component_observers()419.get(&entity)420{421for (observer, runner) in map {422// SAFETY:423// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`424// - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`425// - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`426// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`427unsafe {428(runner)(429world.reborrow(),430*observer,431trigger_context,432event.reborrow(),433self.into(),434);435}436}437}438}439}440}441}442443444