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.

411 lines
18KB

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