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.

374 lines
16KB

  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 SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new()
  149. {
  150. DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to");
  151. var entityViewBuilders = EntityDescriptorTemplate<T>.Default.entityViewsToBuild;
  152. int entityViewBuildersCount = entityViewBuilders.Length;
  153. for (int i = 0; i < entityViewBuildersCount; i++)
  154. {
  155. IEntityViewBuilder entityViewBuilder = entityViewBuilders[i];
  156. Type entityViewType = entityViewBuilder.GetEntityViewType();
  157. Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[fromGroupID];
  158. ITypeSafeList fromSafeList = dictionary[entityViewType];
  159. Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped;
  160. if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false)
  161. {
  162. groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>();
  163. _groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped);
  164. }
  165. ITypeSafeList toSafeList;
  166. if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false)
  167. {
  168. toSafeList = fromSafeList.Create();
  169. }
  170. entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList);
  171. if (fromSafeList.UnorderedRemove(entityID) == false)
  172. dictionary.Remove(entityViewType);
  173. if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID);
  174. }
  175. }
  176. void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID,
  177. Dictionary<Type, ITypeSafeList> entityViewsDB)
  178. {
  179. int entityViewBuildersCount = entityViewBuilders.Length;
  180. for (int i = 0; i < entityViewBuildersCount; i++)
  181. {
  182. Type entityViewType = entityViewBuilders[i].GetEntityViewType();
  183. ITypeSafeList entityViews = entityViewsDB[entityViewType];
  184. if (entityViews.UnorderedRemove(entityID) == false)
  185. entityViewsDB.Remove(entityViewType);
  186. if (entityViews.isQueryiableEntityView)
  187. {
  188. var typeSafeDictionary = _entityViewsDBdic[entityViewType];
  189. var entityView = typeSafeDictionary.GetIndexedEntityView(entityID);
  190. if (typeSafeDictionary.Remove(entityID) == false)
  191. _entityViewsDBdic.Remove(entityViewType);
  192. RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType);
  193. }
  194. }
  195. }
  196. void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID,
  197. Dictionary<Type, ITypeSafeList> entityViewsDB)
  198. {
  199. InternalRemoveFromDB(entityViewBuilders, entityID, groupID);
  200. InternalRemove(entityViewBuilders, entityID, entityViewsDB);
  201. }
  202. void InternalRemoveFromDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID)
  203. {
  204. int entityViewBuildersCount = entityViewBuilders.Length;
  205. for (int i = 0; i < entityViewBuildersCount; i++)
  206. {
  207. Type entityViewType = entityViewBuilders[i].GetEntityViewType();
  208. Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[groupID];
  209. if (dictionary[entityViewType].UnorderedRemove(entityID) == false)
  210. dictionary.Remove(entityViewType);
  211. if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID);
  212. }
  213. }
  214. static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines,
  215. IEntityView entityView, Type entityViewType)
  216. {
  217. FasterList<IHandleEntityViewEngine> enginesForEntityView;
  218. if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView))
  219. {
  220. int count;
  221. var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count);
  222. for (int j = 0; j < count; j++)
  223. {
  224. #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
  225. EngineProfiler.MonitorRemoveDuration(fastList[j], entityView);
  226. #else
  227. fastList[j].Remove(entityView);
  228. #endif
  229. }
  230. }
  231. }
  232. class GenericEntityFactory : IEntityFactory
  233. {
  234. DataStructures.WeakReference<EnginesRoot> _weakEngine;
  235. public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference)
  236. {
  237. _weakEngine = weakReference;
  238. }
  239. public void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new()
  240. {
  241. _weakEngine.Target.BuildEntity<T>(entityID, implementors);
  242. }
  243. public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
  244. {
  245. _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors);
  246. }
  247. public void BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new()
  248. {
  249. _weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors);
  250. }
  251. public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new()
  252. {
  253. _weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors);
  254. }
  255. public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null)
  256. {
  257. _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors);
  258. }
  259. public void Preallocate<T>(int size) where T : IEntityDescriptor, new()
  260. {
  261. _weakEngine.Target.Preallocate<T>(size);
  262. }
  263. }
  264. class GenericEntityFunctions : IEntityFunctions
  265. {
  266. public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference)
  267. {
  268. _weakReference = weakReference;
  269. }
  270. public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo)
  271. {
  272. _weakReference.Target.RemoveEntity(entityID, removeInfo);
  273. }
  274. public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new()
  275. {
  276. _weakReference.Target.RemoveEntity<T>(entityID);
  277. }
  278. public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new()
  279. {
  280. _weakReference.Target.RemoveEntity<T>(metaEntityID);
  281. }
  282. public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new()
  283. {
  284. _weakReference.Target.RemoveEntity<T>(entityID);
  285. }
  286. public void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new()
  287. {
  288. _weakReference.Target.SwapEntityGroup<T>(entityID, fromGroupID, toGroupID);
  289. }
  290. readonly DataStructures.WeakReference<EnginesRoot> _weakReference;
  291. }
  292. public void Dispose()
  293. {
  294. foreach (var entity in _entityViewsDB)
  295. {
  296. if (entity.Value.isQueryiableEntityView == true)
  297. {
  298. foreach (var entityView in entity.Value)
  299. {
  300. RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key);
  301. }
  302. }
  303. }
  304. foreach (var entity in _metaEntityViewsDB)
  305. {
  306. foreach (var entityView in entity.Value)
  307. {
  308. RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key);
  309. }
  310. }
  311. }
  312. }
  313. }