Skip to content

Conversation

@Lancelotbronner
Copy link

@Lancelotbronner Lancelotbronner commented Nov 10, 2025

Objective

Tools using bevy_remote will be able to identify (via the schema) and trigger events.

  • Document bevy_ecs/src/reflect/event.rs

Solution

I've added a method world.trigger_event, added Event to the schema's reflection metadata and ReflectEvent to allow this.

Testing

I have copied the (tested) code from my game but have NOT tested this branch yet.
I am new to Rust/Cargo and need to go to sleep now, I'll figure this out and test it tomorrow.


Showcase

Here's what I needed to add to my game in order to allow my editor to access and trigger an event:

#[derive(Event, Reflect)]
#[reflect(Event)]
pub struct AssignToRoute {
    pub vehicle: Entity,
    pub route: Entity,
    pub origin: Entity,
}

Here's a screenshot of my editor using this feature:

Screenshot 2025-11-10 at 1 40 42 AM

@github-actions
Copy link
Contributor

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

@Lancelotbronner Lancelotbronner marked this pull request as draft November 10, 2025 06:58
@ChristopherBiscardi
Copy link
Contributor

gave it a brief look. What happens if you use an EntityEvent?

Otherwise generally seems reasonable and follows the pattern for other such types.

@Lancelotbronner
Copy link
Author

gave it a brief look. What happens if you use an EntityEvent?

Otherwise generally seems reasonable and follows the pattern for other such types.

#[derive(EntityEvent, Reflect)]
#[reflect(Event)]
pub struct Explode(pub Entity);

commands.spawn(Name::new("WontExplode".to_string()));
commands.spawn(Name::new("WillExplode".to_string())).observe(
  |event: On<Explode>, mut commands: Commands| {
    println!("Boom!");
    commands.entity(event.event_target()).despawn();
  },
);

Sending the event for both entities only explodes "WillExplode", so I guess EntityEvent also works!

@Lancelotbronner
Copy link
Author

I'm trying to pass CI locally but I keep getting error: associated function new is never used on the following:

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,
    {
        <ReflectEvent as FromType<T>>::from_type().0
    }
}

It's right but doesn't warn on the equivalent methods for components, resources, bundles, etc. and they have no usage either according to my IDE.

Anything I'm missing? I don't want to allow(dead_code) either since they don't have it but I can't figure out where they're supposed to be used.

@Lancelotbronner Lancelotbronner marked this pull request as ready for review November 10, 2025 15:56
@hymm
Copy link
Contributor

hymm commented Nov 10, 2025

It's probably because ReflectEventFns is not being exported to the bevy_ecs level.

@alice-i-cecile alice-i-cecile added C-Feature A new feature, making something new possible A-Dev-Tools Tools used to debug Bevy applications. S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged X-Uncontroversial This work is generally agreed upon labels Nov 10, 2025
@alice-i-cecile
Copy link
Member

Very sensible idea. Do we have pre-existing tests for this module? If so, we should be testing this too. If not, well, that can wait for follow-up.

@Lancelotbronner
Copy link
Author

Lancelotbronner commented Nov 11, 2025

Added a test for bevy_remote, we sorta didn't but now we have at least one testing the happy path.

I'm also trying to write a test for bevy_ecs but I can't figure out how to satisfy the borrow checker.
Can we consider the bevy_remote one an integration test for both?

Here's what I had for bevy_ecs so far:

#[derive(EntityEvent, Reflect)]
#[reflect(Event)]
struct Explode(pub Entity);

#[derive(Component)]
struct DespawnOnExplode;

#[test]
fn trigger_event() {
    let mut world = World::new();

    let type_registry = AppTypeRegistry::default();
    {
        let mut registry = type_registry.write();
        registry.register::<Explode>();
        registry.register_type_data::<Explode, ReflectEvent>();
    }
    world.insert_resource(type_registry);

    let mut system_state: SystemState<Commands> = SystemState::new(&mut world);
    let mut commands = system_state.get_mut(&mut world);

    let entity = commands
        .spawn_empty()
        .observe(|event: On<Explode>, mut commands: Commands| {
            commands.entity(event.0).despawn()
        })
        .id();
    let entity2 = commands.spawn(DespawnOnExplode).id();

    commands.add_observer(
        |event: On<Explode>,
         entities: Query<Entity, With<DespawnOnExplode>>,
         mut commands: Commands| {
            for entity in entities.iter() {
                commands.entity(entity).despawn()
            }
        },
    );

    let mut reflect_event = DynamicTupleStruct::default();
    reflect_event.insert(entity.to_bits());
    {
        let registry = *world.resource::<AppTypeRegistry>().write();
        let event =
            from_reflect_with_fallback::<Explode>(&reflect_event, &mut world, &registry);
        world.trigger(event);
    }

    assert!(world.get_entity(entity).is_err());
    assert!(world.get_entity(entity2).is_err());
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Dev-Tools Tools used to debug Bevy applications. C-Feature A new feature, making something new possible S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged X-Uncontroversial This work is generally agreed upon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants