`Deferred` doesn't seem to work with observers
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## Bevy version
`0.14.0`
## What you did
I created an observer with a `Deferred` parameter, but never see `T::apply` called.
For context, this comes out of a desire to have component lifecycle observers (`OnAdd`, `OnRemove`, etc.) that trigger after an exclusive system/command has released its `&mut World` access. Previous attempts to use the `Commands` queue for this were ineffective since observer command queues are flushed immediately after the observer finishes rather than added to the end of the "main" command queue.
Relevant code:
```rust
#[derive(Event)]
pub struct Defer(E);
impl From<&'_ OnRemove> for Defer {
fn from(_: &'_ OnRemove) -> Self {
Defer(OnRemove)
}
}
impl From<&'_ OnInsert> for Defer {
fn from(_: &'_ OnInsert) -> Self {
Defer(OnInsert)
}
}
impl From<&'_ OnAdd> for Defer {
fn from(_: &'_ OnAdd) -> Self {
Defer(OnAdd)
}
}
struct EntityComponents(Entity, Vec);
impl TriggerTargets for EntityComponents {
fn components(&self) -> impl ExactSizeIterator {
self.1.iter().copied()
}
fn entities(&self) -> impl ExactSizeIterator {
Some(self.0).into_iter()
}
}
pub trait DeferEvent {
fn defer(&mut self) -> &mut Self
where
E: Event,
B: Bundle,
for<'a> Defer: From<&'a E>;
fn defer_lifecycle(&mut self) -> &mut Self
where
B: Bundle,
{
self
.defer::()
.defer::()
.defer::()
}
}
struct TriggerEvent {
inner: Vec<(E, T)>,
}
impl FromWorld for TriggerEvent {
fn from_world(world: &mut World) -> Self {
Self { inner: vec![] }
}
}
impl SystemBuffer for TriggerEvent
where
E: Event,
T: TriggerTargets,
{
fn apply(&mut self, system_meta: &bevy::ecs::system::SystemMeta, world: &mut World) {
debug!("triggering deferred events");
for (event, targets) in self.inner.drain(..) {
world.trigger_targets(event, targets);
}
}
}
impl DeferEvent for App {
fn defer(&mut self) -> &mut Self
where
E: Event,
B: Bundle,
for<'a> Defer: From<&'a E>,
{
let mut ids = vec![];
let components = self.world().components();
B::get_component_ids(components, &mut |id| {
if let Some(id) = id {
ids.push(id);
}
});
self.observe(
move |trigger: Trigger,
mut defer: Deferred, EntityComponents>>| {
debug!(current_len = defer.inner.len(), "adding event to defer");
defer.inner.push((
Defer::::from(trigger.event()),
EntityComponents(trigger.entity(), ids.clone()),
));
},
)
}
}
```
## What went wrong
I see the "adding event to defer" logs with incrementing queue length, but never see the "triggering deferred events" log from the `impl SystemBuffer for TriggerEvent`.
I expected this to occur _at some point_, even if it was at the same point as the observer's command buffer application.
Contributor guide
Assessment
This issue has not been assessed yet.