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.

143 lines
5.9KB

  1. using System;
  2. using System.Collections.Generic;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS.Internal;
  5. using Svelto.ECS.Schedulers;
  6. namespace Svelto.ECS
  7. {
  8. public partial class EnginesRoot
  9. {
  10. public struct EntitiesSubmitter
  11. {
  12. public EntitiesSubmitter(EnginesRoot enginesRoot)
  13. {
  14. _weakReference = new DataStructures.WeakReference<EnginesRoot>(enginesRoot);
  15. }
  16. public void Invoke()
  17. {
  18. if (_weakReference.IsValid)
  19. _weakReference.Target.SubmitEntityViews();
  20. }
  21. readonly DataStructures.WeakReference<EnginesRoot> _weakReference;
  22. }
  23. /// <summary>
  24. /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot
  25. /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks
  26. /// periodically if new entity must be submitted to the database and the engines. It's an external
  27. /// dependencies to be independent by the running platform as the user can define it.
  28. /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why
  29. /// it must receive a weak reference of the EnginesRoot callback.
  30. /// </summary>
  31. public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler)
  32. {
  33. _entitiesOperations = new FasterDictionary<ulong, EntitySubmitOperation>();
  34. _reactiveEnginesAddRemove = new FasterDictionary<RefWrapper<Type>, FasterList<IEngine>>();
  35. _reactiveEnginesSwap = new FasterDictionary<RefWrapper<Type>, FasterList<IEngine>>();
  36. _enginesSet = new FasterList<IEngine>();
  37. _enginesTypeSet = new HashSet<Type>();
  38. _disposableEngines = new FasterList<IDisposable>();
  39. _transientEntitiesOperations = new FasterList<EntitySubmitOperation>();
  40. _groupEntityViewsDB = new FasterDictionary<uint, FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>>();
  41. _groupsPerEntity = new FasterDictionary<RefWrapper<Type>, FasterDictionary<uint, ITypeSafeDictionary>>();
  42. _groupedEntityToAdd = new DoubleBufferedEntitiesToAdd();
  43. _entitiesStream = new EntitiesStream();
  44. _entitiesDB = new EntitiesDB(_groupEntityViewsDB, _groupsPerEntity, _entitiesStream);
  45. _scheduler = entityViewScheduler;
  46. _scheduler.onTick = new EntitiesSubmitter(this);
  47. }
  48. public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler, bool isDeserializationOnly):this(entityViewScheduler)
  49. {
  50. _isDeserializationOnly = isDeserializationOnly;
  51. }
  52. public void AddEngine(IEngine engine)
  53. {
  54. var type = engine.GetType();
  55. var refWrapper = new RefWrapper<Type>(type);
  56. DBC.ECS.Check.Require(
  57. _enginesTypeSet.Contains(refWrapper) == false ||
  58. type.ContainsCustomAttribute(typeof(AllowMultipleAttribute)) == true,
  59. "The same engine has been added more than once, if intentional, use [AllowMultiple] class attribute "
  60. .FastConcat(engine.ToString()));
  61. try
  62. {
  63. if (engine is IReactOnAddAndRemove viewEngine)
  64. CheckEntityViewsEngine(viewEngine, _reactiveEnginesAddRemove);
  65. if (engine is IReactOnSwap viewEngineSwap)
  66. CheckEntityViewsEngine(viewEngineSwap, _reactiveEnginesSwap);
  67. _enginesTypeSet.Add(refWrapper);
  68. _enginesSet.Add(engine);
  69. if (engine is IDisposable)
  70. _disposableEngines.Add(engine as IDisposable);
  71. if (engine is IQueryingEntitiesEngine queryableEntityViewEngine)
  72. {
  73. queryableEntityViewEngine.entitiesDB = _entitiesDB;
  74. queryableEntityViewEngine.Ready();
  75. }
  76. }
  77. catch (Exception e)
  78. {
  79. throw new ECSException("Code crashed while adding engine ".FastConcat(engine.GetType().ToString(), " "), e);
  80. }
  81. }
  82. void CheckEntityViewsEngine<T>(T engine, FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines)
  83. where T : class, IEngine
  84. {
  85. var interfaces = engine.GetType().GetInterfaces();
  86. foreach (var interf in interfaces)
  87. {
  88. if (interf.IsGenericTypeEx() && typeof(T).IsAssignableFrom(interf))
  89. {
  90. var genericArguments = interf.GetGenericArgumentsEx();
  91. AddEngine(engine, genericArguments, engines);
  92. }
  93. }
  94. }
  95. static void AddEngine<T>(T engine, Type[] entityViewTypes,
  96. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines)
  97. where T : class, IEngine
  98. {
  99. for (var i = 0; i < entityViewTypes.Length; i++)
  100. {
  101. var type = entityViewTypes[i];
  102. AddEngine(engine, engines, type);
  103. }
  104. }
  105. static void AddEngine<T>(T engine, FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines, Type type)
  106. where T : class, IEngine
  107. {
  108. if (engines.TryGetValue(new RefWrapper<Type>(type), out var list) == false)
  109. {
  110. list = new FasterList<IEngine>();
  111. engines.Add(new RefWrapper<Type>(type), list);
  112. }
  113. list.Add(engine);
  114. }
  115. readonly FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> _reactiveEnginesAddRemove;
  116. readonly FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> _reactiveEnginesSwap;
  117. readonly FasterList<IDisposable> _disposableEngines;
  118. readonly FasterList<IEngine> _enginesSet;
  119. readonly HashSet<Type> _enginesTypeSet;
  120. }
  121. }