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 swaptags/2.7
@@ -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 | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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) | |||
{ | |||
@@ -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); | |||
} | |||
} |
@@ -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 | |||
@@ -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); | |||
@@ -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 | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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>() | |||
@@ -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; | |||
} | |||
@@ -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()); | |||
} | |||
} |
@@ -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 | |||
} | |||
@@ -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 | |||
@@ -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(); | |||
@@ -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) | |||
{ | |||
@@ -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; | |||
} | |||
} |
@@ -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 | |||
@@ -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; | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -7,7 +7,7 @@ namespace Svelto.ECS | |||
entitiesToBuild = descriptor.entitiesToBuild; | |||
} | |||
public IEntityBuilder[] entitiesToBuild { get; } | |||
public IEntityBuilder[] entitiesToBuild { get; private set; } | |||
} | |||
} | |||