Use resources from the resource manager, implement startup systems

This commit is contained in:
SeanOMik 2023-09-14 12:58:59 -04:00
parent a1c3cd6d99
commit bd21e62cba
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
11 changed files with 103 additions and 64 deletions

6
Cargo.lock generated
View File

@ -1716,12 +1716,12 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
[[package]] [[package]]
name = "petgraph" name = "petgraph"
version = "0.6.3" version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [ dependencies = [
"fixedbitset", "fixedbitset",
"indexmap 1.9.3", "indexmap 2.0.0",
] ]
[[package]] [[package]]

View File

@ -27,7 +27,6 @@ tobj = { version = "3.2.1", features = [
instant = "0.1" instant = "0.1"
async-trait = "0.1.65" async-trait = "0.1.65"
glam = { version = "0.24.0", features = ["bytemuck"] } glam = { version = "0.24.0", features = ["bytemuck"] }
petgraph = "0.6.3"
gilrs-core = "0.5.6" gilrs-core = "0.5.6"
syn = "2.0.26" syn = "2.0.26"
quote = "1.0.29" quote = "1.0.29"
@ -36,3 +35,4 @@ atomicell = "0.1.9"
aligned-vec = "0.5.0" aligned-vec = "0.5.0"
tracing-appender = "0.2.2" tracing-appender = "0.2.2"
stopwatch = "0.0.7" stopwatch = "0.0.7"
petgraph = "0.6.4"

View File

@ -28,7 +28,7 @@ impl From<io::Error> for LoaderError {
} }
} }
pub trait ResourceLoader { pub trait ResourceLoader: Send + Sync {
fn extensions(&self) -> &[&str]; fn extensions(&self) -> &[&str];
fn does_support_file(&self, path: &str) -> bool; fn does_support_file(&self, path: &str) -> bool;
fn load(&self, path: &str) -> Result<Arc<dyn ResourceStorage>, LoaderError>; fn load(&self, path: &str) -> Result<Arc<dyn ResourceStorage>, LoaderError>;

View File

@ -1,31 +1,29 @@
use std::collections::HashMap;
use petgraph::{prelude::StableDiGraph, stable_graph::NodeIndex, visit::Topo};
use tracing::warn;
use crate::game::Controls;
pub use edict::*; pub use edict::*;
pub mod components; pub mod components;
pub mod events; pub mod events;
pub use events::*; pub use events::*;
use std::collections::HashMap;
use petgraph::{stable_graph::{StableDiGraph, NodeIndex}, visit::Topo};
use tracing::warn;
/// A trait that represents a simple system /// A trait that represents a simple system
pub trait SimpleSystem { pub trait SimpleSystem {
fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> { fn setup(&mut self, world: &mut World) -> anyhow::Result<()> {
Ok(()) Ok(())
} }
// todo: make async? // todo: make async?
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()>; fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()>;
} }
impl<S> SimpleSystem for S impl<S> SimpleSystem for S
where S: FnMut(&mut edict::World) -> anyhow::Result<()> where S: FnMut(&mut edict::World) -> anyhow::Result<()>
{ {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
self(controls.world) self(world)
} }
} }
@ -44,9 +42,9 @@ impl BatchedSystem {
} }
impl SimpleSystem for BatchedSystem { impl SimpleSystem for BatchedSystem {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
for system in self.systems.iter_mut() { for system in self.systems.iter_mut() {
system.execute_mut(controls)?; system.execute_mut(world)?;
} }
Ok(()) Ok(())
@ -122,13 +120,13 @@ impl SystemDispatcher {
true true
} }
pub(crate) fn execute_systems(&mut self, controls: &mut Controls) { pub(crate) fn execute_systems(&mut self, world: &mut World) {
let mut topo = Topo::new(&self.graph); let mut topo = Topo::new(&self.graph);
while let Some(nx) = topo.next(&self.graph) { while let Some(nx) = topo.next(&self.graph) {
let node = self.graph.node_weight_mut(nx).unwrap(); let node = self.graph.node_weight_mut(nx).unwrap();
match node.system.execute_mut(controls) { match node.system.execute_mut(world) {
Ok(()) => {}, Ok(()) => {},
Err(e) => { Err(e) => {
warn!("System execution of {} resulted in an error! '{}'.", node.name, e); warn!("System execution of {} resulted in an error! '{}'.", node.name, e);
@ -144,8 +142,8 @@ impl SystemDispatcher {
} }
impl SimpleSystem for SystemDispatcher { impl SimpleSystem for SystemDispatcher {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> { fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
self.execute_systems(controls); self.execute_systems(world);
Ok(()) Ok(())
} }

View File

@ -68,15 +68,11 @@ impl GameLoop {
} }
async fn update(&mut self) { async fn update(&mut self) {
let mut controls = Controls { if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut self.world) {
world: &mut self.world,
};
if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut controls) {
error!("Error when executing engine ecs systems: '{}'", e); error!("Error when executing engine ecs systems: '{}'", e);
} }
if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut controls) { if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut self.world) {
error!("Error when executing user ecs systems: '{}'", e); error!("Error when executing user ecs systems: '{}'", e);
} }
} }
@ -224,9 +220,10 @@ impl GameLoop {
} }
pub struct Game { pub struct Game {
pub world: Option<edict::World>, world: Option<edict::World>,
plugins: VecDeque<Box<dyn Plugin>>, plugins: VecDeque<Box<dyn Plugin>>,
system_dispatcher: Option<SystemDispatcher>, system_dispatcher: Option<SystemDispatcher>,
startup_systems: VecDeque<Box<dyn SimpleSystem>>,
} }
impl Default for Game { impl Default for Game {
@ -235,6 +232,7 @@ impl Default for Game {
world: Some(edict::World::new()), world: Some(edict::World::new()),
plugins: VecDeque::new(), plugins: VecDeque::new(),
system_dispatcher: Some(SystemDispatcher::new()), system_dispatcher: Some(SystemDispatcher::new()),
startup_systems: VecDeque::new(),
} }
} }
} }
@ -244,6 +242,13 @@ impl Game {
Self::default() Self::default()
} }
/// Get the world of this game
pub fn world(&mut self) -> &mut edict::World {
// world is always `Some`, so unwrapping is safe
self.world.as_mut().unwrap()
}
/// Add a system to the ecs world
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
@ -254,7 +259,18 @@ impl Game {
self self
} }
/// Add a plugin to the game /// Add a startup system that will be ran right after plugins are setup.
/// They will only be ran once
pub fn with_startup_system<S>(&mut self, system: S) -> &mut Self
where
S: SimpleSystem + 'static
{
self.startup_systems.push_back(Box::new(system));
self
}
/// Add a plugin to the game. These will be executed before the window is initiated and opened
pub fn with_plugin<P>(&mut self, plugin: P) -> &mut Self pub fn with_plugin<P>(&mut self, plugin: P) -> &mut Self
where where
P: Plugin + 'static P: Plugin + 'static
@ -264,12 +280,16 @@ impl Game {
self self
} }
/// Override the default (empty) world
///
/// This isn't recommended, you should create a startup system and add it to `with_startup_system`
pub fn with_world(&mut self, world: edict::World) -> &mut Self { pub fn with_world(&mut self, world: edict::World) -> &mut Self {
self.world = Some(world); self.world = Some(world);
self self
} }
/// Start the game
pub async fn run(&mut self) { pub async fn run(&mut self) {
// init logging // init logging
let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout()); let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout());
@ -286,11 +306,19 @@ impl Game {
plugin.as_ref().setup(self); plugin.as_ref().setup(self);
} }
let mut world = self.world.take().unwrap_or_else(|| edict::World::new());
// run startup systems
while let Some(mut startup) = self.startup_systems.pop_front() {
let startup = startup.as_mut();
startup.setup(&mut world).expect("World returned an error!");
startup.execute_mut(&mut world).expect("World returned an error!");
}
// start winit event loops // 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 world = self.world.take().unwrap_or_else(|| edict::World::new());
let system_dispatcher = self.system_dispatcher.take().unwrap(); let system_dispatcher = self.system_dispatcher.take().unwrap();
let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await; let mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await;
g_loop.on_init().await; g_loop.on_init().await;

View File

@ -313,9 +313,7 @@ impl InputSystem {
} }
impl SimpleSystem for InputSystem { impl SimpleSystem for InputSystem {
fn execute_mut(&mut self, controls: &mut crate::game::Controls) -> anyhow::Result<()> { fn execute_mut(&mut self, world: &mut edict::World) -> anyhow::Result<()> {
let world = &mut controls.world;
let queue = world.get_resource_mut::<EventQueue>() let queue = world.get_resource_mut::<EventQueue>()
.map(|q| q.read_events::<InputEvent>()).flatten(); .map(|q| q.read_events::<InputEvent>()).flatten();

View File

@ -8,17 +8,6 @@ pub mod input;
pub mod castable_any; pub mod castable_any;
pub mod plugin; pub mod plugin;
use plugin::Plugin; pub use lyra_resource as assets;
use crate::input::InputPlugin; pub use plugin::DefaultPlugins;
/// Default plugins of Lyra. Make sure to have these added to the Game first
#[derive(Default)]
pub struct DefaultPlugins;
impl Plugin for DefaultPlugins {
fn setup(&self, game: &mut game::Game) {
// setup input
InputPlugin::default().setup(game);
}
}

View File

@ -1,4 +1,7 @@
use lyra_resource::ResourceManager;
use crate::game::Game; use crate::game::Game;
use crate::input::InputPlugin;
/// A Plugin is something you can add to a `Game` that can be used to define systems, or spawn initial entities. /// A Plugin is something you can add to a `Game` that can be used to define systems, or spawn initial entities.
pub trait Plugin { pub trait Plugin {
@ -74,3 +77,24 @@ impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6)
impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) } impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) }
impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) } impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) }
impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) (C14, 14) } impl_tuple_plugin_set! { (C0, 0) (C1, 1) (C2, 2) (C3, 3) (C4, 4) (C5, 5) (C6, 6) (C7, 7) (C8, 8) (C9, 9) (C10, 10) (C11, 11) (C12, 12) (C13, 13) (C14, 14) }
#[derive(Default)]
pub struct ResourceManagerPlugin;
impl Plugin for ResourceManagerPlugin {
fn setup(&self, game: &mut Game) {
game.world().insert_resource(ResourceManager::new());
}
}
/// Default plugins of Lyra. Make sure to have these added to the Game first
#[derive(Default)]
pub struct DefaultPlugins;
impl Plugin for DefaultPlugins {
fn setup(&self, game: &mut Game) {
// setup input
InputPlugin::default().setup(game);
ResourceManagerPlugin::default().setup(game);
}
}

View File

@ -1,7 +1,9 @@
use super::texture::Texture; use std::sync::Arc;
use lyra_resource::{Texture, Resource};
#[derive(Clone)] #[derive(Clone)]
pub struct Material { pub struct Material {
pub shader_id: u32, pub shader_id: u32,
pub texture: Texture, pub texture: Arc<Resource<Texture>>,
} }

View File

@ -462,8 +462,9 @@ impl BasicRenderer {
let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh); let (vertex_buffer, buffer_indices) = self.create_vertex_index_buffers(mesh);
let texture_img = &model.material.texture; let model_texture = &model.material.texture;
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, &texture_img.img, 0, None).unwrap(); let image = &model_texture.data.as_ref().unwrap().image;
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, image, None).unwrap();
let texture_bind_group_layout = let texture_bind_group_layout =
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {

View File

@ -1,8 +1,9 @@
use std::sync::Arc; use std::sync::Arc;
use image::GenericImageView; use image::GenericImageView;
use lyra_resource::{Resource, Texture};
#[derive(Clone)] /* #[derive(Clone)]
pub struct Texture { pub struct Texture {
texture_id: u32, texture_id: u32,
pub img: image::DynamicImage, pub img: image::DynamicImage,
@ -17,14 +18,13 @@ impl Texture {
img, img,
}) })
} }
} } */
#[derive(Clone)] #[derive(Clone)]
#[allow(dead_code)] #[allow(dead_code)]
pub struct RenderTexture { pub struct RenderTexture {
texture_id: u32,
texture: Arc<wgpu::Texture>, texture: Arc<wgpu::Texture>,
view: Arc<wgpu::TextureView>, view: Arc<wgpu::TextureView>,
sampler: Arc<wgpu::Sampler>, sampler: Arc<wgpu::Sampler>,
@ -33,12 +33,12 @@ pub struct RenderTexture {
impl RenderTexture { impl RenderTexture {
pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float;
pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], texture_id: u32, label: &str) -> anyhow::Result<Self> { pub fn from_bytes(device: &wgpu::Device, queue: &wgpu::Queue, bytes: &[u8], label: &str) -> anyhow::Result<Self> {
let img = image::load_from_memory(bytes)?; let img = image::load_from_memory(bytes)?;
Self::from_image(device, queue, &img, texture_id, Some(label)) Self::from_image(device, queue, &img, Some(label))
} }
pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, texture_id: u32, label: Option<&str>) -> anyhow::Result<Self> { pub fn from_image(device: &wgpu::Device, queue: &wgpu::Queue, img: &image::DynamicImage, label: Option<&str>) -> anyhow::Result<Self> {
let rgba = img.to_rgba8(); let rgba = img.to_rgba8();
let dimensions = img.dimensions(); let dimensions = img.dimensions();
@ -90,16 +90,16 @@ impl RenderTexture {
); );
Ok(Self { Ok(Self {
texture_id,
texture: Arc::new(texture), texture: Arc::new(texture),
view: Arc::new(view), view: Arc::new(view),
sampler: Arc::new(sampler), sampler: Arc::new(sampler),
}) })
} }
pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Texture) { pub fn update_texture(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, texture: &Arc<Resource<Texture>>) {
let rgba = texture.img.to_rgba8(); let texture = &texture.data.as_ref().unwrap().image;
let dimensions = texture.img.dimensions(); let rgba = texture.to_rgba8();
let dimensions = texture.dimensions();
let size = wgpu::Extent3d { let size = wgpu::Extent3d {
width: dimensions.0, width: dimensions.0,
height: dimensions.1, height: dimensions.1,
@ -162,7 +162,6 @@ impl RenderTexture {
texture: Arc::new(texture), texture: Arc::new(texture),
view: Arc::new(view), view: Arc::new(view),
sampler: Arc::new(sampler), sampler: Arc::new(sampler),
texture_id: 0
} }
} }