-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
Bevy version
0.14.0
What you did
I created an observer with a Deferred<T>
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:
#[derive(Event)]
pub struct Defer<E>(E);
impl From<&'_ OnRemove> for Defer<OnRemove> {
fn from(_: &'_ OnRemove) -> Self {
Defer(OnRemove)
}
}
impl From<&'_ OnInsert> for Defer<OnInsert> {
fn from(_: &'_ OnInsert) -> Self {
Defer(OnInsert)
}
}
impl From<&'_ OnAdd> for Defer<OnAdd> {
fn from(_: &'_ OnAdd) -> Self {
Defer(OnAdd)
}
}
struct EntityComponents(Entity, Vec<ComponentId>);
impl TriggerTargets for EntityComponents {
fn components(&self) -> impl ExactSizeIterator<Item = ComponentId> {
self.1.iter().copied()
}
fn entities(&self) -> impl ExactSizeIterator<Item = Entity> {
Some(self.0).into_iter()
}
}
pub trait DeferEvent {
fn defer<E, B>(&mut self) -> &mut Self
where
E: Event,
B: Bundle,
for<'a> Defer<E>: From<&'a E>;
fn defer_lifecycle<B>(&mut self) -> &mut Self
where
B: Bundle,
{
self
.defer::<OnAdd, B>()
.defer::<OnRemove, B>()
.defer::<OnInsert, B>()
}
}
struct TriggerEvent<E, T> {
inner: Vec<(E, T)>,
}
impl<E, T> FromWorld for TriggerEvent<E, T> {
fn from_world(world: &mut World) -> Self {
Self { inner: vec![] }
}
}
impl<E, T> SystemBuffer for TriggerEvent<E, T>
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<E, B>(&mut self) -> &mut Self
where
E: Event,
B: Bundle,
for<'a> Defer<E>: 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<E, B>,
mut defer: Deferred<TriggerEvent<Defer<E>, EntityComponents>>| {
debug!(current_len = defer.inner.len(), "adding event to defer");
defer.inner.push((
Defer::<E>::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.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status