Hey! I think you did a great job introducing observers. Definitely excited for the use cases they unlock. One thing I've been working on for the next Bevy release is statically differentiating between an "entity event / observer" and a "target-less event / observer", which would remove the weirdness of the placeholder entity. Entity access would only be available on events that expect it and you can only trigger entity targets for events that expect them. Should cut down on the "weirdness factor" a bit.
thanks! The more I dig into the implications of observers the more excited I am about them and what they mean for future releases. Having the static separation would be a nice quality of life improvement.
Thanks for breaking this down, Chris! Haven't tried hooks yet, but the observables has cleaned up my project quite a bit by removing entity fields on event structs because Trigger has the entity. Really happy with 0.14 so far.
Hmm, I could use component hooks to spawn complex entities with just one component and the hook will act as a kind of constructor for the entity. So far I had functions to define them but you had to pass a bunch of references to resources/queries and the commands to make it work, it's not very convenient. So far I only used the on_remove hook to remove entity references I held in other entities for easy queries.
I did this in one of my games last week or so. When adding a Health component, the healthbar children were added via hook. It works, but the caveat is that there can only be one hook per component event, so anything would have to go in that one function if I ever extended it. There's a bunch of people who are doing a global-observer-as-command pattern, where its basically the same but you'd trigger a SpawnHealthBar event instead (or SpawnButton or whatnot)
Hey, Chris. I noticed that you're using a Mac with an M1 processor for Bevy, and I have a big question about the `dynamic_linking` feature. I can't seem to get it to work on my M1 Pro. Maybe I don't understand how it should work. Every time I make a change to the logic, I need to restart my Bevy game. If you know, could you send me some information on where I can find an answer? Thanks!
the "dynamic_linking" feature is meant to make iterative compiles faster. it is not hot-reload for rust code, so its expected that you would recompile. hot reload for rust code would be something like dextrous_developer which is a bit more experimental, so use it with caution if you decide to: github.com/lee-orr/dexterous_developer
@@chrisbiscardi its not something i can pinpoint but just feeling like execution all over the place and pitfalls specially recursive calling observer part or bubbling or hooks between inserted or added idk. gonna need to try them before i judge i think , ok here is what's in my mind - i should be observing "values" of component or resource when it changes ( maybe to dispatch an event ? ). - dispatching events when i need action to happen like adding entity to component for some value reaches some condition. - system should always monitor components as a groups. when you say oh i need an observer not on values but on component that's what kinda doesnt make sense because whats responsable for that component to be added and hook to be called is component values and systems so logicaly we should be observing values of components. correct me if I'm wrong in anything still learning this
Systems that share mutable resources/components/etc will automatically run in serial instead of parallel. Triggers require you to use Commands, mutably. Doesn't that mean every system that uses a trigger now has lost parallel capability? Defeating a core principle of ECS?
Observers themselves do not currently parallelize, but might in the future (its been discussed but I don't know of any concrete plans for this at the moment). The system parameter when using commands is `Commands`, not `&mut Commands`, so it doesn't remove the parallel capacity in trigger-ing systems. Commands add to a command queue that is evaluated at the next sync point, similar to Observers, you're not receiving `&mut World` in your trigger-ing system. Also worth noting that EventReaders/Writers are not "going away". If you want or need the absolute parallelized grinding potential that they provide, you can still use them.
@@Boxing_Gamer They do not, EventWriters/Readers are still useful if you want to parallelize or batch event processing. There are use cases where you can use each approach for similar things but they have different strengths in that way.
@@chrisbiscardi But events are utter useless when systems are scheduled differently. I think they are a quick and dirty solution just to have something until something better comes along.
without observers, it is harder to schedule on-demand event handling. You'd have to schedule the EventReader system to run at every sync point to get similar behavior, and additionally you'd still need to guarantee that EventReader system runs before all other systems at that point, and it would *still* run after apply_deferred (the sync point) even if you did do all that. Its also notable that these are a base primitive and the 0.14 release is the first release; more will be built on top of observers-as-infrastructure. Features like bubbling still need to be built and integrated. bubbling and such will be helpful for building higher-level functionality like bevy_eventlistener, which bevy_mod_picking will eventually rely on, and IMO this will happen in more areas too.
Another great video! The only question I'm left with is the stack overflow concern at 17:29. It was my assumption that the call to trigger another event recursively would just append it to an underlying collection, the trigger system would end (matching up to the fact that normal systems aren't interrupted to fire trigger systems), the collection would pop off the next event, and repeat. Since the popping is basically iterative instead of recursive (if my assumption of the underlying process is correct), wouldn't this avoid a stack overflow?
Here is an example of an observer that will cause an overflow as of the last time I tested for it. ```rust fn on_my_event( trigger: Trigger, mut commands: Commands, ) { info!( "on_my_event {} {:?}", trigger.entity(), trigger.event() ); commands.trigger_targets( MyEvent { message: "overflow!".to_string(), }, trigger.entity(), ); } ```
Hey! I think you did a great job introducing observers. Definitely excited for the use cases they unlock. One thing I've been working on for the next Bevy release is statically differentiating between an "entity event / observer" and a "target-less event / observer", which would remove the weirdness of the placeholder entity. Entity access would only be available on events that expect it and you can only trigger entity targets for events that expect them. Should cut down on the "weirdness factor" a bit.
thanks! The more I dig into the implications of observers the more excited I am about them and what they mean for future releases. Having the static separation would be a nice quality of life improvement.
Thank you for all of your hard work! I'm super excited for the future of Bevy.
Thanks for breaking this down, Chris! Haven't tried hooks yet, but the observables has cleaned up my project quite a bit by removing entity fields on event structs because Trigger has the entity. Really happy with 0.14 so far.
Chris, Thanks for all your awesome work! It really does help
Chris doing so much for the bevy community! Appreciate all your work!!!❤
Very helpful thank you!
Thank you for that describing video
ty for the vibeo
Hmm, I could use component hooks to spawn complex entities with just one component and the hook will act as a kind of constructor for the entity. So far I had functions to define them but you had to pass a bunch of references to resources/queries and the commands to make it work, it's not very convenient. So far I only used the on_remove hook to remove entity references I held in other entities for easy queries.
I did this in one of my games last week or so. When adding a Health component, the healthbar children were added via hook. It works, but the caveat is that there can only be one hook per component event, so anything would have to go in that one function if I ever extended it.
There's a bunch of people who are doing a global-observer-as-command pattern, where its basically the same but you'd trigger a SpawnHealthBar event instead (or SpawnButton or whatnot)
Hey, Chris.
I noticed that you're using a Mac with an M1 processor for Bevy, and I have a big question about the `dynamic_linking` feature. I can't seem to get it to work on my M1 Pro. Maybe I don't understand how it should work. Every time I make a change to the logic, I need to restart my Bevy game.
If you know, could you send me some information on where I can find an answer?
Thanks!
the "dynamic_linking" feature is meant to make iterative compiles faster. it is not hot-reload for rust code, so its expected that you would recompile.
hot reload for rust code would be something like dextrous_developer which is a bit more experimental, so use it with caution if you decide to: github.com/lee-orr/dexterous_developer
@@chrisbiscardi thank you for answer. You are right, I have confused it. I'll take a look. :)
For deckbuilding roguelikes artifacts are actually a lot easier to implement now. Hmm
This all looks interesting but idk why I don't feel motivated about the approach I feel something is missing.
What do you think is missing for you?
@@chrisbiscardi its not something i can pinpoint but just feeling like execution all over the place and pitfalls specially recursive calling observer part or bubbling or hooks between inserted or added idk. gonna need to try them before i judge i think , ok here is what's in my mind
- i should be observing "values" of component or resource when it changes ( maybe to dispatch an event ? ).
- dispatching events when i need action to happen like adding entity to component for some value reaches some condition.
- system should always monitor components as a groups.
when you say oh i need an observer not on values but on component that's what kinda doesnt make sense because whats responsable for that component to be added and hook to be called is component values and systems so logicaly we should be observing values of components.
correct me if I'm wrong in anything still learning this
Systems that share mutable resources/components/etc will automatically run in serial instead of parallel. Triggers require you to use Commands, mutably. Doesn't that mean every system that uses a trigger now has lost parallel capability? Defeating a core principle of ECS?
Observers themselves do not currently parallelize, but might in the future (its been discussed but I don't know of any concrete plans for this at the moment).
The system parameter when using commands is `Commands`, not `&mut Commands`, so it doesn't remove the parallel capacity in trigger-ing systems. Commands add to a command queue that is evaluated at the next sync point, similar to Observers, you're not receiving `&mut World` in your trigger-ing system.
Also worth noting that EventReaders/Writers are not "going away". If you want or need the absolute parallelized grinding potential that they provide, you can still use them.
@@chrisbiscardi thanks
Is this replacing events? I'm not really sure.
@@Boxing_Gamer They do not, EventWriters/Readers are still useful if you want to parallelize or batch event processing. There are use cases where you can use each approach for similar things but they have different strengths in that way.
@@chrisbiscardi But events are utter useless when systems are scheduled differently. I think they are a quick and dirty solution just to have something until something better comes along.
Observers seem weird bc they dont do anything an event couldnt do ?? Seems like a slight optimization over events but eh
However the propogation seems very nice especially for ui
without observers, it is harder to schedule on-demand event handling. You'd have to schedule the EventReader system to run at every sync point to get similar behavior, and additionally you'd still need to guarantee that EventReader system runs before all other systems at that point, and it would *still* run after apply_deferred (the sync point) even if you did do all that.
Its also notable that these are a base primitive and the 0.14 release is the first release; more will be built on top of observers-as-infrastructure. Features like bubbling still need to be built and integrated. bubbling and such will be helpful for building higher-level functionality like bevy_eventlistener, which bevy_mod_picking will eventually rely on, and IMO this will happen in more areas too.
bubbling will open great opportunities to "communicate" between child/parent entities in complex structures.
Another great video! The only question I'm left with is the stack overflow concern at 17:29. It was my assumption that the call to trigger another event recursively would just append it to an underlying collection, the trigger system would end (matching up to the fact that normal systems aren't interrupted to fire trigger systems), the collection would pop off the next event, and repeat. Since the popping is basically iterative instead of recursive (if my assumption of the underlying process is correct), wouldn't this avoid a stack overflow?
Here is an example of an observer that will cause an overflow as of the last time I tested for it.
```rust
fn on_my_event(
trigger: Trigger,
mut commands: Commands,
) {
info!(
"on_my_event {} {:?}",
trigger.entity(),
trigger.event()
);
commands.trigger_targets(
MyEvent {
message: "overflow!".to_string(),
},
trigger.entity(),
);
}
```