diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs index 31aeabd..d852218 100644 --- a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs +++ b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs @@ -108,7 +108,7 @@ namespace Svelto.ECS.Internal if (toGroup != null) { - var toGroupCasted = (toGroup as TypeSafeDictionary); + var toGroupCasted = toGroup as TypeSafeDictionary; fasterValuesBuffer[valueIndex].ID = new EGID(fromEntityGid.entityID, toGroupID); toGroupCasted.Add(fromEntityGid.entityID, ref fasterValuesBuffer[valueIndex]); diff --git a/Svelto.ECS/EGIDMapper.cs b/Svelto.ECS/EGIDMapper.cs new file mode 100644 index 0000000..cec4ee9 --- /dev/null +++ b/Svelto.ECS/EGIDMapper.cs @@ -0,0 +1,14 @@ +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + public struct EGIDMapper where T : IEntityStruct + { + internal TypeSafeDictionary map; + + public uint this[EGID index] + { + get { return map.FindElementIndex(index.entityID); } + } + } +} \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/EnginesRoot.Entities.cs index a778e16..fed433b 100644 --- a/Svelto.ECS/EnginesRoot.Entities.cs +++ b/Svelto.ECS/EnginesRoot.Entities.cs @@ -142,11 +142,11 @@ namespace Svelto.ECS { var entityType = entityBuilders[i].GetEntityType(); - MoveEntity(entityGID, toGroupID, toGroup, entityType); + MoveEntity(entityGID, toGroupID, toGroup, entityType); } } - void MoveEntity(EGID fromEntityGID, int toGroupID, Dictionary toGroup, Type entityType) where T:IEntityDescriptor, new () + void MoveEntity(EGID fromEntityGID, int toGroupID, Dictionary toGroup, Type entityType) { var fromGroup = _groupEntityDB[fromEntityGID.groupID]; @@ -169,7 +169,7 @@ namespace Svelto.ECS if (fromTypeSafeDictionary.Count == 0) //clean up { - _groupedGroups[entityType].Remove(toGroupID); + _groupedGroups[entityType].Remove(fromEntityGID.groupID); //it's probably better to not remove this, but the dictionary should be trimmed? //fromGroup.Remove(entityType); @@ -189,7 +189,7 @@ namespace Svelto.ECS ///-------------------------------------------- - void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T:IEntityDescriptor, new () + 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"); @@ -200,6 +200,8 @@ namespace Svelto.ECS toGroup = _groupEntityDB[toGroupID] = new Dictionary(); MoveEntity(new EGID(entityID, fromGroupID), toGroupID, toGroup); + + return new EGID(entityID, toGroupID); } EGID SwapFirstEntityInGroup(int fromGroupID, int toGroupId) where T:IEntityDescriptor, new() diff --git a/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs b/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs index 402a066..31b2ba0 100644 --- a/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs +++ b/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs @@ -37,19 +37,19 @@ namespace Svelto.ECS _weakReference.Target.RemoveGroupAndEntitiesFromDB(groupID); } - public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() + public EGID SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() { - _weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); + return _weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); } - public void SwapEntityGroup(EGID id, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new() + public EGID SwapEntityGroup(EGID id, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new() { - _weakReference.Target.SwapEntityGroup(id.entityID, id.groupID, toGroupID); + return _weakReference.Target.SwapEntityGroup(id.entityID, id.groupID, toGroupID); } - public void SwapEntityGroup(int entityID, int toGroupID) where T : IEntityDescriptor, new() + public EGID SwapEntityGroup(int entityID, int toGroupID) where T : IEntityDescriptor, new() { - _weakReference.Target.SwapEntityGroup(entityID, ExclusiveGroup.StandardEntitiesGroup, toGroupID); + return _weakReference.Target.SwapEntityGroup(entityID, ExclusiveGroup.StandardEntitiesGroup, toGroupID); } public EGID SwapFirstEntityGroup(int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() diff --git a/Svelto.ECS/EntitiesDB.cs b/Svelto.ECS/EntitiesDB.cs index e446ae9..46e7043 100644 --- a/Svelto.ECS/EntitiesDB.cs +++ b/Svelto.ECS/EntitiesDB.cs @@ -55,6 +55,20 @@ namespace Svelto.ECS.Internal return ((TypeSafeDictionary)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; + + int count; + return QueryEntities(groupID, out count); + } + public T[] QueryEntitiesAndIndex(EGID entityGID, out uint index) where T : IEntityStruct { T[] array; @@ -85,7 +99,7 @@ namespace Svelto.ECS.Internal public void ExecuteOnEntity(EGID entityGID, ref W value, ActionRef action) where T : IEntityStruct { TypeSafeDictionary casted; - if (FindSafeDictionary(entityGID, out casted)) + if (FindSafeDictionary(entityGID.groupID, out casted)) { if (casted != null) if (casted.ExecuteOnEntityView(entityGID.entityID, ref value, action) == true) @@ -98,7 +112,7 @@ namespace Svelto.ECS.Internal public void ExecuteOnEntity(EGID entityGID, ActionRef action) where T : IEntityStruct { TypeSafeDictionary casted; - if (FindSafeDictionary(entityGID, out casted)) + if (FindSafeDictionary(entityGID.groupID, out casted)) { if (casted != null) if (casted.ExecuteOnEntityView(entityGID.entityID, action) == true) @@ -139,11 +153,7 @@ namespace Svelto.ECS.Internal public void ExecuteOnEntities(ActionRef action) where T : IEntityStruct { - int count; - var entities = QueryEntities(out count); - - for (int i = 0; i < count; i++) - action(ref entities[i]); + ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, action); } public void ExecuteOnEntities(int groupID, ref W value, ActionRef action) where T : IEntityStruct @@ -157,11 +167,7 @@ namespace Svelto.ECS.Internal public void ExecuteOnEntities(ref W value, ActionRef action) where T : IEntityStruct { - int count; - var entities = QueryEntities(out count); - - for (int i = 0; i < count; i++) - action(ref entities[i], ref value); + ExecuteOnEntities(ExclusiveGroup.StandardEntitiesGroup, ref value, action); } public void ExecuteOnAllEntities(ActionRef action) where T : IEntityStruct @@ -197,7 +203,7 @@ namespace Svelto.ECS.Internal public bool Exists(EGID entityGID) where T : IEntityStruct { TypeSafeDictionary casted; - if (!FindSafeDictionary(entityGID, out casted)) return false; + if (!FindSafeDictionary(entityGID.groupID, out casted)) return false; if (casted != null && casted.ContainsKey(entityGID.entityID)) @@ -208,14 +214,14 @@ namespace Svelto.ECS.Internal return false; } - bool FindSafeDictionary(EGID entityGID, out TypeSafeDictionary casted) where T : IEntityStruct + bool FindSafeDictionary(int groupID, out TypeSafeDictionary casted) where T : IEntityStruct { var type = typeof(T); ITypeSafeDictionary entityViews; Dictionary entitiesInGroupPerType; - if (_groupEntityViewsDB.TryGetValue(entityGID.groupID, out entitiesInGroupPerType) == false) + if (_groupEntityViewsDB.TryGetValue(groupID, out entitiesInGroupPerType) == false) { casted = null; return false; @@ -248,7 +254,7 @@ namespace Svelto.ECS.Internal bool TryQueryEntityViewInGroup(EGID entityGID, out T entityView) where T:IEntityStruct { TypeSafeDictionary casted; - if (!FindSafeDictionary(entityGID, out casted)) + if (!FindSafeDictionary(entityGID.groupID, out casted)) { entityView = default(T); return false; @@ -268,16 +274,16 @@ namespace Svelto.ECS.Internal T[] QueryEntitiesAndIndexInternal(EGID entityGID, out uint index) where T : IEntityStruct { TypeSafeDictionary casted; - if (!FindSafeDictionary(entityGID, out casted)) + if (!FindSafeDictionary(entityGID.groupID, out casted)) { index = 0; - return null; + throw new Exception("Entity group found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(entityGID.groupID)); } if (casted == null || casted.TryFindElementIndex(entityGID.entityID, out index) == false) { index = 0; - return null; + throw new Exception("Entity not found type: ".FastConcat(typeof(T)).FastConcat(" groupID: ").FastConcat(entityGID.entityID)); } int count; @@ -296,6 +302,8 @@ namespace Svelto.ECS.Internal //grouped set of entity views, this is the standard way to handle entity views readonly Dictionary> _groupEntityViewsDB; - Dictionary> _groupedGroups; + //needed to be able to iterate over all the entities of the same type regardless the group + //may change in future + readonly Dictionary> _groupedGroups; } } diff --git a/Svelto.ECS/EntityViewBuilder.cs b/Svelto.ECS/EntityViewBuilder.cs index 790b0a3..0b91ea7 100644 --- a/Svelto.ECS/EntityViewBuilder.cs +++ b/Svelto.ECS/EntityViewBuilder.cs @@ -37,18 +37,44 @@ namespace Svelto.ECS var field = fields[i]; var fieldFieldType = field.FieldType; - if (fieldFieldType.IsPrimitive == true || fieldFieldType.IsValueType == true) + + SubCheckFields(fieldFieldType); + } + + if (type.Assembly == Assembly.GetCallingAssembly()) + { + var methods = type.GetMethods(BindingFlags.Public | + BindingFlags.Instance | BindingFlags.DeclaredOnly); + + var properties = type.GetProperties(BindingFlags.Public | + BindingFlags.Instance | BindingFlags.DeclaredOnly); + + if (methods.Length > properties.Length + 1) + throw new EntityStructException(type); + + for (int i = properties.Length - 1; i >= 0; --i) { - if (fieldFieldType.IsValueType && !fieldFieldType.IsEnum) - { - CheckFields(fieldFieldType); - } + var propertyInfo = properties[i]; - continue; + var fieldFieldType = propertyInfo.PropertyType; + SubCheckFields(fieldFieldType); } + } + } - throw new EntityStructException(fieldFieldType); + static void SubCheckFields(Type fieldFieldType) + { + if (fieldFieldType.IsPrimitive == true || fieldFieldType.IsValueType == true) + { + if (fieldFieldType.IsValueType && !fieldFieldType.IsEnum && fieldFieldType.IsPrimitive == false) + { + CheckFields(fieldFieldType); + } + + return; } + + throw new EntityStructException(fieldFieldType); } #endif @@ -115,7 +141,7 @@ namespace Svelto.ECS public class EntityStructException : Exception { - public EntityStructException(Type fieldType):base("EntityStruct must contains only value types! " + fieldType.ToString()) + public EntityStructException(Type fieldType):base("EntityStruct must contains only value types and no public methods! " + fieldType.ToString()) {} } } \ No newline at end of file diff --git a/Svelto.ECS/IEntitiesDB.cs b/Svelto.ECS/IEntitiesDB.cs index 56a064c..0de8bbc 100644 --- a/Svelto.ECS/IEntitiesDB.cs +++ b/Svelto.ECS/IEntitiesDB.cs @@ -33,6 +33,7 @@ namespace Svelto.ECS //to use with EntityViews, EntityStructs and EntityViewStructs T[] QueryEntities(out int count) where T : IEntityStruct; T[] QueryEntities(int group, out int count) where T : IEntityStruct; + T[] QueryEntities(int groupID, ref EGIDMapper mapper) where T : IEntityStruct; T[] QueryEntitiesAndIndex(EGID entityGid, out uint index) where T : IEntityStruct; bool TryQueryEntitiesAndIndex(EGID entityGid, out uint index, out T[] array) where T : IEntityStruct; diff --git a/Svelto.ECS/IEntityFunctions.cs b/Svelto.ECS/IEntityFunctions.cs index 0db6b96..b95b6d1 100644 --- a/Svelto.ECS/IEntityFunctions.cs +++ b/Svelto.ECS/IEntityFunctions.cs @@ -13,9 +13,9 @@ namespace Svelto.ECS void RemoveGroupAndEntities(int groupID); - void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new(); - void SwapEntityGroup(EGID id, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new(); - void SwapEntityGroup(int entityID, int toGroupID) where T : IEntityDescriptor, new(); + EGID SwapEntityGroup(int entityID, int fromGroupID, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new(); + EGID SwapEntityGroup(EGID id, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new(); + EGID SwapEntityGroup(int entityID, int toGroupID) where T : IEntityDescriptor, new(); EGID SwapFirstEntityGroup(int fromGroupID = ExclusiveGroup.StandardEntitiesGroup, int toGroupID = ExclusiveGroup.StandardEntitiesGroup) where T : IEntityDescriptor, new(); } } \ No newline at end of file diff --git a/Svelto.ECS/Sequencer.cs b/Svelto.ECS/Sequencer.cs index ba4c25d..700b41a 100644 --- a/Svelto.ECS/Sequencer.cs +++ b/Svelto.ECS/Sequencer.cs @@ -5,28 +5,26 @@ using System.Collections.Generic; namespace Svelto.ECS { public class Steps : Dictionary - {} - - public class To : Dictionary where C : struct, IConvertible { - public void Add(C condition, IStep engine) - { - Add(condition, new [] {engine}); - } - public void Add(C condition, params IStep[] engines) + public new void Add(IEngine engine, IDictionary dictionary) { - Add(condition, engines); + if (ContainsKey(engine)) + { + Utility.Console.LogError("can't hold multiple steps with the same engine as origin in a Sequencer"); + } + base.Add(engine, dictionary); } - public void Add(params IStep[] engines) + } + + public class To : Dictionary[]> where C : struct, IConvertible + { + public new void Add(C condition, params IStep[] engines) { - Add(default(C), engines); + base.Add(condition, engines); } } - public interface IStep - {} - - public interface IStep:IStep where C:struct,IConvertible + public interface IStep where C:struct,IConvertible { void Step(C condition, EGID id); } @@ -38,32 +36,18 @@ namespace Svelto.ECS _steps = steps; } - public void Next(IEngine engine, EGID id) - { - Next(engine, Condition.Always, id); - } - - public void Next(IEngine engine) - { - Next(engine, Condition.Always); - } - - public void Next(IEngine engine, C condition, EGID id = new EGID()) where C:struct,IConvertible + public void Next(IEngine engine, C condition, EGID id) where C:struct,IConvertible { C branch = condition; - var steps = (_steps[engine] as Dictionary)[branch]; + var steps = (_steps[engine] as Dictionary[]>)[branch]; - if (steps == null) return; + if (steps == null) + Utility.Console.LogError("selected steps not found in sequencer ".FastConcat(this.ToString())); for (var i = 0; i < steps.Length; i++) - ((IStep)steps[i]).Step(condition, id); + steps[i].Step(condition, id); } Steps _steps; } - - public static class Condition - { - public const int Always = 0; - } } \ No newline at end of file