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.

222 lines
9.2KB

  1. using System;
  2. using Svelto.Common;
  3. using Svelto.DataStructures;
  4. namespace Svelto.ECS.Internal
  5. {
  6. public interface ITypeSafeDictionary
  7. {
  8. int Count { get; }
  9. ITypeSafeDictionary Create();
  10. void AddEntitiesToEngines(
  11. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDb,
  12. ITypeSafeDictionary realDic, in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group);
  13. void RemoveEntitiesFromEngines(FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB,
  14. in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group);
  15. void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId);
  16. void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
  17. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines, in PlatformProfiler profiler);
  18. void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup);
  19. void RemoveEntityFromDictionary(EGID fromEntityGid, in PlatformProfiler profiler);
  20. void SetCapacity(uint size);
  21. void Trim();
  22. void Clear();
  23. void FastClear();
  24. bool Has(uint entityIdEntityId);
  25. }
  26. class TypeSafeDictionary<TValue> : FasterDictionary<uint, TValue>,
  27. ITypeSafeDictionary where TValue : struct, IEntityStruct
  28. {
  29. static readonly Type _type = typeof(TValue);
  30. static readonly string _typeName = _type.Name;
  31. static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
  32. public TypeSafeDictionary(uint size) : base(size) {}
  33. public TypeSafeDictionary() {}
  34. public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId)
  35. {
  36. var typeSafeDictionary = entitiesToSubmit as TypeSafeDictionary<TValue>;
  37. foreach (var tuple in typeSafeDictionary)
  38. {
  39. try
  40. {
  41. if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref tuple.Value, new EGID(tuple.Key, groupId));
  42. Add(tuple.Key, tuple.Value);
  43. }
  44. catch (Exception e)
  45. {
  46. throw new TypeSafeDictionaryException(
  47. "trying to add an EntityView with the same ID more than once Entity: "
  48. .FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(groupId).FastConcat(", id ").FastConcat(tuple.Key), e);
  49. }
  50. }
  51. }
  52. public void AddEntitiesToEngines(
  53. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB,
  54. ITypeSafeDictionary realDic, in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group)
  55. {
  56. var typeSafeDictionary = realDic as TypeSafeDictionary<TValue>;
  57. //this can be optimized, should pass all the entities and not restart the process for each one
  58. foreach (var value in this)
  59. AddEntityViewToEngines(entityViewEnginesDB, ref typeSafeDictionary.GetValueByRef(value.Key), null,
  60. in profiler, new EGID(value.Key, group));
  61. }
  62. public void RemoveEntitiesFromEngines(
  63. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB,
  64. in PlatformProfiler profiler, ExclusiveGroup.ExclusiveGroupStruct @group)
  65. {
  66. foreach (var value in this)
  67. RemoveEntityViewFromEngines(entityViewEnginesDB, ref GetValueByRef(value.Key), null, in profiler,
  68. new EGID(value.Key, group));
  69. }
  70. public bool Has(uint entityIdEntityId)
  71. {
  72. return ContainsKey(entityIdEntityId);
  73. }
  74. public void RemoveEntityFromDictionary(EGID fromEntityGid, in PlatformProfiler profiler)
  75. {
  76. Remove(fromEntityGid.entityID);
  77. }
  78. public void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup)
  79. {
  80. var valueIndex = GetIndex(fromEntityGid.entityID);
  81. if (toGroup != null)
  82. {
  83. var toGroupCasted = toGroup as TypeSafeDictionary<TValue>;
  84. ref var entity = ref valuesArray[valueIndex];
  85. if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityID);
  86. toGroupCasted.Add(fromEntityGid.entityID, entity);
  87. }
  88. }
  89. public void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
  90. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> engines, in PlatformProfiler profiler)
  91. {
  92. var valueIndex = GetIndex(fromEntityGid.entityID);
  93. ref var entity = ref valuesArray[valueIndex];
  94. if (toGroup != null)
  95. {
  96. RemoveEntityViewFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler,
  97. fromEntityGid);
  98. var toGroupCasted = toGroup as TypeSafeDictionary<TValue>;
  99. var previousGroup = fromEntityGid.groupID;
  100. if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityID.Value);
  101. var index = toGroupCasted.GetIndex(toEntityID.Value.entityID);
  102. AddEntityViewToEngines(engines, ref toGroupCasted.valuesArray[index], previousGroup,
  103. in profiler, toEntityID.Value);
  104. }
  105. else
  106. RemoveEntityViewFromEngines(engines, ref entity, null, in profiler, fromEntityGid);
  107. }
  108. public ITypeSafeDictionary Create()
  109. {
  110. return new TypeSafeDictionary<TValue>();
  111. }
  112. void AddEntityViewToEngines(FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> entityViewEnginesDB,
  113. ref TValue entity, ExclusiveGroup.ExclusiveGroupStruct? previousGroup,
  114. in PlatformProfiler profiler, EGID egid)
  115. {
  116. //get all the engines linked to TValue
  117. if (!entityViewEnginesDB.TryGetValue(new RefWrapper<Type>(_type), out var entityViewsEngines)) return;
  118. if (previousGroup == null)
  119. {
  120. for (var i = 0; i < entityViewsEngines.Count; i++)
  121. try
  122. {
  123. using (profiler.Sample(entityViewsEngines[i], _typeName))
  124. {
  125. (entityViewsEngines[i] as IReactOnAddAndRemove<TValue>).Add(ref entity, egid);
  126. }
  127. }
  128. catch (Exception e)
  129. {
  130. throw new ECSException(
  131. "Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e);
  132. }
  133. }
  134. else
  135. {
  136. for (var i = 0; i < entityViewsEngines.Count; i++)
  137. try
  138. {
  139. using (profiler.Sample(entityViewsEngines[i], _typeName))
  140. {
  141. (entityViewsEngines[i] as IReactOnSwap<TValue>).MovedTo(ref entity, previousGroup.Value,
  142. egid);
  143. }
  144. }
  145. catch (Exception e)
  146. {
  147. throw new ECSException(
  148. "Code crashed inside MovedTo callback ".FastConcat(typeof(TValue).ToString()), e);
  149. }
  150. }
  151. }
  152. static void RemoveEntityViewFromEngines(
  153. FasterDictionary<RefWrapper<Type>, FasterList<IEngine>> @group, ref TValue entity,
  154. ExclusiveGroup.ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid)
  155. {
  156. if (!@group.TryGetValue(new RefWrapper<Type>(_type), out var entityViewsEngines)) return;
  157. if (previousGroup == null)
  158. {
  159. for (var i = 0; i < entityViewsEngines.Count; i++)
  160. try
  161. {
  162. using (profiler.Sample(entityViewsEngines[i], _typeName))
  163. (entityViewsEngines[i] as IReactOnAddAndRemove<TValue>).Remove(ref entity, egid);
  164. }
  165. catch (Exception e)
  166. {
  167. throw new ECSException(
  168. "Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
  169. }
  170. }
  171. #if SEEMS_UNNECESSARY
  172. else
  173. {
  174. for (var i = 0; i < entityViewsEngines.Count; i++)
  175. try
  176. {
  177. using (profiler.Sample(entityViewsEngines[i], _typeName))
  178. (entityViewsEngines[i] as IReactOnSwap<TValue>).MovedFrom(ref entity, egid);
  179. }
  180. catch (Exception e)
  181. {
  182. throw new ECSException(
  183. "Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
  184. }
  185. }
  186. #endif
  187. }
  188. }
  189. }