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.

314 lines
14KB

  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using Svelto.DataStructures;
  4. using Svelto.Utilities;
  5. namespace Svelto.ECS
  6. {
  7. class EntitiesOperations
  8. {
  9. /// <summary>
  10. /// Todo: need to go back here and add a ton of comments
  11. /// </summary>
  12. public EntitiesOperations()
  13. {
  14. _thisSubmissionInfo.Init();
  15. _lastSubmittedInfo.Init();
  16. _newGroupDictionary = NewGroupDictionary;
  17. _newGroupsDictionary = NewGroupsDictionary;
  18. _recycleDictionary = RecycleDictionary;
  19. _newList = NewList;
  20. _clearList = ClearList;
  21. _newGroupsDictionaryWithCaller = NewGroupsDictionaryWithCaller;
  22. _recycleGroupDictionaryWithCaller = RecycleGroupDictionaryWithCaller;
  23. _recycleDicitionaryWithCaller = RecycleDicitionaryWithCaller;
  24. _newListWithCaller = NewListWithCaller;
  25. _clearListWithCaller = ClearListWithCaller;
  26. }
  27. public void QueueRemoveGroupOperation(ExclusiveBuildGroup groupID, string caller)
  28. {
  29. _thisSubmissionInfo._groupsToRemove.Add((groupID, caller));
  30. }
  31. public void QueueRemoveOperation(EGID fromEgid, IComponentBuilder[] componentBuilders, string caller)
  32. {
  33. // Check if the entity is already queued for removal
  34. if (_thisSubmissionInfo._entitiesRemoved.Contains(fromEgid))
  35. {
  36. // If it is, skip the rest of the function
  37. return;
  38. }
  39. _thisSubmissionInfo._entitiesRemoved.Add(fromEgid);
  40. RevertSwapOperationIfPreviouslyQueued(fromEgid);
  41. //todo: limit the number of dictionaries that can be cached
  42. //recycle or create dictionaries of components per group
  43. var removedComponentsPerType = _thisSubmissionInfo._currentRemoveEntitiesOperations.RecycleOrAdd(
  44. fromEgid.groupID, _newGroupsDictionary, _recycleDictionary);
  45. foreach (var operation in componentBuilders)
  46. {
  47. removedComponentsPerType //recycle or create dictionaries per component type
  48. .RecycleOrAdd(operation.getComponentID, _newList, _clearList)
  49. //add entity to remove
  50. .Add((fromEgid.entityID, caller));
  51. }
  52. void RevertSwapOperationIfPreviouslyQueued(EGID fromEgid)
  53. {
  54. if (_thisSubmissionInfo._entitiesSwapped.Remove(fromEgid, out (EGID fromEgid, EGID toEgid) val)) //Remove supersedes swap, check comment in IEntityFunctions.cs
  55. {
  56. var swappedComponentsPerType = _thisSubmissionInfo._currentSwapEntitiesOperations[fromEgid.groupID];
  57. var componentBuildersLength = componentBuilders.Length - 1;
  58. for (var index = componentBuildersLength; index >= 0; index--)
  59. {
  60. var operation = componentBuilders[index];
  61. //todo: maybe the order of swappedComponentsPerType should be fromID, toGroupID, componentID
  62. swappedComponentsPerType[operation.getComponentID][val.toEgid.groupID].Remove(fromEgid.entityID);
  63. }
  64. }
  65. }
  66. }
  67. public void QueueSwapGroupOperation(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID, string caller)
  68. {
  69. _thisSubmissionInfo._groupsToSwap.Add((fromGroupID, toGroupID, caller));
  70. }
  71. public void QueueSwapOperation(EGID fromEGID, EGID toEGID, IComponentBuilder[] componentBuilders, string caller)
  72. {
  73. _thisSubmissionInfo._entitiesSwapped.Add(fromEGID, (fromEGID, toEGID));
  74. //todo: limit the number of dictionaries that can be cached
  75. //Get (or create) the dictionary that holds the entities that are swapping from fromEGID group
  76. var swappedComponentsPerType = _thisSubmissionInfo._currentSwapEntitiesOperations.RecycleOrAdd(
  77. fromEGID.groupID, _newGroupsDictionaryWithCaller, _recycleGroupDictionaryWithCaller);
  78. var componentBuildersLength = componentBuilders.Length - 1;
  79. //for each component of the entity that is swapping
  80. for (var index = componentBuildersLength; index >= 0; index--)
  81. {
  82. var operation = componentBuilders[index];
  83. //Get the dictionary for each component that holds the list of entities to swap
  84. swappedComponentsPerType
  85. //recycle or create dictionaries per component type
  86. .RecycleOrAdd(operation.getComponentID, _newGroupDictionary, _recycleDicitionaryWithCaller)
  87. //recycle or create list of entities to swap
  88. .RecycleOrAdd(toEGID.groupID, _newListWithCaller, _clearListWithCaller)
  89. //add entity to swap
  90. .Add(fromEGID.entityID, new SwapInfo(fromEGID.entityID, toEGID.entityID, caller));
  91. }
  92. }
  93. [MethodImpl(MethodImplOptions.Synchronized)]
  94. public bool AnyOperationQueued()
  95. {
  96. return _thisSubmissionInfo.AnyOperationQueued();
  97. }
  98. public void ExecuteRemoveAndSwappingOperations(
  99. Action<FasterDictionary<ExclusiveGroupStruct, FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>>, FasterDictionary<EGID, (EGID, EGID)>, EnginesRoot> swapEntities, Action<FasterDictionary<ExclusiveGroupStruct, FasterDictionary<ComponentID, FasterList<(uint, string)>>>,
  100. FasterList<EGID>, EnginesRoot> removeEntities, Action<ExclusiveGroupStruct, EnginesRoot> removeGroup,
  101. Action<ExclusiveGroupStruct, ExclusiveGroupStruct, EnginesRoot> swapGroup, EnginesRoot enginesRoot)
  102. {
  103. (_thisSubmissionInfo, _lastSubmittedInfo) = (_lastSubmittedInfo, _thisSubmissionInfo);
  104. /// todo: entity references should be updated before calling all the methods to avoid callbacks handling
  105. /// references that should be marked as invalid.
  106. foreach (var (group, caller) in _lastSubmittedInfo._groupsToRemove)
  107. try
  108. {
  109. removeGroup(group, enginesRoot);
  110. }
  111. catch
  112. {
  113. var str = "Crash while removing a whole group on ".FastConcat(group.ToString())
  114. .FastConcat(" from : ", caller);
  115. Console.LogError(str);
  116. throw;
  117. }
  118. foreach (var (fromGroup, toGroup, caller) in _lastSubmittedInfo._groupsToSwap)
  119. try
  120. {
  121. swapGroup(fromGroup, toGroup, enginesRoot);
  122. }
  123. catch
  124. {
  125. var str = "Crash while swapping a whole group on "
  126. .FastConcat(fromGroup.ToString(), " ", toGroup.ToString()).FastConcat(" from : ", caller);
  127. Console.LogError(str);
  128. throw;
  129. }
  130. if (_lastSubmittedInfo._entitiesSwapped.count > 0)
  131. swapEntities(_lastSubmittedInfo._currentSwapEntitiesOperations, _lastSubmittedInfo._entitiesSwapped, enginesRoot);
  132. if (_lastSubmittedInfo._entitiesRemoved.count > 0)
  133. removeEntities(
  134. _lastSubmittedInfo._currentRemoveEntitiesOperations, _lastSubmittedInfo._entitiesRemoved
  135. , enginesRoot);
  136. _lastSubmittedInfo.Clear();
  137. }
  138. static FasterDictionary<ComponentID, FasterList<(uint, string)>> NewGroupsDictionary()
  139. {
  140. return new FasterDictionary<ComponentID, FasterList<(uint, string)>>();
  141. }
  142. static void RecycleDictionary(ref FasterDictionary<ComponentID, FasterList<(uint, string)>> recycled)
  143. {
  144. recycled.Recycle();
  145. }
  146. static FasterList<(uint, string)> NewList()
  147. {
  148. return new FasterList<(uint, string)>();
  149. }
  150. static void ClearList(ref FasterList<(uint, string)> target)
  151. {
  152. target.Clear();
  153. }
  154. static void RecycleDicitionaryWithCaller(ref FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>> target)
  155. {
  156. target.Recycle();
  157. }
  158. static void ClearListWithCaller(ref FasterDictionary<uint, SwapInfo> target)
  159. {
  160. target.Clear();
  161. }
  162. static FasterDictionary<uint, SwapInfo> NewListWithCaller()
  163. {
  164. return new FasterDictionary<uint, SwapInfo>();
  165. }
  166. static FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>
  167. NewGroupsDictionaryWithCaller()
  168. {
  169. return new FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>();
  170. }
  171. static void RecycleGroupDictionaryWithCaller(
  172. ref FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>> recycled)
  173. {
  174. recycled.Recycle();
  175. }
  176. static FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>> NewGroupDictionary()
  177. {
  178. return new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>();
  179. }
  180. struct Info
  181. {
  182. //from group //actual component type
  183. internal FasterDictionary<ExclusiveGroupStruct, FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>> _currentSwapEntitiesOperations;
  184. internal FasterDictionary<ExclusiveGroupStruct,
  185. FasterDictionary<ComponentID, FasterList<(uint, string)>>> _currentRemoveEntitiesOperations;
  186. internal FasterDictionary<EGID, (EGID fromEgid, EGID toEgid)> _entitiesSwapped;
  187. internal FasterList<EGID> _entitiesRemoved;
  188. public FasterList<(ExclusiveBuildGroup, ExclusiveBuildGroup, string)> _groupsToSwap;
  189. public FasterList<(ExclusiveBuildGroup, string)> _groupsToRemove;
  190. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  191. internal bool AnyOperationQueued()
  192. {
  193. return _entitiesSwapped.count > 0 || _entitiesRemoved.count > 0 || _groupsToSwap.count > 0
  194. || _groupsToRemove.count > 0;
  195. }
  196. internal void Clear()
  197. {
  198. _currentSwapEntitiesOperations.Recycle();
  199. _currentRemoveEntitiesOperations.Recycle();
  200. _entitiesSwapped.Clear();
  201. _entitiesRemoved.Clear();
  202. _groupsToRemove.Clear();
  203. _groupsToSwap.Clear();
  204. }
  205. internal void Init()
  206. {
  207. _entitiesSwapped = new FasterDictionary<EGID, (EGID fromEgid, EGID toEgid)>();
  208. _entitiesRemoved = new FasterList<EGID>();
  209. _groupsToRemove = new FasterList<(ExclusiveBuildGroup, string)>();
  210. _groupsToSwap = new FasterList<(ExclusiveBuildGroup, ExclusiveBuildGroup, string)>();
  211. _currentSwapEntitiesOperations =
  212. new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<ComponentID,
  213. FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>>();
  214. _currentRemoveEntitiesOperations =
  215. new FasterDictionary<ExclusiveGroupStruct,
  216. FasterDictionary<ComponentID, FasterList<(uint, string)>>>();
  217. }
  218. }
  219. Info _lastSubmittedInfo;
  220. Info _thisSubmissionInfo;
  221. readonly Func<FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>> _newGroupDictionary;
  222. readonly Func<FasterDictionary<ComponentID, FasterList<(uint, string)>>> _newGroupsDictionary;
  223. readonly ActionRef<FasterDictionary<ComponentID, FasterList<(uint, string)>>> _recycleDictionary;
  224. readonly Func<FasterList<(uint, string)>> _newList;
  225. readonly ActionRef<FasterList<(uint, string)>> _clearList;
  226. readonly Func<FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>>
  227. _newGroupsDictionaryWithCaller;
  228. readonly ActionRef<FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>>>
  229. _recycleGroupDictionaryWithCaller;
  230. readonly ActionRef<FasterDictionary<ExclusiveGroupStruct, FasterDictionary<uint, SwapInfo>>> _recycleDicitionaryWithCaller;
  231. readonly Func<FasterDictionary<uint, SwapInfo>> _newListWithCaller;
  232. readonly ActionRef<FasterDictionary<uint, SwapInfo>> _clearListWithCaller;
  233. }
  234. public struct SwapInfo
  235. {
  236. public uint fromID; //to do this information should be redundant, try to remove it
  237. public uint toID;
  238. public uint toIndex;
  239. public string trace;
  240. public SwapInfo(uint fromEgidEntityId, uint toEgidEntityId, string s)
  241. {
  242. fromID = fromEgidEntityId;
  243. toID = toEgidEntityId;
  244. toIndex = 0;
  245. trace = s;
  246. }
  247. public void Deconstruct(out uint fromID, out uint toID, out uint toIndex, out string caller)
  248. {
  249. fromID = this.fromID;
  250. toID = this.toID;
  251. toIndex = this.toIndex;
  252. caller = this.trace;
  253. }
  254. public void Deconstruct(out uint fromID, out uint toID, out string caller)
  255. {
  256. fromID = this.fromID;
  257. toID = this.toID;
  258. caller = this.trace;
  259. }
  260. }
  261. }