Mirror of Svelto.ECS because we're a fan of it
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

194 行
8.7KB

  1. //#define PARANOID_CHECK
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. using Svelto.DataStructures;
  6. using Svelto.ECS.Internal;
  7. namespace Svelto.ECS
  8. {
  9. public partial class EnginesRoot : IDisposable, IUnitTestingInterface
  10. {
  11. ///--------------------------------------------
  12. ///
  13. public IEntityStreamConsumerFactory GenerateConsumerFactory()
  14. {
  15. return new GenericEntityStreamConsumerFactory(this);
  16. }
  17. public IEntityFactory GenerateEntityFactory()
  18. {
  19. return new GenericEntityFactory(this);
  20. }
  21. public IEntityFunctions GenerateEntityFunctions()
  22. {
  23. return new GenericEntityFunctions(this);
  24. }
  25. ///--------------------------------------------
  26. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  27. EntityInitializer BuildEntity(EGID entityID, IComponentBuilder[] componentsToBuild, Type descriptorType,
  28. IEnumerable<object> implementors, string caller)
  29. {
  30. CheckAddEntityID(entityID, descriptorType, caller);
  31. DBC.ECS.Check.Require(entityID.groupID.isInvalid == false,
  32. "invalid group detected, are you using new ExclusiveGroupStruct() instead of new ExclusiveGroup()?");
  33. var reference = _entityLocator.ClaimReference();
  34. _entityLocator.SetReference(reference, entityID);
  35. var dic = EntityFactory.BuildGroupedEntities(entityID, _groupedEntityToAdd, componentsToBuild, implementors
  36. #if DEBUG && !PROFILE_SVELTO
  37. , descriptorType
  38. #endif
  39. );
  40. return new EntityInitializer(entityID, dic, reference);
  41. }
  42. /// <summary>
  43. /// Preallocate memory to avoid the impact to resize arrays when many entities are submitted at once
  44. /// </summary>
  45. void Preallocate(ExclusiveGroupStruct groupID, uint size, IComponentBuilder[] entityComponentsToBuild)
  46. {
  47. void PreallocateEntitiesToAdd()
  48. {
  49. _groupedEntityToAdd.Preallocate(groupID, size, entityComponentsToBuild);
  50. }
  51. void PreallocateDBGroup()
  52. {
  53. var numberOfEntityComponents = entityComponentsToBuild.Length;
  54. FasterDictionary<RefWrapperType, ITypeSafeDictionary> group = GetOrAddDBGroup(groupID);
  55. for (var index = 0; index < numberOfEntityComponents; index++)
  56. {
  57. var entityComponentBuilder = entityComponentsToBuild[index];
  58. var entityComponentType = entityComponentBuilder.GetEntityComponentType();
  59. var refWrapper = new RefWrapperType(entityComponentType);
  60. var dbList = group.GetOrAdd(refWrapper, () => entityComponentBuilder.CreateDictionary(size));
  61. entityComponentBuilder.Preallocate(dbList, size);
  62. if (_groupsPerEntity.TryGetValue(refWrapper, out var groupedGroup) == false)
  63. groupedGroup = _groupsPerEntity[refWrapper] =
  64. new FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>();
  65. groupedGroup[groupID] = dbList;
  66. }
  67. }
  68. PreallocateDBGroup();
  69. PreallocateEntitiesToAdd();
  70. _entityLocator.PreallocateReferenceMaps(groupID, size);
  71. }
  72. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  73. FasterDictionary<RefWrapperType, ITypeSafeDictionary> GetDBGroup(ExclusiveGroupStruct fromIdGroupId)
  74. {
  75. if (_groupEntityComponentsDB.TryGetValue(fromIdGroupId,
  76. out FasterDictionary<RefWrapperType, ITypeSafeDictionary> fromGroup) == false)
  77. throw new ECSException("Group doesn't exist: ".FastConcat(fromIdGroupId.ToName()));
  78. return fromGroup;
  79. }
  80. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  81. FasterDictionary<RefWrapperType, ITypeSafeDictionary> GetOrAddDBGroup(ExclusiveGroupStruct toGroupId)
  82. {
  83. return _groupEntityComponentsDB.GetOrAdd(toGroupId,
  84. () => new FasterDictionary<RefWrapperType, ITypeSafeDictionary>());
  85. }
  86. IComponentBuilder[] FindRealComponents<T>(EGID fromEntityGID) where T : IEntityDescriptor, new()
  87. {
  88. var fromGroup = GetDBGroup(fromEntityGID.groupID);
  89. if (fromGroup.TryGetValue(new RefWrapperType(ComponentBuilderUtilities.ENTITY_INFO_COMPONENT),
  90. out var entityInfoDic) //<entity ID, EntityInfoComponent>
  91. && ((ITypeSafeDictionary<EntityInfoComponent>)entityInfoDic).TryGetValue(fromEntityGID.entityID,
  92. out var entityInfo)) //there could be multiple entity descriptors registered in the same group, so it's necessary to check if the entity registered in the group has entityInfoComponent
  93. {
  94. #if PARANOID_CHECK
  95. var hash = new HashSet<IComponentBuilder>(entityInfo.componentsToBuild,
  96. default(ComponentBuilderComparer));
  97. foreach (var component in EntityDescriptorTemplate<T>.descriptor.componentsToBuild)
  98. {
  99. if (hash.Contains(component) == false)
  100. throw new Exception(
  101. $"entityInfo.componentsToBuild must contain all the base components {fromEntityGID}," +
  102. $" missing component {component}");
  103. hash.Remove(component);
  104. }
  105. #endif
  106. return entityInfo.componentsToBuild;
  107. }
  108. return EntityDescriptorTemplate<T>.descriptor.componentsToBuild;
  109. }
  110. IComponentBuilder[] FindRealComponents(EGID fromEntityGID, IComponentBuilder[] baseComponents)
  111. {
  112. var fromGroup = GetDBGroup(fromEntityGID.groupID);
  113. if (fromGroup.TryGetValue(new RefWrapperType(ComponentBuilderUtilities.ENTITY_INFO_COMPONENT),
  114. out var entityInfoDic) //<entity ID, EntityInfoComponent>
  115. && ((ITypeSafeDictionary<EntityInfoComponent>)entityInfoDic).TryGetValue(fromEntityGID.entityID,
  116. out var entityInfo)) //there could be multiple entity descriptors registered in the same group, so it's necessary to check if the entity registered in the group has entityInfoComponent
  117. {
  118. #if PARANOID_CHECK
  119. var hash = new HashSet<IComponentBuilder>(entityInfo.componentsToBuild,
  120. default(ComponentBuilderComparer));
  121. foreach (var component in baseComponents)
  122. {
  123. if (hash.Contains(component) == false)
  124. throw new Exception(
  125. $"entityInfo.componentsToBuild must contain all the base components {fromEntityGID}," +
  126. $" missing component {component}");
  127. hash.Remove(component);
  128. }
  129. #endif
  130. return entityInfo.componentsToBuild;
  131. }
  132. return baseComponents;
  133. }
  134. //one datastructure rule them all:
  135. //split by group
  136. //split by type per group. It's possible to get all the entities of a give type T per group thanks
  137. //to the FasterDictionary capabilities OR it's possible to get a specific entityComponent indexed by
  138. //ID. This ID doesn't need to be the EGID, it can be just the entityID
  139. //for each group id, save a dictionary indexed by entity type of entities indexed by id
  140. // group EntityComponentType entityID, EntityComponent
  141. internal readonly FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>
  142. _groupEntityComponentsDB;
  143. //for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are
  144. //found indexed by group id. TypeSafeDictionary are never created, they instead point to the ones hold
  145. //by _groupEntityComponentsDB
  146. // <EntityComponentType <groupID <entityID, EntityComponent>>>
  147. internal readonly FasterDictionary<RefWrapperType, FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>>
  148. _groupsPerEntity;
  149. //The filters stored for each component and group
  150. internal readonly FasterDictionary<RefWrapperType, FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>>
  151. _groupFilters;
  152. readonly EntitiesDB _entitiesDB;
  153. EntitiesDB IUnitTestingInterface.entitiesForTesting => _entitiesDB;
  154. }
  155. public interface IUnitTestingInterface
  156. {
  157. EntitiesDB entitiesForTesting { get; }
  158. }
  159. }