Mirror of Svelto.ECS because we're a fan of it
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

549 行
26KB

  1. using System;
  2. using System.Runtime.CompilerServices;
  3. using DBC.ECS;
  4. using Svelto.Common;
  5. using Svelto.DataStructures;
  6. namespace Svelto.ECS.Internal
  7. {
  8. public static class TypeSafeDictionaryMethods
  9. {
  10. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  11. public static void AddEntitiesToDictionary<Strategy1, Strategy2, Strategy3, TValue>
  12. (in SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  13. , ITypeSafeDictionary<TValue> toDic
  14. #if SLOW_SVELTO_SUBMISSION
  15. , in EnginesRoot.EntityReferenceMap entityLocator
  16. #endif
  17. , ExclusiveGroupStruct toGroupID) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  18. where Strategy2 : struct, IBufferStrategy<TValue>
  19. where Strategy3 : struct, IBufferStrategy<int>
  20. where TValue : struct, _IInternalEntityComponent
  21. {
  22. foreach (var tuple in fromDictionary)
  23. {
  24. #if SLOW_SVELTO_SUBMISSION
  25. var egid = new EGID(tuple.key, toGroupID);
  26. if (SlowSubmissionInfo<TValue>.hasEgid)
  27. SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref tuple.value, egid);
  28. if (SlowSubmissionInfo<TValue>.hasReference)
  29. SetEGIDWithoutBoxing<TValue>.SetRefWithoutBoxing(ref tuple.value,
  30. entityLocator.GetEntityReference(egid));
  31. #endif
  32. try
  33. {
  34. toDic.Add(tuple.key, tuple.value);
  35. }
  36. catch (Exception e)
  37. {
  38. Console.LogException(
  39. e, "trying to add an EntityComponent with the same ID more than once Entity: ".FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(toGroupID.ToName()).FastConcat(", id ").FastConcat(tuple.key));
  40. throw;
  41. }
  42. #if PARANOID_CHECK && SLOW_SVELTO_SUBMISSION
  43. DBC.ECS.Check.Ensure(_hasEgid == false || ((INeedEGID)fromDictionary[egid.entityID]).ID == egid, "impossible situation happened during swap");
  44. #endif
  45. }
  46. }
  47. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  48. public static void ExecuteEnginesAddCallbacks<Strategy1, Strategy2, Strategy3, TValue>
  49. (ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  50. , ITypeSafeDictionary<TValue> todic, ExclusiveGroupStruct togroup
  51. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAdd>>> entitycomponentenginesdb
  52. , in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  53. where Strategy2 : struct, IBufferStrategy<TValue>
  54. where Strategy3 : struct, IBufferStrategy<int>
  55. where TValue : struct, _IInternalEntityComponent
  56. {
  57. if (entitycomponentenginesdb.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  58. , out var entityComponentsEngines))
  59. {
  60. if (entityComponentsEngines.count == 0)
  61. return;
  62. var dictionaryKeyEnumerator = fromDictionary.unsafeKeys;
  63. var count = fromDictionary.count;
  64. for (var i = 0; i < count; ++i)
  65. try
  66. {
  67. var key = dictionaryKeyEnumerator[i].key;
  68. ref var entity = ref todic.GetValueByRef(key);
  69. var egid = new EGID(key, togroup);
  70. //get all the engines linked to TValue
  71. for (var j = 0; j < entityComponentsEngines.count; j++)
  72. using (sampler.Sample(entityComponentsEngines[j].name))
  73. {
  74. #pragma warning disable CS0612
  75. ((IReactOnAdd<TValue>)entityComponentsEngines[j].engine).Add(ref entity, egid);
  76. #pragma warning restore CS0612
  77. }
  78. }
  79. catch (Exception e)
  80. {
  81. Console.LogException(
  82. e, "Code crashed inside Add callback with Type ".FastConcat(TypeCache<TValue>.name));
  83. throw;
  84. }
  85. }
  86. }
  87. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  88. public static void ExecuteEnginesDisposeCallbacks_Group<Strategy1, Strategy2, Strategy3, TValue>
  89. (ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  90. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>> allEngines
  91. , ExclusiveGroupStruct inGroup, in PlatformProfiler sampler)
  92. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  93. where Strategy2 : struct, IBufferStrategy<TValue>
  94. where Strategy3 : struct, IBufferStrategy<int>
  95. where TValue : struct, _IInternalEntityComponent
  96. {
  97. if (allEngines.TryGetValue(new RefWrapperType(TypeCache<TValue>.type), out var entityComponentsEngines)
  98. == false)
  99. return;
  100. for (var i = 0; i < entityComponentsEngines.count; i++)
  101. try
  102. {
  103. using (sampler.Sample(entityComponentsEngines[i].name))
  104. {
  105. foreach (var value in fromDictionary)
  106. {
  107. ref var entity = ref value.value;
  108. var egid = new EGID(value.key, inGroup);
  109. var reactOnRemove = (IReactOnDispose<TValue>)entityComponentsEngines[i].engine;
  110. reactOnRemove.Remove(ref entity, egid);
  111. }
  112. }
  113. }
  114. catch
  115. {
  116. Console.LogError(
  117. "Code crashed inside Remove callback ".FastConcat(entityComponentsEngines[i].name));
  118. throw;
  119. }
  120. }
  121. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  122. public static void ExecuteEnginesRemoveCallbacks<Strategy1, Strategy2, Strategy3, TValue>
  123. (FasterList<(uint, string)> infostoprocess
  124. , ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  125. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveenginesremove
  126. , ExclusiveGroupStruct fromgroup, in PlatformProfiler profiler)
  127. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  128. where Strategy2 : struct, IBufferStrategy<TValue>
  129. where Strategy3 : struct, IBufferStrategy<int>
  130. where TValue : struct, _IInternalEntityComponent
  131. {
  132. if (reactiveenginesremove.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  133. , out var entityComponentsEngines))
  134. {
  135. if (entityComponentsEngines.count == 0)
  136. return;
  137. var iterations = infostoprocess.count;
  138. for (var i = 0; i < iterations; i++)
  139. {
  140. var (entityID, trace) = infostoprocess[i];
  141. try
  142. {
  143. ref var entity = ref fromDictionary.GetValueByRef(entityID);
  144. var egid = new EGID(entityID, fromgroup);
  145. for (var j = 0; j < entityComponentsEngines.count; j++)
  146. using (profiler.Sample(entityComponentsEngines[j].name))
  147. {
  148. #pragma warning disable CS0612
  149. ((IReactOnRemove<TValue>)entityComponentsEngines[j].engine).Remove(ref entity, egid);
  150. #pragma warning restore CS0612
  151. }
  152. }
  153. catch
  154. {
  155. var str = "Crash while executing Remove Entity callback on ".FastConcat(TypeCache<TValue>.name)
  156. .FastConcat(" from : ", trace);
  157. Console.LogError(str);
  158. throw;
  159. }
  160. }
  161. }
  162. }
  163. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  164. public static void ExecuteEnginesRemoveCallbacks_Group<Strategy1, Strategy2, Strategy3, TValue>
  165. (ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  166. , ITypeSafeDictionary<TValue> typeSafeDictionary
  167. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveenginesremove
  168. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemoveEx>>> reactiveenginesremoveex
  169. , int count, IEntityIDs entityids, ExclusiveGroupStruct group, in PlatformProfiler sampler)
  170. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  171. where Strategy2 : struct, IBufferStrategy<TValue>
  172. where Strategy3 : struct, IBufferStrategy<int>
  173. where TValue : struct, _IInternalEntityComponent
  174. {
  175. if (reactiveenginesremove.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  176. , out var reactiveEnginesRemovePerType))
  177. {
  178. var enginesCount = reactiveEnginesRemovePerType.count;
  179. for (var i = 0; i < enginesCount; i++)
  180. try
  181. {
  182. foreach (var value in fromDictionary)
  183. {
  184. ref var entity = ref value.value;
  185. var egid = new EGID(value.key, group);
  186. using (sampler.Sample(reactiveEnginesRemovePerType[i].name))
  187. {
  188. #pragma warning disable CS0612
  189. ((IReactOnRemove<TValue>)reactiveEnginesRemovePerType[i].engine).Remove(
  190. #pragma warning restore CS0612
  191. ref entity, egid);
  192. }
  193. }
  194. }
  195. catch
  196. {
  197. Console.LogError(
  198. "Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemovePerType[i].name));
  199. throw;
  200. }
  201. }
  202. if (reactiveenginesremoveex.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  203. , out var reactiveEnginesRemoveExPerType))
  204. {
  205. var enginesCount = reactiveEnginesRemoveExPerType.count;
  206. for (var i = 0; i < enginesCount; i++)
  207. try
  208. {
  209. using (sampler.Sample(reactiveEnginesRemoveExPerType[i].name))
  210. {
  211. ((IReactOnRemoveEx<TValue>)reactiveEnginesRemoveExPerType[i].engine).Remove(
  212. (0, (uint)count)
  213. , new EntityCollection<TValue>(typeSafeDictionary.GetValues(out _), entityids
  214. , (uint)count), group);
  215. }
  216. }
  217. catch
  218. {
  219. Console.LogError(
  220. "Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemoveExPerType[i].name));
  221. throw;
  222. }
  223. }
  224. }
  225. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  226. public static void ExecuteEnginesSwapCallbacks<Strategy1, Strategy2, Strategy3, TValue>
  227. (FasterList<(uint, uint, string)> infostoprocess
  228. , ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  229. , FasterList<ReactEngineContainer<IReactOnSwap>> reactiveenginesswap, ExclusiveGroupStruct togroup
  230. , ExclusiveGroupStruct fromgroup, in PlatformProfiler sampler)
  231. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  232. where Strategy2 : struct, IBufferStrategy<TValue>
  233. where Strategy3 : struct, IBufferStrategy<int>
  234. where TValue : struct, _IInternalEntityComponent
  235. {
  236. if (reactiveenginesswap.count == 0)
  237. return;
  238. var iterations = infostoprocess.count;
  239. for (var i = 0; i < iterations; i++)
  240. {
  241. var (fromEntityID, toEntityID, trace) = infostoprocess[i];
  242. try
  243. {
  244. ref var entityComponent = ref fromDictionary.GetValueByRef(fromEntityID);
  245. var newEgid = new EGID(toEntityID, togroup);
  246. for (var j = 0; j < reactiveenginesswap.count; j++)
  247. using (sampler.Sample(reactiveenginesswap[j].name))
  248. {
  249. #pragma warning disable CS0612
  250. ((IReactOnSwap<TValue>)reactiveenginesswap[j].engine).MovedTo(
  251. #pragma warning restore CS0612
  252. ref entityComponent, fromgroup, newEgid);
  253. }
  254. }
  255. catch
  256. {
  257. var str = "Crash while executing Swap Entity callback on ".FastConcat(TypeCache<TValue>.name)
  258. .FastConcat(" from : ", trace);
  259. Console.LogError(str);
  260. throw;
  261. }
  262. }
  263. }
  264. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  265. public static void ExecuteEnginesSwapCallbacks_Group<Strategy1, Strategy2, Strategy3, TValue>
  266. (ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  267. , ITypeSafeDictionary<TValue> toDic, ExclusiveGroupStruct togroup, ExclusiveGroupStruct fromgroup
  268. , ITypeSafeDictionary<TValue> typeSafeDictionary
  269. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwap>>> reactiveenginesswap
  270. , FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwapEx>>> reactiveenginesswapex
  271. , int count, IEntityIDs entityids, in PlatformProfiler sampler)
  272. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  273. where Strategy2 : struct, IBufferStrategy<TValue>
  274. where Strategy3 : struct, IBufferStrategy<int>
  275. where TValue : struct, _IInternalEntityComponent
  276. {
  277. //get all the engines linked to TValue
  278. if (!reactiveenginesswap.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  279. , out var reactiveEnginesSwapPerType))
  280. return;
  281. var componentsEnginesCount = reactiveEnginesSwapPerType.count;
  282. for (var i = 0; i < componentsEnginesCount; i++)
  283. try
  284. {
  285. foreach (var value in fromDictionary)
  286. {
  287. ref var entityComponent = ref toDic.GetValueByRef(value.key);
  288. var newEgid = new EGID(value.key, togroup);
  289. using (sampler.Sample(reactiveEnginesSwapPerType[i].name))
  290. {
  291. #pragma warning disable CS0612
  292. ((IReactOnSwap<TValue>)reactiveEnginesSwapPerType[i].engine).MovedTo(
  293. #pragma warning restore CS0612
  294. ref entityComponent, fromgroup, newEgid);
  295. }
  296. }
  297. }
  298. catch (Exception)
  299. {
  300. Console.LogError(
  301. "Code crashed inside MoveTo callback ".FastConcat(reactiveEnginesSwapPerType[i].name));
  302. throw;
  303. }
  304. if (reactiveenginesswapex.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  305. , out var reactiveEnginesRemoveExPerType))
  306. {
  307. var enginesCount = reactiveEnginesRemoveExPerType.count;
  308. for (var i = 0; i < enginesCount; i++)
  309. try
  310. {
  311. using (sampler.Sample(reactiveEnginesRemoveExPerType[i].name))
  312. {
  313. ((IReactOnSwapEx<TValue>)reactiveEnginesRemoveExPerType[i].engine).MovedTo(
  314. (0, (uint)count)
  315. , new EntityCollection<TValue>(typeSafeDictionary.GetValues(out _), entityids
  316. , (uint)count), fromgroup, togroup);
  317. }
  318. }
  319. catch
  320. {
  321. Console.LogError(
  322. "Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemoveExPerType[i].name));
  323. throw;
  324. }
  325. }
  326. }
  327. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  328. public static void RemoveEntitiesFromDictionary<Strategy1, Strategy2, Strategy3, TValue>
  329. (FasterList<(uint, string)> infostoprocess
  330. , ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  331. , FasterList<uint> entityIDsAffectedByRemoval)
  332. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  333. where Strategy2 : struct, IBufferStrategy<TValue>
  334. where Strategy3 : struct, IBufferStrategy<int>
  335. where TValue : struct, _IInternalEntityComponent
  336. {
  337. var iterations = infostoprocess.count;
  338. for (var i = 0; i < iterations; i++)
  339. {
  340. var (id, trace) = infostoprocess[i];
  341. try
  342. {
  343. if (fromDictionary.Remove(id, out var index, out var value))
  344. {
  345. //Note I am doing this to be able to use a range of values even with the
  346. //remove Ex callbacks. Basically I am copying back the deleted value
  347. //at the end of the array, so I can use as range count, count + number of deleted entities
  348. //I need to swap the keys too to have matching EntityIDs
  349. fromDictionary.unsafeValues[(uint)fromDictionary.count] = value;
  350. fromDictionary.unsafeKeys[(uint)fromDictionary.count] = new SveltoDictionaryNode<uint>(ref id, 0);
  351. //when a component is removed from a component array, a remove swap back happens. This means
  352. //that not only we have to remove the index of the component of the entity deleted from the array
  353. //but we need also to update the index of the component that has been swapped in the cell
  354. //of the deleted component
  355. //entityIDsAffectedByRemoval tracks all the entitiesID of the components that need to be updated
  356. //in the filters because their indices in the array changed.
  357. entityIDsAffectedByRemoval.Add(fromDictionary.unsafeKeys[index].key);
  358. }
  359. }
  360. catch
  361. {
  362. var str = "Crash while executing Remove Entity operation on ".FastConcat(TypeCache<TValue>.name)
  363. .FastConcat(" from : ", trace);
  364. Console.LogError(str);
  365. throw;
  366. }
  367. }
  368. }
  369. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  370. public static void SwapEntitiesBetweenDictionaries<Strategy1, Strategy2, Strategy3, TValue>
  371. (FasterList<(uint, uint, string)> infostoprocess
  372. , ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary
  373. , ITypeSafeDictionary<TValue> toDictionary, ExclusiveGroupStruct fromgroup, ExclusiveGroupStruct togroup
  374. , FasterList<uint> entityIDsAffectedByRemoval)
  375. where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>>
  376. where Strategy2 : struct, IBufferStrategy<TValue>
  377. where Strategy3 : struct, IBufferStrategy<int>
  378. where TValue : struct, _IInternalEntityComponent
  379. {
  380. var iterations = infostoprocess.count;
  381. for (var i = 0; i < iterations; i++)
  382. {
  383. var (fromID, toID, trace) = infostoprocess[i];
  384. try
  385. {
  386. var fromEntityGid = new EGID(fromID, fromgroup);
  387. var toEntityEgid = new EGID(toID, togroup);
  388. Check.Require(togroup.isInvalid == false, "Invalid To Group");
  389. if (fromDictionary.Remove(fromEntityGid.entityID, out var index, out var value))
  390. entityIDsAffectedByRemoval.Add(fromDictionary.unsafeKeys[index].key);
  391. else
  392. Check.Assert(false, "Swapping an entity that doesn't exist");
  393. #if SLOW_SVELTO_SUBMISSION
  394. if (SlowSubmissionInfo<TValue>.hasEgid)
  395. SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref value, toEntityEgid);
  396. #endif
  397. toDictionary.Add(toEntityEgid.entityID, value);
  398. #if PARANOID_CHECK
  399. DBC.ECS.Check.Ensure(_hasEgid == false || ((INeedEGID)toGroupCasted[toEntityEGID.entityID]).ID == toEntityEGID, "impossible situation happened during swap");
  400. #endif
  401. }
  402. catch
  403. {
  404. var str = "Crash while executing Swap Entity operation on ".FastConcat(TypeCache<TValue>.name)
  405. .FastConcat(" from : ", trace);
  406. Console.LogError(str);
  407. throw;
  408. }
  409. }
  410. }
  411. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  412. public static void ExecuteEnginesAddEntityCallbacksFast<TValue>
  413. (FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAddEx>>> fasterDictionary
  414. , ExclusiveGroupStruct groupId, (uint, uint) rangeTuple, IEntityIDs entityids
  415. , ITypeSafeDictionary<TValue> typeSafeDictionary, PlatformProfiler profiler)
  416. where TValue : struct, _IInternalEntityComponent
  417. {
  418. //get all the engines linked to TValue
  419. if (!fasterDictionary.TryGetValue(new RefWrapperType(TypeCache<TValue>.type)
  420. , out var entityComponentsEngines))
  421. return;
  422. for (var i = 0; i < entityComponentsEngines.count; i++)
  423. try
  424. {
  425. using (profiler.Sample(entityComponentsEngines[i].name))
  426. {
  427. ((IReactOnAddEx<TValue>)entityComponentsEngines[i].engine).Add(
  428. rangeTuple
  429. , new EntityCollection<TValue>(typeSafeDictionary.GetValues(out var count), entityids, count)
  430. , groupId);
  431. }
  432. }
  433. catch (Exception e)
  434. {
  435. Console.LogException(
  436. e, "Code crashed inside Add callback ".FastConcat(entityComponentsEngines[i].name));
  437. throw;
  438. }
  439. }
  440. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  441. public static void ExecuteEnginesSwapCallbacksFast<TValue>
  442. (FasterList<ReactEngineContainer<IReactOnSwapEx>> fasterList, ExclusiveGroupStruct fromGroup
  443. , ExclusiveGroupStruct toGroup, IEntityIDs entityids, ITypeSafeDictionary<TValue> typeSafeDictionary
  444. , (uint, uint) rangeofsubmittedentitiesindicies, PlatformProfiler sampler)
  445. where TValue : struct, _IInternalEntityComponent
  446. {
  447. for (var i = 0; i < fasterList.count; i++)
  448. try
  449. {
  450. using (sampler.Sample(fasterList[i].name))
  451. {
  452. ((IReactOnSwapEx<TValue>)fasterList[i].engine).MovedTo(rangeofsubmittedentitiesindicies
  453. , new EntityCollection<TValue>(
  454. typeSafeDictionary.GetValues(
  455. out var count), entityids, count)
  456. , fromGroup, toGroup);
  457. }
  458. }
  459. catch (Exception e)
  460. {
  461. Console.LogException(e, "Code crashed inside Add callback ".FastConcat(fasterList[i].name));
  462. throw;
  463. }
  464. }
  465. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  466. public static void ExecuteEnginesRemoveCallbacksFast<TValue>
  467. (FasterList<ReactEngineContainer<IReactOnRemoveEx>> fasterList, ExclusiveGroupStruct exclusiveGroupStruct
  468. , (uint, uint) valueTuple, IEntityIDs entityids, ITypeSafeDictionary<TValue> typeSafeDictionary
  469. , PlatformProfiler sampler) where TValue : struct, _IInternalEntityComponent
  470. {
  471. for (var i = 0; i < fasterList.count; i++)
  472. try
  473. {
  474. using (sampler.Sample(fasterList[i].name))
  475. {
  476. ((IReactOnRemoveEx<TValue>)fasterList[i].engine).Remove(
  477. valueTuple
  478. , new EntityCollection<TValue>(typeSafeDictionary.GetValues(out var count), entityids, count)
  479. , exclusiveGroupStruct);
  480. }
  481. }
  482. catch (Exception e)
  483. {
  484. Console.LogException(e, "Code crashed inside Add callback ".FastConcat(fasterList[i].name));
  485. throw;
  486. }
  487. }
  488. }
  489. }