1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use store::StoreBase;
use buffer::BufferBase;
use id_manager::PrimaryIdManager;
use subsystem::SubsystemBase;
use process::ProcessBase;

use ioc::{Ioc, IocBuilder};

use std::fmt::Debug;

pub struct Simulation<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> {
    ids: IdMgr,

    subsystems: Ioc<Key, SsysBase>,
    stores: Ioc<Key, StoBase>,
    buffers: Ioc<Key, BufBase>,

    pipeline: Vec<Ioc<Key, ProcBase>>,

    paused: bool,
}

impl<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> Simulation<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> 
where
    IdMgr: PrimaryIdManager,
    Key: Debug + Ord,
    SsysBase: SubsystemBase,
    StoBase: StoreBase<Id = IdMgr::Id>,
    BufBase: BufferBase,
    ProcBase: ProcessBase<IdMgr, Key, SsysBase, StoBase, BufBase>,
{
    pub fn subsystems(&self) -> &Ioc<Key, SsysBase> { &self.subsystems }

    pub fn update(&mut self){
        if self.is_paused(){ self.unpause(); }

        // trigger `on_before_frame`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_before_frame();
        }

        // clear all event buffers
        for (_, mut buffer) in self.buffers.write_all().unwrap() {
            buffer.clear();
        }

        // run state through the pipeline
        for stage in &self.pipeline {
            for (_, mut process) in stage.write_all().unwrap() {
                process._update(&self.ids, &self.subsystems, &self.stores, &self.buffers);
            }
        }

        // trigger `on_after_frame`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_after_frame();
        }
    }

    pub fn is_paused(&self) -> bool { self.paused }

    pub fn pause(&mut self){
        if self.is_paused() { return; }

        self.paused = true;

        // trigger `on_before_pause`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_before_pause();
        }
    }

    pub fn unpause(&mut self){
        if !self.is_paused() { return; }

        self.paused = false;

        // trigger `on_after_pause`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_after_pause();
        }
    }
}

pub struct SimulationBuilder<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> {
    ids: IdMgr,
    
    subsystems: IocBuilder<Key, SsysBase>,
    stores: IocBuilder<Key, StoBase>,
    buffers: IocBuilder<Key, BufBase>,

    pipeline: Vec<IocBuilder<Key, ProcBase>>,
}

impl<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> SimulationBuilder<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> 
where
    IdMgr: PrimaryIdManager,
    Key: Debug + Ord,
    SsysBase: SubsystemBase,
    StoBase: StoreBase<Id = IdMgr::Id>,
    BufBase: BufferBase,
    ProcBase: ProcessBase<IdMgr, Key, SsysBase, StoBase, BufBase>,
{
    pub fn new(ids: IdMgr) -> Self {
        SimulationBuilder{
            ids: ids, 
            subsystems: IocBuilder::new(), 
            stores: IocBuilder::new(),
            buffers: IocBuilder::new(),
            pipeline: Vec::new(),
        }
    }

    pub fn subsystems(&mut self) -> &mut IocBuilder<Key, SsysBase> { &mut self.subsystems }
    pub fn stores(&mut self) -> &mut IocBuilder<Key, StoBase> { &mut self.stores }
    pub fn buffers(&mut self) -> &mut IocBuilder<Key, BufBase> { &mut self.buffers }

    /// TODO: This isn't very user-friendly. Currently works fine if you have a fixed amount
    /// of stages, but beyond that it's quite whacky.
    pub fn pipeline(&mut self) -> &mut Vec<IocBuilder<Key, ProcBase>> { &mut self.pipeline }

    pub fn build(self) -> Simulation<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> {
        Simulation{ 
            ids: self.ids, 
            subsystems: self.subsystems.build(),
            stores: self.stores.build(),
            buffers: self.buffers.build(),
            pipeline: self.pipeline.into_iter().map(|stage| stage.build()).collect(),
            paused: false,
        }
    }
}