diff --git a/ECS/EngineEntityViewDB.cs b/ECS/EngineEntityViewDB.cs index 103275f..495073f 100644 --- a/ECS/EngineEntityViewDB.cs +++ b/ECS/EngineEntityViewDB.cs @@ -18,7 +18,7 @@ namespace Svelto.ECS _groupEntityViewsDB = groupEntityViewsDB; } - public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() + public FasterReadOnlyList QueryEntityViews() where T:EntityView, new() { var type = typeof(T); @@ -30,7 +30,7 @@ namespace Svelto.ECS return new FasterReadOnlyList((FasterList)entityViews); } - public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() + public FasterReadOnlyList QueryGroupedEntityViews(int @group) where T:EntityView, new() { Dictionary entityViews; @@ -128,17 +128,17 @@ namespace Svelto.ECS throw new Exception("EntityView Not Found"); } - public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() + public T QueryMetaEntityView(int metaEntityID) where T:EntityView, new() { return QueryEntityView(metaEntityID); } - public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() + public bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T:EntityView, new() { return TryQueryEntityView(metaEntityID, out entityView); } - public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() + public FasterReadOnlyList QueryMetaEntityViews() where T:EntityView, new() { var type = typeof(T); diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs deleted file mode 100644 index 5443753..0000000 --- a/ECS/EnginesRoot.cs +++ /dev/null @@ -1,665 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using Svelto.DataStructures; -using Svelto.ECS.Internal; -using Svelto.ECS.Schedulers; -using Svelto.Utilities; -using Svelto.WeakEvents; - -#if EXPERIMENTAL -using Svelto.ECS.Experimental; -using Svelto.ECS.Experimental.Internal; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR -using Svelto.ECS.Profiler; -#endif - -namespace Svelto.ECS -{ - public sealed class EnginesRoot : IDisposable - { - public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) - { - _entityViewEngines = new Dictionary>(); - _otherEngines = new FasterList(); - - _entityViewsDB = new Dictionary(); - _metaEntityViewsDB = new Dictionary(); - _groupEntityViewsDB = new Dictionary>(); - _entityViewsDBdic = new Dictionary(); - - _entityViewsToAdd = new DoubleBufferedEntityViews>(); - _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); - _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - _addEntityViewToEngine = AddEntityViewToEngine; - _removeEntityViewFromEngine = RemoveEntityViewFromEngine; -#endif - _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); - - _scheduler = entityViewScheduler; - _scheduler.Schedule(new WeakAction(SubmitEntityViews)); -#if EXPERIMENTAL - _sharedStructEntityViewLists = new SharedStructEntityViewLists(); - _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); - - _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); - _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); - - _implementedInterfaceTypes = new Dictionary(); -#endif -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); - debugEngineObject.gameObject.AddComponent(); -#endif - } - - public IEntityFactory GenerateEntityFactory() - { - return new GenericEntityFactory(new DataStructures.WeakReference(this)); - } - - public IEntityFunctions GenerateEntityFunctions() - { - return new GenericEntityFunctions(new DataStructures.WeakReference(this)); - } - - void BuildEntity(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() - { - EntityFactory.BuildEntityViews - (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); - } - - void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - EntityFactory.BuildEntityViews - (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); - } - - /// - /// A meta entity is a way to manage a set of entitites that are not easily - /// queriable otherwise. For example you may want to group existing entities - /// by size and type and then use the meta entity entityView to manage the data - /// shared among the single entities of the same type and size. This will - /// prevent the scenario where the coder is forced to parse all the entities to - /// find the ones of the same size and type. - /// Since the entities are managed through the shared entityView, the same - /// shared entityView must be found on the single entities of the same type and size. - /// The shared entityView of the meta entity is then used by engines that are meant - /// to manage a group of entities through a single entityView. - /// The same engine can manage several meta entities entityViews too. - /// The Engine manages the logic of the Meta EntityView data and other engines - /// can read back this data through the normal entity as the shared entityView - /// will be present in their descriptor too. - /// It's a way to control a group of Entities through a entityView only. - /// This set of entities can share exactly the same entityView reference if - /// built through this function. In this way, if you need to set a variable - /// on a group of entities, instead to inject N entityViews and iterate over - /// them to set the same value, you can inject just one entityView, set the value - /// and be sure that the value is shared between entities. - /// - /// - /// - /// - void BuildMetaEntity(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new() - { - EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, - EntityDescriptorTemplate.Default, implementors); - } - - /// - /// Using this function is like building a normal entity, but the entityViews - /// are grouped by groupID to be better processed inside engines and - /// improve cache locality. Only IGroupStructEntityViewWithID entityViews are grouped - /// other entityViews are managed as usual. - /// - /// - /// - /// - /// - void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new() - { - EntityFactory.BuildGroupedEntityViews(entityID, groupID, - _groupedEntityViewsToAdd.current, - EntityDescriptorTemplate.Default, - implementors); - } - - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - EntityFactory.BuildGroupedEntityViews(entityID, groupID, - _groupedEntityViewsToAdd.current, - entityDescriptor, implementors); - } - - void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) - { - var removeEntityImplementor = removeInfo as RemoveEntityImplementor; - - if (removeEntityImplementor.removeEntityInfo.isInAGroup) - InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, removeEntityImplementor.removeEntityInfo.groupID, _entityViewsDB); - else - InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB); - } - - void RemoveEntity(int entityID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB); - } - - void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); - } - - void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() - { - InternalRemove(EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); - } - - void Preallocate(int size) where T : IEntityDescriptor, new() - { - var entityViewsToBuild = EntityDescriptorTemplate.Default.descriptor.entityViewsToBuild; - int count = entityViewsToBuild.Length; - - for (int index = 0; index < count; index++) - { - var entityViewBuilder = entityViewsToBuild[index]; - var entityViewType = entityViewBuilder.GetEntityViewType(); - - ITypeSafeList dbList; - if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) - _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); - else - dbList.ReserveCapacity(size); - - if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) - _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); - else - dbList.ReserveCapacity(size); - } - } - - public void AddEngine(IEngine engine) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - Profiler.EngineProfiler.AddEngine(engine); -#endif - var engineType = engine.GetType(); -#if EXPERIMENTAL - bool engineAdded; - - var implementedInterfaces = engineType.GetInterfaces(); - - CollectImplementedInterfaces(implementedInterfaces); - - engineAdded = CheckSpecialEngine(engine); -#endif - var viewEngine = engine as IHandleEntityViewEngine; - - if (viewEngine != null) - CheckEntityViewsEngine(viewEngine, engineType); - else - _otherEngines.Add(engine); - - var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; - if (queryableEntityViewEngine != null) - { - queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; - queryableEntityViewEngine.Ready(); - } - } - -#if EXPERIMENTAL - void CollectImplementedInterfaces(Type[] implementedInterfaces) - { - _implementedInterfaceTypes.Clear(); - - var type = typeof(IHandleEntityViewEngine); - - for (int index = 0; index < implementedInterfaces.Length; index++) - { - var interfaceType = implementedInterfaces[index]; - - if (type.IsAssignableFrom(interfaceType) == false) - continue; - - if (false == interfaceType.IsGenericTypeEx()) - { - continue; - } - - var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); - - _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); - } - } - - bool CheckSpecialEngine(IEngine engine) - { - if (_implementedInterfaceTypes.Count == 0) return false; - - bool engineAdded = false; - - if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) - { - ((IStructEntityViewEngine)engine).CreateStructEntityViews - (_sharedStructEntityViewLists); - } - - if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) - { - ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews - (_sharedGroupedStructEntityViewLists); - } - - return engineAdded; - } -#endif - void CheckEntityViewsEngine(IEngine engine, Type engineType) - { - var baseType = engineType.GetBaseType(); - - if (baseType.IsGenericTypeEx()) - { - var genericArguments = baseType.GetGenericArguments(); - AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); -#if EXPERIMENTAL - var activableEngine = engine as IHandleActivableEntityEngine; - if (activableEngine != null) - AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); -#endif - - return; - } - - throw new Exception("Not Supported Engine"); - } - - static void AddEngine(T engine, Type[] types, - Dictionary> engines) - { - for (int i = 0; i < types.Length; i++) - { - FasterList list; - - var type = types[i]; - - if (engines.TryGetValue(type, out list) == false) - { - list = new FasterList(); - - engines.Add(type, list); - } - - list.Add(engine); - } - } - - void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, - Dictionary entityViewsDB) - { - foreach (var entityViewList in entityViewsToAdd) - { - AddEntityViewToDB(entityViewsDB, entityViewList); - - if (entityViewList.Value.isQueryiableEntityView) - { - AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); - } - } - - foreach (var entityViewList in entityViewsToAdd) - { - if (entityViewList.Value.isQueryiableEntityView) - { - AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, - entityViewList.Key); - } - } - } - - void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, - Dictionary> groupEntityViewsDB, - Dictionary entityViewsDB) - { - foreach (var group in groupedEntityViewsToAdd) - { - AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); - - AddEntityViewsToGroupDB(groupEntityViewsDB, @group); - } - } - - static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, - KeyValuePair> @group) - { - Dictionary groupedEntityViewsByType; - - if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) - groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); - - foreach (var entityView in @group.Value) - { - groupedEntityViewsByType.Add(entityView.Key, entityView.Value); - } - } - - static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) - { - ITypeSafeList dbList; - - if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) - dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); - - dbList.AddRange(entityViewList.Value); - } - - static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, - ITypeSafeList entityViews, Type entityViewType) - { - ITypeSafeDictionary entityViewsDic; - - if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) - entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); - - entityViewsDic.FillWithIndexedEntityViews(entityViews); - } - - static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) - { - FasterList enginesForEntityView; - - if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) - { - int viewsCount; - - var entityViews = entityViewsList.ToArrayFast(out viewsCount); - - for (int i = 0; i < viewsCount; i++) - { - int count; - var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); - IEntityView entityView = entityViews[i]; - for (int j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); -#else - fastList[j].Add(entityView); -#endif - } - } - } - } - - void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, - Dictionary entityViewsDB) - { - int entityViewBuildersCount = entityViewBuilders.Length; - - for (int i = 0; i < entityViewBuildersCount; i++) - { - Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - - ITypeSafeList entityViews = entityViewsDB[entityViewType]; - if (entityViews.UnorderedRemove(entityID) == false) - entityViewsDB.Remove(entityViewType); - - if (entityViews.isQueryiableEntityView) - { - var typeSafeDictionary = _entityViewsDBdic[entityViewType]; - var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); - - if (typeSafeDictionary.Remove(entityID) == false) - _entityViewsDBdic.Remove(entityViewType); - - RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); - } - } - } - - void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, - Dictionary entityViewsDB) - { - int entityViewBuildersCount = entityViewBuilders.Length; - - for (int i = 0; i < entityViewBuildersCount; i++) - { - Type entityViewType = entityViewBuilders[i].GetEntityViewType(); - Dictionary dictionary = _groupEntityViewsDB[groupID]; - - if (dictionary[entityViewType].UnorderedRemove(entityID) == false) - dictionary.Remove(entityViewType); - - if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); - } - - InternalRemove(entityViewBuilders, entityID, entityViewsDB); - } - - static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, - IEntityView entityView, Type entityViewType) - { - FasterList enginesForEntityView; - - if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) - { - int count; - var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); - - for (int j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); -#else - fastList[j].Remove(entityView); -#endif - } - } - } - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) - { - engine.Add(entityView); - } - - static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) - { - engine.Remove(entityView); - } -#endif - - void SubmitEntityViews() - { - bool newEntityViewsHaveBeenAddedWhileIterating = - _metaEntityViewsToAdd.current.Count > 0 - || _entityViewsToAdd.current.Count > 0 - || _groupedEntityViewsToAdd.current.Count > 0; - - int numberOfReenteringLoops = 0; - - while (newEntityViewsHaveBeenAddedWhileIterating) - { - //use other as source from now on - //current will be use to write new entityViews - _entityViewsToAdd.Swap(); - _metaEntityViewsToAdd.Swap(); - _groupedEntityViewsToAdd.Swap(); - - if ( _entityViewsToAdd.other.Count > 0) - AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); - - if ( _metaEntityViewsToAdd.other.Count > 0) - AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); - - if (_groupedEntityViewsToAdd.other.Count > 0) - AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); - - //other can be cleared now - _entityViewsToAdd.other.Clear(); - _metaEntityViewsToAdd.other.Clear(); - _groupedEntityViewsToAdd.other.Clear(); - - //has current new entityViews? - newEntityViewsHaveBeenAddedWhileIterating = - _metaEntityViewsToAdd.current.Count > 0 - || _entityViewsToAdd.current.Count > 0 - || _groupedEntityViewsToAdd.current.Count > 0; - - if (numberOfReenteringLoops > 5) - throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); - - numberOfReenteringLoops++; - } - } - - readonly Dictionary> _entityViewEngines; - - readonly FasterList _otherEngines; - - readonly Dictionary _entityViewsDB; - readonly Dictionary _metaEntityViewsDB; - readonly Dictionary> _groupEntityViewsDB; - - readonly Dictionary _entityViewsDBdic; - - readonly DoubleBufferedEntityViews> _entityViewsToAdd; - readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; - readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; - - readonly EntitySubmissionScheduler _scheduler; -#if EXPERIMENTAL - readonly Type _structEntityViewEngineType; - readonly Type _groupedStructEntityViewsEngineType; - - readonly SharedStructEntityViewLists _sharedStructEntityViewLists; - readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; - - readonly Dictionary _implementedInterfaceTypes; -#endif - -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - static Action _addEntityViewToEngine; - static Action _removeEntityViewFromEngine; -#endif - readonly EngineEntityViewDB _engineEntityViewDB; - - class DoubleBufferedEntityViews where T : class, IDictionary, new() - { - readonly T _entityViewsToAddBufferA = new T(); - readonly T _entityViewsToAddBufferB = new T(); - - public DoubleBufferedEntityViews() - { - this.other = _entityViewsToAddBufferA; - this.current = _entityViewsToAddBufferB; - } - - public T other { get; private set; } - public T current { get; private set; } - - public void Swap() - { - var toSwap = other; - other = current; - current = toSwap; - } - } - - class GenericEntityFactory : IEntityFactory - { - DataStructures.WeakReference _weakEngine; - - public GenericEntityFactory(DataStructures.WeakReference weakReference) - { - _weakEngine = weakReference; - } - - public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildEntity(entityID, implementors); - } - - public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); - } - - public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); - } - - public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() - { - _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); - } - - public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) - { - _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); - } - - public void Preallocate(int size) where T : IEntityDescriptor, new() - { - _weakEngine.Target.Preallocate(size); - } - } - - class GenericEntityFunctions : IEntityFunctions - { - public GenericEntityFunctions(DataStructures.WeakReference weakReference) - { - _weakReference = weakReference; - } - - public void RemoveEntity(int entityID, IRemoveEntityComponent entityTemplate) - { - _weakReference.Target.RemoveEntity(entityID, entityTemplate); - } - - public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(entityID); - } - - public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(metaEntityID); - } - - public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() - { - _weakReference.Target.RemoveEntity(entityID); - } - - readonly DataStructures.WeakReference _weakReference; - } - - public void Dispose() - { - foreach (var entity in _entityViewsDB) - { - if (entity.Value.isQueryiableEntityView == true) - { - foreach (var entityView in entity.Value) - { - RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); - } - } - } - - foreach (var entity in _metaEntityViewsDB) - { - foreach (var entityView in entity.Value) - { - RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); - } - } - } - } -} \ No newline at end of file diff --git a/ECS/EnginesRootEngines.cs b/ECS/EnginesRootEngines.cs new file mode 100644 index 0000000..fb47ffe --- /dev/null +++ b/ECS/EnginesRootEngines.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; +using Svelto.ECS.Schedulers; +using Svelto.Utilities; +using Svelto.WeakEvents; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot + /// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks + /// periodically if new entity must be submited to the database and the engines. It's an external + /// dependencies to be indipendent by the running platform as the user can define it. + /// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why + /// it must receive a weak reference of the EnginesRoot callback. + /// + public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) + { + _entityViewEngines = new Dictionary>(); + _otherEngines = new FasterList(); + + _entityViewsDB = new Dictionary(); + _metaEntityViewsDB = new Dictionary(); + _groupEntityViewsDB = new Dictionary>(); + _entityViewsDBdic = new Dictionary(); + + _entityViewsToAdd = new DoubleBufferedEntityViews>(); + _metaEntityViewsToAdd = new DoubleBufferedEntityViews>(); + _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); + + _engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); + + _scheduler = entityViewScheduler; + _scheduler.Schedule(new WeakAction(SubmitEntityViews)); +#if EXPERIMENTAL + _sharedStructEntityViewLists = new SharedStructEntityViewLists(); + _sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); + + _structEntityViewEngineType = typeof(IStructEntityViewEngine<>); + _groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); + + _implementedInterfaceTypes = new Dictionary(); +#endif +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + _addEntityViewToEngine = AddEntityViewToEngine; + _removeEntityViewFromEngine = RemoveEntityViewFromEngine; + + UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); + debugEngineObject.gameObject.AddComponent(); +#endif + } + + public void AddEngine(IEngine engine) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + Profiler.EngineProfiler.AddEngine(engine); +#endif + var engineType = engine.GetType(); +#if EXPERIMENTAL + bool engineAdded; + + var implementedInterfaces = engineType.GetInterfaces(); + + CollectImplementedInterfaces(implementedInterfaces); + + engineAdded = CheckSpecialEngine(engine); +#endif + var viewEngine = engine as IHandleEntityViewEngine; + + if (viewEngine != null) + CheckEntityViewsEngine(viewEngine, engineType); + else + _otherEngines.Add(engine); + + var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; + if (queryableEntityViewEngine != null) + { + queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; + queryableEntityViewEngine.Ready(); + } + } + +#if EXPERIMENTAL + void CollectImplementedInterfaces(Type[] implementedInterfaces) + { + _implementedInterfaceTypes.Clear(); + + var type = typeof(IHandleEntityViewEngine); + + for (int index = 0; index < implementedInterfaces.Length; index++) + { + var interfaceType = implementedInterfaces[index]; + + if (type.IsAssignableFrom(interfaceType) == false) + continue; + + if (false == interfaceType.IsGenericTypeEx()) + { + continue; + } + + var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); + + _implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); + } + } + + bool CheckSpecialEngine(IEngine engine) + { + if (_implementedInterfaceTypes.Count == 0) return false; + + bool engineAdded = false; + + if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) + { + ((IStructEntityViewEngine)engine).CreateStructEntityViews + (_sharedStructEntityViewLists); + } + + if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) + { + ((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews + (_sharedGroupedStructEntityViewLists); + } + + return engineAdded; + } +#endif + void CheckEntityViewsEngine(IEngine engine, Type engineType) + { + var baseType = engineType.GetBaseType(); + + if (baseType.IsGenericTypeEx()) + { + var genericArguments = baseType.GetGenericArguments(); + AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); +#if EXPERIMENTAL + var activableEngine = engine as IHandleActivableEntityEngine; + if (activableEngine != null) + AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); +#endif + + return; + } + + throw new Exception("Not Supported Engine"); + } + + //The T parameter allows to pass datastructure sthat not necessarly are + //defined with IEngine, but must be defined with IEngine implementations + static void AddEngine(T engine, Type[] types, + Dictionary> engines) where T:IEngine + { + for (int i = 0; i < types.Length; i++) + { + FasterList list; + + var type = types[i]; + + if (engines.TryGetValue(type, out list) == false) + { + list = new FasterList(); + + engines.Add(type, list); + } + + list.Add(engine); + } + } + + readonly Dictionary> _entityViewEngines; + + readonly FasterList _otherEngines; + + readonly Dictionary _entityViewsDB; + readonly Dictionary _metaEntityViewsDB; + readonly Dictionary> _groupEntityViewsDB; + + readonly Dictionary _entityViewsDBdic; + + readonly DoubleBufferedEntityViews> _entityViewsToAdd; + readonly DoubleBufferedEntityViews> _metaEntityViewsToAdd; + readonly DoubleBufferedEntityViews>> _groupedEntityViewsToAdd; + + readonly EntitySubmissionScheduler _scheduler; +#if EXPERIMENTAL + readonly Type _structEntityViewEngineType; + readonly Type _groupedStructEntityViewsEngineType; + + readonly SharedStructEntityViewLists _sharedStructEntityViewLists; + readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; + + readonly Dictionary _implementedInterfaceTypes; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static Action _addEntityViewToEngine; + static Action _removeEntityViewFromEngine; +#endif + readonly EngineEntityViewDB _engineEntityViewDB; + + class DoubleBufferedEntityViews where T : class, IDictionary, new() + { + readonly T _entityViewsToAddBufferA = new T(); + readonly T _entityViewsToAddBufferB = new T(); + + internal DoubleBufferedEntityViews() + { + this.other = _entityViewsToAddBufferA; + this.current = _entityViewsToAddBufferB; + } + + internal T other; + internal T current; + + internal void Swap() + { + var toSwap = other; + other = current; + current = toSwap; + } + } + } +} \ No newline at end of file diff --git a/ECS/EnginesRootEntities.cs b/ECS/EnginesRootEntities.cs new file mode 100644 index 0000000..7d258ab --- /dev/null +++ b/ECS/EnginesRootEntities.cs @@ -0,0 +1,337 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + /// + /// an EnginesRoot reference cannot be held by anything else than the Composition Root + /// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference + /// of the EnginesRoot to be passed around. + /// + /// + public IEntityFactory GenerateEntityFactory() + { + return new GenericEntityFactory(new DataStructures.WeakReference(this)); + } + + public IEntityFunctions GenerateEntityFunctions() + { + return new GenericEntityFunctions(new DataStructures.WeakReference(this)); + } + + /// + /// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity + /// itself in terms of EntityViews to build. The Implementors are passed to fill the + /// references of the EntityViews components. Please read the articles on my blog + /// to understand better the terminologies + /// + /// + /// + /// + void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, EntityDescriptorTemplate.Default, implementors); + } + + /// + /// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo + /// can be built in place of the generic parameter T. + /// + /// + /// + /// + void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildEntityViews + (entityID, _entityViewsToAdd.current, entityDescriptor, implementors); + } + + /// + /// A meta entity is a way to manage a set of entitites that are not easily + /// queriable otherwise. For example you may want to group existing entities + /// by size and type and then use the meta entity entityView to manage the data + /// shared among the single entities of the same type and size. This will + /// prevent the scenario where the coder is forced to parse all the entities to + /// find the ones of the same size and type. + /// Since the entities are managed through the shared entityView, the same + /// shared entityView must be found on the single entities of the same type and size. + /// The shared entityView of the meta entity is then used by engines that are meant + /// to manage a group of entities through a single entityView. + /// The same engine can manage several meta entities entityViews too. + /// The Engine manages the logic of the Meta EntityView data and other engines + /// can read back this data through the normal entity as the shared entityView + /// will be present in their descriptor too. + /// It's a way to control a group of Entities through a entityView only. + /// This set of entities can share exactly the same entityView reference if + /// built through this function. In this way, if you need to set a variable + /// on a group of entities, instead to inject N entityViews and iterate over + /// them to set the same value, you can inject just one entityView, set the value + /// and be sure that the value is shared between entities. + /// + /// + /// + /// + void BuildMetaEntity(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() + { + EntityFactory.BuildEntityViews(metaEntityID, _entityViewsToAdd.current, + EntityDescriptorTemplate.Default, implementors); + } + + /// + /// Using this function is like building a normal entity, but the entityViews + /// are grouped by groupID to be more efficently processed inside engines and + /// improve cache locality. Either class entityViews and struct entityViews can be + /// grouped. + /// + /// + /// + /// + /// + void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + EntityDescriptorTemplate.Default, + implementors); + } + + void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + EntityFactory.BuildGroupedEntityViews(entityID, groupID, + _groupedEntityViewsToAdd.current, + entityDescriptor, implementors); + } + + void Preallocate(int size) where T : IEntityDescriptor, new() + { + var entityViewsToBuild = EntityDescriptorTemplate.Default.entityViewsToBuild; + int count = entityViewsToBuild.Length; + + for (int index = 0; index < count; index++) + { + var entityViewBuilder = entityViewsToBuild[index]; + var entityViewType = entityViewBuilder.GetEntityViewType(); + + ITypeSafeList dbList; + if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) + _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + + if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) + _entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + else + dbList.ReserveCapacity(size); + } + } + + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + var removeEntityImplementor = removeInfo as RemoveEntityImplementor; + + if (removeEntityImplementor.isInAGroup) + InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); + else + InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _entityViewsDB); + } + + void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); + } + + void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + InternalRemove(EntityDescriptorTemplate.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); + } + + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + + ITypeSafeList entityViews = entityViewsDB[entityViewType]; + if (entityViews.UnorderedRemove(entityID) == false) + entityViewsDB.Remove(entityViewType); + + if (entityViews.isQueryiableEntityView) + { + var typeSafeDictionary = _entityViewsDBdic[entityViewType]; + var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); + + if (typeSafeDictionary.Remove(entityID) == false) + _entityViewsDBdic.Remove(entityViewType); + + RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); + } + } + } + + void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, + Dictionary entityViewsDB) + { + int entityViewBuildersCount = entityViewBuilders.Length; + + for (int i = 0; i < entityViewBuildersCount; i++) + { + Type entityViewType = entityViewBuilders[i].GetEntityViewType(); + Dictionary dictionary = _groupEntityViewsDB[groupID]; + + if (dictionary[entityViewType].UnorderedRemove(entityID) == false) + dictionary.Remove(entityViewType); + + if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); + } + + InternalRemove(entityViewBuilders, entityID, entityViewsDB); + } + + static void RemoveEntityViewFromEngines(Dictionary> entityViewEngines, + IEntityView entityView, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + + for (int j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); +#else + fastList[j].Remove(entityView); +#endif + } + } + } + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) + { + engine.Add(entityView); + } + + static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) + { + engine.Remove(entityView); + } +#endif + + class GenericEntityFactory : IEntityFactory + { + DataStructures.WeakReference _weakEngine; + + public GenericEntityFactory(DataStructures.WeakReference weakReference) + { + _weakEngine = weakReference; + } + + public void BuildEntity(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntity(entityID, implementors); + } + + public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); + } + + public void BuildMetaEntity(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildMetaEntity(metaEntityID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, implementors); + } + + public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) + { + _weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); + } + + public void Preallocate(int size) where T : IEntityDescriptor, new() + { + _weakEngine.Target.Preallocate(size); + } + } + + class GenericEntityFunctions : IEntityFunctions + { + public GenericEntityFunctions(DataStructures.WeakReference weakReference) + { + _weakReference = weakReference; + } + + public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) + { + _weakReference.Target.RemoveEntity(entityID, removeInfo); + } + + public void RemoveEntity(int entityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + public void RemoveMetaEntity(int metaEntityID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(metaEntityID); + } + + public void RemoveEntityFromGroup(int entityID, int groupID) where T : IEntityDescriptor, new() + { + _weakReference.Target.RemoveEntity(entityID); + } + + readonly DataStructures.WeakReference _weakReference; + } + + public void Dispose() + { + foreach (var entity in _entityViewsDB) + { + if (entity.Value.isQueryiableEntityView == true) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + + foreach (var entity in _metaEntityViewsDB) + { + foreach (var entityView in entity.Value) + { + RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); + } + } + } + } +} \ No newline at end of file diff --git a/ECS/EnginesRootSubmission.cs b/ECS/EnginesRootSubmission.cs new file mode 100644 index 0000000..c0c7641 --- /dev/null +++ b/ECS/EnginesRootSubmission.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using Svelto.DataStructures; +using Svelto.ECS.Internal; + +#if EXPERIMENTAL +using Svelto.ECS.Experimental; +using Svelto.ECS.Experimental.Internal; +#endif + +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +using Svelto.ECS.Profiler; +#endif + +namespace Svelto.ECS +{ + public partial class EnginesRoot : IDisposable + { + void SubmitEntityViews() + { + bool newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; + + int numberOfReenteringLoops = 0; + + while (newEntityViewsHaveBeenAddedWhileIterating) + { + //use other as source from now on + //current will be use to write new entityViews + _entityViewsToAdd.Swap(); + _metaEntityViewsToAdd.Swap(); + _groupedEntityViewsToAdd.Swap(); + + if (_entityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); + + if (_metaEntityViewsToAdd.other.Count > 0) + AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); + + if (_groupedEntityViewsToAdd.other.Count > 0) + AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); + + //other can be cleared now + _entityViewsToAdd.other.Clear(); + _metaEntityViewsToAdd.other.Clear(); + _groupedEntityViewsToAdd.other.Clear(); + + //has current new entityViews? + newEntityViewsHaveBeenAddedWhileIterating = + _metaEntityViewsToAdd.current.Count > 0 + || _entityViewsToAdd.current.Count > 0 + || _groupedEntityViewsToAdd.current.Count > 0; + + if (numberOfReenteringLoops > 5) + throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); + + numberOfReenteringLoops++; + } + } + + void AddEntityViewsToTheDBAndSuitableEngines(Dictionary entityViewsToAdd, + Dictionary entityViewsDB) + { + foreach (var entityViewList in entityViewsToAdd) + { + AddEntityViewToDB(entityViewsDB, entityViewList); + + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); + } + } + + foreach (var entityViewList in entityViewsToAdd) + { + if (entityViewList.Value.isQueryiableEntityView) + { + AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, + entityViewList.Key); + } + } + } + + void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary> groupedEntityViewsToAdd, + Dictionary> groupEntityViewsDB, + Dictionary entityViewsDB) + { + foreach (var group in groupedEntityViewsToAdd) + { + AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); + + AddEntityViewsToGroupDB(groupEntityViewsDB, @group); + } + } + + static void AddEntityViewsToGroupDB(Dictionary> groupEntityViewsDB, + KeyValuePair> @group) + { + Dictionary groupedEntityViewsByType; + + if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) + groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary(); + + foreach (var entityView in @group.Value) + { + groupedEntityViewsByType.Add(entityView.Key, entityView.Value); + } + } + + static void AddEntityViewToDB(Dictionary entityViewsDB, KeyValuePair entityViewList) + { + ITypeSafeList dbList; + + if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) + dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); + + dbList.AddRange(entityViewList.Value); + } + + static void AddEntityViewToEntityViewsDictionary(Dictionary entityViewsDBdic, + ITypeSafeList entityViews, Type entityViewType) + { + ITypeSafeDictionary entityViewsDic; + + if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) + entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); + + entityViewsDic.FillWithIndexedEntityViews(entityViews); + } + + static void AddEntityViewToTheSuitableEngines(Dictionary> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) + { + FasterList enginesForEntityView; + + if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) + { + int viewsCount; + + var entityViews = entityViewsList.ToArrayFast(out viewsCount); + + for (int i = 0; i < viewsCount; i++) + { + int count; + var fastList = FasterList.NoVirt.ToArrayFast(enginesForEntityView, out count); + IEntityView entityView = entityViews[i]; + for (int j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); +#else + fastList[j].Add(entityView); +#endif + } + } + } + } + } +} \ No newline at end of file diff --git a/ECS/EntityDescriptorTemplate.cs b/ECS/EntityDescriptorTemplate.cs index 3c20589..d917577 100644 --- a/ECS/EntityDescriptorTemplate.cs +++ b/ECS/EntityDescriptorTemplate.cs @@ -1,3 +1,5 @@ +using Svelto.DataStructures; +using Svelto.ECS.Internal; using System; using System.Collections.Generic; @@ -8,20 +10,22 @@ namespace Svelto.ECS IEntityViewBuilder[] entityViewsToBuild { get; } } - static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + internal static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() { public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); } public class EntityDescriptorInfo { - public readonly IEntityDescriptor descriptor; - public readonly string name; + readonly internal IEntityViewBuilder[] entityViewsToBuild; + readonly internal RemoveEntityImplementor removeEntityImplementor; + internal readonly string name; - public EntityDescriptorInfo(IEntityDescriptor entityDescriptor) + internal EntityDescriptorInfo(IEntityDescriptor descriptor) { - descriptor = entityDescriptor; name = descriptor.ToString(); + entityViewsToBuild = descriptor.entityViewsToBuild; + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); } } } @@ -31,11 +35,11 @@ namespace Svelto.ECS.Internal static class EntityFactory { internal static void BuildGroupedEntityViews(int entityID, int groupID, - Dictionary> groupEntityViewsByType, + Dictionary> groupEntityViewsByType, EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) { - var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; int count = entityViewsToBuild.Length; RemoveEntityImplementor removeEntityImplementor = null; @@ -53,6 +57,8 @@ namespace Svelto.ECS.Internal groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); } + //only class EntityView will be returned + //struct EntityView cannot be filled so it will be null. var entityViewObjectToFill = BuildEntityView(entityID, groupedEntityViewsTyped, entityViewType, entityViewBuilder); @@ -62,7 +68,7 @@ namespace Svelto.ECS.Internal if (entityViewObjectToFill != null) { if (removeEntityImplementor == null) - removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor, groupID); + removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, entityViewsToBuildDescriptor.name); @@ -70,20 +76,21 @@ namespace Svelto.ECS.Internal } } - internal static void BuildEntityViews(int entityID, Dictionary entityViewsByType, + internal static void BuildEntityViews(int entityID, + Dictionary entityViewsByType, EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) { - var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; + var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; int count = entityViewsToBuild.Length; - RemoveEntityImplementor removeEntityImplementor = null; - for (int index = 0; index < count; index++) { var entityViewBuilder = entityViewsToBuild[index]; var entityViewType = entityViewBuilder.GetEntityViewType(); + //only class EntityView will be returned + //struct EntityView cannot be filled so it will be null. var entityViewObjectToFill = BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); @@ -92,23 +99,26 @@ namespace Svelto.ECS.Internal //it's a EntityView if (entityViewObjectToFill != null) { - if (removeEntityImplementor == null) - removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor); - - FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, + FillEntityView(entityViewObjectToFill as EntityView, implementors, entityViewsToBuildDescriptor.removeEntityImplementor, entityViewsToBuildDescriptor.name); } } } static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, - Type entityViewType, IEntityViewBuilder entityViewBuilderId) + Type entityViewType, IEntityViewBuilder entityViewBuilder) { ITypeSafeList entityViewsList; var entityViewsPoolWillBeCreated = entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; - var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViewsList, entityID); + + IEntityView entityViewObjectToFill; + + //passing the undefined entityViewsByType inside the entityViewBuilder will allow + //it to be created with the correct type and casted back to the undefined list. + //that's how the list will be eventually of the target type. + entityViewBuilder.BuildEntityViewAndAddToList(ref entityViewsList, entityID, out entityViewObjectToFill); if (entityViewsPoolWillBeCreated) entityViewsByType.Add(entityViewType, entityViewsList); @@ -116,6 +126,13 @@ namespace Svelto.ECS.Internal return entityViewObjectToFill as IEntityView; } + //this is used to avoid newing a dictionary every time, but it's used locally only and it's clearead for each use +#if DEBUG && !PROFILER + static readonly Dictionary> implementorsByType = new Dictionary>(); +#else + static readonly Dictionary implementorsByType = new Dictionary(); +#endif + static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, string entityDescriptorName) { @@ -136,12 +153,16 @@ namespace Svelto.ECS.Internal var componentType = interfaces[iindex]; #if DEBUG && !PROFILER Tuple implementorHolder; + if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) implementorHolder.item2++; else + implementorsByType[componentType] = new Tuple(implementor, 1); +#else + implementorsByType[componentType] = implementor; #endif - implementorsByType[componentType] = new Tuple(implementor, 0); + } } #if DEBUG && !PROFILER @@ -153,8 +174,8 @@ namespace Svelto.ECS.Internal int count; //Very efficent way to collect the fields of every EntityViewType - KeyValuePair>[] setters = - entityView.EntityViewBlazingFastReflection(out count); + KeyValuePair>[] setters = + FasterList>>.NoVirt.ToArrayFast(entityView.EntityViewBlazingFastReflection, out count); var removeEntityComponentType = typeof(IRemoveEntityComponent); @@ -211,13 +232,7 @@ namespace Svelto.ECS.Internal item2 = v; } } -#endif - //this is used to avoid newing a dictionary every time, but it's used locally only -#if DEBUG && !PROFILER - static readonly Dictionary> implementorsByType = new Dictionary>(); -#else - static readonly Dictionary implementorsByType = new Dictionary(); -#endif +#endif static Dictionary _cachedTypes = new Dictionary(); const string DUPLICATE_IMPLEMENTOR_ERROR = diff --git a/ECS/EntityView.cs b/ECS/EntityView.cs index 445781c..5891198 100644 --- a/ECS/EntityView.cs +++ b/ECS/EntityView.cs @@ -20,19 +20,17 @@ namespace Svelto.ECS { public int ID { get { return _ID; } } - abstract internal KeyValuePair>[] - EntityViewBlazingFastReflection(out int count); - - protected int _ID; + internal FasterList>> EntityViewBlazingFastReflection; + internal int _ID; } - public class EntityView: EntityView where T: EntityView + internal static class EntityView where T: EntityView, new() { - internal static TEntityViewType BuildEntityView(int ID) where TEntityViewType: EntityView, new() + internal static T BuildEntityView(int ID) { - if (FieldCache.list.Count == 0) + if (FieldCache.list.Count == 0) { - var type = typeof(TEntityViewType); + var type = typeof(T); var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); @@ -43,26 +41,15 @@ namespace Svelto.ECS Action setter = FastInvoke.MakeSetter(field); - FieldCache.Add(new KeyValuePair>(field.FieldType, setter)); + FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); } } - return new TEntityViewType { _ID = ID }; - } - - override internal KeyValuePair>[] - EntityViewBlazingFastReflection(out int count) - { - return FasterList>>.NoVirt.ToArrayFast(FieldCache.list, out count); + return new T { _ID = ID, EntityViewBlazingFastReflection = FieldCache.list }; } - static class FieldCache + static class FieldCache where W:T { - internal static void Add(KeyValuePair> setter) - { - list.Add(setter); - } - internal static readonly FasterList>> list = new FasterList>>(); } } diff --git a/ECS/EntityViewBuilder.cs b/ECS/EntityViewBuilder.cs index 48ce2dd..6b02a66 100644 --- a/ECS/EntityViewBuilder.cs +++ b/ECS/EntityViewBuilder.cs @@ -5,26 +5,26 @@ namespace Svelto.ECS { public interface IEntityViewBuilder { - IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID); + void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); ITypeSafeList Preallocate(ref ITypeSafeList list, int size); Type GetEntityViewType(); } - public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() + public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() { - public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) { if (list == null) list = new TypeSafeFasterListForECSForClasses(); var castedList = list as TypeSafeFasterListForECSForClasses; - var entityView = EntityView.BuildEntityView(entityID); + var lentityView = EntityView.BuildEntityView(entityID); - castedList.Add(entityView); + castedList.Add(lentityView); - return entityView; + entityView = lentityView; } public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) @@ -47,19 +47,19 @@ namespace Svelto.ECS public class EntityStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct { - public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) { - var entityView = default(EntityViewType); - entityView.ID = entityID; + var lentityView = default(EntityViewType); + lentityView.ID = entityID; if (list == null) list = new TypeSafeFasterListForECSForStructs(); var castedList = list as TypeSafeFasterListForECSForStructs; - castedList.Add(entityView); + castedList.Add(lentityView); - return null; + entityView = null; } public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) diff --git a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs index 8a6c173..a2dcf89 100644 --- a/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs +++ b/ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs @@ -13,7 +13,7 @@ namespace Svelto.ECS.Schedulers //the entityViews immediatly just because convenient for your game //logic. This is not how it works. - public class UnitySumbmissionEntityViewScheduler : EntityViewSubmissionScheduler + public class UnitySumbmissionEntityViewScheduler : EntitySubmissionScheduler { public UnitySumbmissionEntityViewScheduler() { diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs index da643e9..a717870 100644 --- a/ECS/GenericEntityDescriptor.cs +++ b/ECS/GenericEntityDescriptor.cs @@ -2,7 +2,7 @@ namespace Svelto.ECS { - public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() + public class GenericEntityDescriptor:IEntityDescriptor where T : EntityView, new() { static GenericEntityDescriptor() { @@ -18,8 +18,8 @@ namespace Svelto.ECS } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() { static GenericEntityDescriptor() { @@ -34,9 +34,9 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { static GenericEntityDescriptor() { @@ -51,10 +51,10 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - where W : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() { static GenericEntityDescriptor() { @@ -69,11 +69,11 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - where W : EntityView, new() - where X : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() { static GenericEntityDescriptor() { @@ -88,12 +88,12 @@ namespace Svelto.ECS public static readonly IEntityViewBuilder[] entityViewBuilders; } - public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() - where W : EntityView, new() - where X : EntityView, new() - where Y : EntityView, new() + public class GenericEntityDescriptor : IEntityDescriptor where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() + where W : EntityView, new() + where X : EntityView, new() + where Y : EntityView, new() { static GenericEntityDescriptor() { diff --git a/ECS/IEngineEntityViewDB.cs b/ECS/IEngineEntityViewDB.cs index ddbf011..571f3f8 100644 --- a/ECS/IEngineEntityViewDB.cs +++ b/ECS/IEngineEntityViewDB.cs @@ -4,9 +4,9 @@ namespace Svelto.ECS { public interface IEngineEntityViewDB { - FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); - FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); - FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); + FasterReadOnlyList QueryEntityViews() where T:EntityView, new(); + FasterReadOnlyList QueryMetaEntityViews() where T: EntityView, new(); + FasterReadOnlyList QueryGroupedEntityViews(int group) where T: EntityView, new(); T[] QueryEntityViewsAsArray(out int count) where T: IEntityView; T[] QueryGroupedEntityViewsAsArray(int @group, out int count) where T: IEntityView; @@ -15,8 +15,8 @@ namespace Svelto.ECS bool TryQueryEntityView(int ID, out T entityView) where T : IEntityView; T QueryEntityView(int ID) where T: IEntityView; - bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); - T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); + bool TryQueryMetaEntityView(int metaEntityID, out T entityView) where T: EntityView, new(); + T QueryMetaEntityView(int metaEntityID) where T: EntityView, new(); } } diff --git a/ECS/IEnginesInterfaces.cs b/ECS/IEnginesInterfaces.cs index 6c8945c..1929ca9 100644 --- a/ECS/IEnginesInterfaces.cs +++ b/ECS/IEnginesInterfaces.cs @@ -15,7 +15,7 @@ namespace Svelto.ECS public interface IEntityFunctions { - void RemoveEntity(int entityID, IRemoveEntityComponent template); + void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); void RemoveEntity(int entityID) where T:IEntityDescriptor, new(); diff --git a/ECS/MultiEntityViewsEngine.cs b/ECS/MultiEntityViewsEngine.cs index 2ba4856..895a48b 100644 --- a/ECS/MultiEntityViewsEngine.cs +++ b/ECS/MultiEntityViewsEngine.cs @@ -2,7 +2,7 @@ using Svelto.ECS.Internal; namespace Svelto.ECS.Internal { - public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() + public abstract class MultiEntityViewsEngine:IHandleEntityViewEngine where T:EntityView, new() { protected abstract void Add(T entityView); protected abstract void Remove(T entityView); @@ -22,8 +22,8 @@ namespace Svelto.ECS.Internal namespace Svelto.ECS { public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine - where T:EntityView, new() - where U:EntityView, new() + where T:EntityView, new() + where U:EntityView, new() { protected abstract void Add(U entityView); protected abstract void Remove(U entityView); @@ -55,9 +55,9 @@ namespace Svelto.ECS } public abstract class MultiEntityViewsEngine : MultiEntityViewsEngine - where T : EntityView, new() - where U : EntityView, new() - where V : EntityView, new() + where T : EntityView, new() + where U : EntityView, new() + where V : EntityView, new() { protected abstract void Add(V entityView); protected abstract void Remove(V entityView); diff --git a/ECS/RemoveEntityImplementor.cs b/ECS/RemoveEntityImplementor.cs index 30f74c5..7bd03b3 100644 --- a/ECS/RemoveEntityImplementor.cs +++ b/ECS/RemoveEntityImplementor.cs @@ -2,17 +2,20 @@ { sealed class RemoveEntityImplementor : IRemoveEntityComponent { - public RemoveEntityImplementor(IEntityDescriptor descriptor, int groupID) : this(descriptor) + public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) { - removeEntityInfo = new RemoveEntityInfo(descriptor, groupID); + this.groupID = groupID; + isInAGroup = true; } - internal RemoveEntityImplementor(IEntityDescriptor descriptor) + internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) { - removeEntityInfo = new RemoveEntityInfo(descriptor); + removeEntityInfo = new RemoveEntityInfo(entityViews); } - internal RemoveEntityInfo removeEntityInfo; + readonly internal RemoveEntityInfo removeEntityInfo; + readonly internal int groupID; + readonly internal bool isInAGroup; } } @@ -23,20 +26,11 @@ namespace Svelto.ECS public struct RemoveEntityInfo { - readonly public IEntityDescriptor descriptor; - readonly public int groupID; - readonly public bool isInAGroup; - - public RemoveEntityInfo(IEntityDescriptor descriptor) : this() - { - this.descriptor = descriptor; - } - - public RemoveEntityInfo(IEntityDescriptor descriptor, int groupID) + readonly internal IEntityViewBuilder[] entityViewsToBuild; + + public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() { - this.descriptor = descriptor; - this.groupID = groupID; - isInAGroup = true; + this.entityViewsToBuild = entityViews; } } } diff --git a/ECS/SingleEntityViewEngine.cs b/ECS/SingleEntityViewEngine.cs index a3ac1ad..605f775 100644 --- a/ECS/SingleEntityViewEngine.cs +++ b/ECS/SingleEntityViewEngine.cs @@ -2,7 +2,7 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() + public abstract class SingleEntityViewEngine : IHandleEntityViewEngine where T:EntityView, new() { public void Add(IEntityView entityView) {