1 /**
2  * This is a state machine for the Engine. The state machine manages a set of states,
3  * each of which has a set of System providers. When the state machine changes the state, it removes
4  * Systems associated with the previous state and adds Systems associated with the new state.
5  */
6 module ashd.fsm.engineStateMachine;
7 
8 import ashd.core.engine        : Engine;
9 import ashd.core.system        : System;
10 import ashd.fsm.engineState    : EngineState;
11 import ashd.fsm.ISystemProvider: ISystemProvider;
12 
13 
14 
15 
16 public class EngineStateMachine
17 {
18     private
19     {
20         Engine              mEngine;
21         EngineState[string] mStates;
22         EngineState         mCurrentState;
23     }
24     /**
25      * Constructor. Creates an SystemStateMachine.
26      */
27     public this( Engine engine_a )
28     {
29         mEngine = engine_a;
30     }
31 
32     /**
33      * Add a state to this state machine.
34      *
35      * @param name The name of this state - used to identify it later in the changeState method call.
36      * @param state The state.
37      * @return This state machine, so methods can be chained.
38      */
39     public EngineStateMachine addState( string name_a, EngineState state_a )
40     {
41         mStates[name_a] = state_a;
42         return this;
43     }
44 
45     /**
46      * Create a new state in this state machine.
47      *
48      * @param name The name of the new state - used to identify it later in the changeState method call.
49      * @return The new EntityState object that is the state. This will need to be configured with
50      * the appropriate component providers.
51      */
52     public EngineState createState( string name_a )
53     {
54         EngineState state = new EngineState();
55 
56         mStates[name_a] = state;
57         return state;
58     }
59 
60     /**
61      * Change to a new state. The Systems from the old state will be removed and the Systems
62      * for the new state will be added.
63      *
64      * @param name The name of the state to change to.
65      */
66     public void changeState( string name_a )
67     {
68         if ( name_a !in mStates )
69         {
70             throw( new Exception( "Engine state "~name_a~" doesn't exist" ) );
71         }
72 
73         EngineState newState = mStates[name_a];
74         if ( newState == mCurrentState )
75         {
76             newState = null;
77             return;
78         }
79 
80 
81         ISystemProvider[ClassInfo] toAdd = newState.providers();
82 
83         if ( mCurrentState )
84         {
85             foreach ( key, provider; mCurrentState.providers )
86             {
87                 hash_t id = provider.identifier;
88                 if ( (key in toAdd) && (toAdd[key].identifier == id) )
89                 {
90                     toAdd.remove(key);
91                 }
92                 else
93                 {
94                     mEngine.removeSystem( provider.getSystem(key) );
95                 }
96             }
97         }
98 
99         foreach ( key, provider; toAdd )
100         {
101             System tmpSystem = provider.getSystem(key);
102             mEngine.addSystem( tmpSystem, key, provider.priority );
103         }
104         mCurrentState = newState;
105     }
106 }