- introduced the concept of global ID, as a combination of groupID and entityID - only 256 groups and 2^24 entities can be created - all the entities are now built always in group, when the group is not specified, the "standard" groups is used - the groupID can be retrieved from the EGID -tags/Rel2
@@ -27,6 +27,11 @@ namespace Svelto.ECS | |||
_weakReference.Target.RemoveEntity(entityID, groupID); | |||
} | |||
public void RemoveEntity(EGID entityEGID) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityEGID); | |||
} | |||
public void RemoveGroupAndEntities(int groupID) | |||
{ | |||
_weakReference.Target.RemoveGroupAndEntitiesFromDB(groupID); | |||
@@ -14,11 +14,12 @@ 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); | |||
bool isQueryiableEntityView { get; } | |||
} | |||
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 +35,7 @@ namespace Svelto.ECS.Internal | |||
{ | |||
var entityView = buffer[i]; | |||
Add(entityView.ID, entityView); | |||
Add(entityView._ID.GID, entityView); | |||
} | |||
} | |||
catch (Exception e) | |||
@@ -43,16 +44,64 @@ 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]; | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return true; } | |||
} | |||
} | |||
class TypeSafeDictionaryForStruct<TValue> : Dictionary<int, TValue>, ITypeSafeDictionary where TValue : struct, IEntityStruct | |||
{ | |||
internal static readonly ReadOnlyDictionary<int, TValue> Default = | |||
new ReadOnlyDictionary<int, TValue>(new Dictionary<int, TValue>()); | |||
public void FillWithIndexedEntityViews(ITypeSafeList entityViews) | |||
{ | |||
int count; | |||
var buffer = FasterList<TValue>.NoVirt.ToArrayFast((FasterList<TValue>) entityViews, out count); | |||
try | |||
{ | |||
for (var i = 0; i < count; i++) | |||
{ | |||
var entityView = buffer[i]; | |||
Add(entityView.ID.GID, entityView); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeDictionaryException(e); | |||
} | |||
} | |||
public bool Remove(EGID entityId) | |||
{ | |||
base.Remove(entityId.GID); | |||
return Count > 0; | |||
} | |||
public IEntityView GetIndexedEntityView(EGID entityID) | |||
{ | |||
return this[entityID.GID]; | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return false; } | |||
} | |||
} | |||
} |
@@ -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,7 +12,7 @@ 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 AddCapacity(int capacity); | |||
@@ -32,17 +32,26 @@ 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; | |||
{ | |||
try | |||
{ | |||
_mappedIndices.Add(this[index].ID.GID, index); | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeFasterListForECSException(e); | |||
} | |||
} | |||
return Count > 0; | |||
} | |||
@@ -53,8 +62,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,7 +82,14 @@ 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 AddCapacity(int capacity) | |||
@@ -72,9 +98,9 @@ namespace Svelto.ECS.Internal | |||
Resize(Count + capacity); | |||
} | |||
public int GetIndexFromID(int entityID) | |||
public int GetIndexFromID(EGID entityID) | |||
{ | |||
return _mappedIndices[entityID]; | |||
return _mappedIndices[entityID.GID]; | |||
} | |||
} | |||
@@ -82,12 +108,10 @@ namespace Svelto.ECS.Internal | |||
where T : struct, IEntityStruct | |||
{ | |||
public TypeSafeFasterListForECSForStructs(int size) : base(size) | |||
{ | |||
} | |||
{} | |||
public TypeSafeFasterListForECSForStructs() | |||
{ | |||
} | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
@@ -101,7 +125,7 @@ namespace Svelto.ECS.Internal | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
throw new Exception("Not Allowed"); | |||
return new TypeSafeDictionaryForStruct<T>(); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
@@ -118,12 +142,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 +159,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,38 @@ | |||
using DBC; | |||
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); | |||
} | |||
int MAKE_GLOBAL_ID(int entityId, int groupId) | |||
{ | |||
#if DEBUG && !PROFILER | |||
Check.Require(entityId <= 0xFFFFFF); | |||
Check.Require(groupId <= 0xFF); | |||
#endif | |||
return entityId | groupId << 24; | |||
} | |||
} | |||
} |
@@ -37,13 +37,13 @@ namespace Svelto.ECS | |||
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_entityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_globalEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsDBDic = new Dictionary<int, Dictionary<Type, ITypeSafeDictionary>>(); | |||
_globalEntityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_DB = new EntityViewsDB(_entityViewsDB, _groupedEntityViewsDBDic, _groupEntityViewsDB); | |||
_DB = new EntityViewsDB(_globalEntityViewsDB, _globalEntityViewsDBDic, _groupEntityViewsDB); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.Schedule(new WeakAction(SubmitEntityViews)); | |||
@@ -14,7 +14,7 @@ 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); | |||
@@ -64,7 +64,7 @@ namespace Svelto.ECS | |||
implementors); | |||
} | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, | |||
object[] implementors = null) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
@@ -74,9 +74,15 @@ namespace Svelto.ECS | |||
///-------------------------------------------- | |||
/// <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++) | |||
@@ -86,8 +92,8 @@ namespace Svelto.ECS | |||
//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.AddCapacity(size); | |||
@@ -111,18 +117,44 @@ namespace Svelto.ECS | |||
dbList.AddCapacity(size); | |||
} | |||
} | |||
void RemoveEntity(ref EntityInfoView entityInfoView) | |||
///-------------------------------------------- | |||
/// | |||
void RemoveEntity(int entityID, int groupID) | |||
{ | |||
InternalRemoveFromGroupAndDBAndEngines(entityInfoView.entityViews, entityInfoView.ID, | |||
entityInfoView.groupID); | |||
RemoveEntity(new EGID(entityID, groupID)); | |||
} | |||
void RemoveEntity(int entityID, int groupID) | |||
void RemoveEntity(EGID entityGID) | |||
{ | |||
var entityInfoView = _DB.QueryEntityViewInGroup<EntityInfoView>(entityID, groupID); | |||
_DB.TryQueryEntityView<EntityInfoView>(entityGID, out var entityInfoView); | |||
var entityViewBuilders = entityInfoView.entityViews; | |||
EGID id = entityInfoView._ID; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
var group = _groupEntityViewsDB[id.group]; | |||
//for each entity view generated by the entity descriptor | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
var entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
InternalRemoveEntityViewFromDBDicAndEngines(entityViewType, id); | |||
RemoveEntityViewFromDB(@group, entityViewType, id); | |||
RemoveEntityViewFromDB(@_globalEntityViewsDB, entityViewType, id); | |||
} | |||
RemoveEntity(ref entityInfoView); | |||
InternalRemoveEntityViewFromDBDicAndEngines(_entityInfoViewType, id); | |||
} | |||
static void RemoveEntityViewFromDB(Dictionary<Type, ITypeSafeList> @group, Type entityViewType, EGID id) | |||
{ | |||
//remove it from entity views group DB | |||
var typeSafeList = @group[entityViewType]; | |||
if (typeSafeList.MappedRemove(id) == false) //clean up | |||
@group.Remove(entityViewType); | |||
} | |||
void RemoveGroupAndEntitiesFromDB(int groupID) | |||
@@ -138,40 +170,70 @@ namespace Svelto.ECS | |||
{ | |||
var entityID = entities[i].ID; | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewType, entityID, groupID); | |||
RemoveEntityViewFromDB(@_globalEntityViewsDB, entityViewType, entityID); | |||
InternalRemoveEntityViewFromDBDicAndEngines(entityViewType, entityID); | |||
} | |||
} | |||
_groupEntityViewsDB.Remove(groupID); | |||
} | |||
void InternalRemoveEntityViewFromDBAndEngines(Type entityViewType, | |||
int entityID, | |||
int groupID) | |||
void InternalRemoveEntityViewFromDBDicAndEngines(Type entityViewType, EGID id) | |||
{ | |||
var entityViews = _entityViewsDB[entityViewType]; | |||
if (entityViews.MappedRemove(entityID) == false) | |||
_entityViewsDB.Remove(entityViewType); | |||
if (entityViews.isQueryiableEntityView) | |||
var typeSafeDictionary = _globalEntityViewsDBDic[entityViewType]; | |||
if (typeSafeDictionary.isQueryiableEntityView) | |||
{ | |||
var typeSafeDictionary = _groupedEntityViewsDBDic[groupID][entityViewType]; | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); | |||
if (typeSafeDictionary.Remove(entityID) == false) | |||
_groupedEntityViewsDBDic[groupID].Remove(entityViewType); | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(id); | |||
//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) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
for (var j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); | |||
#else | |||
fastList[j].Remove(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
///-------------------------------------------- | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
{ | |||
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; | |||
_DB.TryQueryEntityViewInGroup(fromGroupID, entityID, out EntityInfoView entityInfoView); | |||
var entityViewBuilders = entityInfoView.entityViews; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
var groupedEntities = _groupEntityViewsDB[fromGroupID]; | |||
@@ -195,78 +257,28 @@ namespace Svelto.ECS | |||
if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) | |||
groupedEntityViewsTyped[entityViewType] = toSafeList = fromSafeList.Create(); | |||
entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); | |||
fromSafeList.MappedRemove(entityID); | |||
entityViewBuilder.MoveEntityView(entityInfoView._ID, fromSafeList, toSafeList); | |||
fromSafeList.MappedRemove(entityInfoView._ID); | |||
entityInfoView._ID = new EGID(entityID, toGroupID); | |||
} | |||
var entityInfoView = _DB.QueryEntityView<EntityInfoView>(entityID); | |||
entityInfoView.groupID = toGroupID; | |||
} | |||
void InternalRemoveFromGroupAndDBAndEngines(IEntityViewBuilder[] entityViewBuilders, | |||
int entityID, int groupID) | |||
{ | |||
InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
var entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewType, entityID, groupID); | |||
} | |||
InternalRemoveEntityViewFromDBAndEngines(typeof(EntityInfoView), entityID, groupID); | |||
} | |||
void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) | |||
{ | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
var group = _groupEntityViewsDB[groupID]; | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
var entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
var typeSafeList = group[entityViewType]; | |||
typeSafeList.MappedRemove(entityID); | |||
} | |||
} | |||
static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, | |||
IEntityView entityView, | |||
Type entityViewType) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
for (var j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); | |||
#else | |||
fastList[j].Remove(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
readonly Type _entityInfoViewType = typeof(EntityInfoView); | |||
readonly EntityViewsDB _DB; | |||
//grouped set of entity views, this is the standard way to handle entity views | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
//indexable entity views when the entity ID is known. Usually useful to handle | |||
//event based logic. | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupedEntityViewsDBDic; | |||
//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> _entityViewsDB; | |||
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; | |||
} | |||
} |
@@ -39,7 +39,7 @@ namespace Svelto.ECS | |||
numberOfReenteringLoops++; | |||
} | |||
} | |||
//todo: can I make the entity creation less complicated? | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupsToSubmit) | |||
{ | |||
//for each groups there is a dictionary of built lists of EntityView grouped by type | |||
@@ -57,18 +57,9 @@ namespace Svelto.ECS | |||
//add the entity View in the group | |||
AddEntityViewToDB(groupDB, entityViewsPerType); | |||
//add the entity view in the gloal pool | |||
AddEntityViewToDB(_entityViewsDB, entityViewsPerType); | |||
AddEntityViewToDB(_globalEntityViewsDB, entityViewsPerType); | |||
//and it's not a struct, add in the indexable DB too | |||
if (entityViewsPerType.Value.isQueryiableEntityView) | |||
{ | |||
Dictionary<Type, ITypeSafeDictionary> groupDic; | |||
if (_groupedEntityViewsDBDic.TryGetValue(groupID, out groupDic) == false) | |||
groupDic = _groupedEntityViewsDBDic[groupID] = | |||
new Dictionary<Type, ITypeSafeDictionary>(); | |||
AddEntityViewToEntityViewsDictionary(groupDic, entityViewsPerType.Value, entityViewsPerType.Key); | |||
} | |||
AddEntityViewToEntityViewsDictionary(_globalEntityViewsDBDic, entityViewsPerType.Value, entityViewsPerType.Key); | |||
} | |||
} | |||
@@ -87,8 +78,8 @@ namespace Svelto.ECS | |||
} | |||
} | |||
static void AddEntityViewToDB(Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
KeyValuePair<Type, ITypeSafeList> entityViewList) | |||
static void AddEntityViewToDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
KeyValuePair<Type, ITypeSafeList> entityViewList) | |||
{ | |||
ITypeSafeList dbList; | |||
@@ -13,25 +13,45 @@ namespace Svelto.ECS.Internal | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
Dictionary<Type, ITypeSafeList> group; | |||
var @group = FetchGroup(groupID, groupEntityViewsByType); | |||
if (groupEntityViewsByType.TryGetValue(groupID, out group) == false) | |||
{ | |||
group = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, group); | |||
} | |||
BuildEntityViewsAndAddToGroup(new EGID(entityID, groupID), group, entityViewsToBuildDescriptor, implementors); | |||
InternalBuildEntityViews(entityID, group, entityViewsToBuildDescriptor, implementors); | |||
AddEntityInfoView(new EGID(entityID, groupID), entityViewsToBuildDescriptor, @group); | |||
} | |||
EntityInfoView removeEntityView = | |||
(EntityInfoView) BuildEntityView | |||
(entityID, group, EntityViewBuilder<EntityInfoView>.ENTITY_VIEW_TYPE, new EntityViewBuilder<EntityInfoView>()); | |||
static void AddEntityInfoView(EGID entityID, EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
Dictionary<Type, ITypeSafeList> @group) | |||
{ | |||
//should be a struct? | |||
var removeEntityView = new EntityInfoView(); | |||
removeEntityView.groupID = groupID; | |||
removeEntityView._ID = entityID; | |||
removeEntityView.entityViews = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
ITypeSafeList list; | |||
if (group.TryGetValue(typeof(EntityInfoView), out list) == false) | |||
list = group[typeof(EntityInfoView)] = | |||
new TypeSafeFasterListForECSForClasses<EntityInfoView>(); | |||
((TypeSafeFasterListForECSForClasses<EntityInfoView>) list).Add(removeEntityView); | |||
} | |||
static void InternalBuildEntityViews(int entityID, | |||
static Dictionary<Type, ITypeSafeList> FetchGroup(int groupID, Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType) | |||
{ | |||
Dictionary<Type, ITypeSafeList> group; | |||
if (groupEntityViewsByType.TryGetValue(groupID, out @group) == false) | |||
{ | |||
@group = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, @group); | |||
} | |||
return @group; | |||
} | |||
static void BuildEntityViewsAndAddToGroup(EGID entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
object[] implementors) | |||
@@ -54,8 +74,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; | |||
@@ -182,7 +202,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,8 +1,7 @@ | |||
namespace Svelto.ECS | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public class EntityInfoView : EntityView | |||
class EntityInfoView : EntityView | |||
{ | |||
internal IEntityViewBuilder[] entityViews; | |||
public int groupID; | |||
} | |||
} |
@@ -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,17 @@ 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; } | |||
} | |||
public struct EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView, new() | |||
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>(); | |||
@@ -44,7 +44,7 @@ namespace Svelto.ECS | |||
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>; | |||
@@ -57,12 +57,12 @@ namespace Svelto.ECS | |||
get { return true; } | |||
} | |||
internal static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); | |||
public static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); | |||
} | |||
public struct EntityViewStructBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : struct, IEntityStruct | |||
public class EntityViewStructBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : struct, IEntityStruct | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, EGID entityID, out IEntityView entityView) | |||
{ | |||
var structEntityView = default(EntityViewType); | |||
structEntityView.ID = entityID; | |||
@@ -92,7 +92,7 @@ namespace Svelto.ECS | |||
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 +105,6 @@ namespace Svelto.ECS | |||
get { return false; } | |||
} | |||
internal static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); | |||
public static readonly Type ENTITY_VIEW_TYPE = typeof(EntityViewType); | |||
} | |||
} |
@@ -7,10 +7,10 @@ namespace Svelto.ECS.Internal | |||
class EntityViewsDB : IEntityViewsDB | |||
{ | |||
internal EntityViewsDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> entityViewsDBdic, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB) | |||
{ | |||
_entityViewsDB = entityViewsDB; | |||
_globalEntityViewsDB = entityViewsDB; | |||
_groupedEntityViewsDBDic = entityViewsDBdic; | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
@@ -21,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); | |||
@@ -48,7 +48,7 @@ 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); | |||
@@ -73,56 +73,60 @@ namespace Svelto.ECS.Internal | |||
public T QueryEntityView<T>(int entityID) where T:EntityView | |||
{ | |||
return QueryEntityViewInGroup<T>(entityID, ExclusiveGroups.StandardEntity); | |||
} | |||
T entityView; | |||
public bool TryQueryEntityView<T>(int entityID, out T entityView) where T:EntityView | |||
{ | |||
return TryQueryEntityViewInGroup(entityID, ExclusiveGroups.StandardEntity, out entityView); | |||
TryQueryEntityViewInGroup(new EGID(entityID, ExclusiveGroups.StandardEntity), out entityView); | |||
return entityView; | |||
} | |||
public T QueryEntityViewInGroup<T>(int entityID, int groupID) where T:EntityView | |||
public T QueryEntityView<T>(EGID entityGID) where T : EntityView | |||
{ | |||
T entityView; | |||
TryQueryEntityView(entityID, groupID, _groupedEntityViewsDBDic, out entityView); | |||
TryQueryEntityViewInGroup(entityGID, out entityView); | |||
return entityView; | |||
} | |||
public bool TryQueryEntityViewInGroup<T>(int entityID, int groupID, out T entityView) where T:EntityView | |||
public bool TryQueryEntityView<T>(int entityID, out T entityView) where T:EntityView | |||
{ | |||
return TryQueryEntityView(entityID, groupID, _groupedEntityViewsDBDic, out entityView); | |||
return TryQueryEntityViewInGroup(new EGID(entityID, ExclusiveGroups.StandardEntity), out 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>() | |||
public T QueryEntityViewInGroup<T>(int entityID, int groupID) where T:EntityView | |||
{ | |||
return FasterList<T>.DefaultList.ToArrayFast(); | |||
T entityView; | |||
TryQueryEntityViewInGroup(entityID, groupID, out entityView); | |||
return entityView; | |||
} | |||
static bool TryQueryEntityView<T>(int ID, int groupID, Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> entityDic, out T entityView) where T : EntityView | |||
public bool TryQueryEntityViewInGroup<T>(int entityID, int groupID, out T entityView) where T : EntityView | |||
{ | |||
return TryQueryEntityViewInGroup(new EGID(entityID, groupID), out entityView); | |||
} | |||
bool TryQueryEntityViewInGroup<T>(EGID entityGID, out T entityView) where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
Dictionary<Type, ITypeSafeDictionary> @group; | |||
if (entityDic.TryGetValue(groupID, out group) == false) | |||
throw new Exception("Group not found"); | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionaryForClass<T> casted; | |||
group.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; | |||
@@ -134,9 +138,24 @@ namespace Svelto.ECS.Internal | |||
return false; | |||
} | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupedEntityViewsDBDic; | |||
static FasterReadOnlyList<T> RetrieveEmptyEntityViewList<T>() | |||
{ | |||
return FasterReadOnlyList<T>.DefaultList; | |||
} | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
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; | |||
} | |||
} |
@@ -2,6 +2,6 @@ | |||
{ | |||
static class ExclusiveGroups | |||
{ | |||
internal const int StandardEntity = unchecked((int) 0xFFFFFFFF); | |||
internal const int StandardEntity = 0xFF; | |||
} | |||
} |
@@ -41,7 +41,7 @@ namespace Svelto.ECS | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity<T>(int entityID, object[] implementors) where T:IEntityDescriptor, new(); | |||
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 | |||
@@ -7,6 +7,7 @@ namespace Svelto.ECS | |||
//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); | |||
@@ -11,8 +11,10 @@ namespace Svelto.ECS | |||
T[] QueryGroupedEntityViewsAsArray<T>(int group, out int count) where T : IEntityView; | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : EntityView; | |||
bool TryQueryEntityView<T>(EGID ID, out T entityView) where T : EntityView; | |||
T QueryEntityView<T>(int ID) where T : EntityView; | |||
T QueryEntityView<T>(EGID entityGID) where T : EntityView; | |||
bool TryQueryEntityViewInGroup<T>(int entityID, int groupID, out T entityView) where T : EntityView; | |||
T QueryEntityViewInGroup<T>(int entityID, int groupID) where T : EntityView; | |||
} |