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.

293 lines
13KB

  1. #if EXPERIMENTAL
  2. using System;
  3. using System.Runtime.CompilerServices;
  4. using Svelto.Common;
  5. using Svelto.DataStructures;
  6. namespace Svelto.ECS.Internal
  7. {
  8. sealed class FastTypeSafeDictionary<TValue> : ITypeSafeDictionary<TValue> where TValue : struct, IEntityComponent
  9. {
  10. static readonly Type _type = typeof(TValue);
  11. static readonly string _typeName = _type.Name;
  12. static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type);
  13. public FastTypeSafeDictionary(uint size) { _implementation = new SetDictionary<TValue>(size); }
  14. public FastTypeSafeDictionary() { _implementation = new SetDictionary<TValue>(1); }
  15. /// <summary>
  16. /// Add entities from external typeSafeDictionary
  17. /// </summary>
  18. /// <param name="entitiesToSubmit"></param>
  19. /// <param name="groupId"></param>
  20. /// <exception cref="TypeSafeDictionaryException"></exception>
  21. public void AddEntitiesFromDictionary(ITypeSafeDictionary entitiesToSubmit, uint groupId)
  22. {
  23. var typeSafeDictionary = entitiesToSubmit as FastTypeSafeDictionary<TValue>;
  24. foreach (var tuple in typeSafeDictionary)
  25. {
  26. try
  27. {
  28. if (_hasEgid)
  29. SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref typeSafeDictionary.unsafeValues[tuple.Key],
  30. new EGID(tuple.Key, groupId));
  31. _implementation.Add(tuple.Value);
  32. }
  33. catch (Exception e)
  34. {
  35. throw new
  36. TypeSafeDictionaryException("trying to add an EntityComponent with the same ID more than once Entity: ".
  37. FastConcat(typeof(TValue).ToString()).FastConcat(", group ").
  38. FastConcat(groupId).FastConcat(", id ").FastConcat(tuple.Key), e);
  39. }
  40. }
  41. }
  42. public void AddEntityToDictionary(EGID fromEntityGid, EGID toEntityID, ITypeSafeDictionary toGroup)
  43. {
  44. var valueIndex = _implementation.GetIndex(fromEntityGid.entityID);
  45. if (toGroup != null)
  46. {
  47. var toGroupCasted = toGroup as ITypeSafeDictionary<TValue>;
  48. ref var entity = ref _implementation.unsafeValues[(int) valueIndex];
  49. if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityID);
  50. toGroupCasted.Add(fromEntityGid.entityID, entity);
  51. }
  52. }
  53. public void AddEntitiesToEngines(FasterDictionary<RefWrapperType, FasterList<IEngine>> entityComponentEnginesDB,
  54. ITypeSafeDictionary realDic,
  55. ExclusiveGroupStruct @group,
  56. in PlatformProfiler profiler)
  57. {
  58. var typeSafeDictionary = realDic as ITypeSafeDictionary<TValue>;
  59. //this can be optimized, should pass all the entities and not restart the process for each one
  60. foreach (var value in _implementation)
  61. AddEntityComponentToEngines(entityComponentEnginesDB, ref typeSafeDictionary.GetValueByRef(value.Key), null,
  62. in profiler, new EGID(value.Key, group));
  63. }
  64. public void RemoveEntitiesFromEngines(
  65. FasterDictionary<RefWrapperType, FasterList<IEngine>> entityComponentEnginesDB, in PlatformProfiler profiler,
  66. ExclusiveGroupStruct @group)
  67. {
  68. foreach (var value in _implementation)
  69. RemoveEntityComponentFromEngines(entityComponentEnginesDB, ref _implementation.GetValueByRef(value.Key), null,
  70. in profiler, new EGID(value.Key, group));
  71. }
  72. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  73. public void FastClear() { _implementation.FastClear(); }
  74. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  75. public bool Has(uint key) { return _implementation.ContainsKey(key); }
  76. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  77. public void RemoveEntityFromDictionary(EGID fromEntityGid)
  78. {
  79. _implementation.Remove(fromEntityGid.entityID);
  80. }
  81. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  82. public void SetCapacity(uint size) { throw new NotImplementedException(); }
  83. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  84. public void Trim() { _implementation.Trim(); }
  85. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  86. public void Clear() { _implementation.Clear(); }
  87. public void MoveEntityFromEngines(EGID fromEntityGid, EGID? toEntityID, ITypeSafeDictionary toGroup,
  88. FasterDictionary<RefWrapperType, FasterList<IEngine>> engines,
  89. in PlatformProfiler profiler)
  90. {
  91. var valueIndex = _implementation.GetIndex(fromEntityGid.entityID);
  92. ref var entity = ref _implementation.unsafeValues[(int) valueIndex];
  93. if (toGroup != null)
  94. {
  95. RemoveEntityComponentFromEngines(engines, ref entity, fromEntityGid.groupID, in profiler, fromEntityGid);
  96. var toGroupCasted = toGroup as ITypeSafeDictionary<TValue>;
  97. var previousGroup = fromEntityGid.groupID;
  98. if (_hasEgid) SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityID.Value);
  99. var index = toGroupCasted.GetIndex(toEntityID.Value.entityID);
  100. AddEntityComponentToEngines(engines, ref toGroupCasted.unsafeValues[(int) index], previousGroup, in profiler,
  101. toEntityID.Value);
  102. }
  103. else
  104. RemoveEntityComponentFromEngines(engines, ref entity, null, in profiler, fromEntityGid);
  105. }
  106. public uint Count
  107. {
  108. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  109. get => _implementation.count;
  110. }
  111. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  112. public ITypeSafeDictionary Create() { return new FastTypeSafeDictionary<TValue>(); }
  113. void AddEntityComponentToEngines(FasterDictionary<RefWrapperType, FasterList<IEngine>> entityComponentEnginesDB,
  114. ref TValue entity,
  115. ExclusiveGroupStruct? previousGroup,
  116. in PlatformProfiler profiler,
  117. EGID egid)
  118. {
  119. //get all the engines linked to TValue
  120. if (!entityComponentEnginesDB.TryGetValue(new RefWrapperType(_type), out var entityComponentsEngines)) return;
  121. if (previousGroup == null)
  122. {
  123. for (var i = 0; i < entityComponentsEngines.count; i++)
  124. try
  125. {
  126. using (profiler.Sample(entityComponentsEngines[i], _typeName))
  127. {
  128. (entityComponentsEngines[i] as IReactOnAddAndRemove<TValue>).Add(ref entity, egid);
  129. }
  130. }
  131. catch (Exception e)
  132. {
  133. throw new
  134. ECSException("Code crashed inside Add callback ".FastConcat(typeof(TValue).ToString()), e);
  135. }
  136. }
  137. else
  138. {
  139. for (var i = 0; i < entityComponentsEngines.count; i++)
  140. try
  141. {
  142. using (profiler.Sample(entityComponentsEngines[i], _typeName))
  143. {
  144. (entityComponentsEngines[i] as IReactOnSwap<TValue>).MovedTo(ref entity, previousGroup.Value,
  145. egid);
  146. }
  147. }
  148. catch (Exception e)
  149. {
  150. throw new
  151. ECSException("Code crashed inside MovedTo callback ".FastConcat(typeof(TValue).ToString()),
  152. e);
  153. }
  154. }
  155. }
  156. static void RemoveEntityComponentFromEngines(FasterDictionary<RefWrapperType, FasterList<IEngine>> @group,
  157. ref TValue entity,
  158. ExclusiveGroupStruct? previousGroup,
  159. in PlatformProfiler profiler,
  160. EGID egid)
  161. {
  162. if (!@group.TryGetValue(new RefWrapperType(_type), out var entityComponentsEngines)) return;
  163. if (previousGroup == null)
  164. {
  165. for (var i = 0; i < entityComponentsEngines.count; i++)
  166. try
  167. {
  168. using (profiler.Sample(entityComponentsEngines[i], _typeName))
  169. (entityComponentsEngines[i] as IReactOnAddAndRemove<TValue>).Remove(ref entity, egid);
  170. }
  171. catch (Exception e)
  172. {
  173. throw new
  174. ECSException("Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()),
  175. e);
  176. }
  177. }
  178. #if SEEMS_UNNECESSARY
  179. else
  180. {
  181. for (var i = 0; i < entityComponentsEngines.Count; i++)
  182. try
  183. {
  184. using (profiler.Sample(entityComponentsEngines[i], _typeName))
  185. (entityComponentsEngines[i] as IReactOnSwap<TValue>).MovedFrom(ref entity, egid);
  186. }
  187. catch (Exception e)
  188. {
  189. throw new ECSException(
  190. "Code crashed inside Remove callback ".FastConcat(typeof(TValue).ToString()), e);
  191. }
  192. }
  193. #endif
  194. }
  195. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  196. public TValue[] GetValuesArray(out uint count)
  197. {
  198. var managedBuffer = _implementation.GetValuesArray(out count);
  199. return managedBuffer;
  200. }
  201. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  202. public bool ContainsKey(uint egidEntityId) { return _implementation.ContainsKey(egidEntityId); }
  203. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  204. public void Add(uint egidEntityId, in TValue entityComponent) { _implementation.Add(entityComponent); }
  205. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  206. public SetDictionary<TValue>.SetDictionaryKeyValueEnumerator GetEnumerator()
  207. {
  208. return _implementation.GetEnumerator();
  209. }
  210. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  211. public ref TValue GetValueByRef(uint key) { return ref _implementation.GetValueByRef(key); }
  212. public TValue this[uint idEntityId]
  213. {
  214. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  215. get => _implementation[idEntityId];
  216. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  217. set => _implementation[idEntityId] = value;
  218. }
  219. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  220. public uint GetIndex(uint valueEntityId) { return _implementation.GetIndex(valueEntityId); }
  221. public TValue[] unsafeValues
  222. {
  223. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  224. get => _implementation.unsafeValues;
  225. }
  226. public SetDictionary<TValue> implementation => _implementation;
  227. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  228. public bool TryGetValue(uint entityId, out TValue item)
  229. {
  230. return _implementation.TryGetValue(entityId, out item);
  231. }
  232. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  233. public ref TValue GetOrCreate(uint idEntityId) { throw new NotImplementedException(); }
  234. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  235. public bool TryFindIndex(uint entityId, out uint index)
  236. {
  237. return _implementation.TryFindIndex(entityId, out index);
  238. }
  239. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  240. public ref TValue GetDirectValue(uint findElementIndex)
  241. {
  242. return ref _implementation.GetDirectValue(findElementIndex);
  243. }
  244. readonly SetDictionary<TValue> _implementation;
  245. }
  246. }
  247. #endif