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 12KB

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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. }
  100. else
  101. {
  102. var engineType = engine.GetType();
  103. // Type baseInterface = null;
  104. #if !NETFX_CORE
  105. var baseType = engineType.BaseType;
  106. if (baseType.IsGenericType
  107. #else
  108. var baseType = engineType.GetTypeInfo().BaseType;
  109. if (baseType.IsConstructedGenericType
  110. #endif
  111. && baseType.GetGenericTypeDefinition() == typeof (SingleNodeEngine<>))
  112. {
  113. AddEngine(engine as INodeEngine<INode>, baseType.GetGenericArguments(), _nodeEngines);
  114. }
  115. else
  116. _otherEnginesReferences.Add(engine);
  117. }
  118. if (engine is ICallBackOnAddEngine)
  119. (engine as ICallBackOnAddEngine).Ready();
  120. }
  121. public void BuildEntity(int ID, EntityDescriptor ed)
  122. {
  123. var entityNodes = ed.BuildNodes(ID, (node) =>
  124. {
  125. if (_engineRootWeakReference.IsValid == true)
  126. InternalRemove(node);
  127. });
  128. _nodesToAdd.AddRange(entityNodes);
  129. }
  130. /// <summary>
  131. /// An entity group is a meta entity. It's a way to create a set of entitites that
  132. /// are not easily queriable otherwise. For example you may group existing entities
  133. /// by size and type and then use the groupID to retrieve a single node that is shared
  134. /// among the single entities of the same type and size. This willwd prevent the scenario
  135. /// where the coder is forced to parse all the entities to find the ones of the same
  136. /// size and type. Since the entity group is managed through the shared node, the same
  137. /// shared node must be found on the single entities of the same type and size.
  138. /// The shared node is then used by engines that are meant to manage a group of entities
  139. /// through a single node. The same engine can manage several groups of entitites.
  140. /// </summary>
  141. /// <param name="groupID"></param>
  142. /// <param name="ed"></param>
  143. public void BuildEntityGroup(int groupID, EntityDescriptor ed)
  144. {
  145. var entityNodes = ed.BuildNodes(groupID, (node) =>
  146. {
  147. if (_engineRootWeakReference.IsValid == true)
  148. InternalGroupRemove(node);
  149. });
  150. _groupNodesToAdd.AddRange(entityNodes);
  151. }
  152. static void AddEngine<T>(T engine, Type[] types, Dictionary<Type, FasterList<INodeEngine<INode>>> engines) where T : INodeEngine<INode>
  153. {
  154. for (int i = 0; i < types.Length; i++)
  155. {
  156. FasterList<INodeEngine<INode>> list;
  157. var type = types[i];
  158. if (engines.TryGetValue(type, out list) == false)
  159. {
  160. list = new FasterList<INodeEngine<INode>>();
  161. engines.Add(type, list);
  162. }
  163. list.Add(engine);
  164. }
  165. }
  166. void AddNodeToGroupDB(INode node, Type nodeType)
  167. {
  168. FasterList<INode> nodes;
  169. if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == false)
  170. nodes = _nodesDBgroups[nodeType] = new FasterList<INode>();
  171. nodes.Add(node);
  172. AddNodeToNodesDictionary(node, nodeType);
  173. }
  174. void AddNodeToTheDB<T>(T node, Type nodeType) where T : INode
  175. {
  176. FasterList<INode> nodes;
  177. if (_nodesDB.TryGetValue(nodeType, out nodes) == false)
  178. nodes = _nodesDB[nodeType] = new FasterList<INode>();
  179. nodes.Add(node);
  180. AddNodeToNodesDictionary(node, nodeType);
  181. }
  182. void AddNodeToNodesDictionary<T>(T node, Type nodeType) where T : INode
  183. {
  184. if (node is NodeWithID)
  185. {
  186. Dictionary<int, INode> nodesDic;
  187. if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false)
  188. nodesDic = _nodesDBdic[nodeType] = new Dictionary<int, INode>();
  189. nodesDic[(node as NodeWithID).ID] = node;
  190. }
  191. }
  192. void AddNodeToTheSuitableEngines<T>(T node, Type nodeType) where T : INode
  193. {
  194. FasterList<INodeEngine<INode>> enginesForNode;
  195. if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
  196. {
  197. for (int j = 0; j < enginesForNode.Count; j++)
  198. {
  199. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  200. EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j], node);
  201. #else
  202. enginesForNode[j].Add(node);
  203. #endif
  204. }
  205. }
  206. }
  207. void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode
  208. {
  209. FasterList<INode> nodes;
  210. if (_nodesDB.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 RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INode
  215. {
  216. if (node is NodeWithID)
  217. {
  218. Dictionary<int, INode> nodesDic;
  219. if (_nodesDBdic.TryGetValue(nodeType, out nodesDic))
  220. nodesDic.Remove((node as NodeWithID).ID);
  221. }
  222. }
  223. void RemoveNodeFromGroupDB<T>(T node, Type nodeType) where T : INode
  224. {
  225. FasterList<INode> nodes;
  226. if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == true)
  227. nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero?
  228. RemoveNodeFromNodesDictionary(node, nodeType);
  229. }
  230. void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode
  231. {
  232. FasterList<INodeEngine<INode>> enginesForNode;
  233. if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
  234. {
  235. for (int j = 0; j < enginesForNode.Count; j++)
  236. {
  237. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  238. EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node);
  239. #else
  240. enginesForNode[j].Remove(node);
  241. #endif
  242. }
  243. }
  244. }
  245. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  246. void AddNodeToEngine(INodeEngine<INode> engine, INode node)
  247. {
  248. engine.Add(node);
  249. }
  250. void RemoveNodeFromEngine(INodeEngine<INode> engine, INode node)
  251. {
  252. engine.Remove(node);
  253. }
  254. #endif
  255. void InternalRemove<T>(T node) where T : INode
  256. {
  257. Type nodeType = node.GetType();
  258. RemoveNodeFromEngines(node, nodeType);
  259. RemoveNodeFromTheDB(node, node.GetType());
  260. }
  261. void InternalGroupRemove<T>(T node) where T : INode
  262. {
  263. Type nodeType = node.GetType();
  264. RemoveNodeFromEngines(node, nodeType);
  265. RemoveNodeFromGroupDB(node, node.GetType());
  266. }
  267. Dictionary<Type, FasterList<INodeEngine<INode>>> _nodeEngines;
  268. FasterList<IEngine> _otherEnginesReferences;
  269. Dictionary<Type, FasterList<INode>> _nodesDB;
  270. Dictionary<Type, Dictionary<int, INode>> _nodesDBdic;
  271. Dictionary<Type, FasterList<INode>> _nodesDBgroups;
  272. FasterList<INode> _nodesToAdd;
  273. FasterList<INode> _groupNodesToAdd;
  274. WeakReference _engineRootWeakReference;
  275. }
  276. }