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.

178 lines
7.4KB

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