From d456dcbffffd10f61bfe4c6f11bc27cf033cd038 Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sun, 5 Aug 2018 11:21:58 +0100 Subject: [PATCH] Experiment with safe ExecuteOnEntities (it protects from fatal mistakes and database misues) and ExecuteOnEntities with multiple entity views --- Svelto.ECS/EnginesRoot.Entities.cs | 2 +- Svelto.ECS/EntitiesDB.cs | 211 ++++++++++++++--------------- Svelto.ECS/EntitiesDBException.cs | 10 ++ Svelto.ECS/IEntitiesDB.cs | 5 + 4 files changed, 119 insertions(+), 109 deletions(-) create mode 100644 Svelto.ECS/EntitiesDBException.cs diff --git a/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/EnginesRoot.Entities.cs index fed433b..1e7691f 100644 --- a/Svelto.ECS/EnginesRoot.Entities.cs +++ b/Svelto.ECS/EnginesRoot.Entities.cs @@ -192,7 +192,7 @@ namespace Svelto.ECS EGID SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T:IEntityDescriptor, new () { DBC.ECS.Check.Require(fromGroupID != toGroupID, - "can't move an entity to the same fromGroup where it already belongs to"); + "the entity is already in this group"); Dictionary toGroup; diff --git a/Svelto.ECS/EntitiesDB.cs b/Svelto.ECS/EntitiesDB.cs index 46e7043..c584eaf 100644 --- a/Svelto.ECS/EntitiesDB.cs +++ b/Svelto.ECS/EntitiesDB.cs @@ -22,16 +22,10 @@ namespace Svelto.ECS.Internal public ReadOnlyCollectionStruct QueryEntityViews(int @group) where T:class, IEntityStruct { - Dictionary entitiesInGroupPerType; - - if (_groupEntityViewsDB.TryGetValue(group, out entitiesInGroupPerType) == false) - return RetrieveEmptyEntityViewList(); - - ITypeSafeDictionary outList; - if (entitiesInGroupPerType.TryGetValue(typeof(T), out outList) == false) - return RetrieveEmptyEntityViewList(); + TypeSafeDictionary typeSafeDictionary; + if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return RetrieveEmptyEntityViewList(); - return (outList as TypeSafeDictionary).FasterValues; + return typeSafeDictionary.FasterValues; } public T[] QueryEntities(out int count) where T : IEntityStruct @@ -41,32 +35,24 @@ namespace Svelto.ECS.Internal public T[] QueryEntities(int @group, out int count) where T : IEntityStruct { + TypeSafeDictionary typeSafeDictionary; count = 0; - - Dictionary entitiesInGroupPerType; - - if (_groupEntityViewsDB.TryGetValue(group, out entitiesInGroupPerType) == false) - return RetrieveEmptyEntityViewArray(); - - ITypeSafeDictionary typeSafeDictionary; - if (entitiesInGroupPerType.TryGetValue(typeof(T), out typeSafeDictionary) == false) - return RetrieveEmptyEntityViewArray(); + if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return RetrieveEmptyEntityViewArray(); - return ((TypeSafeDictionary)typeSafeDictionary).GetFasterValuesBuffer(out count); + return typeSafeDictionary.GetFasterValuesBuffer(out count); } - + public T[] QueryEntities(int groupID, ref EGIDMapper mapper) where T : IEntityStruct { - TypeSafeDictionary casted; - if (!FindSafeDictionary(groupID, out casted)) - { - throw new Exception("Entity group found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(groupID)); - } - - mapper.map = casted; + TypeSafeDictionary typeSafeDictionary; + + if (QueryEntitySafeDictionary(groupID, out typeSafeDictionary) == false) + throw new EntitiesDBException("Entity group not found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(groupID)); + + mapper.map = typeSafeDictionary; int count; - return QueryEntities(groupID, out count); + return typeSafeDictionary.GetFasterValuesBuffer(out count); } public T[] QueryEntitiesAndIndex(EGID entityGID, out uint index) where T : IEntityStruct @@ -75,7 +61,7 @@ namespace Svelto.ECS.Internal if ((array = QueryEntitiesAndIndexInternal(entityGID, out index)) != null) return array; - throw new Exception("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); + throw new EntitiesDBException("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); } public bool TryQueryEntitiesAndIndex(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct @@ -90,8 +76,8 @@ namespace Svelto.ECS.Internal { T entityView; - if (TryQueryEntityViewInGroup(entityGID, out entityView) == false) - throw new Exception("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); + if (TryQueryEntityViewInGroupInternal(entityGID, out entityView) == false) + throw new EntitiesDBException("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); return entityView; } @@ -99,27 +85,27 @@ namespace Svelto.ECS.Internal public void ExecuteOnEntity(EGID entityGID, ref W value, ActionRef action) where T : IEntityStruct { TypeSafeDictionary casted; - if (FindSafeDictionary(entityGID.groupID, out casted)) + if (QueryEntitySafeDictionary(entityGID.groupID, out casted)) { if (casted != null) if (casted.ExecuteOnEntityView(entityGID.entityID, ref value, action) == true) return; } - throw new Exception("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); + throw new EntitiesDBException("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); } public void ExecuteOnEntity(EGID entityGID, ActionRef action) where T : IEntityStruct { TypeSafeDictionary casted; - if (FindSafeDictionary(entityGID.groupID, out casted)) + if (QueryEntitySafeDictionary(entityGID.groupID, out casted)) { if (casted != null) if (casted.ExecuteOnEntityView(entityGID.entityID, action) == true) return; } - throw new Exception("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); + throw new EntitiesDBException("Entity not found id: ".FastConcat(entityGID.entityID).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); } public void ExecuteOnEntity(int id, ActionRef action) where T : IEntityStruct @@ -172,71 +158,77 @@ namespace Svelto.ECS.Internal public void ExecuteOnAllEntities(ActionRef action) where T : IEntityStruct { - int count; - var typeSafeDictionaries = _groupedGroups[typeof(T)].GetFasterValuesBuffer(out count); - for (int j = 0; j < count; j++) + var type = typeof(T); + FasterDictionary dic; + if (_groupedGroups.TryGetValue(type, out dic)) { - int count2; - var safedic = typeSafeDictionaries[j]; - TypeSafeDictionary casted = safedic as TypeSafeDictionary; - var entities = casted.GetFasterValuesBuffer(out count2); - for (int i = 0; i < count2; i++) - action(ref entities[i]); + int count; + var typeSafeDictionaries = dic.GetFasterValuesBuffer(out count); + for (int j = 0; j < count; j++) + { + int innerCount; + var safedic = typeSafeDictionaries[j]; + var casted = safedic as TypeSafeDictionary; + var entities = casted.GetFasterValuesBuffer(out innerCount); + for (int i = 0; i < innerCount; i++) + action(ref entities[i]); + } } } public void ExecuteOnAllEntities(ref W value, ActionRef action) where T : IEntityStruct { - int count; - var typeSafeDictionaries = _groupedGroups[typeof(T)].GetFasterValuesBuffer(out count); - for (int j = 0; j < count; j++) + var type = typeof(T); + FasterDictionary dic; + if (_groupedGroups.TryGetValue(type, out dic)) { - int count2; - var safedic = typeSafeDictionaries[j]; - TypeSafeDictionary casted = safedic as TypeSafeDictionary; - var entities = casted.GetFasterValuesBuffer(out count2); - for (int i = 0; i < count2; i++) - action(ref entities[i], ref value); + int count; + var typeSafeDictionaries = dic.GetFasterValuesBuffer(out count); + for (int j = 0; j < count; j++) + { + int innerCount; + var safedic = typeSafeDictionaries[j]; + var casted = safedic as TypeSafeDictionary; + var entities = casted.GetFasterValuesBuffer(out innerCount); + for (int i = 0; i < innerCount; i++) + action(ref entities[i], ref value); + } } } - public bool Exists(EGID entityGID) where T : IEntityStruct + public void ExecuteOnEntities(int group, ActionRef action) where T : IEntityStruct where T1 : IEntityStruct { - TypeSafeDictionary casted; - if (!FindSafeDictionary(entityGID.groupID, out casted)) return false; - - if (casted != null && - casted.ContainsKey(entityGID.entityID)) + int count; + TypeSafeDictionary typeSafeDictionary; + if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return; + + var entities = typeSafeDictionary.GetFasterValuesBuffer(out count); + + for (var i = 0; i < count; i++) { - return true; + uint index; + action(ref entities[i], ref QueryEntitiesAndIndex(entities[i].ID, out index)[index]); + if (typeSafeDictionary.Count != count) + throw new EntitiesDBException("Entities cannot be swapped or removed during an iteration"); } - - return false; } - bool FindSafeDictionary(int groupID, out TypeSafeDictionary casted) where T : IEntityStruct + public void ExecuteOnEntities(ActionRef action) where T : IEntityStruct where T1 : IEntityStruct { - var type = typeof(T); - - ITypeSafeDictionary entityViews; + ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, action); + } - Dictionary entitiesInGroupPerType; - if (_groupEntityViewsDB.TryGetValue(groupID, out entitiesInGroupPerType) == false) - { - casted = null; - return false; - } + public bool Exists(EGID entityGID) where T : IEntityStruct + { + TypeSafeDictionary casted; + if (QueryEntitySafeDictionary(entityGID.groupID, out casted) == false) return false; - entitiesInGroupPerType.TryGetValue(type, out entityViews); - casted = entityViews as TypeSafeDictionary; - return true; + return casted != null && casted.ContainsKey(entityGID.entityID); } public bool HasAny() where T : IEntityStruct { - int count; - QueryEntities(out count); - return count > 0; + return HasAny(ExclusiveGroup.StandardEntitiesGroup); } public bool HasAny(int @group) where T : IEntityStruct @@ -248,48 +240,51 @@ namespace Svelto.ECS.Internal public bool TryQueryEntityView(EGID entityegid, out T entityView) where T : class, IEntityStruct { - return TryQueryEntityViewInGroup(entityegid, out entityView); + return TryQueryEntityViewInGroupInternal(entityegid, out entityView); } - - bool TryQueryEntityViewInGroup(EGID entityGID, out T entityView) where T:IEntityStruct + + bool TryQueryEntityViewInGroupInternal(EGID entityGID, out T entityView) where T:class, IEntityStruct { - TypeSafeDictionary casted; - if (!FindSafeDictionary(entityGID.groupID, out casted)) - { - entityView = default(T); - return false; - } + entityView = null; + TypeSafeDictionary safeDictionary; + if (QueryEntitySafeDictionary(entityGID.groupID, out safeDictionary) == false) return false; - if (casted != null && - casted.TryGetValue(entityGID.entityID, out entityView)) - { - return true; - } + return safeDictionary.TryGetValue(entityGID.entityID, out entityView) != false; + } + + T[] QueryEntitiesAndIndexInternal(EGID entityGID, out uint index) where T : IEntityStruct + { + TypeSafeDictionary safeDictionary; + if (QueryEntitySafeDictionary(entityGID.groupID, out safeDictionary) == false) + throw new EntitiesDBException("Entity not found, type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(entityGID.entityID)); - entityView = default(T); + if (safeDictionary.TryFindElementIndex(entityGID.entityID, out index) == false) + throw new EntitiesDBException("Entity not found, type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(entityGID.entityID)); - return false; + int count; + return safeDictionary.GetFasterValuesBuffer(out count); } - T[] QueryEntitiesAndIndexInternal(EGID entityGID, out uint index) where T : IEntityStruct + bool QueryEntitySafeDictionary(int @group, out TypeSafeDictionary typeSafeDictionary) where T : IEntityStruct { - TypeSafeDictionary casted; - if (!FindSafeDictionary(entityGID.groupID, out casted)) - { - index = 0; - throw new Exception("Entity group found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); - } + Dictionary entitiesInGroupPerType; + typeSafeDictionary = null; - if (casted == null || casted.TryFindElementIndex(entityGID.entityID, out index) == false) - { - index = 0; - throw new Exception("Entity not found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(entityGID.entityID)); - } + //search for the group + if (_groupEntityViewsDB.TryGetValue(@group, out entitiesInGroupPerType) == false) + return false; - int count; + //search for the indexed entities in the group + ITypeSafeDictionary safeDictionary; + if (entitiesInGroupPerType.TryGetValue(typeof(T), out safeDictionary) == false) + return false; + + //return the indexes entities if they exist + typeSafeDictionary = (safeDictionary as TypeSafeDictionary); - return QueryEntities(entityGID.groupID, out count); + return true; } + static ReadOnlyCollectionStruct RetrieveEmptyEntityViewList() { return ReadOnlyCollectionStruct.DefaultList; diff --git a/Svelto.ECS/EntitiesDBException.cs b/Svelto.ECS/EntitiesDBException.cs new file mode 100644 index 0000000..f75a8cf --- /dev/null +++ b/Svelto.ECS/EntitiesDBException.cs @@ -0,0 +1,10 @@ +using System; + +namespace Svelto.ECS +{ + public class EntitiesDBException : Exception + { + public EntitiesDBException(string message):base(message) + {} + } +} \ No newline at end of file diff --git a/Svelto.ECS/IEntitiesDB.cs b/Svelto.ECS/IEntitiesDB.cs index 0de8bbc..7289d0c 100644 --- a/Svelto.ECS/IEntitiesDB.cs +++ b/Svelto.ECS/IEntitiesDB.cs @@ -1,3 +1,4 @@ +using System; using Svelto.DataStructures; using Svelto.Utilities; @@ -56,10 +57,14 @@ namespace Svelto.ECS void ExecuteOnAllEntities(ActionRef action) where T : IEntityStruct; void ExecuteOnAllEntities(ref W value, ActionRef action) where T : IEntityStruct; + + void ExecuteOnEntities(int groupID, ActionRef action) where T : IEntityStruct where T1 : IEntityStruct; + void ExecuteOnEntities(ActionRef action) where T : IEntityStruct where T1 : IEntityStruct; bool Exists(EGID egid) where T : IEntityStruct; bool HasAny() where T:IEntityStruct; bool HasAny(int group) where T:IEntityStruct; + } } \ No newline at end of file