Mirror of Svelto.ECS because we're a fan of it
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

442 rindas
22KB

  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using System.Threading;
  4. using Svelto.Common;
  5. using Svelto.DataStructures;
  6. using Svelto.DataStructures.Native;
  7. using Svelto.ECS.Internal;
  8. namespace Svelto.ECS
  9. {
  10. //this cannot be inside EntitiesDB otherwise it will cause hashing of reference in Burst
  11. public class Internal_FilterHelper
  12. {
  13. //since the user can choose their own filterID, in order to avoid collisions between
  14. //filters of the same type, the FilterContext is provided. The type is identified through
  15. //ComponentTypeID<T>
  16. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  17. internal static CombinedFilterComponentID CombineFilterIDWithComponentID<T>(CombinedFilterID combinedFilterID)
  18. where T : struct, _IInternalEntityComponent
  19. {
  20. return combinedFilterID.CombineComponent<T>();
  21. }
  22. }
  23. public partial class EntitiesDB
  24. {
  25. public SveltoFilters GetFilters()
  26. {
  27. return new SveltoFilters(
  28. _enginesRoot._persistentEntityFilters,
  29. _enginesRoot._indicesOfPersistentFiltersUsedByThisComponent,
  30. _enginesRoot._transientEntityFilters,
  31. _enginesRoot._indicesOfTransientFiltersUsedByThisComponent);
  32. }
  33. /// <summary>
  34. /// this whole structure is usable inside DOTS JOBS and BURST
  35. /// </summary>
  36. public readonly struct SveltoFilters
  37. {
  38. static readonly SharedStaticWrapper<int, Internal_FilterHelper> uniqueContextID;
  39. #if UNITY_BURST
  40. [Unity.Burst.BurstDiscard]
  41. //SharedStatic values must be initialized from not burstified code
  42. #endif
  43. public static FilterContextID GetNewContextID()
  44. {
  45. return new FilterContextID((ushort)Interlocked.Increment(ref uniqueContextID.Data));
  46. }
  47. internal SveltoFilters(SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> persistentEntityFilters,
  48. SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>> indicesOfPersistentFiltersUsedByThisComponent,
  49. SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> transientEntityFilters,
  50. SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>> indicesOfTransientFiltersUsedByThisComponent)
  51. {
  52. _persistentEntityFilters = persistentEntityFilters;
  53. _indicesOfPersistentFiltersUsedByThisComponent = indicesOfPersistentFiltersUsedByThisComponent;
  54. _transientEntityFilters = transientEntityFilters;
  55. _indicesOfTransientFiltersUsedByThisComponent = indicesOfTransientFiltersUsedByThisComponent;
  56. }
  57. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  58. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID, FilterContextID filterContextId)
  59. where T : struct, _IInternalEntityComponent
  60. {
  61. return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
  62. }
  63. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  64. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID) where T : struct, _IInternalEntityComponent
  65. {
  66. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);
  67. if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true)
  68. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  69. _persistentEntityFilters.Add(componentAndFilterID, new EntityFilterCollection(filterID));
  70. var lastIndex = _persistentEntityFilters.count - 1;
  71. var componentId = ComponentTypeID<T>.id;
  72. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(componentId, out var getIndex) == false)
  73. {
  74. var newArray = new NativeDynamicArrayCast<int>(1, Allocator.Persistent);
  75. newArray.Add(lastIndex);
  76. _indicesOfPersistentFiltersUsedByThisComponent.Add(componentId, newArray);
  77. }
  78. else
  79. {
  80. ref var array = ref _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(getIndex);
  81. array.Add(lastIndex);
  82. }
  83. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  84. }
  85. /// <summary>
  86. /// Create a persistent filter. Persistent filters are not deleted after each submission,
  87. /// however they have a maintenance cost that must be taken into account and will affect
  88. /// entities submission performance.
  89. /// Persistent filters keep track of the entities group swaps and they are automatically updated accordingly.
  90. /// </summary>
  91. /// <typeparam name="T"></typeparam>
  92. /// <returns></returns>
  93. #if UNITY_BURST && UNITY_COLLECTIONS
  94. [Unity.Burst.BurstDiscard] //not burst compatible because of ComponentTypeID<T>.id and GetOrAdd callback;
  95. #endif
  96. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  97. public ref EntityFilterCollection CreatePersistentFilter<T>(CombinedFilterID filterID)
  98. where T : struct, _IInternalEntityComponent
  99. {
  100. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);
  101. if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true)
  102. throw new ECSException("filter already exists");
  103. var filterCollection = new EntityFilterCollection(filterID);
  104. _persistentEntityFilters.Add(componentAndFilterID, filterCollection);
  105. var lastIndex = _persistentEntityFilters.count - 1;
  106. _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(ComponentTypeID<T>.id, _builder).Add(lastIndex);
  107. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  108. }
  109. static NativeDynamicArrayCast<int> Builder()
  110. {
  111. return new NativeDynamicArrayCast<int>(1, Allocator.Persistent);
  112. }
  113. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  114. public ref EntityFilterCollection GetPersistentFilter<T>(int filterID, FilterContextID filterContextId)
  115. where T : struct, _IInternalEntityComponent
  116. {
  117. return ref GetPersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
  118. }
  119. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  120. public ref EntityFilterCollection GetPersistentFilter<T>(CombinedFilterID filterID)
  121. where T : struct, _IInternalEntityComponent
  122. {
  123. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);
  124. if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true)
  125. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  126. throw new ECSException("filter not found");
  127. }
  128. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  129. public bool TryGetPersistentFilter<T>(CombinedFilterID combinedFilterID,
  130. out EntityFilterCollection entityCollection)
  131. where T : struct, _IInternalEntityComponent
  132. {
  133. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(combinedFilterID);
  134. if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true)
  135. {
  136. entityCollection = _persistentEntityFilters.GetDirectValueByRef(index);
  137. return true;
  138. }
  139. entityCollection = default;
  140. return false;
  141. }
  142. /// <summary>
  143. /// Svelto.ECS tracks the filters linked to each
  144. /// component. This allows to iterate over all the filters of a given filter context linked to a component.
  145. /// </summary>
  146. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  147. public EntityFilterCollectionsEnumerator GetPersistentFilters<T>()
  148. where T : struct, _IInternalEntityComponent
  149. {
  150. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID<T>.id, out var index) == true)
  151. return new EntityFilterCollectionsEnumerator(
  152. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  153. _persistentEntityFilters);
  154. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  155. }
  156. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  157. public EntityFilterCollectionsWithContextEnumerator GetPersistentFilters<T>(FilterContextID filterContextId)
  158. where T : struct, _IInternalEntityComponent
  159. {
  160. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID<T>.id, out var index) == true)
  161. return new EntityFilterCollectionsWithContextEnumerator(
  162. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  163. _persistentEntityFilters, filterContextId);
  164. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  165. }
  166. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  167. public bool TryGetPersistentFilters<T>(FilterContextID filterContextId,
  168. out EntityFilterCollectionsWithContextEnumerator enumerator)
  169. where T : struct, _IInternalEntityComponent
  170. {
  171. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID<T>.id, out var index) == true)
  172. {
  173. ref var filterIndices = ref _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index);
  174. enumerator = new EntityFilterCollectionsWithContextEnumerator(filterIndices, _persistentEntityFilters, filterContextId);
  175. return true;
  176. }
  177. enumerator = default;
  178. return false;
  179. }
  180. /// <summary>
  181. /// Creates a transient filter. Transient filters are deleted after each submission
  182. /// transient filters are identified by filterID and Context and can be linked to several groups.
  183. /// So for each group there can be as many as necessary transient filters with different ID and contextID
  184. /// </summary>
  185. /// <typeparam name="T"></typeparam>
  186. /// <returns></returns>
  187. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  188. public ref EntityFilterCollection GetOrCreateTransientFilter<T>(CombinedFilterID combinedFilterID, bool trackFilter = false)
  189. where T : struct, _IInternalEntityComponent
  190. {
  191. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(combinedFilterID);
  192. if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index))
  193. return ref _transientEntityFilters.GetDirectValueByRef(index);
  194. return ref InternalCreateTransientFilter<T>(combinedFilterID, componentAndFilterID, trackFilter);
  195. }
  196. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  197. public ref EntityFilterCollection GetOrCreateTransientFilter<T>(int filterID, FilterContextID filterContextId)
  198. where T : struct, _IInternalEntityComponent
  199. {
  200. return ref GetOrCreateTransientFilter<T>(new CombinedFilterID(filterID, filterContextId));
  201. }
  202. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  203. public ref EntityFilterCollection CreateTransientFilter<T>(CombinedFilterID combinedFilterID, bool trackFilter = false)
  204. where T : struct, _IInternalEntityComponent
  205. {
  206. CombinedFilterComponentID componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(combinedFilterID);
  207. #if DEBUG && !PROFILE_SVELTO
  208. if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out _))
  209. throw new ECSException($"filter already exists {TypeCache<T>.name}");
  210. #endif
  211. return ref InternalCreateTransientFilter<T>(combinedFilterID, componentAndFilterID, trackFilter);
  212. }
  213. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  214. public bool TryGetTransientFilter<T>(CombinedFilterID filterID, out EntityFilterCollection entityCollection)
  215. where T : struct, _IInternalEntityComponent
  216. {
  217. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);
  218. if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index))
  219. {
  220. entityCollection = _transientEntityFilters.GetDirectValueByRef(index);
  221. return true;
  222. }
  223. entityCollection = default;
  224. return false;
  225. }
  226. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  227. public ref EntityFilterCollection GetTransientFilter<T>(CombinedFilterID filterID)
  228. where T : struct, _IInternalEntityComponent
  229. {
  230. var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);
  231. if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index))
  232. {
  233. return ref _transientEntityFilters.GetDirectValueByRef(index);
  234. }
  235. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  236. }
  237. /// <summary>
  238. /// Svelto.ECS tracks the filters linked to each
  239. /// component. This allows to iterate over all the filters of a given filter context linked to a component.
  240. /// </summary>
  241. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  242. public EntityFilterCollectionsEnumerator GetTransientFilters<T>()
  243. where T : struct, _IInternalEntityComponent
  244. {
  245. if (_indicesOfTransientFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID<T>.id, out var index) == true)
  246. return new EntityFilterCollectionsEnumerator(
  247. _indicesOfTransientFiltersUsedByThisComponent.GetDirectValueByRef(index),
  248. _transientEntityFilters);
  249. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  250. }
  251. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  252. public EntityFilterCollectionsWithContextEnumerator GetTransientFilters<T>(FilterContextID filterContextId)
  253. where T : struct, _IInternalEntityComponent
  254. {
  255. if (_indicesOfTransientFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID<T>.id, out var index) == true)
  256. return new EntityFilterCollectionsWithContextEnumerator(
  257. _indicesOfTransientFiltersUsedByThisComponent.GetDirectValueByRef(index),
  258. _transientEntityFilters, filterContextId);
  259. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  260. }
  261. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  262. public bool TryGetTransientFilters<T>(FilterContextID filterContextId, out EntityFilterCollectionsWithContextEnumerator enumerator)
  263. where T : struct, _IInternalEntityComponent
  264. {
  265. if (_indicesOfTransientFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID<T>.id, out var index) == true)
  266. {
  267. enumerator = new EntityFilterCollectionsWithContextEnumerator(
  268. _indicesOfTransientFiltersUsedByThisComponent.GetDirectValueByRef(index),
  269. _transientEntityFilters, filterContextId);
  270. return true;
  271. }
  272. enumerator = default;
  273. return false;
  274. }
  275. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  276. ref EntityFilterCollection InternalCreateTransientFilter<T>(CombinedFilterID filterID, CombinedFilterComponentID componentAndFilterID,
  277. bool trackFilter)
  278. where T : struct, _IInternalEntityComponent
  279. {
  280. var filterCollection = new EntityFilterCollection(filterID);
  281. _transientEntityFilters.Add(componentAndFilterID, filterCollection);
  282. if (trackFilter)
  283. {
  284. var typeRef = ComponentTypeID<T>.id;
  285. var lastIndex = _transientEntityFilters.count - 1;
  286. _indicesOfTransientFiltersUsedByThisComponent.GetOrAdd(ComponentTypeID<T>.id, _builder).Add(lastIndex);
  287. }
  288. return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1));
  289. }
  290. public struct EntityFilterCollectionsEnumerator
  291. {
  292. internal EntityFilterCollectionsEnumerator(NativeDynamicArrayCast<int> getDirectValueByRef,
  293. SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> sharedSveltoDictionaryNative): this()
  294. {
  295. _getDirectValueByRef = getDirectValueByRef;
  296. _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative;
  297. }
  298. public EntityFilterCollectionsEnumerator GetEnumerator()
  299. {
  300. return this;
  301. }
  302. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  303. public bool MoveNext()
  304. {
  305. if (_currentIndex < _getDirectValueByRef.count)
  306. {
  307. _currentIndex++;
  308. return true;
  309. }
  310. return false;
  311. }
  312. public ref EntityFilterCollection Current
  313. {
  314. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  315. get => ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
  316. }
  317. readonly NativeDynamicArrayCast<int> _getDirectValueByRef;
  318. readonly SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> _sharedSveltoDictionaryNative;
  319. int _currentIndex;
  320. }
  321. /// <summary>
  322. /// TODO: ABSOLUTELY UNIT TEST THIS AS THE CODE WAS WRONG!!!
  323. /// </summary>
  324. public struct EntityFilterCollectionsWithContextEnumerator
  325. {
  326. internal EntityFilterCollectionsWithContextEnumerator(NativeDynamicArrayCast<int> filterIndices,
  327. SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> sharedSveltoDictionaryNative,
  328. FilterContextID filterContextId): this()
  329. {
  330. _filterIndices = filterIndices;
  331. _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative;
  332. _filterContextId = filterContextId;
  333. }
  334. public EntityFilterCollectionsWithContextEnumerator GetEnumerator()
  335. {
  336. return this;
  337. }
  338. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  339. public bool MoveNext()
  340. {
  341. while (_currentIndex++ < _filterIndices.count &&
  342. _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_filterIndices[(uint)_currentIndex - 1]).combinedFilterID
  343. .contextID.id != _filterContextId.id);
  344. if (_currentIndex - 1 < _filterIndices.count)
  345. return true;
  346. return false;
  347. }
  348. public ref EntityFilterCollection Current
  349. {
  350. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  351. get => ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_filterIndices[(uint)_currentIndex - 1]);
  352. }
  353. readonly NativeDynamicArrayCast<int> _filterIndices;
  354. readonly SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> _sharedSveltoDictionaryNative;
  355. readonly FilterContextID _filterContextId;
  356. int _currentIndex;
  357. }
  358. readonly SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> _persistentEntityFilters;
  359. readonly SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>>
  360. _indicesOfPersistentFiltersUsedByThisComponent;
  361. readonly SharedSveltoDictionaryNative<CombinedFilterComponentID, EntityFilterCollection> _transientEntityFilters;
  362. readonly SharedSveltoDictionaryNative<ComponentID, NativeDynamicArrayCast<int>>
  363. _indicesOfTransientFiltersUsedByThisComponent;
  364. static readonly Func<NativeDynamicArrayCast<int>> _builder = Builder;
  365. }
  366. }
  367. }