bevy_ecs/event/base.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
use crate::change_detection::MaybeLocation;
use crate::component::ComponentId;
use crate::world::World;
use crate::{component::Component, traversal::Traversal};
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::Reflect;
use core::{
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
marker::PhantomData,
};
/// Something that "happens" and might be read / observed by app logic.
///
/// Events can be stored in an [`Events<E>`] resource
/// You can conveniently access events using the [`EventReader`] and [`EventWriter`] system parameter.
///
/// Events can also be "triggered" on a [`World`], which will then cause any [`Observer`] of that trigger to run.
///
/// Events must be thread-safe.
///
/// ## Derive
/// This trait can be derived.
/// Adding `auto_propagate` sets [`Self::AUTO_PROPAGATE`] to true.
/// Adding `traversal = "X"` sets [`Self::Traversal`] to be of type "X".
///
/// ```
/// use bevy_ecs::prelude::*;
///
/// #[derive(Event)]
/// #[event(auto_propagate)]
/// struct MyEvent;
/// ```
///
///
/// [`World`]: crate::world::World
/// [`ComponentId`]: crate::component::ComponentId
/// [`Observer`]: crate::observer::Observer
/// [`Events<E>`]: super::Events
/// [`EventReader`]: super::EventReader
/// [`EventWriter`]: super::EventWriter
#[diagnostic::on_unimplemented(
message = "`{Self}` is not an `Event`",
label = "invalid `Event`",
note = "consider annotating `{Self}` with `#[derive(Event)]`"
)]
pub trait Event: Send + Sync + 'static {
/// The component that describes which Entity to propagate this event to next, when [propagation] is enabled.
///
/// [propagation]: crate::observer::Trigger::propagate
type Traversal: Traversal<Self>;
/// When true, this event will always attempt to propagate when [triggered], without requiring a call
/// to [`Trigger::propagate`].
///
/// [triggered]: crate::system::Commands::trigger_targets
/// [`Trigger::propagate`]: crate::observer::Trigger::propagate
const AUTO_PROPAGATE: bool = false;
/// Generates the [`ComponentId`] for this event type.
///
/// If this type has already been registered,
/// this will return the existing [`ComponentId`].
///
/// This is used by various dynamically typed observer APIs,
/// such as [`World::trigger_targets_dynamic`].
///
/// # Warning
///
/// This method should not be overridden by implementors,
/// and should always correspond to the implementation of [`component_id`](Event::component_id).
fn register_component_id(world: &mut World) -> ComponentId {
world.register_component::<EventWrapperComponent<Self>>()
}
/// Fetches the [`ComponentId`] for this event type,
/// if it has already been generated.
///
/// This is used by various dynamically typed observer APIs,
/// such as [`World::trigger_targets_dynamic`].
///
/// # Warning
///
/// This method should not be overridden by implementors,
/// and should always correspond to the implementation of [`register_component_id`](Event::register_component_id).
fn component_id(world: &World) -> Option<ComponentId> {
world.component_id::<EventWrapperComponent<Self>>()
}
}
/// An internal type that implements [`Component`] for a given [`Event`] type.
///
/// This exists so we can easily get access to a unique [`ComponentId`] for each [`Event`] type,
/// without requiring that [`Event`] types implement [`Component`] directly.
/// [`ComponentId`] is used internally as a unique identitifier for events because they are:
///
/// - Unique to each event type.
/// - Can be quickly generated and looked up.
/// - Are compatible with dynamic event types, which aren't backed by a Rust type.
///
/// This type is an implementation detail and should never be made public.
// TODO: refactor events to store their metadata on distinct entities, rather than using `ComponentId`
#[derive(Component)]
struct EventWrapperComponent<E: Event + ?Sized>(PhantomData<E>);
/// An `EventId` uniquely identifies an event stored in a specific [`World`].
///
/// An `EventId` can among other things be used to trace the flow of an event from the point it was
/// sent to the point it was processed. `EventId`s increase monotonically by send order.
///
/// [`World`]: crate::world::World
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Clone, Debug, PartialEq, Hash)
)]
pub struct EventId<E: Event> {
/// Uniquely identifies the event associated with this ID.
// This value corresponds to the order in which each event was added to the world.
pub id: usize,
/// The source code location that triggered this event.
pub caller: MaybeLocation,
#[cfg_attr(feature = "bevy_reflect", reflect(ignore, clone))]
pub(super) _marker: PhantomData<E>,
}
impl<E: Event> Copy for EventId<E> {}
impl<E: Event> Clone for EventId<E> {
fn clone(&self) -> Self {
*self
}
}
impl<E: Event> fmt::Display for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, f)
}
}
impl<E: Event> fmt::Debug for EventId<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"event<{}>#{}",
core::any::type_name::<E>().split("::").last().unwrap(),
self.id,
)
}
}
impl<E: Event> PartialEq for EventId<E> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<E: Event> Eq for EventId<E> {}
impl<E: Event> PartialOrd for EventId<E> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<E: Event> Ord for EventId<E> {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl<E: Event> Hash for EventId<E> {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.id, state);
}
}
#[derive(Debug)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
pub(crate) struct EventInstance<E: Event> {
pub event_id: EventId<E>,
pub event: E,
}