Exposes Observer's system's name (#19611)

# Objective

Fixes #18726
Alternative to and closes #18797

## Solution

Create a method `Observer::system_name` to expose the name of the
`Observer`'s system

## Showcase

```rust
// Returns `my_crate::my_observer`
let observer = Observer::new(my_observer);
println!(observer.system_name());

// Returns `my_crate::method::{{closure}}`
let observer = Observer::new(|_trigger: Trigger<...>|);
println!(observer.system_name());

// Returns `custom_name`
let observer = Observer::new(IntoSystem::into_system(my_observer).with_name("custom_name"));
println!(observer.system_name());
```

## TODO
- [ ] Achieve cart's approval

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Lucas Franca 2025-06-17 19:38:31 -03:00 committed by GitHub
parent f3e7a4b048
commit 6f08bb84d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 12 deletions

View File

@ -1,4 +1,4 @@
use alloc::{boxed::Box, vec};
use alloc::{borrow::Cow, boxed::Box, vec};
use core::any::Any;
use crate::{
@ -194,7 +194,7 @@ pub type ObserverRunner = fn(DeferredWorld, ObserverTrigger, PtrMut, propagate:
pub struct Observer {
hook_on_add: ComponentHook,
error_handler: Option<ErrorHandler>,
system: Box<dyn Any + Send + Sync + 'static>,
system: Box<dyn AnyNamedSystem>,
pub(crate) descriptor: ObserverDescriptor,
pub(crate) last_trigger_id: u32,
pub(crate) despawned_watched_entities: u32,
@ -232,7 +232,7 @@ impl Observer {
/// Creates a new [`Observer`] with custom runner, this is mostly used for dynamic event observer
pub fn with_dynamic_runner(runner: ObserverRunner) -> Self {
Self {
system: Box::new(|| {}),
system: Box::new(IntoSystem::into_system(|| {})),
descriptor: Default::default(),
hook_on_add: |mut world, hook_context| {
let default_error_handler = world.default_error_handler();
@ -299,6 +299,11 @@ impl Observer {
pub fn descriptor(&self) -> &ObserverDescriptor {
&self.descriptor
}
/// Returns the name of the [`Observer`]'s system .
pub fn system_name(&self) -> Cow<'static, str> {
self.system.system_name()
}
}
impl Component for Observer {
@ -364,7 +369,8 @@ fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
// - observer was triggered so must have an `Observer` component.
// - observer cannot be dropped or mutated until after the system pointer is already dropped.
let system: *mut dyn ObserverSystem<E, B> = unsafe {
let system = state.system.downcast_mut::<S>().debug_checked_unwrap();
let system: &mut dyn Any = state.system.as_mut();
let system = system.downcast_mut::<S>().debug_checked_unwrap();
&mut *system
};
@ -413,6 +419,16 @@ fn observer_system_runner<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
}
}
trait AnyNamedSystem: Any + Send + Sync + 'static {
fn system_name(&self) -> Cow<'static, str>;
}
impl<T: Any + System> AnyNamedSystem for T {
fn system_name(&self) -> Cow<'static, str> {
self.name()
}
}
/// A [`ComponentHook`] used by [`Observer`] to handle its [`on-add`](`crate::lifecycle::ComponentHooks::on_add`).
///
/// This function exists separate from [`Observer`] to allow [`Observer`] to have its type parameters
@ -431,11 +447,12 @@ fn hook_on_add<E: Event, B: Bundle, S: ObserverSystem<E, B>>(
B::component_ids(&mut world.components_registrator(), &mut |id| {
components.push(id);
});
if let Some(mut observe) = world.get_mut::<Observer>(entity) {
observe.descriptor.events.push(event_id);
observe.descriptor.components.extend(components);
if let Some(mut observer) = world.get_mut::<Observer>(entity) {
observer.descriptor.events.push(event_id);
observer.descriptor.components.extend(components);
let system: *mut dyn ObserverSystem<E, B> = observe.system.downcast_mut::<S>().unwrap();
let system: &mut dyn Any = observer.system.as_mut();
let system: *mut dyn ObserverSystem<E, B> = system.downcast_mut::<S>().unwrap();
// SAFETY: World reference is exclusive and initialize does not touch system, so references do not alias
unsafe {
(*system).initialize(world);

View File

@ -137,7 +137,6 @@ where
T: Send + Sync + 'static,
{
type In = ();
type Out = S::Out;
fn name(&self) -> Cow<'static, str> {
@ -231,7 +230,6 @@ where
T: FromWorld + Send + Sync + 'static,
{
type In = ();
type Out = S::Out;
fn name(&self) -> Cow<'static, str> {

View File

@ -1,7 +1,7 @@
---
title: Observer Overhaul
authors: ["@Jondolf", "@alice-i-cecile"]
pull_requests: [19596, 19663]
authors: ["@Jondolf", "@alice-i-cecile", "@hukasu]
pull_requests: [19596, 19663, 19611]
---
## Rename `Trigger` to `On`
@ -40,3 +40,8 @@ allowing you to bubble events up your hierarchy to see if any of the parents car
then act on the entity that was actually picked in the first place.
This was handy! We've enabled this functionality for all entity-events: simply call `On::original_target`.
## Expose name of the Observer's system
The name of the Observer's system is now accessible through `Observer::system_name`,
this opens up the possibility for the debug tools to show more meaningful names for observers.