Start working on game plugins

This commit is contained in:
SeanOMik 2023-09-09 10:51:58 -04:00
parent 31e6af7015
commit e96cb3585b
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
5 changed files with 86 additions and 105 deletions

3
src/app.rs Normal file
View File

@ -0,0 +1,3 @@
pub struct App {
}

View File

@ -1,4 +1,4 @@
use std::sync::Arc; use std::{sync::Arc, collections::VecDeque};
use async_std::{task::block_on, sync::Mutex}; use async_std::{task::block_on, sync::Mutex};
@ -14,7 +14,7 @@ use tracing_subscriber::{
use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}}; use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}};
use crate::{render::renderer::{Renderer, BasicRenderer}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, input::InputSystem}; use crate::{render::renderer::{Renderer, BasicRenderer}, input_event::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, input::InputSystem, plugin::Plugin};
pub struct Controls<'a> { pub struct Controls<'a> {
pub world: &'a mut edict::World, pub world: &'a mut edict::World,
@ -36,14 +36,14 @@ struct GameLoop {
window: Arc<Window>, window: Arc<Window>,
renderer: Box<dyn Renderer>, renderer: Box<dyn Renderer>,
world: Arc<Mutex<edict::World>>, world: edict::World,
/// higher priority systems /// higher priority systems
engine_sys_dispatcher: SystemDispatcher, engine_sys_dispatcher: SystemDispatcher,
user_sys_dispatcher: SystemDispatcher, user_sys_dispatcher: SystemDispatcher,
} }
impl GameLoop { impl GameLoop {
pub async fn new(window: Arc<Window>, world: Arc<Mutex<edict::World>>, user_systems: SystemDispatcher) -> GameLoop { pub async fn new(window: Arc<Window>, world: edict::World, user_systems: SystemDispatcher) -> GameLoop {
Self { Self {
window: Arc::clone(&window), window: Arc::clone(&window),
renderer: Box::new(BasicRenderer::create_with_window(window).await), renderer: Box::new(BasicRenderer::create_with_window(window).await),
@ -60,8 +60,7 @@ impl GameLoop {
pub async fn on_init(&mut self) { pub async fn on_init(&mut self) {
// Create the EventQueue resource in the world // Create the EventQueue resource in the world
let mut world = self.world.lock().await; self.world.insert_resource(EventQueue::new());
world.insert_resource(EventQueue::new());
} }
pub fn run_sync(&mut self, event: Event<()>, control_flow: &mut ControlFlow) { pub fn run_sync(&mut self, event: Event<()>, control_flow: &mut ControlFlow) {
@ -69,10 +68,8 @@ impl GameLoop {
} }
async fn update(&mut self) { async fn update(&mut self) {
let mut world = self.world.lock().await;
let mut controls = Controls { let mut controls = Controls {
world: &mut world, world: &mut self.world,
}; };
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) { if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) {
@ -102,18 +99,14 @@ impl GameLoop {
// TODO: Create system for this? or maybe merge into input system, idk // TODO: Create system for this? or maybe merge into input system, idk
InputEvent::CursorEntered { .. } => { InputEvent::CursorEntered { .. } => {
let mut world = self.world.lock().await; let mut state = self.world.with_resource(|| WindowState::new());
let mut state = world.with_resource(|| WindowState::new());
state.is_cursor_inside_window = true; state.is_cursor_inside_window = true;
None None
}, },
InputEvent::CursorLeft { .. } => { InputEvent::CursorLeft { .. } => {
let mut world = self.world.lock().await; let mut state = self.world.with_resource(|| WindowState::new());
let mut state = world.with_resource(|| WindowState::new());
state.is_cursor_inside_window = false; state.is_cursor_inside_window = false;
None None
@ -127,14 +120,6 @@ impl GameLoop {
} }
} }
fn render_window() {
todo!()
}
fn render_item() {
todo!()
}
fn on_exit(&mut self) { fn on_exit(&mut self) {
info!("On exit!"); info!("On exit!");
} }
@ -145,16 +130,14 @@ impl GameLoop {
Event::DeviceEvent { device_id, event } => match event { Event::DeviceEvent { device_id, event } => match event {
// convert a MouseMotion event to an InputEvent // convert a MouseMotion event to an InputEvent
DeviceEvent::MouseMotion { delta } => { DeviceEvent::MouseMotion { delta } => {
let mut world = self.world.lock().await;
// make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion // make sure that the mouse is inside the window and the mouse has focus before reporting mouse motion
let trigger = match world.get_resource::<WindowState>() { let trigger = match self.world.get_resource::<WindowState>() {
Some(window_state) if window_state.is_focused && window_state.is_cursor_inside_window => true, Some(window_state) if window_state.is_focused && window_state.is_cursor_inside_window => true,
_ => false, _ => false,
}; };
if trigger { if trigger {
let event_queue = world.with_resource(|| Events::<InputEvent>::new()); let event_queue = self.world.with_resource(|| Events::<InputEvent>::new());
let input_event = InputEvent::MouseMotion { device_id, delta, }; let input_event = InputEvent::MouseMotion { device_id, delta, };
event_queue.push_back(input_event); event_queue.push_back(input_event);
@ -173,8 +156,7 @@ impl GameLoop {
// Its possible to receive multiple input events before the update event for // Its possible to receive multiple input events before the update event for
// the InputSystem is called, so we must use a queue for the events. // the InputSystem is called, so we must use a queue for the events.
{ {
let world = self.world.lock().await; if let Some(mut event_queue) = self.world.get_resource_mut::<EventQueue>() {
if let Some(mut event_queue) = world.get_resource_mut::<EventQueue>() {
event_queue.trigger_event(input_event.clone()); event_queue.trigger_event(input_event.clone());
}; };
} }
@ -199,9 +181,7 @@ impl GameLoop {
}, },
WindowEvent::Focused(is_focused) => { WindowEvent::Focused(is_focused) => {
let mut world = self.world.lock().await; let mut state = self.world.with_resource(|| WindowState::new());
let mut state = world.with_resource(|| WindowState::new());
state.is_focused = *is_focused; state.is_focused = *is_focused;
}, },
@ -219,12 +199,10 @@ impl GameLoop {
debug!("FPS: {}fps, {:.2}ms/frame", fps, self.fps_counter.get_tick_time()); debug!("FPS: {}fps, {:.2}ms/frame", fps, self.fps_counter.get_tick_time());
} */ } */
let mut world = self.world.lock().await; self.renderer.as_mut().prepare(&mut self.world);
self.renderer.as_mut().prepare(&mut world); if let Some(mut event_queue) = self.world.get_resource_mut::<EventQueue>() {
if let Some(mut event_queue) = world.get_resource_mut::<EventQueue>() {
event_queue.update_events(); event_queue.update_events();
} }
drop(world);
match self.renderer.as_mut().render() { match self.renderer.as_mut().render() {
Ok(_) => {} Ok(_) => {}
@ -246,14 +224,16 @@ impl GameLoop {
} }
pub struct Game { pub struct Game {
world: Option<Arc<Mutex<edict::World>>>, pub world: Option<edict::World>,
plugins: VecDeque<Box<dyn Plugin>>,
system_dispatcher: Option<SystemDispatcher>, system_dispatcher: Option<SystemDispatcher>,
} }
impl Default for Game { impl Default for Game {
fn default() -> Self { fn default() -> Self {
Self { Self {
world: None, world: Some(edict::World::new()),
plugins: VecDeque::new(),
system_dispatcher: Some(SystemDispatcher::new()), system_dispatcher: Some(SystemDispatcher::new()),
} }
} }
@ -261,55 +241,33 @@ impl Default for Game {
impl Game { impl Game {
pub async fn initialize() -> Game { pub async fn initialize() -> Game {
/* let filter = FilterFn::new(|metadata| {
metadata.module_path()
.unwrap_or_else(|| metadata.target())
.starts_with("lyra_engine") && (LevelFilter::DEBUG >= metadata.level().to_owned())
});
let layer = tracing_subscriber::fmt::layer();
tracing_subscriber::registry()
.with(layer.with_filter(filter))
.init(); */
/* tracing_subscriber::registry()
.with(fmt::layer().with_writer(stdout_layer))
.with(filter::Targets::new()
.with_target("lyra_engine", Level::TRACE)
.with_default(Level::DEBUG))
.init(); */
/* tracing_subscriber::fmt()
.with_max_level(Level::DEBUG)
.init(); */
info!("dheiudfgbwehifwe");
let mut def = Self::default(); let mut def = Self::default();
def.system_dispatcher.as_mut().unwrap().add_system("input", InputSystem::new(), &[]); //def.system_dispatcher.add_system("input", InputSystem::new(), &[]);
def def
} }
pub fn with_world(&mut self, world: edict::World) -> &mut Self {
self.world = Some(Arc::new(Mutex::new(world)));
self
}
pub fn with_world_arc(&mut self, world: Arc<Mutex<edict::World>>) -> &mut Self {
self.world = Some(world);
self
}
pub fn with_system<S>(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self pub fn with_system<S>(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self
where where
S: SimpleSystem + 'static S: SimpleSystem + 'static
{ {
let dispatcher = self.system_dispatcher.as_mut().unwrap(); let system_dispatcher = self.system_dispatcher.as_mut().unwrap();
dispatcher.add_system(name, system, depends); system_dispatcher.add_system(name, system, depends);
self
}
/// Add a plugin to the game
pub fn with_plugin<P>(&mut self, plugin: P) -> &mut Self
where
P: Plugin + 'static
{
self.plugins.push_back(Box::new(plugin));
self
}
pub fn with_world(&mut self, world: edict::World) -> &mut Self {
self.world = Some(world);
self self
} }
@ -323,16 +281,19 @@ impl Game {
.with_target("lyra_engine", Level::TRACE) .with_target("lyra_engine", Level::TRACE)
.with_default(Level::INFO)) .with_default(Level::INFO))
.init(); .init();
let world = self.world.take().expect("ECS World was never given to Game!");
// setup all the plugins
while let Some(plugin) = self.plugins.pop_front() {
plugin.as_ref().setup(self);
}
// start winit event loops
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap()); let window = Arc::new(WindowBuilder::new().build(&event_loop).unwrap());
let systems = self.system_dispatcher.take().unwrap(); let world = self.world.take().unwrap_or_else(|| edict::World::new());
let system_dispatcher = self.system_dispatcher.take().unwrap();
let mut g_loop = GameLoop::new(Arc::clone(&window), world, systems).await; let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await;
g_loop.on_init().await; g_loop.on_init().await;
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {

View File

@ -5,7 +5,7 @@ use glam::Vec2;
use tracing::{warn, debug}; use tracing::{warn, debug};
use winit::event::{ElementState, MouseScrollDelta}; use winit::event::{ElementState, MouseScrollDelta};
use crate::{ecs::{SimpleSystem, EventQueue}, input_event::InputEvent}; use crate::{ecs::{SimpleSystem, EventQueue}, input_event::InputEvent, plugin::Plugin};
pub type KeyCode = winit::event::VirtualKeyCode; pub type KeyCode = winit::event::VirtualKeyCode;
@ -84,8 +84,6 @@ impl From<winit::event::Force> for Force {
} }
} }
///
///
/// Translated `WindowEvent::Touch` from `winit` crate /// Translated `WindowEvent::Touch` from `winit` crate
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Touch { pub struct Touch {
@ -206,22 +204,6 @@ trait InputStorage {
impl<T: Clone + Hash + Eq + PartialEq + 'static> InputStorage for InputButtons<T> { impl<T: Clone + Hash + Eq + PartialEq + 'static> InputStorage for InputButtons<T> {
fn update_just_pressed(&mut self) { fn update_just_pressed(&mut self) {
/* for (hash, button) in self.button_events.iter_mut() {
/* if let ButtonEvent::JustPressed(b) = button {
*button = ButtonEvent::Pressed(b.clone());
} */
match button {
ButtonEvent::Pressed(_) => todo!(),
ButtonEvent::Released(b) => {
return false;
},
ButtonEvent::JustPressed(b) => {
*button = ButtonEvent::Pressed(b.clone());
},
}
} */
self.button_events.retain(|_hash, button| { self.button_events.retain(|_hash, button| {
match button { match button {
// remove released, no need to keep those around. // remove released, no need to keep those around.
@ -365,4 +347,30 @@ impl SimpleSystem for InputSystem {
Ok(()) Ok(())
} }
}
fn input_system_fn(world: &mut edict::World) -> anyhow::Result<()> {
//let world = &mut controls.world;
let queue = world.get_resource_mut::<EventQueue>()
.map(|q| q.read_events::<InputEvent>()).flatten();
if queue.is_none() {
return Ok(());
}
let mut events = queue.unwrap();
let mut input = InputSystem::new();
while let Some(event) = events.pop_front() {
input.update(&event, world);
}
Ok(())
}
impl Plugin for InputSystem {
fn setup(&self, game: &mut crate::game::Game) {
game.with_system("input", input_system_fn, &[]);
}
} }

View File

@ -5,4 +5,6 @@ pub mod resources;
pub mod ecs; pub mod ecs;
pub mod math; pub mod math;
pub mod input; pub mod input;
pub mod castable_any; pub mod castable_any;
pub mod plugin;
pub mod app;

7
src/plugin.rs Normal file
View File

@ -0,0 +1,7 @@
use crate::game::Game;
pub trait Plugin {
/// Setup this plugin. This runs before the game has started
fn setup(&self, game: &mut Game);
}