using System; using System.Collections.Generic; using System.Threading; using Svelto.DataStructures; namespace Svelto.ECS { public abstract class GroupCompound where G1 : GroupTag where G2 : GroupTag where G3 : GroupTag where G4 : GroupTag { static readonly FasterList _Groups; static readonly HashSet _GroupsHashSet; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static int isInitializing; static GroupCompound() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) { _Groups = new FasterList(1); var Group = new ExclusiveGroup(); _Groups.Add(Group); _GroupsHashSet = new HashSet(_Groups.ToArrayFast(out _)); 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 GroupNamesMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint) Group}"; #endif GroupHashMap.RegisterGroup(BuildGroup, $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name}"); //all the combinations must share the same group and group hashset 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; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; } } internal 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); _GroupsHashSet.Add(group); } public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } } public abstract class GroupCompound where G1 : GroupTag where G2 : GroupTag where G3 : GroupTag { static readonly FasterList _Groups; static readonly HashSet _GroupsHashSet; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static int isInitializing; 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); _GroupsHashSet.Add(group); } public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } static GroupCompound() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) { _Groups = new FasterList(1); var Group = new ExclusiveGroup(); _Groups.Add(Group); _GroupsHashSet = new HashSet(_Groups.ToArrayFast(out _)); 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 GroupNamesMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint) Group}"; #endif GroupHashMap.RegisterGroup(BuildGroup, $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}"); //all the combinations must share the same group and group hashset GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._Groups = _Groups; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; GroupCompound._GroupsHashSet = _GroupsHashSet; } } } public abstract class GroupCompound where G1 : GroupTag where G2 : GroupTag { static readonly FasterList _Groups; static readonly HashSet _GroupsHashSet; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static int isInitializing; 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); _GroupsHashSet.Add(group); } public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } static GroupCompound() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) { var Group = new ExclusiveGroup(); _Groups = new FasterList(1); _Groups.Add(Group); _GroupsHashSet = new HashSet(_Groups.ToArrayFast(out _)); //every abstract group preemptively adds this group, it may or may not be empty in future GroupTag.Add(Group); GroupTag.Add(Group); #if DEBUG GroupNamesMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {(uint) Group}"; #endif GroupHashMap.RegisterGroup(BuildGroup, $"Compound: {typeof(G1).Name}-{typeof(G2).Name}"); GroupCompound._Groups = _Groups; GroupCompound._GroupsHashSet = _GroupsHashSet; } } } /// ///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); static readonly HashSet _GroupsHashSet; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static int isInitializing; static GroupTag() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) { var group = new ExclusiveGroup(); _Groups.Add(group); _GroupsHashSet = new HashSet(_Groups.ToArrayFast(out _)); #if DEBUG var typeInfo = typeof(T); var typeInfoBaseType = typeInfo.BaseType; if (typeInfoBaseType.GenericTypeArguments[0] != typeInfo) throw new ECSException("Invalid Group Tag declared"); GroupNamesMap.idToName[(uint)group] = $"Compound: {typeInfo.Name} ID {(uint)group}"; #endif GroupHashMap.RegisterGroup(BuildGroup, $"Compound: {typeof(T).FullName}"); } } //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); _GroupsHashSet.Add(group); } public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } } }