aevyrie / bevy_eventlistener

Event listening, bubbling, and callbacks
Apache License 2.0
178 stars 27 forks source link

Custom events sometimes get eaten #12

Closed viridia closed 1 year ago

viridia commented 1 year ago

Here's a minimal example that illustrates the issue I discussed last week on the Discord. When I sent a custom event "Clicked" (not "Click"), the first event is sometimes not received:

The problem is intermittent - you may have to run the example multiple times in order to see it. For me, happens about 50% of the time, so it shouldn't take many runs to see it.

When it is not working, you'll see output like this:

--> Sending Clicked id='One' target=4v0
? Reading global clicked: id='One' target=4v0

And when it is working, you'll see output like this:

--> Sending Clicked id='One' target=4v0
<-- Received Clicked Button id='One' target=4v0
? Reading global clicked: id='One' target=4v0

main.rs.zip

aevyrie commented 1 year ago

Working through what is happening here:

  1. Pointer<Click> callback executes, sends Clicked event
  2. System runs, reading for that bevy event, and always sees it as expected.
  3. A second callback system listens for the Clicked event.

My guess is that because the order of callback systems is not gauranteed, it is possible that the eventlistener system for Clicked is sometimes run before, and sometimes after, the one for Pointer<Click>. I can solve the issue of the single gobbled event, but you have another issue on your hands - the eventlistener systems only run once per frame, so the amount that the reactive system can propagate is dependent on the order of these systems, as well as the framerate. Ideally, we could run these event listener systems as many times as needed until no more events are generated.

aevyrie commented 1 year ago

@viridia I'm having trouble replicating this. The only thing I see is this: Correct

--> Sending Clicked id='One' target=2v0
<-- Received Clicked Button id='One' target=2v0
? Reading global clicked: id='One' target=2v0

Delayed one frame

--> Sending Clicked id='One' target=4v0
? Reading global clicked: id='One' target=4v0
<-- Received Clicked Button id='One' target=4v0

So, this is caused by what I said before - in this case the Pointer<Click> eventlistener plugin is running after the Clicked eventlistener plugin, which means it cannot be received until the next frame.

However, I can't replicate the event being missed entirely.

viridia commented 1 year ago

OK, I'll need to look into the reproducibility issue. I've been able to reproduce this many times, including just now, so it could be something in my environment.

If it makes any difference, I'm testing on a MacBook (Apple Silicon) under OS X Monterey. Rustc is 1.73.0. Bevy is v0.12.0.

viridia commented 1 year ago

In fact, if I disable the global listener, I can get the following output:

--> Sending Clicked id='One' target=2v0

In other words, the event is not received at by the On handler, even without the presence of the global listener. So I don't think the order of handlers is what matters.