GameActionsController.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. using System;
  2. using System.Linq;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using Sirenix.OdinInspector;
  7. using UniRx;
  8. using KairoEngine.Core;
  9. namespace KairoEngine.Core.GameActions
  10. {
  11. [System.Serializable]
  12. public class GameActionsController : ISerializationCallbackReceiver
  13. {
  14. /// <summary>A context object that holds a list of GameActionContextVariables to be accessible for GameActions to use.</summary>
  15. [InlineProperty, HideLabel, ShowIf("showContext")]
  16. public GameActionContext context = new GameActionContext();
  17. [HideInInspector] public bool showContext = false;
  18. /// <summary>A list of GameActions to be executed in order.</summary>
  19. [ListDrawerSettings(HideAddButton = true, HideRemoveButton = false, DraggableItems = true, Expanded = false, ShowPaging = false, ShowItemCount = true)]
  20. [ShowInInspector, NonSerialized, OnInspectorInit("InitializeActionList")]
  21. [Space(4)]
  22. public List<GameAction> actions = new List<GameAction>();
  23. [NonSerialized] private CompositeDisposable cancel;
  24. private int actionIndex = 0;
  25. public bool started => _started;
  26. public bool isDone => _done;
  27. private bool _started = false;
  28. private bool _done = false;
  29. [HideInInspector] public int depth = 0;
  30. #region FlowControl
  31. /// <summary>Run GameActions on this controller. Each action will be fired after the previous action ended.</summary>
  32. public void Start()
  33. {
  34. actionIndex = 0;
  35. _done = false;
  36. _started = true;
  37. var observable = Observable.EveryUpdate();
  38. cancel = new CompositeDisposable();
  39. observable.Subscribe(xs => ExecuteActions()).AddTo(cancel);
  40. }
  41. /// <summary>Executes GameActions until it has to wait for an Update or reach the end of the action list.</summary>
  42. private void ExecuteActions()
  43. {
  44. if(actionIndex >= actions.Count)
  45. {
  46. // done
  47. _done = true;
  48. cancel.Dispose();
  49. return;
  50. }
  51. if(actions[actionIndex].done)
  52. {
  53. actionIndex += 1;
  54. ExecuteActions();
  55. }
  56. else
  57. {
  58. if(actions[actionIndex].started == false)
  59. {
  60. actions[actionIndex].Start();
  61. ExecuteActions();
  62. }
  63. else actions[actionIndex].Update();
  64. }
  65. }
  66. /// <summary>Stop executing GameActions on this controller.</summary>
  67. public void Stop()
  68. {
  69. if(cancel != null) cancel.Dispose();
  70. }
  71. public void Restart()
  72. {
  73. actionIndex = 0;
  74. _started = false;
  75. _done = false;
  76. foreach (var action in actions) action.Restart();
  77. }
  78. #endregion
  79. #region Serialization
  80. [SerializeField, HideInInspector] private List<string> serializedActions = new List<string>();
  81. [SerializeField, HideInInspector] public GameActionObjectSerializer objectSerializer = new GameActionObjectSerializer();
  82. private void SerializeActions()
  83. {
  84. if(actions == null) return;
  85. serializedActions = new List<string>();
  86. objectSerializer.ClearGameObjects();
  87. objectSerializer.ClearScriptableObjects();
  88. for (int i = 0; i < actions.Count; i++)
  89. {
  90. actions[i].OnBeforeSerialize(objectSerializer, i, depth);
  91. string data = JsonUtility.ToJson(actions[i]);
  92. serializedActions.Add(data);
  93. }
  94. }
  95. private void DeserializeActions()
  96. {
  97. if(serializedActions == null) return;
  98. if(actions == null) actions = new List<GameAction>();
  99. if(actions.Count > 0) actions.Clear();
  100. for (int i = 0; i < serializedActions.Count; i++)
  101. {
  102. GameAction action = JsonUtility.FromJson<GameActionBase>(serializedActions[i]);
  103. action = GameAction.InvokeStringMethod(action.className, action.typeName, serializedActions[i]);
  104. action.controller = this;
  105. action.OnBeforeDeserialize(objectSerializer, i, depth);
  106. actions.Add(action);
  107. // Type t = Type.GetType(action.typeName);
  108. // dynamic obj = Convert.ChangeType(action, t);
  109. // if(obj != null) actions.Add(obj.Duplicate());
  110. // else if(action != null) actions.Add(action);
  111. }
  112. for (int i = 0; i < actions.Count; i++)
  113. {
  114. actions[i].Initialize(objectSerializer);
  115. }
  116. objectSerializer.ClearGameObjects();
  117. objectSerializer.ClearScriptableObjects();
  118. //serializedActions = new List<string>();
  119. }
  120. public void OnBeforeSerialize() => SerializeActions();
  121. public void OnAfterDeserialize() => DeserializeActions();
  122. #endregion
  123. #region NewAction
  124. [OnInspectorInit("GetCompatibleVariablenames"), OnValueChanged("AddNewAction")]
  125. [ValueDropdown("possibleActions", IsUniqueList = false)]
  126. [LabelText("Add New Action")]
  127. [NonSerialized]
  128. public GameAction newAction;
  129. [NonSerialized] private IEnumerable possibleActions = new ValueDropdownList<GameAction>();
  130. private void GetCompatibleVariablenames()
  131. {
  132. possibleActions = ReflectiveEnumerator.GetEnumerableOfType<GameAction>(this)
  133. .Where(x => x.GetTypeName() != "GameActionBase")
  134. .Where(x => x.GetTypeName() != "GameAction")
  135. .Select(x => new ValueDropdownItem(x.GetActionName(), x));
  136. }
  137. private void AddNewAction()
  138. {
  139. if(newAction != null)
  140. {
  141. newAction.controller = this;
  142. newAction.className = newAction.GetType().AssemblyQualifiedName;
  143. actions.Add(newAction);
  144. newAction = null;
  145. }
  146. }
  147. #endregion
  148. #region Utilities
  149. private void InitializeActionList()
  150. {
  151. if(actions == null) actions = new List<GameAction>();
  152. foreach (var action in actions)
  153. {
  154. action.controller = this;
  155. }
  156. }
  157. public GameActionsController Duplicate()
  158. {
  159. GameActionsController newController = new GameActionsController();
  160. newController.actions = new List<GameAction>();
  161. var newSerializedActions = new List<string>();
  162. objectSerializer.ClearGameObjects();
  163. for (int i = 0; i < actions.Count; i++)
  164. {
  165. actions[i].OnBeforeSerialize(objectSerializer, i, depth);
  166. string data = JsonUtility.ToJson(actions[i]);
  167. newSerializedActions.Add(data);
  168. }
  169. newController.objectSerializer = objectSerializer;
  170. objectSerializer = new GameActionObjectSerializer();
  171. newController.context = this.context.Duplicate();
  172. for (int i = 0; i < newSerializedActions.Count; i++)
  173. {
  174. //Debug.Log(newSerializedActions[i]);
  175. GameAction action = JsonUtility.FromJson<GameActionBase>(newSerializedActions[i]);
  176. if(action == null) continue;
  177. action = GameAction.InvokeStringMethod(action.className, action.typeName, newSerializedActions[i]);
  178. action.controller = newController;
  179. action.OnBeforeDeserialize(newController.objectSerializer, i, depth);
  180. newController.actions.Add(action);
  181. }
  182. newController.objectSerializer.ClearGameObjects();
  183. return newController;
  184. }
  185. #endregion
  186. }
  187. }