lyra-engine/lyra-game/src/events.rs

83 lines
2.4 KiB
Rust

use std::{collections::{HashMap, VecDeque}, any::{TypeId, Any}, cell::RefCell};
use crate::{castable_any::CastableAny, plugin::Plugin};
pub trait Event: Clone + Send + Sync + 'static {}
impl<T: Clone + Send + Sync + 'static> Event for T {}
pub type Events<T> = VecDeque<T>;
pub struct EventQueue {
events: HashMap<TypeId, RefCell<Box<dyn CastableAny>>>,
event_write_queue: HashMap<TypeId, RefCell<Box<dyn CastableAny>>>
}
impl Default for EventQueue {
fn default() -> Self {
Self::new()
}
}
impl EventQueue {
pub fn new() -> Self {
Self {
event_write_queue: HashMap::new(),
events: HashMap::new(),
}
}
/// Trigger an event
pub fn trigger_event<E>(&mut self, event: E)
where
E: Event
{
// the compiler wants me to explicit right here for some reason
let default = || RefCell::new(Box::<Events::<E>>::default() as Box<dyn CastableAny>);
// Get, or create, a list of events of this type
let type_id = event.type_id();
let mut events = self.event_write_queue.entry(type_id)
.or_insert_with(default)
.borrow_mut();
// downcast resource as an events storage
let e: &mut Events<E> = events.as_mut().as_any_mut().downcast_mut().unwrap();
e.push_back(event);
}
// Clear events, this should happen at the start of every tick since events are cloned
// before being given to the reader.
pub fn update_events(&mut self) {
self.events.clear();
// get all keys of events
let keys: Vec<TypeId> = self.event_write_queue.keys().copied().collect();
// remove all elements from self.event_write_queue and insert them to events
for k in keys.into_iter() {
let v = self.event_write_queue.remove(&k).unwrap();
self.events.insert(k, v);
}
}
pub fn read_events<E>(&self) -> Option<Events<E>>
where
E: Event
{
if let Some(event ) = self.events.get(&TypeId::of::<E>()) {
let eref = event.borrow();
Some(eref.as_ref().as_any().downcast_ref::<Events<E>>().unwrap().clone())
} else {
None
}
}
}
#[derive(Default)]
pub struct EventsPlugin;
impl Plugin for EventsPlugin {
fn setup(&self, game: &mut crate::game::Game) {
game.world_mut().add_resource(EventQueue::new());
}
}