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.

196 lines
9.0KB

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