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.

187 lines
7.8KB

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