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.

180 lines
6.6KB

  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. using System.Runtime.InteropServices;
  5. using System.Threading;
  6. #pragma warning disable CS0660, CS0661
  7. namespace Svelto.ECS
  8. {
  9. [DebuggerDisplay("{ToString()}")]
  10. [StructLayout(LayoutKind.Explicit, Size = 4)]
  11. //the type doesn't implement IEqualityComparer, what implements it is a custom comparer
  12. public readonly struct ExclusiveGroupStruct : IEquatable<ExclusiveGroupStruct>, IComparable<ExclusiveGroupStruct>
  13. {
  14. public static readonly ExclusiveGroupStruct Invalid; //must stay here because of Burst
  15. public ExclusiveGroupStruct(byte[] data, uint pos):this()
  16. {
  17. _idInternal = (uint)(
  18. data[pos]
  19. | data[++pos] << 8
  20. | data[++pos] << 16
  21. );
  22. _bytemask = (byte) (data[++pos] << 24);
  23. DBC.ECS.Check.Ensure(id < _globalId, "Invalid group ID deserialiased");
  24. }
  25. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  26. public override int GetHashCode()
  27. {
  28. return (int) id;
  29. }
  30. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  31. public static bool operator ==(ExclusiveGroupStruct c1, ExclusiveGroupStruct c2)
  32. {
  33. return c1.Equals(c2);
  34. }
  35. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  36. public static bool operator !=(ExclusiveGroupStruct c1, ExclusiveGroupStruct c2)
  37. {
  38. return c1.Equals(c2) == false;
  39. }
  40. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  41. public bool Equals(ExclusiveGroupStruct other)
  42. {
  43. #if DEBUG && !PROFILE_SVELTO
  44. if ((other.id != id || other._bytemask == _bytemask) == false)
  45. throw new ECSException(
  46. "if the groups are correctly initialised, two groups with the same ID and different bitmask cannot exist");
  47. #endif
  48. return other.id == id;
  49. }
  50. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  51. public int CompareTo(ExclusiveGroupStruct other)
  52. {
  53. return other.id.CompareTo(id);
  54. }
  55. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  56. public bool IsEnabled()
  57. {
  58. return (_bytemask & (byte)ExclusiveGroupBitmask.DISABLED_BIT) == 0;
  59. }
  60. public override string ToString()
  61. {
  62. return this.ToName();
  63. }
  64. public bool isInvalid => this == Invalid;
  65. public uint id => _idInternal & 0xFFFFFF;
  66. public uint ToIDAndBitmask() => _idInternal;
  67. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  68. public static ExclusiveGroupStruct operator+(ExclusiveGroupStruct a, uint b)
  69. {
  70. var aID = a.id + b;
  71. #if DEBUG && !PROFILE_SVELTO
  72. if (aID >= 0xFFFFFF)
  73. throw new IndexOutOfRangeException();
  74. #endif
  75. var group = new ExclusiveGroupStruct(aID);
  76. return @group;
  77. }
  78. internal static ExclusiveGroupStruct Generate()
  79. {
  80. var newValue = Interlocked.Increment(ref _staticGlobalID);
  81. ExclusiveGroupStruct groupStruct = new ExclusiveGroupStruct((uint) newValue - (uint) 1);
  82. DBC.ECS.Check.Require(_globalId < ExclusiveGroup.MaxNumberOfExclusiveGroups, "too many exclusive groups created");
  83. return groupStruct;
  84. }
  85. internal static ExclusiveGroupStruct Generate(byte bitmask)
  86. {
  87. var newValue = Interlocked.Increment(ref _staticGlobalID);
  88. ExclusiveGroupStruct groupStruct = new ExclusiveGroupStruct((uint) newValue - (uint) 1, bitmask);
  89. DBC.ECS.Check.Require(_globalId < ExclusiveGroup.MaxNumberOfExclusiveGroups, "too many exclusive groups created");
  90. return groupStruct;
  91. }
  92. /// <summary>
  93. /// Use this to reserve N groups. We of course assign the current ID and then increment the index
  94. /// by range so that the next reserved index will take the range in consideration. This method is used
  95. /// internally by ExclusiveGroup.
  96. /// </summary>
  97. internal static ExclusiveGroupStruct GenerateWithRange(ushort range)
  98. {
  99. var newValue = Interlocked.Add(ref _staticGlobalID, (int)range);
  100. ExclusiveGroupStruct groupStruct = new ExclusiveGroupStruct((uint)newValue - (uint)range);
  101. DBC.ECS.Check.Require(_globalId < ExclusiveGroup.MaxNumberOfExclusiveGroups, "too many exclusive groups created");
  102. return groupStruct;
  103. }
  104. public static ExclusiveGroupStruct GenerateWithRange(ushort range, byte bitmask)
  105. {
  106. var newValue = Interlocked.Add(ref _staticGlobalID, (int)range);
  107. ExclusiveGroupStruct groupStruct = new ExclusiveGroupStruct((uint)newValue - (uint)range, bitmask);
  108. DBC.ECS.Check.Require(_globalId < ExclusiveGroup.MaxNumberOfExclusiveGroups, "too many exclusive groups created");
  109. return groupStruct;
  110. }
  111. /// <summary>
  112. /// used internally only by the framework to convert uint in to groups. ID must be generated by the framework
  113. /// so only the framework can assure that this method is not being abused
  114. /// </summary>
  115. internal ExclusiveGroupStruct(uint groupID):this()
  116. {
  117. #if DEBUG && !PROFILE_SVELTO
  118. if (groupID >= 0xFFFFFF)
  119. throw new IndexOutOfRangeException();
  120. #endif
  121. _idInternal = groupID;
  122. }
  123. internal ExclusiveGroupStruct(uint groupID, byte bytemask):this()
  124. {
  125. #if DEBUG && !PROFILE_SVELTO
  126. if (groupID >= 0xFFFFFF)
  127. throw new IndexOutOfRangeException();
  128. #endif
  129. _idInternal = groupID;
  130. _bytemask = bytemask;
  131. }
  132. static ExclusiveGroupStruct()
  133. {
  134. _staticGlobalID = 1;
  135. }
  136. [FieldOffset(0)] readonly uint _idInternal;
  137. //byte mask can be used to add special flags to specific groups that can be checked for example when swapping groups
  138. //however at the moment we are not letting the user access it, because if we do so we should give access only to
  139. //4 bits are the other 4 bits will stay reserved for Svelto use (at the moment of writing using only the disable
  140. //bit)
  141. [FieldOffset(3)] readonly byte _bytemask;
  142. static int _staticGlobalID;
  143. static uint _globalId => (uint) _staticGlobalID;
  144. }
  145. }