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.

182 lines
8.7KB

  1. using Svelto.DataStructures;
  2. using Svelto.ECS.Internal;
  3. namespace Svelto.ECS
  4. {
  5. public partial class EnginesRoot
  6. {
  7. internal class DoubleBufferedEntitiesToAdd
  8. {
  9. const int MAX_NUMBER_OF_ITEMS_PER_FRAME_BEFORE_TO_CLEAR = 100;
  10. public DoubleBufferedEntitiesToAdd()
  11. {
  12. _currentEntitiesCreatedPerGroup = _entitiesCreatedPerGroupA;
  13. _otherEntitiesCreatedPerGroup = _entitiesCreatedPerGroupB;
  14. current = _entityComponentsToAddBufferA;
  15. other = _entityComponentsToAddBufferB;
  16. }
  17. public void ClearOther()
  18. {
  19. //do not clear the groups created so far, they will be reused, unless they are too many!
  20. var otherCount = other.count;
  21. if (otherCount > MAX_NUMBER_OF_ITEMS_PER_FRAME_BEFORE_TO_CLEAR)
  22. {
  23. var otherValuesArray = other.unsafeValues;
  24. for (var i = 0; i < otherCount; ++i)
  25. {
  26. var safeDictionariesCount = otherValuesArray[i].count;
  27. var safeDictionaries = otherValuesArray[i].unsafeValues;
  28. {
  29. for (var j = 0; j < safeDictionariesCount; ++j)
  30. //clear the dictionary of entities create do far (it won't allocate though)
  31. safeDictionaries[j].Dispose();
  32. }
  33. }
  34. //reset the number of entities created so far
  35. _otherEntitiesCreatedPerGroup.FastClear();
  36. other.FastClear();
  37. return;
  38. }
  39. {
  40. var otherValuesArray = other.unsafeValues;
  41. for (var i = 0; i < otherCount; ++i)
  42. {
  43. var safeDictionariesCount = otherValuesArray[i].count;
  44. var safeDictionaries = otherValuesArray[i].unsafeValues;
  45. //do not remove the dictionaries of entities per type created so far, they will be reused
  46. if (safeDictionariesCount <= MAX_NUMBER_OF_ITEMS_PER_FRAME_BEFORE_TO_CLEAR)
  47. {
  48. for (var j = 0; j < safeDictionariesCount; ++j)
  49. //clear the dictionary of entities create do far (it won't allocate though)
  50. safeDictionaries[j].FastClear();
  51. }
  52. else
  53. {
  54. for (var j = 0; j < safeDictionariesCount; ++j)
  55. //clear the dictionary of entities create do far (it won't allocate though)
  56. safeDictionaries[j].Dispose();
  57. otherValuesArray[i].FastClear();
  58. }
  59. }
  60. //reset the number of entities created so far
  61. _otherEntitiesCreatedPerGroup.FastClear();
  62. }
  63. }
  64. public void Dispose()
  65. {
  66. {
  67. var otherValuesArray = other.unsafeValues;
  68. for (var i = 0; i < other.count; ++i)
  69. {
  70. var safeDictionariesCount = otherValuesArray[i].count;
  71. var safeDictionaries = otherValuesArray[i].unsafeValues;
  72. //do not remove the dictionaries of entities per type created so far, they will be reused
  73. for (var j = 0; j < safeDictionariesCount; ++j)
  74. //clear the dictionary of entities create do far (it won't allocate though)
  75. safeDictionaries[j].Dispose();
  76. }
  77. }
  78. {
  79. var currentValuesArray = current.unsafeValues;
  80. for (var i = 0; i < current.count; ++i)
  81. {
  82. var safeDictionariesCount = currentValuesArray[i].count;
  83. var safeDictionaries = currentValuesArray[i].unsafeValues;
  84. //do not remove the dictionaries of entities per type created so far, they will be reused
  85. for (var j = 0; j < safeDictionariesCount; ++j)
  86. //clear the dictionary of entities create do far (it won't allocate though)
  87. safeDictionaries[j].Dispose();
  88. }
  89. }
  90. }
  91. internal bool AnyEntityCreated()
  92. {
  93. return _currentEntitiesCreatedPerGroup.count > 0;
  94. }
  95. internal bool AnyOtherEntityCreated()
  96. {
  97. return _otherEntitiesCreatedPerGroup.count > 0;
  98. }
  99. internal void IncrementEntityCount(ExclusiveGroupStruct groupID)
  100. {
  101. _currentEntitiesCreatedPerGroup.GetOrCreate(groupID)++;
  102. }
  103. internal void Preallocate
  104. (ExclusiveGroupStruct groupID, uint numberOfEntities, IComponentBuilder[] entityComponentsToBuild)
  105. {
  106. void PreallocateDictionaries
  107. (FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> dic)
  108. {
  109. var group = dic.GetOrCreate(groupID, () => new FasterDictionary<RefWrapperType,
  110. ITypeSafeDictionary>());
  111. foreach (var componentBuilder in entityComponentsToBuild)
  112. {
  113. var entityComponentType = componentBuilder.GetEntityComponentType();
  114. var safeDictionary = group.GetOrCreate(new RefWrapperType(entityComponentType)
  115. , () => componentBuilder
  116. .CreateDictionary(numberOfEntities));
  117. componentBuilder.Preallocate(safeDictionary, numberOfEntities);
  118. }
  119. }
  120. PreallocateDictionaries(current);
  121. PreallocateDictionaries(other);
  122. _currentEntitiesCreatedPerGroup.GetOrCreate(groupID);
  123. _otherEntitiesCreatedPerGroup.GetOrCreate(groupID);
  124. }
  125. internal void Swap()
  126. {
  127. Swap(ref current, ref other);
  128. Swap(ref _currentEntitiesCreatedPerGroup, ref _otherEntitiesCreatedPerGroup);
  129. }
  130. void Swap<T>(ref T item1, ref T item2)
  131. {
  132. var toSwap = item2;
  133. item2 = item1;
  134. item1 = toSwap;
  135. }
  136. //Before I tried for the third time to use a SparseSet instead of FasterDictionary, remember that
  137. //while group indices are sequential, they may not be used in a sequential order. Sparseset needs
  138. //entities to be created sequentially (the index cannot be managed externally)
  139. internal FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> current;
  140. internal FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> other;
  141. readonly FasterDictionary<ExclusiveGroupStruct, uint> _entitiesCreatedPerGroupA =
  142. new FasterDictionary<ExclusiveGroupStruct, uint>();
  143. readonly FasterDictionary<ExclusiveGroupStruct, uint> _entitiesCreatedPerGroupB =
  144. new FasterDictionary<ExclusiveGroupStruct, uint>();
  145. readonly FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> _entityComponentsToAddBufferA =
  146. new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>();
  147. readonly FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>> _entityComponentsToAddBufferB =
  148. new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>();
  149. /// <summary>
  150. /// To avoid extra allocation, I don't clear the groups, so I need an extra data structure
  151. /// to keep count of the number of entities built this frame. At the moment the actual number
  152. /// of entities built is not used
  153. /// </summary>
  154. FasterDictionary<ExclusiveGroupStruct, uint> _currentEntitiesCreatedPerGroup;
  155. FasterDictionary<ExclusiveGroupStruct, uint> _otherEntitiesCreatedPerGroup;
  156. }
  157. }
  158. }