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.

156 lines
6.9KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Text;
  5. using Svelto.ECS.Serialization;
  6. namespace Svelto.ECS
  7. {
  8. public static class GroupHashMap
  9. {
  10. /// <summary>
  11. /// c# Static constructors are guaranteed to be thread safe
  12. /// </summary>
  13. internal static void Init()
  14. {
  15. List<Assembly> assemblies = AssemblyUtility.GetCompatibleAssemblies();
  16. foreach (Assembly assembly in assemblies)
  17. {
  18. try
  19. {
  20. var typeOfExclusiveGroup = typeof(ExclusiveGroup);
  21. var typeOfExclusiveGroupStruct = typeof(ExclusiveGroupStruct);
  22. var typeOfExclusiveBuildGroup = typeof(ExclusiveBuildGroup);
  23. foreach (Type type in AssemblyUtility.GetTypesSafe(assembly))
  24. {
  25. CheckForGroupCompounds(type);
  26. if (type != null && type.IsClass && type.IsSealed &&
  27. type.IsAbstract) //IsClass and IsSealed and IsAbstract means only static classes
  28. {
  29. var subClasses = type.GetNestedTypes();
  30. foreach (var subclass in subClasses)
  31. {
  32. CheckForGroupCompounds(subclass);
  33. }
  34. var fields = type.GetFields();
  35. foreach (var field in fields)
  36. {
  37. if (field.IsStatic
  38. && (typeOfExclusiveGroup.IsAssignableFrom(field.FieldType)
  39. || typeOfExclusiveGroupStruct.IsAssignableFrom(field.FieldType)
  40. || typeOfExclusiveBuildGroup.IsAssignableFrom(field.FieldType)))
  41. {
  42. uint groupID;
  43. if (typeOfExclusiveGroup.IsAssignableFrom(field.FieldType))
  44. {
  45. var group = (ExclusiveGroup)field.GetValue(null);
  46. groupID = ((ExclusiveGroupStruct)@group).id;
  47. }
  48. else
  49. if (typeOfExclusiveGroupStruct.IsAssignableFrom(field.FieldType))
  50. {
  51. var group = (ExclusiveGroupStruct)field.GetValue(null);
  52. groupID = @group.id;
  53. }
  54. else
  55. {
  56. var group = (ExclusiveBuildGroup)field.GetValue(null);
  57. groupID = ((ExclusiveGroupStruct)@group).id;
  58. }
  59. {
  60. ExclusiveGroupStruct group = new ExclusiveGroupStruct(groupID);
  61. #if DEBUG && !PROFILE_SVELTO
  62. if (GroupNamesMap.idToName.ContainsKey(@group) == false)
  63. GroupNamesMap.idToName[@group] =
  64. $"{type.FullName}.{field.Name} {@group.id})";
  65. #endif
  66. //The hashname is independent from the actual group ID. this is fundamental because it is want
  67. //guarantees the hash to be the same across different machines
  68. RegisterGroup(@group, $"{type.FullName}.{field.Name}");
  69. }
  70. }
  71. }
  72. }
  73. }
  74. }
  75. catch
  76. {
  77. Console.LogDebugWarning(
  78. "something went wrong while gathering group names on the assembly: ".FastConcat(
  79. assembly.FullName));
  80. }
  81. }
  82. }
  83. static void CheckForGroupCompounds(Type type)
  84. {
  85. if (typeof(ITouchedByReflection).IsAssignableFrom(type))
  86. {
  87. //this wil call the static constructor, but only once. Static constructors won't be called
  88. //more than once with this
  89. System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(type.BaseType.TypeHandle);
  90. }
  91. }
  92. /// <summary>
  93. /// The hashname is independent from the actual group ID. this is fundamental because it is want
  94. /// guarantees the hash to be the same across different machines
  95. /// </summary>
  96. /// <param name="exclusiveGroupStruct"></param>
  97. /// <param name="name"></param>
  98. /// <exception cref="ECSException"></exception>
  99. public static void RegisterGroup(ExclusiveGroupStruct exclusiveGroupStruct, string name)
  100. {
  101. //Group already registered by another field referencing the same group, can happen because
  102. //the group poked is a group compound which static constructor is already been called at this point
  103. if (_hashByGroups.ContainsKey(exclusiveGroupStruct))
  104. return;
  105. var nameHash = DesignatedHash.Hash(Encoding.ASCII.GetBytes(name));
  106. if (_groupsByHash.ContainsKey(nameHash))
  107. throw new ECSException($"Group hash collision with {name} and {_groupsByHash[nameHash]}");
  108. Console.LogDebug($"Registering group {name} with ID {exclusiveGroupStruct.id} to {nameHash}");
  109. _groupsByHash.Add(nameHash, exclusiveGroupStruct);
  110. _hashByGroups.Add(exclusiveGroupStruct, nameHash);
  111. }
  112. internal static uint GetHashFromGroup(ExclusiveGroupStruct groupStruct)
  113. {
  114. #if DEBUG && !PROFILE_SVELTO
  115. if (_hashByGroups.ContainsKey(groupStruct) == false)
  116. throw new ECSException($"Attempted to get hash from unregistered group {groupStruct}");
  117. #endif
  118. return _hashByGroups[groupStruct];
  119. }
  120. internal static ExclusiveGroupStruct GetGroupFromHash(uint groupHash)
  121. {
  122. #if DEBUG && !PROFILE_SVELTO
  123. if (_groupsByHash.ContainsKey(groupHash) == false)
  124. throw new ECSException($"Attempted to get group from unregistered hash {groupHash}");
  125. #endif
  126. return _groupsByHash[groupHash];
  127. }
  128. static readonly Dictionary<uint, ExclusiveGroupStruct> _groupsByHash;
  129. static readonly Dictionary<ExclusiveGroupStruct, uint> _hashByGroups;
  130. static GroupHashMap()
  131. {
  132. _groupsByHash = new Dictionary<uint, ExclusiveGroupStruct>();
  133. _hashByGroups = new Dictionary<ExclusiveGroupStruct, uint>();
  134. }
  135. }
  136. }