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.

403 lines
18KB

  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. //TypeCounter
  16. public static long CombineFilterIDs<T>(CombinedFilterID combinedFilterID)
  17. where T : struct, _IInternalEntityComponent
  18. {
  19. var id = (uint)ComponentID<T>.id.Data;
  20. var combineFilterIDs = (long)combinedFilterID.id | id;
  21. return combineFilterIDs;
  22. }
  23. }
  24. public partial class EntitiesDB
  25. {
  26. public SveltoFilters GetFilters()
  27. {
  28. return new SveltoFilters(
  29. _enginesRoot._persistentEntityFilters,
  30. _enginesRoot._indicesOfPersistentFiltersUsedByThisComponent, _enginesRoot._transientEntityFilters);
  31. }
  32. /// <summary>
  33. /// this whole structure is usable inside DOTS JOBS and BURST
  34. /// </summary>
  35. public readonly struct SveltoFilters
  36. {
  37. static readonly SharedStaticWrapper<int, Internal_FilterHelper> uniqueContextID;
  38. #if UNITY_BURST
  39. [Unity.Burst.BurstDiscard]
  40. //SharedStatic values must be initialized from not burstified code
  41. #endif
  42. public static FilterContextID GetNewContextID()
  43. {
  44. return new FilterContextID((uint)Interlocked.Increment(ref uniqueContextID.Data));
  45. }
  46. public SveltoFilters(SharedSveltoDictionaryNative<long, EntityFilterCollection> persistentEntityFilters,
  47. SharedSveltoDictionaryNative<NativeRefWrapperType, NativeDynamicArrayCast<int>>
  48. indicesOfPersistentFiltersUsedByThisComponent,
  49. SharedSveltoDictionaryNative<long, EntityFilterCollection> transientEntityFilters)
  50. {
  51. _persistentEntityFilters = persistentEntityFilters;
  52. _indicesOfPersistentFiltersUsedByThisComponent = indicesOfPersistentFiltersUsedByThisComponent;
  53. _transientEntityFilters = transientEntityFilters;
  54. }
  55. #if UNITY_BURST //the following methods do not make sense without burst as they are workaround for burst
  56. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID,
  57. FilterContextID filterContextId, NativeRefWrapperType typeRef)
  58. where T : unmanaged, IEntityComponent
  59. {
  60. return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId), typeRef);
  61. }
  62. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID,
  63. NativeRefWrapperType typeRef)
  64. where T : unmanaged, IEntityComponent
  65. {
  66. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  67. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  68. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  69. _persistentEntityFilters.Add(combineFilterIDs, new EntityFilterCollection(filterID));
  70. var lastIndex = _persistentEntityFilters.count - 1;
  71. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(typeRef, out var getIndex) == false)
  72. {
  73. var newArray = new NativeDynamicArrayCast<int>(1, Allocator.Persistent);
  74. newArray.Add(lastIndex);
  75. _indicesOfPersistentFiltersUsedByThisComponent.Add(typeRef, newArray);
  76. }
  77. else
  78. {
  79. ref var array = ref _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(getIndex);
  80. array.Add(lastIndex);
  81. }
  82. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  83. }
  84. #endif
  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. /// </summary>
  90. /// <typeparam name="T"></typeparam>
  91. /// <returns></returns>
  92. #if UNITY_BURST && UNITY_COLLECTIONS
  93. [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper<T>.wrapper;
  94. #endif
  95. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  96. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID,
  97. FilterContextID filterContextId)
  98. where T : unmanaged, _IInternalEntityComponent
  99. {
  100. return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
  101. }
  102. #if UNITY_BURST && UNITY_COLLECTIONS
  103. [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper<T>.wrapper and GetOrAdd callback;
  104. #endif
  105. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID)
  106. where T : unmanaged, _IInternalEntityComponent
  107. {
  108. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  109. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  110. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  111. var typeRef = TypeRefWrapper<T>.wrapper;
  112. var filterCollection = new EntityFilterCollection(filterID);
  113. _persistentEntityFilters.Add(combineFilterIDs, filterCollection);
  114. var lastIndex = _persistentEntityFilters.count - 1;
  115. _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(new NativeRefWrapperType(typeRef), _builder).Add(lastIndex);
  116. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  117. }
  118. #if UNITY_BURST && UNITY_COLLECTIONS
  119. [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper<T>.wrapper and GetOrAdd callback;
  120. #endif
  121. public ref EntityFilterCollection CreatePersistentFilter<T>(CombinedFilterID filterID)
  122. where T : unmanaged, _IInternalEntityComponent
  123. {
  124. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  125. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  126. throw new ECSException("filter already exists");
  127. var typeRef = TypeRefWrapper<T>.wrapper;
  128. var filterCollection = new EntityFilterCollection(filterID);
  129. _persistentEntityFilters.Add(combineFilterIDs, filterCollection);
  130. var lastIndex = _persistentEntityFilters.count - 1;
  131. _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(new NativeRefWrapperType(typeRef), _builder).Add(lastIndex);
  132. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  133. }
  134. static NativeDynamicArrayCast<int> Builder()
  135. {
  136. return new NativeDynamicArrayCast<int>(1, Allocator.Persistent);
  137. }
  138. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  139. public ref EntityFilterCollection GetPersistentFilter<T>(int filterID, FilterContextID filterContextId)
  140. where T : unmanaged, _IInternalEntityComponent
  141. {
  142. return ref GetPersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
  143. }
  144. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  145. public ref EntityFilterCollection GetPersistentFilter<T>(CombinedFilterID filterID)
  146. where T : unmanaged, _IInternalEntityComponent
  147. {
  148. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  149. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  150. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  151. throw new ECSException("filter not found");
  152. }
  153. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  154. public bool TryGetPersistentFilter<T>(CombinedFilterID combinedFilterID,
  155. out EntityFilterCollection entityCollection)
  156. where T : unmanaged, _IInternalEntityComponent
  157. {
  158. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(combinedFilterID);
  159. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  160. {
  161. entityCollection = _persistentEntityFilters.GetDirectValueByRef(index);
  162. return true;
  163. }
  164. entityCollection = default;
  165. return false;
  166. }
  167. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  168. public EntityFilterCollectionsEnumerator GetPersistentFilters<T>()
  169. where T : unmanaged, _IInternalEntityComponent
  170. {
  171. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(
  172. new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true)
  173. return new EntityFilterCollectionsEnumerator(
  174. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  175. _persistentEntityFilters);
  176. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  177. }
  178. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  179. public EntityFilterCollectionsWithContextEnumerator GetPersistentFilters<T>(FilterContextID filterContextId)
  180. {
  181. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(
  182. new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true)
  183. return new EntityFilterCollectionsWithContextEnumerator(
  184. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  185. _persistentEntityFilters, filterContextId);
  186. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  187. }
  188. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  189. public bool TryGetPersistentFilters<T>(FilterContextID filterContextId,
  190. out EntityFilterCollectionsWithContextEnumerator enumerator)
  191. {
  192. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(
  193. new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true)
  194. {
  195. enumerator = new EntityFilterCollectionsWithContextEnumerator(
  196. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  197. _persistentEntityFilters, filterContextId);
  198. return true;
  199. }
  200. enumerator = default;
  201. return false;
  202. }
  203. /// <summary>
  204. /// Creates a transient filter. Transient filters are deleted after each submission
  205. /// </summary>
  206. /// <typeparam name="T"></typeparam>
  207. /// <returns></returns>
  208. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  209. public ref EntityFilterCollection GetOrCreateTransientFilter<T>(CombinedFilterID filterID)
  210. where T : unmanaged, _IInternalEntityComponent
  211. {
  212. var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  213. if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index))
  214. return ref _transientEntityFilters.GetDirectValueByRef(index);
  215. var filterCollection = new EntityFilterCollection(filterID);
  216. _transientEntityFilters.Add(combineFilterIDs, filterCollection);
  217. return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1));
  218. }
  219. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  220. public bool TryGetTransientFilter<T>(CombinedFilterID filterID, out EntityFilterCollection entityCollection)
  221. where T : unmanaged, _IInternalEntityComponent
  222. {
  223. var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  224. if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index))
  225. {
  226. entityCollection = _transientEntityFilters.GetDirectValueByRef(index);
  227. return true;
  228. }
  229. entityCollection = default;
  230. return false;
  231. }
  232. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  233. public ref EntityFilterCollection GetTransientFilter<T>(CombinedFilterID filterID)
  234. where T : unmanaged, _IInternalEntityComponent
  235. {
  236. var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  237. if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index))
  238. {
  239. return ref _transientEntityFilters.GetDirectValueByRef(index);
  240. }
  241. throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
  242. }
  243. public void CreateTransientFilter<T>(CombinedFilterID filterID)
  244. where T : struct, _IInternalEntityComponent
  245. {
  246. var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  247. #if DEBUG && !PROFILE_SVELTO
  248. if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out _))
  249. throw new ECSException($"filter already exists {TypeCache<T>.name}");
  250. #endif
  251. var filterCollection = new EntityFilterCollection(filterID);
  252. _transientEntityFilters.Add(combineFilterIDs, filterCollection);
  253. }
  254. public struct EntityFilterCollectionsEnumerator
  255. {
  256. public EntityFilterCollectionsEnumerator(NativeDynamicArrayCast<int> getDirectValueByRef,
  257. SharedSveltoDictionaryNative<long, EntityFilterCollection> sharedSveltoDictionaryNative): this()
  258. {
  259. _getDirectValueByRef = getDirectValueByRef;
  260. _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative;
  261. }
  262. public EntityFilterCollectionsEnumerator GetEnumerator()
  263. {
  264. return this;
  265. }
  266. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  267. public bool MoveNext()
  268. {
  269. if (_currentIndex < _getDirectValueByRef.count)
  270. {
  271. _currentIndex++;
  272. return true;
  273. }
  274. return false;
  275. }
  276. public ref EntityFilterCollection Current
  277. {
  278. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  279. get
  280. {
  281. return ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
  282. }
  283. }
  284. readonly NativeDynamicArrayCast<int> _getDirectValueByRef;
  285. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _sharedSveltoDictionaryNative;
  286. int _currentIndex;
  287. }
  288. public struct EntityFilterCollectionsWithContextEnumerator
  289. {
  290. public EntityFilterCollectionsWithContextEnumerator(NativeDynamicArrayCast<int> getDirectValueByRef,
  291. SharedSveltoDictionaryNative<long, EntityFilterCollection> sharedSveltoDictionaryNative,
  292. FilterContextID filterContextId): this()
  293. {
  294. _getDirectValueByRef = getDirectValueByRef;
  295. _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative;
  296. _filterContextId = filterContextId;
  297. }
  298. public EntityFilterCollectionsWithContextEnumerator GetEnumerator()
  299. {
  300. return this;
  301. }
  302. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  303. public bool MoveNext()
  304. {
  305. while (_currentIndex++ < _getDirectValueByRef.count &&
  306. _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1).combinedFilterID
  307. .contextID.id != _filterContextId.id) ;
  308. if (_currentIndex - 1 < _getDirectValueByRef.count)
  309. return true;
  310. return false;
  311. }
  312. public ref EntityFilterCollection Current
  313. {
  314. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  315. get
  316. {
  317. return ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
  318. }
  319. }
  320. readonly NativeDynamicArrayCast<int> _getDirectValueByRef;
  321. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _sharedSveltoDictionaryNative;
  322. readonly FilterContextID _filterContextId;
  323. int _currentIndex;
  324. }
  325. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _persistentEntityFilters;
  326. readonly SharedSveltoDictionaryNative<NativeRefWrapperType, NativeDynamicArrayCast<int>>
  327. _indicesOfPersistentFiltersUsedByThisComponent;
  328. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _transientEntityFilters;
  329. static readonly Func<NativeDynamicArrayCast<int>> _builder = Builder;
  330. }
  331. }
  332. }