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.

349 lines
16KB

  1. using System;
  2. using System.Threading;
  3. using Svelto.Common;
  4. using Svelto.DataStructures;
  5. using Svelto.DataStructures.Native;
  6. using Svelto.ECS.DataStructures;
  7. namespace Svelto.ECS
  8. {
  9. public struct FilterContextID
  10. {
  11. public readonly uint id;
  12. internal FilterContextID(uint id)
  13. {
  14. DBC.ECS.Check.Require(id < ushort.MaxValue, "too many types registered, HOW :)");
  15. this.id = id;
  16. }
  17. }
  18. public readonly struct CombinedFilterID
  19. {
  20. internal readonly long id;
  21. public FilterContextID contextID => new FilterContextID((uint)((id & 0xFFFF0000) >> 16));
  22. public uint filterID => (uint)(id >> 32);
  23. public CombinedFilterID(int filterID, FilterContextID contextID)
  24. {
  25. id = (long)filterID << 32 | (uint)contextID.id << 16;
  26. }
  27. public static implicit operator CombinedFilterID((int filterID, FilterContextID contextID) data)
  28. {
  29. return new CombinedFilterID(data.filterID, data.contextID);
  30. }
  31. }
  32. //this cannot be inside EntitiesDB otherwise it will cause hashing of reference in Burst
  33. public class Internal_FilterHelper
  34. {
  35. //since the user can choose their own filterID, in order to avoid collisions between
  36. //filters of the same type, the FilterContext is provided. The type is identified through
  37. //TypeCounter
  38. public static long CombineFilterIDs<T>(CombinedFilterID combinedFilterID) where T: struct, IEntityComponent
  39. {
  40. var id = (uint)ComponentID<T>.id.Data;
  41. var combineFilterIDs = (long)combinedFilterID.id | id;
  42. return combineFilterIDs;
  43. }
  44. }
  45. public partial class EntitiesDB
  46. {
  47. public SveltoFilters GetFilters()
  48. {
  49. return new SveltoFilters(_enginesRoot._persistentEntityFilters,
  50. _enginesRoot._indicesOfPersistentFiltersUsedByThisComponent, _enginesRoot._transientEntityFilters);
  51. }
  52. /// <summary>
  53. /// this whole structure is usable inside DOTS JOBS and BURST
  54. /// </summary>
  55. public readonly struct SveltoFilters
  56. {
  57. static readonly SharedStaticWrapper<int, Internal_FilterHelper> uniqueContextID;
  58. #if UNITY_BURST
  59. [Unity.Burst.BurstDiscard]
  60. //SharedStatic values must be initialized from not burstified code
  61. #endif
  62. public static FilterContextID GetNewContextID()
  63. {
  64. return new FilterContextID((uint)Interlocked.Increment(ref uniqueContextID.Data));
  65. }
  66. public SveltoFilters(SharedSveltoDictionaryNative<long, EntityFilterCollection> persistentEntityFilters,
  67. SharedSveltoDictionaryNative<NativeRefWrapperType, NativeDynamicArrayCast<int>>
  68. indicesOfPersistentFiltersUsedByThisComponent,
  69. SharedSveltoDictionaryNative<long, EntityFilterCollection> transientEntityFilters)
  70. {
  71. _persistentEntityFilters = persistentEntityFilters;
  72. _indicesOfPersistentFiltersUsedByThisComponent = indicesOfPersistentFiltersUsedByThisComponent;
  73. _transientEntityFilters = transientEntityFilters;
  74. }
  75. #if UNITY_BURST
  76. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID,
  77. FilterContextID filterContextId, NativeRefWrapperType typeRef) where T : unmanaged, IEntityComponent
  78. {
  79. return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId), typeRef);
  80. }
  81. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID,
  82. NativeRefWrapperType typeRef) where T : unmanaged, IEntityComponent
  83. {
  84. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  85. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  86. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  87. _persistentEntityFilters.Add(combineFilterIDs, new EntityFilterCollection(filterID));
  88. var lastIndex = _persistentEntityFilters.count - 1;
  89. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(typeRef, out var getIndex) == false)
  90. {
  91. var newArray = new NativeDynamicArrayCast<int>(1, Allocator.Persistent);
  92. newArray.Add(lastIndex);
  93. _indicesOfPersistentFiltersUsedByThisComponent.Add(typeRef, newArray);
  94. }
  95. else
  96. {
  97. ref var array = ref _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(getIndex);
  98. array.Add(lastIndex);
  99. }
  100. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  101. }
  102. #endif
  103. /// <summary>
  104. /// Create a persistent filter. Persistent filters are not deleted after each submission,
  105. /// however they have a maintenance cost that must be taken into account and will affect
  106. /// entities submission performance.
  107. /// </summary>
  108. /// <typeparam name="T"></typeparam>
  109. /// <returns></returns>
  110. #if UNITY_BURST && UNITY_COLLECTIONS
  111. [Unity.Collections.NotBurstCompatible]
  112. #endif
  113. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID, FilterContextID filterContextId)
  114. where T : unmanaged, IEntityComponent
  115. {
  116. return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
  117. }
  118. #if UNITY_BURST && UNITY_COLLECTIONS
  119. [Unity.Collections.NotBurstCompatible]
  120. #endif
  121. public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID)
  122. where T : unmanaged, IEntityComponent
  123. {
  124. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  125. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  126. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  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),
  132. () => new NativeDynamicArrayCast<int>(1, Svelto.Common.Allocator.Persistent)).Add(lastIndex);
  133. return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
  134. }
  135. public ref EntityFilterCollection GetPersistentFilter<T>(int filterID, FilterContextID filterContextId)
  136. where T : unmanaged, IEntityComponent
  137. {
  138. return ref GetPersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
  139. }
  140. public ref EntityFilterCollection GetPersistentFilter<T>(CombinedFilterID filterID)
  141. where T : unmanaged, IEntityComponent
  142. {
  143. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  144. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  145. return ref _persistentEntityFilters.GetDirectValueByRef(index);
  146. throw new Exception("filter not found");
  147. }
  148. public bool TryGetPersistentFilter<T>(CombinedFilterID combinedFilterID, out EntityFilterCollection entityCollection)
  149. where T : unmanaged, IEntityComponent
  150. {
  151. long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(combinedFilterID);
  152. if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true)
  153. {
  154. entityCollection = _persistentEntityFilters.GetDirectValueByRef(index);
  155. return true;
  156. }
  157. entityCollection = default;
  158. return false;
  159. }
  160. public EntityFilterCollectionsEnumerator GetPersistentFilters<T>() where T : unmanaged, IEntityComponent
  161. {
  162. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(
  163. new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true)
  164. return new EntityFilterCollectionsEnumerator(
  165. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  166. _persistentEntityFilters);
  167. throw new Exception($"no filters associated with the type {TypeCache<T>.name}");
  168. }
  169. public EntityFilterCollectionsWithContextEnumerator GetPersistentFilters<T>(FilterContextID filterContextId)
  170. {
  171. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(
  172. new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true)
  173. return new EntityFilterCollectionsWithContextEnumerator(
  174. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  175. _persistentEntityFilters, filterContextId);
  176. throw new Exception($"no filters associated with the type {TypeCache<T>.name}");
  177. }
  178. public bool TryGetPersistentFilters<T>(FilterContextID filterContextId, out EntityFilterCollectionsWithContextEnumerator enumerator)
  179. {
  180. if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(
  181. new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true)
  182. {
  183. enumerator = new EntityFilterCollectionsWithContextEnumerator(
  184. _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index),
  185. _persistentEntityFilters, filterContextId);
  186. return true;
  187. }
  188. enumerator = default;
  189. return false;
  190. }
  191. public struct EntityFilterCollectionsEnumerator
  192. {
  193. public EntityFilterCollectionsEnumerator(NativeDynamicArrayCast<int> getDirectValueByRef,
  194. SharedSveltoDictionaryNative<long, EntityFilterCollection> sharedSveltoDictionaryNative) : this()
  195. {
  196. _getDirectValueByRef = getDirectValueByRef;
  197. _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative;
  198. }
  199. public EntityFilterCollectionsEnumerator GetEnumerator()
  200. {
  201. return this;
  202. }
  203. public bool MoveNext()
  204. {
  205. if (_currentIndex < _getDirectValueByRef.count)
  206. {
  207. _currentIndex++;
  208. return true;
  209. }
  210. return false;
  211. }
  212. public ref EntityFilterCollection Current =>
  213. ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
  214. readonly NativeDynamicArrayCast<int> _getDirectValueByRef;
  215. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _sharedSveltoDictionaryNative;
  216. int _currentIndex;
  217. }
  218. public struct EntityFilterCollectionsWithContextEnumerator
  219. {
  220. public EntityFilterCollectionsWithContextEnumerator(NativeDynamicArrayCast<int> getDirectValueByRef,
  221. SharedSveltoDictionaryNative<long, EntityFilterCollection> sharedSveltoDictionaryNative,
  222. FilterContextID filterContextId) : this()
  223. {
  224. _getDirectValueByRef = getDirectValueByRef;
  225. _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative;
  226. _filterContextId = filterContextId;
  227. }
  228. public EntityFilterCollectionsWithContextEnumerator GetEnumerator()
  229. {
  230. return this;
  231. }
  232. public bool MoveNext()
  233. {
  234. while (_currentIndex++ < _getDirectValueByRef.count &&
  235. _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1).combinedFilterID
  236. .contextID.id != _filterContextId.id) ;
  237. if (_currentIndex - 1 < _getDirectValueByRef.count)
  238. return true;
  239. return false;
  240. }
  241. public ref EntityFilterCollection Current =>
  242. ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
  243. readonly NativeDynamicArrayCast<int> _getDirectValueByRef;
  244. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _sharedSveltoDictionaryNative;
  245. readonly FilterContextID _filterContextId;
  246. int _currentIndex;
  247. }
  248. /// <summary>
  249. /// Creates a transient filter. Transient filters are deleted after each submission
  250. /// </summary>
  251. /// <typeparam name="T"></typeparam>
  252. /// <returns></returns>
  253. public ref EntityFilterCollection GetOrCreateTransientFilter<T>(CombinedFilterID filterID)
  254. where T : unmanaged, IEntityComponent
  255. {
  256. var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  257. if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index))
  258. return ref _transientEntityFilters.GetDirectValueByRef(index);
  259. var filterCollection = new EntityFilterCollection(filterID);
  260. _transientEntityFilters.Add(combineFilterIDs, filterCollection);
  261. return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1));
  262. }
  263. public bool TryGetTransientFilter<T>(CombinedFilterID filterID, out EntityFilterCollection entityCollection)
  264. where T : unmanaged, IEntityComponent
  265. {
  266. var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID);
  267. if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index))
  268. {
  269. entityCollection = _transientEntityFilters.GetDirectValueByRef(index);
  270. return true;
  271. }
  272. entityCollection = default;
  273. return false;
  274. }
  275. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _persistentEntityFilters;
  276. readonly SharedSveltoDictionaryNative<NativeRefWrapperType, NativeDynamicArrayCast<int>>
  277. _indicesOfPersistentFiltersUsedByThisComponent;
  278. readonly SharedSveltoDictionaryNative<long, EntityFilterCollection> _transientEntityFilters;
  279. }
  280. }
  281. }