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.

165 lines
8.7KB

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