using System; using System.Threading; using Svelto.DataStructures; namespace Svelto.ECS { /// /// Very naive fail safe, but at least it's simple to understand and safe /// static class GroupCompoundInitializer { internal static readonly ThreadLocal isInitializing4 = new ThreadLocal(); internal static readonly ThreadLocal isInitializing3 = new ThreadLocal(); internal static readonly ThreadLocal isInitializing2 = new ThreadLocal(); } public abstract class GroupCompound where G1 : GroupTag where G2 : GroupTag where G3 : GroupTag where G4 : GroupTag { static readonly FasterList _Groups; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static GroupCompound() { if (GroupCompoundInitializer.isInitializing4.Value == false) { _Groups = new FasterList(1); var Group = new ExclusiveGroup(); _Groups.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); // and must share the same array GroupCompound.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); GroupCompound.Add(Group); //This is done here to be sure that the group is added once per group tag //(if done inside the previous group compound it would be added multiple times) GroupTag.Add(Group); GroupTag.Add(Group); GroupTag.Add(Group); GroupTag.Add(Group); #if DEBUG GroupMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint)Group}"; #endif GroupCompoundInitializer.isInitializing4.Value = true; //all the combinations must share the same group GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompoundInitializer.isInitializing4.Value = false; } } public static void Add(ExclusiveGroupStruct @group) { for (int i = 0; i < _Groups.count; ++i) if (_Groups[i] == group) throw new Exception("temporary must be transformed in unit test"); _Groups.Add(group); } } public abstract class GroupCompound where G1 : GroupTag where G2 : GroupTag where G3 : GroupTag { static readonly FasterList _Groups; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static void Add(ExclusiveGroupStruct group) { for (var i = 0; i < _Groups.count; ++i) if (_Groups[i] == group) throw new Exception("temporary must be transformed in unit test"); _Groups.Add(group); } static GroupCompound() { if (GroupCompoundInitializer.isInitializing3.Value == false) { _Groups = new FasterList(1); var Group = new ExclusiveGroup(); _Groups.Add(Group); GroupCompound.Add(Group); // and must share the same array GroupCompound.Add(Group); GroupCompound.Add(Group); //This is done here to be sure that the group is added once per group tag //(if done inside the previous group compound it would be added multiple times) GroupTag.Add(Group); GroupTag.Add(Group); GroupTag.Add(Group); #if DEBUG GroupMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint)Group}"; #endif //all the combinations must share the same group GroupCompoundInitializer.isInitializing3.Value = true; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompoundInitializer.isInitializing3.Value = false; } } } public abstract class GroupCompound where G1 : GroupTag where G2 : GroupTag { static readonly FasterList _Groups; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static void Add(ExclusiveGroupStruct group) { for (var i = 0; i < _Groups.count; ++i) if (_Groups[i] == group) throw new Exception("temporary must be transformed in unit test"); _Groups.Add(group); } static GroupCompound() { if (GroupCompoundInitializer.isInitializing2.Value == false) { var Group = new ExclusiveGroup(); _Groups = new FasterList(1); _Groups.Add(Group); //every abstract group preemptively adds this group, it may or may not be empty in future GroupTag.Add(Group); GroupTag.Add(Group); #if DEBUG GroupMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {(uint)Group}"; #endif GroupCompoundInitializer.isInitializing2.Value = true; GroupCompound._Groups = _Groups; GroupCompoundInitializer.isInitializing2.Value = false; } } } /// ///A Group Tag holds initially just a group, itself. However the number of groups can grow with the number of ///combinations of GroupTags including this one. This because a GroupTag is an adjective and different entities ///can use the same adjective together with other ones. However since I need to be able to iterate over all the ///groups with the same adjective, a group tag needs to hold all the groups sharing it. /// /// public abstract class GroupTag where T : GroupTag { static readonly FasterList _Groups = new FasterList(1); public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static GroupTag() { var group = new ExclusiveGroup(); _Groups.Add(group); #if DEBUG GroupMap.idToName[(uint) group] = $"Compound: {typeof(T).Name} ID {(uint)group}"; #endif } //Each time a new combination of group tags is found a new group is added. internal static void Add(ExclusiveGroupStruct group) { for (var i = 0; i < _Groups.count; ++i) if (_Groups[i] == group) throw new Exception("temporary must be transformed in unit test"); _Groups.Add(group); } } }