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.

177 lines
8.7KB

  1. using System.Collections.Generic;
  2. using Svelto.Common;
  3. using Svelto.DataStructures;
  4. namespace Svelto.ECS
  5. {
  6. public partial class EnginesRoot
  7. {
  8. /// <summary>
  9. /// Todo: it would be probably better to split even further the logic between submission and callbacks
  10. /// Something to do when I will optimize the callbacks
  11. /// </summary>
  12. /// <param name="profiler"></param>
  13. /// <param name="maxNumberOfOperations"></param>
  14. IEnumerator<bool> SingleSubmission(PlatformProfiler profiler)
  15. {
  16. while (true)
  17. {
  18. DBC.ECS.Check.Require(_maxNumberOfOperationsPerFrame > 0);
  19. ClearChecks();
  20. uint numberOfOperations = 0;
  21. if (_entitiesOperations.count > 0)
  22. {
  23. using (var sample = profiler.Sample("Remove and Swap operations"))
  24. {
  25. _transientEntitiesOperations.FastClear();
  26. _entitiesOperations.CopyValuesTo(_transientEntitiesOperations);
  27. _entitiesOperations.FastClear();
  28. EntitySubmitOperation[] entitiesOperations =
  29. _transientEntitiesOperations.ToArrayFast(out var count);
  30. for (var i = 0; i < count; i++)
  31. {
  32. try
  33. {
  34. switch (entitiesOperations[i].type)
  35. {
  36. case EntitySubmitOperationType.Swap:
  37. MoveEntityFromAndToEngines(entitiesOperations[i].builders
  38. , entitiesOperations[i].fromID
  39. , entitiesOperations[i].toID);
  40. break;
  41. case EntitySubmitOperationType.Remove:
  42. MoveEntityFromAndToEngines(entitiesOperations[i].builders
  43. , entitiesOperations[i].fromID, null);
  44. break;
  45. case EntitySubmitOperationType.RemoveGroup:
  46. RemoveEntitiesFromGroup(entitiesOperations[i].fromID.groupID, profiler);
  47. break;
  48. case EntitySubmitOperationType.SwapGroup:
  49. SwapEntitiesBetweenGroups(entitiesOperations[i].fromID.groupID
  50. , entitiesOperations[i].toID.groupID, profiler);
  51. break;
  52. }
  53. }
  54. catch
  55. {
  56. var str = "Crash while executing Entity Operation ".FastConcat(
  57. entitiesOperations[i].type.ToString());
  58. Svelto.Console.LogError(str.FastConcat(" ")
  59. #if DEBUG && !PROFILE_SVELTO
  60. .FastConcat(entitiesOperations[i].trace.ToString())
  61. #endif
  62. );
  63. throw;
  64. }
  65. ++numberOfOperations;
  66. if ((uint) numberOfOperations >= (uint) _maxNumberOfOperationsPerFrame)
  67. {
  68. using (sample.Yield())
  69. yield return true;
  70. numberOfOperations = 0;
  71. }
  72. }
  73. }
  74. }
  75. _groupedEntityToAdd.Swap();
  76. if (_groupedEntityToAdd.AnyOtherEntityCreated())
  77. {
  78. using (var outerSampler = profiler.Sample("Add operations"))
  79. {
  80. try
  81. {
  82. using (profiler.Sample("Add entities to database"))
  83. {
  84. //each group is indexed by entity view type. for each type there is a dictionary indexed by entityID
  85. foreach (var groupToSubmit in _groupedEntityToAdd.other)
  86. {
  87. var groupID = groupToSubmit.Key;
  88. var groupDB = GetOrCreateDBGroup(groupID);
  89. //add the entityComponents in the group
  90. foreach (var entityComponentsToSubmit in groupToSubmit.Value)
  91. {
  92. var type = entityComponentsToSubmit.Key;
  93. var targetTypeSafeDictionary = entityComponentsToSubmit.Value;
  94. var wrapper = new RefWrapperType(type);
  95. var dbDic = GetOrCreateTypeSafeDictionary(
  96. groupID, groupDB, wrapper, targetTypeSafeDictionary);
  97. //Fill the DB with the entity components generated this frame.
  98. dbDic.AddEntitiesFromDictionary(targetTypeSafeDictionary, groupID, this);
  99. }
  100. }
  101. }
  102. //then submit everything in the engines, so that the DB is up to date with all the entity components
  103. //created by the entity built
  104. using (var sampler = profiler.Sample("Add entities to engines"))
  105. {
  106. foreach (var groupToSubmit in _groupedEntityToAdd.other)
  107. {
  108. var groupID = groupToSubmit.Key;
  109. var groupDB = GetDBGroup(groupID);
  110. //entityComponentsToSubmit is the array of components found in the groupID per component type.
  111. //if there are N entities to submit, and M components type to add for each entity, this foreach will run NxM times.
  112. foreach (var entityComponentsToSubmit in groupToSubmit.Value)
  113. {
  114. var realDic = groupDB[new RefWrapperType(entityComponentsToSubmit.Key)];
  115. entityComponentsToSubmit.Value.ExecuteEnginesAddOrSwapCallbacks(
  116. _reactiveEnginesAddRemove, realDic, null, groupID, in profiler);
  117. numberOfOperations += entityComponentsToSubmit.Value.count;
  118. if (numberOfOperations >= _maxNumberOfOperationsPerFrame)
  119. {
  120. using (outerSampler.Yield())
  121. using (sampler.Yield())
  122. {
  123. yield return true;
  124. }
  125. numberOfOperations = 0;
  126. }
  127. }
  128. }
  129. }
  130. }
  131. finally
  132. {
  133. using (profiler.Sample("clear double buffering"))
  134. {
  135. //other can be cleared now, but let's avoid deleting the dictionary every time
  136. _groupedEntityToAdd.ClearOther();
  137. }
  138. }
  139. }
  140. }
  141. yield return false;
  142. }
  143. }
  144. bool HasMadeNewStructuralChangesInThisIteration()
  145. {
  146. return _groupedEntityToAdd.AnyEntityCreated() || _entitiesOperations.count > 0;
  147. }
  148. readonly DoubleBufferedEntitiesToAdd _groupedEntityToAdd;
  149. readonly FasterDictionary<ulong, EntitySubmitOperation> _entitiesOperations;
  150. readonly FasterList<EntitySubmitOperation> _transientEntitiesOperations;
  151. uint _maxNumberOfOperationsPerFrame;
  152. }
  153. }