From df921b47ebf268fba04520150ef1518857b9f03e Mon Sep 17 00:00:00 2001 From: sebas77 Date: Fri, 21 Sep 2018 18:21:31 +0100 Subject: [PATCH] Fix DynamicEntityDescriptor based entities, now they can be removed and swapped again improve code add more debug checks --- .../DataStructures/TypeSafeDictionary.cs | 1 - Svelto.ECS/DynamicEntityDescriptorInfo.cs | 37 ++++++++++++++ Svelto.ECS/ECSException.cs | 10 ++++ Svelto.ECS/EnginesRoot.Entities.cs | 50 +++++++++++++------ .../EnginesRoot.GenericEntityFactory.cs | 4 +- Svelto.ECS/EntityBuilder.cs | 4 +- Svelto.ECS/EntityFactory.cs | 38 +++++++++----- Svelto.ECS/GenericEntityDescriptor.cs | 36 ++++++------- Svelto.ECS/IEntityBuilder.cs | 2 +- Svelto.ECS/IEntityFactory.cs | 4 +- Svelto.ECS/StaticEntityDescriptorInfo.cs | 22 -------- 11 files changed, 132 insertions(+), 76 deletions(-) create mode 100644 Svelto.ECS/DynamicEntityDescriptorInfo.cs create mode 100644 Svelto.ECS/ECSException.cs diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs index 2efc925..74289c2 100644 --- a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs +++ b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs @@ -25,7 +25,6 @@ namespace Svelto.ECS.Internal void Trim(); void Clear(); bool Has(int entityIdEntityId); - int GetFirstID(); } class TypeSafeDictionary : FasterDictionary, ITypeSafeDictionary where TValue : IEntityStruct diff --git a/Svelto.ECS/DynamicEntityDescriptorInfo.cs b/Svelto.ECS/DynamicEntityDescriptorInfo.cs new file mode 100644 index 0000000..f049330 --- /dev/null +++ b/Svelto.ECS/DynamicEntityDescriptorInfo.cs @@ -0,0 +1,37 @@ +using System; +using Svelto.DataStructures; + +namespace Svelto.ECS +{ + public struct DynamicEntityDescriptorInfo:IEntityDescriptor where TType : IEntityDescriptor, new() + { + public DynamicEntityDescriptorInfo(FasterList extraEntities) : this() + { + DBC.ECS.Check.Require(extraEntities.Count > 0, + "don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); + + var defaultEntities = EntityDescriptorTemplate.descriptor.entitiesToBuild; + var length = defaultEntities.Length; + + entitiesToBuild = new IEntityBuilder[length + extraEntities.Count + 1]; + + Array.Copy(defaultEntities, 0, entitiesToBuild, 0, length); + Array.Copy(extraEntities.ToArrayFast(), 0, entitiesToBuild, length, extraEntities.Count); + + var _builder = new EntityBuilder + { + _initializer = new EntityInfoView { entitiesToBuild = entitiesToBuild } + }; + entitiesToBuild[entitiesToBuild.Length - 1] = _builder; + } + + public IEntityBuilder[] entitiesToBuild { get; private set; } + } + + public struct EntityInfoView : IEntityStruct + { + public EGID ID { get; set; } + + public IEntityBuilder[] entitiesToBuild; + } +} \ No newline at end of file diff --git a/Svelto.ECS/ECSException.cs b/Svelto.ECS/ECSException.cs new file mode 100644 index 0000000..591d1fd --- /dev/null +++ b/Svelto.ECS/ECSException.cs @@ -0,0 +1,10 @@ +using System; + +namespace Svelto.ECS.Internal +{ + class ECSException : Exception + { + public ECSException(string message):base(message) + {} + } +} \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/EnginesRoot.Entities.cs index 5716d6f..c2d8b49 100644 --- a/Svelto.ECS/EnginesRoot.Entities.cs +++ b/Svelto.ECS/EnginesRoot.Entities.cs @@ -44,16 +44,16 @@ namespace Svelto.ECS return BuildEntity(entityID, EntityDescriptorTemplate.descriptor, implementors); } - EntityStructInitializer BuildEntity(EGID entityID, - IEntityDescriptor entityDescriptor, - object[] implementors) + EntityStructInitializer BuildEntity(EGID entityID, + T entityDescriptor, + object[] implementors) where T:IEntityDescriptor { var descriptorEntitiesToBuild = entityDescriptor.entitiesToBuild; #if DEBUG && !PROFILER CheckEntityID(entityID, entityDescriptor); #endif - var dic = EntityFactory.BuildGroupedEntityViews(entityID, + var dic = EntityFactory.BuildGroupedEntities(entityID, _groupedEntityToAdd.current, descriptorEntitiesToBuild, implementors); @@ -132,25 +132,41 @@ namespace Svelto.ECS ///-------------------------------------------- /// - void MoveEntity(IEntityBuilder[] entityBuilders, EGID entityGID, int toGroupID = -1, Dictionary toGroup = null) + void MoveEntity(IEntityBuilder[] entityBuilders, EGID entityGID, int toGroupID = -1, + Dictionary toGroup = null) { var entityBuildersCount = entityBuilders.Length; //for each entity view generated by the entity descriptor - for (var i = 0; i < entityBuildersCount; i++) + DBC.ECS.Check.Require(_groupEntityDB.ContainsKey(entityGID.groupID) == true, "from group not found"); + var fromGroup = _groupEntityDB[entityGID.groupID]; + + ITypeSafeDictionary entityInfoViewDic; + if (fromGroup.TryGetValue(_entityInfoView, out entityInfoViewDic) == true) { - var entityType = entityBuilders[i].GetEntityType(); + var realEntityInfoView = entityInfoViewDic as TypeSafeDictionary; + var entitiesToMove = realEntityInfoView[entityGID.entityID].entitiesToBuild; - MoveEntity(entityGID, toGroupID, toGroup, entityType); + for (int i = 0; i < entitiesToMove.Length; i++) + MoveEntityView(entityGID, toGroupID, toGroup, fromGroup, entitiesToMove[i].GetEntityType()); + } + else + { + for (var i = 0; i < entityBuildersCount; i++) + { + var entityType = entityBuilders[i].GetEntityType(); + + MoveEntityView(entityGID, toGroupID, toGroup, fromGroup, entityType); + } } } - void MoveEntity(EGID fromEntityGID, int toGroupID, Dictionary toGroup, Type entityType) + void MoveEntityView(EGID entityGID, int toGroupID, Dictionary toGroup, + Dictionary fromGroup, Type entityType) { - var fromGroup = _groupEntityDB[fromEntityGID.groupID]; - - var fromTypeSafeDictionary = fromGroup[entityType]; - ITypeSafeDictionary safeDictionary = null; + DBC.ECS.Check.Require(fromGroup.ContainsKey(entityType) == true, "from group not found"); + var fromTypeSafeDictionary = fromGroup[entityType]; + ITypeSafeDictionary safeDictionary = null; if (toGroup != null) { @@ -164,17 +180,18 @@ namespace Svelto.ECS _groupedGroups[entityType][toGroupID] = safeDictionary; } - fromTypeSafeDictionary.MoveEntityFromDictionaryAndEngines(fromEntityGID, toGroupID, safeDictionary, _entityEngines); + DBC.ECS.Check.Assert(fromTypeSafeDictionary.Has(entityGID.entityID), "entity not found"); + fromTypeSafeDictionary.MoveEntityFromDictionaryAndEngines(entityGID, toGroupID, safeDictionary, _entityEngines); if (fromTypeSafeDictionary.Count == 0) //clean up { - _groupedGroups[entityType].Remove(fromEntityGID.groupID); + _groupedGroups[entityType].Remove(entityGID.groupID); //it's probably better to not remove this, but the dictionary should be trimmed? //fromGroup.Remove(entityType); fromTypeSafeDictionary.Trim(); } - + //it doesn't eliminate the fromGroup itself on purpose } @@ -202,6 +219,7 @@ namespace Svelto.ECS readonly EntitiesDB _DB; int _newEntitiesBuiltToProcess; + Type _entityInfoView = typeof(EntityInfoView); } public struct EntityStructInitializer diff --git a/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs b/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs index 9f3739d..e81155e 100644 --- a/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs +++ b/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs @@ -25,12 +25,12 @@ namespace Svelto.ECS return _weakEngine.Target.BuildEntity(egid, implementors); } - public EntityStructInitializer BuildEntity(EGID egid, IEntityDescriptor descriptorEntity, object[] implementors) + public EntityStructInitializer BuildEntity(EGID egid, T descriptorEntity, object[] implementors) where T:IEntityDescriptor { return _weakEngine.Target.BuildEntity(egid, descriptorEntity, implementors); } - public EntityStructInitializer BuildEntity(int entityID, ExclusiveGroup groupID, IEntityDescriptor descriptorEntity, object[] implementors) + public EntityStructInitializer BuildEntity(int entityID, ExclusiveGroup groupID, T descriptorEntity, object[] implementors) where T:IEntityDescriptor { return _weakEngine.Target.BuildEntity(new EGID(entityID, (int)groupID), descriptorEntity, implementors); } diff --git a/Svelto.ECS/EntityBuilder.cs b/Svelto.ECS/EntityBuilder.cs index 18f0168..29f631b 100644 --- a/Svelto.ECS/EntityBuilder.cs +++ b/Svelto.ECS/EntityBuilder.cs @@ -16,7 +16,7 @@ namespace Svelto.ECS _initializer = default(T); #if DEBUG && !PROFILER - if (needsReflection == false) + if (needsReflection == false && typeof(T) != typeof(EntityInfoView) ) { CheckFields(typeof(T)); } @@ -78,7 +78,7 @@ namespace Svelto.ECS } #endif - public void BuildEntityViewAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors) + public void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors) { if (dictionary == null) dictionary = new TypeSafeDictionary(); diff --git a/Svelto.ECS/EntityFactory.cs b/Svelto.ECS/EntityFactory.cs index 838e9d3..5956350 100644 --- a/Svelto.ECS/EntityFactory.cs +++ b/Svelto.ECS/EntityFactory.cs @@ -7,19 +7,19 @@ namespace Svelto.ECS.Internal static class EntityFactory { internal static Dictionary - BuildGroupedEntityViews(EGID egid, + BuildGroupedEntities(EGID egid, FasterDictionary> groupEntityViewsByType, - IEntityBuilder[] entityToBuild, + IEntityBuilder[] entitiesToBuild, object[] implementors) { - var @group = FetchEntityViewGroup(egid.groupID, groupEntityViewsByType); + var @group = FetchEntityGroup(egid.groupID, groupEntityViewsByType); - BuildEntityViewsAndAddToGroup(egid, group, entityToBuild, implementors); + BuildEntitiesAndAddToGroup(egid, group, entitiesToBuild, implementors); return group; } - static Dictionary FetchEntityViewGroup(int groupID, + static Dictionary FetchEntityGroup(int groupID, FasterDictionary> groupEntityViewsByType) { Dictionary group; @@ -33,23 +33,37 @@ namespace Svelto.ECS.Internal return @group; } - static void BuildEntityViewsAndAddToGroup(EGID entityID, + static void BuildEntitiesAndAddToGroup(EGID entityID, Dictionary @group, - IEntityBuilder[] entityToBuild, + IEntityBuilder[] entitiesToBuild, object[] implementors) { - var count = entityToBuild.Length; + var count = entitiesToBuild.Length; +#if DEBUG && !PROFILER + HashSet types = new HashSet(); + + for (var index = 0; index < count; ++index) + { + var entityType = entitiesToBuild[index].GetEntityType(); + if (types.Contains(entityType)) + { + throw new ECSException("EntityBuilders must be unique inside an EntityDescriptor"); + } + + types.Add(entityType); + } +#endif for (var index = 0; index < count; ++index) { - var entityViewBuilder = entityToBuild[index]; + var entityViewBuilder = entitiesToBuild[index]; var entityViewType = entityViewBuilder.GetEntityType(); - BuildEntityView(entityID, @group, entityViewType, entityViewBuilder, implementors); + BuildEntity(entityID, @group, entityViewType, entityViewBuilder, implementors); } } - static void BuildEntityView(EGID entityID, Dictionary @group, + static void BuildEntity(EGID entityID, Dictionary @group, Type entityViewType, IEntityBuilder entityBuilder, object[] implementors) { ITypeSafeDictionary safeDictionary; @@ -59,7 +73,7 @@ namespace Svelto.ECS.Internal //passing the undefined entityViewsByType inside the entityViewBuilder will allow //it to be created with the correct type and casted back to the undefined list. //that's how the list will be eventually of the target type. - entityBuilder.BuildEntityViewAndAddToList(ref safeDictionary, entityID, implementors); + entityBuilder.BuildEntityAndAddToList(ref safeDictionary, entityID, implementors); if (entityViewsPoolWillBeCreated) @group.Add(entityViewType, safeDictionary); diff --git a/Svelto.ECS/GenericEntityDescriptor.cs b/Svelto.ECS/GenericEntityDescriptor.cs index 7d3d6b0..a280bba 100644 --- a/Svelto.ECS/GenericEntityDescriptor.cs +++ b/Svelto.ECS/GenericEntityDescriptor.cs @@ -4,15 +4,15 @@ { static GenericEntityDescriptor() { - EntityBuilders = new IEntityBuilder[] { new EntityBuilder() }; + _entityBuilders = new IEntityBuilder[] { new EntityBuilder() }; } public IEntityBuilder[] entitiesToBuild { - get { return EntityBuilders; } + get { return _entityBuilders; } } - static readonly IEntityBuilder[] EntityBuilders; + static readonly IEntityBuilder[] _entityBuilders; } public abstract class GenericEntityDescriptor : IEntityDescriptor where T : IEntityStruct, new() @@ -20,15 +20,15 @@ { static GenericEntityDescriptor() { - EntityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder()}; + _entityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder()}; } public IEntityBuilder[] entitiesToBuild { - get { return EntityBuilders; } + get { return _entityBuilders; } } - static readonly IEntityBuilder[] EntityBuilders; + static readonly IEntityBuilder[] _entityBuilders; } public abstract class GenericEntityDescriptor : IEntityDescriptor where T : IEntityStruct, new() @@ -37,15 +37,15 @@ { static GenericEntityDescriptor() { - EntityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; + _entityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; } public IEntityBuilder[] entitiesToBuild { - get { return EntityBuilders; } + get { return _entityBuilders; } } - static readonly IEntityBuilder[] EntityBuilders; + static readonly IEntityBuilder[] _entityBuilders; } public abstract class GenericEntityDescriptor : IEntityDescriptor where T : IEntityStruct, new() @@ -55,15 +55,15 @@ { static GenericEntityDescriptor() { - EntityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; + _entityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; } public IEntityBuilder[] entitiesToBuild { - get { return EntityBuilders; } + get { return _entityBuilders; } } - static readonly IEntityBuilder[] EntityBuilders; + static readonly IEntityBuilder[] _entityBuilders; } public abstract class GenericEntityDescriptor : IEntityDescriptor where T : IEntityStruct, new() @@ -74,15 +74,15 @@ { static GenericEntityDescriptor() { - EntityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; + _entityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; } public IEntityBuilder[] entitiesToBuild { - get { return EntityBuilders; } + get { return _entityBuilders; } } - static readonly IEntityBuilder[] EntityBuilders; + static readonly IEntityBuilder[] _entityBuilders; } public abstract class GenericEntityDescriptor : IEntityDescriptor where T : IEntityStruct, new() @@ -94,14 +94,14 @@ { static GenericEntityDescriptor() { - EntityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; + _entityBuilders = new IEntityBuilder[] {new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder(), new EntityBuilder()}; } public IEntityBuilder[] entitiesToBuild { - get { return EntityBuilders; } + get { return _entityBuilders; } } - static readonly IEntityBuilder[] EntityBuilders; + static readonly IEntityBuilder[] _entityBuilders; } } diff --git a/Svelto.ECS/IEntityBuilder.cs b/Svelto.ECS/IEntityBuilder.cs index d53f21b..c3e234d 100644 --- a/Svelto.ECS/IEntityBuilder.cs +++ b/Svelto.ECS/IEntityBuilder.cs @@ -5,7 +5,7 @@ namespace Svelto.ECS { public interface IEntityBuilder { - void BuildEntityViewAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors); + void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors); ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, int size); Type GetEntityType(); diff --git a/Svelto.ECS/IEntityFactory.cs b/Svelto.ECS/IEntityFactory.cs index 0b54848..1ca9fa9 100644 --- a/Svelto.ECS/IEntityFactory.cs +++ b/Svelto.ECS/IEntityFactory.cs @@ -48,7 +48,7 @@ namespace Svelto.ECS /// /// /// - EntityStructInitializer BuildEntity(int entityID, ExclusiveGroup groupID, IEntityDescriptor descriptorEntity, object[] implementors); - EntityStructInitializer BuildEntity(EGID egid, IEntityDescriptor descriptorEntity, object[] implementors); + EntityStructInitializer BuildEntity(int entityID, ExclusiveGroup groupID, T descriptorEntity, object[] implementors) where T:IEntityDescriptor; + EntityStructInitializer BuildEntity(EGID egid, T descriptorEntity, object[] implementors) where T:IEntityDescriptor; } } diff --git a/Svelto.ECS/StaticEntityDescriptorInfo.cs b/Svelto.ECS/StaticEntityDescriptorInfo.cs index a939066..7e27600 100644 --- a/Svelto.ECS/StaticEntityDescriptorInfo.cs +++ b/Svelto.ECS/StaticEntityDescriptorInfo.cs @@ -1,6 +1,3 @@ -using System; -using Svelto.DataStructures; - namespace Svelto.ECS { public interface IEntityDescriptor @@ -23,25 +20,6 @@ namespace Svelto.ECS public static readonly StaticEntityDescriptorInfo descriptor = new StaticEntityDescriptorInfo(new TType()); } - public struct DynamicEntityDescriptorInfo:IEntityDescriptor where TType : IEntityDescriptor, new() - { - public DynamicEntityDescriptorInfo(FasterList extraEntityViews) : this() - { - DBC.ECS.Check.Require(extraEntityViews.Count > 0, - "don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); - - var defaultEntityViewsToBuild = EntityDescriptorTemplate.descriptor.entitiesToBuild; - var length = defaultEntityViewsToBuild.Length; - - entitiesToBuild = new IEntityBuilder[length + extraEntityViews.Count]; - - Array.Copy(defaultEntityViewsToBuild, 0, entitiesToBuild, 0, length); - Array.Copy(extraEntityViews.ToArrayFast(), 0, entitiesToBuild, length, extraEntityViews.Count); - } - - public IEntityBuilder[] entitiesToBuild { get; private set; } - } - public class StaticEntityDescriptorInfo: IEntityDescriptor where TType : IEntityDescriptor { internal StaticEntityDescriptorInfo(TType descriptor)