Switch to lyra-ecs systems, move ecs mod to scene mod, reexport lyra-ecs as ecs
This commit is contained in:
parent
0a0ac0ae6f
commit
09bba5b3b3
|
@ -2335,7 +2335,6 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-std",
|
||||
"fps_counter",
|
||||
"lyra-ecs",
|
||||
"lyra-engine",
|
||||
"tracing",
|
||||
]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<World>) -> anyhow::Result<()> {
|
||||
let world = unsafe { world.as_mut() };
|
||||
let mut camera_rot = Vec3::default();
|
||||
|
||||
let delta_time = **world.get_resource::<DeltaTime>();
|
||||
|
||||
let events = world
|
||||
.try_get_resource_mut::<EventQueue>()
|
||||
.try_get_resource::<EventQueue>()
|
||||
.and_then(|q| q.read_events::<MouseMotion>());
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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<World>, check_count: u32) -> CriteriaSchedule {
|
||||
let world = unsafe { world.as_mut() };
|
||||
if check_count == 0 {
|
||||
let delta_time = world.get_resource::<DeltaTime>();
|
||||
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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -208,7 +208,7 @@ impl<T: 'static> 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};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Entity>,
|
||||
|
|
|
@ -152,7 +152,7 @@ impl<R: ResourceObject> AsQuery for QueryResourceMut<R> {
|
|||
}
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{world::World, tests::{Vec2, Vec3}, QueryResourceMut};
|
||||
use crate::{world::World, tests::{Vec2, Vec3}, query::QueryResourceMut};
|
||||
|
||||
use super::QueryResource;
|
||||
|
||||
|
|
|
@ -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<T> {
|
||||
|
|
|
@ -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<Box<dyn SimpleSystem>>,
|
||||
systems: Vec<Box<dyn System>>,
|
||||
criteria: Vec<Box<dyn Criteria>>,
|
||||
criteria_checks: u32,
|
||||
}
|
||||
|
@ -23,7 +25,7 @@ impl BatchedSystem {
|
|||
|
||||
pub fn with_system<S>(&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<World>) -> 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;
|
|
@ -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<World>, check_count: u32) -> CriteriaSchedule;
|
||||
}
|
||||
|
||||
impl<F> 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<World>, check_count: u32) -> CriteriaSchedule {
|
||||
let world_mut = unsafe { world.as_mut() };
|
||||
self(world_mut, check_count)
|
||||
}
|
||||
}
|
|
@ -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<Vec<GraphExecutorError>, GraphExecutorError> {
|
||||
let world = NonNull::from(world);
|
||||
pub fn execute(&mut self, world: NonNull<World>, stop_on_error: bool) -> Result<Vec<GraphExecutorError>, 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::<Vec<String>>();
|
||||
|
|
|
@ -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<World>) -> anyhow::Result<()>;
|
||||
|
||||
/// A setup step of the System, called before `execute` ever runs.
|
||||
fn setup(&self, world: NonNull<World>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for converting something into a system.
|
||||
pub trait IntoSystem<T> {
|
||||
type System: System;
|
||||
|
||||
|
@ -61,6 +75,21 @@ macro_rules! impl_fn_system_tuple {
|
|||
}
|
||||
}
|
||||
|
||||
/* impl<F, $($name: FnArg,)+> IntoSystem for F
|
||||
where
|
||||
F: FnMut($($name,)+) -> anyhow::Result<()>,
|
||||
F: for<'a> FnMut($(<$name::Fetcher as FnArgFetcher>::Arg<'a>,)+) -> anyhow::Result<()>,
|
||||
{
|
||||
type System = FnSystem<F, ($($name::Fetcher,)+)>;
|
||||
|
||||
fn into_system(self) -> Self::System {
|
||||
FnSystem {
|
||||
args: ($($name::Fetcher::new(),)+),
|
||||
inner: self
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
impl<F, $($name: FnArg,)+> IntoSystem<($($name,)+)> for F
|
||||
where
|
||||
F: FnMut($($name,)+) -> anyhow::Result<()>,
|
||||
|
@ -223,7 +252,7 @@ impl<R: ResourceObject> FnArgFetcher for ResourceMutArgFetcher<R> {
|
|||
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::<SomeCounter>();
|
||||
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::<SomeCounter>();
|
||||
counter.0 += 10;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
test_system.into_system().execute(NonNull::from(&world)).unwrap();
|
||||
|
||||
let counter = world.get_resource::<SomeCounter>();
|
||||
assert_eq!(counter.0, 20);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resource_system() {
|
||||
let mut world = World::new();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(), &[]);
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
pub use lyra_ecs;
|
||||
|
||||
pub mod components;
|
||||
|
||||
pub mod events;
|
||||
pub use events::*;
|
||||
|
||||
pub mod system;
|
||||
pub use system::*;
|
|
@ -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<S> 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<String>, // TODO
|
||||
system: Box<dyn SimpleSystem>,
|
||||
}
|
||||
|
||||
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<SystemGraphNode, SystemGraphEdge>,
|
||||
node_refs: HashMap<String, NodeIndex>,
|
||||
}
|
||||
|
||||
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<S>(&mut self, name: &str, system: S, dependencies: &[&str]) -> bool
|
||||
where
|
||||
S: SimpleSystem + 'static
|
||||
{
|
||||
let name = name.to_string();
|
||||
let dependencies: Vec<String> = dependencies.iter().map(|s| s.to_string()).collect();
|
||||
let system = Box::new(system) as Box<dyn SimpleSystem>;
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
36
src/game.rs
36
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<Window>, world: World, user_systems: SystemDispatcher) -> GameLoop {
|
||||
pub async fn new(window: Arc<Window>, 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<World>,
|
||||
plugins: VecDeque<Box<dyn Plugin>>,
|
||||
system_dispatcher: Option<SystemDispatcher>,
|
||||
startup_systems: VecDeque<Box<dyn SimpleSystem>>,
|
||||
system_dispatcher: Option<GraphExecutor>,
|
||||
startup_systems: VecDeque<Box<dyn System>>,
|
||||
}
|
||||
|
||||
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<S>(&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<S>(&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
|
||||
|
|
|
@ -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(), &[]);
|
||||
}
|
||||
}
|
|
@ -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<World>) -> anyhow::Result<()> {
|
||||
let world = unsafe { world.as_mut() };
|
||||
let queue = world.try_get_resource_mut::<EventQueue>()
|
||||
.and_then(|q| q.read_events::<InputEvent>());
|
||||
|
||||
|
@ -113,6 +116,10 @@ impl SimpleSystem for InputSystem {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn world_access(&self) -> lyra_ecs::Access {
|
||||
lyra_ecs::Access::Write
|
||||
}
|
||||
}
|
||||
|
||||
/// Plugin that runs InputSystem
|
||||
|
|
12
src/lib.rs
12
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;
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(), &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,3 @@ pub use camera::*;
|
|||
|
||||
pub mod free_fly_camera;
|
||||
pub use free_fly_camera::*;
|
||||
|
||||
pub mod delta_time;
|
||||
pub use delta_time::*;
|
Loading…
Reference in New Issue