Browse Source

Rename DynamicEntityDescriptorInfoRef in something that makes more sense (ExtendibleEntityDescriptor)

Egid doesn't need to expose the long value anymore
Added a lot more debug informations
Added a new SwapEntityGroup that declare explcitly (by contract) which group the entity must be before the swap
tags/2.7
sebas77 6 years ago
parent
commit
78d54f0702
20 changed files with 325 additions and 189 deletions
  1. +97
    -0
      Svelto.ECS/CheckEntityUtilities.cs
  2. +7
    -14
      Svelto.ECS/DynamicEntityDescriptorInfo.cs
  3. +6
    -6
      Svelto.ECS/EGID.cs
  4. +24
    -6
      Svelto.ECS/EnginesRoot.Engines.cs
  5. +30
    -55
      Svelto.ECS/EnginesRoot.Entities.cs
  6. +1
    -1
      Svelto.ECS/EnginesRoot.GenericEntityFactory.cs
  7. +74
    -21
      Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs
  8. +22
    -37
      Svelto.ECS/EnginesRoot.Submission.cs
  9. +13
    -8
      Svelto.ECS/EntitiesDB.cs
  10. +6
    -4
      Svelto.ECS/EntityBuilder.cs
  11. +2
    -4
      Svelto.ECS/EntityDescriptorInfo.cs
  12. +8
    -4
      Svelto.ECS/EntitySubmitOperation.cs
  13. +1
    -1
      Svelto.ECS/EntityView.cs
  14. +9
    -9
      Svelto.ECS/ExclusiveGroups.cs
  15. +2
    -2
      Svelto.ECS/ExecuteOnEntitiesDB.cs
  16. +14
    -0
      Svelto.ECS/ExtendibleEntityDescriptor.cs
  17. +3
    -3
      Svelto.ECS/IEntitiesDB.cs
  18. +3
    -11
      Svelto.ECS/IEntityFactory.cs
  19. +2
    -2
      Svelto.ECS/IEntityFunctions.cs
  20. +1
    -1
      Svelto.ECS/StaticEntityDescriptorInfo.cs

+ 97
- 0
Svelto.ECS/CheckEntityUtilities.cs View File

@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public partial class EnginesRoot
{
void CheckRemoveEntityID(EGID entityID, IEntityDescriptor descriptorEntity)
{
#if DEBUG && !PROFILER
Dictionary<Type, ITypeSafeDictionary> @group;
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
if (_groupEntityDB.TryGetValue(entityID.groupID, out @group) == true)
{
for (int i = 0; i < descriptorEntitiesToBuild.Length; i++)
{
CheckRemoveEntityID(entityID, descriptorEntitiesToBuild[i].GetEntityType(), @group, descriptorEntity.ToString());
}
}
else
{
Svelto.Utilities.Console.LogError("Entity ".FastConcat(" with not found ID is about to be removed: ")
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
.FastConcat(entityID.groupID));
}
#endif
}

void CheckRemoveEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> @group, string name)
{
#if DEBUG && !PROFILER
ITypeSafeDictionary entities;
if (@group.TryGetValue(entityType, out entities) == true)
{
if (entities.Has(entityID.entityID) == false)
{
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ")
.FastConcat(entityType)
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
.FastConcat(entityID.groupID));
}
}
else
{
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with not found ID is about to be removed: ")
.FastConcat(entityType)
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
.FastConcat(entityID.groupID));
}
#endif
}
void CheckAddEntityID<T>(EGID entityID, T descriptorEntity) where T:IEntityDescriptor
{
#if DEBUG && !PROFILER
Dictionary<Type, ITypeSafeDictionary> @group;
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
//these are the entities added in this frame
if (_groupEntityDB.TryGetValue(entityID.groupID, out @group) == true)
{
for (int i = 0; i < descriptorEntitiesToBuild.Length; i++)
{
CheckAddEntityID(entityID, descriptorEntitiesToBuild[i].GetEntityType(), @group, descriptorEntity.ToString());
}
}
#endif
}

static void CheckAddEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> @group, string name)
{
#if DEBUG && !PROFILER
ITypeSafeDictionary entities;
if (@group.TryGetValue(entityType, out entities))
{
if (entities.Has(entityID.entityID) == true)
{
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with used ID is about to be built: ")
.FastConcat(entityType)
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
.FastConcat(entityID.groupID));
}
}
#endif
}
}
}

+ 7
- 14
Svelto.ECS/DynamicEntityDescriptorInfo.cs View File

@@ -19,7 +19,11 @@ namespace Svelto.ECS

var _builder = new EntityBuilder<EntityInfoView>
{
_initializer = new EntityInfoView { entitiesToBuild = entitiesToBuild }
_initializer = new EntityInfoView
{
entitiesToBuild = entitiesToBuild,
type = typeof(TType)
}
};
entitiesToBuild[entitiesToBuild.Length - 1] = _builder;
}
@@ -27,22 +31,11 @@ namespace Svelto.ECS
public IEntityBuilder[] entitiesToBuild { get; }
}

public class DynamicEntityDescriptorInfoRef<TType>:IEntityDescriptor where TType : IEntityDescriptor, new()
{
public DynamicEntityDescriptorInfoRef(IEntityBuilder[] extraEntities)
{
_dynamicDescriptor = new DynamicEntityDescriptorInfo<TType>(extraEntities);
}

public IEntityBuilder[] entitiesToBuild { get { return _dynamicDescriptor.entitiesToBuild; } }

DynamicEntityDescriptorInfo<TType> _dynamicDescriptor;
}
public struct EntityInfoView : IEntityStruct
{
public EGID ID { get; set; }
public Type type { get; set; }

public IEntityBuilder[] entitiesToBuild;
}
}

+ 6
- 6
Svelto.ECS/EGID.cs View File

@@ -7,11 +7,6 @@ namespace Svelto.ECS
{
long _GID;
public long GID
{
get { return _GID; }
}
public int entityID
{
get { return (int) (_GID & 0xFFFFFFFF); }
@@ -29,7 +24,7 @@ namespace Svelto.ECS
public EGID(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) : this()
{
_GID = MAKE_GLOBAL_ID(entityID, (int) groupID);
_GID = MAKE_GLOBAL_ID(entityID, groupID);
}
static long MAKE_GLOBAL_ID(int entityId, int groupId)
@@ -41,6 +36,11 @@ namespace Svelto.ECS
{
return id.entityID;
}
public static implicit operator long(EGID id)
{
return id._GID;
}

public bool Equals(long other)
{


+ 24
- 6
Svelto.ECS/EnginesRoot.Engines.cs View File

@@ -37,9 +37,12 @@ namespace Svelto.ECS
/// </summary>
public EnginesRoot(IEntitySubmissionScheduler entityViewScheduler)
{
#if DEBUG && !PROFILER
_entitiesOperationsDebug = new FasterDictionary<long, EntitySubmitOperationType>();
#endif
_entitiesOperations = new FasterList<EntitySubmitOperation>();
_entityEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>>();
_otherEngines = new FasterList<IEngine>();
_enginesSet = new HashSet<IEngine>();
_disposableEngines = new FasterList<IDisposable>();
_transientEntitiesOperations = new FasterList<EntitySubmitOperation>();

@@ -47,7 +50,7 @@ namespace Svelto.ECS
_groupsPerEntity = new Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>>();
_groupedEntityToAdd = new DoubleBufferedEntitiesToAdd<FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>>();

_DB = new EntitiesDB(_groupEntityDB, _groupsPerEntity);
_entitiesDB = new EntitiesDB(_groupEntityDB, _groupsPerEntity);

_scheduler = entityViewScheduler;
_scheduler.onTick = new WeakAction(SubmitEntityViews);
@@ -62,8 +65,11 @@ namespace Svelto.ECS
if (viewEngine != null)
CheckEntityViewsEngine(viewEngine);
else
_otherEngines.Add(engine);
DBC.ECS.Check.Assert(_enginesSet.Contains(engine) == false, "The same engine has been added more than once "
.FastConcat(engine.ToString()));
_enginesSet.Add(engine);
if (engine is IDisposable)
_disposableEngines.Add(engine as IDisposable);
@@ -71,7 +77,7 @@ namespace Svelto.ECS
var queryableEntityViewEngine = engine as IQueryingEntitiesEngine;
if (queryableEntityViewEngine != null)
{
queryableEntityViewEngine.entitiesDB = _DB;
queryableEntityViewEngine.entitiesDB = _entitiesDB;
queryableEntityViewEngine.Ready();
}
}
@@ -122,9 +128,21 @@ namespace Svelto.ECS
}

readonly Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> _entityEngines;
readonly FasterList<IEngine> _otherEngines;
readonly HashSet<IEngine> _enginesSet;
readonly FasterList<IDisposable> _disposableEngines;
//one datastructure rule them all:
//split by group
//split by type per group. It's possible to get all the entities of a give type T per group thanks
//to the FasterDictionary capabilities OR it's possible to get a specific entityView indexed by
//ID. This ID doesn't need to be the EGID, it can be just the entityID
//for each group id, save a dictionary indexed by entity type of entities indexed by id
readonly FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupEntityDB;
readonly EntitiesDB _entitiesDB;
//for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are
//found indexed by group id
readonly Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>> _groupsPerEntity; //yes I am being sarcastic
static readonly Type _objectType = typeof(object);
}
}

+ 30
- 55
Svelto.ECS/EnginesRoot.Entities.cs View File

@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Svelto.DataStructures;
using Svelto.DataStructures.Experimental;
using Svelto.DataStructures.Experimental;
using Svelto.ECS.Internal;

#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
@@ -61,9 +59,8 @@ namespace Svelto.ECS
{
var descriptorEntitiesToBuild = entityDescriptor.entitiesToBuild;
#if DEBUG && !PROFILER
CheckEntityID(entityID, entityDescriptor);
#endif
CheckAddEntityID(entityID, entityDescriptor);

var dic = EntityFactory.BuildGroupedEntities(entityID,
_groupedEntityToAdd.current,
descriptorEntitiesToBuild,
@@ -71,38 +68,7 @@ namespace Svelto.ECS
return new EntityStructInitializer(entityID, dic);
}
#if DEBUG && !PROFILER
void CheckEntityID(EGID entityID, IEntityDescriptor descriptorEntity)
{
Dictionary<Type, ITypeSafeDictionary> @group;
var descriptorEntitiesToBuild = descriptorEntity.entitiesToBuild;
if (_groupEntityDB.TryGetValue(entityID.groupID, out @group) == true)
{
for (int i = 0; i < descriptorEntitiesToBuild.Length; i++)
{
CheckEntityID(entityID, descriptorEntitiesToBuild[i].GetEntityType(), @group, descriptorEntity.ToString());
}
}
}

static void CheckEntityID(EGID entityID, Type entityType, Dictionary<Type, ITypeSafeDictionary> @group, string name)
{
ITypeSafeDictionary entities;
if (@group.TryGetValue(entityType, out entities))
{
if (entities.Has(entityID.entityID) == true)
{
Svelto.Utilities.Console.LogError("Entity ".FastConcat(name, " with used ID is about to be built: ")
.FastConcat(entityType)
.FastConcat(" id: ")
.FastConcat(entityID.entityID)
.FastConcat(" groupid: ")
.FastConcat(entityID.groupID));
}
}
}
#endif
///--------------------------------------------

void Preallocate<T>(int groupID, int size) where T : IEntityDescriptor, new()
@@ -141,11 +107,9 @@ namespace Svelto.ECS
///--------------------------------------------
///
void MoveEntity(IEntityBuilder[] entityBuilders, EGID entityGID, int toGroupID = -1,
void MoveEntity(IEntityBuilder[] entityBuilders, EGID entityGID, Type originalDescriptorType, int toGroupID = -1,
Dictionary<Type, ITypeSafeDictionary> toGroup = null)
{
var entityBuildersCount = entityBuilders.Length;
//for each entity view generated by the entity descriptor
Dictionary<Type, ITypeSafeDictionary> fromGroup;
if (_groupEntityDB.TryGetValue(entityGID.groupID, out fromGroup) == false)
@@ -153,23 +117,32 @@ namespace Svelto.ECS
throw new ECSException("from group not found eid: ".FastConcat(entityGID.entityID).FastConcat(" group: ").FastConcat(entityGID.groupID));
}

ITypeSafeDictionary entityInfoViewDic;
if (fromGroup.TryGetValue(_entityInfoView, out entityInfoViewDic) == true)
ITypeSafeDictionary entityInfoViewDic; EntityInfoView entityInfoView = default(EntityInfoView);
//Check if there is an EntityInfoView linked to this entity, if so it's a DynamicEntityDescriptor!
bool correctEntityDescriptorFound = true;
if (fromGroup.TryGetValue(_entityInfoView, out entityInfoViewDic) == true
&& (entityInfoViewDic as TypeSafeDictionary<EntityInfoView>).TryGetValue
(entityGID.entityID, out entityInfoView) == true &&
//I really need to improve this:
(correctEntityDescriptorFound = entityInfoView.type == originalDescriptorType) == true)
{
var realEntityInfoView = entityInfoViewDic as TypeSafeDictionary<EntityInfoView>;
var entitiesToMove = realEntityInfoView[entityGID.entityID].entitiesToBuild;
var entitiesToMove = entityInfoView.entitiesToBuild;
for (int i = 0; i < entitiesToMove.Length; i++)
MoveEntityView(entityGID, toGroupID, toGroup, fromGroup, entitiesToMove[i].GetEntityType());
}
//otherwise it's a normal static entity descriptor
else
{
for (var i = 0; i < entityBuildersCount; i++)
{
var entityType = entityBuilders[i].GetEntityType();

MoveEntityView(entityGID, toGroupID, toGroup, fromGroup, entityType);
}
if (correctEntityDescriptorFound == false)
Utilities.Console.LogError(INVALID_DYNAMIC_DESCRIPTOR_ERROR.FastConcat(entityGID.entityID)
.FastConcat(" group ID ").FastConcat(entityGID.groupID).FastConcat(
" descriptor found: ", entityInfoView.type.Name, " descriptor Excepted ",
originalDescriptorType.Name));
for (var i = 0; i < entityBuilders.Length; i++)
MoveEntityView(entityGID, toGroupID, toGroup, fromGroup, entityBuilders[i].GetEntityType());
}
}

@@ -233,7 +206,7 @@ namespace Svelto.ECS

///--------------------------------------------

void SwapEntityGroup(IEntityBuilder[] builders, int entityID, int fromGroupID, int toGroupID)
void SwapEntityGroup(IEntityBuilder[] builders, Type originalEntityDescriptor, int entityID, int fromGroupID, int toGroupID)
{
DBC.ECS.Check.Require(fromGroupID != toGroupID, "the entity is already in this group");

@@ -242,11 +215,13 @@ namespace Svelto.ECS
if (_groupEntityDB.TryGetValue(toGroupID, out toGroup) == false)
toGroup = _groupEntityDB[toGroupID] = new Dictionary<Type, ITypeSafeDictionary>();

MoveEntity(builders, new EGID(entityID, fromGroupID), toGroupID, toGroup);
MoveEntity(builders, new EGID(entityID, fromGroupID), originalEntityDescriptor, toGroupID, toGroup);
}
readonly EntitiesDB _DB;
Type _entityInfoView = typeof(EntityInfoView);
readonly Type _entityInfoView = typeof(EntityInfoView);
const string INVALID_DYNAMIC_DESCRIPTOR_ERROR = "Found an entity requesting an invalid dynamic descriptor, this " +
"can happen only if you are building different entities with the " +
"same ID in the same group! id: ";
}

public struct EntityStructInitializer


+ 1
- 1
Svelto.ECS/EnginesRoot.GenericEntityFactory.cs View File

@@ -34,7 +34,7 @@ namespace Svelto.ECS
{
return _weakEngine.Target.BuildEntity(new EGID(entityID, (int)groupStructId), descriptorEntity, implementors);
}
public void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, int size) where T : IEntityDescriptor, new()
{
_weakEngine.Target.Preallocate<T>((int)groupStructId, size);


+ 74
- 21
Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs View File

@@ -19,58 +19,111 @@ namespace Svelto.ECS

public void RemoveEntity<T>(int entityID, int groupID) where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation(new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityID, groupID, -1, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild));
#if DEBUG && !PROFILER
_weakReference.Target.CheckRemoveEntityID(new EGID(entityID, groupID), EntityDescriptorTemplate<T>.descriptor);
#endif
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityID, groupID, -1,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}

public void RemoveEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) where T : IEntityDescriptor, new()
public void RemoveEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupID) where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityID, (int)groupID, -1, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild));
#if DEBUG && !PROFILER
_weakReference.Target.CheckRemoveEntityID(new EGID(entityID, (int) groupID), EntityDescriptorTemplate<T>.descriptor);
#endif
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityID, (int)groupID, -1,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}

public void RemoveEntity<T>(EGID entityEGID) where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityEGID.entityID, entityEGID.groupID, -1, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild));
#if DEBUG && !PROFILER
_weakReference.Target.CheckRemoveEntityID(entityEGID, EntityDescriptorTemplate<T>.descriptor);
#endif
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityEGID.entityID, entityEGID.groupID,
-1, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}

public void RemoveGroupAndEntities(int groupID)
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, -1, groupID, -1, null));
new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, -1, groupID, -1, null, null));
}

public void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID)
public void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID)
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, -1, (int)groupID, -1, null));
new EntitySubmitOperation(EntitySubmitOperationType.RemoveGroup, -1, (int)groupID, -1, null, null));
}

public void SwapEntityGroup<T>(int entityID, int fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
public void SwapEntityGroup<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.Swap, entityID, fromGroupID, (int)toGroupID, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild));
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Swap,
entityID,
(int) fromGroupID,
(int) toGroupID,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}

public void SwapEntityGroup<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
public void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.Swap, entityID, (int) fromGroupID, (int) toGroupID, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild));
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Swap,
id.entityID,
id.groupID,
(int) toGroupID,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}

public void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
public void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new()
{
_weakReference.Target.QueueEntitySubmitOperation(
new EntitySubmitOperation(EntitySubmitOperationType.Swap, id.entityID, id.groupID, (int)toGroupID, EntityDescriptorTemplate<T>.descriptor.entitiesToBuild));
_weakReference.Target.QueueEntitySubmitOperation<T>(
new EntitySubmitOperation(EntitySubmitOperationType.Swap,
id.entityID,
id.groupID,
(int) toGroupID,
EntityDescriptorTemplate<T>.descriptor.entitiesToBuild, typeof(T)));
}
}

void QueueEntitySubmitOperation(EntitySubmitOperation entitySubmitOperation)
{
#if DEBUG
#if DEBUG && !PROFILER
entitySubmitOperation.trace = Environment.StackTrace;
#endif
_entitiesOperations.AddRef(ref entitySubmitOperation);
}

void QueueEntitySubmitOperation<T>(EntitySubmitOperation entitySubmitOperation) where T:IEntityDescriptor
{
#if DEBUG && !PROFILER
entitySubmitOperation.trace = Environment.StackTrace;
var egid = new EGID(entitySubmitOperation.id, entitySubmitOperation.fromGroupID);
if (_entitiesOperationsDebug.ContainsKey(egid) == true)
Utilities.Console.LogError("Only one entity operation per submission is allowed. Entity "
.FastConcat(" with not found ID is about to be removed: ")
.FastConcat(" id: ")
.FastConcat(entitySubmitOperation.id)
.FastConcat(" groupid: ")
.FastConcat(entitySubmitOperation.fromGroupID)
//.FastConcat(entitySubmitOperation.fromGroupID.GetType().Name)); do this later
.FastConcat(" entityType: ")
.FastConcat(typeof(T).Name)
.FastConcat(" submission type ", entitySubmitOperation.type.ToString(),
" previous type: ", _entitiesOperationsDebug[egid].ToString()));
else
_entitiesOperationsDebug[egid] = entitySubmitOperation.type;
#endif
_entitiesOperations.AddRef(ref entitySubmitOperation);
}
#if DEBUG && !PROFILER
readonly Svelto.DataStructures.Experimental.FasterDictionary<long, EntitySubmitOperationType> _entitiesOperationsDebug;
#endif
}
}

+ 22
- 37
Svelto.ECS/EnginesRoot.Submission.cs View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Svelto.Common;
using Svelto.DataStructures;
using Svelto.DataStructures.Experimental;
@@ -22,6 +21,9 @@ namespace Svelto.ECS
{
if (_entitiesOperations.Count > 0)
{
#if DEBUG && !PROFILER
_entitiesOperationsDebug.Clear();
#endif
_transientEntitiesOperations.FastClear();
_transientEntitiesOperations.AddRange(_entitiesOperations);
_entitiesOperations.FastClear();
@@ -33,12 +35,14 @@ namespace Svelto.ECS
switch (entitiesOperations[i].type)
{
case EntitySubmitOperationType.Swap:
SwapEntityGroup(entitiesOperations[i].builders, entitiesOperations[i].id,
SwapEntityGroup(entitiesOperations[i].builders,
entitiesOperations[i].entityDescriptor, entitiesOperations[i].id,
entitiesOperations[i].fromGroupID, entitiesOperations[i].toGroupID);
break;
case EntitySubmitOperationType.Remove:
MoveEntity(entitiesOperations[i].builders,
new EGID(entitiesOperations[i].id, entitiesOperations[i].fromGroupID));
new EGID(entitiesOperations[i].id, entitiesOperations[i].fromGroupID),
entitiesOperations[i].entityDescriptor);
break;
case EntitySubmitOperationType.RemoveGroup:
RemoveGroupAndEntitiesFromDB(entitiesOperations[i].fromGroupID);
@@ -47,9 +51,8 @@ namespace Svelto.ECS
}
catch (Exception e)
{
#if DEBUG
var str = "Entity ".FastConcat(entitiesOperations[i].type.ToString(),
" with used ID is about to be built: ")
#if DEBUG && !PROFILER
var str = "Entity Operation is ".FastConcat(entitiesOperations[i].type.ToString())
.FastConcat(" id: ")
.FastConcat(entitiesOperations[i].id)
.FastConcat(" from groupid: ")
@@ -58,8 +61,6 @@ namespace Svelto.ECS
.FastConcat(entitiesOperations[i].toGroupID);

Console.LogError(e.Message.FastConcat(" ", str, " ", entitiesOperations[i].trace));

throw;
#else
Console.LogException(e);
#endif
@@ -71,34 +72,30 @@ namespace Svelto.ECS
{
if (_groupedEntityToAdd.current.Count > 0)
{
//use other as source from now on
//current will be use to write new entityViews
//use other as source from now on current will be use to write new entityViews
_groupedEntityToAdd.Swap();

//Note: if N entity of the same type are added on the same frame
//the Add callback is called N times on the same frame.
//if the Add callback builds a new entity, that entity will not
//be available in the database until the N callbacks are done
//solving it could be complicated as callback and database update
//must be interleaved.

//Note: if N entity of the same type are added on the same frame the Add callback is called N
//times on the same frame. if the Add callback builds a new entity, that entity will not
//be available in the database until the N callbacks are done solving it could be complicated as
//callback and database update must be interleaved.
AddEntityViewsToTheDBAndSuitableEngines(_groupedEntityToAdd.other);

//other can be cleared now, but let's avoid deleting the dictionary every time
_groupedEntityToAdd.ClearOther();
}
}
catch (Exception e)
{
Console.LogException(e);
#if DEBUG
throw;
#endif
}
finally
{
//other can be cleared now, but let's avoid deleting the dictionary every time
_groupedEntityToAdd.ClearOther();
}
}
}
void AddEntityViewsToTheDBAndSuitableEngines(FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupsOfEntitiesToSubmit)
void AddEntityViewsToTheDBAndSuitableEngines(
FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupsOfEntitiesToSubmit)
{
//each group is indexed by entity view type. for each type there is a dictionary indexed by entityID
foreach (var groupOfEntitiesToSubmit in groupsOfEntitiesToSubmit)
@@ -140,22 +137,10 @@ namespace Svelto.ECS
}

readonly FasterList<EntitySubmitOperation> _entitiesOperations;
readonly DoubleBufferedEntitiesToAdd<FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>>>
_groupedEntityToAdd;

//for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are
//found indexed by group id
readonly Dictionary<Type, FasterDictionary<int, ITypeSafeDictionary>> _groupsPerEntity; //yes I am being sarcastic

//one datastructure rule them all:
//split by group
//split by type per group. It's possible to get all the entities of a give type T per group thanks
//to the FasterDictionary capabilities OR it's possible to get a specific entityView indexed by
//ID. This ID doesn't need to be the EGID, it can be just the entityID

//for each group id, save a dictionary indexed by entity type of entities indexed by id
readonly FasterDictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupEntityDB;
readonly IEntitySubmissionScheduler _scheduler;
readonly FasterList<EntitySubmitOperation> _transientEntitiesOperations;
}

+ 13
- 8
Svelto.ECS/EntitiesDB.cs View File

@@ -1,5 +1,10 @@
#if DEBUG && !PROFILER
#define ENABLE_DEBUG_FUNC
#endif

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Svelto.DataStructures;
using Svelto.DataStructures.Experimental;

@@ -17,19 +22,20 @@ namespace Svelto.ECS.Internal
public ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int @group) where T:class, IEntityStruct
{
TypeSafeDictionary<T> typeSafeDictionary;
if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return RetrieveEmptyEntityViewList<T>();
if (QueryEntitySafeDictionary(@group, out typeSafeDictionary) == false) return
new ReadOnlyCollectionStruct<T>(RetrieveEmptyEntityViewArray<T>(), 0);

return typeSafeDictionary.Values;
}

public ReadOnlyCollectionStruct<T> QueryEntityViews<T>(ExclusiveGroup @group) where T : class, IEntityStruct
public ReadOnlyCollectionStruct<T> QueryEntityViews<T>(ExclusiveGroup.ExclusiveGroupStruct @group) where T : class, IEntityStruct
{
return QueryEntityViews<T>((int) group);
}

public T QueryEntityView<T>(int id, ExclusiveGroup @group) where T : class, IEntityStruct
public T QueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct @group) where T : class, IEntityStruct
{
return QueryEntityView<T>(new EGID(id, group));
return QueryEntityView<T>(new EGID(id, (int) @group));
}

public T[] QueryEntities<T>(int @group, out int count) where T : IEntityStruct
@@ -125,9 +131,9 @@ namespace Svelto.ECS.Internal
return TryQueryEntityViewInGroupInternal(entityegid, out entityView);
}
public bool TryQueryEntityView<T>(int id, ExclusiveGroup @group, out T entityView) where T : class, IEntityStruct
public bool TryQueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct @group, out T entityView) where T : class, IEntityStruct
{
return TryQueryEntityViewInGroupInternal(new EGID(id, group), out entityView);
return TryQueryEntityViewInGroupInternal(new EGID(id, (int) @group), out entityView);
}
bool TryQueryEntityViewInGroupInternal<T>(EGID entityGID, out T entityView) where T:class, IEntityStruct
@@ -173,12 +179,11 @@ namespace Svelto.ECS.Internal
return true;
}
[Conditional("ENABLE_DEBUG_FUNC")]
static void SafetyChecks<T>(TypeSafeDictionary<T> typeSafeDictionary, int count) where T : IEntityStruct
{
#if DEBUG
if (typeSafeDictionary.Count != count)
throw new EntitiesDBException("Entities cannot be swapped or removed during an iteration");
#endif
}

static ReadOnlyCollectionStruct<T> RetrieveEmptyEntityViewList<T>()


+ 6
- 4
Svelto.ECS/EntityBuilder.cs View File

@@ -13,12 +13,12 @@ namespace Svelto.ECS
{
public EntityBuilder()
{
_initializer = default(T);
_initializer = defaultIt;

#if DEBUG && !PROFILER
if (needsReflection == false && typeof(T) != typeof(EntityInfoView) )
if (needsReflection == false && ENTITY_VIEW_TYPE != typeof(EntityInfoView) )
{
CheckFields(typeof(T));
CheckFields(ENTITY_VIEW_TYPE);
}
#endif
if (needsReflection == true)
@@ -41,7 +41,7 @@ namespace Svelto.ECS
SubCheckFields(fieldFieldType);
}

if (type.Assembly == Assembly.GetCallingAssembly() && type != typeof(Svelto.ECS.EGID))
if (type.Assembly == Assembly.GetCallingAssembly() && type != EGIDType)
{
var methods = type.GetMethods(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);
@@ -137,6 +137,8 @@ namespace Svelto.ECS
static readonly Type ENTITY_VIEW_TYPE = typeof(T);
static readonly string DESCRIPTOR_NAME = ENTITY_VIEW_TYPE.ToString();
static readonly bool needsReflection = typeof(IEntityViewStruct).IsAssignableFrom(typeof(T));
static readonly T defaultIt = default(T);
static readonly Type EGIDType = typeof(Svelto.ECS.EGID);

internal T _initializer;
}


+ 2
- 4
Svelto.ECS/EntityDescriptorInfo.cs View File

@@ -7,9 +7,6 @@ namespace Svelto.ECS

public class EntityDescriptor : IEntityDescriptor
{
private EntityDescriptor()
{}
protected EntityDescriptor(IEntityBuilder[] entityToBuild)
{
entitiesToBuild = entityToBuild;
@@ -20,6 +17,7 @@ namespace Svelto.ECS

static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new()
{
public static readonly StaticEntityDescriptorInfo<TType> descriptor = new StaticEntityDescriptorInfo<TType>(new TType());
public static readonly StaticEntityDescriptorInfo<TType> descriptor
= new StaticEntityDescriptorInfo<TType>(new TType());
}
}

+ 8
- 4
Svelto.ECS/EntitySubmitOperation.cs View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System;

namespace Svelto.ECS
{
@@ -9,7 +9,8 @@ namespace Svelto.ECS
public readonly int id;
public readonly int toGroupID;
public readonly int fromGroupID;
#if DEBUG
public readonly Type entityDescriptor;
#if DEBUG && !PROFILER
public string trace;
#endif

@@ -17,14 +18,17 @@ namespace Svelto.ECS
int entityId,
int fromGroupId,
int toGroupId,
IEntityBuilder[] builders)
IEntityBuilder[] builders,
Type entityDescriptor)
{
type = operation;
this.builders = builders;
id = entityId;
toGroupID = toGroupId;
fromGroupID = fromGroupId;
#if DEBUG
this.entityDescriptor = entityDescriptor;
#if DEBUG && !PROFILER
trace = string.Empty;
#endif
}


+ 1
- 1
Svelto.ECS/EntityView.cs View File

@@ -38,7 +38,7 @@ namespace Svelto.ECS
}
}

///<summary>EntityViews can inherit from the EntityView class</summary>
[Obsolete("You should only use IEntityViewStruct or IEntityStructs struct implementations now")]
public class EntityView : IEntityViewStruct
{
public EGID ID


+ 9
- 9
Svelto.ECS/ExclusiveGroups.cs View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices.WindowsRuntime;

using System.Collections.Generic;
namespace Svelto.ECS
{
/// <summary>
@@ -29,14 +28,14 @@ namespace Svelto.ECS
_group = new ExclusiveGroupStruct(range);
}
public static implicit operator ExclusiveGroupStruct (ExclusiveGroup group) // explicit byte to digit conversion operator
public static implicit operator ExclusiveGroupStruct (ExclusiveGroup group)
{
return group._group;
}
public static explicit operator int (ExclusiveGroup group) // explicit byte to digit conversion operator
public static explicit operator int (ExclusiveGroup group)
{
return (int)group._group;
return @group._group;
}

public static ExclusiveGroupStruct operator + (ExclusiveGroup a, int b)
@@ -46,6 +45,7 @@ namespace Svelto.ECS

readonly ExclusiveGroupStruct _group;
//I use this as parameter because it must not be possible to pass null Exclusive Groups.
public struct ExclusiveGroupStruct : IEquatable<ExclusiveGroupStruct>, IComparable<ExclusiveGroupStruct>,
IEqualityComparer<ExclusiveGroupStruct>
{
@@ -100,12 +100,12 @@ namespace Svelto.ECS
_globalId += range;
}

public static explicit operator int (ExclusiveGroupStruct groupStruct) // explicit byte to digit conversion operator
public static implicit operator int(ExclusiveGroupStruct groupStruct)
{
return groupStruct._id;
}
public static ExclusiveGroupStruct operator + (ExclusiveGroupStruct a, int b)
public static ExclusiveGroupStruct operator+(ExclusiveGroupStruct a, int b)
{
var group = new ExclusiveGroupStruct();



+ 2
- 2
Svelto.ECS/ExecuteOnEntitiesDB.cs View File

@@ -149,7 +149,7 @@ namespace Svelto.ECS.Internal
}
}

public void ExecuteOnAllEntities<T>(Svelto.ECS.ExclusiveGroup [] groups, EntitiesAction<T> action) where T : IEntityStruct
public void ExecuteOnAllEntities<T>(Svelto.ECS.ExclusiveGroup[] groups, EntitiesAction<T> action) where T : IEntityStruct
{
foreach (var group in groups)
{
@@ -157,7 +157,7 @@ namespace Svelto.ECS.Internal
}
}

public void ExecuteOnAllEntities<T, W>(Svelto.ECS.ExclusiveGroup [] groups, ref W value, EntitiesAction<T, W> action) where T : IEntityStruct
public void ExecuteOnAllEntities<T, W>(Svelto.ECS.ExclusiveGroup[] groups, ref W value, EntitiesAction<T, W> action) where T : IEntityStruct
{
foreach (var group in groups)
{


+ 14
- 0
Svelto.ECS/ExtendibleEntityDescriptor.cs View File

@@ -0,0 +1,14 @@
namespace Svelto.ECS
{
public class ExtendibleEntityDescriptor<TType>:IEntityDescriptor where TType : IEntityDescriptor, new()
{
protected ExtendibleEntityDescriptor(IEntityBuilder[] extraEntities)
{
_dynamicDescriptor = new DynamicEntityDescriptorInfo<TType>(extraEntities);
}

public IEntityBuilder[] entitiesToBuild { get { return _dynamicDescriptor.entitiesToBuild; } }

readonly DynamicEntityDescriptorInfo<TType> _dynamicDescriptor;
}
}

+ 3
- 3
Svelto.ECS/IEntitiesDB.cs View File

@@ -10,21 +10,21 @@ namespace Svelto.ECS
/// over EntityView
/// </summary>
ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int group) where T : class, IEntityStruct;
ReadOnlyCollectionStruct<T> QueryEntityViews<T>(ExclusiveGroup group) where T : class, IEntityStruct;
ReadOnlyCollectionStruct<T> QueryEntityViews<T>(ExclusiveGroup.ExclusiveGroupStruct group) where T : class, IEntityStruct;
/// <summary>
/// All the EntityView related methods are left for back compatibility, but
/// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct
/// over EntityView
/// </summary>
bool TryQueryEntityView<T>(EGID egid, out T entityView) where T : class, IEntityStruct;
bool TryQueryEntityView<T>(int id, ExclusiveGroup group, out T entityView) where T : class, IEntityStruct;
bool TryQueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group, out T entityView) where T : class, IEntityStruct;
/// <summary>
/// All the EntityView related methods are left for back compatibility, but
/// shouldn't be used anymore. Always pick EntityViewStruct or EntityStruct
/// over EntityView
/// </summary>
T QueryEntityView<T>(EGID egid) where T : class, IEntityStruct;
T QueryEntityView<T>(int id, ExclusiveGroup group) where T : class, IEntityStruct;
T QueryEntityView<T>(int id, ExclusiveGroup.ExclusiveGroupStruct group) where T : class, IEntityStruct;
/// <summary>
/// Fast and raw (therefore not safe) return of entities buffer
/// Modifying a buffer would compromise the integrity of the whole DB


+ 3
- 11
Svelto.ECS/IEntityFactory.cs View File

@@ -22,8 +22,7 @@ namespace Svelto.ECS
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="size"></param>
void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId,
int size) where T : IEntityDescriptor, new();
void PreallocateEntitySpace<T>(ExclusiveGroup.ExclusiveGroupStruct groupStructId, int size) where T : IEntityDescriptor, new();
/// <summary>
/// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity
@@ -39,10 +38,7 @@ namespace Svelto.ECS
/// <param name="groupStructId"></param>
/// <param name="ed"></param>
/// <param name="implementors"></param>
EntityStructInitializer BuildEntity<T>(int entityID,
ExclusiveGroup.ExclusiveGroupStruct groupStructId,
object[] implementors)
where T : IEntityDescriptor, new();
EntityStructInitializer BuildEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId, object[] implementors) where T:IEntityDescriptor, new();
EntityStructInitializer BuildEntity<T>(EGID egid, object[] implementors) where T:IEntityDescriptor, new();
/// <summary>
/// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo
@@ -52,11 +48,7 @@ namespace Svelto.ECS
/// <param name="entityDescriptor"></param>
/// <param name="implementors"></param>
///
EntityStructInitializer BuildEntity<T>(int entityID,
ExclusiveGroup.ExclusiveGroupStruct groupStructId,
T descriptorEntity,
object[] implementors)
where T : IEntityDescriptor;
EntityStructInitializer BuildEntity<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct groupStructId, T descriptorEntity, object[] implementors) where T:IEntityDescriptor;
EntityStructInitializer BuildEntity<T>(EGID egid, T entityDescriptor, object[] implementors) where T:IEntityDescriptor;
}
}

+ 2
- 2
Svelto.ECS/IEntityFunctions.cs View File

@@ -12,10 +12,10 @@ namespace Svelto.ECS
void RemoveEntity<T>(EGID entityegid) where T : IEntityDescriptor, new();

void RemoveGroupAndEntities(int groupID);
void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID);
void RemoveGroupAndEntities(ExclusiveGroup.ExclusiveGroupStruct groupID);
void SwapEntityGroup<T>(int entityID, int fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(int entityID, ExclusiveGroup.ExclusiveGroupStruct fromGroupID, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
void SwapEntityGroup<T>(EGID id, ExclusiveGroup.ExclusiveGroupStruct mustBeFromGroup, ExclusiveGroup.ExclusiveGroupStruct toGroupID) where T : IEntityDescriptor, new();
}
}

+ 1
- 1
Svelto.ECS/StaticEntityDescriptorInfo.cs View File

@@ -7,7 +7,7 @@ namespace Svelto.ECS
entitiesToBuild = descriptor.entitiesToBuild;
}

public IEntityBuilder[] entitiesToBuild { get; }
public IEntityBuilder[] entitiesToBuild { get; private set; }
}
}


Loading…
Cancel
Save