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