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.

168 lines
5.4KB

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