From cc5458b51e14829daa282993c04452e2de3432bd Mon Sep 17 00:00:00 2001
From: erheine <erheine@nps.edu>
Date: Tue, 24 Mar 2020 10:26:13 -0700
Subject: [PATCH] Added a class that fires game events based on its current
 state.

---
 State Manager.meta                            | 10 +++
 State Manager/Shared.StateManager.asmdef      | 15 ++++
 State Manager/Shared.StateManager.asmdef.meta |  7 ++
 State Manager/State.cs                        | 32 ++++++++
 State Manager/State.cs.meta                   | 11 +++
 State Manager/StateManager.cs                 | 76 +++++++++++++++++++
 State Manager/StateManager.cs.meta            | 11 +++
 package.json                                  |  2 +-
 8 files changed, 163 insertions(+), 1 deletion(-)
 create mode 100644 State Manager.meta
 create mode 100644 State Manager/Shared.StateManager.asmdef
 create mode 100644 State Manager/Shared.StateManager.asmdef.meta
 create mode 100644 State Manager/State.cs
 create mode 100644 State Manager/State.cs.meta
 create mode 100644 State Manager/StateManager.cs
 create mode 100644 State Manager/StateManager.cs.meta

diff --git a/State Manager.meta b/State Manager.meta
new file mode 100644
index 0000000..fe7ec35
--- /dev/null
+++ b/State Manager.meta	
@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: a51ef5da8031fd141a078805d54ccb66
+folderAsset: yes
+timeCreated: 1510599145
+licenseType: Pro
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/State Manager/Shared.StateManager.asmdef b/State Manager/Shared.StateManager.asmdef
new file mode 100644
index 0000000..44340e4
--- /dev/null
+++ b/State Manager/Shared.StateManager.asmdef	
@@ -0,0 +1,15 @@
+{
+    "name": "Shared.StateManager",
+    "references": [
+        "GUID:6735fe1fe1dbd994a96eb9d888b81400"
+    ],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}
\ No newline at end of file
diff --git a/State Manager/Shared.StateManager.asmdef.meta b/State Manager/Shared.StateManager.asmdef.meta
new file mode 100644
index 0000000..57cd66d
--- /dev/null
+++ b/State Manager/Shared.StateManager.asmdef.meta	
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: bf6ca905532d08647bc1c0964551b0f5
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/State Manager/State.cs b/State Manager/State.cs
new file mode 100644
index 0000000..8278e89
--- /dev/null
+++ b/State Manager/State.cs	
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using UnityEngine;
+using Shared.ScriptableVariables;
+
+namespace Shared.StateManager {
+  // A scriptable object that represents one state a StateManager can be in
+  [CreateAssetMenu(menuName = "Scriptable Objects/State")]
+  public class State : ScriptableObject {
+    [Tooltip("The GameEvent that will switch a StateManager into this State")]
+    public GameEvent enterEvent;
+
+    [Tooltip("The list of GameEvents to fire when this State gets activated")]
+    public List<GameEvent> inEvents = new List<GameEvent>();
+
+    [Tooltip("The list of GameEvents to fire when this State gets deactivated")]
+    public List<GameEvent> outEvents = new List<GameEvent>();
+
+    // ------------------------------------------------------------------------
+    public void EnterState() {
+      foreach (var inEvent in inEvents) {
+        inEvent?.Raise();
+      }
+    }
+
+    // ------------------------------------------------------------------------
+    public void ExitState() {
+      foreach (var outEvent in outEvents) {
+        outEvent?.Raise();
+      }
+    }
+  }
+}
diff --git a/State Manager/State.cs.meta b/State Manager/State.cs.meta
new file mode 100644
index 0000000..0b5da36
--- /dev/null
+++ b/State Manager/State.cs.meta	
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f4ee41ed730737741b3c93effc4fb5a9
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/State Manager/StateManager.cs b/State Manager/StateManager.cs
new file mode 100644
index 0000000..9a0575c
--- /dev/null
+++ b/State Manager/StateManager.cs	
@@ -0,0 +1,76 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Shared.ScriptableVariables;
+
+namespace Shared.StateManager {
+  // Manages what State is currently active in a given scene
+  public class StateManager : MonoBehaviour {
+    [Tooltip("The state we should start out with when this manager is enabled")]
+    public State startingState;
+
+    [Tooltip("The list of possible states this component is managing")]
+    public List<State> possibleStates = new List<State>();
+
+    [Tooltip("The currently active state for this manager")]
+    [SerializeField]
+    private State currentState;
+
+    // A list of delegates the possible states are listening to for entering so
+    // we can stop listening on disable
+    private Dictionary<State, GameEvent.GameEventRaised> stateListeners = new Dictionary<State, GameEvent.GameEventRaised>();
+
+    // ------------------------------------------------------------------------
+    void OnEnable() {
+      StartCoroutine(ActivateStartingState());
+
+      // Start listening to the events that will change our state
+      foreach (var state in possibleStates) {
+        GameEvent.GameEventRaised listener = delegate() { ActivateState(state); };
+        state.enterEvent.OnRaised += listener;
+        stateListeners.Add(state, listener);
+      }
+    }
+
+    // ------------------------------------------------------------------------
+    void OnDisable() {
+      if (currentState != null) {
+        DeactivateState(currentState);
+      }
+
+      // Stop listening to the events that will change our state
+      foreach (var state in possibleStates) {
+        state.enterEvent.OnRaised -= stateListeners[state];
+      }
+      stateListeners.Clear();
+    }
+
+    // ------------------------------------------------------------------------
+    private IEnumerator ActivateStartingState() {
+      // Wait one frame to make sure all starting listeners have a chance to setup
+      yield return null;
+      ActivateState(startingState);
+    }
+
+    // ------------------------------------------------------------------------
+    private void ActivateState(State state) {
+      // Can't transition into a state we're already in
+      if (currentState != state) {
+        if (currentState != null) {
+          DeactivateState(currentState);
+        }
+
+        currentState = state;
+        state.EnterState();
+      }
+    }
+
+    // ------------------------------------------------------------------------
+    private void DeactivateState(State state) {
+      if (state == currentState) {
+        currentState = null;
+      }
+      state.ExitState();
+    }
+  }
+}
diff --git a/State Manager/StateManager.cs.meta b/State Manager/StateManager.cs.meta
new file mode 100644
index 0000000..1d78084
--- /dev/null
+++ b/State Manager/StateManager.cs.meta	
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: a55df0166f51f7941954952e3c47dfa0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/package.json b/package.json
index 8f386ad..75c1eb8 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
 	"name": "com.futuretech.shared",
 	"displayName": "FutureTech Shared",
 	"description": "Contains shared items such as the Scriptable Variables.",
-	"version": "0.1.23",
+	"version": "0.1.24",
 	"unity": "2019.2",
 	"license": "MIT",
 	"repository": {
-- 
GitLab