From 2e7376001f71c3950dc875aa701958c79e823fac Mon Sep 17 00:00:00 2001 From: Christophe Bronner Date: Mon, 10 Nov 2025 01:03:26 -0500 Subject: [PATCH 1/6] Implement world.trigger_event remote method --- crates/bevy_ecs/src/reflect/event.rs | 27 +++++++++++ crates/bevy_ecs/src/reflect/mod.rs | 2 + crates/bevy_remote/src/builtin_methods.rs | 57 +++++++++++++++++++++-- crates/bevy_remote/src/lib.rs | 14 ++++++ crates/bevy_remote/src/schemas/mod.rs | 3 +- 5 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 crates/bevy_ecs/src/reflect/event.rs diff --git a/crates/bevy_ecs/src/reflect/event.rs b/crates/bevy_ecs/src/reflect/event.rs new file mode 100644 index 0000000000000..43ebdf758e2a0 --- /dev/null +++ b/crates/bevy_ecs/src/reflect/event.rs @@ -0,0 +1,27 @@ +use crate::{event::Event, reflect::from_reflect_with_fallback, world::World}; +use bevy_reflect::{FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; + +#[derive(Clone)] +pub struct ReflectEvent { + trigger: fn(&mut World, &dyn PartialReflect, &TypeRegistry), +} + +impl ReflectEvent { + pub fn trigger(&self, world: &mut World, event: &dyn PartialReflect, registry: &TypeRegistry) { + (self.trigger)(world, event, registry) + } +} + +impl<'a, E: Reflect + Event + TypePath> FromType for ReflectEvent +where + ::Trigger<'a>: Default, +{ + fn from_type() -> Self { + ReflectEvent { + trigger: |world, reflected_event, registry| { + let event = from_reflect_with_fallback::(reflected_event, world, registry); + world.trigger(event); + }, + } + } +} diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index c306723f3a707..e0e79dc067374 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -17,6 +17,7 @@ mod entity_commands; mod from_world; mod map_entities; mod resource; +mod event; use bevy_utils::prelude::DebugName; pub use bundle::{ReflectBundle, ReflectBundleFns}; @@ -25,6 +26,7 @@ pub use entity_commands::ReflectCommandExt; pub use from_world::{ReflectFromWorld, ReflectFromWorldFns}; pub use map_entities::ReflectMapEntities; pub use resource::{ReflectResource, ReflectResourceFns}; +pub use event::{ReflectEvent}; /// A [`Resource`] storing [`TypeRegistry`] for /// type registrations relevant to a whole app. diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index abe8881731fc0..7ba12ae7673d9 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -16,11 +16,9 @@ use bevy_ecs::{ }; use bevy_log::warn_once; use bevy_platform::collections::HashMap; -use bevy_reflect::{ - serde::{ReflectSerializer, TypedReflectDeserializer}, - GetPath, PartialReflect, TypeRegistration, TypeRegistry, -}; +use bevy_reflect::{serde::{ReflectSerializer, TypedReflectDeserializer}, DynamicStruct, GetPath, PartialReflect, TypeRegistration, TypeRegistry}; use serde::{de::DeserializeSeed as _, Deserialize, Serialize}; +use serde::de::IntoDeserializer; use serde_json::{Map, Value}; use crate::{ @@ -34,6 +32,8 @@ use crate::{ #[cfg(all(feature = "http", not(target_family = "wasm")))] use {crate::schemas::open_rpc::ServerObject, bevy_utils::default}; +use bevy_ecs::reflect::ReflectEvent; +use bevy_ecs::world::Mut; /// The method path for a `world.get_components` request. pub const BRP_GET_COMPONENTS_METHOD: &str = "world.get_components"; @@ -83,6 +83,9 @@ pub const BRP_MUTATE_RESOURCE_METHOD: &str = "world.mutate_resources"; /// The method path for a `world.list_resources` request. pub const BRP_LIST_RESOURCES_METHOD: &str = "world.list_resources"; +/// The method path for a `world.trigger_event` request. +pub const BRP_TRIGGER_EVENT_METHOD: &str = "world.trigger_event"; + /// The method path for a `registry.schema` request. pub const BRP_REGISTRY_SCHEMA_METHOD: &str = "registry.schema"; @@ -299,6 +302,19 @@ pub struct BrpMutateResourcesParams { pub value: Value, } +/// `world.trigger_event`: +/// +/// The server responds with a null. +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +struct BrpTriggerEventParams { + /// The [full path] of the event to trigger. + /// + /// [full path]: bevy_reflect::TypePath::type_path + pub event: String, + /// The serialized value of the event to be triggered, if any. + pub value: Option, +} + /// Describes the data that is to be fetched in a query. #[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq)] pub struct BrpQuery { @@ -1348,6 +1364,39 @@ pub fn process_remote_list_components_watching_request( } } +/// Handles a `world.trigger_event` request coming from a client. +pub fn process_remote_trigger_event_request(In(params): In>, world: &mut World) -> BrpResult { + let BrpTriggerEventParams { event, value } = parse_some(params)?; + + world.resource_scope(|world, registry: Mut| { + let registry = registry.read(); + + let Some(registration) = registry.get_with_type_path(&event) else { + return Err(BrpError::resource_error(format!( + "Unknown event type: `{event}`" + ))); + }; + let Some(reflect_event) = registration.data::() else { + return Err(BrpError::resource_error(format!( + "Event `{event}` is not reflectable" + ))); + }; + + if let Some(payload) = value { + let payload: Box = + TypedReflectDeserializer::new(registration, ®istry) + .deserialize(payload.into_deserializer()) + .map_err(|err| BrpError::resource_error(format!("{event} is invalid: {err}")))?; + reflect_event.trigger(world, &*payload, ®istry); + } else { + let payload = DynamicStruct::default(); + reflect_event.trigger(world, &payload, ®istry); + } + + Ok(Value::Null) + }) +} + /// Handles a `registry.schema` request (list all registry types in form of schema) coming from a client. pub fn export_registry_types(In(params): In>, world: &World) -> BrpResult { let filter: BrpJsonSchemaQueryFilter = match params { diff --git a/crates/bevy_remote/src/lib.rs b/crates/bevy_remote/src/lib.rs index 4713f88451327..214d249e6bcb1 100644 --- a/crates/bevy_remote/src/lib.rs +++ b/crates/bevy_remote/src/lib.rs @@ -455,6 +455,16 @@ //! //! `result`: An array of [fully-qualified type names] of registered resource types. //! +//! ### `world.trigger_event` +//! +//! Triggers an event. +//! +//! `params`: +//! - `event`: The [fully-qualified type name] of the event to trigger. +//! - `value`: The value of the event to trigger. +//! +//! `result`: null. +//! //! ### `registry.schema` //! //! Retrieve schema information about registered types in the Bevy app's type registry. @@ -669,6 +679,10 @@ impl Default for RemotePlugin { builtin_methods::BRP_LIST_RESOURCES_METHOD, builtin_methods::process_remote_list_resources_request, ) + .with_method( + builtin_methods::BRP_TRIGGER_EVENT_METHOD, + builtin_methods::process_remote_trigger_event_request, + ) .with_method( builtin_methods::BRP_REGISTRY_SCHEMA_METHOD, builtin_methods::export_registry_types, diff --git a/crates/bevy_remote/src/schemas/mod.rs b/crates/bevy_remote/src/schemas/mod.rs index 10cb2e942133a..a89f95440ac93 100644 --- a/crates/bevy_remote/src/schemas/mod.rs +++ b/crates/bevy_remote/src/schemas/mod.rs @@ -1,6 +1,6 @@ //! Module with schemas used for various BRP endpoints use bevy_ecs::{ - reflect::{ReflectComponent, ReflectResource}, + reflect::{ReflectComponent, ReflectResource, ReflectEvent}, resource::Resource, }; use bevy_platform::collections::HashMap; @@ -29,6 +29,7 @@ impl Default for SchemaTypesMetadata { }; data_types.map_type_data::("Component"); data_types.map_type_data::("Resource"); + data_types.map_type_data::("Event"); data_types.map_type_data::("Default"); #[cfg(feature = "bevy_asset")] data_types.map_type_data::("Asset"); From 60a77fd6e1ab9678b33521f0355a352be42d114b Mon Sep 17 00:00:00 2001 From: Christophe Bronner Date: Mon, 10 Nov 2025 01:56:12 -0500 Subject: [PATCH 2/6] Cleanup use in builtin_methods.rs --- crates/bevy_remote/src/builtin_methods.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index 7ba12ae7673d9..007d3388b8521 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -10,15 +10,17 @@ use bevy_ecs::{ lifecycle::RemovedComponentEntity, message::MessageCursor, query::QueryBuilder, - reflect::{AppTypeRegistry, ReflectComponent, ReflectResource}, + reflect::{AppTypeRegistry, ReflectComponent, ReflectResource, ReflectEvent}, system::{In, Local}, - world::{EntityRef, EntityWorldMut, FilteredEntityRef, World}, + world::{EntityRef, EntityWorldMut, FilteredEntityRef, World, Mut}, }; use bevy_log::warn_once; use bevy_platform::collections::HashMap; -use bevy_reflect::{serde::{ReflectSerializer, TypedReflectDeserializer}, DynamicStruct, GetPath, PartialReflect, TypeRegistration, TypeRegistry}; -use serde::{de::DeserializeSeed as _, Deserialize, Serialize}; -use serde::de::IntoDeserializer; +use bevy_reflect::{ + serde::{ReflectSerializer, TypedReflectDeserializer}, + DynamicStruct, GetPath, PartialReflect, TypeRegistration, TypeRegistry +}; +use serde::{de::DeserializeSeed as _, Deserialize, Serialize, de::IntoDeserializer}; use serde_json::{Map, Value}; use crate::{ @@ -32,8 +34,6 @@ use crate::{ #[cfg(all(feature = "http", not(target_family = "wasm")))] use {crate::schemas::open_rpc::ServerObject, bevy_utils::default}; -use bevy_ecs::reflect::ReflectEvent; -use bevy_ecs::world::Mut; /// The method path for a `world.get_components` request. pub const BRP_GET_COMPONENTS_METHOD: &str = "world.get_components"; From 7e8d9b81e3911c143df61079dda6da1fa7b3e985 Mon Sep 17 00:00:00 2001 From: Christophe Bronner Date: Mon, 10 Nov 2025 10:55:54 -0500 Subject: [PATCH 3/6] Improvements and Ci fixes --- crates/bevy_ecs/src/reflect/event.rs | 62 ++++++++++++++++++++--- crates/bevy_ecs/src/reflect/mod.rs | 4 +- crates/bevy_remote/src/builtin_methods.rs | 17 ++++--- crates/bevy_remote/src/schemas/mod.rs | 2 +- 4 files changed, 70 insertions(+), 15 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/event.rs b/crates/bevy_ecs/src/reflect/event.rs index 43ebdf758e2a0..44048e33ed20f 100644 --- a/crates/bevy_ecs/src/reflect/event.rs +++ b/crates/bevy_ecs/src/reflect/event.rs @@ -1,27 +1,77 @@ +//! Definitions for [`Event`] reflection. +//! This allows triggering events whose type is only known at runtime. +//! +//! This module exports two types: [`ReflectEventFns`] and [`ReflectEvent`]. +//! +//! Same as [`component`](`super::component`), but for events. + use crate::{event::Event, reflect::from_reflect_with_fallback, world::World}; -use bevy_reflect::{FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; +use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; + +/// A struct used to operate on reflected [`Event`] trait of a type. +/// Also works for [`EntityEvent`]. +/// +/// A [`ReflectEvent`] for type `T` can be obtained via +/// [`bevy_reflect::TypeRegistration::data`]. +#[derive(Clone)] +pub struct ReflectEvent(ReflectEventFns); +/// The raw function pointers needed to make up a [`ReflectEvent`]. +/// +/// This is used when creating custom implementations of [`ReflectEvent`] with +/// [`ReflectEvent::new()`]. +/// +/// > **Note:** +/// > Creating custom implementations of [`ReflectEvent`] is an advanced feature that most users +/// > will not need. +/// > Usually a [`ReflectEvent`] is created for a type by deriving [`Reflect`] +/// > and adding the `#[reflect(Event)]` attribute. +/// > After adding the component to the [`TypeRegistry`], +/// > its [`ReflectEvent`] can then be retrieved when needed. +/// +/// Creating a custom [`ReflectEvent`] may be useful if you need to create new component types +/// at runtime, for example, for scripting implementations. +/// +/// By creating a custom [`ReflectEvent`] and inserting it into a type's +/// [`TypeRegistration`][bevy_reflect::TypeRegistration], +/// you can modify the way that reflected event of that type will be triggered in the Bevy +/// world. #[derive(Clone)] -pub struct ReflectEvent { +pub struct ReflectEventFns { trigger: fn(&mut World, &dyn PartialReflect, &TypeRegistry), } +impl ReflectEventFns { + /// Get the default set of [`ReflectEventFns`] for a specific event type using its + /// [`FromType`] implementation. + /// + /// This is useful if you want to start with the default implementation before overriding some + /// of the functions to create a custom implementation. + pub fn new<'a, T: Event + FromReflect + TypePath>() -> Self + where + T::Trigger<'a>: Default, + { + >::from_type().0 + } +} + impl ReflectEvent { + /// Triggers a reflected [`Event`] like [`trigger()`](World::trigger). pub fn trigger(&self, world: &mut World, event: &dyn PartialReflect, registry: &TypeRegistry) { - (self.trigger)(world, event, registry) + (self.0.trigger)(world, event, registry); } } -impl<'a, E: Reflect + Event + TypePath> FromType for ReflectEvent +impl<'a, E: Event + Reflect + TypePath> FromType for ReflectEvent where ::Trigger<'a>: Default, { fn from_type() -> Self { - ReflectEvent { + ReflectEvent(ReflectEventFns { trigger: |world, reflected_event, registry| { let event = from_reflect_with_fallback::(reflected_event, world, registry); world.trigger(event); }, - } + }) } } diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index e0e79dc067374..bffc2b88af33b 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -14,19 +14,19 @@ use bevy_reflect::{ mod bundle; mod component; mod entity_commands; +mod event; mod from_world; mod map_entities; mod resource; -mod event; use bevy_utils::prelude::DebugName; pub use bundle::{ReflectBundle, ReflectBundleFns}; pub use component::{ReflectComponent, ReflectComponentFns}; pub use entity_commands::ReflectCommandExt; +pub use event::ReflectEvent; pub use from_world::{ReflectFromWorld, ReflectFromWorldFns}; pub use map_entities::ReflectMapEntities; pub use resource::{ReflectResource, ReflectResourceFns}; -pub use event::{ReflectEvent}; /// A [`Resource`] storing [`TypeRegistry`] for /// type registrations relevant to a whole app. diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index 007d3388b8521..ada91e75c736c 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -10,17 +10,17 @@ use bevy_ecs::{ lifecycle::RemovedComponentEntity, message::MessageCursor, query::QueryBuilder, - reflect::{AppTypeRegistry, ReflectComponent, ReflectResource, ReflectEvent}, + reflect::{AppTypeRegistry, ReflectComponent, ReflectEvent, ReflectResource}, system::{In, Local}, - world::{EntityRef, EntityWorldMut, FilteredEntityRef, World, Mut}, + world::{EntityRef, EntityWorldMut, FilteredEntityRef, Mut, World}, }; use bevy_log::warn_once; use bevy_platform::collections::HashMap; use bevy_reflect::{ serde::{ReflectSerializer, TypedReflectDeserializer}, - DynamicStruct, GetPath, PartialReflect, TypeRegistration, TypeRegistry + DynamicStruct, GetPath, PartialReflect, TypeRegistration, TypeRegistry, }; -use serde::{de::DeserializeSeed as _, Deserialize, Serialize, de::IntoDeserializer}; +use serde::{de::DeserializeSeed as _, de::IntoDeserializer, Deserialize, Serialize}; use serde_json::{Map, Value}; use crate::{ @@ -1365,7 +1365,10 @@ pub fn process_remote_list_components_watching_request( } /// Handles a `world.trigger_event` request coming from a client. -pub fn process_remote_trigger_event_request(In(params): In>, world: &mut World) -> BrpResult { +pub fn process_remote_trigger_event_request( + In(params): In>, + world: &mut World, +) -> BrpResult { let BrpTriggerEventParams { event, value } = parse_some(params)?; world.resource_scope(|world, registry: Mut| { @@ -1386,7 +1389,9 @@ pub fn process_remote_trigger_event_request(In(params): In>, world let payload: Box = TypedReflectDeserializer::new(registration, ®istry) .deserialize(payload.into_deserializer()) - .map_err(|err| BrpError::resource_error(format!("{event} is invalid: {err}")))?; + .map_err(|err| { + BrpError::resource_error(format!("{event} is invalid: {err}")) + })?; reflect_event.trigger(world, &*payload, ®istry); } else { let payload = DynamicStruct::default(); diff --git a/crates/bevy_remote/src/schemas/mod.rs b/crates/bevy_remote/src/schemas/mod.rs index a89f95440ac93..c17016db9c4f0 100644 --- a/crates/bevy_remote/src/schemas/mod.rs +++ b/crates/bevy_remote/src/schemas/mod.rs @@ -1,6 +1,6 @@ //! Module with schemas used for various BRP endpoints use bevy_ecs::{ - reflect::{ReflectComponent, ReflectResource, ReflectEvent}, + reflect::{ReflectComponent, ReflectEvent, ReflectResource}, resource::Resource, }; use bevy_platform::collections::HashMap; From b9a39aa696c920b90b9ec796aecb748aa65da4c1 Mon Sep 17 00:00:00 2001 From: Christophe Bronner Date: Tue, 11 Nov 2025 05:45:28 -0500 Subject: [PATCH 4/6] Add test for trigger method --- crates/bevy_remote/src/builtin_methods.rs | 36 +++++++++++++++++++++++ crates/bevy_remote/src/lib.rs | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index ada91e75c736c..5c359dab5b2e1 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -1682,6 +1682,11 @@ mod tests { } use super::*; + use bevy_ecs::{ + component::Component, event::Event, observer::On, resource::Resource, system::ResMut, + }; + use bevy_reflect::Reflect; + use serde_json::Value::Null; #[test] fn insert_reflect_only_component() { @@ -1713,6 +1718,37 @@ mod tests { insert_reflected_components(e, deserialized_components).expect("FAIL"); } + #[test] + fn trigger_reflect_only_event() { + #[derive(Event, Reflect)] + #[reflect(Event)] + struct Pass; + + #[derive(Resource)] + struct TestResult(pub bool); + + let atr = AppTypeRegistry::default(); + { + let mut register = atr.write(); + register.register::(); + } + let mut world = World::new(); + world.add_observer(move |_event: On, mut result: ResMut| result.0 = true); + world.insert_resource(TestResult(false)); + world.insert_resource(atr); + + let params = serde_json::to_value(&BrpTriggerEventParams { + event: "bevy_remote::builtin_methods::tests::Pass".to_owned(), + value: None, + }) + .expect("FAIL"); + assert_eq!( + process_remote_trigger_event_request(In(Some(params)), &mut world), + Ok(Null) + ); + assert!(world.resource::().0); + } + #[test] fn serialization_tests() { test_serialize_deserialize(BrpQueryRow { diff --git a/crates/bevy_remote/src/lib.rs b/crates/bevy_remote/src/lib.rs index 214d249e6bcb1..c30a8594900bd 100644 --- a/crates/bevy_remote/src/lib.rs +++ b/crates/bevy_remote/src/lib.rs @@ -929,7 +929,7 @@ impl From for BrpPayload { } /// An error a request might return. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] pub struct BrpError { /// Defines the general type of the error. pub code: i16, From f2103f41d71c2979b3766938bd1d4fc7698c87c0 Mon Sep 17 00:00:00 2001 From: Christophe Bronner Date: Tue, 11 Nov 2025 08:27:03 -0500 Subject: [PATCH 5/6] Pass CI? --- crates/bevy_ecs/src/lib.rs | 2 +- crates/bevy_ecs/src/reflect/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index b26f9a9d805af..da0c6c5296d7c 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -109,7 +109,7 @@ pub mod prelude { #[doc(hidden)] #[cfg(feature = "bevy_reflect")] pub use crate::reflect::{ - AppTypeRegistry, ReflectComponent, ReflectFromWorld, ReflectResource, + AppTypeRegistry, ReflectComponent, ReflectEvent, ReflectFromWorld, ReflectResource, }; #[doc(hidden)] diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index bffc2b88af33b..c0c5ee7ade282 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -23,7 +23,7 @@ use bevy_utils::prelude::DebugName; pub use bundle::{ReflectBundle, ReflectBundleFns}; pub use component::{ReflectComponent, ReflectComponentFns}; pub use entity_commands::ReflectCommandExt; -pub use event::ReflectEvent; +pub use event::{ReflectEvent, ReflectEventFns}; pub use from_world::{ReflectFromWorld, ReflectFromWorldFns}; pub use map_entities::ReflectMapEntities; pub use resource::{ReflectResource, ReflectResourceFns}; From 3928d73feb24703da8ec65417eb8b3f0a35e5577 Mon Sep 17 00:00:00 2001 From: Christophe Bronner Date: Fri, 14 Nov 2025 11:06:22 -0500 Subject: [PATCH 6/6] Pass CI? --- crates/bevy_ecs/src/reflect/event.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/reflect/event.rs b/crates/bevy_ecs/src/reflect/event.rs index 44048e33ed20f..dbdc152bb4871 100644 --- a/crates/bevy_ecs/src/reflect/event.rs +++ b/crates/bevy_ecs/src/reflect/event.rs @@ -5,7 +5,11 @@ //! //! Same as [`component`](`super::component`), but for events. -use crate::{event::Event, reflect::from_reflect_with_fallback, world::World}; +use crate::{ + event::{EntityEvent, Event}, + reflect::from_reflect_with_fallback, + world::World, +}; use bevy_reflect::{FromReflect, FromType, PartialReflect, Reflect, TypePath, TypeRegistry}; /// A struct used to operate on reflected [`Event`] trait of a type. @@ -19,7 +23,7 @@ pub struct ReflectEvent(ReflectEventFns); /// The raw function pointers needed to make up a [`ReflectEvent`]. /// /// This is used when creating custom implementations of [`ReflectEvent`] with -/// [`ReflectEvent::new()`]. +/// [`ReflectEventFns::new()`]. /// /// > **Note:** /// > Creating custom implementations of [`ReflectEvent`] is an advanced feature that most users