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.

162 lines
7.0KB

  1. using System;
  2. using Svelto.Common;
  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. readonly FasterList<EntitySubmitOperation> _transientEntitiesOperations;
  11. void SubmitEntityViews()
  12. {
  13. using (var profiler = new PlatformProfiler("Svelto.ECS - Entities Submission"))
  14. {
  15. int iterations = 0;
  16. do
  17. {
  18. SingleSubmission(profiler);
  19. } while ((_groupedEntityToAdd.currentEntitiesCreatedPerGroup.Count > 0 ||
  20. _entitiesOperations.Count > 0) && ++iterations < 5);
  21. #if DEBUG && !PROFILER
  22. if (iterations == 5)
  23. throw new ECSException("possible circular submission detected");
  24. #endif
  25. }
  26. }
  27. void SingleSubmission(in PlatformProfiler profiler)
  28. {
  29. if (_entitiesOperations.Count > 0)
  30. {
  31. using (profiler.Sample("Remove and Swap operations"))
  32. {
  33. _transientEntitiesOperations.FastClear();
  34. var entitySubmitOperations = _entitiesOperations.GetValuesArray(out var count);
  35. _transientEntitiesOperations.AddRange(entitySubmitOperations, count);
  36. _entitiesOperations.FastClear();
  37. var entitiesOperations = _transientEntitiesOperations.ToArrayFast();
  38. for (var i = 0; i < _transientEntitiesOperations.Count; i++)
  39. {
  40. try
  41. {
  42. switch (entitiesOperations[i].type)
  43. {
  44. case EntitySubmitOperationType.Swap:
  45. MoveEntityFromAndToEngines(entitiesOperations[i].builders,
  46. entitiesOperations[i].fromID,
  47. entitiesOperations[i].toID);
  48. break;
  49. case EntitySubmitOperationType.Remove:
  50. MoveEntityFromAndToEngines(entitiesOperations[i].builders,
  51. entitiesOperations[i].fromID, null);
  52. break;
  53. case EntitySubmitOperationType.RemoveGroup:
  54. RemoveGroupAndEntitiesFromDB(
  55. entitiesOperations[i].fromID.groupID, profiler);
  56. break;
  57. }
  58. }
  59. catch (Exception e)
  60. {
  61. var str = "Crash while executing Entity Operation "
  62. .FastConcat(entitiesOperations[i].type.ToString());
  63. throw new ECSException(str.FastConcat(" ")
  64. #if DEBUG && !PROFILER
  65. .FastConcat(entitiesOperations[i].trace.ToString())
  66. #endif
  67. , e);
  68. }
  69. }
  70. }
  71. }
  72. _groupedEntityToAdd.Swap();
  73. if (_groupedEntityToAdd.otherEntitiesCreatedPerGroup.Count > 0)
  74. {
  75. using (profiler.Sample("Add operations"))
  76. {
  77. try
  78. {
  79. AddEntityViewsToTheDBAndSuitableEngines(profiler);
  80. }
  81. finally
  82. {
  83. using (profiler.Sample("clear operates double buffering"))
  84. {
  85. //other can be cleared now, but let's avoid deleting the dictionary every time
  86. _groupedEntityToAdd.ClearOther();
  87. }
  88. }
  89. }
  90. }
  91. }
  92. void AddEntityViewsToTheDBAndSuitableEngines(in PlatformProfiler profiler)
  93. {
  94. using (profiler.Sample("Add entities to database"))
  95. {
  96. //each group is indexed by entity view type. for each type there is a dictionary indexed by entityID
  97. foreach (var groupOfEntitiesToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup)
  98. {
  99. var groupID = groupOfEntitiesToSubmit.Key;
  100. //if the group doesn't exist in the current DB let's create it first
  101. if (_groupEntityViewsDB.TryGetValue(groupID, out var groupDB) == false)
  102. groupDB = _groupEntityViewsDB[groupID] =
  103. new FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary>();
  104. //add the entityViews in the group
  105. foreach (var entityViewsToSubmit in _groupedEntityToAdd.other[groupID])
  106. {
  107. var type = entityViewsToSubmit.Key;
  108. var typeSafeDictionary = entityViewsToSubmit.Value;
  109. var wrapper = new RefWrapper<Type>(type);
  110. if (groupDB.TryGetValue(wrapper, out var dbDic) == false)
  111. dbDic = groupDB[wrapper] = typeSafeDictionary.Create();
  112. //Fill the DB with the entity views generate this frame.
  113. dbDic.AddEntitiesFromDictionary(typeSafeDictionary, groupID);
  114. if (_groupsPerEntity.TryGetValue(wrapper, out var groupedGroup) == false)
  115. groupedGroup = _groupsPerEntity[wrapper] =
  116. new FasterDictionary<uint, ITypeSafeDictionary>();
  117. groupedGroup[groupID] = dbDic;
  118. }
  119. }
  120. }
  121. //then submit everything in the engines, so that the DB is up to date with all the entity views and struct
  122. //created by the entity built
  123. using (profiler.Sample("Add entities to engines"))
  124. {
  125. foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup)
  126. {
  127. var groupID = groupToSubmit.Key;
  128. var groupDB = _groupEntityViewsDB[groupID];
  129. foreach (var entityViewsToSubmit in _groupedEntityToAdd.other[groupID])
  130. {
  131. var realDic = groupDB[new RefWrapper<Type>(entityViewsToSubmit.Key)];
  132. entityViewsToSubmit.Value.AddEntitiesToEngines(_reactiveEnginesAddRemove, realDic, in profiler,
  133. new ExclusiveGroup.ExclusiveGroupStruct(groupToSubmit.Key));
  134. }
  135. }
  136. }
  137. }
  138. DoubleBufferedEntitiesToAdd _groupedEntityToAdd;
  139. readonly IEntitySubmissionScheduler _scheduler;
  140. readonly FasterDictionary<ulong, EntitySubmitOperation> _entitiesOperations;
  141. }
  142. }