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.

294 lines
13KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. using Svelto.DataStructures;
  5. namespace Svelto.ECS
  6. {
  7. public abstract class GroupCompound<G1, G2, G3, G4> where G1 : GroupTag<G1>
  8. where G2 : GroupTag<G2>
  9. where G3 : GroupTag<G3>
  10. where G4 : GroupTag<G4>
  11. {
  12. static readonly FasterList<ExclusiveGroupStruct> _Groups;
  13. static readonly HashSet<ExclusiveGroupStruct> _GroupsHashSet;
  14. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  15. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  16. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  17. static int isInitializing;
  18. static GroupCompound()
  19. {
  20. if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0)
  21. {
  22. _Groups = new FasterList<ExclusiveGroupStruct>(1);
  23. var Group = new ExclusiveGroup();
  24. _Groups.Add(Group);
  25. _GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _));
  26. GroupCompound<G1, G2, G3>.Add(Group);
  27. GroupCompound<G1, G2, G4>.Add(Group);
  28. GroupCompound<G1, G3, G4>.Add(Group);
  29. GroupCompound<G2, G3, G4>.Add(Group);
  30. GroupCompound<G1, G2>.Add(Group); //<G1/G2> and <G2/G1> must share the same array
  31. GroupCompound<G1, G3>.Add(Group);
  32. GroupCompound<G1, G4>.Add(Group);
  33. GroupCompound<G2, G3>.Add(Group);
  34. GroupCompound<G2, G4>.Add(Group);
  35. GroupCompound<G3, G4>.Add(Group);
  36. //This is done here to be sure that the group is added once per group tag
  37. //(if done inside the previous group compound it would be added multiple times)
  38. GroupTag<G1>.Add(Group);
  39. GroupTag<G2>.Add(Group);
  40. GroupTag<G3>.Add(Group);
  41. GroupTag<G4>.Add(Group);
  42. #if DEBUG
  43. GroupNamesMap.idToName[(uint) Group] =
  44. $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint) Group}";
  45. #endif
  46. GroupHashMap.RegisterGroup(BuildGroup,
  47. $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name}");
  48. //all the combinations must share the same group and group hashset
  49. GroupCompound<G1, G2, G4, G3>._Groups = _Groups;
  50. GroupCompound<G1, G3, G2, G4>._Groups = _Groups;
  51. GroupCompound<G1, G3, G4, G2>._Groups = _Groups;
  52. GroupCompound<G1, G4, G2, G3>._Groups = _Groups;
  53. GroupCompound<G2, G1, G3, G4>._Groups = _Groups;
  54. GroupCompound<G2, G3, G4, G1>._Groups = _Groups;
  55. GroupCompound<G3, G1, G2, G4>._Groups = _Groups;
  56. GroupCompound<G4, G1, G2, G3>._Groups = _Groups;
  57. GroupCompound<G1, G4, G3, G2>._Groups = _Groups;
  58. GroupCompound<G2, G1, G4, G3>._Groups = _Groups;
  59. GroupCompound<G2, G4, G3, G1>._Groups = _Groups;
  60. GroupCompound<G3, G1, G4, G2>._Groups = _Groups;
  61. GroupCompound<G4, G1, G3, G2>._Groups = _Groups;
  62. GroupCompound<G2, G3, G1, G4>._Groups = _Groups;
  63. GroupCompound<G3, G4, G1, G2>._Groups = _Groups;
  64. GroupCompound<G2, G4, G1, G3>._Groups = _Groups;
  65. GroupCompound<G3, G2, G1, G4>._Groups = _Groups;
  66. GroupCompound<G3, G2, G4, G1>._Groups = _Groups;
  67. GroupCompound<G3, G4, G2, G1>._Groups = _Groups;
  68. GroupCompound<G4, G2, G1, G3>._Groups = _Groups;
  69. GroupCompound<G4, G2, G3, G1>._Groups = _Groups;
  70. GroupCompound<G4, G3, G1, G2>._Groups = _Groups;
  71. GroupCompound<G4, G3, G2, G1>._Groups = _Groups;
  72. GroupCompound<G1, G2, G4, G3>._GroupsHashSet = _GroupsHashSet;
  73. GroupCompound<G1, G3, G2, G4>._GroupsHashSet = _GroupsHashSet;
  74. GroupCompound<G1, G3, G4, G2>._GroupsHashSet = _GroupsHashSet;
  75. GroupCompound<G1, G4, G2, G3>._GroupsHashSet = _GroupsHashSet;
  76. GroupCompound<G2, G1, G3, G4>._GroupsHashSet = _GroupsHashSet;
  77. GroupCompound<G2, G3, G4, G1>._GroupsHashSet = _GroupsHashSet;
  78. GroupCompound<G3, G1, G2, G4>._GroupsHashSet = _GroupsHashSet;
  79. GroupCompound<G4, G1, G2, G3>._GroupsHashSet = _GroupsHashSet;
  80. GroupCompound<G1, G4, G3, G2>._GroupsHashSet = _GroupsHashSet;
  81. GroupCompound<G2, G1, G4, G3>._GroupsHashSet = _GroupsHashSet;
  82. GroupCompound<G2, G4, G3, G1>._GroupsHashSet = _GroupsHashSet;
  83. GroupCompound<G3, G1, G4, G2>._GroupsHashSet = _GroupsHashSet;
  84. GroupCompound<G4, G1, G3, G2>._GroupsHashSet = _GroupsHashSet;
  85. GroupCompound<G2, G3, G1, G4>._GroupsHashSet = _GroupsHashSet;
  86. GroupCompound<G3, G4, G1, G2>._GroupsHashSet = _GroupsHashSet;
  87. GroupCompound<G2, G4, G1, G3>._GroupsHashSet = _GroupsHashSet;
  88. GroupCompound<G3, G2, G1, G4>._GroupsHashSet = _GroupsHashSet;
  89. GroupCompound<G3, G2, G4, G1>._GroupsHashSet = _GroupsHashSet;
  90. GroupCompound<G3, G4, G2, G1>._GroupsHashSet = _GroupsHashSet;
  91. GroupCompound<G4, G2, G1, G3>._GroupsHashSet = _GroupsHashSet;
  92. GroupCompound<G4, G2, G3, G1>._GroupsHashSet = _GroupsHashSet;
  93. GroupCompound<G4, G3, G1, G2>._GroupsHashSet = _GroupsHashSet;
  94. GroupCompound<G4, G3, G2, G1>._GroupsHashSet = _GroupsHashSet;
  95. }
  96. }
  97. internal static void Add(ExclusiveGroupStruct @group)
  98. {
  99. for (int i = 0; i < _Groups.count; ++i)
  100. if (_Groups[i] == group)
  101. throw new Exception("temporary must be transformed in unit test");
  102. _Groups.Add(group);
  103. _GroupsHashSet.Add(group);
  104. }
  105. public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); }
  106. }
  107. public abstract class GroupCompound<G1, G2, G3>
  108. where G1 : GroupTag<G1> where G2 : GroupTag<G2> where G3 : GroupTag<G3>
  109. {
  110. static readonly FasterList<ExclusiveGroupStruct> _Groups;
  111. static readonly HashSet<ExclusiveGroupStruct> _GroupsHashSet;
  112. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  113. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  114. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  115. static int isInitializing;
  116. internal static void Add(ExclusiveGroupStruct group)
  117. {
  118. for (var i = 0; i < _Groups.count; ++i)
  119. if (_Groups[i] == group)
  120. throw new Exception("temporary must be transformed in unit test");
  121. _Groups.Add(group);
  122. _GroupsHashSet.Add(group);
  123. }
  124. public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); }
  125. static GroupCompound()
  126. {
  127. if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0)
  128. {
  129. _Groups = new FasterList<ExclusiveGroupStruct>(1);
  130. var Group = new ExclusiveGroup();
  131. _Groups.Add(Group);
  132. _GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _));
  133. GroupCompound<G1, G2>.Add(Group); //<G1/G2> and <G2/G1> must share the same array
  134. GroupCompound<G1, G3>.Add(Group);
  135. GroupCompound<G2, G3>.Add(Group);
  136. //This is done here to be sure that the group is added once per group tag
  137. //(if done inside the previous group compound it would be added multiple times)
  138. GroupTag<G1>.Add(Group);
  139. GroupTag<G2>.Add(Group);
  140. GroupTag<G3>.Add(Group);
  141. #if DEBUG
  142. GroupNamesMap.idToName[(uint) Group] =
  143. $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint) Group}";
  144. #endif
  145. GroupHashMap.RegisterGroup(BuildGroup,
  146. $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}");
  147. //all the combinations must share the same group and group hashset
  148. GroupCompound<G3, G1, G2>._Groups = _Groups;
  149. GroupCompound<G2, G3, G1>._Groups = _Groups;
  150. GroupCompound<G3, G2, G1>._Groups = _Groups;
  151. GroupCompound<G1, G3, G2>._Groups = _Groups;
  152. GroupCompound<G2, G1, G3>._Groups = _Groups;
  153. GroupCompound<G3, G1, G2>._GroupsHashSet = _GroupsHashSet;
  154. GroupCompound<G2, G3, G1>._GroupsHashSet = _GroupsHashSet;
  155. GroupCompound<G3, G2, G1>._GroupsHashSet = _GroupsHashSet;
  156. GroupCompound<G1, G3, G2>._GroupsHashSet = _GroupsHashSet;
  157. GroupCompound<G2, G1, G3>._GroupsHashSet = _GroupsHashSet;
  158. }
  159. }
  160. }
  161. public abstract class GroupCompound<G1, G2> where G1 : GroupTag<G1> where G2 : GroupTag<G2>
  162. {
  163. static readonly FasterList<ExclusiveGroupStruct> _Groups;
  164. static readonly HashSet<ExclusiveGroupStruct> _GroupsHashSet;
  165. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  166. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  167. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  168. static int isInitializing;
  169. internal static void Add(ExclusiveGroupStruct group)
  170. {
  171. for (var i = 0; i < _Groups.count; ++i)
  172. if (_Groups[i] == group)
  173. throw new Exception("temporary must be transformed in unit test");
  174. _Groups.Add(group);
  175. _GroupsHashSet.Add(group);
  176. }
  177. public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); }
  178. static GroupCompound()
  179. {
  180. if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0)
  181. {
  182. var Group = new ExclusiveGroup();
  183. _Groups = new FasterList<ExclusiveGroupStruct>(1);
  184. _Groups.Add(Group);
  185. _GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _));
  186. //every abstract group preemptively adds this group, it may or may not be empty in future
  187. GroupTag<G1>.Add(Group);
  188. GroupTag<G2>.Add(Group);
  189. #if DEBUG
  190. GroupNamesMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {(uint) Group}";
  191. #endif
  192. GroupHashMap.RegisterGroup(BuildGroup,
  193. $"Compound: {typeof(G1).Name}-{typeof(G2).Name}");
  194. GroupCompound<G2, G1>._Groups = _Groups;
  195. GroupCompound<G2, G1>._GroupsHashSet = _GroupsHashSet;
  196. }
  197. }
  198. }
  199. /// <summary>
  200. ///A Group Tag holds initially just a group, itself. However the number of groups can grow with the number of
  201. ///combinations of GroupTags including this one. This because a GroupTag is an adjective and different entities
  202. ///can use the same adjective together with other ones. However since I need to be able to iterate over all the
  203. ///groups with the same adjective, a group tag needs to hold all the groups sharing it.
  204. /// </summary>
  205. /// <typeparam name="T"></typeparam>
  206. public abstract class GroupTag<T> where T : GroupTag<T>
  207. {
  208. static readonly FasterList<ExclusiveGroupStruct> _Groups = new FasterList<ExclusiveGroupStruct>(1);
  209. static readonly HashSet<ExclusiveGroupStruct> _GroupsHashSet;
  210. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  211. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  212. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  213. static int isInitializing;
  214. static GroupTag()
  215. {
  216. if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0)
  217. {
  218. var group = new ExclusiveGroup();
  219. _Groups.Add(group);
  220. _GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _));
  221. #if DEBUG
  222. var typeInfo = typeof(T);
  223. var typeInfoBaseType = typeInfo.BaseType;
  224. if (typeInfoBaseType.GenericTypeArguments[0] != typeInfo)
  225. throw new ECSException("Invalid Group Tag declared");
  226. GroupNamesMap.idToName[(uint)group] = $"Compound: {typeInfo.Name} ID {(uint)group}";
  227. #endif
  228. GroupHashMap.RegisterGroup(BuildGroup,
  229. $"Compound: {typeof(T).FullName}");
  230. }
  231. }
  232. //Each time a new combination of group tags is found a new group is added.
  233. internal static void Add(ExclusiveGroupStruct group)
  234. {
  235. for (var i = 0; i < _Groups.count; ++i)
  236. if (_Groups[i] == group)
  237. throw new Exception("temporary must be transformed in unit test");
  238. _Groups.Add(group);
  239. _GroupsHashSet.Add(group);
  240. }
  241. public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); }
  242. }
  243. }