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]]
name = "petgraph"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
dependencies = [
"fixedbitset",
"indexmap 1.9.3",
"indexmap 2.0.0",
]
[[package]]

View File

@ -27,7 +27,6 @@ tobj = { version = "3.2.1", features = [
instant = "0.1"
async-trait = "0.1.65"
glam = { version = "0.24.0", features = ["bytemuck"] }
petgraph = "0.6.3"
gilrs-core = "0.5.6"
syn = "2.0.26"
quote = "1.0.29"
@ -36,3 +35,4 @@ atomicell = "0.1.9"
aligned-vec = "0.5.0"
tracing-appender = "0.2.2"
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 does_support_file(&self, path: &str) -> bool;
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 mod components;
pub mod 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
pub trait SimpleSystem {
fn setup(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
fn setup(&mut self, world: &mut World) -> anyhow::Result<()> {
Ok(())
}
// 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
where S: FnMut(&mut edict::World) -> anyhow::Result<()>
{
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
self(controls.world)
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
self(world)
}
}
@ -44,9 +42,9 @@ impl 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() {
system.execute_mut(controls)?;
system.execute_mut(world)?;
}
Ok(())
@ -122,13 +120,13 @@ impl SystemDispatcher {
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);
while let Some(nx) = topo.next(&self.graph) {
let node = self.graph.node_weight_mut(nx).unwrap();
match node.system.execute_mut(controls) {
match node.system.execute_mut(world) {
Ok(()) => {},
Err(e) => {
warn!("System execution of {} resulted in an error! '{}'.", node.name, e);
@ -144,8 +142,8 @@ impl SystemDispatcher {
}
impl SimpleSystem for SystemDispatcher {
fn execute_mut(&mut self, controls: &mut Controls) -> anyhow::Result<()> {
self.execute_systems(controls);
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
self.execute_systems(world);
Ok(())
}

View File

@ -68,15 +68,11 @@ impl GameLoop {
}
async fn update(&mut self) {
let mut controls = Controls {
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 self.world) {
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);
}
}
@ -224,9 +220,10 @@ impl GameLoop {
}
pub struct Game {
pub world: Option<edict::World>,
world: Option<edict::World>,
plugins: VecDeque<Box<dyn Plugin>>,
system_dispatcher: Option<SystemDispatcher>,
startup_systems: VecDeque<Box<dyn SimpleSystem>>,
}
impl Default for Game {
@ -235,6 +232,7 @@ impl Default for Game {
world: Some(edict::World::new()),
plugins: VecDeque::new(),
system_dispatcher: Some(SystemDispatcher::new()),
startup_systems: VecDeque::new(),
}
}
}
@ -244,6 +242,13 @@ impl Game {
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
where
S: SimpleSystem + 'static
@ -254,7 +259,18 @@ impl Game {
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
where
P: Plugin + 'static
@ -264,12 +280,16 @@ impl Game {
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 {
self.world = Some(world);
self
}
/// Start the game
pub async fn run(&mut self) {
// init logging
let (stdout_layer, _stdout_nb) = non_blocking(std::io::stdout());
@ -286,11 +306,19 @@ impl Game {
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
let event_loop = EventLoop::new();
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 mut g_loop = GameLoop::new(Arc::clone(&window), world, system_dispatcher).await;
g_loop.on_init().await;

View File

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

View File

@ -8,17 +8,6 @@ pub mod input;
pub mod castable_any;
pub mod plugin;
use plugin::Plugin;
pub use lyra_resource as assets;
use crate::input::InputPlugin;
/// 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);
}
}
pub use plugin::DefaultPlugins;

View File

@ -1,4 +1,7 @@
use lyra_resource::ResourceManager;
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.
pub trait Plugin {
@ -73,4 +76,25 @@ 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) }
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) (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)]
pub struct Material {
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 texture_img = &model.material.texture;
let diffuse_texture = RenderTexture::from_image(&self.device, &self.queue, &texture_img.img, 0, None).unwrap();
let model_texture = &model.material.texture;
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 =
self.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {

View File

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