Mirror of Svelto.ECS because we're a fan of it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EnginesRoot.cs 11KB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Svelto.DataStructures;
  5. using UnityEngine;
  6. using WeakReference = Svelto.DataStructures.WeakReference<Svelto.ECS.EnginesRoot>;
  7. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  8. using Svelto.ECS.Profiler;
  9. #endif
  10. namespace Svelto.ECS
  11. {
  12. class Scheduler : MonoBehaviour
  13. {
  14. IEnumerator Start()
  15. {
  16. while (true)
  17. {
  18. yield return new WaitForEndOfFrame();
  19. OnTick();
  20. }
  21. }
  22. internal Action OnTick;
  23. }
  24. public sealed class EnginesRoot : IEnginesRoot, IEntityFactory
  25. {
  26. public EnginesRoot()
  27. {
  28. _nodeEngines = new Dictionary<Type, FasterList<INodeEngine<INode>>>();
  29. _engineRootWeakReference = new WeakReference(this);
  30. _otherEnginesReferences = new FasterList<IEngine>();
  31. _nodesDB = new Dictionary<Type, FasterList<INode>>();
  32. _nodesDBdic = new Dictionary<Type, Dictionary<int, INode>>();
  33. _nodesToAdd = new FasterList<INode>();
  34. _groupNodesToAdd = new FasterList<INode>();
  35. _nodesDBgroups = new Dictionary<Type, FasterList<INode>>();
  36. GameObject go = new GameObject("ECSScheduler");
  37. go.AddComponent<Scheduler>().OnTick += SubmitNodes;
  38. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  39. GameObject debugEngineObject = new GameObject("Engine Debugger");
  40. debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>();
  41. #endif
  42. }
  43. void SubmitNodes()
  44. {
  45. int groupNodesCount;
  46. int nodesCount;
  47. bool newNodesHaveBeenAddedWhileIterating;
  48. int startNodes = 0;
  49. int startGroupNodes = 0;
  50. int numberOfReenteringLoops = 0;
  51. do
  52. {
  53. groupNodesCount = _groupNodesToAdd.Count;
  54. nodesCount = _nodesToAdd.Count;
  55. for (int i = startNodes; i < nodesCount; i++)
  56. {
  57. var node = _nodesToAdd[i];
  58. AddNodeToTheDB(node, node.GetType());
  59. }
  60. for (int i = startGroupNodes; i < groupNodesCount; i++)
  61. {
  62. var node = _groupNodesToAdd[i];
  63. AddNodeToGroupDB(node, node.GetType());
  64. }
  65. for (int i = startNodes; i < nodesCount; i++)
  66. {
  67. var node = _nodesToAdd[i];
  68. AddNodeToTheSuitableEngines(node, node.GetType());
  69. }
  70. for (int i = startGroupNodes; i < groupNodesCount; i++)
  71. {
  72. var node = _groupNodesToAdd[i];
  73. AddNodeToTheSuitableEngines(node, node.GetType());
  74. }
  75. newNodesHaveBeenAddedWhileIterating = _groupNodesToAdd.Count > groupNodesCount || _nodesToAdd.Count > nodesCount;
  76. startNodes = nodesCount;
  77. startGroupNodes = groupNodesCount;
  78. if (numberOfReenteringLoops > 5)
  79. throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method");
  80. numberOfReenteringLoops++;
  81. } while (newNodesHaveBeenAddedWhileIterating);
  82. _nodesToAdd.Clear();
  83. _groupNodesToAdd.Clear();
  84. }
  85. public void AddEngine(IEngine engine)
  86. {
  87. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  88. EngineProfiler.AddEngine(engine);
  89. #endif
  90. if (engine is IQueryableNodeEngine)
  91. (engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic, _nodesDBgroups);
  92. if (engine is INodesEngine)
  93. {
  94. var nodesEngine = engine as INodesEngine;
  95. AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines);
  96. return;
  97. }
  98. /* var baseType = engine.GetType().BaseType;
  99. if (baseType.IsGenericType)
  100. {
  101. var genericType = baseType.GetGenericTypeDefinition();
  102. if (genericType == typeof(SingleNodeEngine<>))
  103. {
  104. AddEngine(engine as INodeEngine<INode>, baseType.GetGenericArguments(), _nodeEngines);
  105. return;
  106. }
  107. }*/
  108. _otherEnginesReferences.Add(engine);
  109. }
  110. public void BuildEntity(int ID, EntityDescriptor ed)
  111. {
  112. var entityNodes = ed.BuildNodes(ID, (node) =>
  113. {
  114. if (_engineRootWeakReference.IsValid == true)
  115. InternalRemove(node);
  116. });
  117. _nodesToAdd.AddRange(entityNodes);
  118. }
  119. public void BuildEntityGroup(int groupID, EntityDescriptor ed)
  120. {
  121. var entityNodes = ed.BuildNodes(groupID, (node) =>
  122. {
  123. if (_engineRootWeakReference.IsValid == true)
  124. InternalGroupRemove(node);
  125. });
  126. _groupNodesToAdd.AddRange(entityNodes);
  127. }
  128. static void AddEngine<T>(T engine, Type[] types, Dictionary<Type, FasterList<INodeEngine<INode>>> engines) where T : INodeEngine<INode>
  129. {
  130. for (int i = 0; i < types.Length; i++)
  131. {
  132. FasterList<INodeEngine<INode>> list;
  133. var type = types[i];
  134. if (engines.TryGetValue(type, out list) == false)
  135. {
  136. list = new FasterList<INodeEngine<INode>>();
  137. engines.Add(type, list);
  138. }
  139. list.Add(engine);
  140. }
  141. }
  142. void AddNodeToGroupDB(INode node, Type nodeType)
  143. {
  144. FasterList<INode> nodes;
  145. if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == false)
  146. nodes = _nodesDBgroups[nodeType] = new FasterList<INode>();
  147. nodes.Add(node);
  148. AddNodeToNodesDictionary(node, nodeType);
  149. }
  150. void AddNodeToTheDB<T>(T node, Type nodeType) where T : INode
  151. {
  152. FasterList<INode> nodes;
  153. if (_nodesDB.TryGetValue(nodeType, out nodes) == false)
  154. nodes = _nodesDB[nodeType] = new FasterList<INode>();
  155. nodes.Add(node);
  156. AddNodeToNodesDictionary(node, nodeType);
  157. }
  158. void AddNodeToNodesDictionary<T>(T node, Type nodeType) where T : INode
  159. {
  160. if (node is NodeWithID)
  161. {
  162. Dictionary<int, INode> nodesDic;
  163. if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false)
  164. nodesDic = _nodesDBdic[nodeType] = new Dictionary<int, INode>();
  165. nodesDic[(node as NodeWithID).ID] = node;
  166. }
  167. }
  168. void AddNodeToTheSuitableEngines<T>(T node, Type nodeType) where T : INode
  169. {
  170. FasterList<INodeEngine<INode>> enginesForNode;
  171. if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
  172. {
  173. for (int j = 0; j < enginesForNode.Count; j++)
  174. {
  175. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  176. EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j], node);
  177. #else
  178. enginesForNode[j].Add(node);
  179. #endif
  180. }
  181. }
  182. }
  183. void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode
  184. {
  185. FasterList<INode> nodes;
  186. if (_nodesDB.TryGetValue(nodeType, out nodes) == true)
  187. nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero?
  188. RemoveNodeFromNodesDictionary(node, nodeType);
  189. }
  190. void RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INode
  191. {
  192. if (node is NodeWithID)
  193. {
  194. Dictionary<int, INode> nodesDic;
  195. if (_nodesDBdic.TryGetValue(nodeType, out nodesDic))
  196. nodesDic.Remove((node as NodeWithID).ID);
  197. }
  198. }
  199. void RemoveNodeFromGroupDB<T>(T node, Type nodeType) where T : INode
  200. {
  201. FasterList<INode> nodes;
  202. if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == true)
  203. nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero?
  204. RemoveNodeFromNodesDictionary(node, nodeType);
  205. }
  206. void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode
  207. {
  208. FasterList<INodeEngine<INode>> enginesForNode;
  209. if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
  210. {
  211. for (int j = 0; j < enginesForNode.Count; j++)
  212. {
  213. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  214. EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node);
  215. #else
  216. enginesForNode[j].Remove(node);
  217. #endif
  218. }
  219. }
  220. }
  221. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  222. void AddNodeToEngine(INodeEngine<INode> engine, INode node)
  223. {
  224. engine.Add(node);
  225. }
  226. void RemoveNodeFromEngine(INodeEngine<INode> engine, INode node)
  227. {
  228. engine.Remove(node);
  229. }
  230. #endif
  231. void InternalRemove<T>(T node) where T : INode
  232. {
  233. Type nodeType = node.GetType();
  234. RemoveNodeFromEngines(node, nodeType);
  235. RemoveNodeFromTheDB(node, node.GetType());
  236. }
  237. void InternalGroupRemove<T>(T node) where T : INode
  238. {
  239. Type nodeType = node.GetType();
  240. RemoveNodeFromEngines(node, nodeType);
  241. RemoveNodeFromGroupDB(node, node.GetType());
  242. }
  243. Dictionary<Type, FasterList<INodeEngine<INode>>> _nodeEngines;
  244. FasterList<IEngine> _otherEnginesReferences;
  245. Dictionary<Type, FasterList<INode>> _nodesDB;
  246. Dictionary<Type, Dictionary<int, INode>> _nodesDBdic;
  247. Dictionary<Type, FasterList<INode>> _nodesDBgroups;
  248. FasterList<INode> _nodesToAdd;
  249. FasterList<INode> _groupNodesToAdd;
  250. WeakReference _engineRootWeakReference;
  251. //integrated pooling system
  252. //add debug panel like Entitas has
  253. //GCHandle should be used to reduce the number of strong references
  254. //datastructure could be thread safe
  255. //future enhancements:
  256. }
  257. }