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.

167 lines
5.4KB

  1. using System;
  2. using System.Collections.Generic;
  3. #pragma warning disable 660,661
  4. namespace Svelto.ECS
  5. {
  6. /// <summary>
  7. /// Exclusive Groups guarantee that the GroupID is unique.
  8. ///
  9. /// The best way to use it is like:
  10. ///
  11. /// public static class MyExclusiveGroups //(can be as many as you want)
  12. /// {
  13. /// public static ExclusiveGroup MyExclusiveGroup1 = new ExclusiveGroup();
  14. ///
  15. /// public static ExclusiveGroup[] GroupOfGroups = { MyExclusiveGroup1, ...}; //for each on this!
  16. /// }
  17. /// </summary>
  18. ///To debug it use in your debug window: Svelto.ECS.Debugger.EGID.GetGroupNameFromId(groupID)
  19. public class ExclusiveGroup
  20. {
  21. public const uint MaxNumberOfExclusiveGroups = 2 << 20;
  22. public ExclusiveGroup()
  23. {
  24. _group = ExclusiveGroupStruct.Generate();
  25. }
  26. public ExclusiveGroup(string recognizeAs)
  27. {
  28. _group = ExclusiveGroupStruct.Generate();
  29. _knownGroups.Add(recognizeAs, _group);
  30. }
  31. public ExclusiveGroup(ushort range)
  32. {
  33. _group = new ExclusiveGroupStruct(range);
  34. #if DEBUG
  35. _range = range;
  36. #endif
  37. }
  38. public static implicit operator ExclusiveGroupStruct(ExclusiveGroup group)
  39. {
  40. return group._group;
  41. }
  42. public static explicit operator uint(ExclusiveGroup group)
  43. {
  44. return group._group;
  45. }
  46. public static ExclusiveGroupStruct operator+(ExclusiveGroup a, uint b)
  47. {
  48. #if DEBUG
  49. if (a._range == 0)
  50. throw new ECSException($"Adding values to a not ranged ExclusiveGroup: {(uint)a}");
  51. if (b >= a._range)
  52. throw new ECSException($"Using out of range group: {(uint)a} + {b}");
  53. #endif
  54. return a._group + b;
  55. }
  56. //todo document the use case for this method
  57. public static ExclusiveGroupStruct Search(string holderGroupName)
  58. {
  59. if (_knownGroups.ContainsKey(holderGroupName) == false)
  60. throw new Exception("Named Group Not Found ".FastConcat(holderGroupName));
  61. return _knownGroups[holderGroupName];
  62. }
  63. public override string ToString()
  64. {
  65. return _group.ToString();
  66. }
  67. static readonly Dictionary<string, ExclusiveGroupStruct> _knownGroups = new Dictionary<string,
  68. ExclusiveGroupStruct>();
  69. #if DEBUG
  70. readonly ushort _range;
  71. #endif
  72. readonly ExclusiveGroupStruct _group;
  73. }
  74. }
  75. #if future
  76. public static void ConstructStaticGroups()
  77. {
  78. Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
  79. // Assemblies or types aren't guaranteed to be returned in the same order,
  80. // and I couldn't find proof that `GetTypes()` returns them in fixed order either,
  81. // even for builds made with the exact same source code.
  82. // So will sort reflection results by name before constructing groups.
  83. var groupFields = new List<KeyValuePair<string, FieldInfo>>();
  84. foreach (Assembly assembly in assemblies)
  85. {
  86. Type[] types = GetTypesSafe(assembly);
  87. foreach (Type type in types)
  88. {
  89. if (type == null || !type.IsClass)
  90. {
  91. continue;
  92. }
  93. // Groups defined as static members in static classes
  94. if (type.IsSealed && type.IsAbstract)
  95. {
  96. FieldInfo[] fields = type.GetFields();
  97. foreach(var field in fields)
  98. {
  99. if (field.IsStatic && typeof(ExclusiveGroup).IsAssignableFrom(field.FieldType))
  100. {
  101. groupFields.Add(new KeyValuePair<string, FieldInfo>($"{type.FullName}.{field.Name}", field));
  102. }
  103. }
  104. }
  105. // Groups defined as classes
  106. else if (type.BaseType != null
  107. && type.BaseType.IsGenericType
  108. && type.BaseType.GetGenericTypeDefinition() == typeof(ExclusiveGroup<>))
  109. {
  110. FieldInfo field = type.GetField("Group",
  111. BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
  112. groupFields.Add(new KeyValuePair<string, FieldInfo>(type.FullName, field));
  113. }
  114. }
  115. }
  116. groupFields.Sort((a, b) => string.CompareOrdinal(a.Key, b.Key));
  117. for (int i = 0; i < groupFields.Count; ++i)
  118. {
  119. groupFields[i].Value.GetValue(null);
  120. #if DEBUG
  121. var group = (ExclusiveGroup) groupFields[i].Value.GetValue(null);
  122. groupNames[(uint) group] = groupFields[i].Key;
  123. #endif
  124. }
  125. }
  126. static Type[] GetTypesSafe(Assembly assembly)
  127. {
  128. try
  129. {
  130. Type[] types = assembly.GetTypes();
  131. return types;
  132. }
  133. catch (ReflectionTypeLoadException e)
  134. {
  135. return e.Types;
  136. }
  137. }
  138. #if DEBUG
  139. static string[] groupNames = new string[ExclusiveGroup.MaxNumberOfExclusiveGroups];
  140. #endif
  141. #endif