Database and ID refactoringtags/Rel2
@@ -0,0 +1,33 @@ | |||
using System.Collections; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
class DoubleBufferedEntityViews<T> where T : class, IDictionary, new() | |||
{ | |||
readonly T _entityViewsToAddBufferA = new T(); | |||
readonly T _entityViewsToAddBufferB = new T(); | |||
internal DoubleBufferedEntityViews() | |||
{ | |||
this.other = _entityViewsToAddBufferA; | |||
this.current = _entityViewsToAddBufferB; | |||
} | |||
internal T other; | |||
internal T current; | |||
internal void Swap() | |||
{ | |||
var toSwap = other; | |||
other = current; | |||
current = toSwap; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
using Svelto.ECS.Internal; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
class GenericEntityFactory : IEntityFactory | |||
{ | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakEngine; | |||
public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(entityID, implementors); | |||
} | |||
public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); | |||
} | |||
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors); | |||
} | |||
public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, | |||
object[] implementors) | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); | |||
} | |||
public void PreallocateEntitySpace<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(ExclusiveGroups.StandardEntity, size); | |||
} | |||
public void PreallocateEntitySpaceInGroup<T>(int groupID, int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(groupID, size); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,51 @@ | |||
using Svelto.ECS.Internal; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot | |||
{ | |||
class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
public void RemoveEntity(int entityID) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, ExclusiveGroups.StandardEntity); | |||
} | |||
public void RemoveEntity(int entityID, int groupID) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, groupID); | |||
} | |||
public void RemoveEntity(EGID entityEGID) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityEGID); | |||
} | |||
public void RemoveGroupAndEntities(int groupID) | |||
{ | |||
_weakReference.Target.RemoveGroupAndEntitiesFromDB(groupID); | |||
} | |||
public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
{ | |||
_weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); | |||
} | |||
public void SwapEntityGroup(int entityID, int toGroupID) | |||
{ | |||
_weakReference.Target.SwapEntityGroup(entityID, ExclusiveGroups.StandardEntity, toGroupID); | |||
} | |||
} | |||
} | |||
} |
@@ -14,11 +14,11 @@ namespace Svelto.ECS.Internal | |||
public interface ITypeSafeDictionary | |||
{ | |||
void FillWithIndexedEntityViews(ITypeSafeList entityViews); | |||
bool Remove(int entityId); | |||
IEntityView GetIndexedEntityView(int entityID); | |||
bool Remove(EGID entityId); | |||
IEntityView GetIndexedEntityView(EGID entityID); | |||
} | |||
class TypeSafeDictionary<TValue> : Dictionary<int, TValue>, ITypeSafeDictionary where TValue : IEntityView | |||
class TypeSafeDictionaryForClass<TValue> : Dictionary<int, TValue>, ITypeSafeDictionary where TValue : EntityView | |||
{ | |||
internal static readonly ReadOnlyDictionary<int, TValue> Default = | |||
new ReadOnlyDictionary<int, TValue>(new Dictionary<int, TValue>()); | |||
@@ -34,7 +34,7 @@ namespace Svelto.ECS.Internal | |||
{ | |||
var entityView = buffer[i]; | |||
Add(entityView.ID, entityView); | |||
Add(entityView._ID.GID, entityView); | |||
} | |||
} | |||
catch (Exception e) | |||
@@ -43,16 +43,16 @@ namespace Svelto.ECS.Internal | |||
} | |||
} | |||
public new bool Remove(int entityId) | |||
public bool Remove(EGID entityId) | |||
{ | |||
base.Remove(entityId); | |||
base.Remove(entityId.GID); | |||
return Count > 0; | |||
} | |||
public IEntityView GetIndexedEntityView(int entityID) | |||
public IEntityView GetIndexedEntityView(EGID entityID) | |||
{ | |||
return this[entityID]; | |||
return this[entityID.GID]; | |||
} | |||
} | |||
} |
@@ -4,7 +4,7 @@ namespace Svelto.ECS | |||
{ | |||
public class TypeSafeDictionaryException : Exception | |||
{ | |||
public TypeSafeDictionaryException(Exception exception) : base(exception.Message, exception) | |||
public TypeSafeDictionaryException(Exception exception) : base("trying to add an EntityView with the same ID more than once", exception) | |||
{ | |||
} | |||
} |
@@ -12,10 +12,10 @@ namespace Svelto.ECS.Internal | |||
void AddRange(ITypeSafeList entityViewListValue); | |||
ITypeSafeList Create(); | |||
bool MappedRemove(int entityID); | |||
bool MappedRemove(EGID entityID); | |||
ITypeSafeDictionary CreateIndexedDictionary(); | |||
IEntityView[] ToArrayFast(out int count); | |||
void ReserveCapacity(int capacity); | |||
void AddCapacity(int capacity); | |||
} | |||
class TypeSafeFasterListForECS<T> : FasterList<T> where T : IEntityView | |||
@@ -32,17 +32,19 @@ namespace Svelto.ECS.Internal | |||
_mappedIndices = new Dictionary<int, int>(); | |||
} | |||
public bool MappedRemove(int entityID) | |||
public bool MappedRemove(EGID entityID) | |||
{ | |||
var index = _mappedIndices[entityID]; | |||
var index = _mappedIndices[entityID.GID]; | |||
Check.Assert(entityID == this[index].ID, | |||
Check.Assert(entityID.GID == this[index].ID.GID, | |||
"Something went wrong with the Svelto.ECS code, please contact the author"); | |||
_mappedIndices.Remove(entityID); | |||
_mappedIndices.Remove(entityID.GID); | |||
if (UnorderedRemoveAt(index)) | |||
_mappedIndices[this[index].ID] = index; | |||
{ | |||
_mappedIndices[this[index].ID.GID] = index; | |||
} | |||
return Count > 0; | |||
} | |||
@@ -53,8 +55,18 @@ namespace Svelto.ECS.Internal | |||
base.AddRange(entityViewListValue as FasterList<T>); | |||
for (var i = index; i < Count; ++i) | |||
_mappedIndices[this[i].ID] = i; | |||
{ | |||
try | |||
{ | |||
_mappedIndices.Add(this[i].ID.GID, i); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeFasterListForECSException(e); | |||
} | |||
} | |||
} | |||
public new void Add(T entityView) | |||
@@ -63,18 +75,25 @@ namespace Svelto.ECS.Internal | |||
base.Add(entityView); | |||
_mappedIndices[entityView.ID] = index; | |||
try | |||
{ | |||
_mappedIndices.Add(entityView.ID.GID, index); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeFasterListForECSException(e); | |||
} | |||
} | |||
public void ReserveCapacity(int capacity) | |||
public void AddCapacity(int capacity) | |||
{ | |||
if (ToArrayFast().Length < capacity) | |||
Resize(capacity); | |||
if (ToArrayFast().Length < Count + capacity) | |||
Resize(Count + capacity); | |||
} | |||
public int GetIndexFromID(int entityID) | |||
public int GetIndexFromID(EGID entityID) | |||
{ | |||
return _mappedIndices[entityID]; | |||
return _mappedIndices[entityID.GID]; | |||
} | |||
} | |||
@@ -82,12 +101,10 @@ namespace Svelto.ECS.Internal | |||
where T : struct, IEntityStruct | |||
{ | |||
public TypeSafeFasterListForECSForStructs(int size) : base(size) | |||
{ | |||
} | |||
{} | |||
public TypeSafeFasterListForECSForStructs() | |||
{ | |||
} | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
@@ -101,7 +118,7 @@ namespace Svelto.ECS.Internal | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
throw new Exception("Not Allowed"); | |||
throw new NotSupportedException(); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
@@ -118,12 +135,10 @@ namespace Svelto.ECS.Internal | |||
class TypeSafeFasterListForECSForClasses<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T : EntityView, new() | |||
{ | |||
public TypeSafeFasterListForECSForClasses(int size) : base(size) | |||
{ | |||
} | |||
{} | |||
public TypeSafeFasterListForECSForClasses() | |||
{ | |||
} | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
@@ -137,7 +152,7 @@ namespace Svelto.ECS.Internal | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
return new TypeSafeDictionary<T>(); | |||
return new TypeSafeDictionaryForClass<T>(); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
@@ -0,0 +1,10 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class TypeSafeFasterListForECSException : Exception | |||
{ | |||
public TypeSafeFasterListForECSException(Exception exception):base("Trying to add an Entity View with the same ID more than once", exception) | |||
{} | |||
} | |||
} |
@@ -0,0 +1,49 @@ | |||
using DBC; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public struct EGID | |||
{ | |||
int _GID; | |||
public int GID | |||
{ | |||
get { return _GID; } | |||
} | |||
public int ID | |||
{ | |||
get { return _GID & 0xFFFFFF; } | |||
} | |||
public int group | |||
{ | |||
get { return (int) ((_GID & 0xFF000000) >> 24); } | |||
} | |||
public EGID(int entityID, int groupID) : this() | |||
{ | |||
_GID = MAKE_GLOBAL_ID(entityID, groupID); | |||
} | |||
public EGID(int entityID) : this() | |||
{ | |||
_GID = MAKE_GLOBAL_ID(entityID, ExclusiveGroups.StandardEntity); | |||
} | |||
int MAKE_GLOBAL_ID(int entityId, int groupId) | |||
{ | |||
#if DEBUG && !PROFILER | |||
Check.Require(entityId <= 0xFFFFFF); | |||
Check.Require(groupId <= 0xFF); | |||
#endif | |||
return entityId | groupId << 24; | |||
} | |||
public bool IsEqualTo(EGID otherGID) | |||
{ | |||
return otherGID._GID == _GID; | |||
} | |||
} | |||
} |
@@ -1,5 +1,4 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
@@ -38,17 +37,15 @@ namespace Svelto.ECS | |||
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_entityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_metaEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_globalEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_entityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_metaEntityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_globalEntityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_entityInfos = new Dictionary<int, IEntityViewBuilder[]>(); | |||
_entityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_metaEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_DB = new EntityViewsDB(_entityViewsDB, _metaEntityViewsDB, _entityViewsDBDic, _metaEntityViewsDBDic, _groupEntityViewsDB); | |||
_DB = new EntityViewsDB(_globalEntityViewsDB, _globalEntityViewsDBDic, _groupEntityViewsDB); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.Schedule(new WeakAction(SubmitEntityViews)); | |||
@@ -125,27 +122,5 @@ namespace Svelto.ECS | |||
static readonly Type _entityViewType= typeof(EntityView); | |||
static readonly Type _object = typeof(object); | |||
class DoubleBufferedEntityViews<T> where T : class, IDictionary, new() | |||
{ | |||
readonly T _entityViewsToAddBufferA = new T(); | |||
readonly T _entityViewsToAddBufferB = new T(); | |||
internal DoubleBufferedEntityViews() | |||
{ | |||
this.other = _entityViewsToAddBufferA; | |||
this.current = _entityViewsToAddBufferB; | |||
} | |||
internal T other; | |||
internal T current; | |||
internal void Swap() | |||
{ | |||
var toSwap = other; | |||
other = current; | |||
current = toSwap; | |||
} | |||
} | |||
} | |||
} |
@@ -14,24 +14,14 @@ namespace Svelto.ECS | |||
{ | |||
public void Dispose() | |||
{ | |||
foreach (var entity in _entityViewsDB) | |||
foreach (var entity in _globalEntityViewsDB) | |||
if (entity.Value.isQueryiableEntityView) | |||
foreach (var entityView in entity.Value) | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); | |||
foreach (var entity in _metaEntityViewsDB) | |||
{ | |||
foreach (var entityView in entity.Value) | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); | |||
} | |||
} | |||
/// <summary> | |||
/// an EnginesRoot reference cannot be held by anything else than the Composition Root | |||
/// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference | |||
/// of the EnginesRoot to be passed around. | |||
/// </summary> | |||
/// <returns></returns> | |||
///-------------------------------------------- | |||
public IEntityFactory GenerateEntityFactory() | |||
{ | |||
return new GenericEntityFactory(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
@@ -42,97 +32,60 @@ namespace Svelto.ECS | |||
return new GenericEntityFunctions(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
/// <summary> | |||
/// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity | |||
/// itself in terms of EntityViews to build. The Implementors are passed to fill the | |||
/// references of the EntityViews components. Please read the articles on my blog | |||
/// to understand better the terminologies | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="implementors"></param> | |||
///-------------------------------------------- | |||
void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, EntityDescriptorTemplate<T>.Default, implementors); | |||
BuildEntityInGroup<T> | |||
(entityID, ExclusiveGroups.StandardEntity, implementors); | |||
} | |||
/// <summary> | |||
/// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo | |||
/// can be built in place of the generic parameter T. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="entityDescriptor"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors) | |||
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors) | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, entityDescriptor, implementors); | |||
BuildEntityInGroup | |||
(entityID, ExclusiveGroups.StandardEntity, entityDescriptor, implementors); | |||
} | |||
/// <summary> | |||
/// A meta entity is a way to manage a set of entitites that are not easily | |||
/// queriable otherwise. For example you may want to group existing entities | |||
/// by size and type and then use the meta entity entityView to manage the data | |||
/// shared among the single entities of the same type and size. This will | |||
/// prevent the scenario where the coder is forced to parse all the entities to | |||
/// find the ones of the same size and type. | |||
/// Since the entities are managed through the shared entityView, the same | |||
/// shared entityView must be found on the single entities of the same type and size. | |||
/// The shared entityView of the meta entity is then used by engines that are meant | |||
/// to manage a group of entities through a single entityView. | |||
/// The same engine can manage several meta entities entityViews too. | |||
/// The Engine manages the logic of the Meta EntityView data and other engines | |||
/// can read back this data through the normal entity as the shared entityView | |||
/// will be present in their descriptor too. | |||
/// It's a way to control a group of Entities through a entityView only. | |||
/// This set of entities can share exactly the same entityView reference if | |||
/// built through this function. In this way, if you need to set a variable | |||
/// on a group of entities, instead to inject N entityViews and iterate over | |||
/// them to set the same value, you can inject just one entityView, set the value | |||
/// and be sure that the value is shared between entities. | |||
/// </summary> | |||
/// <param name="metaEntityID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews(metaEntityID, _metaEntityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
/// <summary> | |||
/// Using this function is like building a normal entity, but the entityViews | |||
/// are grouped by groupID to be more efficently processed inside engines and | |||
/// improve cache locality. Either class entityViews and struct entityViews can be | |||
/// grouped. | |||
/// Build the entity using the entityID, inside the group with Id groupID, using the | |||
/// implementors (if necessary). The entityViews generated will be stored to be | |||
/// added later in the engines. | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
_entityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, | |||
_entityInfos, | |||
implementors); | |||
} | |||
void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, | |||
object[] implementors = null) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
_entityViewsToAdd.current, | |||
entityDescriptor, implementors); | |||
entityDescriptor, | |||
_entityInfos, | |||
implementors); | |||
} | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
///-------------------------------------------- | |||
/// <summary> | |||
/// This function is experimental and untested. I never used it in production | |||
/// it may not be necessary. | |||
/// TODO: understand if this method is useful in a performance critical | |||
/// scenario | |||
/// </summary> | |||
void Preallocate<T>(int groupID, int size) where T : IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = ((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild; | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.Default.entityViewsToBuild; | |||
var count = entityViewsToBuild.Length; | |||
for (var index = 0; index < count; index++) | |||
@@ -140,166 +93,119 @@ namespace Svelto.ECS | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
//reserve space for the global pool | |||
ITypeSafeList dbList; | |||
if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
if (_globalEntityViewsDB.TryGetValue(entityViewType, out dbList) == false) | |||
_globalEntityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.ReserveCapacity(size); | |||
if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
dbList.AddCapacity(size); | |||
//reserve space for the single group | |||
Dictionary<Type, ITypeSafeList> @group; | |||
if (_groupEntityViewsDB.TryGetValue(groupID, out group) == false) | |||
group = _groupEntityViewsDB[groupID] = new Dictionary<Type, ITypeSafeList>(); | |||
if (group.TryGetValue(entityViewType, out dbList) == false) | |||
group[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.AddCapacity(size); | |||
if (_groupedEntityViewsToAdd.current.TryGetValue(groupID, out group) == false) | |||
group = _groupEntityViewsDB[groupID] = new Dictionary<Type, ITypeSafeList>(); | |||
//reserve space to the temporary buffer | |||
if (group.TryGetValue(entityViewType, out dbList) == false) | |||
group[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.ReserveCapacity(size); | |||
dbList.AddCapacity(size); | |||
} | |||
} | |||
void RemoveEntity(ref EntityInfoView entityInfoView, Dictionary<Type, ITypeSafeList> viewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
///-------------------------------------------- | |||
/// | |||
void RemoveEntity(int entityID, int groupID) | |||
{ | |||
if (entityInfoView.isInAGroup) | |||
InternalRemoveFromGroupAndDBAndEngines(entityInfoView.entityViews, entityInfoView.ID, | |||
entityInfoView.groupID, viewsDB, entityViewsDBDic); | |||
else | |||
InternalRemoveFromDBAndEngines(entityInfoView.entityViews, entityInfoView.ID, viewsDB, | |||
entityViewsDBDic); | |||
RemoveEntity(new EGID(entityID, groupID)); | |||
} | |||
void RemoveEntity(int entityID) | |||
void RemoveEntity(EGID entityGID) | |||
{ | |||
var entityInfoView = _DB.QueryEntityView<EntityInfoView>(entityID); | |||
RemoveEntity(ref entityInfoView, _entityViewsDB, _entityViewsDBDic); | |||
} | |||
void RemoveMetaEntity(int metaEntityID) | |||
{ | |||
var entityInfoView = _DB.QueryMetaEntityView<EntityInfoView>(metaEntityID); | |||
RemoveEntity(ref entityInfoView, _metaEntityViewsDB, _metaEntityViewsDBDic); | |||
} | |||
void RemoveGroupAndEntitiesFromDB(int groupID) | |||
{ | |||
foreach (var group in _groupEntityViewsDB[groupID]) | |||
var entityViewBuilders = _entityInfos[entityGID.GID]; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
//for each entity view generated by the entity descriptor | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
var entityViewType = group.Key; | |||
int count; | |||
var entities = group.Value.ToArrayFast(out count); | |||
var entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
for (var i = 0; i < count; i++) | |||
if (entityViewBuilders[i].isQueryiableEntityView) | |||
{ | |||
var entityID = entities[i].ID; | |||
InternalRemoveEntityViewFromDBAndEngines(_entityViewsDB, _entityViewsDBDic, entityViewType, | |||
entityID); | |||
var group = _groupEntityViewsDB[entityGID.group]; | |||
InternalRemoveEntityViewFromDBDicAndEngines(entityViewType, entityGID); | |||
RemoveEntityViewFromDB(@group, entityViewType, entityGID); | |||
} | |||
RemoveEntityViewFromDB(@_globalEntityViewsDB, entityViewType, entityGID); | |||
} | |||
_groupEntityViewsDB.Remove(groupID); | |||
_entityInfos.Remove(entityGID.GID); | |||
} | |||
void InternalRemoveEntityViewFromDBAndEngines(Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic, | |||
Type entityViewType, | |||
int entityID) | |||
static void RemoveEntityViewFromDB(Dictionary<Type, ITypeSafeList> @group, Type entityViewType, EGID id) | |||
{ | |||
var entityViews = entityViewsDB[entityViewType]; | |||
if (entityViews.MappedRemove(entityID) == false) | |||
entityViewsDB.Remove(entityViewType); | |||
if (entityViews.isQueryiableEntityView) | |||
{ | |||
var typeSafeDictionary = entityViewsDBDic[entityViewType]; | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); | |||
if (typeSafeDictionary.Remove(entityID) == false) | |||
entityViewsDBDic.Remove(entityViewType); | |||
for (var current = entityViewType; current != _entityViewType; current = current.BaseType) | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); | |||
} | |||
//remove it from entity views group DB | |||
var typeSafeList = @group[entityViewType]; | |||
if (typeSafeList.MappedRemove(id) == false) //clean up | |||
@group.Remove(entityViewType); | |||
} | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
void RemoveGroupAndEntitiesFromDB(int groupID) | |||
{ | |||
Check.Require(fromGroupID != toGroupID, | |||
"can't move an entity to the same group where it already belongs to"); | |||
var entityViewBuilders = _DB.QueryEntityView<EntityInfoView>(entityID).entityViews; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
var groupedEntities = _groupEntityViewsDB[fromGroupID]; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); | |||
} | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
foreach (var group in _groupEntityViewsDB[groupID]) | |||
{ | |||
var entityViewBuilder = entityViewBuilders[i]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
var fromSafeList = groupedEntities[entityViewType]; | |||
ITypeSafeList toSafeList; | |||
if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) | |||
groupedEntityViewsTyped[entityViewType] = toSafeList = fromSafeList.Create(); | |||
{ | |||
var entityViewType = group.Key; | |||
entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); | |||
int count; | |||
var entities = group.Value.ToArrayFast(out count); | |||
fromSafeList.MappedRemove(entityID); | |||
} | |||
for (var i = 0; i < count; i++) | |||
{ | |||
var entityID = entities[i].ID; | |||
var entityInfoView = _DB.QueryEntityView<EntityInfoView>(entityID); | |||
entityInfoView.groupID = toGroupID; | |||
} | |||
RemoveEntityViewFromDB(@_globalEntityViewsDB, entityViewType, entityID); | |||
void InternalRemoveFromDBAndEngines(IEntityViewBuilder[] entityViewBuilders, int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
var entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewsDBDic, entityViewType, entityID); | |||
if (group.Value.isQueryiableEntityView) | |||
InternalRemoveEntityViewFromDBDicAndEngines(entityViewType, entityID); | |||
} | |||
} | |||
} | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewsDBDic, typeof(EntityInfoView), entityID); | |||
} | |||
void InternalRemoveFromGroupAndDBAndEngines(IEntityViewBuilder[] entityViewBuilders, | |||
int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); | |||
InternalRemoveFromDBAndEngines(entityViewBuilders, entityID, entityViewsDB, entityViewsDBDic); | |||
_groupEntityViewsDB.Remove(groupID); | |||
} | |||
void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) | |||
void InternalRemoveEntityViewFromDBDicAndEngines(Type entityViewType, EGID id) | |||
{ | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
var dictionary = _groupEntityViewsDB[groupID]; | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
var typeSafeDictionary = _globalEntityViewsDBDic[entityViewType]; | |||
{ | |||
var entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(id); | |||
var typeSafeList = dictionary[entityViewType]; | |||
typeSafeList.MappedRemove(entityID); | |||
//the reason why this for exists is because in the past hierarchical entity views | |||
//where supported :( | |||
//Only EntityView can be removed from engines (won't work for IEntityStruct or IEntityView) | |||
for (var current = entityViewType; current != _entityViewType; current = current.BaseType) | |||
{ | |||
#if DEBUG && !PROFILER | |||
if (current != entityViewType) | |||
Utility.Console.LogWarning("Hierarchical Entity Views are design mistakes, ECS is not OOD!!"); | |||
#endif | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); | |||
} | |||
} | |||
typeSafeDictionary.Remove(id); | |||
} | |||
static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, | |||
IEntityView entityView, | |||
Type entityViewType) | |||
@@ -321,87 +227,61 @@ namespace Svelto.ECS | |||
} | |||
} | |||
} | |||
///-------------------------------------------- | |||
class GenericEntityFactory : IEntityFactory | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
{ | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakEngine; | |||
public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(entityID, implementors); | |||
} | |||
public void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); | |||
} | |||
Check.Require(fromGroupID != toGroupID, | |||
"can't move an entity to the same group where it already belongs to"); | |||
public void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors); | |||
} | |||
var entityegid = new EGID(entityID, fromGroupID); | |||
var entityViewBuilders = _entityInfos[entityegid.GID]; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors); | |||
} | |||
var groupedEntities = _groupEntityViewsDB[fromGroupID]; | |||
public void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, | |||
object[] implementors) | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); | |||
} | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
public void PreallocateEntitySlots<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(size); | |||
_groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); | |||
} | |||
} | |||
class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
var entityViewBuilder = entityViewBuilders[i]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
public void RemoveEntity(int entityID) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID); | |||
} | |||
var fromSafeList = groupedEntities[entityViewType]; | |||
ITypeSafeList toSafeList; | |||
public void RemoveMetaEntity(int metaEntityID) | |||
{ | |||
_weakReference.Target.RemoveEntity(metaEntityID); | |||
} | |||
if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) | |||
groupedEntityViewsTyped[entityViewType] = toSafeList = fromSafeList.Create(); | |||
public void RemoveGroupAndEntities(int groupID) | |||
{ | |||
_weakReference.Target.RemoveGroupAndEntitiesFromDB(groupID); | |||
entityViewBuilder.MoveEntityView(entityegid, fromSafeList, toSafeList); | |||
fromSafeList.MappedRemove(entityegid); | |||
} | |||
public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
{ | |||
_weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); | |||
} | |||
_entityInfos.Remove(entityegid.GID); | |||
_entityInfos.Add(new EGID(entityID, toGroupID).GID, entityViewBuilders); | |||
} | |||
readonly EntityViewsDB _DB; | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBDic; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _metaEntityViewsDBDic; | |||
//grouped set of entity views, this is the standard way to handle entity views | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
//TODO: Use faster dictionary and merge these two? | |||
//Global pool of entity views when engines want to manage entityViews regardless | |||
//the group | |||
readonly Dictionary<Type, ITypeSafeList> _globalEntityViewsDB; | |||
//indexable entity views when the entity ID is known. Usually useful to handle | |||
//event based logic. | |||
readonly Dictionary<Type, ITypeSafeDictionary> _globalEntityViewsDBDic; | |||
Dictionary<int, IEntityViewBuilder[]> _entityInfos; | |||
} | |||
} |
@@ -14,10 +14,7 @@ namespace Svelto.ECS | |||
{ | |||
void SubmitEntityViews() | |||
{ | |||
bool newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
bool newEntityViewsHaveBeenAddedWhileIterating = _groupedEntityViewsToAdd.current.Count > 0; | |||
int numberOfReenteringLoops = 0; | |||
@@ -25,29 +22,16 @@ namespace Svelto.ECS | |||
{ | |||
//use other as source from now on | |||
//current will be use to write new entityViews | |||
_entityViewsToAdd.Swap(); | |||
_metaEntityViewsToAdd.Swap(); | |||
_groupedEntityViewsToAdd.Swap(); | |||
if (_entityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB, _entityViewsDBDic); | |||
if (_metaEntityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB, _metaEntityViewsDBDic); | |||
if (_groupedEntityViewsToAdd.other.Count > 0) | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB, _entityViewsDBDic); | |||
AddEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other); | |||
//other can be cleared now | |||
_entityViewsToAdd.other.Clear(); | |||
_metaEntityViewsToAdd.other.Clear(); | |||
_groupedEntityViewsToAdd.other.Clear(); | |||
//has current new entityViews? | |||
newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
newEntityViewsHaveBeenAddedWhileIterating = _groupedEntityViewsToAdd.current.Count > 0; | |||
if (numberOfReenteringLoops > 5) | |||
throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); | |||
@@ -55,78 +39,73 @@ namespace Svelto.ECS | |||
numberOfReenteringLoops++; | |||
} | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> entityViewsToAdd, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
//todo: can I make the entity creation less complicated? | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupsToSubmit) | |||
{ | |||
foreach (var entityViewList in entityViewsToAdd) | |||
//for each groups there is a dictionary of built lists of EntityView grouped by type | |||
foreach (var groupToSubmit in groupsToSubmit) | |||
{ | |||
AddEntityViewToDB(entityViewsDB, entityViewList); | |||
Dictionary<Type, ITypeSafeList> groupDB; | |||
int groupID = groupToSubmit.Key; | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
//if the group doesn't exist in the current DB let's create it frst | |||
if (_groupEntityViewsDB.TryGetValue(groupID, out groupDB) == false) | |||
groupDB = _groupEntityViewsDB[groupID] = new Dictionary<Type, ITypeSafeList>(); | |||
foreach (var entityViewsPerType in groupToSubmit.Value) | |||
{ | |||
AddEntityViewToEntityViewsDictionary(entityViewsDBDic, entityViewList.Value, entityViewList.Key); | |||
//add the entity View in the group | |||
if (entityViewsPerType.Value.isQueryiableEntityView == true) | |||
AddEntityViewToDB(groupDB, entityViewsPerType); | |||
//add the entity view in the gloal pool | |||
AddEntityViewToDB(_globalEntityViewsDB, entityViewsPerType); | |||
//and it's not a struct, add in the indexable DB too | |||
AddEntityViewToEntityViewsDictionary(_globalEntityViewsDBDic, entityViewsPerType.Value, entityViewsPerType.Key); | |||
} | |||
} | |||
foreach (var entityViewList in entityViewsToAdd) | |||
//then submit everything in the engines, so that the DB is up to date | |||
//with all the entity views and struct created by the entity built | |||
foreach (var group in groupsToSubmit) | |||
{ | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
foreach (var entityViewList in group.Value) | |||
{ | |||
var type = entityViewList.Key; | |||
for (var current = type; current != _entityViewType; current = current.BaseType) | |||
AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, | |||
current); | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
var type = entityViewList.Key; | |||
for (var current = type; current != _entityViewType; current = current.BaseType) | |||
AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, current); | |||
} | |||
} | |||
} | |||
} | |||
void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedEntityViewsToAdd, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB | |||
, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
static void AddEntityViewToDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
KeyValuePair<Type, ITypeSafeList> entityViewList) | |||
{ | |||
foreach (var group in groupedEntityViewsToAdd) | |||
{ | |||
AddEntityViewsToGroupDB(groupEntityViewsDB, @group); | |||
ITypeSafeList dbList; | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB, entityViewsDBDic); | |||
} | |||
} | |||
static void AddEntityViewsToGroupDB(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
KeyValuePair<int, Dictionary<Type, ITypeSafeList>> @group) | |||
{ | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsByType; | |||
if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) | |||
groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary<Type, ITypeSafeList>(); | |||
if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) | |||
dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); | |||
foreach (var entityView in @group.Value) | |||
{ | |||
groupedEntityViewsByType.Add(entityView.Key, entityView.Value); | |||
dbList.AddRange(entityViewList.Value); | |||
} | |||
} | |||
static void AddEntityViewToDB(Dictionary<Type, ITypeSafeList> entityViewsDB, KeyValuePair<Type, ITypeSafeList> entityViewList) | |||
{ | |||
ITypeSafeList dbList; | |||
if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) | |||
dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); | |||
dbList.AddRange(entityViewList.Value); | |||
} | |||
static void AddEntityViewToEntityViewsDictionary(Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
ITypeSafeList entityViews, Type entityViewType) | |||
ITypeSafeList entityViews, Type entityViewType) | |||
{ | |||
ITypeSafeDictionary entityViewsDic; | |||
if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) | |||
entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); | |||
entityViewsDic.FillWithIndexedEntityViews(entityViews); | |||
if (entityViews.isQueryiableEntityView == true) | |||
{ | |||
ITypeSafeDictionary entityViewsDic; | |||
if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) | |||
entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); | |||
entityViewsDic.FillWithIndexedEntityViews(entityViews); | |||
} | |||
} | |||
static void AddEntityViewToTheSuitableEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) | |||
@@ -156,12 +135,7 @@ namespace Svelto.ECS | |||
} | |||
} | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _entityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _metaEntityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedEntityViewsToAdd; | |||
readonly EntitySubmissionScheduler _scheduler; | |||
} | |||
} |
@@ -1,7 +1,6 @@ | |||
using System; | |||
using DBC; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
@@ -17,16 +16,12 @@ namespace Svelto.ECS | |||
this.entityViewsToBuild = entityViewsToBuild; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild { get; private set; } | |||
} | |||
public interface IEntityDescriptorInfo | |||
{ | |||
public IEntityViewBuilder[] entityViewsToBuild { get; } | |||
} | |||
public static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
{ | |||
public static readonly IEntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); | |||
public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); | |||
} | |||
public class DynamicEntityDescriptorInfo<TType> : EntityDescriptorInfo where TType : IEntityDescriptor, new() | |||
@@ -36,34 +31,30 @@ namespace Svelto.ECS | |||
Check.Require(extraEntityViews.Count > 0, | |||
"don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); | |||
var descriptor = new TType(); | |||
var length = descriptor.entityViewsToBuild.Length; | |||
var defaultEntityViewsToBuild = EntityDescriptorTemplate<TType>.Default.entityViewsToBuild; | |||
var length = defaultEntityViewsToBuild.Length; | |||
entityViewsToBuild = new IEntityViewBuilder[length + extraEntityViews.Count]; | |||
Array.Copy(descriptor.entityViewsToBuild, 0, entityViewsToBuild, 0, length); | |||
Array.Copy(defaultEntityViewsToBuild, 0, entityViewsToBuild, 0, length); | |||
Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); | |||
name = descriptor.ToString(); | |||
name = EntityDescriptorTemplate<TType>.Default.name; | |||
} | |||
} | |||
} | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public class EntityDescriptorInfo : IEntityDescriptorInfo | |||
public class EntityDescriptorInfo | |||
{ | |||
internal IEntityViewBuilder[] entityViewsToBuild; | |||
internal string name; | |||
internal string name; | |||
internal EntityDescriptorInfo(IEntityDescriptor descriptor) | |||
{ | |||
name = descriptor.ToString(); | |||
name = descriptor.ToString(); | |||
entityViewsToBuild = descriptor.entityViewsToBuild; | |||
} | |||
protected EntityDescriptorInfo() | |||
{ | |||
} | |||
{ } | |||
} | |||
} | |||
} |
@@ -10,64 +10,41 @@ namespace Svelto.ECS.Internal | |||
{ | |||
internal static void BuildGroupedEntityViews(int entityID, int groupID, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
Dictionary<int, IEntityViewBuilder[]> entityInfos, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = | |||
eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
var @group = FetchGroup(groupID, groupEntityViewsByType); | |||
if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); | |||
} | |||
InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors); | |||
BuildEntityViewsAndAddToGroup(new EGID(entityID, groupID), group, entityViewsToBuildDescriptor, implementors); | |||
var removeEntityView = EntityView<EntityInfoView>.BuildEntityView(entityID); | |||
removeEntityView.groupID = groupID; | |||
removeEntityView.isInAGroup = true; | |||
removeEntityView.entityViews = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
AddEntityInfoView(entityViewsByType, removeEntityView); | |||
AddEntityInfoView(new EGID(entityID, groupID), entityViewsToBuildDescriptor, entityInfos); | |||
} | |||
internal static void BuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
static void AddEntityInfoView(EGID entityID, EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
Dictionary<int, IEntityViewBuilder[]> entityInfos) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors); | |||
var removeEntityView = EntityView<EntityInfoView>.BuildEntityView(entityID); | |||
removeEntityView.entityViews = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
AddEntityInfoView(entityViewsByType, removeEntityView); | |||
entityInfos.Add(entityID.GID, entityViewsToBuildDescriptor.entityViewsToBuild); | |||
} | |||
static void AddEntityInfoView(Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
EntityInfoView removeEntityView) | |||
static Dictionary<Type, ITypeSafeList> FetchGroup(int groupID, Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType) | |||
{ | |||
ITypeSafeList list; | |||
Dictionary<Type, ITypeSafeList> group; | |||
if (entityViewsByType.TryGetValue(typeof(EntityInfoView), out list) == false) | |||
list = entityViewsByType[typeof(EntityInfoView)] = | |||
new TypeSafeFasterListForECSForClasses<EntityInfoView>(); | |||
if (groupEntityViewsByType.TryGetValue(groupID, out @group) == false) | |||
{ | |||
@group = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, @group); | |||
} | |||
(list as TypeSafeFasterListForECSForClasses<EntityInfoView>).Add(removeEntityView); | |||
return @group; | |||
} | |||
static void InternalBuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
static void BuildEntityViewsAndAddToGroup(EGID entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
var count = entityViewsToBuild.Length; | |||
@@ -86,8 +63,8 @@ namespace Svelto.ECS.Internal | |||
} | |||
} | |||
static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder) | |||
static IEntityView BuildEntityView(EGID entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder) | |||
{ | |||
ITypeSafeList entityViewsList; | |||
@@ -158,7 +135,7 @@ namespace Svelto.ECS.Internal | |||
#if DEBUG && !PROFILER | |||
else | |||
{ | |||
Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); | |||
Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat("Type ", entityDescriptorName, " entityView ", entityView.ToString())); | |||
} | |||
#endif | |||
} | |||
@@ -185,9 +162,9 @@ namespace Svelto.ECS.Internal | |||
#if DEBUG && !PROFILER | |||
if (component.numberOfImplementations > 1) | |||
Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( | |||
"Component Type: ", fieldType.Name, | |||
" implementor: ", | |||
component.implementorType.ToString()) + | |||
"Component Type: ", fieldType.Name, | |||
" implementor: ", | |||
component.implementorType.ToString()) + | |||
" - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
#endif | |||
@@ -214,7 +191,7 @@ namespace Svelto.ECS.Internal | |||
} | |||
#endif | |||
static readonly Dictionary<Type, Type[]> _cachedTypes = new Dictionary<Type, Type[]>(); | |||
const string DUPLICATE_IMPLEMENTOR_ERROR = | |||
"<color=orange>Svelto.ECS</color> the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; | |||
@@ -1,9 +0,0 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
class EntityInfoView : EntityView | |||
{ | |||
internal IEntityViewBuilder[] entityViews; | |||
internal int groupID; | |||
internal bool isInAGroup; | |||
} | |||
} |
@@ -6,27 +6,29 @@ using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
//todo: can I remove the ID from the struct? | |||
public interface IEntityView | |||
{ | |||
int ID { get; } | |||
EGID ID { get; } | |||
} | |||
public interface IEntityStruct:IEntityView | |||
{ | |||
new int ID { set; } | |||
new EGID ID { get; set; } | |||
} | |||
public class EntityView : IEntityView | |||
{ | |||
public int ID { get { return _ID; } } | |||
public EGID ID { get { return _ID; } } | |||
internal FasterList<KeyValuePair<Type, CastedAction<EntityView>>> entityViewBlazingFastReflection; | |||
internal int _ID; | |||
internal EGID _ID; | |||
} | |||
static class EntityView<T> where T: EntityView, new() | |||
{ | |||
internal static T BuildEntityView(int ID) | |||
internal static T BuildEntityView(EGID ID) | |||
{ | |||
if (FieldCache<T>.list.Count == 0) | |||
{ | |||
@@ -5,17 +5,18 @@ namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewBuilder | |||
{ | |||
void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); | |||
void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView); | |||
ITypeSafeList Preallocate(ref ITypeSafeList list, int size); | |||
Type GetEntityViewType(); | |||
void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); | |||
void MoveEntityView(EGID entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); | |||
bool mustBeFilled { get; } | |||
bool isQueryiableEntityView { get; } | |||
} | |||
public class EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView, new() | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(); | |||
@@ -34,17 +35,17 @@ namespace Svelto.ECS | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(size); | |||
else | |||
list.ReserveCapacity(size); | |||
list.AddCapacity(size); | |||
return list; | |||
} | |||
public Type GetEntityViewType() | |||
{ | |||
return _entityViewType; | |||
return ENTITY_VIEW_TYPE; | |||
} | |||
public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
public void MoveEntityView(EGID entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
{ | |||
var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
@@ -56,23 +57,35 @@ namespace Svelto.ECS | |||
{ | |||
get { return true; } | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return true; } | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
public static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); | |||
} | |||
public class EntityViewStructBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : struct, IEntityStruct | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
public EntityViewStructBuilder() | |||
{} | |||
public EntityViewStructBuilder(ref EntityViewType initializer) | |||
{ | |||
var structEntityView = default(EntityViewType); | |||
structEntityView.ID = entityID; | |||
_initializer = initializer; | |||
} | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView) | |||
{ | |||
_initializer.ID = entityID; | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
castedList.Add(structEntityView); | |||
castedList.Add(_initializer); | |||
entityView = null; | |||
} | |||
@@ -82,17 +95,17 @@ namespace Svelto.ECS | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(size); | |||
else | |||
list.ReserveCapacity(size); | |||
list.AddCapacity(size); | |||
return list; | |||
} | |||
public Type GetEntityViewType() | |||
{ | |||
return _entityViewType; | |||
return ENTITY_VIEW_TYPE; | |||
} | |||
public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
public void MoveEntityView(EGID entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
{ | |||
var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
@@ -105,6 +118,12 @@ namespace Svelto.ECS | |||
get { return false; } | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return false; } | |||
} | |||
public static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); | |||
EntityViewType _initializer; | |||
} | |||
} |
@@ -7,17 +7,11 @@ namespace Svelto.ECS.Internal | |||
class EntityViewsDB : IEntityViewsDB | |||
{ | |||
internal EntityViewsDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeList> metaEntityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
Dictionary<Type, ITypeSafeDictionary> metaEntityViewsDBdic, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB) | |||
{ | |||
_entityViewsDB = entityViewsDB; | |||
_metaEntityViewsDB = metaEntityViewsDB; | |||
_entityViewsDBdic = entityViewsDBdic; | |||
_metaEntityViewsDBdic = metaEntityViewsDBdic; | |||
_globalEntityViewsDB = entityViewsDB; | |||
_groupedEntityViewsDBDic = entityViewsDBdic; | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
@@ -27,7 +21,7 @@ namespace Svelto.ECS.Internal | |||
ITypeSafeList entityViews; | |||
if (_entityViewsDB.TryGetValue(type, out entityViews) == false) | |||
if (_globalEntityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
@@ -54,13 +48,13 @@ namespace Svelto.ECS.Internal | |||
ITypeSafeList entityViews; | |||
if (_entityViewsDB.TryGetValue(type, out entityViews) == false) | |||
if (_globalEntityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewArray<T>(); | |||
return FasterList<T>.NoVirt.ToArrayFast((FasterList<T>)entityViews, out count); | |||
} | |||
public T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T : IEntityView | |||
public T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T : EntityView | |||
{ | |||
var type = typeof(T); | |||
count = 0; | |||
@@ -77,120 +71,63 @@ namespace Svelto.ECS.Internal | |||
return FasterList<T>.NoVirt.ToArrayFast((FasterList<T>)entitiesInGroupPerType[type], out count); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary entityViews; | |||
if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) | |||
return TypeSafeDictionary<T>.Default; | |||
return new ReadOnlyDictionary<int, T>(entityViews as Dictionary<int, T>); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableMetaEntityViews<T>() where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary entityViews; | |||
if (_metaEntityViewsDBdic.TryGetValue(type, out entityViews) == false) | |||
return TypeSafeDictionary<T>.Default; | |||
return new ReadOnlyDictionary<int, T>(entityViews as Dictionary<int, T>); | |||
} | |||
public T QueryEntityView<T>(int entityID) where T:EntityView | |||
{ | |||
return QueryEntityView<T>(entityID, _entityViewsDBdic); | |||
} | |||
public bool TryQueryEntityView<T>(int entityID, out T entityView) where T:EntityView | |||
{ | |||
return TryQueryEntityView(entityID, _entityViewsDBdic, out entityView); | |||
} | |||
public T QueryMetaEntityView<T>(int metaEntityID) where T:EntityView | |||
{ | |||
return QueryEntityView<T>(metaEntityID, _metaEntityViewsDBdic); | |||
} | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView | |||
{ | |||
return TryQueryEntityView(metaEntityID, _metaEntityViewsDBdic, out entityView); | |||
} | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView | |||
public T QueryEntityView<T>(EGID entityGID) where T : EntityView | |||
{ | |||
var type = typeof(T); | |||
T entityView; | |||
ITypeSafeList entityViews; | |||
TryQueryEntityViewInGroup(entityGID, out entityView); | |||
if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
return entityView; | |||
} | |||
static FasterReadOnlyList<T> RetrieveEmptyEntityViewList<T>() | |||
public bool TryQueryEntityView<T>(EGID entityegid, out T entityView) where T : EntityView | |||
{ | |||
return FasterReadOnlyList<T>.DefaultList; | |||
return TryQueryEntityViewInGroup(entityegid, out entityView); | |||
} | |||
static T[] RetrieveEmptyEntityViewArray<T>() | |||
{ | |||
return FasterList<T>.DefaultList.ToArrayFast(); | |||
} | |||
static bool TryQueryEntityView<T>(int ID, Dictionary<Type, ITypeSafeDictionary> entityDic, out T entityView) where T : EntityView | |||
bool TryQueryEntityViewInGroup<T>(EGID entityGID, out T entityView) where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionaryForClass<T> casted; | |||
entityDic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
_groupedEntityViewsDBDic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionaryForClass<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
casted.TryGetValue(entityGID.GID, out internalEntityView)) | |||
{ | |||
entityView = internalEntityView; | |||
return true; | |||
} | |||
entityView = default(T); | |||
entityView = null; | |||
return false; | |||
} | |||
static T QueryEntityView<T>(int ID, Dictionary<Type, ITypeSafeDictionary> entityDic) where T : EntityView | |||
static FasterReadOnlyList<T> RetrieveEmptyEntityViewList<T>() | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
entityDic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
return (T)internalEntityView; | |||
throw new Exception("EntityView Not Found"); | |||
return FasterReadOnlyList<T>.DefaultList; | |||
} | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _metaEntityViewsDBdic; | |||
static T[] RetrieveEmptyEntityViewArray<T>() | |||
{ | |||
return FasterList<T>.DefaultList.ToArrayFast(); | |||
} | |||
//grouped set of entity views, this is the standard way to handle entity views | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
//Global pool of entity views when engines want to manage entityViews regardless | |||
//the group | |||
readonly Dictionary<Type, ITypeSafeList> _globalEntityViewsDB; | |||
//indexable entity views when the entity ID is known. Usually useful to handle | |||
//event based logic. | |||
readonly Dictionary<Type, ITypeSafeDictionary> _groupedEntityViewsDBDic; | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
static class ExclusiveGroups | |||
{ | |||
internal const int StandardEntity = 0xFF; | |||
} | |||
} |
@@ -1,183 +0,0 @@ | |||
#if EXPERIMENTAL | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Experimental.Internal; | |||
namespace Svelto.ECS.Experimental.Internal | |||
{ | |||
public interface IStructEntityViewEngine : IEngine | |||
{ | |||
void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); | |||
} | |||
public interface IGroupedStructEntityViewsEngine : IEngine | |||
{ | |||
void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); | |||
} | |||
} | |||
namespace Svelto.ECS.Experimental | |||
{ | |||
public interface IGroupedEntityView | |||
{ | |||
int groupID { get; set; } | |||
} | |||
/// <summary> | |||
/// The engines can receive and store IEntityViews structs | |||
/// Unboxing will happen during the Add, but the | |||
/// data will then be stored and processed as stucts | |||
/// </summary> | |||
public interface IStructEntityViewEngine<T> : IStructEntityViewEngine where T:struct, IEntityStruct | |||
{ } | |||
/// <summary> | |||
/// same as above, but the entityViews are grouped by ID | |||
/// usually the ID is the owner of the entityViews of that | |||
/// group | |||
/// </summary> | |||
public interface IGroupedStructEntityViewsEngine<T> : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView | |||
{ | |||
void Add(ref T entityView); | |||
void Remove(ref T entityView); | |||
} | |||
public sealed class StructEntityViews<T> where T:struct, IEntityStruct | |||
{ | |||
public T[] GetList(out int numberOfItems) | |||
{ | |||
numberOfItems = _internalList.Count; | |||
return _internalList.ToArrayFast(); | |||
} | |||
public StructEntityViews(SharedStructEntityViewLists container) | |||
{ | |||
_internalList = SharedStructEntityViewLists.NoVirt.GetList<T>(container); | |||
} | |||
public void Add(T entityView) | |||
{ | |||
T convert = (T)entityView; | |||
_internalList.Add(convert); | |||
} | |||
readonly FasterList<T> _internalList; | |||
} | |||
public struct StructGroupEntityViews<T> | |||
where T : struct, IEntityView | |||
{ | |||
public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) | |||
{ | |||
_container = container; | |||
indices = new Dictionary<int, int>(); | |||
} | |||
public void Add(int groupID, T entityView) | |||
{ | |||
T convert = (T)entityView; | |||
var fasterList = | |||
(SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
indices[entityView.ID] = fasterList.Count; | |||
fasterList.Add(convert); | |||
} | |||
public void Remove(int groupID, T entityView) | |||
{ | |||
var fasterList = | |||
(SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
var index = indices[entityView.ID]; | |||
indices.Remove(entityView.ID); | |||
if (fasterList.UnorderedRemoveAt(index)) | |||
indices[fasterList[index].ID] = index; | |||
} | |||
public T[] GetList(int groupID, out int numberOfItems) | |||
{ | |||
var fasterList = | |||
(SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
return FasterList<T>.NoVirt.ToArrayFast(fasterList, out numberOfItems); | |||
} | |||
readonly SharedGroupedStructEntityViewsLists _container; | |||
readonly Dictionary<int, int> indices; | |||
} | |||
public class SharedStructEntityViewLists | |||
{ | |||
internal SharedStructEntityViewLists() | |||
{ | |||
_collection = new Dictionary<Type, IFasterList>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static FasterList<T> GetList<T>(SharedStructEntityViewLists obj) where T : struct | |||
{ | |||
IFasterList list; | |||
if (obj._collection.TryGetValue(typeof(T), out list)) | |||
{ | |||
return list as FasterList<T>; | |||
} | |||
list = new FasterList<T>(); | |||
obj._collection.Add(typeof(T), list); | |||
return (FasterList<T>)list; | |||
} | |||
} | |||
readonly Dictionary<Type, IFasterList> _collection; | |||
} | |||
public class SharedGroupedStructEntityViewsLists | |||
{ | |||
internal SharedGroupedStructEntityViewsLists() | |||
{ | |||
_collection = new Dictionary<Type, Dictionary<int, IFasterList>>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static IFasterList GetList<T>(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic = GetGroup<T>(list); | |||
IFasterList localList; | |||
if (dic.TryGetValue(groupID, out localList)) | |||
return localList; | |||
localList = new FasterList<T>(); | |||
dic.Add(groupID, localList); | |||
return localList; | |||
} | |||
internal static Dictionary<int, IFasterList> GetGroup<T>(SharedGroupedStructEntityViewsLists list) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic; | |||
if (list._collection.TryGetValue(typeof(T), out dic)) | |||
{ | |||
return dic; | |||
} | |||
dic = new Dictionary<int, IFasterList>(); | |||
list._collection.Add(typeof(T), dic); | |||
return dic; | |||
} | |||
} | |||
readonly Dictionary<Type, Dictionary<int, IFasterList>> _collection; | |||
} | |||
} | |||
#endif |
@@ -5,7 +5,7 @@ namespace Svelto.ECS | |||
UnityEngine.MonoBehaviour , IEntityDescriptorHolder | |||
where T: class, IEntityDescriptor, new() | |||
{ | |||
public IEntityDescriptorInfo RetrieveDescriptor() | |||
public EntityDescriptorInfo RetrieveDescriptor() | |||
{ | |||
return EntityDescriptorTemplate<T>.Default; | |||
} | |||
@@ -1,26 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityFactory | |||
{ | |||
void PreallocateEntitySlots<T>(int size) where T : IEntityDescriptor, new(); | |||
void BuildEntity<T>(int entityID, object[] implementors) where T:IEntityDescriptor, new(); | |||
void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptorInfo, object[] implementors); | |||
void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T:IEntityDescriptor, new(); | |||
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors) where T:IEntityDescriptor, new(); | |||
void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors); | |||
} | |||
public interface IEntityFunctions | |||
{ | |||
void RemoveEntity(int entityID); | |||
void RemoveMetaEntity(int metaEntityID); | |||
void RemoveGroupAndEntities(int groupID); | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID); | |||
} | |||
} |
@@ -2,6 +2,6 @@ namespace Svelto.ECS | |||
{ | |||
public interface IEntityDescriptorHolder | |||
{ | |||
IEntityDescriptorInfo RetrieveDescriptor(); | |||
EntityDescriptorInfo RetrieveDescriptor(); | |||
} | |||
} |
@@ -0,0 +1,55 @@ | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// Entities are always built in group. Where the group is not specificed, a special standard group is used | |||
/// ID can be reused within groups | |||
/// an EnginesRoot reference cannot be held by anything else than the Composition Root | |||
/// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference | |||
/// of the EnginesRoot to be passed around. | |||
/// </summary> | |||
public interface IEntityFactory | |||
{ | |||
/// <summary> | |||
///where performance is critical, you may wish to pre allocate the space needed | |||
///to store the entities | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="size"></param> | |||
void PreallocateEntitySpace<T>(int size) where T : IEntityDescriptor, new(); | |||
void PreallocateEntitySpaceInGroup<T>(int groupID, int size) where T : IEntityDescriptor, new(); | |||
/// <summary> | |||
/// Using this function is like building a normal entity, but the entityViews | |||
/// are grouped by groupID to be more efficently processed inside engines and | |||
/// improve cache locality. Either class entityViews and struct entityViews can be | |||
/// grouped. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors) where T:IEntityDescriptor, new(); | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors); | |||
/// <summary> | |||
/// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity | |||
/// itself in terms of EntityViews to build. The Implementors are passed to fill the | |||
/// references of the EntityViews components. Please read the articles on my blog | |||
/// to understand better the terminologies | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity<T>(int entityID, object[] implementors) where T:IEntityDescriptor, new(); | |||
/// <summary> | |||
/// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo | |||
/// can be built in place of the generic parameter T. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="entityDescriptor"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors); | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityFunctions | |||
{ | |||
//being entity ID globally not unique, the group must be specified when | |||
//an entity is removed. Not specificing the group will attempt to remove | |||
//the entity from the special standard group. | |||
void RemoveEntity(int entityID); | |||
void RemoveEntity(int entityID, int groupID); | |||
void RemoveEntity(EGID entityegid); | |||
void RemoveGroupAndEntities(int groupID); | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID); | |||
void SwapEntityGroup(int entityID, int toGroupID); | |||
} | |||
} |
@@ -5,19 +5,12 @@ namespace Svelto.ECS | |||
public interface IEntityViewsDB | |||
{ | |||
FasterReadOnlyList<T> QueryEntityViews<T>() where T : EntityView; | |||
FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T : EntityView; | |||
FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int group) where T : EntityView; | |||
T[] QueryEntityViewsAsArray<T>(out int count) where T : IEntityView; | |||
T[] QueryGroupedEntityViewsAsArray<T>(int group, out int count) where T : IEntityView; | |||
T[] QueryGroupedEntityViewsAsArray<T>(int group, out int count) where T : EntityView; | |||
ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T : EntityView; | |||
ReadOnlyDictionary<int, T> QueryIndexableMetaEntityViews<T>() where T : EntityView; | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : EntityView; | |||
T QueryEntityView<T>(int ID) where T : EntityView; | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T : EntityView; | |||
T QueryMetaEntityView<T>(int metaEntityID) where T : EntityView; | |||
bool TryQueryEntityView<T>(EGID ID, out T entityView) where T : EntityView; | |||
T QueryEntityView<T>(EGID entityGID) where T : EntityView; | |||
} | |||
} |