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.

148 lines
6.2KB

  1. using System;
  2. using System.Collections.Generic;
  3. using Svelto.DataStructures;
  4. using Svelto.DataStructures.Experimental;
  5. using Svelto.ECS.Internal;
  6. using Svelto.ECS.Schedulers;
  7. using Svelto.WeakEvents;
  8. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  9. using Svelto.ECS.Profiler;
  10. #endif
  11. namespace Svelto.ECS
  12. {
  13. public partial class EnginesRoot
  14. {
  15. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  16. static EnginesRoot()
  17. {
  18. /// <summary>
  19. /// I still need to find a good solution for this. Need to move somewhere else
  20. /// </summary>
  21. UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Svelto.ECS.Profiler");
  22. debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>();
  23. UnityEngine.GameObject.DontDestroyOnLoad(debugEngineObject);
  24. }
  25. #endif
  26. /// <summary>
  27. /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot
  28. /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks
  29. /// periodically if new entity must be submitted to the database and the engines. It's an external
  30. /// dependencies to be independent by the running platform as the user can define it.
  31. /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why
  32. /// it must receive a weak reference of the EnginesRoot callback.
  33. /// </summary>
  34. public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler)
  35. {
  36. #if DEBUG && !PROFILER
  37. _entitiesOperationsDebug = new FasterDictionary<long, EntitySubmitOperationType>();
  38. #endif
  39. _entitiesOperations = new FasterList<EntitySubmitOperation>();
  40. _entityEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>>();
  41. _enginesSet = new HashSet<IEngine>();
  42. _disposableEngines = new FasterList<IDisposable>();
  43. _transientEntitiesOperations = new FasterList<EntitySubmitOperation>();
  44. _groupEntityDB = new FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>();
  45. _groupsPerEntity = new Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>>();
  46. _groupedEntityToAdd = new DoubleBufferedEntitiesToAdd<FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>>();
  47. _entitiesDB = new EntitiesDB(_groupEntityDB, _groupsPerEntity);
  48. _scheduler = entityViewScheduler;
  49. _scheduler.onTick = new WeakAction(SubmitEntityViews);
  50. }
  51. public void AddEngine(IEngine engine)
  52. {
  53. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  54. Profiler.EngineProfiler.AddEngine(engine);
  55. #endif
  56. var viewEngine = engine as IHandleEntityViewEngineAbstracted;
  57. if (viewEngine != null)
  58. CheckEntityViewsEngine(viewEngine);
  59. DBC.ECS.Check.Assert(_enginesSet.Contains(engine) == false, "The same engine has been added more than once "
  60. .FastConcat(engine.ToString()));
  61. _enginesSet.Add(engine);
  62. if (engine is IDisposable)
  63. _disposableEngines.Add(engine as IDisposable);
  64. var queryableEntityViewEngine = engine as IQueryingEntitiesEngine;
  65. if (queryableEntityViewEngine != null)
  66. {
  67. queryableEntityViewEngine.entitiesDB = _entitiesDB;
  68. queryableEntityViewEngine.Ready();
  69. }
  70. }
  71. void CheckEntityViewsEngine(IEngine engine)
  72. {
  73. var baseType = engine.GetType().GetBaseType();
  74. while (baseType != _objectType)
  75. {
  76. if (baseType.IsGenericTypeEx())
  77. {
  78. var genericArguments = baseType.GetGenericArgumentsEx();
  79. AddEngine(engine as IHandleEntityViewEngineAbstracted, genericArguments, _entityEngines);
  80. return;
  81. }
  82. baseType = baseType.GetBaseType();
  83. }
  84. throw new ArgumentException("Not Supported Engine " + engine);
  85. }
  86. static void AddEngine<T>(T engine, Type[] entityViewTypes,
  87. Dictionary<Type, FasterList<T>> engines) where T:IEngine
  88. {
  89. for (int i = 0; i < entityViewTypes.Length; i++)
  90. {
  91. var type = entityViewTypes[i];
  92. AddEngine(engine, engines, type);
  93. }
  94. }
  95. static void AddEngine<T>(T engine, Dictionary<Type, FasterList<T>> engines, Type type) where T : IEngine
  96. {
  97. FasterList<T> list;
  98. if (engines.TryGetValue(type, out list) == false)
  99. {
  100. list = new FasterList<T>();
  101. engines.Add(type, list);
  102. }
  103. list.Add(engine);
  104. }
  105. readonly Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> _entityEngines;
  106. readonly HashSet<IEngine> _enginesSet;
  107. readonly FasterList<IDisposable> _disposableEngines;
  108. //one datastructure rule them all:
  109. //split by group
  110. //split by type per group. It's possible to get all the entities of a give type T per group thanks
  111. //to the FasterDictionary capabilities OR it's possible to get a specific entityView indexed by
  112. //ID. This ID doesn't need to be the EGID, it can be just the entityID
  113. //for each group id, save a dictionary indexed by entity type of entities indexed by id
  114. readonly FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupEntityDB;
  115. readonly EntitiesDB _entitiesDB;
  116. //for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are
  117. //found indexed by group id
  118. readonly Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>> _groupsPerEntity; //yes I am being sarcastic
  119. static readonly Type _objectType = typeof(object);
  120. }
  121. }