Mirror of Svelto.ECS because we're a fan of it
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

345 satır
17KB

  1. #if DEBUG && !PROFILE_SVELTO
  2. #define ENABLE_DEBUG_FUNC
  3. #endif
  4. using System;
  5. using System.Runtime.CompilerServices;
  6. using Svelto.Common;
  7. using Svelto.DataStructures;
  8. using Svelto.ECS.Internal;
  9. namespace Svelto.ECS
  10. {
  11. public partial class EntitiesDB
  12. {
  13. internal EntitiesDB(EnginesRoot enginesRoot, EnginesRoot.EntityReferenceMap entityReferencesMap)
  14. {
  15. _enginesRoot = enginesRoot;
  16. _entityReferencesMap = entityReferencesMap;
  17. }
  18. EntityCollection<T> InternalQueryEntities<T>
  19. (FasterDictionary<ComponentID, ITypeSafeDictionary> entitiesInGroupPerType)
  20. where T : struct, _IInternalEntityComponent
  21. {
  22. uint count = 0;
  23. IBuffer<T> buffer;
  24. IEntityIDs ids = default;
  25. if (SafeQueryEntityDictionary<T>(out var typeSafeDictionary, entitiesInGroupPerType) == false)
  26. buffer = default;
  27. else
  28. {
  29. ITypeSafeDictionary<T> safeDictionary = (typeSafeDictionary as ITypeSafeDictionary<T>);
  30. buffer = safeDictionary.GetValues(out count);
  31. ids = safeDictionary.entityIDs;
  32. }
  33. return new EntityCollection<T>(buffer, ids, count);
  34. }
  35. /// <summary>
  36. /// The QueryEntities<T> follows the rule that entities could always be iterated regardless if they
  37. /// are 0, 1 or N. In case of 0 it returns an empty array. This allows to use the same for iteration
  38. /// regardless the number of entities built.
  39. /// </summary>
  40. /// <param name="groupStructId"></param>
  41. /// <typeparam name="T"></typeparam>
  42. /// <returns></returns>
  43. public EntityCollection<T> QueryEntities<T>(ExclusiveGroupStruct groupStructId)
  44. where T : struct, _IInternalEntityComponent
  45. {
  46. if (groupEntityComponentsDB.TryGetValue(groupStructId, out var entitiesInGroupPerType) == false)
  47. {
  48. return new EntityCollection<T>(default, default, 0);
  49. }
  50. return InternalQueryEntities<T>(entitiesInGroupPerType);
  51. }
  52. public EntityCollection<T1, T2> QueryEntities<T1, T2>(ExclusiveGroupStruct groupStruct)
  53. where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent
  54. {
  55. if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false)
  56. {
  57. return new EntityCollection<T1, T2>(
  58. new EntityCollection<T1>(default, default, 0)
  59. , new EntityCollection<T2>(default, default, 0));
  60. }
  61. var T1entities = InternalQueryEntities<T1>(entitiesInGroupPerType);
  62. var T2entities = InternalQueryEntities<T2>(entitiesInGroupPerType);
  63. #if DEBUG && !PROFILE_SVELTO
  64. if (T1entities.count != T2entities.count)
  65. throw new ECSException("Entity components count do not match in group. Entity 1: ' count: "
  66. .FastConcat(T1entities.count).FastConcat(" ", typeof(T1).ToString())
  67. .FastConcat("'. Entity 2: ' count: ".FastConcat(T2entities.count)
  68. .FastConcat(" ", typeof(T2).ToString())
  69. .FastConcat(
  70. "' group: ", groupStruct.ToName())).FastConcat(" this means that you are mixing descriptors in the same group that do not share the components that you are querying"));
  71. #endif
  72. return new EntityCollection<T1, T2>(T1entities, T2entities);
  73. }
  74. public EntityCollection<T1, T2, T3> QueryEntities<T1, T2, T3>(ExclusiveGroupStruct groupStruct)
  75. where T1 : struct, _IInternalEntityComponent
  76. where T2 : struct, _IInternalEntityComponent
  77. where T3 : struct, _IInternalEntityComponent
  78. {
  79. if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false)
  80. {
  81. return new EntityCollection<T1, T2, T3>(
  82. new EntityCollection<T1>(default, default, 0)
  83. , new EntityCollection<T2>(default, default, 0)
  84. , new EntityCollection<T3>(default, default, 0));
  85. }
  86. var T1entities = InternalQueryEntities<T1>(entitiesInGroupPerType);
  87. var T2entities = InternalQueryEntities<T2>(entitiesInGroupPerType);
  88. var T3entities = InternalQueryEntities<T3>(entitiesInGroupPerType);
  89. #if DEBUG && !PROFILE_SVELTO
  90. if (T1entities.count != T2entities.count || T2entities.count != T3entities.count)
  91. throw new ECSException("Entity components count do not match in group. Entity 1: "
  92. .FastConcat(typeof(T1).ToString()).FastConcat(" count: ")
  93. .FastConcat(T1entities.count).FastConcat(
  94. " Entity 2: ".FastConcat(typeof(T2).ToString()).FastConcat(" count: ")
  95. .FastConcat(T2entities.count)
  96. .FastConcat(" Entity 3: ".FastConcat(typeof(T3).ToString()))
  97. .FastConcat(" count: ").FastConcat(T3entities.count)).FastConcat(" this means that you are mixing descriptors in the same group that do not share the components that you are querying"));
  98. #endif
  99. return new EntityCollection<T1, T2, T3>(T1entities, T2entities, T3entities);
  100. }
  101. public EntityCollection<T1, T2, T3, T4> QueryEntities<T1, T2, T3, T4>(ExclusiveGroupStruct groupStruct)
  102. where T1 : struct, _IInternalEntityComponent
  103. where T2 : struct, _IInternalEntityComponent
  104. where T3 : struct, _IInternalEntityComponent
  105. where T4 : struct, _IInternalEntityComponent
  106. {
  107. if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false)
  108. {
  109. return new EntityCollection<T1, T2, T3, T4>(
  110. new EntityCollection<T1>(default, default, 0)
  111. , new EntityCollection<T2>(default, default, 0)
  112. , new EntityCollection<T3>(default, default, 0)
  113. , new EntityCollection<T4>(default, default, 0));
  114. }
  115. var T1entities = InternalQueryEntities<T1>(entitiesInGroupPerType);
  116. var T2entities = InternalQueryEntities<T2>(entitiesInGroupPerType);
  117. var T3entities = InternalQueryEntities<T3>(entitiesInGroupPerType);
  118. var T4entities = InternalQueryEntities<T4>(entitiesInGroupPerType);
  119. #if DEBUG && !PROFILE_SVELTO
  120. if (T1entities.count != T2entities.count || T2entities.count != T3entities.count
  121. || T3entities.count != T4entities.count)
  122. throw new ECSException("Entity components count do not match in group. Entity 1: "
  123. .FastConcat(typeof(T1).ToString()).FastConcat(" count: ")
  124. .FastConcat(T1entities.count).FastConcat(
  125. " Entity 2: ".FastConcat(typeof(T2).ToString()).FastConcat(" count: ")
  126. .FastConcat(T2entities.count)
  127. .FastConcat(" Entity 3: ".FastConcat(typeof(T3).ToString()))
  128. .FastConcat(" count: ").FastConcat(T3entities.count)
  129. .FastConcat(" Entity 4: ".FastConcat(typeof(T4).ToString()))
  130. .FastConcat(" count: ").FastConcat(T4entities.count)).FastConcat(" this means that you are mixing descriptors in the same group that do not share the components that you are querying"));
  131. #endif
  132. return new EntityCollection<T1, T2, T3, T4>(T1entities, T2entities, T3entities, T4entities);
  133. }
  134. public GroupsEnumerable<T> QueryEntities<T>
  135. (in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T : struct, _IInternalEntityComponent
  136. {
  137. return new GroupsEnumerable<T>(this, groups);
  138. }
  139. /// <summary>
  140. /// Note: Remember that EntityViewComponents are always put at the end of the generic parameters tuple.
  141. /// The Query entity code won't inexplicably compile otherwise
  142. /// </summary>
  143. /// <returns></returns>
  144. public GroupsEnumerable<T1, T2> QueryEntities<T1, T2>(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups)
  145. where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent
  146. {
  147. return new GroupsEnumerable<T1, T2>(this, groups);
  148. }
  149. public GroupsEnumerable<T1, T2, T3> QueryEntities<T1, T2, T3>
  150. (in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T1 : struct, _IInternalEntityComponent
  151. where T2 : struct, _IInternalEntityComponent
  152. where T3 : struct, _IInternalEntityComponent
  153. {
  154. return new GroupsEnumerable<T1, T2, T3>(this, groups);
  155. }
  156. public GroupsEnumerable<T1, T2, T3, T4> QueryEntities<T1, T2, T3, T4>
  157. (in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T1 : struct, _IInternalEntityComponent
  158. where T2 : struct, _IInternalEntityComponent
  159. where T3 : struct, _IInternalEntityComponent
  160. where T4 : struct, _IInternalEntityComponent
  161. {
  162. return new GroupsEnumerable<T1, T2, T3, T4>(this, groups);
  163. }
  164. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  165. public EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroupStruct groupStructId)
  166. where T : struct, _IInternalEntityComponent
  167. {
  168. if (SafeQueryEntityDictionary<T>(groupStructId, out var typeSafeDictionary) == false)
  169. throw new EntityGroupNotFoundException(typeof(T), groupStructId.ToName());
  170. return (typeSafeDictionary as ITypeSafeDictionary<T>).ToEGIDMapper(groupStructId);
  171. }
  172. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  173. public bool TryQueryMappedEntities<T>
  174. (ExclusiveGroupStruct groupStructId, out EGIDMapper<T> mapper) where T : struct, _IInternalEntityComponent
  175. {
  176. mapper = default;
  177. if (SafeQueryEntityDictionary<T>(groupStructId, out var typeSafeDictionary) == false
  178. || typeSafeDictionary.count == 0)
  179. return false;
  180. mapper = (typeSafeDictionary as ITypeSafeDictionary<T>).ToEGIDMapper(groupStructId);
  181. return true;
  182. }
  183. /// <summary>
  184. /// determine if component with specific ID exists in group
  185. /// </summary>
  186. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  187. public bool Exists<T>(EGID entityGID) where T : struct, _IInternalEntityComponent
  188. {
  189. if (SafeQueryEntityDictionary<T>(entityGID.groupID, out var casted) == false)
  190. return false;
  191. return casted != null && casted.ContainsKey(entityGID.entityID);
  192. }
  193. /// <summary>
  194. /// determine if component with specific ID exists in group
  195. /// </summary>
  196. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  197. public bool Exists<T>(uint id, ExclusiveGroupStruct group) where T : struct, _IInternalEntityComponent
  198. {
  199. if (SafeQueryEntityDictionary<T>(group, out var casted) == false)
  200. return false;
  201. return casted != null && casted.ContainsKey(id);
  202. }
  203. /// <summary>
  204. /// determine if group exists and is not empty
  205. /// </summary>
  206. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  207. public bool ExistsAndIsNotEmpty(ExclusiveGroupStruct gid)
  208. {
  209. if (groupEntityComponentsDB.TryGetValue(
  210. gid, out FasterDictionary<ComponentID, ITypeSafeDictionary> group) == true)
  211. {
  212. return group.count > 0;
  213. }
  214. return false;
  215. }
  216. /// <summary>
  217. /// determine if entities we specific components are found in group
  218. /// </summary>
  219. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  220. public bool HasAny<T>(ExclusiveGroupStruct groupStruct) where T : struct, _IInternalEntityComponent
  221. {
  222. return Count<T>(groupStruct) > 0;
  223. }
  224. /// <summary>
  225. /// count the number of components in a group
  226. /// </summary>
  227. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  228. public int Count<T>(ExclusiveGroupStruct groupStruct) where T : struct, _IInternalEntityComponent
  229. {
  230. if (SafeQueryEntityDictionary<T>(groupStruct, out var typeSafeDictionary) == false)
  231. return 0;
  232. return (int)typeSafeDictionary.count;
  233. }
  234. public bool FoundInGroups<T>() where T : struct, _IInternalEntityComponent
  235. {
  236. return groupsPerComponent.ContainsKey(ComponentTypeID<T>.id);
  237. }
  238. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  239. bool SafeQueryEntityDictionary<T>
  240. (out ITypeSafeDictionary typeSafeDictionary
  241. , FasterDictionary<ComponentID, ITypeSafeDictionary> entitiesInGroupPerType) where T : struct, _IInternalEntityComponent
  242. {
  243. if (entitiesInGroupPerType.TryGetValue(ComponentTypeID<T>.id, out var safeDictionary)
  244. == false)
  245. {
  246. typeSafeDictionary = default;
  247. return false;
  248. }
  249. //return the indexes entities if they exist
  250. typeSafeDictionary = safeDictionary;
  251. return true;
  252. }
  253. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  254. internal bool SafeQueryEntityDictionary<T>
  255. (ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : struct, _IInternalEntityComponent
  256. {
  257. if (UnsafeQueryEntityDictionary(group, ComponentTypeID<T>.id, out var safeDictionary) == false)
  258. {
  259. typeSafeDictionary = default;
  260. return false;
  261. }
  262. //return the indexes entities if they exist
  263. typeSafeDictionary = safeDictionary;
  264. return true;
  265. }
  266. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  267. internal bool UnsafeQueryEntityDictionary
  268. (ExclusiveGroupStruct group, ComponentID id, out ITypeSafeDictionary typeSafeDictionary)
  269. {
  270. //search for the group
  271. if (groupEntityComponentsDB.TryGetValue(group, out var entitiesInGroupPerType) == false)
  272. {
  273. typeSafeDictionary = null;
  274. return false;
  275. }
  276. //search for the indexed entities in the group
  277. return entitiesInGroupPerType.TryGetValue(id, out typeSafeDictionary);
  278. }
  279. static readonly FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary> _emptyDictionary =
  280. new FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>();
  281. readonly EnginesRoot _enginesRoot;
  282. EntitiesStreams _entityStream => _enginesRoot._entityStreams;
  283. //grouped set of entity components, this is the standard way to handle entity components are grouped per
  284. //group, then indexable per type, then indexable per EGID. however the TypeSafeDictionary can return an array of
  285. //values directly, that can be iterated over, so that is possible to iterate over all the entity components of
  286. //a specific type inside a specific group.
  287. FasterDictionary<ExclusiveGroupStruct, FasterDictionary<ComponentID, ITypeSafeDictionary>>
  288. groupEntityComponentsDB => _enginesRoot._groupEntityComponentsDB;
  289. //for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are
  290. //found indexed by group id. TypeSafeDictionary are never created, they instead point to the ones hold
  291. //by _groupEntityComponentsDB
  292. // <EntityComponentType <groupID <entityID, EntityComponent>>>
  293. FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>> groupsPerComponent =>
  294. _enginesRoot._groupsPerEntity;
  295. EnginesRoot.EntityReferenceMap _entityReferencesMap;
  296. }
  297. }