use crate::executor::with_world_mut;
use crate::reactors::Change;
use crate::signals::{SignalSender, Signals};
use crate::tween::AsSeconds;
use crate::{
access::{deref::AsyncComponentDeref, AsyncComponent},
AccessResult,
};
use crate::{AccessError, OwnedQueryState};
use bevy::animation::prelude::{AnimationNodeIndex, AnimationTransitions};
use bevy::animation::AnimationPlayer;
use bevy::ecs::component::Component;
use bevy::ecs::entity::{Entity, EntityHashMap};
use bevy::ecs::query::With;
use bevy::ecs::system::Local;
use bevy::ecs::{query::Changed, system::Query};
use futures::{Future, FutureExt};
use ref_cast::RefCast;
use std::ops::{Deref, DerefMut};
#[derive(RefCast)]
#[repr(transparent)]
pub struct AsyncAnimationPlayer(AsyncComponent<AnimationPlayer>);
impl AsyncComponentDeref for AnimationPlayer {
type Target = AsyncAnimationPlayer;
fn async_deref(this: &AsyncComponent<Self>) -> &Self::Target {
AsyncAnimationPlayer::ref_cast(this)
}
}
#[derive(RefCast)]
#[repr(transparent)]
pub struct AsyncAnimationTransitions(AsyncComponent<AnimationTransitions>);
impl AsyncComponentDeref for AnimationTransitions {
type Target = AsyncAnimationTransitions;
fn async_deref(this: &AsyncComponent<Self>) -> &Self::Target {
AsyncAnimationTransitions::ref_cast(this)
}
}
impl AsyncAnimationPlayer {
pub fn start(&self, clip: AnimationNodeIndex) -> AccessResult {
self.0.get_mut(move |player| {
player.start(clip);
})
}
pub fn play(&self, clip: AnimationNodeIndex) -> AccessResult {
self.0.get_mut(move |player| {
player.play(clip);
})
}
pub fn play_repeat(&self, clip: AnimationNodeIndex) -> AccessResult {
self.0.get_mut(move |player| {
player.play(clip).repeat();
})
}
pub fn stop(&self, clip: AnimationNodeIndex) -> AccessResult {
self.0.get_mut(move |player| {
player.stop(clip);
})
}
pub fn stop_all(&self) -> AccessResult {
self.0.get_mut(move |player| {
player.stop_all();
})
}
pub fn is_playing_animation(&self, clip: AnimationNodeIndex) -> AccessResult<bool> {
self.0.get(move |player| player.is_playing_animation(clip))
}
pub fn wait(
&self,
event: AnimationEvent,
) -> AccessResult<impl Future<Output = bool> + 'static> {
let (send, recv) = async_oneshot::oneshot();
with_world_mut(|w| {
let Ok(mut entity) = w.get_entity_mut(self.0.entity) else {
return Err(AccessError::EntityNotFound(self.0.entity));
};
if let Some(mut reactors) = entity.get_mut::<AnimationReactor>() {
reactors.push((event, send));
} else {
entity.insert(AnimationReactor(vec![(event, send)]));
};
Ok(())
})?;
Ok(recv.map(|v| v.unwrap_or(false)))
}
}
impl AsyncAnimationTransitions {
pub fn play(&self, animation: AnimationNodeIndex, transition: impl AsSeconds) {
with_world_mut(|w| {
let mut query =
OwnedQueryState::<(&mut AnimationPlayer, &mut AnimationTransitions), ()>::new(w);
if let Ok((mut player, mut transitions)) = query.get_mut(self.0.entity().id()) {
transitions.play(&mut player, animation, transition.as_duration());
}
})
}
}
#[derive(Debug)]
pub enum AnimationEvent {
OnExit(AnimationNodeIndex),
OnEnter(AnimationNodeIndex),
WaitUnitOnExit(AnimationNodeIndex),
OnFrame {
animation: AnimationNodeIndex,
frame: f32,
},
}
#[derive(Component, Clone, Default)]
pub struct PreviousAnimationPlayer(AnimationPlayer);
impl Deref for PreviousAnimationPlayer {
type Target = AnimationPlayer;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Component)]
pub struct AnimationReactor(Vec<(AnimationEvent, async_oneshot::Sender<bool>)>);
#[derive(RefCast)]
#[repr(transparent)]
pub struct AsyncAnimationReactor(AsyncComponent<AnimationReactor>);
impl AsyncComponentDeref for AnimationReactor {
type Target = AsyncAnimationReactor;
fn async_deref(this: &AsyncComponent<Self>) -> &Self::Target {
AsyncAnimationReactor::ref_cast(this)
}
}
impl AnimationReactor {
pub fn react_to(&mut self, event: AnimationEvent) -> impl Future<Output = bool> + 'static {
let (send, recv) = async_oneshot::oneshot();
self.push((event, send));
recv.map(|v| v.unwrap_or(false))
}
}
impl AsyncAnimationReactor {
pub async fn react_to(&self, event: AnimationEvent) -> AccessResult<bool> {
Ok(self.0.get_mut(|x| x.react_to(event))?.await)
}
}
impl Deref for AnimationReactor {
type Target = Vec<(AnimationEvent, async_oneshot::Sender<bool>)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for AnimationReactor {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub fn react_to_animation(
mut query: Query<
(
&AnimationPlayer,
&mut PreviousAnimationPlayer,
Option<&mut AnimationReactor>,
),
Changed<AnimationPlayer>,
>,
) {
for (player, mut prev, reactors) in query.iter_mut() {
if let Some(mut reactors) = reactors {
reactors.0.retain_mut(|(event, channel)| {
let yields = match event {
AnimationEvent::OnExit(idx) => {
(!player.is_playing_animation(*idx)).then_some(true)
}
AnimationEvent::OnEnter(idx) => {
player.is_playing_animation(*idx).then_some(true)
}
AnimationEvent::WaitUnitOnExit(idx) => (player.is_playing_animation(*idx)
&& !prev.0.is_playing_animation(*idx))
.then_some(true),
AnimationEvent::OnFrame { animation, frame } => {
if let Some(prev) = prev.0.animation(*animation) {
if let Some(curr) = player.animation(*animation) {
if curr.seek_time() >= *frame && *frame > prev.seek_time() {
Some(true)
} else {
None
}
} else {
Some(false)
}
} else {
None
}
}
};
match yields {
Some(v) => {
let _ = channel.send(v);
false
}
None => true,
}
});
}
prev.0.clone_from(player);
}
}
pub type MainAnimationChange = Change<Option<AnimationNodeIndex>>;
pub fn react_to_main_animation_change(
mut cache: Local<EntityHashMap<Option<AnimationNodeIndex>>>,
query: Query<
(
Entity,
&AnimationTransitions,
SignalSender<MainAnimationChange>,
),
(With<Signals>, Changed<AnimationTransitions>),
>,
) {
for (entity, transition, sender) in query.iter() {
let prev = cache.get(&entity).copied();
if prev.flatten() != transition.get_main_animation() {
cache.insert(entity, transition.get_main_animation());
sender.send(Change {
from: prev,
to: transition.get_main_animation(),
});
}
}
}