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.

188 lines
7.9KB

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