use bevy_ecs::{component::Mutable, prelude::*};
use firewheel::diff::{Diff, EventQueue, Patch, PathBuilder};
use firewheel::event::NodeEventType;
use smallvec::SmallVec;
use crate::time::{Audio, AudioTime};
use super::{DiffTimestamp, events::AudioEvents};
#[derive(Debug, Component)]
#[relationship(relationship_target = Followers)]
#[cfg_attr(feature = "reflect", derive(bevy_reflect::Reflect))]
pub struct FollowerOf(pub Entity);
#[derive(Debug, Component)]
#[relationship_target(relationship = FollowerOf)]
pub struct Followers(SmallVec<[Entity; 2]>);
pub(crate) fn param_follower<T: Diff + Patch + Component<Mutability = Mutable> + Clone>(
mut sources: Query<(&mut T, &mut AudioEvents, Option<&DiffTimestamp>), Without<FollowerOf>>,
mut followers: Query<(Entity, &FollowerOf, &mut T, &mut AudioEvents)>,
time: Res<bevy_time::Time<Audio>>,
mut commands: Commands,
) -> Result {
let render_range = time.render_range();
let mut event_queue = Vec::new();
for (entity, follower, mut params, mut events) in followers.iter_mut() {
let Ok((mut source, mut source_events, timestamp)) = sources.get_mut(follower.0) else {
continue;
};
source.diff(¶ms, PathBuilder::default(), &mut event_queue);
if source_events.active_within(render_range.start, render_range.end) {
source_events.value_at(render_range.start, render_range.end, source.as_mut())?;
}
events.merge_timelines_and_clear(&mut source_events, time.now());
for event in source_events.queue.drain(..) {
if !matches!(event, NodeEventType::Param { .. }) {
events.push(event);
}
}
if let Some(timestamp) = timestamp {
if !event_queue.is_empty() {
commands.entity(entity).insert(timestamp.clone());
}
commands.entity(follower.0).remove::<DiffTimestamp>();
}
for event in event_queue.drain(..) {
match event {
e @ NodeEventType::Param { .. } => {
super::apply_patch(params.as_mut(), &e)?;
}
other => {
events.push(other);
}
}
}
}
Ok(())
}