use bevy_time_runner::TimeContext;
use std::marker::PhantomData;
use bevy::{
app::PluginGroupBuilder,
ecs::schedule::{InternedScheduleLabel, ScheduleLabel},
prelude::*,
};
use bevy_time_runner::TimeSpanProgress;
use crate::tween::{SkipTween, TweenInterpolationValue};
pub struct TweenEventPlugin<Data, TimeCtx = ()>
where
Data: Send + Sync + 'static + Clone,
TimeCtx: Default + Send + Sync + 'static,
{
pub schedule: InternedScheduleLabel,
marker: PhantomData<(Data, TimeCtx)>,
}
impl<Data, TimeCtx> TweenEventPlugin<Data, TimeCtx>
where
Data: Send + Sync + 'static + Clone,
TimeCtx: Default + Send + Sync + 'static,
{
pub fn in_schedule(schedule: impl ScheduleLabel) -> Self {
Self {
schedule: schedule.intern(),
marker: PhantomData,
}
}
}
impl<Data, TimeCtx> Plugin for TweenEventPlugin<Data, TimeCtx>
where
Data: Send + Sync + 'static + Clone,
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,
(tween_event_system::<Data, TimeCtx>)
.in_set(crate::TweenSystemSet::ApplyTween),
)
.add_message::<TweenEvent<Data>>();
}
}
pub struct DefaultTweenEventPlugins<TimeCtx = ()>
where
TimeCtx: Default + Send + Sync + 'static,
{
pub schedule: InternedScheduleLabel,
marker: PhantomData<TimeCtx>,
}
impl<TimeCtx> PluginGroup for DefaultTweenEventPlugins<TimeCtx>
where
TimeCtx: Default + Send + Sync + 'static,
{
#[allow(unused)]
#[allow(clippy::let_and_return)]
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<DefaultTweenEventPlugins>()
.add(TweenEventPlugin::<(), TimeCtx>::in_schedule(self.schedule))
.add(TweenEventPlugin::<&'static str, TimeCtx>::in_schedule(
self.schedule,
))
}
}
impl<TimeCtx> DefaultTweenEventPlugins<TimeCtx>
where
TimeCtx: Default + Send + Sync + 'static,
{
pub fn in_schedule(schedule: impl ScheduleLabel) -> Self {
Self {
schedule: schedule.intern(),
marker: PhantomData,
}
}
}
impl Default for DefaultTweenEventPlugins<()> {
fn default() -> Self {
Self {
schedule: PostUpdate.intern(),
marker: Default::default(),
}
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Component, Reflect)]
#[reflect(Component)]
#[require(EventEmittingTween)]
pub struct TweenEventData<Data = ()>(pub Data)
where
Data: Send + Sync + 'static;
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Component, Reflect)]
#[reflect(Component)]
pub struct EventEmittingTween;
impl<Data: Send + Sync + 'static> TweenEventData<Data> {
pub fn with_data(data: Data) -> Self {
TweenEventData(data)
}
}
impl TweenEventData<()> {
pub fn new() -> Self {
TweenEventData(())
}
}
#[derive(Debug, Clone, PartialEq, Message, Reflect, EntityEvent)]
pub struct TweenEvent<Data = ()> {
pub data: Data,
pub progress: TimeSpanProgress,
pub interpolation_value: Option<f32>,
pub entity: Entity,
}
#[allow(clippy::type_complexity)]
pub fn tween_event_system<Data, TimeCtx>(
mut commands: Commands,
q_tween_event_data: Query<
(
Entity,
&TweenEventData<Data>,
&TimeSpanProgress,
Option<&TweenInterpolationValue>,
),
(Without<SkipTween>, With<TimeContext<TimeCtx>>),
>,
mut event_writer: MessageWriter<TweenEvent<Data>>,
) where
Data: Clone + Send + Sync + 'static,
TimeCtx: Default + Send + Sync + 'static,
{
q_tween_event_data.iter().for_each(
|(entity, event_data, progress, interpolation_value)| {
let event = TweenEvent {
data: event_data.0.clone(),
progress: *progress,
interpolation_value: interpolation_value.map(|v| v.0),
entity,
};
commands.trigger(event.clone());
event_writer.write(event);
},
);
}