Add system criteria
ci/woodpecker/push/build Pipeline was successful
Details
ci/woodpecker/push/build Pipeline was successful
Details
This commit is contained in:
parent
927566ca3d
commit
6b935739ef
|
@ -39,9 +39,9 @@ impl FreeFlyCamera {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FreeFlyCameraController;
|
||||
pub struct FreeFlyCameraPlugin;
|
||||
|
||||
impl SimpleSystem for FreeFlyCameraController {
|
||||
impl SimpleSystem for FreeFlyCameraPlugin {
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
let mut camera_rot = Vec3::default();
|
||||
|
||||
|
@ -147,8 +147,8 @@ impl SimpleSystem for FreeFlyCameraController {
|
|||
}
|
||||
}
|
||||
|
||||
impl Plugin for FreeFlyCameraController {
|
||||
impl Plugin for FreeFlyCameraPlugin {
|
||||
fn setup(&self, game: &mut Game) {
|
||||
game.with_system("free_fly_camera_controller", FreeFlyCameraController, &[]);
|
||||
game.with_system("free_fly_camera_system", FreeFlyCameraPlugin, &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,60 @@
|
|||
use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent}, EventQueue, SimpleSystem, Component}, math::Transform, input::{KeyCode, InputButtons, MouseMotion}, game::Game, plugin::Plugin, render::window::{CursorGrabMode, WindowOptions}, change_tracker::Ct};
|
||||
use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent, DeltaTime}, EventQueue, SimpleSystem, Component, Criteria, CriteriaSchedule, BatchedSystem}, math::Transform, input::{KeyCode, InputButtons, MouseMotion}, game::Game, plugin::Plugin, render::window::{CursorGrabMode, WindowOptions}, change_tracker::Ct};
|
||||
use lyra_engine::assets::{ResourceManager, Model};
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
mod free_fly_camera;
|
||||
use free_fly_camera::{FreeFlyCameraController, FreeFlyCamera};
|
||||
use free_fly_camera::{FreeFlyCameraPlugin, FreeFlyCamera};
|
||||
|
||||
/* pub const VERTICES: &[Vertex] = &[
|
||||
Vertex { position: [-0.0868241, 0.49240386, 0.0], tex_coords: [0.4131759, 0.00759614], }, // A
|
||||
Vertex { position: [-0.49513406, 0.06958647, 0.0], tex_coords: [0.0048659444, 0.43041354], }, // B
|
||||
Vertex { position: [-0.21918549, -0.44939706, 0.0], tex_coords: [0.28081453, 0.949397], }, // C
|
||||
Vertex { position: [0.35966998, -0.3473291, 0.0], tex_coords: [0.85967, 0.84732914], }, // D
|
||||
Vertex { position: [0.44147372, 0.2347359, 0.0], tex_coords: [0.9414737, 0.2652641], }, // E
|
||||
]; */
|
||||
struct FixedTimestep {
|
||||
max_tps: u32,
|
||||
fixed_time: f32,
|
||||
accumulator: f32,
|
||||
}
|
||||
|
||||
pub const INDICES: &[u16] = &[
|
||||
0, 1, 4,
|
||||
1, 2, 4,
|
||||
2, 3, 4,
|
||||
];
|
||||
impl FixedTimestep {
|
||||
pub fn new(max_tps: u32) -> Self {
|
||||
Self {
|
||||
max_tps,
|
||||
fixed_time: Self::calc_fixed_time(max_tps),
|
||||
accumulator: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
fn calc_fixed_time(max_tps: u32) -> f32 {
|
||||
1.0 / max_tps as f32
|
||||
}
|
||||
|
||||
fn set_tps(&mut self, tps: u32) {
|
||||
self.max_tps = tps;
|
||||
self.fixed_time = Self::calc_fixed_time(tps);
|
||||
}
|
||||
|
||||
fn tps(&self) -> u32 {
|
||||
self.max_tps
|
||||
}
|
||||
|
||||
fn fixed_time(&self) -> f32 {
|
||||
self.fixed_time
|
||||
}
|
||||
}
|
||||
|
||||
impl Criteria for FixedTimestep {
|
||||
fn can_run(&mut self, world: &mut edict::World, check_count: u32) -> CriteriaSchedule {
|
||||
if check_count == 0 {
|
||||
let delta_time = world.get_resource::<DeltaTime>().unwrap();
|
||||
self.accumulator += **delta_time;
|
||||
}
|
||||
|
||||
if self.accumulator >= self.fixed_time {
|
||||
self.accumulator -= self.fixed_time;
|
||||
return CriteriaSchedule::YesAndLoop;
|
||||
}
|
||||
|
||||
CriteriaSchedule::No
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct TpsAccumulator(f32);
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
|
@ -54,111 +90,42 @@ async fn main() {
|
|||
Ok(())
|
||||
};
|
||||
|
||||
/* let fps_system = |world: &mut World| -> anyhow::Result<()> {
|
||||
let mut counter: RefMut<fps_counter::FPSCounter> = world.get_resource_mut().unwrap();
|
||||
let fps_system = |world: &mut World| -> anyhow::Result<()> {
|
||||
let mut counter = world.get_resource_mut::<fps_counter::FPSCounter>().unwrap();
|
||||
|
||||
let fps = counter.tick();
|
||||
|
||||
debug!("FPS: {fps}");
|
||||
println!("FPS: {fps}");
|
||||
|
||||
Ok(())
|
||||
};
|
||||
let fps_plugin = move |game: &mut Game| {
|
||||
let world = game.world();
|
||||
world.insert_resource(fps_counter::FPSCounter::new());
|
||||
};
|
||||
|
||||
game.with_system("fps", fps_system, &["input"]);
|
||||
}; */
|
||||
|
||||
let jiggle_system = |world: &mut World| -> anyhow::Result<()> {
|
||||
let keys = world.get_resource::<InputButtons<KeyCode>>();
|
||||
if keys.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
let keys = keys.unwrap();
|
||||
|
||||
let speed = 0.01;
|
||||
let rot_speed = 1.0;
|
||||
|
||||
let mut dir_x = 0.0;
|
||||
let mut dir_y = 0.0;
|
||||
let mut dir_z = 0.0;
|
||||
|
||||
let mut rot_x = 0.0;
|
||||
let mut rot_y = 0.0;
|
||||
|
||||
if keys.is_pressed(KeyCode::A) {
|
||||
dir_x += speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::D) {
|
||||
dir_x -= speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::S) {
|
||||
dir_y += speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::W) {
|
||||
dir_y -= speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::E) {
|
||||
dir_z += speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::Q) {
|
||||
dir_z -= speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::Left) {
|
||||
rot_y -= rot_speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::Right) {
|
||||
rot_y += rot_speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::Up) {
|
||||
rot_x -= rot_speed;
|
||||
}
|
||||
|
||||
if keys.is_pressed(KeyCode::Down) {
|
||||
rot_x += rot_speed;
|
||||
}
|
||||
|
||||
drop(keys);
|
||||
|
||||
if dir_x == 0.0 && dir_y == 0.0 && dir_z == 0.0 && rot_x == 0.0 && rot_y == 0.0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
//debug!("moving by ({}, {})", dir_x, dir_y);
|
||||
let spin_system = |world: &mut World| -> anyhow::Result<()> {
|
||||
const SPEED: f32 = 5.0;
|
||||
let delta_time = **world.get_resource::<DeltaTime>().unwrap();
|
||||
|
||||
for transform in world.query_mut::<(&mut TransformComponent,)>().iter_mut() {
|
||||
let t = &mut transform.transform;
|
||||
//debug!("Translation: {}", t.translation);
|
||||
//debug!("Rotation: {}", t.rotation);
|
||||
|
||||
/* t.translation += glam::Vec3::new(0.0, 0.001, 0.0);
|
||||
t.translation.x *= -1.0; */
|
||||
t.translation.x += dir_x;
|
||||
t.translation.y += dir_y;
|
||||
t.translation.z += dir_z;
|
||||
t.rotate_x(math::Angle::Degrees(rot_x));
|
||||
t.rotate_y(math::Angle::Degrees(rot_y));
|
||||
}
|
||||
|
||||
let events = world.get_resource_mut::<EventQueue>().unwrap();
|
||||
if let Some(mm) = events.read_events::<MouseMotion>() {
|
||||
debug!("Mouse motion: {:?}", mm);
|
||||
t.rotate_y(math::Angle::Degrees(SPEED * delta_time));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let jiggle_plugin = move |game: &mut Game| {
|
||||
//game.with_system("jiggle", jiggle_system, &["input"]);
|
||||
game.world().insert_resource(TpsAccumulator(0.0));
|
||||
|
||||
let mut sys = BatchedSystem::new();
|
||||
sys.with_criteria(FixedTimestep::new(60));
|
||||
sys.with_system(spin_system);
|
||||
sys.with_system(fps_system);
|
||||
|
||||
game.with_system("fixed", sys, &[]);
|
||||
fps_plugin(game);
|
||||
};
|
||||
|
||||
Game::initialize().await
|
||||
|
@ -166,6 +133,6 @@ async fn main() {
|
|||
.with_startup_system(setup_sys)
|
||||
//.with_plugin(fps_plugin)
|
||||
.with_plugin(jiggle_plugin)
|
||||
.with_plugin(FreeFlyCameraController)
|
||||
.with_plugin(FreeFlyCameraPlugin)
|
||||
.run().await;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use instant::Instant;
|
|||
use crate::plugin::Plugin;
|
||||
|
||||
#[derive(Clone, Component)]
|
||||
pub struct DeltaTime(f32, Instant);
|
||||
pub struct DeltaTime(f32, Option<Instant>);
|
||||
|
||||
impl std::ops::Deref for DeltaTime {
|
||||
type Target = f32;
|
||||
|
@ -25,8 +25,10 @@ impl std::ops::DerefMut for DeltaTime {
|
|||
fn delta_time_system(world: &mut World) -> anyhow::Result<()> {
|
||||
let now = Instant::now();
|
||||
let mut delta = world.get_resource_mut::<DeltaTime>().unwrap();
|
||||
delta.0 = delta.1.elapsed().as_secs_f32();
|
||||
delta.1 = now;
|
||||
delta.0 = delta.1.unwrap_or(now).elapsed().as_secs_f32();
|
||||
delta.1 = Some(now);
|
||||
|
||||
//println!("delta: {}", delta.0);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -35,7 +37,7 @@ pub struct DeltaTimePlugin;
|
|||
|
||||
impl Plugin for DeltaTimePlugin {
|
||||
fn setup(&self, game: &mut crate::game::Game) {
|
||||
game.world().insert_resource(DeltaTime(0.0, Instant::now()));
|
||||
game.world().insert_resource(DeltaTime(0.0, None));
|
||||
game.with_system("delta_time", delta_time_system, &[]);
|
||||
}
|
||||
}
|
148
src/ecs/mod.rs
148
src/ecs/mod.rs
|
@ -1,151 +1,9 @@
|
|||
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, _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 edict::World) -> anyhow::Result<()>
|
||||
{
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
self(world)
|
||||
}
|
||||
}
|
||||
|
||||
/// A system that executes a batch of systems in order that they were given.
|
||||
pub struct BatchedSystem {
|
||||
systems: Vec<Box<dyn SimpleSystem>>,
|
||||
}
|
||||
|
||||
impl BatchedSystem {
|
||||
/// Create a new BatchedSystems. The systems will be executed in the order given.
|
||||
pub fn new(systems: Vec<Box<dyn SimpleSystem>>) -> Self {
|
||||
Self {
|
||||
systems
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SimpleSystem for BatchedSystem {
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
for system in self.systems.iter_mut() {
|
||||
system.execute_mut(world)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
pub mod system;
|
||||
pub use system::*;
|
|
@ -0,0 +1,75 @@
|
|||
use super::{SimpleSystem, Criteria};
|
||||
use edict::World;
|
||||
|
||||
/// 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>>,
|
||||
criteria: Vec<Box<dyn Criteria>>,
|
||||
criteria_checks: u32,
|
||||
}
|
||||
|
||||
impl BatchedSystem {
|
||||
/// Create a new BatchedSystem
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
systems: Vec::new(),
|
||||
criteria: Vec::new(),
|
||||
criteria_checks: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_system<S>(&mut self, system: S) -> &mut Self
|
||||
where
|
||||
S: SimpleSystem + 'static
|
||||
{
|
||||
self.systems.push(Box::new(system));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_criteria<C>(&mut self, criteria: C) -> &mut Self
|
||||
where
|
||||
C: Criteria + 'static
|
||||
{
|
||||
self.criteria.push(Box::new(criteria));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl SimpleSystem for BatchedSystem {
|
||||
fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> {
|
||||
let mut can_run = true;
|
||||
let mut check_again = false;
|
||||
|
||||
for criteria in self.criteria.iter_mut() {
|
||||
match criteria.can_run(world, self.criteria_checks) {
|
||||
super::CriteriaSchedule::Yes => can_run = can_run && true,
|
||||
super::CriteriaSchedule::No => can_run = false,
|
||||
super::CriteriaSchedule::YesAndLoop => {
|
||||
can_run = can_run && true;
|
||||
check_again = can_run && true;
|
||||
},
|
||||
super::CriteriaSchedule::NoAndLoop => {
|
||||
can_run = false;
|
||||
check_again = true;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if can_run {
|
||||
for system in self.systems.iter_mut() {
|
||||
system.execute_mut(world)?;
|
||||
}
|
||||
}
|
||||
|
||||
if check_again {
|
||||
self.criteria_checks += 1;
|
||||
self.execute_mut(world)?;
|
||||
}
|
||||
|
||||
self.criteria_checks = 0;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
pub enum CriteriaSchedule {
|
||||
Yes,
|
||||
No,
|
||||
YesAndLoop,
|
||||
NoAndLoop,
|
||||
}
|
||||
|
||||
pub trait Criteria {
|
||||
/// Checks if this Criteria can run, and if it should check it again.
|
||||
///
|
||||
/// 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 edict::World, check_count: u32) -> CriteriaSchedule;
|
||||
}
|
||||
|
||||
impl<F> Criteria for F
|
||||
where F: FnMut(&mut edict::World, u32) -> CriteriaSchedule
|
||||
{
|
||||
fn can_run(&mut self, world: &mut edict::World, check_count: u32) -> CriteriaSchedule {
|
||||
self(world, check_count)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
pub mod batched;
|
||||
pub use batched::*;
|
||||
|
||||
pub mod criteria;
|
||||
pub use criteria::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use edict::World;
|
||||
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 edict::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(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue