Implement world.trigger_event remote method
Objective
Tools using bevy_remote will be able to identify (via the schema) and trigger events.
- [x] 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:
Welcome, new contributor!
Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨
gave it a brief look. What happens if you use an EntityEvent?
Otherwise generally seems reasonable and follows the pattern for other such types.
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!
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.
It's probably because ReflectEventFns is not being exported to the bevy_ecs level.
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.
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, ®istry);
world.trigger(event);
}
assert!(world.get_entity(entity).is_err());
assert!(world.get_entity(entity2).is_err());
}
So my local CI runs keep flagging unrelated code so I can't verify locally and now the actions CI will fail if I'm missing a use for documentation and fails if I add it because I'm not using it in code...
Also why are there like 3 different actions (build, check-doc, ci) that all build separately? Isn't that a bit wasteful?
So my local CI runs keep flagging unrelated code so I can't verify locally and now the actions CI will fail if I'm missing a use for documentation and fails if I add it because I'm not using it in code...
You can add the link in-line, using e.g. [Schedule](bevy::ecs::prelude::Schedule) :)
Also why are there like 3 different actions (build, check-doc, ci) that all build separately? Isn't that a bit wasteful?
In some ways! Generally our CI is limited by cache size and length of the longest job, not the number of runners. Some of the duplicated builds use slightly different settings as well. Not saying that it's perfect, but just giving you a bit of background.
Thanks! I might be able to get it to pass CI now! Still wondering what I did wrong for local CI to fail on latest main so I'm going off the remote CI's feedback
Thanks! I might be able to get it to pass CI now! Still wondering what I did wrong for local CI to fail on latest main so I'm going off the remote CI's feedback
Yep, that's totally fine. I sometimes do this myself when it's acting up or I'm feeling lazy.