use crate::event::SetEntityEventTarget;1use crate::{2component::ComponentId,3entity::Entity,4event::{EntityEvent, Event},5observer::{CachedObservers, TriggerContext},6traversal::Traversal,7world::DeferredWorld,8};9use bevy_ptr::PtrMut;10use core::{fmt, marker::PhantomData};1112/// [`Trigger`] determines _how_ an [`Event`] is triggered when [`World::trigger`](crate::world::World::trigger) is called.13/// This decides which [`Observer`](crate::observer::Observer)s will run, what data gets passed to them, and the order they will14/// be executed in.15///16/// Implementing [`Trigger`] is "advanced-level" territory, and is generally unnecessary unless you are developing highly specialized17/// [`Event`] trigger logic.18///19/// Bevy comes with a number of built-in [`Trigger`] implementations (see their documentation for more info):20/// - [`GlobalTrigger`]: The [`Event`] derive defaults to using this21/// - [`EntityTrigger`]: The [`EntityEvent`] derive defaults to using this22/// - [`PropagateEntityTrigger`]: The [`EntityEvent`] derive uses this when propagation is enabled.23/// - [`EntityComponentsTrigger`]: Used by Bevy's [component lifecycle events](crate::lifecycle).24///25/// # Safety26///27/// Implementing this properly is _advanced_ soundness territory! Implementers must abide by the following:28///29/// - The `E`' [`Event::Trigger`] must be constrained to the implemented [`Trigger`] type, as part of the implementation.30/// This prevents other [`Trigger`] implementations from directly deferring to your implementation, which is a very easy31/// soundness misstep, as most [`Trigger`] implementations will invoke observers that are developed _for their specific [`Trigger`] type_.32/// Without this constraint, something like [`GlobalTrigger`] could be called for _any_ [`Event`] type, even one that expects a different33/// [`Trigger`] type. This would result in an unsound cast of [`GlobalTrigger`] reference.34/// This is not expressed as an explicit type constraint,, as the `for<'a> Event::Trigger<'a>` lifetime can mismatch explicit lifetimes in35/// some impls.36pub unsafe trait Trigger<E: Event> {37/// Trigger the given `event`, running every [`Observer`](crate::observer::Observer) that matches the `event`, as defined by this38/// [`Trigger`] and the state stored on `self`.39///40/// # Safety41/// - The [`CachedObservers`] `observers` must come from the [`DeferredWorld`] `world`42/// - [`TriggerContext`] must contain an [`EventKey`](crate::event::EventKey) that matches the `E` [`Event`] type43/// - `observers` must correspond to observers compatible with the event type `E`44/// - Read and abide by the "Safety" section defined in the top-level [`Trigger`] docs. Calling this function is45/// unintuitively risky. _Do not use it directly unless you know what you are doing_. Importantly, this should only46/// be called for an `event` whose [`Event::Trigger`] matches this trigger.47unsafe fn trigger(48&mut self,49world: DeferredWorld,50observers: &CachedObservers,51trigger_context: &TriggerContext,52event: &mut E,53);54}5556/// A [`Trigger`] that runs _every_ "global" [`Observer`](crate::observer::Observer) (ex: registered via [`World::add_observer`](crate::world::World::add_observer))57/// that matches the given [`Event`].58///59/// The [`Event`] derive defaults to using this [`Trigger`], and it is usable for any [`Event`] type.60#[derive(Default, Debug)]61pub struct GlobalTrigger;6263// SAFETY:64// - `E`'s [`Event::Trigger`] is constrained to [`GlobalTrigger`]65// - The implementation abides by the other safety constraints defined in [`Trigger`]66unsafe impl<E: for<'a> Event<Trigger<'a> = Self>> Trigger<E> for GlobalTrigger {67unsafe fn trigger(68&mut self,69world: DeferredWorld,70observers: &CachedObservers,71trigger_context: &TriggerContext,72event: &mut E,73) {74// SAFETY:75// - The caller of `trigger` ensures that `observers` come from the `world`76// - The passed in event ptr comes from `event`, which is E: Event77// - E: Event::Trigger is constrained to GlobalTrigger78// - The caller of `trigger` ensures that `TriggerContext::event_key` matches `event`79unsafe {80self.trigger_internal(world, observers, trigger_context, event.into());81}82}83}8485impl GlobalTrigger {86/// # Safety87/// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type88/// - `event` must point to an [`Event`]89/// - The `event` [`Event::Trigger`] must be [`GlobalTrigger`]90/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.91unsafe fn trigger_internal(92&mut self,93mut world: DeferredWorld,94observers: &CachedObservers,95trigger_context: &TriggerContext,96mut event: PtrMut,97) {98// SAFETY: `observers` is the only active reference to something in `world`99unsafe {100world.as_unsafe_world_cell().increment_trigger_id();101}102for (observer, runner) in observers.global_observers() {103// SAFETY:104// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`105// - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`106// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `event`, enforced by `trigger_internal`107// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`108// - this abides by the nuances defined in the `Trigger` safety docs109unsafe {110(runner)(111world.reborrow(),112*observer,113trigger_context,114event.reborrow(),115self.into(),116);117}118}119}120}121122/// An [`EntityEvent`] [`Trigger`] that does two things:123/// - Runs all "global" [`Observer`] (ex: registered via [`World::add_observer`](crate::world::World::add_observer))124/// that matches the given [`Event`]. This is the same behavior as [`GlobalTrigger`].125/// - Runs every "entity scoped" [`Observer`] that watches the given [`EntityEvent::event_target`] entity.126///127/// The [`EntityEvent`] derive defaults to using this [`Trigger`], and it is usable for any [`EntityEvent`] type.128///129/// [`Observer`]: crate::observer::Observer130#[derive(Default, Debug)]131pub struct EntityTrigger;132133// SAFETY:134// - `E`'s [`Event::Trigger`] is constrained to [`EntityTrigger`]135// - The implementation abides by the other safety constraints defined in [`Trigger`]136unsafe impl<E: EntityEvent + for<'a> Event<Trigger<'a> = Self>> Trigger<E> for EntityTrigger {137unsafe fn trigger(138&mut self,139world: DeferredWorld,140observers: &CachedObservers,141trigger_context: &TriggerContext,142event: &mut E,143) {144let entity = event.event_target();145// SAFETY:146// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`147// - the passed in event pointer comes from `event`, which is an `Event`148// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`149// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`150unsafe {151trigger_entity_internal(152world,153observers,154event.into(),155self.into(),156entity,157trigger_context,158);159}160}161}162163/// Trigger observers watching for the given entity event.164/// The `target_entity` should match the [`EntityEvent::event_target`] on `event` for logical correctness.165///166/// # Safety167/// - `observers` must come from the `world` [`DeferredWorld`], and correspond to observers that match the `event` type168/// - `event` must point to an [`Event`]169/// - `trigger` must correspond to the [`Event::Trigger`] type expected by the `event`170/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.171/// - Read, understand, and abide by the [`Trigger`] safety documentation172// Note: this is not an EntityTrigger method because we want to reuse this logic for the entity propagation trigger173#[inline(never)]174pub unsafe fn trigger_entity_internal(175mut world: DeferredWorld,176observers: &CachedObservers,177mut event: PtrMut,178mut trigger: PtrMut,179target_entity: Entity,180trigger_context: &TriggerContext,181) {182// SAFETY: there are no outstanding world references183unsafe {184world.as_unsafe_world_cell().increment_trigger_id();185}186for (observer, runner) in observers.global_observers() {187// SAFETY:188// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`189// - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`190// - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`191// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`192unsafe {193(runner)(194world.reborrow(),195*observer,196trigger_context,197event.reborrow(),198trigger.reborrow(),199);200}201}202203if let Some(map) = observers.entity_observers().get(&target_entity) {204for (observer, runner) in map {205// SAFETY:206// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_entity_internal`207// - the passed in event pointer is an `Event`, enforced by the call to `trigger_entity_internal`208// - `trigger` is a matching trigger type, enforced by the call to `trigger_entity_internal`209// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_entity_internal`210unsafe {211(runner)(212world.reborrow(),213*observer,214trigger_context,215event.reborrow(),216trigger.reborrow(),217);218}219}220}221}222223/// An [`EntityEvent`] [`Trigger`] that behaves like [`EntityTrigger`], but "propagates" the event224/// using an [`Entity`] [`Traversal`]. At each step in the propagation, the [`EntityTrigger`] logic will225/// be run, until [`PropagateEntityTrigger::propagate`] is false, or there are no entities left to traverse.226///227/// This is used by the [`EntityEvent`] derive when `#[entity_event(propagate)]` is enabled. It is usable by every228/// [`EntityEvent`] type.229///230/// If `AUTO_PROPAGATE` is `true`, [`PropagateEntityTrigger::propagate`] will default to `true`.231pub struct PropagateEntityTrigger<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> {232/// The original [`Entity`] the [`Event`] was _first_ triggered for.233pub original_event_target: Entity,234235/// Whether or not to continue propagating using the `T` [`Traversal`]. If this is false,236/// The [`Traversal`] will stop on the current entity.237pub propagate: bool,238239_marker: PhantomData<(E, T)>,240}241242impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> Default243for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>244{245fn default() -> Self {246Self {247original_event_target: Entity::PLACEHOLDER,248propagate: AUTO_PROPAGATE,249_marker: Default::default(),250}251}252}253254impl<const AUTO_PROPAGATE: bool, E: EntityEvent, T: Traversal<E>> fmt::Debug255for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>256{257fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {258f.debug_struct("PropagateEntityTrigger")259.field("original_event_target", &self.original_event_target)260.field("propagate", &self.propagate)261.field("_marker", &self._marker)262.finish()263}264}265266// SAFETY:267// - `E`'s [`Event::Trigger`] is constrained to [`PropagateEntityTrigger<E>`]268unsafe impl<269const AUTO_PROPAGATE: bool,270E: EntityEvent + SetEntityEventTarget + for<'a> Event<Trigger<'a> = Self>,271T: Traversal<E>,272> Trigger<E> for PropagateEntityTrigger<AUTO_PROPAGATE, E, T>273{274unsafe fn trigger(275&mut self,276mut world: DeferredWorld,277observers: &CachedObservers,278trigger_context: &TriggerContext,279event: &mut E,280) {281let mut current_entity = event.event_target();282self.original_event_target = current_entity;283// SAFETY:284// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`285// - the passed in event pointer comes from `event`, which is an `Event`286// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`287// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`288unsafe {289trigger_entity_internal(290world.reborrow(),291observers,292event.into(),293self.into(),294current_entity,295trigger_context,296);297}298299loop {300if !self.propagate {301return;302}303if let Ok(entity) = world.get_entity(current_entity)304&& let Ok(item) = entity.get_components::<T>()305&& let Some(traverse_to) = T::traverse(item, event)306{307current_entity = traverse_to;308} else {309break;310}311312event.set_event_target(current_entity);313// SAFETY:314// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`315// - the passed in event pointer comes from `event`, which is an `Event`316// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`317// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`318unsafe {319trigger_entity_internal(320world.reborrow(),321observers,322event.into(),323self.into(),324current_entity,325trigger_context,326);327}328}329}330}331332/// An [`EntityEvent`] [`Trigger`] that, in addition to behaving like a normal [`EntityTrigger`], _also_ runs observers333/// that watch for components that match the slice of [`ComponentId`]s referenced in [`EntityComponentsTrigger`]. This includes334/// both _global_ observers of those components and "entity scoped" observers that watch the [`EntityEvent::event_target`].335///336/// This is used by Bevy's built-in [lifecycle events](crate::lifecycle).337#[derive(Default)]338pub struct EntityComponentsTrigger<'a> {339/// All of the components whose observers were triggered together for the target entity. For example,340/// if components `A` and `B` are added together, producing the [`Add`](crate::lifecycle::Add) event, this will341/// contain the [`ComponentId`] for both `A` and `B`.342pub components: &'a [ComponentId],343}344345// SAFETY:346// - `E`'s [`Event::Trigger`] is constrained to [`EntityComponentsTrigger`]347unsafe impl<'a, E: EntityEvent + Event<Trigger<'a> = EntityComponentsTrigger<'a>>> Trigger<E>348for EntityComponentsTrigger<'a>349{350unsafe fn trigger(351&mut self,352world: DeferredWorld,353observers: &CachedObservers,354trigger_context: &TriggerContext,355event: &mut E,356) {357let entity = event.event_target();358// SAFETY:359// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`360// - the passed in event pointer comes from `event`, which is an `Event`361// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`362unsafe {363self.trigger_internal(world, observers, event.into(), entity, trigger_context);364}365}366}367368impl<'a> EntityComponentsTrigger<'a> {369/// # Safety370/// - `observers` must come from the `world` [`DeferredWorld`]371/// - `event` must point to an [`Event`] whose [`Event::Trigger`] is [`EntityComponentsTrigger`]372/// - `trigger_context`'s [`TriggerContext::event_key`] must correspond to the `event` type.373#[inline(never)]374unsafe fn trigger_internal(375&mut self,376mut world: DeferredWorld,377observers: &CachedObservers,378mut event: PtrMut,379entity: Entity,380trigger_context: &TriggerContext,381) {382// SAFETY:383// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`384// - the passed in event pointer comes from `event`, which is an `Event`385// - `trigger` is a matching trigger type, as it comes from `self`, which is the Trigger for `E`386// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger`387unsafe {388trigger_entity_internal(389world.reborrow(),390observers,391event.reborrow(),392self.into(),393entity,394trigger_context,395);396}397398// Trigger observers watching for a specific component399for id in self.components {400if let Some(component_observers) = observers.component_observers().get(id) {401for (observer, runner) in component_observers.global_observers() {402// SAFETY:403// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`404// - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`405// - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`406// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`407unsafe {408(runner)(409world.reborrow(),410*observer,411trigger_context,412event.reborrow(),413self.into(),414);415}416}417418if let Some(map) = component_observers419.entity_component_observers()420.get(&entity)421{422for (observer, runner) in map {423// SAFETY:424// - `observers` come from `world` and match the `event` type, enforced by the call to `trigger_internal`425// - the passed in event pointer is an `Event`, enforced by the call to `trigger_internal`426// - `trigger` is a matching trigger type, enforced by the call to `trigger_internal`427// - `trigger_context`'s event_key matches `E`, enforced by the call to `trigger_internal`428unsafe {429(runner)(430world.reborrow(),431*observer,432trigger_context,433event.reborrow(),434self.into(),435);436}437}438}439}440}441}442}443444445