Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/bevy_ecs/macros/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ pub fn derive_entity_event(input: TokenStream) -> TokenStream {

impl #impl_generics #bevy_ecs_path::event::EntityEvent for #struct_name #type_generics #where_clause {
fn event_target(&self) -> #bevy_ecs_path::entity::Entity {
self.#entity_field
#bevy_ecs_path::entity::ContainsEntity::entity(&self.#entity_field)
}

fn event_target_mut(&mut self) -> &mut #bevy_ecs_path::entity::Entity {
&mut self.#entity_field
fn set_event_target(&mut self, entity: #bevy_ecs_path::entity::Entity) {
self.#entity_field = Into::into(entity);
}
}

Expand Down
76 changes: 73 additions & 3 deletions crates/bevy_ecs/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,11 @@ pub trait Event: Send + Sync + Sized + 'static {
pub trait EntityEvent: Event {
/// The [`Entity`] "target" of this [`EntityEvent`]. When triggered, this will run observers that watch for this specific entity.
fn event_target(&self) -> Entity;
/// Returns a mutable reference to the [`Entity`] "target" of this [`EntityEvent`]. When triggered, this will run observers that watch for this specific entity.
/// Sets the [`Entity`] "target" of this [`EntityEvent`]. When triggered, this will run observers that watch for this specific entity.
///
/// Note: In general, this should not be mutated from within an [`Observer`](crate::observer::Observer), as this will not "retarget"
/// Note: In general, this should not be called from within an [`Observer`](crate::observer::Observer), as this will not "retarget"
/// the event in any of Bevy's built-in [`Trigger`] implementations.
fn event_target_mut(&mut self) -> &mut Entity;
fn set_event_target(&mut self, entity: Entity);
}

impl World {
Expand Down Expand Up @@ -959,4 +959,74 @@ mod tests {
});
schedule.run(&mut world);
}

#[test]
fn test_derive_entity_event() {
use bevy_ecs::prelude::*;

struct Entitoid(Entity);

impl ContainsEntity for Entitoid {
fn entity(&self) -> Entity {
self.0
}
}

// Lame :(
impl From<Entity> for Entitoid {
fn from(value: Entity) -> Self {
Self(value)
}
}

#[derive(EntityEvent)]
struct A(Entity);

#[derive(EntityEvent)]
struct B {
entity: Entity,
}

#[derive(EntityEvent)]
struct C {
#[event_target]
target: Entity,
}

#[derive(EntityEvent)]
struct D(Entitoid);

#[derive(EntityEvent)]
struct E {
entity: Entitoid,
}

#[derive(EntityEvent)]
struct F {
#[event_target]
target: Entitoid,
}

let mut world = World::new();
let entity = world.spawn_empty().id();

world.entity_mut(entity).trigger(A);

// Lame :(
world.entity_mut(entity).trigger(|entity| B { entity });
world
.entity_mut(entity)
.trigger(|entity| C { target: entity });
world
.entity_mut(entity)
.trigger(|entity| D(Entitoid(entity)));
world.entity_mut(entity).trigger(|entity| E {
entity: Entitoid(entity),
});
world.entity_mut(entity).trigger(|entity| F {
target: Entitoid(entity),
});

// No asserts; test just needs to compile
}
}
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/event/trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ unsafe impl<
break;
}

*event.event_target_mut() = current_entity;
event.set_event_target(current_entity);
// SAFETY:
// - `observers` come from `world` and match the event type `E`, enforced by the call to `trigger`
// - the passed in event pointer comes from `event`, which is an `Event`
Expand Down