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.

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