use bevy_app::{App, Plugin};
use bevy_ecs::prelude::*;
use bevy_ecs::system::IntoObserverSystem;
use std::marker::PhantomData;
use std::sync::Mutex;
use crate::Static;
pub trait SingleEvent: Static {}
pub trait AddSingleObserver {
fn has_single_observer<E: SingleEvent>(&self) -> bool;
fn add_single_observer<E: SingleEvent, B: Bundle, M>(
self,
observer: impl IntoSingleObserverSystem<E, B, M>,
) -> Self;
}
impl AddSingleObserver for &mut App {
fn has_single_observer<E: SingleEvent>(&self) -> bool {
self.is_plugin_added::<SingleEventObserverPlugin<E>>()
}
fn add_single_observer<E: SingleEvent, B: Bundle, M>(
self,
observer: impl IntoSingleObserverSystem<E, B, M>,
) -> Self {
if !self.is_plugin_added::<SingleEventObserverPlugin<E>>() {
self.add_plugins(SingleEventObserverPlugin::<E>::new());
} else {
panic!(
"a single observer is already registered for event: {}",
std::any::type_name::<E>()
);
}
self.add_observer(observer)
}
}
pub trait TriggerSingle {
fn trigger_single<E: SingleEvent>(self, event: E);
}
impl TriggerSingle for &mut Commands<'_, '_> {
fn trigger_single<E: SingleEvent>(self, event: E) {
self.trigger(SingleEventWrapper::new(event));
}
}
impl TriggerSingle for &mut World {
fn trigger_single<E: SingleEvent>(self, event: E) {
self.trigger(SingleEventWrapper::new(event));
}
}
#[doc(hidden)]
pub trait IntoSingleObserverSystem<E: SingleEvent, B: Bundle, M>:
IntoObserverSystem<SingleEventWrapper<E>, B, M>
{
}
impl<E: SingleEvent, B: Bundle, M, S> IntoSingleObserverSystem<E, B, M> for S where
S: IntoObserverSystem<SingleEventWrapper<E>, B, M>
{
}
#[derive(Event)]
pub struct SingleEventWrapper<E: SingleEvent>(Mutex<Option<E>>);
impl<E: SingleEvent> SingleEventWrapper<E> {
fn new(event: E) -> Self {
Self(Mutex::new(Some(event)))
}
pub fn consume(&self) -> Option<E> {
self.0.lock().unwrap().take()
}
}
pub type OnSingle<'w, 't, E, B = ()> = On<'w, 't, SingleEventWrapper<E>, B>;
#[doc(hidden)]
pub struct SingleEventObserverPlugin<E: SingleEvent>(PhantomData<E>);
impl<E: SingleEvent> SingleEventObserverPlugin<E> {
fn new() -> Self {
Self(PhantomData)
}
}
impl<E: SingleEvent> Plugin for SingleEventObserverPlugin<E> {
fn build(&self, _: &mut App) {}
}