use super::*;
use crate::InternedScheduleLabel;
use ::bevy_lookup_curve::{LookupCache, LookupCurve};
use bevy::platform::collections::HashSet;
use tracing::error;
pub struct BevyLookupCurveInterpolationPlugin<TimeCtx = ()>
where
TimeCtx: Default + Send + Sync + 'static,
{
pub schedule: InternedScheduleLabel,
marker: PhantomData<TimeCtx>,
}
impl<TimeCtx> BevyLookupCurveInterpolationPlugin<TimeCtx>
where
TimeCtx: Default + Send + Sync + 'static,
{
pub fn in_schedule(schedule: impl ScheduleLabel) -> Self {
Self {
schedule: schedule.intern(),
marker: PhantomData,
}
}
}
impl<TimeCtx> Plugin for BevyLookupCurveInterpolationPlugin<TimeCtx>
where
TimeCtx: Default + Send + Sync + 'static,
{
fn build(&self, app: &mut App) {
#[allow(deprecated)]
let schedule = app
.world()
.get_resource::<crate::TweenAppResource>()
.map(|a| a.schedule)
.unwrap_or(self.schedule);
app.add_systems(
schedule,
(
sample_lookup_curve_system::<TimeCtx>
.in_set(TweenSystemSet::UpdateInterpolationValue),
),
);
}
}
impl Default for BevyLookupCurveInterpolationPlugin<()> {
fn default() -> Self {
Self {
schedule: PostUpdate.intern(),
marker: Default::default(),
}
}
}
#[derive(Clone, Debug, Component, Reflect)]
#[reflect(Component)]
pub struct LookupCurveCache(pub LookupCache);
#[derive(Clone, Debug, Component, Reflect)]
pub struct LookupCurveHandle(pub Handle<LookupCurve>);
#[allow(clippy::type_complexity)]
pub fn sample_lookup_curve_system<TimeCtx>(
mut commands: Commands,
mut query: Query<
(
Entity,
&LookupCurveHandle,
Option<&mut LookupCurveCache>,
&TimeSpanProgress,
),
(
Or<(Changed<LookupCurveHandle>, Changed<TimeSpanProgress>)>,
With<TimeContext<TimeCtx>>,
),
>,
mut removed: RemovedComponents<TimeSpanProgress>,
lookup_curve: Res<Assets<LookupCurve>>,
mut last_handle_error: Local<HashSet<AssetId<LookupCurve>>>,
) where
TimeCtx: Default + Send + Sync + 'static,
{
let mut handle_error = HashSet::new();
query
.iter_mut()
.for_each(|(entity, curve, cache, progress)| {
if progress.now_percentage.is_nan() {
return;
}
let curve = &curve.0;
let Some(curve) = lookup_curve.get(curve) else {
if !last_handle_error.contains(&curve.id())
&& !handle_error.contains(&curve.id())
{
error!(
"LookupCurve handle {} is not valid for interpolation",
curve.id()
);
}
handle_error.insert(curve.id());
return;
};
let value = match cache {
Some(mut cache) => curve.lookup_cached(
progress.now_percentage.clamp(0., 1.),
&mut cache.0,
),
None => curve.lookup(progress.now_percentage.clamp(0., 1.)),
};
commands
.entity(entity)
.insert(TweenInterpolationValue(value));
});
removed.read().for_each(|entity| {
if let Ok(mut entity) = commands.get_entity(entity) {
entity.remove::<TweenInterpolationValue>();
}
});
*last_handle_error = handle_error;
}