Mirror of Svelto.ECS because we're a fan of it
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

162 Zeilen
7.5KB

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