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.

325 lines
14KB

  1. using System;
  2. using System.Collections.Generic;
  3. using Svelto.DataStructures;
  4. using Svelto.ECS.Internal;
  5. #if EXPERIMENTAL
  6. using Svelto.ECS.Experimental;
  7. using Svelto.ECS.Experimental.Internal;
  8. #endif
  9. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  10. using Svelto.ECS.Profiler;
  11. #endif
  12. namespace Svelto.ECS
  13. {
  14. public partial class EnginesRoot : IDisposable
  15. {
  16. /// <summary>
  17. /// an EnginesRoot reference cannot be held by anything else than the Composition Root
  18. /// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference
  19. /// of the EnginesRoot to be passed around.
  20. /// </summary>
  21. /// <returns></returns>
  22. public IEntityFactory GenerateEntityFactory()
  23. {
  24. return new GenericEntityFactory(new DataStructures.WeakReference<EnginesRoot>(this));
  25. }
  26. public IEntityFunctions GenerateEntityFunctions()
  27. {
  28. return new GenericEntityFunctions(new DataStructures.WeakReference<EnginesRoot>(this));
  29. }
  30. /// <summary>
  31. /// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity
  32. /// itself in terms of EntityViews to build. The Implementors are passed to fill the
  33. /// references of the EntityViews components. Please read the articles on my blog
  34. /// to understand better the terminologies
  35. /// </summary>
  36. /// <typeparam name="T"></typeparam>
  37. /// <param name="entityID"></param>
  38. /// <param name="implementors"></param>
  39. void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new()
  40. {
  41. EntityFactory.BuildEntityViews
  42. (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate<T>.Default, implementors);
  43. }
  44. /// <summary>
  45. /// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo
  46. /// can be built in place of the generic parameter T.
  47. /// </summary>
  48. /// <param name="entityID"></param>
  49. /// <param name="entityDescriptor"></param>
  50. /// <param name="implementors"></param>
  51. void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
  52. {
  53. EntityFactory.BuildEntityViews
  54. (entityID, _entityViewsToAdd.current, entityDescriptor, implementors);
  55. }
  56. /// <summary>
  57. /// A meta entity is a way to manage a set of entitites that are not easily
  58. /// queriable otherwise. For example you may want to group existing entities
  59. /// by size and type and then use the meta entity entityView to manage the data
  60. /// shared among the single entities of the same type and size. This will
  61. /// prevent the scenario where the coder is forced to parse all the entities to
  62. /// find the ones of the same size and type.
  63. /// Since the entities are managed through the shared entityView, the same
  64. /// shared entityView must be found on the single entities of the same type and size.
  65. /// The shared entityView of the meta entity is then used by engines that are meant
  66. /// to manage a group of entities through a single entityView.
  67. /// The same engine can manage several meta entities entityViews too.
  68. /// The Engine manages the logic of the Meta EntityView data and other engines
  69. /// can read back this data through the normal entity as the shared entityView
  70. /// will be present in their descriptor too.
  71. /// It's a way to control a group of Entities through a entityView only.
  72. /// This set of entities can share exactly the same entityView reference if
  73. /// built through this function. In this way, if you need to set a variable
  74. /// on a group of entities, instead to inject N entityViews and iterate over
  75. /// them to set the same value, you can inject just one entityView, set the value
  76. /// and be sure that the value is shared between entities.
  77. /// </summary>
  78. /// <param name="metaEntityID"></param>
  79. /// <param name="ed"></param>
  80. /// <param name="implementors"></param>
  81. void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new()
  82. {
  83. EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current,
  84. EntityDescriptorTemplate<T>.Default, implementors);
  85. }
  86. /// <summary>
  87. /// Using this function is like building a normal entity, but the entityViews
  88. /// are grouped by groupID to be more efficently processed inside engines and
  89. /// improve cache locality. Either class entityViews and struct entityViews can be
  90. /// grouped.
  91. /// </summary>
  92. /// <param name="entityID"></param>
  93. /// <param name="groupID"></param>
  94. /// <param name="ed"></param>
  95. /// <param name="implementors"></param>
  96. void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new()
  97. {
  98. EntityFactory.BuildGroupedEntityViews(entityID, groupID,
  99. _groupedEntityViewsToAdd.current,
  100. EntityDescriptorTemplate<T>.Default,
  101. implementors);
  102. }
  103. void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
  104. {
  105. EntityFactory.BuildGroupedEntityViews(entityID, groupID,
  106. _groupedEntityViewsToAdd.current,
  107. entityDescriptor, implementors);
  108. }
  109. void Preallocate<T>(int size) where T : IEntityDescriptor, new()
  110. {
  111. var entityViewsToBuild = EntityDescriptorTemplate<T>.Default.entityViewsToBuild;
  112. int count = entityViewsToBuild.Length;
  113. for (int index = 0; index < count; index++)
  114. {
  115. var entityViewBuilder = entityViewsToBuild[index];
  116. var entityViewType = entityViewBuilder.GetEntityViewType();
  117. ITypeSafeList dbList;
  118. if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false)
  119. _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size);
  120. else
  121. dbList.ReserveCapacity(size);
  122. if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false)
  123. _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size);
  124. else
  125. dbList.ReserveCapacity(size);
  126. }
  127. }
  128. void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo)
  129. {
  130. var removeEntityImplementor = removeInfo as RemoveEntityImplementor;
  131. if (removeEntityImplementor.isInAGroup)
  132. InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB);
  133. else
  134. InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB);
  135. }
  136. void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new()
  137. {
  138. InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, entityID, _entityViewsDB);
  139. }
  140. void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new()
  141. {
  142. InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, metaEntityID, _metaEntityViewsDB);
  143. }
  144. void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new()
  145. {
  146. InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]);
  147. }
  148. void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID,
  149. Dictionary<Type, ITypeSafeList> entityViewsDB)
  150. {
  151. int entityViewBuildersCount = entityViewBuilders.Length;
  152. for (int i = 0; i < entityViewBuildersCount; i++)
  153. {
  154. Type entityViewType = entityViewBuilders[i].GetEntityViewType();
  155. ITypeSafeList entityViews = entityViewsDB[entityViewType];
  156. if (entityViews.UnorderedRemove(entityID) == false)
  157. entityViewsDB.Remove(entityViewType);
  158. if (entityViews.isQueryiableEntityView)
  159. {
  160. var typeSafeDictionary = _entityViewsDBdic[entityViewType];
  161. var entityView = typeSafeDictionary.GetIndexedEntityView(entityID);
  162. if (typeSafeDictionary.Remove(entityID) == false)
  163. _entityViewsDBdic.Remove(entityViewType);
  164. RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType);
  165. }
  166. }
  167. }
  168. void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID,
  169. Dictionary<Type, ITypeSafeList> entityViewsDB)
  170. {
  171. int entityViewBuildersCount = entityViewBuilders.Length;
  172. for (int i = 0; i < entityViewBuildersCount; i++)
  173. {
  174. Type entityViewType = entityViewBuilders[i].GetEntityViewType();
  175. Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[groupID];
  176. if (dictionary[entityViewType].UnorderedRemove(entityID) == false)
  177. dictionary.Remove(entityViewType);
  178. if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID);
  179. }
  180. InternalRemove(entityViewBuilders, entityID, entityViewsDB);
  181. }
  182. static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines,
  183. IEntityView entityView, Type entityViewType)
  184. {
  185. FasterList<IHandleEntityViewEngine> enginesForEntityView;
  186. if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView))
  187. {
  188. int count;
  189. var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count);
  190. for (int j = 0; j < count; j++)
  191. {
  192. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  193. EngineProfiler.MonitorRemoveDuration(fastList[j], entityView);
  194. #else
  195. fastList[j].Remove(entityView);
  196. #endif
  197. }
  198. }
  199. }
  200. class GenericEntityFactory : IEntityFactory
  201. {
  202. DataStructures.WeakReference<EnginesRoot> _weakEngine;
  203. public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference)
  204. {
  205. _weakEngine = weakReference;
  206. }
  207. public void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new()
  208. {
  209. _weakEngine.Target.BuildEntity<T>(entityID, implementors);
  210. }
  211. public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
  212. {
  213. _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors);
  214. }
  215. public void BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new()
  216. {
  217. _weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors);
  218. }
  219. public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new()
  220. {
  221. _weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors);
  222. }
  223. public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
  224. {
  225. _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors);
  226. }
  227. public void Preallocate<T>(int size) where T : IEntityDescriptor, new()
  228. {
  229. _weakEngine.Target.Preallocate<T>(size);
  230. }
  231. }
  232. class GenericEntityFunctions : IEntityFunctions
  233. {
  234. public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference)
  235. {
  236. _weakReference = weakReference;
  237. }
  238. public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo)
  239. {
  240. _weakReference.Target.RemoveEntity(entityID, removeInfo);
  241. }
  242. public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new()
  243. {
  244. _weakReference.Target.RemoveEntity<T>(entityID);
  245. }
  246. public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new()
  247. {
  248. _weakReference.Target.RemoveEntity<T>(metaEntityID);
  249. }
  250. public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new()
  251. {
  252. _weakReference.Target.RemoveEntity<T>(entityID);
  253. }
  254. readonly DataStructures.WeakReference<EnginesRoot> _weakReference;
  255. }
  256. public void Dispose()
  257. {
  258. foreach (var entity in _entityViewsDB)
  259. {
  260. if (entity.Value.isQueryiableEntityView == true)
  261. {
  262. foreach (var entityView in entity.Value)
  263. {
  264. RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key);
  265. }
  266. }
  267. }
  268. foreach (var entity in _metaEntityViewsDB)
  269. {
  270. foreach (var entityView in entity.Value)
  271. {
  272. RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key);
  273. }
  274. }
  275. }
  276. }
  277. }