use std::{
any::{Any, TypeId},
collections::HashMap,
marker::PhantomData,
ops::{Deref, DerefMut},
};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use winit::event::{DeviceEvent, WindowEvent};
use crate::{
asset::AssetLibrary,
components::EventLabel,
resources::{Frame, Input},
scene::Scene,
};
pub trait Resource: Any {}
pub struct Res<'a, T: Resource + 'static> {
lock: RwLockReadGuard<'a, Box<dyn Any + Send + Sync>>,
_ty: PhantomData<T>,
}
pub struct ResMut<'a, T: Resource + 'static> {
lock: RwLockWriteGuard<'a, Box<dyn Any + Send + Sync>>,
_ty: PhantomData<T>,
}
impl<'a, T: Resource + Send + Sync> Deref for Res<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.lock
.downcast_ref()
.expect("Res type and Resource type should be the same")
}
}
impl<'a, T: Resource + Send + Sync> Deref for ResMut<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.lock
.downcast_ref()
.expect("ResMut type and Resource type should be the same")
}
}
impl<'a, T: Resource + Send + Sync> DerefMut for ResMut<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.lock
.downcast_mut()
.expect("ResMut type and Resource type should be the same")
}
}
pub struct GameContext {
pub scene: Scene,
pub assets: AssetLibrary,
resources: HashMap<TypeId, RwLock<Box<dyn Any + Send + Sync>>>,
}
impl Default for GameContext {
fn default() -> Self {
Self::new()
}
}
impl GameContext {
pub fn new() -> GameContext {
GameContext {
scene: Scene::new(),
resources: HashMap::new(),
assets: AssetLibrary::new(),
}
}
pub fn device_event(&mut self, event: &DeviceEvent) {
self.get_resource_mut::<Input>().handle_device_event(event)
}
pub fn window_event(&mut self, event: &WindowEvent) {
self.get_resource_mut::<Input>().handle_event(event);
}
pub fn begin_frame(&mut self) {
self.scene.poll_async(&self.assets);
self.get_resource_mut::<Frame>().update();
}
pub fn end_frame(&mut self) {
self.get_resource_mut::<Input>().end_frame();
}
pub fn get_resource<R: Resource>(&self) -> Res<'_, R> {
let id = TypeId::of::<R>();
let name = std::any::type_name::<R>();
let cell = self.resources.get(&id).unwrap_or_else(|| {
panic!("Resource: {name} not found (did you forget to add its plugin?)")
});
let lock = cell.read();
Res {
lock,
_ty: PhantomData,
}
}
pub fn get_resource_mut<R: Resource>(&self) -> ResMut<'_, R> {
let id = TypeId::of::<R>();
let name = std::any::type_name::<R>();
let cell = self.resources.get(&id).unwrap_or_else(|| {
panic!("Resource: {name} not found (did you forget to add its plugin?)")
});
let lock = cell.write();
ResMut {
lock,
_ty: PhantomData,
}
}
pub fn insert_resource<R: Resource + Send + Sync>(&mut self, resource: R) {
let id = TypeId::of::<R>();
self.resources.insert(id, RwLock::new(Box::new(resource)));
}
pub fn pop_ready_queue(&self) {
self.scene.pop_ready_queue(self);
}
pub fn emit<E: EventLabel>(&self, event: E) {
let nodes = &self.scene;
nodes.emit(&event, self);
}
}