From 36cae3be95fc01450799fad9938d6c7d448aa6a7 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Fri, 30 Mar 2018 23:29:48 +0100 Subject: [PATCH] refactoring complete (minus some improvements) - introduced the concept of global ID, as a combination of groupID and entityID - only 256 groups and 2^24 entities can be created - all the entities are now built always in group, when the group is not specified, the "standard" groups is used - the groupID can be retrieved from the EGID - --- EnginesRoot.GenericEntityFunctions.cs | 5 + .../DataStructures/TypeSafeDictionary.cs | 65 +++++- .../TypeSafeDictionaryException.cs | 2 +- .../TypeSafeFasterListForECS.cs | 62 ++++-- .../TypeSafeFasterListForECSException.cs | 10 + Svelto.ECS/EGID.cs | 38 ++++ Svelto.ECS/EnginesRootEngines.cs | 6 +- Svelto.ECS/EnginesRootEntities.cs | 190 ++++++++++-------- Svelto.ECS/EnginesRootSubmission.cs | 19 +- Svelto.ECS/EntityFactory.cs | 50 +++-- Svelto.ECS/EntityInfoView.cs | 5 +- Svelto.ECS/EntityView.cs | 12 +- Svelto.ECS/EntityViewBuilder.cs | 20 +- Svelto.ECS/EntityViewsDB.cs | 85 +++++--- Svelto.ECS/ExclusiveGroups.cs | 2 +- Svelto.ECS/IEntityFactory.cs | 2 +- Svelto.ECS/IEntityFunctions.cs | 1 + Svelto.ECS/IEntityViewsDB.cs | 4 +- 18 files changed, 374 insertions(+), 204 deletions(-) create mode 100644 Svelto.ECS/DataStructures/TypeSafeFasterListForECSException.cs create mode 100644 Svelto.ECS/EGID.cs diff --git a/EnginesRoot.GenericEntityFunctions.cs b/EnginesRoot.GenericEntityFunctions.cs index de14160..1d3b1cf 100644 --- a/EnginesRoot.GenericEntityFunctions.cs +++ b/EnginesRoot.GenericEntityFunctions.cs @@ -27,6 +27,11 @@ namespace Svelto.ECS _weakReference.Target.RemoveEntity(entityID, groupID); } + public void RemoveEntity(EGID entityEGID) + { + _weakReference.Target.RemoveEntity(entityEGID); + } + public void RemoveGroupAndEntities(int groupID) { _weakReference.Target.RemoveGroupAndEntitiesFromDB(groupID); diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs index d1e7dcc..164017e 100644 --- a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs +++ b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs @@ -14,11 +14,12 @@ namespace Svelto.ECS.Internal public interface ITypeSafeDictionary { void FillWithIndexedEntityViews(ITypeSafeList entityViews); - bool Remove(int entityId); - IEntityView GetIndexedEntityView(int entityID); + bool Remove(EGID entityId); + IEntityView GetIndexedEntityView(EGID entityID); + bool isQueryiableEntityView { get; } } - class TypeSafeDictionary : Dictionary, ITypeSafeDictionary where TValue : IEntityView + class TypeSafeDictionaryForClass : Dictionary, ITypeSafeDictionary where TValue : EntityView { internal static readonly ReadOnlyDictionary Default = new ReadOnlyDictionary(new Dictionary()); @@ -34,7 +35,7 @@ namespace Svelto.ECS.Internal { var entityView = buffer[i]; - Add(entityView.ID, entityView); + Add(entityView._ID.GID, entityView); } } catch (Exception e) @@ -43,16 +44,64 @@ namespace Svelto.ECS.Internal } } - public new bool Remove(int entityId) + public bool Remove(EGID entityId) { - base.Remove(entityId); + base.Remove(entityId.GID); return Count > 0; } - public IEntityView GetIndexedEntityView(int entityID) + public IEntityView GetIndexedEntityView(EGID entityID) { - return this[entityID]; + return this[entityID.GID]; + } + + public bool isQueryiableEntityView + { + get { return true; } + } + } + + class TypeSafeDictionaryForStruct : Dictionary, ITypeSafeDictionary where TValue : struct, IEntityStruct + { + internal static readonly ReadOnlyDictionary Default = + new ReadOnlyDictionary(new Dictionary()); + + public void FillWithIndexedEntityViews(ITypeSafeList entityViews) + { + int count; + var buffer = FasterList.NoVirt.ToArrayFast((FasterList) entityViews, out count); + + try + { + for (var i = 0; i < count; i++) + { + var entityView = buffer[i]; + + Add(entityView.ID.GID, entityView); + } + } + catch (Exception e) + { + throw new TypeSafeDictionaryException(e); + } + } + + public bool Remove(EGID entityId) + { + base.Remove(entityId.GID); + + return Count > 0; + } + + public IEntityView GetIndexedEntityView(EGID entityID) + { + return this[entityID.GID]; + } + + public bool isQueryiableEntityView + { + get { return false; } } } } \ No newline at end of file diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs b/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs index 4f2a321..5504e00 100644 --- a/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs +++ b/Svelto.ECS/DataStructures/TypeSafeDictionaryException.cs @@ -4,7 +4,7 @@ namespace Svelto.ECS { public class TypeSafeDictionaryException : Exception { - public TypeSafeDictionaryException(Exception exception) : base(exception.Message, exception) + public TypeSafeDictionaryException(Exception exception) : base("trying to add an EntityView with the same ID more than once", exception) { } } diff --git a/Svelto.ECS/DataStructures/TypeSafeFasterListForECS.cs b/Svelto.ECS/DataStructures/TypeSafeFasterListForECS.cs index e6603c4..929b567 100644 --- a/Svelto.ECS/DataStructures/TypeSafeFasterListForECS.cs +++ b/Svelto.ECS/DataStructures/TypeSafeFasterListForECS.cs @@ -12,7 +12,7 @@ namespace Svelto.ECS.Internal void AddRange(ITypeSafeList entityViewListValue); ITypeSafeList Create(); - bool MappedRemove(int entityID); + bool MappedRemove(EGID entityID); ITypeSafeDictionary CreateIndexedDictionary(); IEntityView[] ToArrayFast(out int count); void AddCapacity(int capacity); @@ -32,17 +32,26 @@ namespace Svelto.ECS.Internal _mappedIndices = new Dictionary(); } - public bool MappedRemove(int entityID) + public bool MappedRemove(EGID entityID) { - var index = _mappedIndices[entityID]; + var index = _mappedIndices[entityID.GID]; - Check.Assert(entityID == this[index].ID, + Check.Assert(entityID.GID == this[index].ID.GID, "Something went wrong with the Svelto.ECS code, please contact the author"); - _mappedIndices.Remove(entityID); + _mappedIndices.Remove(entityID.GID); if (UnorderedRemoveAt(index)) - _mappedIndices[this[index].ID] = index; + { + try + { + _mappedIndices.Add(this[index].ID.GID, index); + } + catch (Exception e) + { + throw new TypeSafeFasterListForECSException(e); + } + } return Count > 0; } @@ -53,8 +62,18 @@ namespace Svelto.ECS.Internal base.AddRange(entityViewListValue as FasterList); + for (var i = index; i < Count; ++i) - _mappedIndices[this[i].ID] = i; + { + try + { + _mappedIndices.Add(this[i].ID.GID, i); + } + catch (Exception e) + { + throw new TypeSafeFasterListForECSException(e); + } + } } public new void Add(T entityView) @@ -63,7 +82,14 @@ namespace Svelto.ECS.Internal base.Add(entityView); - _mappedIndices[entityView.ID] = index; + try + { + _mappedIndices.Add(entityView.ID.GID, index); + } + catch (Exception e) + { + throw new TypeSafeFasterListForECSException(e); + } } public void AddCapacity(int capacity) @@ -72,9 +98,9 @@ namespace Svelto.ECS.Internal Resize(Count + capacity); } - public int GetIndexFromID(int entityID) + public int GetIndexFromID(EGID entityID) { - return _mappedIndices[entityID]; + return _mappedIndices[entityID.GID]; } } @@ -82,12 +108,10 @@ namespace Svelto.ECS.Internal where T : struct, IEntityStruct { public TypeSafeFasterListForECSForStructs(int size) : base(size) - { - } + {} public TypeSafeFasterListForECSForStructs() - { - } + {} public ITypeSafeList Create() { @@ -101,7 +125,7 @@ namespace Svelto.ECS.Internal public ITypeSafeDictionary CreateIndexedDictionary() { - throw new Exception("Not Allowed"); + return new TypeSafeDictionaryForStruct(); } public IEntityView[] ToArrayFast(out int count) @@ -118,12 +142,10 @@ namespace Svelto.ECS.Internal class TypeSafeFasterListForECSForClasses : TypeSafeFasterListForECS, ITypeSafeList where T : EntityView, new() { public TypeSafeFasterListForECSForClasses(int size) : base(size) - { - } + {} public TypeSafeFasterListForECSForClasses() - { - } + {} public ITypeSafeList Create() { @@ -137,7 +159,7 @@ namespace Svelto.ECS.Internal public ITypeSafeDictionary CreateIndexedDictionary() { - return new TypeSafeDictionary(); + return new TypeSafeDictionaryForClass(); } public IEntityView[] ToArrayFast(out int count) diff --git a/Svelto.ECS/DataStructures/TypeSafeFasterListForECSException.cs b/Svelto.ECS/DataStructures/TypeSafeFasterListForECSException.cs new file mode 100644 index 0000000..038eaa2 --- /dev/null +++ b/Svelto.ECS/DataStructures/TypeSafeFasterListForECSException.cs @@ -0,0 +1,10 @@ +using System; + +namespace Svelto.ECS +{ + public class TypeSafeFasterListForECSException : Exception + { + public TypeSafeFasterListForECSException(Exception exception):base("Trying to add an Entity View with the same ID more than once", exception) + {} + } +} \ No newline at end of file diff --git a/Svelto.ECS/EGID.cs b/Svelto.ECS/EGID.cs new file mode 100644 index 0000000..e17367a --- /dev/null +++ b/Svelto.ECS/EGID.cs @@ -0,0 +1,38 @@ +using DBC; + +namespace Svelto.ECS +{ + public struct EGID + { + int _GID; + + public int GID + { + get { return _GID; } + } + + public int ID + { + get { return _GID & 0xFFFFFF; } + } + + public int group + { + get { return (int) ((_GID & 0xFF000000) >> 24); } + } + + public EGID(int entityID, int groupID) : this() + { + _GID = MAKE_GLOBAL_ID(entityID, groupID); + } + + int MAKE_GLOBAL_ID(int entityId, int groupId) + { +#if DEBUG && !PROFILER + Check.Require(entityId <= 0xFFFFFF); + Check.Require(groupId <= 0xFF); +#endif + return entityId | groupId << 24; + } + } +} \ No newline at end of file diff --git a/Svelto.ECS/EnginesRootEngines.cs b/Svelto.ECS/EnginesRootEngines.cs index a7782b1..d16b3ac 100644 --- a/Svelto.ECS/EnginesRootEngines.cs +++ b/Svelto.ECS/EnginesRootEngines.cs @@ -37,13 +37,13 @@ namespace Svelto.ECS _entityViewEngines = new Dictionary>(); _otherEngines = new FasterList(); - _entityViewsDB = new Dictionary(); + _globalEntityViewsDB = new Dictionary(); _groupEntityViewsDB = new Dictionary>(); - _groupedEntityViewsDBDic = new Dictionary>(); + _globalEntityViewsDBDic = new Dictionary(); _groupedEntityViewsToAdd = new DoubleBufferedEntityViews>>(); - _DB = new EntityViewsDB(_entityViewsDB, _groupedEntityViewsDBDic, _groupEntityViewsDB); + _DB = new EntityViewsDB(_globalEntityViewsDB, _globalEntityViewsDBDic, _groupEntityViewsDB); _scheduler = entityViewScheduler; _scheduler.Schedule(new WeakAction(SubmitEntityViews)); diff --git a/Svelto.ECS/EnginesRootEntities.cs b/Svelto.ECS/EnginesRootEntities.cs index 77fbbfa..0703fa3 100644 --- a/Svelto.ECS/EnginesRootEntities.cs +++ b/Svelto.ECS/EnginesRootEntities.cs @@ -14,7 +14,7 @@ namespace Svelto.ECS { public void Dispose() { - foreach (var entity in _entityViewsDB) + foreach (var entity in _globalEntityViewsDB) if (entity.Value.isQueryiableEntityView) foreach (var entityView in entity.Value) RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); @@ -64,7 +64,7 @@ namespace Svelto.ECS implementors); } - void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, + void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) { EntityFactory.BuildGroupedEntityViews(entityID, groupID, @@ -74,9 +74,15 @@ namespace Svelto.ECS ///-------------------------------------------- + /// + /// This function is experimental and untested. I never used it in production + /// it may not be necessary. + /// TODO: understand if this method is useful in a performance critical + /// scenario + /// void Preallocate(int groupID, int size) where T : IEntityDescriptor, new() { - var entityViewsToBuild = ((EntityDescriptorInfo) EntityDescriptorTemplate.Default).entityViewsToBuild; + var entityViewsToBuild = EntityDescriptorTemplate.Default.entityViewsToBuild; var count = entityViewsToBuild.Length; for (var index = 0; index < count; index++) @@ -86,8 +92,8 @@ namespace Svelto.ECS //reserve space for the global pool ITypeSafeList dbList; - if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) - _entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); + if (_globalEntityViewsDB.TryGetValue(entityViewType, out dbList) == false) + _globalEntityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); else dbList.AddCapacity(size); @@ -111,18 +117,44 @@ namespace Svelto.ECS dbList.AddCapacity(size); } } - - void RemoveEntity(ref EntityInfoView entityInfoView) + + ///-------------------------------------------- + /// + void RemoveEntity(int entityID, int groupID) { - InternalRemoveFromGroupAndDBAndEngines(entityInfoView.entityViews, entityInfoView.ID, - entityInfoView.groupID); + RemoveEntity(new EGID(entityID, groupID)); } - void RemoveEntity(int entityID, int groupID) + void RemoveEntity(EGID entityGID) { - var entityInfoView = _DB.QueryEntityViewInGroup(entityID, groupID); + _DB.TryQueryEntityView(entityGID, out var entityInfoView); + + var entityViewBuilders = entityInfoView.entityViews; + EGID id = entityInfoView._ID; + + var entityViewBuildersCount = entityViewBuilders.Length; + var group = _groupEntityViewsDB[id.group]; + + //for each entity view generated by the entity descriptor + for (var i = 0; i < entityViewBuildersCount; i++) + { + var entityViewType = entityViewBuilders[i].GetEntityViewType(); + + InternalRemoveEntityViewFromDBDicAndEngines(entityViewType, id); + + RemoveEntityViewFromDB(@group, entityViewType, id); + RemoveEntityViewFromDB(@_globalEntityViewsDB, entityViewType, id); + } - RemoveEntity(ref entityInfoView); + InternalRemoveEntityViewFromDBDicAndEngines(_entityInfoViewType, id); + } + + static void RemoveEntityViewFromDB(Dictionary @group, Type entityViewType, EGID id) + { + //remove it from entity views group DB + var typeSafeList = @group[entityViewType]; + if (typeSafeList.MappedRemove(id) == false) //clean up + @group.Remove(entityViewType); } void RemoveGroupAndEntitiesFromDB(int groupID) @@ -138,40 +170,70 @@ namespace Svelto.ECS { var entityID = entities[i].ID; - InternalRemoveEntityViewFromDBAndEngines(entityViewType, entityID, groupID); + RemoveEntityViewFromDB(@_globalEntityViewsDB, entityViewType, entityID); + + InternalRemoveEntityViewFromDBDicAndEngines(entityViewType, entityID); } } _groupEntityViewsDB.Remove(groupID); } - void InternalRemoveEntityViewFromDBAndEngines(Type entityViewType, - int entityID, - int groupID) + void InternalRemoveEntityViewFromDBDicAndEngines(Type entityViewType, EGID id) { - var entityViews = _entityViewsDB[entityViewType]; - if (entityViews.MappedRemove(entityID) == false) - _entityViewsDB.Remove(entityViewType); - - if (entityViews.isQueryiableEntityView) + var typeSafeDictionary = _globalEntityViewsDBDic[entityViewType]; + if (typeSafeDictionary.isQueryiableEntityView) { - var typeSafeDictionary = _groupedEntityViewsDBDic[groupID][entityViewType]; - var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); - - if (typeSafeDictionary.Remove(entityID) == false) - _groupedEntityViewsDBDic[groupID].Remove(entityViewType); + var entityView = typeSafeDictionary.GetIndexedEntityView(id); + //the reason why this for exists is because in the past hierarchical entity views + //where supported :( + //Only EntityView can be removed from engines (won't work for IEntityStruct or IEntityView) for (var current = entityViewType; current != _entityViewType; current = current.BaseType) + { +#if DEBUG && !PROFILER + if (current != entityViewType) + Utility.Console.LogWarning("Hierarchical Entity Views are design mistakes, ECS is not OOD!!"); +#endif + RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); + } } + typeSafeDictionary.Remove(id); } + + 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 (var j = 0; j < count; j++) + { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR + EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); +#else + fastList[j].Remove(entityView); +#endif + } + } + } + + ///-------------------------------------------- void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) { Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); - var entityViewBuilders = _DB.QueryEntityView(entityID).entityViews; + _DB.TryQueryEntityViewInGroup(fromGroupID, entityID, out EntityInfoView entityInfoView); + + var entityViewBuilders = entityInfoView.entityViews; var entityViewBuildersCount = entityViewBuilders.Length; var groupedEntities = _groupEntityViewsDB[fromGroupID]; @@ -195,78 +257,28 @@ namespace Svelto.ECS if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) groupedEntityViewsTyped[entityViewType] = toSafeList = fromSafeList.Create(); - entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); - - fromSafeList.MappedRemove(entityID); + entityViewBuilder.MoveEntityView(entityInfoView._ID, fromSafeList, toSafeList); + fromSafeList.MappedRemove(entityInfoView._ID); + entityInfoView._ID = new EGID(entityID, toGroupID); } - - var entityInfoView = _DB.QueryEntityView(entityID); - entityInfoView.groupID = toGroupID; - } - - void InternalRemoveFromGroupAndDBAndEngines(IEntityViewBuilder[] entityViewBuilders, - int entityID, int groupID) - { - InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); - - var entityViewBuildersCount = entityViewBuilders.Length; - - for (var i = 0; i < entityViewBuildersCount; i++) - { - var entityViewType = entityViewBuilders[i].GetEntityViewType(); - - InternalRemoveEntityViewFromDBAndEngines(entityViewType, entityID, groupID); - } - - InternalRemoveEntityViewFromDBAndEngines(typeof(EntityInfoView), entityID, groupID); } - void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) - { - var entityViewBuildersCount = entityViewBuilders.Length; - var group = _groupEntityViewsDB[groupID]; - - for (var i = 0; i < entityViewBuildersCount; i++) - { - var entityViewType = entityViewBuilders[i].GetEntityViewType(); - var typeSafeList = group[entityViewType]; - typeSafeList.MappedRemove(entityID); - } - } - - 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 (var j = 0; j < count; j++) - { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); -#else - fastList[j].Remove(entityView); -#endif - } - } - } + readonly Type _entityInfoViewType = typeof(EntityInfoView); readonly EntityViewsDB _DB; //grouped set of entity views, this is the standard way to handle entity views readonly Dictionary> _groupEntityViewsDB; - //indexable entity views when the entity ID is known. Usually useful to handle - //event based logic. - readonly Dictionary> _groupedEntityViewsDBDic; - + + //TODO: Use faster dictionary and merge these two? + //Global pool of entity views when engines want to manage entityViews regardless //the group - readonly Dictionary _entityViewsDB; + readonly Dictionary _globalEntityViewsDB; + //indexable entity views when the entity ID is known. Usually useful to handle + //event based logic. + readonly Dictionary _globalEntityViewsDBDic; + } } \ No newline at end of file diff --git a/Svelto.ECS/EnginesRootSubmission.cs b/Svelto.ECS/EnginesRootSubmission.cs index 009fa10..3934072 100644 --- a/Svelto.ECS/EnginesRootSubmission.cs +++ b/Svelto.ECS/EnginesRootSubmission.cs @@ -39,7 +39,7 @@ namespace Svelto.ECS numberOfReenteringLoops++; } } - + //todo: can I make the entity creation less complicated? void AddEntityViewsToTheDBAndSuitableEngines(Dictionary> groupsToSubmit) { //for each groups there is a dictionary of built lists of EntityView grouped by type @@ -57,18 +57,9 @@ namespace Svelto.ECS //add the entity View in the group AddEntityViewToDB(groupDB, entityViewsPerType); //add the entity view in the gloal pool - AddEntityViewToDB(_entityViewsDB, entityViewsPerType); + AddEntityViewToDB(_globalEntityViewsDB, entityViewsPerType); //and it's not a struct, add in the indexable DB too - if (entityViewsPerType.Value.isQueryiableEntityView) - { - Dictionary groupDic; - - if (_groupedEntityViewsDBDic.TryGetValue(groupID, out groupDic) == false) - groupDic = _groupedEntityViewsDBDic[groupID] = - new Dictionary(); - - AddEntityViewToEntityViewsDictionary(groupDic, entityViewsPerType.Value, entityViewsPerType.Key); - } + AddEntityViewToEntityViewsDictionary(_globalEntityViewsDBDic, entityViewsPerType.Value, entityViewsPerType.Key); } } @@ -87,8 +78,8 @@ namespace Svelto.ECS } } - static void AddEntityViewToDB(Dictionary entityViewsDB, - KeyValuePair entityViewList) + static void AddEntityViewToDB( Dictionary entityViewsDB, + KeyValuePair entityViewList) { ITypeSafeList dbList; diff --git a/Svelto.ECS/EntityFactory.cs b/Svelto.ECS/EntityFactory.cs index 4c2bb9a..e90d220 100644 --- a/Svelto.ECS/EntityFactory.cs +++ b/Svelto.ECS/EntityFactory.cs @@ -13,25 +13,45 @@ namespace Svelto.ECS.Internal EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) { - Dictionary group; + var @group = FetchGroup(groupID, groupEntityViewsByType); - if (groupEntityViewsByType.TryGetValue(groupID, out group) == false) - { - group = new Dictionary(); - groupEntityViewsByType.Add(groupID, group); - } + BuildEntityViewsAndAddToGroup(new EGID(entityID, groupID), group, entityViewsToBuildDescriptor, implementors); - InternalBuildEntityViews(entityID, group, entityViewsToBuildDescriptor, implementors); + AddEntityInfoView(new EGID(entityID, groupID), entityViewsToBuildDescriptor, @group); + } - EntityInfoView removeEntityView = - (EntityInfoView) BuildEntityView - (entityID, group, EntityViewBuilder.ENTITY_VIEW_TYPE, new EntityViewBuilder()); + static void AddEntityInfoView(EGID entityID, EntityDescriptorInfo entityViewsToBuildDescriptor, + Dictionary @group) + { + //should be a struct? + var removeEntityView = new EntityInfoView(); - removeEntityView.groupID = groupID; + removeEntityView._ID = entityID; removeEntityView.entityViews = entityViewsToBuildDescriptor.entityViewsToBuild; + + ITypeSafeList list; + + if (group.TryGetValue(typeof(EntityInfoView), out list) == false) + list = group[typeof(EntityInfoView)] = + new TypeSafeFasterListForECSForClasses(); + + ((TypeSafeFasterListForECSForClasses) list).Add(removeEntityView); } - static void InternalBuildEntityViews(int entityID, + static Dictionary FetchGroup(int groupID, Dictionary> groupEntityViewsByType) + { + Dictionary group; + + if (groupEntityViewsByType.TryGetValue(groupID, out @group) == false) + { + @group = new Dictionary(); + groupEntityViewsByType.Add(groupID, @group); + } + + return @group; + } + + static void BuildEntityViewsAndAddToGroup(EGID entityID, Dictionary entityViewsByType, EntityDescriptorInfo entityViewsToBuildDescriptor, object[] implementors) @@ -54,8 +74,8 @@ namespace Svelto.ECS.Internal } } - static IEntityView BuildEntityView(int entityID, Dictionary entityViewsByType, - Type entityViewType, IEntityViewBuilder entityViewBuilder) + static IEntityView BuildEntityView(EGID entityID, Dictionary entityViewsByType, + Type entityViewType, IEntityViewBuilder entityViewBuilder) { ITypeSafeList entityViewsList; @@ -182,7 +202,7 @@ namespace Svelto.ECS.Internal } #endif static readonly Dictionary _cachedTypes = new Dictionary(); - + const string DUPLICATE_IMPLEMENTOR_ERROR = "Svelto.ECS the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; diff --git a/Svelto.ECS/EntityInfoView.cs b/Svelto.ECS/EntityInfoView.cs index 618518b..14490bd 100644 --- a/Svelto.ECS/EntityInfoView.cs +++ b/Svelto.ECS/EntityInfoView.cs @@ -1,8 +1,7 @@ -namespace Svelto.ECS +namespace Svelto.ECS.Internal { - public class EntityInfoView : EntityView + class EntityInfoView : EntityView { internal IEntityViewBuilder[] entityViews; - public int groupID; } } \ No newline at end of file diff --git a/Svelto.ECS/EntityView.cs b/Svelto.ECS/EntityView.cs index b8e56fa..c552263 100644 --- a/Svelto.ECS/EntityView.cs +++ b/Svelto.ECS/EntityView.cs @@ -6,27 +6,29 @@ using Svelto.Utilities; namespace Svelto.ECS { + //todo: can I remove the ID from the struct? + public interface IEntityView { - int ID { get; } + EGID ID { get; } } public interface IEntityStruct:IEntityView { - new int ID { set; } + new EGID ID { get; set; } } public class EntityView : IEntityView { - public int ID { get { return _ID; } } + public EGID ID { get { return _ID; } } internal FasterList>> entityViewBlazingFastReflection; - internal int _ID; + internal EGID _ID; } static class EntityView where T: EntityView, new() { - internal static T BuildEntityView(int ID) + internal static T BuildEntityView(EGID ID) { if (FieldCache.list.Count == 0) { diff --git a/Svelto.ECS/EntityViewBuilder.cs b/Svelto.ECS/EntityViewBuilder.cs index 3c81486..f709038 100644 --- a/Svelto.ECS/EntityViewBuilder.cs +++ b/Svelto.ECS/EntityViewBuilder.cs @@ -5,17 +5,17 @@ namespace Svelto.ECS { public interface IEntityViewBuilder { - void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); + void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView); ITypeSafeList Preallocate(ref ITypeSafeList list, int size); Type GetEntityViewType(); - void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); + void MoveEntityView(EGID entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); bool mustBeFilled { get; } } - public struct EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() + public class EntityViewBuilder : IEntityViewBuilder where EntityViewType : EntityView, new() { - public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView) { if (list == null) list = new TypeSafeFasterListForECSForClasses(); @@ -44,7 +44,7 @@ namespace Svelto.ECS return ENTITY_VIEW_TYPE; } - public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) + public void MoveEntityView(EGID entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) { var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses; var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses; @@ -57,12 +57,12 @@ namespace Svelto.ECS get { return true; } } - internal static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); + public static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); } - public struct EntityViewStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct + public class EntityViewStructBuilder : IEntityViewBuilder where EntityViewType : struct, IEntityStruct { - public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) + public void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView) { var structEntityView = default(EntityViewType); structEntityView.ID = entityID; @@ -92,7 +92,7 @@ namespace Svelto.ECS return ENTITY_VIEW_TYPE; } - public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) + public void MoveEntityView(EGID entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) { var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs; var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs; @@ -105,6 +105,6 @@ namespace Svelto.ECS get { return false; } } - internal static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); + public static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); } } \ No newline at end of file diff --git a/Svelto.ECS/EntityViewsDB.cs b/Svelto.ECS/EntityViewsDB.cs index e47bba5..1de4a3d 100644 --- a/Svelto.ECS/EntityViewsDB.cs +++ b/Svelto.ECS/EntityViewsDB.cs @@ -7,10 +7,10 @@ namespace Svelto.ECS.Internal class EntityViewsDB : IEntityViewsDB { internal EntityViewsDB( Dictionary entityViewsDB, - Dictionary> entityViewsDBdic, + Dictionary entityViewsDBdic, Dictionary> groupEntityViewsDB) { - _entityViewsDB = entityViewsDB; + _globalEntityViewsDB = entityViewsDB; _groupedEntityViewsDBDic = entityViewsDBdic; _groupEntityViewsDB = groupEntityViewsDB; } @@ -21,7 +21,7 @@ namespace Svelto.ECS.Internal ITypeSafeList entityViews; - if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + if (_globalEntityViewsDB.TryGetValue(type, out entityViews) == false) return RetrieveEmptyEntityViewList(); return new FasterReadOnlyList((FasterList)entityViews); @@ -48,7 +48,7 @@ namespace Svelto.ECS.Internal ITypeSafeList entityViews; - if (_entityViewsDB.TryGetValue(type, out entityViews) == false) + if (_globalEntityViewsDB.TryGetValue(type, out entityViews) == false) return RetrieveEmptyEntityViewArray(); return FasterList.NoVirt.ToArrayFast((FasterList)entityViews, out count); @@ -73,56 +73,60 @@ namespace Svelto.ECS.Internal public T QueryEntityView(int entityID) where T:EntityView { - return QueryEntityViewInGroup(entityID, ExclusiveGroups.StandardEntity); - } + T entityView; - public bool TryQueryEntityView(int entityID, out T entityView) where T:EntityView - { - return TryQueryEntityViewInGroup(entityID, ExclusiveGroups.StandardEntity, out entityView); + TryQueryEntityViewInGroup(new EGID(entityID, ExclusiveGroups.StandardEntity), out entityView); + + return entityView; } - - public T QueryEntityViewInGroup(int entityID, int groupID) where T:EntityView + + public T QueryEntityView(EGID entityGID) where T : EntityView { T entityView; - - TryQueryEntityView(entityID, groupID, _groupedEntityViewsDBDic, out entityView); + + TryQueryEntityViewInGroup(entityGID, out entityView); return entityView; } - public bool TryQueryEntityViewInGroup(int entityID, int groupID, out T entityView) where T:EntityView + public bool TryQueryEntityView(int entityID, out T entityView) where T:EntityView { - return TryQueryEntityView(entityID, groupID, _groupedEntityViewsDBDic, out entityView); + return TryQueryEntityViewInGroup(new EGID(entityID, ExclusiveGroups.StandardEntity), out entityView); } - static FasterReadOnlyList RetrieveEmptyEntityViewList() + public bool TryQueryEntityView(EGID entityegid, out T entityView) where T : EntityView { - return FasterReadOnlyList.DefaultList; + return TryQueryEntityViewInGroup(entityegid, out entityView); } - static T[] RetrieveEmptyEntityViewArray() + public T QueryEntityViewInGroup(int entityID, int groupID) where T:EntityView { - return FasterList.DefaultList.ToArrayFast(); + T entityView; + + TryQueryEntityViewInGroup(entityID, groupID, out entityView); + + return entityView; } - - static bool TryQueryEntityView(int ID, int groupID, Dictionary> entityDic, out T entityView) where T : EntityView + + public bool TryQueryEntityViewInGroup(int entityID, int groupID, out T entityView) where T : EntityView + { + return TryQueryEntityViewInGroup(new EGID(entityID, groupID), out entityView); + } + + bool TryQueryEntityViewInGroup(EGID entityGID, out T entityView) where T:EntityView { var type = typeof(T); T internalEntityView; - ITypeSafeDictionary entityViews; - TypeSafeDictionary casted; - - Dictionary @group; - if (entityDic.TryGetValue(groupID, out group) == false) - throw new Exception("Group not found"); + ITypeSafeDictionary entityViews; + TypeSafeDictionaryForClass casted; - group.TryGetValue(type, out entityViews); - casted = entityViews as TypeSafeDictionary; + _groupedEntityViewsDBDic.TryGetValue(type, out entityViews); + casted = entityViews as TypeSafeDictionaryForClass; if (casted != null && - casted.TryGetValue(ID, out internalEntityView)) + casted.TryGetValue(entityGID.GID, out internalEntityView)) { entityView = internalEntityView; @@ -134,9 +138,24 @@ namespace Svelto.ECS.Internal return false; } - readonly Dictionary> _groupEntityViewsDB; - readonly Dictionary> _groupedEntityViewsDBDic; + static FasterReadOnlyList RetrieveEmptyEntityViewList() + { + return FasterReadOnlyList.DefaultList; + } - readonly Dictionary _entityViewsDB; + static T[] RetrieveEmptyEntityViewArray() + { + return FasterList.DefaultList.ToArrayFast(); + } + + + //grouped set of entity views, this is the standard way to handle entity views + readonly Dictionary> _groupEntityViewsDB; + //Global pool of entity views when engines want to manage entityViews regardless + //the group + readonly Dictionary _globalEntityViewsDB; + //indexable entity views when the entity ID is known. Usually useful to handle + //event based logic. + readonly Dictionary _groupedEntityViewsDBDic; } } diff --git a/Svelto.ECS/ExclusiveGroups.cs b/Svelto.ECS/ExclusiveGroups.cs index e2a21f4..5e8eb2f 100644 --- a/Svelto.ECS/ExclusiveGroups.cs +++ b/Svelto.ECS/ExclusiveGroups.cs @@ -2,6 +2,6 @@ { static class ExclusiveGroups { - internal const int StandardEntity = unchecked((int) 0xFFFFFFFF); + internal const int StandardEntity = 0xFF; } } \ No newline at end of file diff --git a/Svelto.ECS/IEntityFactory.cs b/Svelto.ECS/IEntityFactory.cs index ebd04a2..cc63776 100644 --- a/Svelto.ECS/IEntityFactory.cs +++ b/Svelto.ECS/IEntityFactory.cs @@ -41,7 +41,7 @@ namespace Svelto.ECS /// /// /// - void BuildEntity(int entityID, object[] implementors) where T:IEntityDescriptor, new(); + void BuildEntity(int entityID, object[] implementors) where T:IEntityDescriptor, new(); /// /// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo diff --git a/Svelto.ECS/IEntityFunctions.cs b/Svelto.ECS/IEntityFunctions.cs index 01ce4ee..3cf8408 100644 --- a/Svelto.ECS/IEntityFunctions.cs +++ b/Svelto.ECS/IEntityFunctions.cs @@ -7,6 +7,7 @@ namespace Svelto.ECS //the entity from the special standard group. void RemoveEntity(int entityID); void RemoveEntity(int entityID, int groupID); + void RemoveEntity(EGID entityegid); void RemoveGroupAndEntities(int groupID); diff --git a/Svelto.ECS/IEntityViewsDB.cs b/Svelto.ECS/IEntityViewsDB.cs index dadb870..0779317 100644 --- a/Svelto.ECS/IEntityViewsDB.cs +++ b/Svelto.ECS/IEntityViewsDB.cs @@ -11,8 +11,10 @@ namespace Svelto.ECS T[] QueryGroupedEntityViewsAsArray(int group, out int count) where T : IEntityView; bool TryQueryEntityView(int ID, out T entityView) where T : EntityView; + bool TryQueryEntityView(EGID ID, out T entityView) where T : EntityView; T QueryEntityView(int ID) where T : EntityView; - + T QueryEntityView(EGID entityGID) where T : EntityView; + bool TryQueryEntityViewInGroup(int entityID, int groupID, out T entityView) where T : EntityView; T QueryEntityViewInGroup(int entityID, int groupID) where T : EntityView; }