Mirror of Svelto.ECS because we're a fan of it
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

272 lignes
11KB

  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using Svelto.Common;
  4. using Svelto.DataStructures.Native;
  5. using Svelto.ECS.Internal;
  6. using Svelto.ECS.Native;
  7. namespace Svelto.ECS
  8. {
  9. /// <summary>
  10. /// note: the whole Svelto ECS framework is based on the assumption that the NB and MB structures are ref
  11. /// since we are holding them inside jobs, we decided to not mark them as ref but the pointers inside must be constant!
  12. /// This works because NB and MB data wrapped can be changed only inside a submission which is not jobifiable
  13. /// however filters can be modified inside jobs which means that data can change asynchronously. For this reason filters should be
  14. /// always queries inside jobs when these are used.
  15. /// </summary>
  16. public readonly struct EntityFilterCollection
  17. {
  18. internal EntityFilterCollection(CombinedFilterID combinedFilterId,
  19. Allocator allocatorStrategy = Allocator.Persistent)
  20. {
  21. _filtersPerGroup =
  22. SharedSveltoDictionaryNative<ExclusiveGroupStruct, GroupFilters>.Create(allocatorStrategy);
  23. combinedFilterID = combinedFilterId;
  24. }
  25. public CombinedFilterID combinedFilterID { get; }
  26. public EntityFilterIterator GetEnumerator() => new EntityFilterIterator(this);
  27. /// <summary>
  28. /// Add a new entity to this filter
  29. /// This method assumes that the entity has already been submitted in the database, so it can be found through the EGIDMapper
  30. /// </summary>
  31. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  32. public void Add<T>(EGID egid, NativeEGIDMapper<T> mmap) where T : unmanaged, _IInternalEntityComponent
  33. {
  34. DBC.ECS.Check.Require(mmap.groupID == egid.groupID, "not compatible NativeEgidMapper used");
  35. Add(egid, mmap.GetIndex(egid.entityID));
  36. }
  37. /// <summary>
  38. /// Add a new entity to this filter
  39. /// This method assumes that the entity has already been submitted in the database, so it can be found through the EGIDMapper
  40. /// </summary>
  41. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  42. public void Add<T>(EGID egid, NativeEGIDMultiMapper<T> mmap) where T : unmanaged, _IInternalEntityComponent
  43. {
  44. Add(egid, mmap.GetIndex(egid));
  45. }
  46. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  47. public void Add<T>(EGID egid, EGIDMapper<T> mmap) where T : unmanaged, _IInternalEntityComponent
  48. {
  49. DBC.ECS.Check.Require(mmap.groupID == egid.groupID, "not compatible NativeEgidMapper used");
  50. Add(egid, mmap.GetIndex(egid.entityID));
  51. }
  52. /// <summary>
  53. /// Add a new entity to this filter
  54. /// This method assumes that the entity has already been submitted in the database, so it can be found through the EGIDMapper
  55. /// </summary>
  56. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  57. public void Add<T>(EGID egid, EGIDMultiMapper<T> mmap) where T : unmanaged, _IInternalEntityComponent
  58. {
  59. Add(egid, mmap.GetIndex(egid));
  60. }
  61. /// <summary>
  62. /// Add a new entity to this filter
  63. /// If the user knows at which position the entity is stored in the database, it can be passed directly to the filter
  64. /// This position can be assumed if the user knows how Svelto stores components internally, but it's only guaranteed when passed back from the
  65. /// Svelto callbacks, like the IReactOnAddEx.Add callbacks. Exploting IReactOnAddEx is the only reccomended pattern to use together with this
  66. /// method. If the wrong index is passed, the filter will have undefined behaviour
  67. /// </summary>
  68. /// <param name="egid"> the entity EGID </param>
  69. /// <param name="indexInComponentArray"> the position in the Svelto database array where the component is stored</param>
  70. /// <returns></returns>
  71. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  72. public void Add(EGID egid, uint indexInComponentArray)
  73. {
  74. GetOrCreateGroupFilter(egid.groupID).Add(egid.entityID, indexInComponentArray);
  75. }
  76. /// <summary>
  77. /// Add a new entity to this filter
  78. /// If the user knows at which position the entity is stored in the database, it can be passed directly to the filter
  79. /// This position can be assumed if the user knows how Svelto stores components internally, but it's only guaranteed when passed back from the
  80. /// Svelto callbacks, like the IReactOnAddEx.Add callbacks. Exploting IReactOnAddEx is the only reccomended pattern to use together with this
  81. /// method. If the wrong index is passed, the filter will have undefined behaviour
  82. /// </summary>
  83. /// <param name="egid"> the entity EGID </param>
  84. /// <param name="indexInComponentArray"> the position in the Svelto database array where the component is stored</param>
  85. /// <returns></returns>
  86. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  87. public void Add(uint entityID, ExclusiveGroupStruct groupId, uint indexInComponentArray)
  88. {
  89. Add(new EGID(entityID, groupId), indexInComponentArray);
  90. }
  91. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  92. public void Remove(EGID egid)
  93. {
  94. _filtersPerGroup[egid.groupID].Remove(egid.entityID);
  95. }
  96. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  97. public void Remove(uint entityID, ExclusiveGroupStruct groupID)
  98. {
  99. _filtersPerGroup[groupID].Remove(entityID);
  100. }
  101. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  102. public bool Exists(EGID egid)
  103. {
  104. if (TryGetGroupFilter(egid.groupID, out var groupFilter))
  105. {
  106. return groupFilter.Exists(egid.entityID);
  107. }
  108. return false;
  109. }
  110. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  111. public bool TryGetGroupFilter(ExclusiveGroupStruct group, out GroupFilters groupFilter)
  112. {
  113. return _filtersPerGroup.TryGetValue(group, out groupFilter);
  114. }
  115. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  116. public GroupFilters GetOrCreateGroupFilter(ExclusiveGroupStruct group)
  117. {
  118. if (_filtersPerGroup.TryGetValue(group, out var groupFilter) == false)
  119. {
  120. groupFilter = new GroupFilters(group);
  121. _filtersPerGroup.Add(group, groupFilter);
  122. }
  123. return groupFilter;
  124. }
  125. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  126. public GroupFilters CreateGroupFilter(ExclusiveBuildGroup group)
  127. {
  128. if (_filtersPerGroup.TryGetValue(group, out var groupFilter) == false)
  129. {
  130. groupFilter = new GroupFilters(group);
  131. _filtersPerGroup.Add(group, groupFilter);
  132. return groupFilter;
  133. }
  134. throw new ECSException("group already linked to filter {group}");
  135. }
  136. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  137. public GroupFilters GetGroupFilter(ExclusiveGroupStruct group)
  138. {
  139. if (_filtersPerGroup.TryGetValue(group, out var groupFilter) == true)
  140. return groupFilter;
  141. throw new Exception($"no filter linked to group {group}");
  142. }
  143. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  144. public void Clear()
  145. {
  146. var filterSets = _filtersPerGroup.GetValues(out var count);
  147. for (var i = 0; i < count; i++)
  148. {
  149. filterSets[i].Clear();
  150. }
  151. }
  152. internal int groupCount => _filtersPerGroup.count;
  153. public int ComputeFinalCount()
  154. {
  155. int count = 0;
  156. for (int i = 0; i < _filtersPerGroup.count; i++)
  157. {
  158. count += (int)GetGroup(i).count;
  159. }
  160. return count;
  161. }
  162. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  163. internal GroupFilters GetGroup(int indexGroup)
  164. {
  165. DBC.ECS.Check.Require(indexGroup < _filtersPerGroup.count);
  166. return _filtersPerGroup.GetValues(out _)[indexGroup];
  167. }
  168. public void Dispose()
  169. {
  170. var filterSets = _filtersPerGroup.GetValues(out var count);
  171. for (var i = 0; i < count; i++)
  172. {
  173. filterSets[i].Dispose();
  174. }
  175. _filtersPerGroup.Dispose();
  176. }
  177. internal readonly SharedSveltoDictionaryNative<ExclusiveGroupStruct, GroupFilters> _filtersPerGroup;
  178. public struct GroupFilters
  179. {
  180. internal GroupFilters(ExclusiveGroupStruct group) : this()
  181. {
  182. _entityIDToDenseIndex = new SharedSveltoDictionaryNative<uint, uint>(1);
  183. _group = group;
  184. }
  185. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  186. public bool Add(uint entityId, uint indexInComponentArray)
  187. {
  188. //it's a TryAdd because there is no reason to not replace the index if the entity is already there
  189. //TODO: when sentinels are finished, we need to add AsWriter here
  190. //cannot write in parallel
  191. return _entityIDToDenseIndex.TryAdd(entityId, indexInComponentArray, out _);
  192. }
  193. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  194. public bool Exists(uint entityId) => _entityIDToDenseIndex.ContainsKey(entityId);
  195. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  196. public bool Remove(uint entityId) => _entityIDToDenseIndex.Remove(entityId);
  197. public EntityFilterIndices indices
  198. {
  199. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  200. get
  201. {
  202. var values = _entityIDToDenseIndex.GetValues(out var count);
  203. return new EntityFilterIndices(values, count);
  204. }
  205. }
  206. public uint this[uint entityId]
  207. {
  208. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  209. get => _entityIDToDenseIndex[entityId];
  210. }
  211. public int count => _entityIDToDenseIndex.count;
  212. public bool isValid => _entityIDToDenseIndex.isValid;
  213. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  214. internal void Clear()
  215. {
  216. _entityIDToDenseIndex.Clear();
  217. }
  218. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  219. internal void Dispose()
  220. {
  221. _entityIDToDenseIndex.Dispose();
  222. }
  223. internal ExclusiveGroupStruct group => _group;
  224. internal SharedSveltoDictionaryNative<uint, uint> _entityIDToDenseIndex;
  225. readonly ExclusiveGroupStruct _group;
  226. }
  227. }
  228. }