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.

GroupCompound.cs 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. using System;
  2. using System.Threading;
  3. using Svelto.DataStructures;
  4. namespace Svelto.ECS
  5. {
  6. /// <summary>
  7. /// Very naive fail safe, but at least it's simple to understand and safe
  8. /// </summary>
  9. static class GroupCompoundInitializer
  10. {
  11. internal static readonly ThreadLocal<bool> isInitializing4 = new ThreadLocal<bool>();
  12. internal static readonly ThreadLocal<bool> isInitializing3 = new ThreadLocal<bool>();
  13. internal static readonly ThreadLocal<bool> isInitializing2 = new ThreadLocal<bool>();
  14. }
  15. public abstract class GroupCompound<G1, G2, G3, G4>
  16. where G1 : GroupTag<G1> where G2 : GroupTag<G2> where G3 : GroupTag<G3> where G4 : GroupTag<G4>
  17. {
  18. static readonly FasterList<ExclusiveGroupStruct> _Groups;
  19. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups => new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  20. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  21. static GroupCompound()
  22. {
  23. if (GroupCompoundInitializer.isInitializing4.Value == false)
  24. {
  25. _Groups = new FasterList<ExclusiveGroupStruct>(1);
  26. var Group = new ExclusiveGroup();
  27. _Groups.Add(Group);
  28. GroupCompound<G1, G2, G3>.Add(Group);
  29. GroupCompound<G1, G2, G4>.Add(Group);
  30. GroupCompound<G1, G3, G4>.Add(Group);
  31. GroupCompound<G2, G3, G4>.Add(Group);
  32. GroupCompound<G1, G2>.Add(Group); //<G1/G2> and <G2/G1> must share the same array
  33. GroupCompound<G1, G3>.Add(Group);
  34. GroupCompound<G1, G4>.Add(Group);
  35. GroupCompound<G2, G3>.Add(Group);
  36. GroupCompound<G2, G4>.Add(Group);
  37. GroupCompound<G3, G4>.Add(Group);
  38. //This is done here to be sure that the group is added once per group tag
  39. //(if done inside the previous group compound it would be added multiple times)
  40. GroupTag<G1>.Add(Group);
  41. GroupTag<G2>.Add(Group);
  42. GroupTag<G3>.Add(Group);
  43. GroupTag<G4>.Add(Group);
  44. #if DEBUG
  45. GroupMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint)Group}";
  46. #endif
  47. GroupCompoundInitializer.isInitializing4.Value = true;
  48. //all the combinations must share the same group
  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. GroupCompoundInitializer.isInitializing4.Value = false;
  73. }
  74. }
  75. public static void Add(ExclusiveGroupStruct @group)
  76. {
  77. for (int i = 0; i < _Groups.count; ++i)
  78. if (_Groups[i] == group)
  79. throw new Exception("temporary must be transformed in unit test");
  80. _Groups.Add(group);
  81. }
  82. }
  83. public abstract class GroupCompound<G1, G2, G3>
  84. where G1 : GroupTag<G1> where G2 : GroupTag<G2> where G3 : GroupTag<G3>
  85. {
  86. static readonly FasterList<ExclusiveGroupStruct> _Groups;
  87. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  88. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  89. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  90. public static void Add(ExclusiveGroupStruct group)
  91. {
  92. for (var i = 0; i < _Groups.count; ++i)
  93. if (_Groups[i] == group)
  94. throw new Exception("temporary must be transformed in unit test");
  95. _Groups.Add(group);
  96. }
  97. static GroupCompound()
  98. {
  99. if (GroupCompoundInitializer.isInitializing3.Value == false)
  100. {
  101. _Groups = new FasterList<ExclusiveGroupStruct>(1);
  102. var Group = new ExclusiveGroup();
  103. _Groups.Add(Group);
  104. GroupCompound<G1, G2>.Add(Group); //<G1/G2> and <G2/G1> must share the same array
  105. GroupCompound<G1, G3>.Add(Group);
  106. GroupCompound<G2, G3>.Add(Group);
  107. //This is done here to be sure that the group is added once per group tag
  108. //(if done inside the previous group compound it would be added multiple times)
  109. GroupTag<G1>.Add(Group);
  110. GroupTag<G2>.Add(Group);
  111. GroupTag<G3>.Add(Group);
  112. #if DEBUG
  113. GroupMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint)Group}";
  114. #endif
  115. //all the combinations must share the same group
  116. GroupCompoundInitializer.isInitializing3.Value = true;
  117. GroupCompound<G3, G1, G2>._Groups = _Groups;
  118. GroupCompound<G2, G3, G1>._Groups = _Groups;
  119. GroupCompound<G3, G2, G1>._Groups = _Groups;
  120. GroupCompound<G1, G3, G2>._Groups = _Groups;
  121. GroupCompound<G2, G1, G3>._Groups = _Groups;
  122. GroupCompoundInitializer.isInitializing3.Value = false;
  123. }
  124. }
  125. }
  126. public abstract class GroupCompound<G1, G2> where G1 : GroupTag<G1> where G2 : GroupTag<G2>
  127. {
  128. static readonly FasterList<ExclusiveGroupStruct> _Groups;
  129. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  130. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  131. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  132. public static void Add(ExclusiveGroupStruct group)
  133. {
  134. for (var i = 0; i < _Groups.count; ++i)
  135. if (_Groups[i] == group)
  136. throw new Exception("temporary must be transformed in unit test");
  137. _Groups.Add(group);
  138. }
  139. static GroupCompound()
  140. {
  141. if (GroupCompoundInitializer.isInitializing2.Value == false)
  142. {
  143. var Group = new ExclusiveGroup();
  144. _Groups = new FasterList<ExclusiveGroupStruct>(1);
  145. _Groups.Add(Group);
  146. //every abstract group preemptively adds this group, it may or may not be empty in future
  147. GroupTag<G1>.Add(Group);
  148. GroupTag<G2>.Add(Group);
  149. #if DEBUG
  150. GroupMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {(uint)Group}";
  151. #endif
  152. GroupCompoundInitializer.isInitializing2.Value = true;
  153. GroupCompound<G2, G1>._Groups = _Groups;
  154. GroupCompoundInitializer.isInitializing2.Value = false;
  155. }
  156. }
  157. }
  158. /// <summary>
  159. ///A Group Tag holds initially just a group, itself. However the number of groups can grow with the number of
  160. ///combinations of GroupTags including this one. This because a GroupTag is an adjective and different entities
  161. ///can use the same adjective together with other ones. However since I need to be able to iterate over all the
  162. ///groups with the same adjective, a group tag needs to hold all the groups sharing it.
  163. /// </summary>
  164. /// <typeparam name="T"></typeparam>
  165. public abstract class GroupTag<T> where T : GroupTag<T>
  166. {
  167. static readonly FasterList<ExclusiveGroupStruct> _Groups = new FasterList<ExclusiveGroupStruct>(1);
  168. public static FasterReadOnlyList<ExclusiveGroupStruct> Groups =>
  169. new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups);
  170. public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]);
  171. static GroupTag()
  172. {
  173. var group = new ExclusiveGroup();
  174. _Groups.Add(group);
  175. #if DEBUG
  176. GroupMap.idToName[(uint) group] = $"Compound: {typeof(T).Name} ID {(uint)group}";
  177. #endif
  178. }
  179. //Each time a new combination of group tags is found a new group is added.
  180. internal static void Add(ExclusiveGroupStruct group)
  181. {
  182. for (var i = 0; i < _Groups.count; ++i)
  183. if (_Groups[i] == group)
  184. throw new Exception("temporary must be transformed in unit test");
  185. _Groups.Add(group);
  186. }
  187. }
  188. }