bevy_ecs/reflect/event.rs
1//! Definitions for [`Event`] reflection.
2//! This allows triggering events whose type is only known at runtime.
3//!
4//! This module exports two types: [`ReflectEventFns`] and [`ReflectEvent`].
5//!
6//! Same as [`component`](`super::component`), but for events.
7
8use crate::{event::Event, reflect::from_reflect_with_fallback, world::World};
9use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry};
10
11/// A struct used to operate on reflected [`Event`] trait of a type.
12///
13/// A [`ReflectEvent`] for type `T` can be obtained via
14/// [`bevy_reflect::TypeRegistration::data`].
15#[derive(Clone)]
16pub struct ReflectEvent(ReflectEventFns);
17
18/// The raw function pointers needed to make up a [`ReflectEvent`].
19///
20/// This is used when creating custom implementations of [`ReflectEvent`] with
21/// [`ReflectEvent::new()`].
22///
23/// > **Note:**
24/// > Creating custom implementations of [`ReflectEvent`] is an advanced feature
25/// > that most users will not need. Usually a [`ReflectEvent`] is created for a
26/// > type by deriving [`Reflect`] and adding the `#[reflect(Event)]` attribute.
27/// > After adding the event to the [`TypeRegistry`], its [`ReflectEvent`] can
28/// > then be retrieved when needed.
29///
30/// Creating a custom [`ReflectEvent`] may be useful if you need to create new
31/// event types at runtime, for example, for scripting implementations.
32///
33/// By creating a custom [`ReflectEvent`] and inserting it into a type's
34/// [`TypeRegistration`][bevy_reflect::TypeRegistration], you can modify the way
35/// that reflected event of that type will be triggered in the Bevy world.
36#[derive(Clone)]
37pub struct ReflectEventFns {
38 /// Function pointer implementing [`ReflectEvent::trigger`].
39 pub trigger: fn(&mut World, &dyn PartialReflect, &TypeRegistry),
40}
41
42impl ReflectEventFns {
43 /// Get the default set of [`ReflectEventFns`] for a specific event type
44 /// using its [`FromType`] implementation.
45 ///
46 /// This is useful if you want to start with the default implementation
47 /// before overriding some of the functions to create a custom implementation.
48 pub fn new<'a, T: Event + FromReflect + TypePath>() -> Self
49 where
50 T::Trigger<'a>: Default,
51 {
52 <ReflectEvent as FromType<T>>::from_type().0
53 }
54}
55
56impl ReflectEvent {
57 /// Triggers a reflected [`Event`] like [`trigger()`](World::trigger).
58 pub fn trigger(&self, world: &mut World, event: &dyn PartialReflect, registry: &TypeRegistry) {
59 (self.0.trigger)(world, event, registry);
60 }
61
62 /// Create a custom implementation of [`ReflectEvent`].
63 ///
64 /// This is an advanced feature,
65 /// useful for scripting implementations,
66 /// that should not be used by most users
67 /// unless you know what you are doing.
68 ///
69 /// Usually you should derive [`Reflect`] and add the `#[reflect(Event)]`
70 /// attribute to generate a [`ReflectEvent`] implementation automatically.
71 ///
72 /// See [`ReflectEventFns`] for more information.
73 pub fn new(fns: ReflectEventFns) -> Self {
74 ReflectEvent(fns)
75 }
76
77 /// The underlying function pointers implementing methods on [`ReflectEvent`].
78 ///
79 /// This is useful when you want to keep track locally of an individual
80 /// function pointer.
81 ///
82 /// Calling [`TypeRegistry::get`] followed by
83 /// [`TypeRegistration::data::<ReflectEvent>`] can be costly if done several
84 /// times per frame. Consider cloning [`ReflectEvent`] and keeping it
85 /// between frames, cloning a `ReflectEvent` is very cheap.
86 ///
87 /// If you only need a subset of the methods on `ReflectEvent`,
88 /// use `fn_pointers` to get the underlying [`ReflectEventFns`]
89 /// and copy the subset of function pointers you care about.
90 ///
91 /// [`TypeRegistration::data::<ReflectEvent>`]: bevy_reflect::TypeRegistration::data
92 /// [`TypeRegistry::get`]: bevy_reflect::TypeRegistry::get
93 pub fn fn_pointers(&self) -> &ReflectEventFns {
94 &self.0
95 }
96}
97
98impl<'a, E: Event + Reflect + TypePath> FromType<E> for ReflectEvent
99where
100 <E as Event>::Trigger<'a>: Default,
101{
102 fn from_type() -> Self {
103 ReflectEvent(ReflectEventFns {
104 trigger: |world, reflected_event, registry| {
105 let event = from_reflect_with_fallback::<E>(reflected_event, world, registry);
106 world.trigger(event);
107 },
108 })
109 }
110}