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.

215 lines
9.6KB

  1. //#define VERBOSE
  2. #if !DEBUG || PROFILE_SVELTO
  3. #define DONT_USE
  4. using System.Diagnostics;
  5. #endif
  6. using System;
  7. using System.Collections.Generic;
  8. using Svelto.DataStructures;
  9. namespace Svelto.ECS
  10. {
  11. /// <summary>
  12. /// Note: this check doesn't catch the case when an add and remove is done on the same entity before the next
  13. /// submission. Two operations on the same entity are not allowed between submissions.
  14. /// </summary>
  15. public partial class EnginesRoot
  16. {
  17. enum OperationType
  18. {
  19. Add,
  20. Remove,
  21. SwapFrom,
  22. SwapTo
  23. }
  24. #if DONT_USE
  25. [Conditional("MEANINGLESS")]
  26. #endif
  27. void InitDebugChecks()
  28. {
  29. _multipleOperationOnSameEGIDChecker = new FasterDictionary<EGID, OperationType>();
  30. _idChecker = new FasterDictionary<ExclusiveGroupStruct, HashSet<uint>>();
  31. }
  32. #if DONT_USE
  33. [Conditional("MEANINGLESS")]
  34. #endif
  35. void CheckSwapEntityID(EGID fromEgid, EGID toEgid, Type entityDescriptorType, string caller)
  36. {
  37. if (_multipleOperationOnSameEGIDChecker.TryGetValue(fromEgid, out var fromOperationType) == true)
  38. {
  39. var operationName = OperationName(fromOperationType);
  40. throw new ECSException(
  41. "Executing multiple structural changes (swapFrom) on the same entity is not supported "
  42. .FastConcat(" caller: ", caller, " ").FastConcat(fromEgid.entityID).FastConcat(" groupid: ")
  43. .FastConcat(fromEgid.groupID.ToName()).FastConcat(" type: ")
  44. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available")
  45. .FastConcat(" previous operation was: ")
  46. .FastConcat(operationName));
  47. }
  48. if (_multipleOperationOnSameEGIDChecker.TryGetValue(toEgid, out var toOperationType) == true)
  49. {
  50. var operationName = OperationName(toOperationType);
  51. throw new ECSException(
  52. "Executing multiple structural changes (swapTo) on the same entity is not supported "
  53. .FastConcat(" caller: ", caller, " ").FastConcat(toEgid.entityID).FastConcat(" groupid: ")
  54. .FastConcat(toEgid.groupID.ToName()).FastConcat(" type: ")
  55. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available")
  56. .FastConcat(" previous operation was: ")
  57. .FastConcat(operationName));
  58. }
  59. HashRemove(fromEgid, entityDescriptorType, false, caller);
  60. HashAdd(toEgid, entityDescriptorType, caller);
  61. _multipleOperationOnSameEGIDChecker.Add(fromEgid, OperationType.SwapFrom);
  62. _multipleOperationOnSameEGIDChecker.Add(toEgid, OperationType.SwapTo);
  63. }
  64. #if DONT_USE
  65. [Conditional("MEANINGLESS")]
  66. #endif
  67. void CheckRemoveEntityID(EGID egid, Type entityDescriptorType, string caller)
  68. {
  69. bool isAllowed = false;
  70. if (_multipleOperationOnSameEGIDChecker.TryGetValue(egid, out var operationType) == true)
  71. {
  72. //remove supersedes swap and remove operations, this means remove is allowed if the previous operation was swap or remove on the same submission
  73. isAllowed = operationType == OperationType.Remove || operationType == OperationType.SwapFrom;
  74. if (isAllowed)
  75. {
  76. #if VERBOSE
  77. var operationName = OperationName(operationType);
  78. Console.LogDebugWarning(
  79. "Executing multiple structural changes (remove) in one submission on the same entity. Remove supersedes swap and remove operations "
  80. .FastConcat(" caller: ", caller, " ").FastConcat(egid.entityID).FastConcat(" groupid: ")
  81. .FastConcat(egid.groupID.ToName()).FastConcat(" type: ")
  82. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available")
  83. .FastConcat(" previous operation was: ")
  84. .FastConcat(operationName));
  85. #endif
  86. }
  87. else
  88. throw new ECSException(
  89. "Executing multiple structural changes (remove) in one submission on the same entity is not supported "
  90. .FastConcat(" caller: ", caller, " ").FastConcat(egid.entityID).FastConcat(" groupid: ")
  91. .FastConcat(egid.groupID.ToName()).FastConcat(" type: ")
  92. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available")
  93. .FastConcat(" previous operation was: ")
  94. .FastConcat("add"));
  95. }
  96. HashRemove(egid, entityDescriptorType, isAllowed, caller);
  97. if (isAllowed == false)
  98. _multipleOperationOnSameEGIDChecker.Add(egid, OperationType.Remove);
  99. else
  100. _multipleOperationOnSameEGIDChecker[egid] = OperationType.Remove;
  101. }
  102. #if DONT_USE
  103. [Conditional("MEANINGLESS")]
  104. #endif
  105. void CheckAddEntityID(EGID egid, Type entityDescriptorType, string caller)
  106. {
  107. if (_multipleOperationOnSameEGIDChecker.TryGetValue(egid, out var operationType) == true)
  108. {
  109. var operationName = OperationName(operationType);
  110. throw new ECSException(
  111. "Executing multiple structural changes (build) on the same entity is not supported "
  112. .FastConcat(" caller: ", caller, " ").FastConcat(egid.entityID).FastConcat(" groupid: ")
  113. .FastConcat(egid.groupID.ToName()).FastConcat(" type: ")
  114. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available")
  115. .FastConcat(" previous operation was: ")
  116. .FastConcat(operationName));
  117. }
  118. HashAdd(egid, entityDescriptorType, caller);
  119. _multipleOperationOnSameEGIDChecker.Add(egid, OperationType.Add);
  120. }
  121. #if DONT_USE
  122. [Conditional("MEANINGLESS")]
  123. #endif
  124. void RemoveGroupID(ExclusiveBuildGroup groupID)
  125. {
  126. _idChecker.Remove(groupID);
  127. }
  128. #if DONT_USE
  129. [Conditional("MEANINGLESS")]
  130. #endif
  131. void ClearChecksForMultipleOperationsOnTheSameEgid()
  132. {
  133. _multipleOperationOnSameEGIDChecker.Clear();
  134. }
  135. void HashRemove(EGID egid, Type entityDescriptorType, bool isAllowed, string caller)
  136. {
  137. if (_idChecker.TryGetValue(egid.groupID, out HashSet<uint> hash))
  138. {
  139. if (hash.Contains(egid.entityID) == false && isAllowed == false)
  140. throw new ECSException(
  141. "Trying to remove an Entity not present in the database "
  142. .FastConcat(" caller: ", caller, " entityID ").FastConcat(egid.entityID).FastConcat(" groupid: ")
  143. .FastConcat(egid.groupID.ToName()).FastConcat(" type: ")
  144. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available"));
  145. }
  146. else
  147. {
  148. throw new ECSException(
  149. "Trying to remove an Entity with a group never used so far "
  150. .FastConcat(" caller: ", caller, " entityID ").FastConcat(egid.entityID).FastConcat(" groupid: ")
  151. .FastConcat(egid.groupID.ToName()).FastConcat(" type: ")
  152. .FastConcat(entityDescriptorType != null ? entityDescriptorType.Name : "not available"));
  153. }
  154. hash.Remove(egid.entityID);
  155. }
  156. void HashAdd(EGID egid, Type entityDescriptorType, string caller)
  157. {
  158. var hash = _idChecker.GetOrAdd(egid.groupID, () => new HashSet<uint>());
  159. if (hash.Contains(egid.entityID) == true)
  160. throw new ECSException(
  161. "Trying to add an Entity already present in the database "
  162. .FastConcat(" caller: ", caller, " entityID ").FastConcat(egid.entityID)
  163. .FastConcat(" groupid: ").FastConcat(egid.groupID.ToName()).FastConcat(" type: ")
  164. .FastConcat(
  165. entityDescriptorType != null
  166. ? entityDescriptorType.Name
  167. : "not available"));
  168. hash.Add(egid.entityID);
  169. }
  170. string OperationName(OperationType operationType)
  171. {
  172. string operationName;
  173. switch (operationType)
  174. {
  175. case OperationType.Remove:
  176. operationName = "remove";
  177. break;
  178. case OperationType.Add:
  179. operationName = "add";
  180. break;
  181. case OperationType.SwapFrom:
  182. operationName = "swapFrom";
  183. break;
  184. default:
  185. operationName = "swapTo";
  186. break;
  187. }
  188. return operationName;
  189. }
  190. DataStructures.FasterDictionary<EGID, OperationType> _multipleOperationOnSameEGIDChecker;
  191. DataStructures.FasterDictionary<ExclusiveGroupStruct, HashSet<uint>> _idChecker;
  192. }
  193. }