From 497f97650b7791efeef0a9edd8c30b1e107f0fcb Mon Sep 17 00:00:00 2001 From: sebas77 Date: Sat, 26 May 2018 14:51:44 +0100 Subject: [PATCH] - put some effort to make the Sequencer declaration more readable, making more generic parameter explicit - reworked IEntityViewsDB interface, some breaking renaming and added more functions - added two struct friendly functions as workaround while we wait for the c# byref keyworkd: QueryEntities and ExecutOnEntity - fix the SwapEntityGroup function - various optimizations - implement a simple and efficient way to initialize entity struct values (EntityStructInitializer) - check (in debug only) if entitystruct has only value and primitive types, otherwise throw exception - --- .../DataStructures/TypeSafeDictionary.cs | 40 ++++++- Svelto.ECS/EGID.cs | 1 - ...sRootEngines.cs => EnginesRoot.Engines.cs} | 11 +- ...ootEntities.cs => EnginesRoot.Entities.cs} | 74 +++++++++--- .../EnginesRoot.GenericEntityFactory.cs | 30 +++-- .../EnginesRoot.GenericEntityFunctions.cs | 7 +- ...ubmission.cs => EnginesRoot.Submission.cs} | 0 Svelto.ECS/EntityDescriptor.cs | 17 +-- Svelto.ECS/EntityFactory.cs | 25 ++-- Svelto.ECS/EntityViewBuilder.cs | 57 +++++++-- Svelto.ECS/EntityViewUtility.cs | 4 +- Svelto.ECS/EntityViewsDB.cs | 108 +++++++++++++----- Svelto.ECS/GenericEntityDescriptor.cs | 1 - Svelto.ECS/IEntityFactory.cs | 16 +-- Svelto.ECS/IEntityFunctions.cs | 5 +- Svelto.ECS/IEntityView.cs | 35 +++--- Svelto.ECS/IEntityViewBuilder.cs | 2 +- Svelto.ECS/IEntityViewsDB.cs | 26 +++-- Svelto.ECS/Sequencer.cs | 25 +++- 19 files changed, 331 insertions(+), 153 deletions(-) rename Svelto.ECS/{EnginesRootEngines.cs => EnginesRoot.Engines.cs} (95%) rename Svelto.ECS/{EnginesRootEntities.cs => EnginesRoot.Entities.cs} (72%) rename Svelto.ECS/{EnginesRootSubmission.cs => EnginesRoot.Submission.cs} (100%) diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs index c739607..5c46875 100644 --- a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs +++ b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Svelto.DataStructures; + using Svelto.Utilities; namespace Svelto.ECS.Internal { @@ -13,24 +14,26 @@ namespace Svelto.ECS.Internal /// public interface ITypeSafeDictionary { + ITypeSafeDictionary Create(); + void RemoveEntitiesFromEngines(Dictionary> entityViewEnginesDB); void RemoveEntityFromEngines(EGID entityGid, Dictionary> entityViewEnginesDB); + + void FillWithIndexedEntityViews(ITypeSafeDictionary entityViews); + void AddEntityViewsToEngines(Dictionary> entityViewEnginesDB); + void AddCapacity(int size); bool Remove(int idGid); - ITypeSafeDictionary Create(); + int Count { get; } - void FillWithIndexedEntityViews(ITypeSafeDictionary entityViews); - void AddEntityViewsToEngines(Dictionary> entityViewEnginesDB); } class TypeSafeDictionary : FasterDictionary, ITypeSafeDictionary where TValue : IEntityData { - static Type _type = typeof(TValue); - public TypeSafeDictionary(int size):base(size) {} @@ -115,5 +118,32 @@ namespace Svelto.ECS.Internal { return new TypeSafeDictionary(); } + + public void ExecuteOnEntityView(int entityGidEntityId, ref W value, ActionRef action) + { + uint findIndex; + if (FindIndex(entityGidEntityId, out findIndex)) + { + action(ref _values[findIndex], ref value); + } + } + + public void ExecuteOnEntityView(int entityGidEntityId, ActionRef action) + { + uint findIndex; + if (FindIndex(entityGidEntityId, out findIndex)) + { + action(ref _values[findIndex]); + } + } + + public uint FindElementIndex(int entityGidEntityId) + { + uint findIndex; + if (FindIndex(entityGidEntityId, out findIndex) == false) throw new Exception(""); + return findIndex; + } + + static readonly Type _type = typeof(TValue); } } \ No newline at end of file diff --git a/Svelto.ECS/EGID.cs b/Svelto.ECS/EGID.cs index 8d328d2..a7e4197 100644 --- a/Svelto.ECS/EGID.cs +++ b/Svelto.ECS/EGID.cs @@ -23,7 +23,6 @@ namespace Svelto.ECS public EGID(int entityID, int groupID) : this() { - DBC.Check.Require(groupID != ExclusiveGroups.StandardEntity, "can't use an exclusive group ID"); _GID = MAKE_GLOBAL_ID(entityID, groupID); } diff --git a/Svelto.ECS/EnginesRootEngines.cs b/Svelto.ECS/EnginesRoot.Engines.cs similarity index 95% rename from Svelto.ECS/EnginesRootEngines.cs rename to Svelto.ECS/EnginesRoot.Engines.cs index 96905c4..f8de1a6 100644 --- a/Svelto.ECS/EnginesRootEngines.cs +++ b/Svelto.ECS/EnginesRoot.Engines.cs @@ -13,17 +13,18 @@ namespace Svelto.ECS { public partial class EnginesRoot : IDisposable { -#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - /// - /// I still need to find a good solution for this. Need to move somewhere else - /// static EnginesRoot() { +#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR +/// +/// I still need to find a good solution for this. Need to move somewhere else +/// UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Svelto.ECS.Profiler"); debugEngineObject.gameObject.AddComponent(); UnityEngine.GameObject.DontDestroyOnLoad(debugEngineObject); +#endif } -#endif + /// /// 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 diff --git a/Svelto.ECS/EnginesRootEntities.cs b/Svelto.ECS/EnginesRoot.Entities.cs similarity index 72% rename from Svelto.ECS/EnginesRootEntities.cs rename to Svelto.ECS/EnginesRoot.Entities.cs index a905daf..647c43a 100644 --- a/Svelto.ECS/EnginesRootEntities.cs +++ b/Svelto.ECS/EnginesRoot.Entities.cs @@ -37,23 +37,26 @@ namespace Svelto.ECS ///-------------------------------------------- - - void BuildEntity(EGID entityID, object[] implementors) - where T : IEntityDescriptor, new() + EntityStructInitializer BuildEntity(EGID entityID, object[] implementors) + where T : class, IEntityDescriptor, new() { - EntityFactory.BuildGroupedEntityViews(entityID, + var dic = EntityFactory.BuildGroupedEntityViews(entityID, _groupedEntityToAdd.current, - EntityDescriptorTemplate.Info, + EntityDescriptorTemplate.Info.entityViewsToBuild, implementors); + + return new EntityStructInitializer(entityID, dic); } - void BuildEntity(EGID entityID, EntityDescriptorInfo entityDescriptorInfo, + EntityStructInitializer BuildEntity(EGID entityID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) { - EntityFactory.BuildGroupedEntityViews(entityID, + var dic = EntityFactory.BuildGroupedEntityViews(entityID, _groupedEntityToAdd.current, - entityDescriptorInfo, + entityViewsToBuild, implementors); + + return new EntityStructInitializer(entityID, dic); } ///-------------------------------------------- @@ -64,7 +67,7 @@ namespace Svelto.ECS /// TODO: understand if this method is useful in a performance critical /// scenario /// - void Preallocate(int groupID, int size) where T : IEntityDescriptor, new() + void Preallocate(int groupID, int size) where T : class, IEntityDescriptor, new() { var entityViewsToBuild = EntityDescriptorTemplate.Info.entityViewsToBuild; var count = entityViewsToBuild.Length; @@ -145,12 +148,10 @@ namespace Svelto.ECS "can't move an entity to the same group where it already belongs to"); var entityegid = new EGID(entityID, fromGroupID); - var entityViewBuilders = - ((TypeSafeDictionary) _groupEntityDB[fromGroupID][_typeEntityInfoView]) - [entityegid.entityID].entityToBuild; - var entityViewBuildersCount = entityViewBuilders.Length; - var groupedEntities = _groupEntityDB[fromGroupID]; + var entityInfoViewDictionary = (TypeSafeDictionary) groupedEntities[_typeEntityInfoView]; + var entityViewBuilders = entityInfoViewDictionary[entityegid.entityID].entityToBuild; + var entityViewBuildersCount = entityViewBuilders.Length; Dictionary groupedEntityViewsTyped; if (_groupEntityDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) @@ -159,21 +160,37 @@ namespace Svelto.ECS _groupEntityDB.Add(toGroupID, groupedEntityViewsTyped); } + + ITypeSafeDictionary toSafeList; for (var i = 0; i < entityViewBuildersCount; i++) { var entityViewBuilder = entityViewBuilders[i]; var entityViewType = entityViewBuilder.GetEntityType(); - var fromSafeList = groupedEntities[entityViewType]; - ITypeSafeDictionary toSafeList; - + var fromSafeList = groupedEntities[entityViewType]; if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) groupedEntityViewsTyped[entityViewType] = toSafeList = fromSafeList.Create(); - entityViewBuilder.MoveEntityView(entityegid, fromSafeList, toSafeList); + entityViewBuilder.MoveEntityView(entityegid, toGroupID, fromSafeList, toSafeList); fromSafeList.Remove(entityegid.entityID); } + + if (groupedEntityViewsTyped.TryGetValue(_typeEntityInfoView, out toSafeList) == false) + groupedEntityViewsTyped[_typeEntityInfoView] = toSafeList = entityInfoViewDictionary.Create(); + + EntityViewBuilder.MoveEntityView(entityegid, toGroupID, entityInfoViewDictionary, toSafeList); + entityInfoViewDictionary.Remove(entityegid.entityID); + } + + EGID SwapFirstEntityGroup(int fromGroupID, int toGroupId) + { + var firstID = + ((TypeSafeDictionary) _groupEntityDB[fromGroupID][_typeEntityInfoView]).FasterValues[0].ID.entityID; + + SwapEntityGroup(firstID, fromGroupID, toGroupId); + + return new EGID(firstID, toGroupId); } readonly EntityViewsDB _DB; @@ -182,4 +199,25 @@ namespace Svelto.ECS readonly Dictionary> _groupEntityDB; static readonly Type _typeEntityInfoView = typeof(EntityInfoView); } + + public struct EntityStructInitializer + { + public EntityStructInitializer(EGID id, Dictionary current) + { + _current = current; + _id = id; + } + + public void Init(ref T initializer) where T: struct, IEntityData + { + var typeSafeDictionary = (TypeSafeDictionary) _current[typeof(T)]; + + initializer.ID = _id; + + typeSafeDictionary.GetFasterValuesBuffer()[typeSafeDictionary.FindElementIndex(_id.entityID)] = initializer; + } + + readonly Dictionary _current; + readonly EGID _id; + } } \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs b/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs index 653cb8f..ab048bd 100644 --- a/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs +++ b/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs @@ -17,44 +17,42 @@ namespace Svelto.ECS _weakEngine = weakReference; } - public void BuildEntity(int entityID, object[] implementors) where T : IEntityDescriptor, new() + public EntityStructInitializer BuildEntity(int entityID, object[] implementors) where T : class, IEntityDescriptor, new() { - _weakEngine.Target.BuildEntity(new EGID(entityID), implementors); + return _weakEngine.Target.BuildEntity(new EGID(entityID), implementors); } - public void BuildEntity(int entityID, int groupID, object[] implementors) where T : IEntityDescriptor, new() + public EntityStructInitializer BuildEntity(int entityID, int groupID, object[] implementors) where T : class, IEntityDescriptor, new() { - _weakEngine.Target.BuildEntity(new EGID(entityID, groupID), implementors); + return _weakEngine.Target.BuildEntity(new EGID(entityID, groupID), implementors); } - public void BuildEntity(EGID egid, object[] implementors) where T : IEntityDescriptor, new() + public EntityStructInitializer BuildEntity(EGID egid, object[] implementors) where T : class, IEntityDescriptor, new() { - _weakEngine.Target.BuildEntity(egid, implementors); + return _weakEngine.Target.BuildEntity(egid, implementors); } - - public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors) + public EntityStructInitializer BuildEntity(int entityID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) { - _weakEngine.Target.BuildEntity(new EGID(entityID), entityDescriptorInfo, implementors); + return _weakEngine.Target.BuildEntity(new EGID(entityID), entityViewsToBuild, implementors); } - public void BuildEntity(EGID egid, EntityDescriptorInfo entityDescriptorInfo, object[] implementors) + public EntityStructInitializer BuildEntity(EGID egid, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) { - _weakEngine.Target.BuildEntity(egid, entityDescriptorInfo, implementors); + return _weakEngine.Target.BuildEntity(egid, entityViewsToBuild, implementors); } - public void BuildEntity(int entityID, int groupID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors) + public EntityStructInitializer BuildEntity(int entityID, int groupID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) { - _weakEngine.Target.BuildEntity(new EGID(entityID, groupID), entityDescriptorInfo, implementors); + return _weakEngine.Target.BuildEntity(new EGID(entityID, groupID), entityViewsToBuild, implementors); } - - public void PreallocateEntitySpace(int size) where T : IEntityDescriptor, new() + public void PreallocateEntitySpace(int size) where T : class, IEntityDescriptor, new() { _weakEngine.Target.Preallocate(ExclusiveGroups.StandardEntity, size); } - public void PreallocateEntitySpace(int groupID, int size) where T : IEntityDescriptor, new() + public void PreallocateEntitySpace(int groupID, int size) where T : class, IEntityDescriptor, new() { _weakEngine.Target.Preallocate(groupID, size); } diff --git a/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs b/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs index a8cf615..bb806e6 100644 --- a/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs +++ b/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs @@ -12,7 +12,7 @@ namespace Svelto.ECS { readonly DataStructures.WeakReference _weakReference; - public GenericEntityFunctions(DataStructures.WeakReference weakReference) + internal GenericEntityFunctions(DataStructures.WeakReference weakReference) { _weakReference = weakReference; } @@ -46,6 +46,11 @@ namespace Svelto.ECS { _weakReference.Target.SwapEntityGroup(entityID, ExclusiveGroups.StandardEntity, toGroupID); } + + public EGID SwapFirstEntityGroup(int fromGroupID, int toGroupID) + { + return _weakReference.Target.SwapFirstEntityGroup( fromGroupID, toGroupID); + } } } } \ No newline at end of file diff --git a/Svelto.ECS/EnginesRootSubmission.cs b/Svelto.ECS/EnginesRoot.Submission.cs similarity index 100% rename from Svelto.ECS/EnginesRootSubmission.cs rename to Svelto.ECS/EnginesRoot.Submission.cs diff --git a/Svelto.ECS/EntityDescriptor.cs b/Svelto.ECS/EntityDescriptor.cs index 7ccd7b1..8a48dc3 100644 --- a/Svelto.ECS/EntityDescriptor.cs +++ b/Svelto.ECS/EntityDescriptor.cs @@ -19,13 +19,15 @@ namespace Svelto.ECS public IEntityViewBuilder[] entityViewsToBuild { get; } } - public static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() + public static class EntityDescriptorTemplate where TType : class, IEntityDescriptor, new() { public static readonly EntityDescriptorInfo Info = new EntityDescriptorInfo(new TType()); } - public class DynamicEntityDescriptorInfo : EntityDescriptorInfo where TType : IEntityDescriptor, new() + public struct DynamicEntityDescriptorInfo where TType : class, IEntityDescriptor, new() { + public readonly IEntityViewBuilder[] entityViewsToBuild; + public DynamicEntityDescriptorInfo(FasterList extraEntityViews) { Check.Require(extraEntityViews.Count > 0, @@ -38,23 +40,16 @@ namespace Svelto.ECS Array.Copy(defaultEntityViewsToBuild, 0, entityViewsToBuild, 0, length); Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); - - name = EntityDescriptorTemplate.Info.name; } } - public class EntityDescriptorInfo + public struct EntityDescriptorInfo { - internal IEntityViewBuilder[] entityViewsToBuild; - internal string name; + public readonly IEntityViewBuilder[] entityViewsToBuild; internal EntityDescriptorInfo(IEntityDescriptor descriptor) { - name = descriptor.ToString(); entityViewsToBuild = descriptor.entityViewsToBuild; } - - protected EntityDescriptorInfo() - { } } } diff --git a/Svelto.ECS/EntityFactory.cs b/Svelto.ECS/EntityFactory.cs index 15ffa7a..f824c9a 100644 --- a/Svelto.ECS/EntityFactory.cs +++ b/Svelto.ECS/EntityFactory.cs @@ -5,14 +5,16 @@ namespace Svelto.ECS.Internal { static class EntityFactory { - internal static void BuildGroupedEntityViews(EGID egid, + internal static Dictionary BuildGroupedEntityViews(EGID egid, Dictionary> groupEntityViewsByType, - EntityDescriptorInfo entityViewsToBuildDescriptor, + IEntityViewBuilder[] entityViewsToBuild, object[] implementors) { var @group = FetchEntityViewGroup(egid.groupID, groupEntityViewsByType); - BuildEntityViewsAndAddToGroup(egid, group, entityViewsToBuildDescriptor, implementors); + BuildEntityViewsAndAddToGroup(egid, group, entityViewsToBuild, implementors); + + return group; } static Dictionary FetchEntityViewGroup(int groupID, Dictionary> groupEntityViewsByType) @@ -29,32 +31,31 @@ namespace Svelto.ECS.Internal } static void BuildEntityViewsAndAddToGroup(EGID entityID, - Dictionary entityViewsByType, - EntityDescriptorInfo entityViewsToBuildDescriptor, + Dictionary @group, + IEntityViewBuilder[] entityViewsToBuild, object[] implementors) { - var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; - var count = entityViewsToBuild.Length; + var count = entityViewsToBuild.Length; for (var index = 0; index < count; ++index) { var entityViewBuilder = entityViewsToBuild[index]; var entityViewType = entityViewBuilder.GetEntityType(); - BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder, implementors); + BuildEntityView(entityID, @group, entityViewType, entityViewBuilder, implementors); } _viewBuilder._initializer = new EntityInfoView {entityToBuild = entityViewsToBuild}; - BuildEntityView(entityID, entityViewsByType, _viewType, _viewBuilder, null); + BuildEntityView(entityID, @group, _viewType, _viewBuilder, null); } - static void BuildEntityView(EGID entityID, Dictionary entityViewsByType, + static void BuildEntityView(EGID entityID, Dictionary @group, Type entityViewType, IEntityViewBuilder entityViewBuilder, object[] implementors) { ITypeSafeDictionary safeDictionary; var entityViewsPoolWillBeCreated = - entityViewsByType.TryGetValue(entityViewType, out safeDictionary) == false; + @group.TryGetValue(entityViewType, out safeDictionary) == false; //passing the undefined entityViewsByType inside the entityViewBuilder will allow //it to be created with the correct type and casted back to the undefined list. @@ -62,7 +63,7 @@ namespace Svelto.ECS.Internal entityViewBuilder.BuildEntityViewAndAddToList(ref safeDictionary, entityID, implementors); if (entityViewsPoolWillBeCreated) - entityViewsByType.Add(entityViewType, safeDictionary); + @group.Add(entityViewType, safeDictionary); } static readonly EntityViewBuilder _viewBuilder = new EntityViewBuilder(); diff --git a/Svelto.ECS/EntityViewBuilder.cs b/Svelto.ECS/EntityViewBuilder.cs index 64db11a..3608d2c 100644 --- a/Svelto.ECS/EntityViewBuilder.cs +++ b/Svelto.ECS/EntityViewBuilder.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +#if DEBUG && !PROFILER +using System.Reflection; +#endif using Svelto.DataStructures; using Svelto.ECS.Internal; using Svelto.Utilities; @@ -8,14 +11,33 @@ namespace Svelto.ECS { public class EntityViewBuilder : IEntityViewBuilder where T : IEntityData, new() { - public EntityViewBuilder(ref T initializer) - { - _initializer = initializer; - } - public EntityViewBuilder() { _initializer = default(T); + +#if DEBUG && !PROFILER + if (needsReflection == false && typeof(T) != typeof(EntityInfoView)) + { + var type = typeof(T); + + var fields = type.GetFields(BindingFlags.Public | + BindingFlags.Instance); + + for (int i = fields.Length - 1; i >= 0; --i) + { + var field = fields[i]; + + if (field.FieldType.IsPrimitive == true || field.FieldType.IsValueType == true) + continue; + + throw new EntityStructException(); + } + } +#endif + if (needsReflection == true) + { + EntityView.InitCache(); + } } public void BuildEntityViewAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors) @@ -62,24 +84,37 @@ namespace Svelto.ECS return ENTITY_VIEW_TYPE; } - public void MoveEntityView(EGID entityID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic) + void IEntityViewBuilder.MoveEntityView(EGID entityID, int toGroupID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic) + { + MoveEntityView(entityID, toGroupID, fromSafeDic, toSafeDic); + } + + public static void MoveEntityView(EGID entityID, int toGroupID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic) { var fromCastedDic = fromSafeDic as TypeSafeDictionary; var toCastedDic = toSafeDic as TypeSafeDictionary; - toCastedDic.Add(entityID.entityID, fromCastedDic[entityID.entityID]); + var entity = fromCastedDic[entityID.entityID]; + entity.ID = new EGID(entityID.entityID, toGroupID); + toCastedDic.Add(entityID.entityID, entity); fromCastedDic.Remove(entityID.entityID); } - FasterList>> entityViewBlazingFastReflection + static FasterList>> entityViewBlazingFastReflection { - get { return EntityView.FieldCache.list; } + get { return EntityView.cachedFields; } } static readonly Type ENTITY_VIEW_TYPE = typeof(T); - static string DESCRIPTOR_NAME = ENTITY_VIEW_TYPE.ToString(); + static readonly string DESCRIPTOR_NAME = ENTITY_VIEW_TYPE.ToString(); + static readonly bool needsReflection = typeof(IEntityView).IsAssignableFrom(typeof(T)); internal T _initializer; - readonly bool needsReflection = typeof(IEntityView).IsAssignableFrom(typeof(T)); + } + + public class EntityStructException : Exception + { + public EntityStructException():base("EntityStruct must contains only value types!") + {} } } \ No newline at end of file diff --git a/Svelto.ECS/EntityViewUtility.cs b/Svelto.ECS/EntityViewUtility.cs index 5c45e93..736a828 100644 --- a/Svelto.ECS/EntityViewUtility.cs +++ b/Svelto.ECS/EntityViewUtility.cs @@ -9,7 +9,7 @@ static class EntityViewUtility { public static void FillEntityView(this IEntityViewBuilder entityViewBuilder , ref T entityView - , FasterList>> entityViewBlazingFastReflection + , FasterList>> entityViewBlazingFastReflection , object[] implementors , string entityDescriptorName) { @@ -17,7 +17,7 @@ static class EntityViewUtility //Very efficent way to collect the fields of every EntityViewType var setters = - FasterList>> + FasterList>> .NoVirt.ToArrayFast(entityViewBlazingFastReflection, out count); #if DEBUG && !PROFILER if (count == 0) diff --git a/Svelto.ECS/EntityViewsDB.cs b/Svelto.ECS/EntityViewsDB.cs index e14f958..725d3d3 100644 --- a/Svelto.ECS/EntityViewsDB.cs +++ b/Svelto.ECS/EntityViewsDB.cs @@ -1,22 +1,23 @@ using System; using System.Collections.Generic; using Svelto.DataStructures; +using Svelto.Utilities; namespace Svelto.ECS.Internal { class EntityViewsDB : IEntityViewsDB { - internal EntityViewsDB(Dictionary> groupEntityViewsDB) + internal EntityViewsDB(Dictionary> groupEntityViewsDB) { _groupEntityViewsDB = groupEntityViewsDB; } - public ReadOnlyCollectionStruct QueryEntities() where T:IEntityData + public ReadOnlyCollectionStruct QueryEntityViews() where T:class, IEntityData { - return QueryEntities(ExclusiveGroups.StandardEntity); + return QueryEntityViews(ExclusiveGroups.StandardEntity); } - public ReadOnlyCollectionStruct QueryEntities(int @group) where T:IEntityData + public ReadOnlyCollectionStruct QueryEntityViews(int @group) where T:class, IEntityData { Dictionary entitiesInGroupPerType; @@ -30,12 +31,12 @@ namespace Svelto.ECS.Internal return (outList as TypeSafeDictionary).FasterValues; } - public T[] QueryEntitiesCacheFriendly(out int count) where T : struct, IEntityData + public T[] QueryEntities(out int count) where T : IEntityData { - return QueryEntitiesCacheFriendly(ExclusiveGroups.StandardEntity, out count); + return QueryEntities(ExclusiveGroups.StandardEntity, out count); } - public T[] QueryEntitiesCacheFriendly(int @group, out int count) where T : struct, IEntityData + public T[] QueryEntities(int @group, out int count) where T : IEntityData { count = 0; @@ -51,6 +52,28 @@ namespace Svelto.ECS.Internal return ((TypeSafeDictionary)typeSafeDictionary).GetFasterValuesBuffer(out count); } + public T[] QueryEntities(EGID entityGID, out uint index) where T : IEntityData + { + TypeSafeDictionary casted; + if (!FindSafeDictionary(entityGID, out casted)) + { + index = 0; + return null; + } + + if (casted != null) + index = casted.FindElementIndex(entityGID.entityID); + else + { + index = 0; + return null; + } + + int count; + + return QueryEntities(out count); + } + public T QueryEntityView(EGID entityGID) where T : class, IEntityData { T entityView; @@ -60,61 +83,84 @@ namespace Svelto.ECS.Internal return entityView; } + public void ExecuteOnEntity(EGID entityGID, ref W value, ActionRef action) where T : IEntityData + { + TypeSafeDictionary casted; + if (!FindSafeDictionary(entityGID, out casted)) return; + + if (casted != null) + casted.ExecuteOnEntityView(entityGID.entityID, ref value, action); + } + + public void ExecuteOnEntity(EGID entityGID, ActionRef action) where T : IEntityData + { + TypeSafeDictionary casted; + if (!FindSafeDictionary(entityGID, out casted)) return; + + if (casted != null) + casted.ExecuteOnEntityView(entityGID.entityID, action); + } + public bool Exists(EGID entityGID) where T : IEntityData + { + TypeSafeDictionary casted; + if (!FindSafeDictionary(entityGID, out casted)) return false; + + if (casted != null && + casted.ContainsKey(entityGID.entityID)) + { + return true; + } + + return false; + } + + bool FindSafeDictionary(EGID entityGID, out TypeSafeDictionary casted) where T : IEntityData { var type = typeof(T); ITypeSafeDictionary entityViews; - + Dictionary entitiesInGroupPerType; if (_groupEntityViewsDB.TryGetValue(entityGID.groupID, out entitiesInGroupPerType) == false) { + casted = null; return false; } entitiesInGroupPerType.TryGetValue(type, out entityViews); - var casted = entityViews as TypeSafeDictionary; - - if (casted != null && - casted.ContainsKey(entityGID.entityID)) - { - return true; - } - - return false; + casted = entityViews as TypeSafeDictionary; + return true; } - public void Fetch(out T entity) where T : IEntityData + public bool HasAny() where T : IEntityData { - entity = QueryEntities()[0]; + int count; + QueryEntities(out count); + return count > 0; } - public bool Has() where T : IEntityData + public bool HasAny(int @group) where T : IEntityData { - return QueryEntities().Count > 0; + int count; + QueryEntities(group, out count); + return count > 0; } - public bool TryQueryEntityView(EGID entityegid, out T entityView) where T : IEntityData + public bool TryQueryEntityView(EGID entityegid, out T entityView) where T : class, IEntityData { return TryQueryEntityViewInGroup(entityegid, out entityView); } bool TryQueryEntityViewInGroup(EGID entityGID, out T entityView) where T:IEntityData { - var type = typeof(T); - - ITypeSafeDictionary entityViews; - - Dictionary entitiesInGroupPerType; - if (_groupEntityViewsDB.TryGetValue(entityGID.groupID, out entitiesInGroupPerType) == false) + TypeSafeDictionary casted; + if (!FindSafeDictionary(entityGID, out casted)) { entityView = default(T); return false; } - entitiesInGroupPerType.TryGetValue(type, out entityViews); - var casted = entityViews as TypeSafeDictionary; - if (casted != null && casted.TryGetValue(entityGID.entityID, out entityView)) { diff --git a/Svelto.ECS/GenericEntityDescriptor.cs b/Svelto.ECS/GenericEntityDescriptor.cs index 093b08c..5a0620b 100644 --- a/Svelto.ECS/GenericEntityDescriptor.cs +++ b/Svelto.ECS/GenericEntityDescriptor.cs @@ -13,7 +13,6 @@ } static readonly IEntityViewBuilder[] entityViewBuilders; - } public abstract class GenericEntityDescriptor : IEntityDescriptor where T : IEntityData, new() diff --git a/Svelto.ECS/IEntityFactory.cs b/Svelto.ECS/IEntityFactory.cs index dbdcc7d..d1039f5 100644 --- a/Svelto.ECS/IEntityFactory.cs +++ b/Svelto.ECS/IEntityFactory.cs @@ -16,8 +16,8 @@ namespace Svelto.ECS /// /// /// - void PreallocateEntitySpace(int size) where T : IEntityDescriptor, new(); - void PreallocateEntitySpace(int groupID, int size) where T : IEntityDescriptor, new(); + void PreallocateEntitySpace(int size) where T : class, IEntityDescriptor, new(); + void PreallocateEntitySpace(int groupID, int size) where T : class, IEntityDescriptor, new(); /// /// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity @@ -28,7 +28,7 @@ namespace Svelto.ECS /// /// /// - void BuildEntity(int entityID, object[] implementors) where T:IEntityDescriptor, new(); + EntityStructInitializer BuildEntity(int entityID, object[] implementors) where T:class, IEntityDescriptor, new(); /// @@ -41,9 +41,9 @@ namespace Svelto.ECS /// /// /// - void BuildEntity(int entityID, int groupID, object[] implementors) where T:IEntityDescriptor, new(); + EntityStructInitializer BuildEntity(int entityID, int groupID, object[] implementors) where T:class, IEntityDescriptor, new(); - void BuildEntity(EGID egid, object[] implementors) where T:IEntityDescriptor, new(); + EntityStructInitializer BuildEntity(EGID egid, object[] implementors) where T:class, IEntityDescriptor, new(); /// @@ -54,8 +54,8 @@ namespace Svelto.ECS /// /// /// - void BuildEntity(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors); - void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors); - void BuildEntity(EGID egid, EntityDescriptorInfo entityDescriptorInfo, object[] implementors); + EntityStructInitializer BuildEntity(int entityID, int groupID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors); + EntityStructInitializer BuildEntity(int entityID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors); + EntityStructInitializer BuildEntity(EGID egid, IEntityViewBuilder[] entityViewsToBuild, object[] implementors); } } diff --git a/Svelto.ECS/IEntityFunctions.cs b/Svelto.ECS/IEntityFunctions.cs index 3cf8408..69fdb24 100644 --- a/Svelto.ECS/IEntityFunctions.cs +++ b/Svelto.ECS/IEntityFunctions.cs @@ -1,3 +1,5 @@ +using Svelto.ECS.Internal; + namespace Svelto.ECS { public interface IEntityFunctions @@ -11,7 +13,8 @@ namespace Svelto.ECS void RemoveGroupAndEntities(int groupID); - void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID); + void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID = ExclusiveGroups.StandardEntity); void SwapEntityGroup(int entityID, int toGroupID); + EGID SwapFirstEntityGroup(int fromGroupID = ExclusiveGroups.StandardEntity, int toGroupID = ExclusiveGroups.StandardEntity); } } \ No newline at end of file diff --git a/Svelto.ECS/IEntityView.cs b/Svelto.ECS/IEntityView.cs index 0636877..87ed0f5 100644 --- a/Svelto.ECS/IEntityView.cs +++ b/Svelto.ECS/IEntityView.cs @@ -6,7 +6,6 @@ using Svelto.Utilities; namespace Svelto.ECS { - //todo: can I remove the ID from the struct? public interface IEntityData { EGID ID { get; set; } @@ -35,33 +34,33 @@ namespace Svelto.ECS public static class EntityView where T: IEntityData, new() { - internal static void BuildEntityView(EGID ID, out T entityView) + internal static readonly FasterList>> cachedFields; + + static EntityView() { - if (FieldCache.list == null) - { - FieldCache.list = new FasterList>>(); + cachedFields = new FasterList>>(); - var type = typeof(T); + var type = typeof(T); - var fields = type.GetFields(BindingFlags.Public | - BindingFlags.Instance); + var fields = type.GetFields(BindingFlags.Public | + BindingFlags.Instance); - for (int i = fields.Length - 1; i >= 0; --i) - { - var field = fields[i]; + for (int i = fields.Length - 1; i >= 0; --i) + { + var field = fields[i]; - ActionRef setter = FastInvoke.MakeSetter(field); + ActionCast setter = FastInvoke.MakeSetter(field); - FieldCache.list.Add(new KeyValuePair>(field.FieldType, setter)); - } + cachedFields.Add(new KeyValuePair>(field.FieldType, setter)); } - - entityView = new T { ID = ID }; } - public static class FieldCache + internal static void InitCache() + {} + + internal static void BuildEntityView(EGID ID, out T entityView) { - public static FasterList>> list; + entityView = new T { ID = ID }; } } } diff --git a/Svelto.ECS/IEntityViewBuilder.cs b/Svelto.ECS/IEntityViewBuilder.cs index 7f847b0..e52433f 100644 --- a/Svelto.ECS/IEntityViewBuilder.cs +++ b/Svelto.ECS/IEntityViewBuilder.cs @@ -9,6 +9,6 @@ namespace Svelto.ECS ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, int size); Type GetEntityType(); - void MoveEntityView(EGID entityID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic); + void MoveEntityView(EGID entityID, int toGroupID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic); } } \ No newline at end of file diff --git a/Svelto.ECS/IEntityViewsDB.cs b/Svelto.ECS/IEntityViewsDB.cs index 2541bc6..e6f38db 100644 --- a/Svelto.ECS/IEntityViewsDB.cs +++ b/Svelto.ECS/IEntityViewsDB.cs @@ -1,23 +1,31 @@ +using System; using Svelto.DataStructures; +using Svelto.Utilities; namespace Svelto.ECS { public interface IEntityViewsDB { - //to use with EntityViews, EntityStructs and EntityViewStructs - ReadOnlyCollectionStruct QueryEntities() where T : IEntityData; - ReadOnlyCollectionStruct QueryEntities(int group) where T : IEntityData; + //to use with EntityViews + ReadOnlyCollectionStruct QueryEntityViews() where T : class, IEntityData; + ReadOnlyCollectionStruct QueryEntityViews(int group) where T : class, IEntityData; - //to use with EntityStructs and EntityViewStructs - T[] QueryEntitiesCacheFriendly(out int count) where T : struct, IEntityData; - T[] QueryEntitiesCacheFriendly(int group, out int count) where T : struct, IEntityData; + //to use with EntityViews, EntityStructs and EntityViewStructs + T[] QueryEntities(out int count) where T : IEntityData; + T[] QueryEntities(int group, out int count) where T : IEntityData; + T[] QueryEntities(EGID entityGID, out uint index) where T : IEntityData; //to use with EntityViews - bool TryQueryEntityView(EGID egid, out T entityView) where T : IEntityData; + bool TryQueryEntityView(EGID egid, out T entityView) where T : class, IEntityData; T QueryEntityView(EGID egid) where T : class, IEntityData; + //to use with EntityViews, EntityStructs and EntityViewStructs + void ExecuteOnEntity(EGID egid, ref W value, ActionRef action) where T : IEntityData; + void ExecuteOnEntity(EGID egid, ActionRef action) where T : IEntityData; + bool Exists(EGID egid) where T : IEntityData; - void Fetch(out T entity) where T:IEntityData; - bool Has() where T:IEntityData; + + bool HasAny() where T:IEntityData; + bool HasAny(int group) where T:IEntityData; } } \ No newline at end of file diff --git a/Svelto.ECS/Sequencer.cs b/Svelto.ECS/Sequencer.cs index 199d089..49948b9 100644 --- a/Svelto.ECS/Sequencer.cs +++ b/Svelto.ECS/Sequencer.cs @@ -1,9 +1,10 @@ using System; +using System.Collections; using System.Collections.Generic; namespace Svelto.ECS { - public class Steps : Dictionary> + public class Steps : Dictionary {} public class To : Dictionary @@ -18,6 +19,9 @@ namespace Svelto.ECS } } + public class To : Dictionary where C:struct,IConvertible + {} + public interface IStep {} @@ -26,11 +30,18 @@ namespace Svelto.ECS void Step(ref T token, int condition); } + public interface IStep:IStep where C:struct,IConvertible + { + void Step(ref T token, C condition); + } + public interface ISequencer { void Next(IEngine engine, ref T param); void Next(IEngine engine, ref T param, int condition); + + void Next(IEngine engine, ref T param, C condition) where C : struct, IConvertible; } public class Sequencer : ISequencer @@ -48,13 +59,23 @@ namespace Svelto.ECS public void Next(IEngine engine, ref T param, int condition) { int branch = condition; - var steps = _steps[engine][branch]; + var steps = (_steps[engine] as Dictionary)[branch]; if (steps != null) for (int i = 0; i < steps.Length; i++) ((IStep)steps[i]).Step(ref param, condition); } + public void Next(IEngine engine, ref T param, C condition) where C:struct,IConvertible + { + C branch = condition; + var steps = (_steps[engine] as Dictionary)[branch]; + + if (steps != null) + for (int i = 0; i < steps.Length; i++) + ((IStep)steps[i]).Step(ref param, condition); + } + Steps _steps; }