|
|
@@ -5,6 +5,19 @@ using Svelto.DataStructures; |
|
|
|
|
|
|
|
namespace Svelto.ECS |
|
|
|
{ |
|
|
|
/// <summary> |
|
|
|
/// This mechanism is not for thread-safety but to be sure that all the permutations of group tags always |
|
|
|
/// point to the same group ID. |
|
|
|
/// A group compound can generate several permutation of tags, so that the order of the tag doesn't matter, |
|
|
|
/// but for this to work, each permutation must be identified by the same ID (generated by the unique combination) |
|
|
|
/// </summary> |
|
|
|
static class GroupCompoundInitializer |
|
|
|
{ |
|
|
|
internal static readonly ThreadLocal<bool> skipStaticCompoundConstructorsWith4Tags = new ThreadLocal<bool>(); |
|
|
|
internal static readonly ThreadLocal<bool> skipStaticCompoundConstructorsWith3Tags = new ThreadLocal<bool>(); |
|
|
|
internal static readonly ThreadLocal<bool> skipStaticCompoundConstructorsWith2Tags = new ThreadLocal<bool>(); |
|
|
|
} |
|
|
|
|
|
|
|
public abstract class GroupCompound<G1, G2, G3, G4> where G1 : GroupTag<G1> |
|
|
|
where G2 : GroupTag<G2> |
|
|
|
where G3 : GroupTag<G3> |
|
|
@@ -22,41 +35,28 @@ namespace Svelto.ECS |
|
|
|
|
|
|
|
static GroupCompound() |
|
|
|
{ |
|
|
|
if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) |
|
|
|
//avoid race conditions if compounds are using on multiple thread |
|
|
|
if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0 |
|
|
|
&& GroupCompoundInitializer.skipStaticCompoundConstructorsWith4Tags.Value == false) |
|
|
|
{ |
|
|
|
_Groups = new FasterList<ExclusiveGroupStruct>(1); |
|
|
|
|
|
|
|
var Group = new ExclusiveGroup(); |
|
|
|
_Groups.Add(Group); |
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
GroupCompound<G1, G2, G3>.Add(Group); |
|
|
|
GroupCompound<G1, G2, G4>.Add(Group); |
|
|
|
GroupCompound<G1, G3, G4>.Add(Group); |
|
|
|
GroupCompound<G2, G3, G4>.Add(Group); |
|
|
|
|
|
|
|
GroupCompound<G1, G2>.Add(Group); //<G1/G2> and <G2/G1> must share the same array |
|
|
|
GroupCompound<G1, G3>.Add(Group); |
|
|
|
GroupCompound<G1, G4>.Add(Group); |
|
|
|
GroupCompound<G2, G3>.Add(Group); |
|
|
|
GroupCompound<G2, G4>.Add(Group); |
|
|
|
GroupCompound<G3, G4>.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<G1>.Add(Group); |
|
|
|
GroupTag<G2>.Add(Group); |
|
|
|
GroupTag<G3>.Add(Group); |
|
|
|
GroupTag<G4>.Add(Group); |
|
|
|
|
|
|
|
var group = new ExclusiveGroup(); |
|
|
|
_Groups.Add(group); |
|
|
|
|
|
|
|
var name = |
|
|
|
$"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint) group}"; |
|
|
|
#if DEBUG |
|
|
|
GroupNamesMap.idToName[(uint) Group] = |
|
|
|
$"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint) Group}"; |
|
|
|
GroupNamesMap.idToName[(uint) group] = name; |
|
|
|
#endif |
|
|
|
GroupHashMap.RegisterGroup(BuildGroup, |
|
|
|
$"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name}"); |
|
|
|
GroupHashMap.RegisterGroup(group, name); |
|
|
|
|
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
//all the combinations must share the same group and group hashset |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith4Tags.Value = true; |
|
|
|
|
|
|
|
//all the permutations must share the same group and group hashset. Warm them up, avoid call the |
|
|
|
//constructors again, set the desired value |
|
|
|
GroupCompound<G1, G2, G4, G3>._Groups = _Groups; |
|
|
|
GroupCompound<G1, G3, G2, G4>._Groups = _Groups; |
|
|
|
GroupCompound<G1, G3, G4, G2>._Groups = _Groups; |
|
|
@@ -80,6 +80,9 @@ namespace Svelto.ECS |
|
|
|
GroupCompound<G4, G2, G3, G1>._Groups = _Groups; |
|
|
|
GroupCompound<G4, G3, G1, G2>._Groups = _Groups; |
|
|
|
GroupCompound<G4, G3, G2, G1>._Groups = _Groups; |
|
|
|
|
|
|
|
//all the permutations are warmed up now |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith4Tags.Value = false; |
|
|
|
|
|
|
|
GroupCompound<G1, G2, G4, G3>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G1, G3, G2, G4>._GroupsHashSet = _GroupsHashSet; |
|
|
@@ -104,6 +107,25 @@ namespace Svelto.ECS |
|
|
|
GroupCompound<G4, G2, G3, G1>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G4, G3, G1, G2>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G4, G3, G2, G1>._GroupsHashSet = _GroupsHashSet; |
|
|
|
|
|
|
|
GroupCompound<G1, G2, G3>.Add(group); |
|
|
|
GroupCompound<G1, G2, G4>.Add(group); |
|
|
|
GroupCompound<G1, G3, G4>.Add(group); |
|
|
|
GroupCompound<G2, G3, G4>.Add(group); |
|
|
|
|
|
|
|
GroupCompound<G1, G2>.Add(group); //<G1/G2> and <G2/G1> must share the same array |
|
|
|
GroupCompound<G1, G3>.Add(group); |
|
|
|
GroupCompound<G1, G4>.Add(group); |
|
|
|
GroupCompound<G2, G3>.Add(group); |
|
|
|
GroupCompound<G2, G4>.Add(group); |
|
|
|
GroupCompound<G3, G4>.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<G1>.Add(group); |
|
|
|
GroupTag<G2>.Add(group); |
|
|
|
GroupTag<G3>.Add(group); |
|
|
|
GroupTag<G4>.Add(group); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -117,7 +139,10 @@ namespace Svelto.ECS |
|
|
|
_GroupsHashSet.Add(group); |
|
|
|
} |
|
|
|
|
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } |
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) |
|
|
|
{ |
|
|
|
return _GroupsHashSet.Contains(@group); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public abstract class GroupCompound<G1, G2, G3> |
|
|
@@ -130,7 +155,7 @@ namespace Svelto.ECS |
|
|
|
new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups); |
|
|
|
|
|
|
|
public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); |
|
|
|
|
|
|
|
|
|
|
|
static int isInitializing; |
|
|
|
|
|
|
|
internal static void Add(ExclusiveGroupStruct group) |
|
|
@@ -143,35 +168,31 @@ namespace Svelto.ECS |
|
|
|
_GroupsHashSet.Add(group); |
|
|
|
} |
|
|
|
|
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } |
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) |
|
|
|
{ |
|
|
|
return _GroupsHashSet.Contains(@group); |
|
|
|
} |
|
|
|
|
|
|
|
static GroupCompound() |
|
|
|
{ |
|
|
|
if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) |
|
|
|
if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0 && |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith3Tags.Value == false) |
|
|
|
{ |
|
|
|
_Groups = new FasterList<ExclusiveGroupStruct>(1); |
|
|
|
|
|
|
|
var Group = new ExclusiveGroup(); |
|
|
|
_Groups.Add(Group); |
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
GroupCompound<G1, G2>.Add(Group); //<G1/G2> and <G2/G1> must share the same array |
|
|
|
GroupCompound<G1, G3>.Add(Group); |
|
|
|
GroupCompound<G2, G3>.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<G1>.Add(Group); |
|
|
|
GroupTag<G2>.Add(Group); |
|
|
|
GroupTag<G3>.Add(Group); |
|
|
|
var group = new ExclusiveGroup(); |
|
|
|
_Groups.Add(group); |
|
|
|
|
|
|
|
var name = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint) group}"; |
|
|
|
#if DEBUG |
|
|
|
GroupNamesMap.idToName[(uint) Group] = |
|
|
|
$"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint) Group}"; |
|
|
|
GroupNamesMap.idToName[(uint) group] = name; |
|
|
|
#endif |
|
|
|
GroupHashMap.RegisterGroup(BuildGroup, |
|
|
|
$"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}"); |
|
|
|
GroupHashMap.RegisterGroup(group, name); |
|
|
|
|
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith3Tags.Value = true; |
|
|
|
|
|
|
|
//all the combinations must share the same group and group hashset |
|
|
|
GroupCompound<G3, G1, G2>._Groups = _Groups; |
|
|
|
GroupCompound<G2, G3, G1>._Groups = _Groups; |
|
|
@@ -179,11 +200,24 @@ namespace Svelto.ECS |
|
|
|
GroupCompound<G1, G3, G2>._Groups = _Groups; |
|
|
|
GroupCompound<G2, G1, G3>._Groups = _Groups; |
|
|
|
|
|
|
|
//all the constructor have been called now |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith3Tags.Value = false; |
|
|
|
|
|
|
|
GroupCompound<G3, G1, G2>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G2, G3, G1>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G3, G2, G1>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G1, G3, G2>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompound<G2, G1, G3>._GroupsHashSet = _GroupsHashSet; |
|
|
|
|
|
|
|
GroupCompound<G1, G2>.Add(group); //<G1/G2> and <G2/G1> must share the same array |
|
|
|
GroupCompound<G1, G3>.Add(group); |
|
|
|
GroupCompound<G2, G3>.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<G1>.Add(group); |
|
|
|
GroupTag<G2>.Add(group); |
|
|
|
GroupTag<G3>.Add(group); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -197,7 +231,7 @@ namespace Svelto.ECS |
|
|
|
new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups); |
|
|
|
|
|
|
|
public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); |
|
|
|
|
|
|
|
|
|
|
|
static int isInitializing; |
|
|
|
|
|
|
|
internal static void Add(ExclusiveGroupStruct group) |
|
|
@@ -210,30 +244,37 @@ namespace Svelto.ECS |
|
|
|
_GroupsHashSet.Add(group); |
|
|
|
} |
|
|
|
|
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } |
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) |
|
|
|
{ |
|
|
|
return _GroupsHashSet.Contains(@group); |
|
|
|
} |
|
|
|
|
|
|
|
static GroupCompound() |
|
|
|
{ |
|
|
|
if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) |
|
|
|
if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0 && |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith2Tags.Value == false) |
|
|
|
{ |
|
|
|
var Group = new ExclusiveGroup(); |
|
|
|
var group = new ExclusiveGroup(); |
|
|
|
|
|
|
|
_Groups = new FasterList<ExclusiveGroupStruct>(1); |
|
|
|
_Groups.Add(Group); |
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
//every abstract group preemptively adds this group, it may or may not be empty in future |
|
|
|
GroupTag<G1>.Add(Group); |
|
|
|
GroupTag<G2>.Add(Group); |
|
|
|
_Groups.Add(group); |
|
|
|
|
|
|
|
var groupName = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {(uint) group}"; |
|
|
|
#if DEBUG |
|
|
|
GroupNamesMap.idToName[(uint) Group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {(uint) Group}"; |
|
|
|
GroupNamesMap.idToName[(uint) group] = groupName; |
|
|
|
#endif |
|
|
|
GroupHashMap.RegisterGroup(BuildGroup, |
|
|
|
$"Compound: {typeof(G1).Name}-{typeof(G2).Name}"); |
|
|
|
GroupHashMap.RegisterGroup(group, groupName); |
|
|
|
|
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
GroupCompound<G2, G1>._Groups = _Groups; |
|
|
|
GroupCompound<G2, G1>._GroupsHashSet = _GroupsHashSet; |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith2Tags.Value = true; |
|
|
|
GroupCompound<G2, G1>._Groups = _Groups; |
|
|
|
GroupCompoundInitializer.skipStaticCompoundConstructorsWith2Tags.Value = false; |
|
|
|
GroupCompound<G2, G1>._GroupsHashSet = _GroupsHashSet; |
|
|
|
|
|
|
|
//every abstract group preemptively adds this group, it may or may not be empty in future |
|
|
|
GroupTag<G1>.Add(group); |
|
|
|
GroupTag<G2>.Add(group); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -254,7 +295,7 @@ namespace Svelto.ECS |
|
|
|
new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups); |
|
|
|
|
|
|
|
public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); |
|
|
|
|
|
|
|
|
|
|
|
static int isInitializing; |
|
|
|
|
|
|
|
static GroupTag() |
|
|
@@ -263,19 +304,22 @@ namespace Svelto.ECS |
|
|
|
{ |
|
|
|
var group = new ExclusiveGroup(); |
|
|
|
_Groups.Add(group); |
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
|
|
|
|
|
|
|
|
#if DEBUG |
|
|
|
var typeInfo = typeof(T); |
|
|
|
|
|
|
|
var name = $"Compound: {typeInfo.Name} ID {(uint) @group}"; |
|
|
|
#if DEBUG |
|
|
|
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}"; |
|
|
|
|
|
|
|
GroupNamesMap.idToName[(uint) group] = name; |
|
|
|
#endif |
|
|
|
GroupHashMap.RegisterGroup(BuildGroup, |
|
|
|
$"Compound: {typeof(T).FullName}"); |
|
|
|
} |
|
|
|
GroupHashMap.RegisterGroup(group, name); |
|
|
|
|
|
|
|
_GroupsHashSet = new HashSet<ExclusiveGroupStruct>(_Groups.ToArrayFast(out _)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//Each time a new combination of group tags is found a new group is added. |
|
|
@@ -289,6 +333,9 @@ namespace Svelto.ECS |
|
|
|
_GroupsHashSet.Add(group); |
|
|
|
} |
|
|
|
|
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) { return _GroupsHashSet.Contains(@group); } |
|
|
|
public static bool Includes(ExclusiveGroupStruct @group) |
|
|
|
{ |
|
|
|
return _GroupsHashSet.Contains(@group); |
|
|
|
} |
|
|
|
} |
|
|
|
} |