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