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.

198 lines
9.9KB

  1. using Svelto.DataStructures;
  2. using Svelto.DataStructures.Native;
  3. using Svelto.ECS.Internal;
  4. namespace Svelto.ECS
  5. {
  6. public partial class EnginesRoot
  7. {
  8. void InitFilters()
  9. {
  10. _transientEntityFilters = new SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection>(0);
  11. _persistentEntityFilters = new SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection>(0);
  12. _indicesOfPersistentFiltersUsedByThisComponent =
  13. new SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>>(0);
  14. _indicesOfTransientFiltersUsedByThisComponent =
  15. new SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>>(0);
  16. }
  17. void DisposeFilters()
  18. {
  19. foreach (var filter in _transientEntityFilters)
  20. {
  21. filter.value.Dispose();
  22. }
  23. foreach (var filter in _indicesOfTransientFiltersUsedByThisComponent)
  24. {
  25. filter.value.Dispose();
  26. }
  27. foreach (var filter in _persistentEntityFilters)
  28. {
  29. filter.value.Dispose();
  30. }
  31. foreach (var filter in _indicesOfPersistentFiltersUsedByThisComponent)
  32. {
  33. filter.value.Dispose();
  34. }
  35. _transientEntityFilters.Dispose();
  36. _persistentEntityFilters.Dispose();
  37. _indicesOfPersistentFiltersUsedByThisComponent.Dispose();
  38. _indicesOfTransientFiltersUsedByThisComponent.Dispose();
  39. }
  40. void ClearTransientFilters()
  41. {
  42. foreach (var filter in _transientEntityFilters)
  43. {
  44. filter.value.Clear();
  45. }
  46. }
  47. /// <summary>
  48. /// Persistent filters are automatically updated by the framework. If entities are removed from the database
  49. /// the filters are updated consequentially.
  50. /// </summary>
  51. /// <param name="entityIDsRemoved"></param>
  52. /// <param name="fromGroup"></param>
  53. /// <param name="refWrapperType"></param>
  54. /// <param name="fromDic"></param>
  55. /// <param name="entityIDsLeftAndAffectedByRemoval"></param>
  56. void RemoveEntitiesFromPersistentFilters
  57. (FasterList<(uint entityID, string)> entityIDsRemoved, ExclusiveGroupStruct fromGroup, ComponentID refWrapperType
  58. , ITypeSafeDictionary fromDic, FasterList<uint> entityIDsLeftAndAffectedByRemoval)
  59. {
  60. //is there any filter used by this component?
  61. if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue(
  62. refWrapperType, out NativeDynamicArrayCast<int> listOfFilters) == true)
  63. {
  64. var numberOfFilters = listOfFilters.count;
  65. var filters = _persistentEntityFilters.unsafeValues;
  66. //remove duplicates
  67. _transientEntityIDsLeftWithoutDuplicates.Clear();
  68. var entityAffectedCount = entityIDsLeftAndAffectedByRemoval.count;
  69. for (int i = 0; i < entityAffectedCount; i++)
  70. {
  71. _transientEntityIDsLeftWithoutDuplicates[entityIDsLeftAndAffectedByRemoval[i]] = -1;
  72. }
  73. for (int filterIndex = 0; filterIndex < numberOfFilters; ++filterIndex)
  74. {
  75. //foreach filter linked to this component
  76. var persistentFiltersPerGroup = filters[listOfFilters[filterIndex]]._filtersPerGroup;
  77. //get the filter linked to this group
  78. if (persistentFiltersPerGroup.TryGetValue(fromGroup, out var fromGroupFilter))
  79. {
  80. var entitiesCount = entityIDsRemoved.count;
  81. //foreach entity to remove, remove it from the filter (if present)
  82. for (int entityIndex = 0; entityIndex < entitiesCount; ++entityIndex)
  83. {
  84. //the current entity id to remove
  85. uint fromEntityID = entityIDsRemoved[entityIndex].entityID;
  86. fromGroupFilter.Remove(fromEntityID); //Remove works even if the ID is not found (just returns false)
  87. }
  88. //when a component is removed from a component array, a remove swap back happens. This means
  89. //that not only we have to remove the index of the component of the entity deleted from the array
  90. //but we need also to update the index of the component that has been swapped in the cell
  91. //of the deleted component
  92. //entityIDsAffectedByRemoval tracks all the entitiesID of the components that need to be updated
  93. //in the filters because their indices in the array changed.
  94. foreach (var entity in _transientEntityIDsLeftWithoutDuplicates)
  95. {
  96. var entityId = entity.key;
  97. if (fromGroupFilter.Exists(entityId)) //does the entityID that has been swapped exist in the filter?
  98. {
  99. if (entity.value == -1)
  100. entity.value = (int)fromDic.GetIndex(entityId); //let's find the index of the entityID in the dictionary only once
  101. fromGroupFilter._entityIDToDenseIndex[entityId] = (uint) entity.value; //update the index in the filter of the component that has been swapped
  102. }
  103. }
  104. }
  105. }
  106. }
  107. }
  108. //this method is called by the framework only if listOfFilters.count > 0
  109. void SwapEntityBetweenPersistentFilters
  110. (FasterList<(uint, uint, string)> fromEntityToEntityIDs, ITypeSafeDictionary fromDic
  111. , ITypeSafeDictionary toDic, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup
  112. , ComponentID refWrapperType, FasterList<uint> entityIDsLeftAndAffectedByRemoval)
  113. {
  114. //is there any filter used by this component?
  115. if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue(
  116. refWrapperType, out NativeDynamicArrayCast<int> listOfFilters) == true)
  117. {
  118. DBC.ECS.Check.Require(listOfFilters.count > 0, "why are you calling this with an empty list?");
  119. var numberOfFilters = listOfFilters.count;
  120. //remove duplicates
  121. _transientEntityIDsLeftWithoutDuplicates.Clear();
  122. var entityAffectedCount = entityIDsLeftAndAffectedByRemoval.count;
  123. for (int i = 0; i < entityAffectedCount; i++)
  124. {
  125. _transientEntityIDsLeftWithoutDuplicates[entityIDsLeftAndAffectedByRemoval[i]] = -1;
  126. }
  127. /// fromEntityToEntityIDs are the IDs of the entities to swap from the from group to the to group.
  128. /// for this component type. for each component type, there is only one set of fromEntityToEntityIDs
  129. /// per from/to group.
  130. for (int filterIndex = 0; filterIndex < numberOfFilters; ++filterIndex)
  131. {
  132. //if the group has a filter linked:
  133. EntityFilterCollection persistentFilter =
  134. _persistentEntityFilters.unsafeValues[listOfFilters[filterIndex]];
  135. if (persistentFilter._filtersPerGroup.TryGetValue(fromGroup, out var fromGroupFilter))
  136. {
  137. EntityFilterCollection.GroupFilters groupFilterTo = default;
  138. foreach (var (fromEntityID, toEntityID, _) in fromEntityToEntityIDs)
  139. {
  140. var toIndex = toDic.GetIndex(toEntityID); //todo: optimize this should be calculated only once and not once per filter
  141. //if there is an entity, it must be moved to the to filter
  142. if (fromGroupFilter.Exists(fromEntityID) == true)
  143. {
  144. if (groupFilterTo.isValid == false)
  145. groupFilterTo = persistentFilter.GetOrCreateGroupFilter(toGroup);
  146. groupFilterTo.Add(toEntityID, toIndex);
  147. }
  148. }
  149. foreach (var (fromEntityID, _, _) in fromEntityToEntityIDs)
  150. {
  151. fromGroupFilter.Remove(fromEntityID); //Remove works even if the ID is not found (just returns false)
  152. }
  153. foreach (var entity in _transientEntityIDsLeftWithoutDuplicates)
  154. {
  155. var entityId = entity.key;
  156. if (fromGroupFilter.Exists(entityId))
  157. {
  158. if (entity.value == -1)
  159. entity.value = (int)fromDic.GetIndex(entityId);
  160. fromGroupFilter._entityIDToDenseIndex[entityId] = (uint) entity.value;
  161. }
  162. }
  163. }
  164. }
  165. }
  166. }
  167. internal SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> _transientEntityFilters;
  168. internal SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> _persistentEntityFilters;
  169. internal SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>> _indicesOfPersistentFiltersUsedByThisComponent;
  170. public SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>> _indicesOfTransientFiltersUsedByThisComponent;
  171. }
  172. }