Skip to content

Commit

Permalink
collapse crates, disable bubbling by default
Browse files Browse the repository at this point in the history
  • Loading branch information
aevyrie committed Feb 17, 2024
1 parent b073959 commit a300dc5
Show file tree
Hide file tree
Showing 14 changed files with 106 additions and 37 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# UNRELEASED

- Changed: ***BREAKING*** `EntityEvent`s no longer bubble by default.
- If you are using `#[derive(EntityEvent)]`, you will need to add the `#[can_bubble]` attribute to
enable bubbling.
- If you are manually implementing the trait, you will need to override the default `can_bubble`
trait method and return true.
- Changed: dissolved the `bevy_eventlistener_core` crate.
- Changed: `commands_mut`, `target_commands_mut`, `target_component_mut`, `listener_commands_mut`,
and `listener_component_mut` have been changed to provide a mutable reference to
`ListenerInput<E>`. This now makes it possible to call `stop_propagation()` from these functions.
Expand Down
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["crates/*"]
members = ["macros"]
resolver = "2"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -15,8 +15,11 @@ keywords = ["gamedev", "bevy", "eventlistener", "callbacks"]
categories = ["game-engines", "rendering"]

[dependencies]
bevy_eventlistener_core = { path = "crates/bevy_eventlistener_core", version = "0.6.2" }
bevy_eventlistener_derive = { path = "crates/bevy_eventlistener_derive", version = "0.6.2" }
bevy_eventlistener_derive = { path = "macros", version = "0.6.2" }
bevy_ecs = "0.12"
bevy_app = "0.12"
bevy_utils = "0.12"
bevy_hierarchy = "0.12"

[dev-dependencies]
bevy = { version = "0.12", default-features = false, features = [
Expand Down
1 change: 1 addition & 0 deletions benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ fn event_listeners(c: &mut Criterion) {
}

#[derive(Clone, Event, EntityEvent)]
#[can_bubble]
struct TestEvent<const N: usize> {
#[target]
target: Entity,
Expand Down
19 changes: 0 additions & 19 deletions crates/bevy_eventlistener_core/Cargo.toml

This file was deleted.

File renamed without changes.
1 change: 1 addition & 0 deletions examples/event_listeners.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ fn some_simple_system(time: Res<Time>) {

/// An event used with event listeners must implement `EntityEvent` and `Clone`.
#[derive(Clone, Event, EntityEvent)]
#[can_bubble]
struct MyEvent<const N: usize> {
#[target] // Marks the field of the event that specifies the target entity
target: Entity,
Expand Down
1 change: 1 addition & 0 deletions examples/minimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn main() {

/// An event used with event listeners must implement `EntityEvent` and `Clone`.
#[derive(Clone, Event, EntityEvent)]
#[can_bubble] // Enables event bubbling for this event, off by default
struct Attack {
#[target] // Marks the field of the event that specifies the target entity
target: Entity,
Expand Down
File renamed without changes.
60 changes: 60 additions & 0 deletions macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use core::panic;

use proc_macro::TokenStream;
use quote::quote;

#[proc_macro_derive(EntityEvent, attributes(target, can_bubble))]
pub fn derive(input: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(input).unwrap();
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

let mut target = None;
let mut can_bubble = false;

for attr in ast.attrs.iter() {
if attr.path().is_ident("can_bubble") {
can_bubble = true;
}
}

match ast.data {
// Only process structs
syn::Data::Struct(ref data_struct) => {
// Check the kind of fields the struct contains
// Structs with named fields
if let syn::Fields::Named(ref fields_named) = data_struct.fields {
// Iterate over the fields
for field in fields_named.named.iter() {
// Get attributes #[..] on each field
for attr in field.attrs.iter() {
// Parse the attribute
match attr.meta {
// Find the duplicated idents
syn::Meta::Path(ref path) if path.get_ident().unwrap() == "target" => {
target = Some(field.ident.clone());
}
_ => (),
}
}
}
}
}
// Panic when we don't have a struct
_ => panic!("Must be a struct"),
}

let target = target.unwrap();

let gen = quote! {
impl #impl_generics EntityEvent for #name #ty_generics #where_clause {
fn target(&self) -> Entity {
self.#target
}
fn can_bubble(&self) -> bool {
#can_bubble
}
}
};
gen.into()
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
//! Implementation of callbacks as one-shot bevy systems.

use bevy_ecs::{prelude::*, system::BoxedSystem};

use crate::EntityEvent;

/// Holds a system, with its own state, that can be run on command from an event listener
/// [`crate::prelude::On`].
#[derive(Default, Debug)]
pub enum CallbackSystem {
/// The system has been removed, because it is currently being executed in the callback graph
/// for event bubbling.
#[default]
Empty,
/// A system that has not yet been initialized.
New(BoxedSystem),
/// A system that is ready to be executed.
Initialized(BoxedSystem),
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! Provides the [`EventDispatcher`], which handles bubbling events through the entity hierarchy,
//! and triggering event listeners.

use bevy_ecs::prelude::*;
use bevy_hierarchy::Parent;
use bevy_utils::{HashMap, HashSet};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! This module provides event listeners, [`On`], the most important part of
//! [`bevy_eventlistener`](crate).

use std::marker::PhantomData;

use crate::callbacks::{CallbackSystem, ListenerInput};
Expand All @@ -10,11 +13,12 @@ use bevy_utils::tracing::error;

/// An event that targets a specific entity, and should support event listeners and bubbling.
pub trait EntityEvent: Event + Clone {
/// The entity that was targeted by this event, e.g. the entity that was clicked on.
fn target(&self) -> Entity;
/// Should events of this type bubble up the entity hierarchy, starting from the target? This is
/// enabled by default.
fn can_bubble(&self) -> bool {
true
false
}
}

Expand Down
19 changes: 12 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![deny(missing_docs)]
#![warn(missing_docs)]

//! Event listening, bubbling, and callbacks.
//!
Expand Down Expand Up @@ -80,19 +80,24 @@
//! total. To reiterate, this is using an entity hierarchy similar to the most complex websites I
//! could find.

pub use bevy_eventlistener_core::*;
pub use bevy_eventlistener_derive::EntityEvent;
pub use plugin::*;

/// Common exports
pub mod prelude {
pub use bevy_eventlistener_core::{
callbacks::{Listener, ListenerInput, ListenerMut},
event_listener::{EntityEvent, On},
EventListenerPlugin,
};
pub use crate::callbacks::{Listener, ListenerInput, ListenerMut};
pub use crate::event_listener::{EntityEvent, On};
pub use crate::EventListenerPlugin;
pub use bevy_eventlistener_derive::EntityEvent;
}

use event_listener::EntityEvent;

pub mod callbacks;
pub mod event_dispatcher;
pub mod event_listener;
pub mod plugin;

#[test]
fn replace_listener() {
use crate::prelude::*;
Expand Down
10 changes: 3 additions & 7 deletions crates/bevy_eventlistener_core/src/lib.rs → src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
//! Core implementation of event listening, bubbling, and callbacks.
//! Provides the [`EventListenerPlugin`].

use bevy_app::prelude::*;
use bevy_ecs::prelude::*;

use event_dispatcher::EventDispatcher;
use event_listener::EntityEvent;

pub mod callbacks;
pub mod event_dispatcher;
pub mod event_listener;
use crate::{event_dispatcher::EventDispatcher, event_listener::EntityEvent};

/// The [`SystemSet`] that event listener plugins are added to.
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
pub struct EventListenerSet;

Expand Down

0 comments on commit a300dc5

Please sign in to comment.