From 09bba5b3b3d436630308114f0604be793d70964f Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Tue, 26 Dec 2023 23:48:46 -0500 Subject: [PATCH] Switch to lyra-ecs systems, move ecs mod to scene mod, reexport lyra-ecs as ecs --- Cargo.lock | 1 - examples/testbed/Cargo.toml | 2 +- examples/testbed/src/free_fly_camera.rs | 17 ++- examples/testbed/src/main.rs | 11 +- lyra-ecs/lyra-ecs-derive/src/lib.rs | 7 +- lyra-ecs/src/lib.rs | 26 ++-- lyra-ecs/src/query/borrow.rs | 2 +- lyra-ecs/src/query/dynamic/mod.rs | 4 +- lyra-ecs/src/query/dynamic/view.rs | 4 +- lyra-ecs/src/query/entities.rs | 4 +- lyra-ecs/src/query/resource.rs | 2 +- lyra-ecs/src/query/tick.rs | 4 +- {src/ecs => lyra-ecs/src}/system/batched.rs | 24 +++- {src/ecs => lyra-ecs/src}/system/criteria.rs | 10 +- lyra-ecs/src/system/graph.rs | 13 +- lyra-ecs/src/system/mod.rs | 64 ++++++++- lyra-ecs/src/tests.rs | 12 +- lyra-ecs/src/world.rs | 4 +- src/{ecs/components => }/delta_time.rs | 4 +- src/ecs/mod.rs | 9 -- src/ecs/system/mod.rs | 127 ------------------ src/{ecs => }/events.rs | 0 src/game.rs | 36 ++--- src/input/action.rs | 4 +- src/input/system.rs | 13 +- src/lib.rs | 12 +- src/plugin.rs | 4 +- src/render/camera.rs | 2 +- src/render/light/mod.rs | 4 +- src/render/renderer.rs | 7 +- src/render/window.rs | 6 +- src/{ecs/components => scene}/camera.rs | 0 .../components => scene}/free_fly_camera.rs | 0 src/{ecs/components => scene}/mesh.rs | 0 src/{ecs/components => scene}/mod.rs | 5 +- src/{ecs/components => scene}/model.rs | 0 src/{ecs/components => scene}/transform.rs | 0 37 files changed, 208 insertions(+), 236 deletions(-) rename {src/ecs => lyra-ecs/src}/system/batched.rs (77%) rename {src/ecs => lyra-ecs/src}/system/criteria.rs (55%) rename src/{ecs/components => }/delta_time.rs (85%) delete mode 100755 src/ecs/mod.rs delete mode 100644 src/ecs/system/mod.rs rename src/{ecs => }/events.rs (100%) rename src/{ecs/components => scene}/camera.rs (100%) rename src/{ecs/components => scene}/free_fly_camera.rs (100%) rename src/{ecs/components => scene}/mesh.rs (100%) rename src/{ecs/components => scene}/mod.rs (70%) mode change 100755 => 100644 rename src/{ecs/components => scene}/model.rs (100%) rename src/{ecs/components => scene}/transform.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index e3db98e..ca6c410 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -2335,7 +2335,6 @@ dependencies = [ "anyhow", "async-std", "fps_counter", - "lyra-ecs", "lyra-engine", "tracing", ] diff --git a/examples/testbed/Cargo.toml b/examples/testbed/Cargo.toml index c840c2c..54a8a77 100644 --- a/examples/testbed/Cargo.toml +++ b/examples/testbed/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] lyra-engine = { path = "../../", version = "0.0.1" } -lyra-ecs = { path = "../../lyra-ecs"} +#lyra-ecs = { path = "../../lyra-ecs"} anyhow = "1.0.75" async-std = "1.12.0" tracing = "0.1.37" diff --git a/examples/testbed/src/free_fly_camera.rs b/examples/testbed/src/free_fly_camera.rs index e3de9d1..aa3dc4f 100644 --- a/examples/testbed/src/free_fly_camera.rs +++ b/examples/testbed/src/free_fly_camera.rs @@ -1,12 +1,10 @@ -use std::ops::Deref; +use std::{ops::Deref, ptr::NonNull}; -use lyra_ecs::{Component, world::World}; use lyra_engine::{ - ecs::{components::{camera::CameraComponent, DeltaTime}, EventQueue, SimpleSystem}, game::Game, input::{InputButtons, KeyCode, MouseMotion}, math::{Quat, Vec3, EulerRot}, - plugin::Plugin, + plugin::Plugin, ecs::{system::System, world::World, Access, Component}, DeltaTime, EventQueue, scene::CameraComponent, }; #[derive(Clone, Component)] @@ -44,14 +42,15 @@ impl FreeFlyCamera { pub struct FreeFlyCameraPlugin; -impl SimpleSystem for FreeFlyCameraPlugin { - fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { +impl System for FreeFlyCameraPlugin { + fn execute(&mut self, mut world: NonNull) -> anyhow::Result<()> { + let world = unsafe { world.as_mut() }; let mut camera_rot = Vec3::default(); let delta_time = **world.get_resource::(); let events = world - .try_get_resource_mut::() + .try_get_resource::() .and_then(|q| q.read_events::()); let keys = world @@ -153,6 +152,10 @@ impl SimpleSystem for FreeFlyCameraPlugin { Ok(()) } + + fn world_access(&self) -> lyra_engine::ecs::Access { + Access::Write + } } impl Plugin for FreeFlyCameraPlugin { diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index f4c90e0..93d8031 100644 --- a/examples/testbed/src/main.rs +++ b/examples/testbed/src/main.rs @@ -1,4 +1,6 @@ -use lyra_engine::{math::{self, Vec3}, ecs::{components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent, DeltaTime}, EventQueue, SimpleSystem, Criteria, CriteriaSchedule, BatchedSystem, lyra_ecs::{Component, world::World}}, math::Transform, input::{KeyCode, InputButtons, MouseMotion, ActionHandler, Layout, Action, ActionKind, LayoutId, ActionMapping, Binding, ActionSource, ActionMappingId, InputActionPlugin, ActionState}, game::Game, plugin::Plugin, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct}; +use std::ptr::NonNull; + +use lyra_engine::{math::{self, Vec3}, math::Transform, input::{KeyCode, InputButtons, MouseMotion, ActionHandler, Layout, Action, ActionKind, LayoutId, ActionMapping, Binding, ActionSource, ActionMappingId, InputActionPlugin, ActionState}, game::Game, plugin::Plugin, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct, ecs::{system::{Criteria, CriteriaSchedule, BatchedSystem, IntoSystem}, world::World, Component}, DeltaTime, scene::{TransformComponent, ModelComponent, CameraComponent}}; use lyra_engine::assets::{ResourceManager, Model}; mod free_fly_camera; @@ -39,7 +41,8 @@ impl FixedTimestep { } impl Criteria for FixedTimestep { - fn can_run(&mut self, world: &mut World, check_count: u32) -> CriteriaSchedule { + fn can_run(&mut self, mut world: NonNull, check_count: u32) -> CriteriaSchedule { + let world = unsafe { world.as_mut() }; if check_count == 0 { let delta_time = world.get_resource::(); self.accumulator += **delta_time; @@ -218,7 +221,7 @@ async fn main() { let mut sys = BatchedSystem::new(); sys.with_criteria(FixedTimestep::new(45)); - sys.with_system(spin_system); + sys.with_system(spin_system.into_system()); //sys.with_system(fps_system); game.with_system("fixed", sys, &[]); @@ -263,7 +266,7 @@ async fn main() { Game::initialize().await .with_plugin(lyra_engine::DefaultPlugins) - .with_startup_system(setup_sys) + .with_startup_system(setup_sys.into_system()) .with_plugin(action_handler_plugin) //.with_plugin(fps_plugin) .with_plugin(jiggle_plugin) diff --git a/lyra-ecs/lyra-ecs-derive/src/lib.rs b/lyra-ecs/lyra-ecs-derive/src/lib.rs index bf56636..46707fb 100644 --- a/lyra-ecs/lyra-ecs-derive/src/lib.rs +++ b/lyra-ecs/lyra-ecs-derive/src/lib.rs @@ -1,21 +1,16 @@ use quote::quote; use syn::{parse_macro_input, DeriveInput}; - #[proc_macro_derive(Component)] pub fn derive_component(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); - - //let generics = input.generics.clone() let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let type_ident = &input.ident; - //type_ident.span(). - let type_name = type_ident.to_string(); proc_macro::TokenStream::from(quote! { - impl #impl_generics ::lyra_ecs::Component for #type_ident #ty_generics #where_clause { + impl #impl_generics lyra_engine::ecs::Component for #type_ident #ty_generics #where_clause { fn name() -> &'static str { #type_name } diff --git a/lyra-ecs/src/lib.rs b/lyra-ecs/src/lib.rs index b1a36f5..4196373 100644 --- a/lyra-ecs/src/lib.rs +++ b/lyra-ecs/src/lib.rs @@ -3,31 +3,37 @@ use crate::world::World; extern crate self as lyra_ecs; //mod lyra_ecs { pub use super::*; } -mod archetype; +pub(crate) mod lyra_engine { + pub(crate) mod ecs { + pub use super::super::*; + } +} + +pub mod archetype; pub use archetype::*; pub mod world; pub use world::*; -mod bundle; +pub mod bundle; pub use bundle::*; -mod component; +pub mod component; pub use component::*; -mod query; -pub use query::*; +pub mod query; +//pub use query::*; -mod component_info; +pub mod component_info; pub use component_info::*; -mod resource; +pub mod resource; pub use resource::*; -mod system; -pub use system::*; +pub mod system; +//pub use system::*; -mod tick; +pub mod tick; pub use tick::*; pub use lyra_ecs_derive::*; diff --git a/lyra-ecs/src/query/borrow.rs b/lyra-ecs/src/query/borrow.rs index 568499f..60dedd0 100644 --- a/lyra-ecs/src/query/borrow.rs +++ b/lyra-ecs/src/query/borrow.rs @@ -208,7 +208,7 @@ impl AsQuery for &mut T { mod tests { use std::{any::TypeId, mem::size_of, marker::PhantomData, ptr::NonNull}; - use crate::{world::{World, Entity, EntityId}, archetype::{Archetype, ArchetypeId}, query::View, tests::Vec2, bundle::Bundle, Fetch, DynTypeId, Tick}; + use crate::{world::{World, Entity, EntityId}, archetype::{Archetype, ArchetypeId}, query::{View, Fetch}, tests::Vec2, bundle::Bundle, DynTypeId, Tick}; use super::{QueryBorrow, QueryBorrowMut, FetchBorrowMut}; diff --git a/lyra-ecs/src/query/dynamic/mod.rs b/lyra-ecs/src/query/dynamic/mod.rs index ee5e6c3..6e285ea 100644 --- a/lyra-ecs/src/query/dynamic/mod.rs +++ b/lyra-ecs/src/query/dynamic/mod.rs @@ -1,10 +1,12 @@ use std::{ptr::NonNull, cell::Ref}; -use crate::{Fetch, world::World, Query, ComponentColumn, ComponentInfo}; +use crate::{world::World, ComponentColumn, ComponentInfo}; pub mod view; pub use view::*; +use super::Fetch; + /// Data that rust does not know the type of pub struct DynamicType { pub info: ComponentInfo, diff --git a/lyra-ecs/src/query/dynamic/view.rs b/lyra-ecs/src/query/dynamic/view.rs index 0f0c47d..aff9ae4 100644 --- a/lyra-ecs/src/query/dynamic/view.rs +++ b/lyra-ecs/src/query/dynamic/view.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use crate::{world::World, Archetype, ArchetypeEntityId, Fetch, ArchetypeId}; +use crate::{world::World, Archetype, ArchetypeEntityId, ArchetypeId, query::Fetch}; use super::{QueryDynamicType, FetchDynamicType, DynamicType}; @@ -104,7 +104,7 @@ impl<'a> Iterator for DynamicViewIter<'a> { mod tests { use std::{alloc::Layout, ptr::NonNull}; - use crate::{world::World, MemoryLayout, ComponentInfo, DynTypeId, DynamicBundle, dynamic::QueryDynamicType}; + use crate::{world::World, MemoryLayout, ComponentInfo, DynTypeId, DynamicBundle, query::dynamic::QueryDynamicType}; use super::DynamicView; diff --git a/lyra-ecs/src/query/entities.rs b/lyra-ecs/src/query/entities.rs index 1e2c94f..914cf19 100644 --- a/lyra-ecs/src/query/entities.rs +++ b/lyra-ecs/src/query/entities.rs @@ -1,6 +1,6 @@ -use crate::{world::{Entity, World}, archetype::{Archetype, ArchetypeId}, AsQuery}; +use crate::{world::{Entity, World}, archetype::{Archetype, ArchetypeId}}; -use super::{Fetch, Query}; +use super::{Fetch, Query, AsQuery}; pub struct EntitiesFetch { entities: Vec, diff --git a/lyra-ecs/src/query/resource.rs b/lyra-ecs/src/query/resource.rs index ed038b8..fb622b7 100644 --- a/lyra-ecs/src/query/resource.rs +++ b/lyra-ecs/src/query/resource.rs @@ -152,7 +152,7 @@ impl AsQuery for QueryResourceMut { } #[cfg(test)] mod tests { - use crate::{world::World, tests::{Vec2, Vec3}, QueryResourceMut}; + use crate::{world::World, tests::{Vec2, Vec3}, query::QueryResourceMut}; use super::QueryResource; diff --git a/lyra-ecs/src/query/tick.rs b/lyra-ecs/src/query/tick.rs index 685c993..30b5b63 100644 --- a/lyra-ecs/src/query/tick.rs +++ b/lyra-ecs/src/query/tick.rs @@ -1,6 +1,8 @@ use std::marker::PhantomData; -use crate::{ComponentColumn, Fetch, Tick, DynTypeId, Query, world::World, AsQuery}; +use crate::{ComponentColumn, Tick, DynTypeId, world::World}; + +use super::{Query, Fetch, AsQuery}; #[derive(Clone, Copy, Debug, Default)] pub struct TickOf { diff --git a/src/ecs/system/batched.rs b/lyra-ecs/src/system/batched.rs similarity index 77% rename from src/ecs/system/batched.rs rename to lyra-ecs/src/system/batched.rs index 7c05e18..58b656a 100644 --- a/src/ecs/system/batched.rs +++ b/lyra-ecs/src/system/batched.rs @@ -1,12 +1,14 @@ use lyra_ecs::world::World; -use super::{SimpleSystem, Criteria}; +use crate::Access; + +use super::{System, Criteria}; /// A system that executes a batch of systems in order that they were given. /// You can optionally add criteria that must pass before the systems are /// executed. pub struct BatchedSystem { - systems: Vec>, + systems: Vec>, criteria: Vec>, criteria_checks: u32, } @@ -23,7 +25,7 @@ impl BatchedSystem { pub fn with_system(&mut self, system: S) -> &mut Self where - S: SimpleSystem + 'static + S: System + 'static { self.systems.push(Box::new(system)); self @@ -38,8 +40,16 @@ impl BatchedSystem { } } -impl SimpleSystem for BatchedSystem { - fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { +impl System for BatchedSystem { + fn world_access(&self) -> crate::Access { + if self.systems.iter().any(|s| s.world_access() == Access::Write) { + Access::Write + } else { + Access::Read + } + } + + fn execute(&mut self, world: std::ptr::NonNull) -> anyhow::Result<()> { let mut can_run = true; let mut check_again = false; @@ -60,13 +70,13 @@ impl SimpleSystem for BatchedSystem { if can_run { for system in self.systems.iter_mut() { - system.execute_mut(world)?; + system.execute(world)?; } } if check_again { self.criteria_checks += 1; - self.execute_mut(world)?; + self.execute(world)?; } self.criteria_checks = 0; diff --git a/src/ecs/system/criteria.rs b/lyra-ecs/src/system/criteria.rs similarity index 55% rename from src/ecs/system/criteria.rs rename to lyra-ecs/src/system/criteria.rs index 295385d..1abbaa9 100644 --- a/src/ecs/system/criteria.rs +++ b/lyra-ecs/src/system/criteria.rs @@ -1,5 +1,8 @@ +use std::ptr::NonNull; + use lyra_ecs::world::World; +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum CriteriaSchedule { Yes, No, @@ -13,13 +16,14 @@ pub trait Criteria { /// Parameters: /// * `world` - The ecs world. /// * `check_count` - The amount of times the Criteria has been checked this tick. - fn can_run(&mut self, world: &mut World, check_count: u32) -> CriteriaSchedule; + fn can_run(&mut self, world: NonNull, check_count: u32) -> CriteriaSchedule; } impl Criteria for F where F: FnMut(&mut World, u32) -> CriteriaSchedule { - fn can_run(&mut self, world: &mut World, check_count: u32) -> CriteriaSchedule { - self(world, check_count) + fn can_run(&mut self, mut world: NonNull, check_count: u32) -> CriteriaSchedule { + let world_mut = unsafe { world.as_mut() }; + self(world_mut, check_count) } } \ No newline at end of file diff --git a/lyra-ecs/src/system/graph.rs b/lyra-ecs/src/system/graph.rs index 68c6651..6aeee00 100644 --- a/lyra-ecs/src/system/graph.rs +++ b/lyra-ecs/src/system/graph.rs @@ -1,6 +1,8 @@ use std::{collections::{HashMap, VecDeque, HashSet}, ptr::NonNull}; -use crate::{System, world::World}; +use super::System; + +use crate::world::World; #[derive(thiserror::Error, Debug)] pub enum GraphExecutorError { @@ -55,8 +57,7 @@ impl GraphExecutor { } /// Executes the systems in the graph - pub fn execute(&mut self, world: &World, stop_on_error: bool) -> Result, GraphExecutorError> { - let world = NonNull::from(world); + pub fn execute(&mut self, world: NonNull, stop_on_error: bool) -> Result, GraphExecutorError> { let mut stack = VecDeque::new(); let mut visited = HashSet::new(); @@ -106,7 +107,9 @@ impl GraphExecutor { #[cfg(test)] mod tests { - use crate::{View, QueryBorrow, tests::Vec2, IntoSystem, world::World, Resource, ResourceMut}; + use std::ptr::NonNull; + + use crate::{world::World, query::{ResourceMut, View}, system::IntoSystem}; use super::GraphExecutor; @@ -150,7 +153,7 @@ mod tests { exec.insert_system("a", a_system.into_system(), &[]); exec.insert_system("b", b_system.into_system(), &["a"]); - exec.execute(&world, true).unwrap(); + exec.execute(NonNull::from(&world), true).unwrap(); println!("Executed systems"); let order = world.get_resource::>(); diff --git a/lyra-ecs/src/system/mod.rs b/lyra-ecs/src/system/mod.rs index 5fc677d..b2d3706 100644 --- a/lyra-ecs/src/system/mod.rs +++ b/lyra-ecs/src/system/mod.rs @@ -1,16 +1,30 @@ use std::{ptr::NonNull, marker::PhantomData, cell::{Ref, RefMut}}; -use crate::{world::World, View, Query, Access, ResourceObject}; +use crate::{world::World, Access, ResourceObject, query::{Query, View}}; pub mod graph; +pub use graph::*; + +pub mod criteria; +pub use criteria::*; + +pub mod batched; +pub use batched::*; /// A system that does not mutate the world pub trait System { + /// A method that indicates the type of access of the world the system requires. fn world_access(&self) -> Access; + + /// The actual execution of the system. fn execute(&mut self, world: NonNull) -> anyhow::Result<()>; + + /// A setup step of the System, called before `execute` ever runs. + fn setup(&self, world: NonNull) -> anyhow::Result<()> { + Ok(()) + } } -/// A trait for converting something into a system. pub trait IntoSystem { type System: System; @@ -61,6 +75,21 @@ macro_rules! impl_fn_system_tuple { } } + /* impl IntoSystem for F + where + F: FnMut($($name,)+) -> anyhow::Result<()>, + F: for<'a> FnMut($(<$name::Fetcher as FnArgFetcher>::Arg<'a>,)+) -> anyhow::Result<()>, + { + type System = FnSystem; + + fn into_system(self) -> Self::System { + FnSystem { + args: ($($name::Fetcher::new(),)+), + inner: self + } + } + } */ + impl IntoSystem<($($name,)+)> for F where F: FnMut($($name,)+) -> anyhow::Result<()>, @@ -223,7 +252,7 @@ impl FnArgFetcher for ResourceMutArgFetcher { mod tests { use std::{ptr::NonNull, cell::RefMut}; - use crate::{tests::{Vec2, Vec3}, View, QueryBorrow, world::World}; + use crate::{tests::{Vec2, Vec3}, world::World, query::{QueryBorrow, View}}; use super::{System, IntoSystem}; struct SomeCounter(u32); @@ -311,6 +340,35 @@ mod tests { assert_eq!(counter.0, 20); } + #[test] + fn function_system() { + let mut world = World::new(); + world.spawn((Vec2::rand(), Vec3::rand())); + world.spawn((Vec2::rand(), Vec3::rand())); + world.add_resource(SomeCounter(0)); + + let test_system = |world: &World| -> anyhow::Result<()> { + let mut counter = world.get_resource_mut::(); + counter.0 += 10; + + Ok(()) + }; + + test_system.into_system().execute(NonNull::from(&world)).unwrap(); + + fn test_system(world: &mut World) -> anyhow::Result<()> { + let mut counter = world.get_resource_mut::(); + counter.0 += 10; + + Ok(()) + } + + test_system.into_system().execute(NonNull::from(&world)).unwrap(); + + let counter = world.get_resource::(); + assert_eq!(counter.0, 20); + } + #[test] fn resource_system() { let mut world = World::new(); diff --git a/lyra-ecs/src/tests.rs b/lyra-ecs/src/tests.rs index 30e81dc..9b8e8df 100644 --- a/lyra-ecs/src/tests.rs +++ b/lyra-ecs/src/tests.rs @@ -1,15 +1,23 @@ -use lyra_ecs_derive::Component; use rand::Rng; + +use crate::Component; +use crate::lyra_engine; //use crate::lyra_ecs; /// This source file includes some common things that tests are using. -#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd, Component)] +#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] pub struct Vec2 { pub x: f32, pub y: f32, } +impl Component for Vec2 { + fn name() -> &'static str { + "Vec2" + } +} + impl Vec2 { pub fn new(x: f32, y: f32) -> Self { Self { diff --git a/lyra-ecs/src/world.rs b/lyra-ecs/src/world.rs index 7795b30..232a4ed 100644 --- a/lyra-ecs/src/world.rs +++ b/lyra-ecs/src/world.rs @@ -1,6 +1,6 @@ use std::{collections::{HashMap, VecDeque}, any::TypeId, cell::{Ref, RefMut}, ptr::NonNull}; -use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component, query::{ViewIter, View}, resource::ResourceData, Query, AsQuery, dynamic::{DynamicViewIter, QueryDynamicType, DynamicView}, ViewOne, ComponentInfo, DynTypeId, TickTracker, Tick}; +use crate::{archetype::{ArchetypeId, Archetype}, bundle::Bundle, component::Component, query::{Query, ViewIter, View, AsQuery}, resource::ResourceData, query::{dynamic::{DynamicViewIter, QueryDynamicType, DynamicView}, ViewOne}, ComponentInfo, DynTypeId, TickTracker, Tick}; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct EntityId(pub u64); @@ -300,7 +300,7 @@ impl World { mod tests { use std::ops::Deref; - use crate::{tests::{Vec2, Vec3}, TickOf}; + use crate::{tests::{Vec2, Vec3}, query::TickOf}; use super::World; diff --git a/src/ecs/components/delta_time.rs b/src/delta_time.rs similarity index 85% rename from src/ecs/components/delta_time.rs rename to src/delta_time.rs index 9bf32b8..50f3e84 100644 --- a/src/ecs/components/delta_time.rs +++ b/src/delta_time.rs @@ -1,7 +1,7 @@ use std::borrow::BorrowMut; use instant::Instant; -use lyra_ecs::{Component, world::World}; +use lyra_ecs::{Component, world::World, system::IntoSystem}; use crate::plugin::Plugin; @@ -36,6 +36,6 @@ pub struct DeltaTimePlugin; impl Plugin for DeltaTimePlugin { fn setup(&self, game: &mut crate::game::Game) { game.world().add_resource(DeltaTime(0.0, None)); - game.with_system("delta_time", delta_time_system, &[]); + game.with_system("delta_time", delta_time_system.into_system(), &[]); } } \ No newline at end of file diff --git a/src/ecs/mod.rs b/src/ecs/mod.rs deleted file mode 100755 index 53a566d..0000000 --- a/src/ecs/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use lyra_ecs; - -pub mod components; - -pub mod events; -pub use events::*; - -pub mod system; -pub use system::*; \ No newline at end of file diff --git a/src/ecs/system/mod.rs b/src/ecs/system/mod.rs deleted file mode 100644 index 6be2304..0000000 --- a/src/ecs/system/mod.rs +++ /dev/null @@ -1,127 +0,0 @@ -pub mod batched; -pub use batched::*; - -pub mod criteria; -pub use criteria::*; -use lyra_ecs::world::World; - -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, _world: &mut World) -> anyhow::Result<()> { - Ok(()) - } - - // todo: make async? - fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()>; -} - -impl SimpleSystem for S - where S: FnMut(&mut World) -> anyhow::Result<()> -{ - fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { - self(world) - } -} - -struct SystemGraphNode { - name: String, - #[allow(dead_code)] - dependent_on: Vec, // TODO - system: Box, -} - -struct SystemGraphEdge { - -} - -/// Dispatcher for multiple systems. -/// -/// This struct uses a graph for finding executing systems with dependencies. -/// At some point this will be multithreaded. -pub struct SystemDispatcher { - graph: StableDiGraph, - node_refs: HashMap, -} - -impl Default for SystemDispatcher { - fn default() -> Self { - Self { - graph: StableDiGraph::new(), - node_refs: HashMap::new(), - } - } -} - -impl SystemDispatcher { - pub fn new() -> Self { - Self::default() - } - - /// Adds a SimpleSystem to the SystemGraph. - /// - /// WARN: Ensure that no cycles are created, this will cause the systems graph to not be sortable by topological sort, - /// and will cause a panic later on in the engine. - /// - /// TODO: Return false if a cycle was created, making it impossible to know when to dispatch them. This will mean that the System would not of had been added. - pub fn add_system(&mut self, name: &str, system: S, dependencies: &[&str]) -> bool - where - S: SimpleSystem + 'static - { - let name = name.to_string(); - let dependencies: Vec = dependencies.iter().map(|s| s.to_string()).collect(); - let system = Box::new(system) as Box; - - let added_index = - self.graph.add_node(SystemGraphNode { - name: name.to_string(), - dependent_on: dependencies.clone(), - system, - }); - - // store name ref to the graph node - self.node_refs.insert(name, added_index); - - // find the dependencies in node_refs and add edges directed towards the new node - for depend in dependencies.into_iter() { - let idx = self.node_refs - .get(&depend) - .expect("Dependency not found!"); - - self.graph.add_edge(*idx, added_index, SystemGraphEdge { }); - } - - true - } - - 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(world) { - Ok(()) => {}, - Err(e) => { - warn!("System execution of {} resulted in an error! '{}'.", node.name, e); - - // TODO: Find some way to stop traversing down a topopath in the graph executor and continue down a different one. - // This might require a custom topopath implementation (preferably iterative). It would have to ensure that it - // doesn't run other systems that are dependent on that failed system. - return; - } - } - } - } -} - -impl SimpleSystem for SystemDispatcher { - fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { - self.execute_systems(world); - - Ok(()) - } -} \ No newline at end of file diff --git a/src/ecs/events.rs b/src/events.rs similarity index 100% rename from src/ecs/events.rs rename to src/events.rs diff --git a/src/game.rs b/src/game.rs index d79bd74..882a074 100755 --- a/src/game.rs +++ b/src/game.rs @@ -1,8 +1,8 @@ -use std::{sync::Arc, collections::VecDeque}; +use std::{sync::Arc, collections::VecDeque, ptr::NonNull}; use async_std::task::block_on; -use lyra_ecs::world::World; +use lyra_ecs::{world::World, system::{GraphExecutor, System}}; use tracing::{info, error, Level, debug}; use tracing_appender::non_blocking; use tracing_subscriber::{ @@ -13,7 +13,7 @@ use tracing_subscriber::{ use winit::{window::{WindowBuilder, Window}, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode, DeviceEvent}, event_loop::{EventLoop, ControlFlow}}; -use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, ecs::{SimpleSystem, SystemDispatcher, EventQueue, Events}, plugin::Plugin, change_tracker::Ct}; +use crate::{render::{renderer::{Renderer, BasicRenderer}, window::WindowOptions}, input::InputEvent, plugin::Plugin, change_tracker::Ct, EventQueue}; pub struct Controls<'a> { pub world: &'a mut World, @@ -37,18 +37,18 @@ struct GameLoop { world: World, /// higher priority systems - engine_sys_dispatcher: SystemDispatcher, - user_sys_dispatcher: SystemDispatcher, + engine_sys_dispatcher: GraphExecutor, + user_sys_dispatcher: GraphExecutor, } impl GameLoop { - pub async fn new(window: Arc, world: World, user_systems: SystemDispatcher) -> GameLoop { + pub async fn new(window: Arc, world: World, user_systems: GraphExecutor) -> GameLoop { Self { window: Arc::clone(&window), renderer: Box::new(BasicRenderer::create_with_window(window).await), world, - engine_sys_dispatcher: SystemDispatcher::new(), + engine_sys_dispatcher: GraphExecutor::new(), user_sys_dispatcher: user_systems, } } @@ -67,11 +67,12 @@ impl GameLoop { } async fn update(&mut self) { - if let Err(e) = self.engine_sys_dispatcher.execute_mut(&mut self.world) { + let world_ptr = NonNull::from(&self.world); + if let Err(e) = self.engine_sys_dispatcher.execute(world_ptr, true) { error!("Error when executing engine ecs systems: '{}'", e); } - if let Err(e) = self.user_sys_dispatcher.execute_mut(&mut self.world) { + if let Err(e) = self.user_sys_dispatcher.execute(world_ptr, true) { error!("Error when executing user ecs systems: '{}'", e); } } @@ -205,8 +206,8 @@ impl GameLoop { pub struct Game { world: Option, plugins: VecDeque>, - system_dispatcher: Option, - startup_systems: VecDeque>, + system_dispatcher: Option, + startup_systems: VecDeque>, } impl Default for Game { @@ -214,7 +215,7 @@ impl Default for Game { Self { world: Some(World::new()), plugins: VecDeque::new(), - system_dispatcher: Some(SystemDispatcher::new()), + system_dispatcher: Some(GraphExecutor::new()), startup_systems: VecDeque::new(), } } @@ -234,10 +235,10 @@ impl Game { /// Add a system to the ecs world pub fn with_system(&mut self, name: &str, system: S, depends: &[&str]) -> &mut Self where - S: SimpleSystem + 'static + S: System + 'static { let system_dispatcher = self.system_dispatcher.as_mut().unwrap(); - system_dispatcher.add_system(name, system, depends); + system_dispatcher.insert_system(name, system, depends); self } @@ -246,7 +247,7 @@ impl Game { /// They will only be ran once pub fn with_startup_system(&mut self, system: S) -> &mut Self where - S: SimpleSystem + 'static + S: System + 'static { self.startup_systems.push_back(Box::new(system)); @@ -294,8 +295,9 @@ impl Game { // 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!"); + let world_ptr = NonNull::from(&world); + startup.setup(world_ptr).expect("World returned an error!"); + startup.execute(world_ptr).expect("World returned an error!"); } // start winit event loops diff --git a/src/input/action.rs b/src/input/action.rs index 482d998..7b9aa3a 100644 --- a/src/input/action.rs +++ b/src/input/action.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, cell::RefCell, borrow::BorrowMut, ops::Deref}; -use lyra_ecs::world::World; +use lyra_ecs::{world::World, system::IntoSystem}; use crate::{castable_any::CastableAny, plugin::Plugin}; @@ -424,6 +424,6 @@ pub struct InputActionPlugin; impl Plugin for InputActionPlugin { fn setup(&self, game: &mut crate::game::Game) { - game.with_system("input_actions", actions_system, &[]); + game.with_system("input_actions", actions_system.into_system(), &[]); } } \ No newline at end of file diff --git a/src/input/system.rs b/src/input/system.rs index 40a2987..087f8f4 100755 --- a/src/input/system.rs +++ b/src/input/system.rs @@ -1,8 +1,10 @@ +use std::ptr::NonNull; + use glam::Vec2; use lyra_ecs::world::World; use winit::event::MouseScrollDelta; -use crate::{ecs::{SimpleSystem, EventQueue}, plugin::Plugin,}; +use crate::{EventQueue, plugin::Plugin}; use super::{events::*, InputButtons, InputEvent}; @@ -96,8 +98,9 @@ impl InputSystem { } } -impl SimpleSystem for InputSystem { - fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { +impl crate::ecs::system::System for InputSystem { + fn execute(&mut self, mut world: NonNull) -> anyhow::Result<()> { + let world = unsafe { world.as_mut() }; let queue = world.try_get_resource_mut::() .and_then(|q| q.read_events::()); @@ -113,6 +116,10 @@ impl SimpleSystem for InputSystem { Ok(()) } + + fn world_access(&self) -> lyra_ecs::Access { + lyra_ecs::Access::Write + } } /// Plugin that runs InputSystem diff --git a/src/lib.rs b/src/lib.rs index 0892b77..21ecbcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,16 +2,26 @@ #![feature(lint_reasons)] #![feature(trait_alias)] +extern crate self as lyra_engine; + pub mod game; pub mod render; pub mod resources; -pub mod ecs; pub mod math; pub mod input; pub mod castable_any; pub mod plugin; pub mod change_tracker; +pub mod events; +pub use events::*; + +pub mod delta_time; +pub use delta_time::*; + +pub mod scene; + pub use lyra_resource as assets; +pub use lyra_ecs as ecs; pub use plugin::DefaultPlugins; \ No newline at end of file diff --git a/src/plugin.rs b/src/plugin.rs index 00033bb..c7adca2 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,7 +1,7 @@ use lyra_resource::ResourceManager; -use crate::ecs::EventsPlugin; -use crate::ecs::components::DeltaTimePlugin; +use crate::EventsPlugin; +use crate::DeltaTimePlugin; use crate::game::Game; use crate::input::InputPlugin; use crate::render::window::WindowPlugin; diff --git a/src/render/camera.rs b/src/render/camera.rs index b7560fd..f2f0729 100755 --- a/src/render/camera.rs +++ b/src/render/camera.rs @@ -1,6 +1,6 @@ use winit::dpi::PhysicalSize; -use crate::{math::{Angle, OPENGL_TO_WGPU_MATRIX}, ecs::components::camera::CameraComponent}; +use crate::{math::{Angle, OPENGL_TO_WGPU_MATRIX}, scene::CameraComponent}; #[derive(Debug, Clone, PartialEq, Eq)] pub enum CameraProjectionMode { diff --git a/src/render/light/mod.rs b/src/render/light/mod.rs index de2c923..f22db94 100644 --- a/src/render/light/mod.rs +++ b/src/render/light/mod.rs @@ -2,7 +2,7 @@ pub mod point; pub mod directional; pub mod spotlight; -use lyra_ecs::{Entity, Tick, world::World, Entities, TickOf}; +use lyra_ecs::{Entity, Tick, world::World, query::{Entities, TickOf}}; pub use point::*; pub use directional::*; pub use spotlight::*; @@ -15,7 +15,7 @@ use wgpu::util::DeviceExt; use std::mem; -use crate::{math::Transform, ecs::components::TransformComponent}; +use crate::{math::Transform, scene::TransformComponent}; use self::directional::DirectionalLight; diff --git a/src/render/renderer.rs b/src/render/renderer.rs index f48fa9e..b9aad0d 100755 --- a/src/render/renderer.rs +++ b/src/render/renderer.rs @@ -7,20 +7,19 @@ use std::borrow::Cow; use glam::Vec3; use instant::Instant; use itertools::izip; -use lyra_ecs::{Entity, Entities, TickOf}; +use lyra_ecs::Entity; +use lyra_ecs::query::{Entities, TickOf}; use lyra_ecs::world::World; use tracing::{debug, warn}; use wgpu::{BindGroup, BindGroupLayout, Limits}; use wgpu::util::DeviceExt; use winit::window::Window; -use crate::ecs::components::camera::CameraComponent; -use crate::ecs::components::model::ModelComponent; -use crate::ecs::components::transform::TransformComponent; use crate::math::{Transform, self}; use crate::render::light::PointLightUniform; use crate::render::material::MaterialUniform; use crate::render::render_buffer::{BufferWrapperBuilder, BindGroupPair}; +use crate::scene::{ModelComponent, TransformComponent, CameraComponent}; use super::camera::{RenderCamera, CameraUniform}; use super::desc_buf_lay::DescVertexBufferLayout; diff --git a/src/render/window.rs b/src/render/window.rs index a7442e9..3388125 100644 --- a/src/render/window.rs +++ b/src/render/window.rs @@ -1,13 +1,13 @@ use std::{sync::Arc, collections::VecDeque}; use glam::{Vec2, IVec2}; -use lyra_ecs::world::World; +use lyra_ecs::{world::World, system::IntoSystem}; use tracing::{warn, error}; use winit::{window::{Window, Fullscreen}, dpi::{LogicalPosition, LogicalSize, PhysicalPosition}, error::ExternalError}; pub use winit::window::{CursorGrabMode, CursorIcon, Icon, Theme, WindowButtons, WindowLevel}; -use crate::{plugin::Plugin, change_tracker::Ct, ecs::EventQueue, input::InputEvent}; +use crate::{plugin::Plugin, change_tracker::Ct, input::InputEvent, EventQueue}; #[derive(Default, Clone)] pub enum WindowMode { @@ -374,6 +374,6 @@ impl Plugin for WindowPlugin { let window_options = WindowOptions::default(); game.world().add_resource(Ct::new(window_options)); - game.with_system("window_updater", window_updater_system, &[]); + game.with_system("window_updater", window_updater_system.into_system(), &[]); } } diff --git a/src/ecs/components/camera.rs b/src/scene/camera.rs similarity index 100% rename from src/ecs/components/camera.rs rename to src/scene/camera.rs diff --git a/src/ecs/components/free_fly_camera.rs b/src/scene/free_fly_camera.rs similarity index 100% rename from src/ecs/components/free_fly_camera.rs rename to src/scene/free_fly_camera.rs diff --git a/src/ecs/components/mesh.rs b/src/scene/mesh.rs similarity index 100% rename from src/ecs/components/mesh.rs rename to src/scene/mesh.rs diff --git a/src/ecs/components/mod.rs b/src/scene/mod.rs old mode 100755 new mode 100644 similarity index 70% rename from src/ecs/components/mod.rs rename to src/scene/mod.rs index aeb9278..5d743fa --- a/src/ecs/components/mod.rs +++ b/src/scene/mod.rs @@ -11,7 +11,4 @@ pub mod camera; pub use camera::*; pub mod free_fly_camera; -pub use free_fly_camera::*; - -pub mod delta_time; -pub use delta_time::*; \ No newline at end of file +pub use free_fly_camera::*; \ No newline at end of file diff --git a/src/ecs/components/model.rs b/src/scene/model.rs similarity index 100% rename from src/ecs/components/model.rs rename to src/scene/model.rs diff --git a/src/ecs/components/transform.rs b/src/scene/transform.rs similarity index 100% rename from src/ecs/components/transform.rs rename to src/scene/transform.rs