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

9 years ago
7 years ago
7 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. using System;
  2. using System.Collections.Generic;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS.Internal;
  5. using Svelto.ECS.NodeSchedulers;
  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. public sealed class EnginesRoot : IEnginesRoot, IEntityFactory
  16. {
  17. public EnginesRoot(NodeSubmissionScheduler nodeScheduler)
  18. {
  19. _nodeEngines = new Dictionary<Type, FasterList<IEngine>>();
  20. _activableEngines = new Dictionary<Type, FasterList<IEngine>>();
  21. _otherEngines = new FasterList<IEngine>();
  22. _engineRootWeakReference = new WeakReference(this);
  23. _nodesDB = new Dictionary<Type, FasterList<INode>>();
  24. _nodesDBdic = new Dictionary<Type, Dictionary<int, INode>>();
  25. _nodesToAdd = new FasterList<INode>();
  26. _metaNodesToAdd = new FasterList<INode>();
  27. _metaNodesDB = new Dictionary<Type, FasterList<INode>>();
  28. _sharedStructNodeLists = new SharedStructNodeLists();
  29. _sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists();
  30. _internalRemove = InternalRemove;
  31. _internalDisable = InternalDisable;
  32. _internalEnable = InternalEnable;
  33. _internalMetaRemove = InternalMetaRemove;
  34. _scheduler = nodeScheduler;
  35. _scheduler.Schedule(SubmitNodes);
  36. _structNodeEngineType = typeof(IStructNodeEngine<>);
  37. _groupedStructNodesEngineType = typeof(IGroupedStructNodesEngine<>);
  38. _activableNodeEngineType = typeof(IActivableNodeEngine<>);
  39. _implementedInterfaceTypes = new Dictionary<Type, Type[]>();
  40. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  41. GameObject debugEngineObject = new GameObject("Engine Debugger");
  42. debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>();
  43. #endif
  44. }
  45. void SubmitNodes()
  46. {
  47. int metaNodesCount = _metaNodesToAdd.Count;
  48. int nodesCount = _nodesToAdd.Count;
  49. if (metaNodesCount + nodesCount == 0) return;
  50. bool newNodesHaveBeenAddedWhileIterating;
  51. int startNodes = 0;
  52. int startMetaNodes = 0;
  53. int numberOfReenteringLoops = 0;
  54. do
  55. {
  56. var nodesToAdd = _nodesToAdd.ToArrayFast();
  57. for (int i = startNodes; i < nodesCount; i++)
  58. {
  59. var node = nodesToAdd[i];
  60. var nodeType = node.GetType();
  61. AddNodeToTheDB(node, nodeType);
  62. var nodeWithId = node as INodeWithID;
  63. if (nodeWithId != null)
  64. AddNodeToNodesDictionary(nodeWithId, nodeType);
  65. }
  66. var metaNodesToAdd = _metaNodesToAdd.ToArrayFast();
  67. for (int i = startMetaNodes; i < metaNodesCount; i++)
  68. {
  69. var node = metaNodesToAdd[i];
  70. var nodeType = node.GetType();
  71. AddNodeToMetaDB(node, nodeType);
  72. var nodeWithId = node as INodeWithID;
  73. if (nodeWithId != null)
  74. AddNodeToNodesDictionary(nodeWithId, nodeType);
  75. }
  76. for (int i = startNodes; i < nodesCount; i++)
  77. {
  78. var node = nodesToAdd[i];
  79. AddNodeToTheSuitableEngines(node, node.GetType());
  80. }
  81. for (int i = startMetaNodes; i < metaNodesCount; i++)
  82. {
  83. var node = metaNodesToAdd[i];
  84. AddNodeToTheSuitableEngines(node, node.GetType());
  85. }
  86. newNodesHaveBeenAddedWhileIterating =
  87. _metaNodesToAdd.Count > metaNodesCount ||
  88. _nodesToAdd.Count > nodesCount;
  89. startNodes = nodesCount;
  90. startMetaNodes = metaNodesCount;
  91. if (numberOfReenteringLoops > 5)
  92. throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method");
  93. numberOfReenteringLoops++;
  94. metaNodesCount = _metaNodesToAdd.Count;
  95. nodesCount = _nodesToAdd.Count;
  96. } while (newNodesHaveBeenAddedWhileIterating);
  97. _nodesToAdd.Clear();
  98. _metaNodesToAdd.Clear();
  99. }
  100. public void AddEngine(IEngine engine)
  101. {
  102. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  103. EngineProfiler.AddEngine(engine);
  104. #endif
  105. var queryableNodeEngine = engine as IQueryableNodeEngine;
  106. if (queryableNodeEngine != null)
  107. queryableNodeEngine.nodesDB =
  108. new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB);
  109. var engineType = engine.GetType();
  110. var implementedInterfaces = engineType.GetInterfaces();
  111. CollectImplementedInterfaces(implementedInterfaces);
  112. var engineAdded = CheckGenericEngines(engine);
  113. if (CheckLegacyNodesEngine(engine, ref engineAdded) == false)
  114. CheckNodesEngine(engine, engineType, ref engineAdded);
  115. if (engineAdded == false)
  116. _otherEngines.Add(engine);
  117. var callBackOnAddEngine = engine as ICallBackOnAddEngine;
  118. if (callBackOnAddEngine != null)
  119. callBackOnAddEngine.Ready();
  120. }
  121. void CollectImplementedInterfaces(Type[] implementedInterfaces)
  122. {
  123. _implementedInterfaceTypes.Clear();
  124. var type = typeof(IEngine);
  125. for (int index = 0; index < implementedInterfaces.Length; index++)
  126. {
  127. var interfaceType = implementedInterfaces[index];
  128. if (type.IsAssignableFrom(interfaceType) == false)
  129. continue;
  130. #if !NETFX_CORE
  131. if (false == interfaceType.IsGenericType)
  132. #else
  133. if (false == interfaceType.IsConstructedGenericType)
  134. #endif
  135. {
  136. continue;
  137. }
  138. var genericTypeDefinition = interfaceType.GetGenericTypeDefinition();
  139. _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments());
  140. }
  141. }
  142. bool CheckGenericEngines(IEngine engine)
  143. {
  144. if (_implementedInterfaceTypes.Count == 0) return false;
  145. bool engineAdded = false;
  146. if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType))
  147. {
  148. ((IStructNodeEngine)engine).CreateStructNodes
  149. (_sharedStructNodeLists);
  150. }
  151. if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType))
  152. {
  153. ((IGroupedStructNodesEngine)engine).CreateStructNodes
  154. (_sharedGroupedStructNodeLists);
  155. }
  156. Type[] arguments;
  157. if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType,
  158. out arguments))
  159. {
  160. AddEngine(engine, arguments, _activableEngines);
  161. engineAdded = true;
  162. }
  163. return engineAdded;
  164. }
  165. bool CheckLegacyNodesEngine(IEngine engine, ref bool engineAdded)
  166. {
  167. var nodesEngine = engine as INodesEngine;
  168. if (nodesEngine != null)
  169. {
  170. AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines);
  171. engineAdded = true;
  172. return true;
  173. }
  174. return false;
  175. }
  176. bool CheckNodesEngine(IEngine engine, Type engineType, ref bool engineAdded)
  177. {
  178. #if !NETFX_CORE
  179. var baseType = engineType.BaseType;
  180. if (baseType.IsGenericType
  181. #else
  182. var baseType = engineType.GetTypeInfo().BaseType;
  183. if (baseType.IsConstructedGenericType
  184. #endif
  185. && engine is INodeEngine)
  186. {
  187. AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines);
  188. engineAdded = true;
  189. return true;
  190. }
  191. return false;
  192. }
  193. public void BuildEntity(int ID, EntityDescriptor ed)
  194. {
  195. var entityNodes = ed.BuildNodes(ID,
  196. _internalRemove,
  197. _internalEnable,
  198. _internalDisable
  199. );
  200. _nodesToAdd.AddRange(entityNodes);
  201. }
  202. /// <summary>
  203. /// A meta entity is a way to manage a set of entitites that are not easily
  204. /// queriable otherwise. For example you may want to group existing entities
  205. /// by size and type and then use the meta entity node to manage the data
  206. /// shared among the single entities of the same type and size. This will
  207. /// prevent the scenario where the coder is forced to parse all the entities to
  208. /// find the ones of the same size and type.
  209. /// Since the entities are managed through the shared node, the same
  210. /// shared node must be found on the single entities of the same type and size.
  211. /// The shared node of the meta entity is then used by engines that are meant
  212. /// to manage a group of entities through a single node.
  213. /// The same engine can manage several meta entities nodes too.
  214. /// The Engine manages the logic of the Meta Node data and other engines
  215. /// can read back this data through the normal entity as the shared node
  216. /// will be present in their descriptor too.
  217. /// </summary>
  218. /// <param name="metaEntityID"></param>
  219. /// <param name="ed"></param>
  220. public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed)
  221. {
  222. var entityNodes = ed.BuildNodes(metaEntityID,
  223. _internalMetaRemove,
  224. _internalEnable,
  225. _internalDisable
  226. );
  227. _metaNodesToAdd.AddRange(entityNodes);
  228. }
  229. /// <summary>
  230. /// Using this function is like building a normal entity, but the nodes
  231. /// are grouped by groupID to be better processed inside engines and
  232. /// improve cache locality. Only IGroupStructNodeWithID nodes are grouped
  233. /// other nodes are managed as usual.
  234. /// </summary>
  235. /// <param name="entityID"></param>
  236. /// <param name="groupID"></param>
  237. /// <param name="ed"></param>
  238. public void BuildEntityInGroup(int entityID, int groupID,
  239. EntityDescriptor ed)
  240. {
  241. var entityNodes = ed.BuildNodes(entityID,
  242. _internalRemove,
  243. _internalEnable,
  244. _internalDisable
  245. );
  246. _nodesToAdd.AddRange(entityNodes);
  247. for (int i = 0; i < entityNodes.Count; i++)
  248. {
  249. var groupNode = entityNodes[i] as IGroupedStructNodeWithID;
  250. if (groupNode != null)
  251. groupNode.groupID = groupID;
  252. }
  253. }
  254. static void AddEngine(IEngine engine, Type[] types,
  255. Dictionary<Type, FasterList<IEngine>> engines)
  256. {
  257. for (int i = 0; i < types.Length; i++)
  258. {
  259. FasterList<IEngine> list;
  260. var type = types[i];
  261. if (engines.TryGetValue(type, out list) == false)
  262. {
  263. list = new FasterList<IEngine>();
  264. engines.Add(type, list);
  265. }
  266. list.Add(engine);
  267. }
  268. }
  269. void AddNodeToMetaDB(INode node, Type nodeType)
  270. {
  271. FasterList<INode> nodes;
  272. if (_metaNodesDB.TryGetValue(nodeType, out nodes) == false)
  273. nodes = _metaNodesDB[nodeType] = new FasterList<INode>();
  274. nodes.Add(node);
  275. }
  276. void AddNodeToTheDB<T>(T node, Type nodeType) where T : INode
  277. {
  278. FasterList<INode> nodes;
  279. if (_nodesDB.TryGetValue(nodeType, out nodes) == false)
  280. nodes = _nodesDB[nodeType] = new FasterList<INode>();
  281. nodes.Add(node);
  282. }
  283. void AddNodeToNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID
  284. {
  285. Dictionary<int, INode> nodesDic;
  286. if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false)
  287. nodesDic = _nodesDBdic[nodeType] = new Dictionary<int, INode>();
  288. nodesDic.Add(node.ID, node);
  289. }
  290. void AddNodeToTheSuitableEngines(INode node, Type nodeType)
  291. {
  292. FasterList<IEngine> enginesForNode;
  293. if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
  294. {
  295. for (int j = 0; j < enginesForNode.Count; j++)
  296. {
  297. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  298. EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j] as INodeEngine, node);
  299. #else
  300. (enginesForNode[j] as INodeEngine).Add(node);
  301. #endif
  302. }
  303. }
  304. }
  305. void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode
  306. {
  307. FasterList<INode> nodes;
  308. if (_nodesDB.TryGetValue(nodeType, out nodes) == true)
  309. nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero?
  310. }
  311. void RemoveNodeFromMetaDB<T>(T node, Type nodeType) where T : INode
  312. {
  313. FasterList<INode> nodes;
  314. if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true)
  315. nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero?
  316. }
  317. void RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID
  318. {
  319. Dictionary<int, INode> nodesDic;
  320. if (_nodesDBdic.TryGetValue(nodeType, out nodesDic))
  321. nodesDic.Remove(node.ID);
  322. }
  323. void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode
  324. {
  325. FasterList<IEngine> enginesForNode;
  326. if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
  327. {
  328. for (int j = 0; j < enginesForNode.Count; j++)
  329. {
  330. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  331. EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node);
  332. #else
  333. (enginesForNode[j] as INodeEngine).Remove(node);
  334. #endif
  335. }
  336. }
  337. }
  338. void DisableNodeFromEngines(INode node, Type nodeType)
  339. {
  340. FasterList<IEngine> enginesForNode;
  341. if (_activableEngines.TryGetValue(nodeType, out enginesForNode))
  342. {
  343. for (int j = 0; j < enginesForNode.Count; j++)
  344. {
  345. (enginesForNode[j] as IActivableNodeEngine).Disable(node);
  346. }
  347. }
  348. }
  349. void EnableNodeFromEngines(INode node, Type nodeType)
  350. {
  351. FasterList<IEngine> enginesForNode;
  352. if (_activableEngines.TryGetValue(nodeType, out enginesForNode))
  353. {
  354. for (int j = 0; j < enginesForNode.Count; j++)
  355. {
  356. (enginesForNode[j] as IActivableNodeEngine).Enable(node);
  357. }
  358. }
  359. }
  360. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  361. void AddNodeToEngine(IEngine engine, INode node)
  362. {
  363. (engine as INodeEngine).Add(node);
  364. }
  365. void RemoveNodeFromEngine(IEngine engine, INode node)
  366. {
  367. (engine as INodeEngine).Remove(node);
  368. }
  369. #endif
  370. void InternalDisable(FasterList<INode> nodes)
  371. {
  372. if (_engineRootWeakReference.IsValid == false)
  373. return;
  374. for (int i = 0; i < nodes.Count; i++)
  375. {
  376. var node = nodes[i];
  377. Type nodeType = node.GetType();
  378. DisableNodeFromEngines(node, nodeType);
  379. }
  380. }
  381. void InternalEnable(FasterList<INode> nodes)
  382. {
  383. if (_engineRootWeakReference.IsValid == false)
  384. return;
  385. for (int i = 0; i < nodes.Count; i++)
  386. {
  387. var node = nodes[i];
  388. Type nodeType = node.GetType();
  389. EnableNodeFromEngines(node, nodeType);
  390. }
  391. }
  392. void InternalRemove(FasterList<INode> nodes)
  393. {
  394. if (_engineRootWeakReference.IsValid == false)
  395. return;
  396. for (int i = 0; i < nodes.Count; i++)
  397. {
  398. var node = nodes[i];
  399. Type nodeType = node.GetType();
  400. RemoveNodeFromEngines(node, nodeType);
  401. RemoveNodeFromTheDB(node, node.GetType());
  402. var nodeWithId = node as INodeWithID;
  403. if (nodeWithId != null)
  404. RemoveNodeFromNodesDictionary(nodeWithId, nodeType);
  405. }
  406. }
  407. void InternalMetaRemove(FasterList<INode> nodes)
  408. {
  409. for (int i = 0; i < nodes.Count; i++)
  410. {
  411. var node = nodes[i];
  412. Type nodeType = node.GetType();
  413. RemoveNodeFromEngines(node, nodeType);
  414. RemoveNodeFromMetaDB(node, nodeType);
  415. var nodeWithId = node as INodeWithID;
  416. if (nodeWithId != null)
  417. RemoveNodeFromNodesDictionary(nodeWithId, nodeType);
  418. }
  419. }
  420. readonly Dictionary<Type, FasterList<IEngine>> _nodeEngines;
  421. readonly Dictionary<Type, FasterList<IEngine>> _activableEngines;
  422. readonly FasterList<IEngine> _otherEngines;
  423. readonly Dictionary<Type, FasterList<INode>> _nodesDB;
  424. readonly Dictionary<Type, FasterList<INode>> _metaNodesDB;
  425. readonly Dictionary<Type, Dictionary<int, INode>> _nodesDBdic;
  426. readonly FasterList<INode> _nodesToAdd;
  427. readonly FasterList<INode> _metaNodesToAdd;
  428. readonly WeakReference _engineRootWeakReference;
  429. readonly SharedStructNodeLists _sharedStructNodeLists;
  430. readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists;
  431. readonly NodeSubmissionScheduler _scheduler;
  432. readonly Action<FasterList<INode>> _internalRemove;
  433. readonly Action<FasterList<INode>> _internalEnable;
  434. readonly Action<FasterList<INode>> _internalDisable;
  435. readonly Action<FasterList<INode>> _internalMetaRemove;
  436. readonly Type _structNodeEngineType;
  437. readonly Type _groupedStructNodesEngineType;
  438. readonly Type _activableNodeEngineType;
  439. readonly Dictionary<Type, Type[]> _implementedInterfaceTypes;
  440. }
  441. }