Mirror of Svelto.ECS because we're a fan of it
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

196 lines
8.2KB

  1. using System;
  2. using Svelto.DataStructures;
  3. using Svelto.ECS.Internal;
  4. namespace Svelto.ECS
  5. {
  6. /// <summary>
  7. /// DynamicEntityDescriptor can be used to add entity components to an existing EntityDescriptor that act as flags,
  8. /// at building time.
  9. /// This method allocates, so it shouldn't be abused
  10. /// TODO:Unit test cases where there could be duplicates of components, especially EntityInfoComponent.
  11. /// Test DynamicED of DynamicED
  12. /// </summary>
  13. /// <typeparam name="TType"></typeparam>
  14. public struct DynamicEntityDescriptor<TType> : IDynamicEntityDescriptor where TType : IEntityDescriptor, new()
  15. {
  16. public static DynamicEntityDescriptor<TType> CreateDynamicEntityDescriptor()
  17. {
  18. var entityDescriptor = new DynamicEntityDescriptor<TType>();
  19. var defaultEntities = EntityDescriptorTemplate<TType>.realDescriptor.componentsToBuild;
  20. var length = defaultEntities.Length;
  21. if (FetchEntityInfoComponent(defaultEntities) == -1)
  22. {
  23. entityDescriptor._componentsToBuild = new IComponentBuilder[length + 1];
  24. Array.Copy(defaultEntities, 0, entityDescriptor._componentsToBuild, 0, length);
  25. //assign it after otherwise the previous copy will overwrite the value in case the item
  26. //is already present
  27. entityDescriptor._componentsToBuild[length] = new ComponentBuilder<EntityInfoComponent>(new EntityInfoComponent
  28. {
  29. componentsToBuild = entityDescriptor._componentsToBuild
  30. });
  31. }
  32. else
  33. {
  34. entityDescriptor._componentsToBuild = new IComponentBuilder[length];
  35. Array.Copy(defaultEntities, 0, entityDescriptor._componentsToBuild, 0, length);
  36. }
  37. return entityDescriptor;
  38. }
  39. public DynamicEntityDescriptor(IComponentBuilder[] extraEntityBuilders)
  40. {
  41. this = CreateDynamicEntityDescriptor();
  42. var extraEntitiesLength = extraEntityBuilders.Length;
  43. _componentsToBuild = Construct(extraEntitiesLength, extraEntityBuilders);
  44. }
  45. public DynamicEntityDescriptor(FasterList<IComponentBuilder> extraEntityBuilders)
  46. {
  47. this = CreateDynamicEntityDescriptor();
  48. var extraEntities = extraEntityBuilders.ToArrayFast(out _);
  49. var extraEntitiesLength = extraEntityBuilders.count;
  50. _componentsToBuild = Construct((int)extraEntitiesLength, extraEntities);
  51. }
  52. public void ExtendWith<T>() where T : IEntityDescriptor, new()
  53. {
  54. var extraEntities = EntityDescriptorTemplate<T>.realDescriptor.componentsToBuild;
  55. _componentsToBuild = Construct(extraEntities.Length, extraEntities);
  56. }
  57. public void ExtendWith(IComponentBuilder[] extraEntities)
  58. {
  59. _componentsToBuild = Construct(extraEntities.Length, extraEntities);
  60. }
  61. public void ExtendWith(FasterList<IComponentBuilder> extraEntities)
  62. {
  63. _componentsToBuild = Construct(extraEntities.count, extraEntities.ToArrayFast(out _));
  64. }
  65. public void Add<T>() where T : struct, _IInternalEntityComponent
  66. {
  67. IComponentBuilder[] extraEntities = { new ComponentBuilder<T>() };
  68. _componentsToBuild = Construct(extraEntities.Length, extraEntities);
  69. }
  70. public void Add<T, U>() where T : struct, _IInternalEntityComponent where U : struct, _IInternalEntityComponent
  71. {
  72. IComponentBuilder[] extraEntities = { new ComponentBuilder<T>(), new ComponentBuilder<U>() };
  73. _componentsToBuild = Construct(extraEntities.Length, extraEntities);
  74. }
  75. public void Add<T, U, V>() where T : struct, _IInternalEntityComponent
  76. where U : struct, _IInternalEntityComponent
  77. where V : struct, _IInternalEntityComponent
  78. {
  79. IComponentBuilder[] extraEntities =
  80. {
  81. new ComponentBuilder<T>(), new ComponentBuilder<U>(), new ComponentBuilder<V>()
  82. };
  83. _componentsToBuild = Construct(extraEntities.Length, extraEntities);
  84. }
  85. /// <summary>
  86. /// Note: unluckily I didn't design the serialization system to be component order independent, so unless
  87. /// I do something about it, this method cannot be optimized, the logic of the component order must stay
  88. /// untouched (no reordering, no use of dictionaries). Components order must stay as it comes, as
  89. /// well as extracomponents order.
  90. /// Speed, however, is not a big issue for this class, as the data is always composed once per entity descriptor
  91. /// at static constructor time
  92. /// </summary>
  93. /// <returns></returns>
  94. IComponentBuilder[] Construct(int extraComponentsLength, IComponentBuilder[] extraComponents)
  95. {
  96. IComponentBuilder[] MergeLists
  97. (IComponentBuilder[] startingComponents, IComponentBuilder[] newComponents, int newComponentsLength)
  98. {
  99. var startComponents =
  100. new FasterDictionary<RefWrapper<IComponentBuilder, ComponentBuilderComparer>, IComponentBuilder>();
  101. var xtraComponents =
  102. new FasterDictionary<RefWrapper<IComponentBuilder, ComponentBuilderComparer>, IComponentBuilder>();
  103. for (uint i = 0; i < startingComponents.Length; i++)
  104. startComponents
  105. [new RefWrapper<IComponentBuilder, ComponentBuilderComparer>(startingComponents[i])] =
  106. startingComponents[i];
  107. for (uint i = 0; i < newComponentsLength; i++)
  108. xtraComponents[new RefWrapper<IComponentBuilder, ComponentBuilderComparer>(newComponents[i])] =
  109. newComponents[i];
  110. xtraComponents.Exclude(startComponents);
  111. if (newComponentsLength != xtraComponents.count)
  112. {
  113. newComponentsLength = xtraComponents.count;
  114. uint index = 0;
  115. foreach (var couple in xtraComponents)
  116. newComponents[index++] = couple.key.type;
  117. }
  118. IComponentBuilder[] componentBuilders =
  119. new IComponentBuilder[newComponentsLength + startingComponents.Length];
  120. Array.Copy(startingComponents, 0, componentBuilders, 0, startingComponents.Length);
  121. Array.Copy(newComponents, 0, componentBuilders, startingComponents.Length, newComponentsLength);
  122. var entityInfoComponentIndex = FetchEntityInfoComponent(componentBuilders);
  123. DBC.ECS.Check.Assert(entityInfoComponentIndex != -1);
  124. componentBuilders[entityInfoComponentIndex] = new ComponentBuilder<EntityInfoComponent>(
  125. new EntityInfoComponent
  126. {
  127. componentsToBuild = componentBuilders
  128. });
  129. return componentBuilders;
  130. }
  131. if (extraComponentsLength == 0)
  132. {
  133. return _componentsToBuild;
  134. }
  135. var safeCopyOfExtraComponents = new IComponentBuilder[extraComponentsLength];
  136. Array.Copy(extraComponents, safeCopyOfExtraComponents, extraComponentsLength);
  137. return MergeLists(_componentsToBuild, safeCopyOfExtraComponents, extraComponentsLength);
  138. }
  139. static int FetchEntityInfoComponent(IComponentBuilder[] defaultEntities)
  140. {
  141. int length = defaultEntities.Length;
  142. int index = -1;
  143. for (var i = 0; i < length; i++)
  144. {
  145. //the special entity already exists
  146. if (defaultEntities[i].GetEntityComponentType() == ComponentBuilderUtilities.ENTITY_INFO_COMPONENT)
  147. {
  148. index = i;
  149. break;
  150. }
  151. }
  152. return index;
  153. }
  154. public IComponentBuilder[] componentsToBuild => _componentsToBuild;
  155. IComponentBuilder[] _componentsToBuild;
  156. }
  157. }