use std::{collections::VecDeque, marker::PhantomData, ops::Deref};
use winit::{
application::ApplicationHandler,
event_loop::{ActiveEventLoop, EventLoopProxy},
};
use super::{
components::ComponentRegistry,
data_state::{DataState, DataStateAccessError, WriteDataState},
events::{EventRegistry, MatrixEvent, MatrixEventable},
plugins::Plugin,
resources::ResourceRegistry,
runtimes::Runtime,
systems::{IntoNonSendSystem, IntoSendSystem, SystemRegistry},
};
#[derive(Debug)]
pub struct SceneRegistryRefs<CustomEvents: MatrixEventable = ()> {
pub components: WriteDataState<ComponentRegistry>,
pub events: WriteDataState<EventRegistry<CustomEvents>>,
pub resources: WriteDataState<ResourceRegistry>,
}
pub(crate) struct DummySceneRegistry<CustomEvents: MatrixEventable = ()> {
pub registry: SceneRegistryRefs<CustomEvents>,
components: DataState<ComponentRegistry>,
events: DataState<EventRegistry<CustomEvents>>,
resources: DataState<ResourceRegistry>,
}
impl<CustomEvents: MatrixEventable> SceneRegistryRefs<CustomEvents> {
pub(crate) fn dummy() -> DummySceneRegistry<CustomEvents> {
DummySceneRegistry::new()
}
}
impl<CustomEvents: MatrixEventable> DummySceneRegistry<CustomEvents> {
pub(crate) fn new() -> Self {
let mut components = DataState::default();
let mut events = DataState::new(EventRegistry::new_no_events());
let mut resources = DataState::default();
DummySceneRegistry {
registry: SceneRegistryRefs {
components: components.write().unwrap(),
events: events.write().unwrap(),
resources: resources.write().unwrap(),
},
components,
events,
resources,
}
}
}
pub struct ActiveEventLoopRef {
ptr: *const ActiveEventLoop,
}
impl ActiveEventLoopRef {
pub fn new(ptr: *const ActiveEventLoop) -> Self {
Self { ptr }
}
}
impl Deref for ActiveEventLoopRef {
type Target = ActiveEventLoop;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
pub struct SendEngineStartupArgs;
pub struct NonSendEngineStartupArgs {
pub event_loop: ActiveEventLoopRef,
}
pub struct SendEngineArgs;
pub struct NonSendEngineArgs;
pub struct Scene<CustomEvents: MatrixEventable> {
marker: PhantomData<CustomEvents>,
components: DataState<ComponentRegistry>,
events: DataState<EventRegistry<CustomEvents>>,
systems: SystemRegistry<SceneRegistryRefs<CustomEvents>, SendEngineArgs, NonSendEngineArgs>,
startup_systems: SystemRegistry<
SceneRegistryRefs<CustomEvents>,
SendEngineStartupArgs,
NonSendEngineStartupArgs,
>,
plugins: VecDeque<Box<dyn Plugin<CustomEvents>>>,
}
impl<CustomEvents: MatrixEventable> Scene<CustomEvents> {
pub fn new(proxy: EventLoopProxy<MatrixEvent<CustomEvents>>) -> Self {
Self {
marker: PhantomData,
components: Default::default(),
events: DataState::new(EventRegistry::new_with_events(proxy)),
systems: SystemRegistry::new(),
startup_systems: SystemRegistry::new(),
plugins: VecDeque::new(),
}
}
pub fn add_send_system<P: 'static>(
&mut self,
sys: impl IntoSendSystem<SceneRegistryRefs<CustomEvents>, SendEngineArgs, P> + 'static,
) {
self.systems.add_send_system(Box::new(sys.into_system()));
}
pub fn add_non_send_system<P: 'static>(
&mut self,
sys: impl IntoNonSendSystem<SceneRegistryRefs<CustomEvents>, NonSendEngineArgs, P> + 'static,
) {
self.systems
.add_non_send_system(Box::new(sys.into_system()));
}
pub fn add_send_startup_system<P: 'static>(
&mut self,
sys: impl IntoSendSystem<SceneRegistryRefs<CustomEvents>, SendEngineStartupArgs, P> + 'static,
) {
self.startup_systems
.add_send_system(Box::new(sys.into_system()));
}
pub fn add_non_send_startup_system<P: 'static>(
&mut self,
sys: impl IntoNonSendSystem<SceneRegistryRefs<CustomEvents>, NonSendEngineStartupArgs, P>
+ 'static,
) {
self.startup_systems
.add_non_send_system(Box::new(sys.into_system()));
}
pub fn components(&self) -> Result<&ComponentRegistry, DataStateAccessError> {
self.components.get()
}
pub fn components_mut(&mut self) -> Result<&mut ComponentRegistry, DataStateAccessError> {
self.components.get_mut()
}
fn destroy_system(&mut self, id: super::entity::SystemEntity) {
if !self.systems.destroy_system(id) {
self.startup_systems.destroy_system(id);
}
}
}
pub struct SceneManager<CustomEvents: MatrixEventable> {
current_scene: Scene<CustomEvents>,
runtime: Box<dyn Runtime<SceneRegistryRefs<CustomEvents>, SendEngineArgs, NonSendEngineArgs>>,
startup_runtime: Box<
dyn Runtime<
SceneRegistryRefs<CustomEvents>,
SendEngineStartupArgs,
NonSendEngineStartupArgs,
>,
>,
resources: DataState<ResourceRegistry>,
closing: bool,
}
impl<CustomEvents: MatrixEventable> SceneManager<CustomEvents> {
pub fn new(
runtime: Box<
dyn Runtime<SceneRegistryRefs<CustomEvents>, SendEngineArgs, NonSendEngineArgs>,
>,
startup_runtime: Box<
dyn Runtime<
SceneRegistryRefs<CustomEvents>,
SendEngineStartupArgs,
NonSendEngineStartupArgs,
>,
>,
proxy: EventLoopProxy<MatrixEvent<CustomEvents>>,
) -> Self {
Self {
current_scene: Scene::new(proxy),
runtime,
startup_runtime,
resources: DataState::default(),
closing: false,
}
}
pub(crate) fn add_plugin(&mut self, new: impl Plugin<CustomEvents> + 'static) {
self.current_scene.plugins.push_back(Box::new(new));
}
}
impl<CustomEvents: MatrixEventable> ApplicationHandler<MatrixEvent<CustomEvents>>
for SceneManager<CustomEvents>
{
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
while let Some(plugin) = self.current_scene.plugins.pop_back() {
plugin.build(&mut self.current_scene);
}
let mut reg = SceneRegistryRefs {
components: self
.current_scene
.components
.write()
.expect("this should be available"),
events: self
.current_scene
.events
.write()
.expect("this should be available"),
resources: self.resources.write().expect("this should be available"),
};
self.startup_runtime.run(
&mut self.current_scene.startup_systems,
&mut reg,
SendEngineStartupArgs,
NonSendEngineStartupArgs {
event_loop: ActiveEventLoopRef::new(event_loop),
},
);
self.current_scene
.components
.consume_write(reg.components)
.unwrap();
self.current_scene.events.consume_write(reg.events).unwrap();
self.resources.consume_write(reg.resources).unwrap();
}
fn window_event(
&mut self,
event_loop: &winit::event_loop::ActiveEventLoop,
_window_id: winit::window::WindowId,
event: winit::event::WindowEvent,
) {
self.current_scene
.events
.get_mut()
.expect("this should not be accessed now")
.events()
.get_mut()
.expect("this should not be accessed now")
.handle_window_event(&event);
if event == winit::event::WindowEvent::RedrawRequested {
let mut reg = SceneRegistryRefs {
components: self
.current_scene
.components
.write()
.expect("this should be available"),
events: self
.current_scene
.events
.write()
.expect("this should be available"),
resources: self.resources.write().expect("this should be available"),
};
self.runtime.run(
&mut self.current_scene.systems,
&mut reg,
SendEngineArgs,
NonSendEngineArgs,
);
self.current_scene
.components
.consume_write(reg.components)
.unwrap();
self.current_scene.events.consume_write(reg.events).unwrap();
self.resources.consume_write(reg.resources).unwrap();
if self.closing {
event_loop.exit();
}
self.current_scene
.events
.get_mut()
.expect("this should not be accessed now")
.events()
.get_mut()
.expect("this should not be accessed now")
.reset();
}
}
fn user_event(&mut self, _event_loop: &ActiveEventLoop, event: MatrixEvent<CustomEvents>) {
match event {
MatrixEvent::Exit => {
self.closing = true;
}
MatrixEvent::DestroySystem(id) => {
self.current_scene.destroy_system(id);
}
_ => (),
}
self.current_scene
.events
.get_mut()
.expect("this should not be accessed now")
.events()
.get_mut()
.expect("this should not be accessed now")
.handle_matrix_event(event.clone());
}
fn device_event(
&mut self,
_event_loop: &ActiveEventLoop,
_device_id: winit::event::DeviceId,
event: winit::event::DeviceEvent,
) {
self.current_scene
.events
.get_mut()
.expect("this should not be accessed now")
.events()
.get_mut()
.expect("this should not be accessed now")
.handle_device_event(event)
}
}