@@ -1,4 +1,5 @@ | |||
using Svelto.DataStructures; | |||
using System; | |||
using Svelto.DataStructures; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS.Internal | |||
@@ -28,15 +29,22 @@ namespace Svelto.ECS.Internal | |||
int count; | |||
var buffer = FasterList<TValue>.NoVirt.ToArrayFast((FasterList<TValue>) entityViews, out count); | |||
for (int i = 0; i < count; i++) | |||
try | |||
{ | |||
var entityView = buffer[i]; | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var entityView = buffer[i]; | |||
Add(entityView.ID, entityView); | |||
Add(entityView.ID, entityView); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
throw new TypeSafeDictionaryException(e); | |||
} | |||
} | |||
new public bool Remove(int entityId) | |||
public new bool Remove(int entityId) | |||
{ | |||
base.Remove(entityId); | |||
@@ -0,0 +1,10 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class TypeSafeDictionaryException : Exception | |||
{ | |||
public TypeSafeDictionaryException(Exception exception):base(exception.Message, exception) | |||
{} | |||
} | |||
} |
@@ -42,12 +42,13 @@ namespace Svelto.ECS | |||
_metaEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_entityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_metaEntityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_entityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_metaEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_DB = new EntityViewsDB(_entityViewsDB, _entityViewsDBDic, _metaEntityViewsDB, _groupEntityViewsDB); | |||
_DB = new EntityViewsDB(_entityViewsDB, _metaEntityViewsDB, _entityViewsDBDic, _metaEntityViewsDBDic, _groupEntityViewsDB); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.Schedule(new WeakAction(SubmitEntityViews)); | |||
@@ -134,32 +134,29 @@ namespace Svelto.ECS | |||
} | |||
} | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
void RemoveEntity(ref EntityInfoView entityInfoView, Dictionary<Type, ITypeSafeList> viewsDB, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
var removeEntityImplementor = removeInfo as RemoveEntityImplementor; | |||
if (removeEntityImplementor.isInAGroup) | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); | |||
if (entityInfoView.isInAGroup) | |||
InternalRemoveFromGroupAndDBAndEngines(entityInfoView.entityViews, entityInfoView.ID, entityInfoView.groupID, viewsDB, entityViewsDBDic); | |||
else | |||
InternalRemoveFromDBAndEngines(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); | |||
InternalRemoveFromDBAndEngines(entityInfoView.entityViews, entityInfoView.ID, viewsDB, entityViewsDBDic); | |||
} | |||
void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemoveFromDBAndEngines( ((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
void RemoveEntity(int entityID) | |||
{ | |||
InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild, metaEntityID, _metaEntityViewsDB); | |||
var entityInfoView = _DB.QueryEntityView<EntityInfoView>(entityID); | |||
RemoveEntity(ref entityInfoView, _entityViewsDB, _entityViewsDBDic); | |||
} | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
void RemoveMetaEntity(int metaEntityID) | |||
{ | |||
InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); | |||
var entityInfoView = _DB.QueryMetaEntityView<EntityInfoView>(metaEntityID); | |||
RemoveEntity(ref entityInfoView, _metaEntityViewsDB, _metaEntityViewsDBDic); | |||
} | |||
void DeleteEntityGroup(int groupID) | |||
void RemoveGroupAndEntitiesFromDB(int groupID) | |||
{ | |||
foreach (var group in _groupEntityViewsDB[groupID]) | |||
{ | |||
@@ -172,7 +169,7 @@ namespace Svelto.ECS | |||
{ | |||
var entityID = entities[i].ID; | |||
InternalRemoveEntityViewFromDBAndEngines(_entityViewsDB, entityViewType, entityID); | |||
InternalRemoveEntityViewFromDBAndEngines(_entityViewsDB, _entityViewsDBDic, entityViewType, entityID); | |||
} | |||
} | |||
@@ -180,6 +177,7 @@ namespace Svelto.ECS | |||
} | |||
void InternalRemoveEntityViewFromDBAndEngines(Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic, | |||
Type entityViewType, int entityID) | |||
{ | |||
var entityViews = entityViewsDB[entityViewType]; | |||
@@ -188,22 +186,22 @@ namespace Svelto.ECS | |||
if (entityViews.isQueryiableEntityView) | |||
{ | |||
var typeSafeDictionary = _entityViewsDBDic[entityViewType]; | |||
var typeSafeDictionary = entityViewsDBDic[entityViewType]; | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); | |||
if (typeSafeDictionary.Remove(entityID) == false) | |||
_entityViewsDBDic.Remove(entityViewType); | |||
entityViewsDBDic.Remove(entityViewType); | |||
for (var current = entityViewType; current != _entityViewType; current = current.BaseType) | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); | |||
} | |||
} | |||
void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
{ | |||
DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); | |||
var entityViewBuilders = ((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild; | |||
var entityViewBuilders = _DB.QueryEntityView<EntityInfoView>(entityID).entityViews; | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
var dictionary = _groupEntityViewsDB[fromGroupID]; | |||
@@ -239,7 +237,7 @@ namespace Svelto.ECS | |||
} | |||
void InternalRemoveFromDBAndEngines(IEntityViewBuilder[] entityViewBuilders, int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
Dictionary<Type, ITypeSafeList> entityViewsDB, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
@@ -247,16 +245,16 @@ namespace Svelto.ECS | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewType, entityID); | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewsDBDic, entityViewType, entityID); | |||
} | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
void InternalRemoveFromGroupAndDBAndEngines(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); | |||
InternalRemoveFromDBAndEngines(entityViewBuilders, entityID, entityViewsDB); | |||
InternalRemoveFromDBAndEngines(entityViewBuilders, entityID, entityViewsDB, entityViewsDBDic); | |||
} | |||
void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) | |||
@@ -269,11 +267,8 @@ namespace Svelto.ECS | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
if (dictionary[entityViewType].UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
dictionary[entityViewType].UnorderedRemove(entityID); | |||
} | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); | |||
} | |||
static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, | |||
@@ -344,34 +339,24 @@ namespace Svelto.ECS | |||
_weakReference = weakReference; | |||
} | |||
public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, removeInfo); | |||
} | |||
public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
public void RemoveEntity(int entityID) | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
_weakReference.Target.RemoveEntity(entityID); | |||
} | |||
public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
public void RemoveMetaEntity(int metaEntityID) | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(metaEntityID); | |||
_weakReference.Target.RemoveEntity(metaEntityID); | |||
} | |||
public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
public void RemoveGroupAndEntities(int groupID) | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
_weakReference.Target.RemoveGroupAndEntitiesFromDB(groupID); | |||
} | |||
public void DeleteEntityGroup(int groupID) | |||
public void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID) | |||
{ | |||
_weakReference.Target.DeleteEntityGroup(groupID); | |||
} | |||
public void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.SwapEntityGroup<T>(entityID, fromGroupID, toGroupID); | |||
_weakReference.Target.SwapEntityGroup(entityID, fromGroupID, toGroupID); | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
@@ -406,6 +391,6 @@ namespace Svelto.ECS | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBDic; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _metaEntityViewsDBDic; | |||
} | |||
} |
@@ -30,13 +30,13 @@ namespace Svelto.ECS | |||
_groupedEntityViewsToAdd.Swap(); | |||
if (_entityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); | |||
AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB, _entityViewsDBDic); | |||
if (_metaEntityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB, _metaEntityViewsDBDic); | |||
if (_groupedEntityViewsToAdd.other.Count > 0) | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB, _entityViewsDBDic); | |||
//other can be cleared now | |||
_entityViewsToAdd.other.Clear(); | |||
@@ -57,7 +57,7 @@ namespace Svelto.ECS | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> entityViewsToAdd, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
Dictionary<Type, ITypeSafeList> entityViewsDB, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
@@ -65,7 +65,7 @@ namespace Svelto.ECS | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToEntityViewsDictionary(_entityViewsDBDic, entityViewList.Value, entityViewList.Key); | |||
AddEntityViewToEntityViewsDictionary(entityViewsDBDic, entityViewList.Value, entityViewList.Key); | |||
} | |||
} | |||
@@ -83,13 +83,14 @@ namespace Svelto.ECS | |||
void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedEntityViewsToAdd, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
Dictionary<Type, ITypeSafeList> entityViewsDB | |||
, Dictionary<Type, ITypeSafeDictionary> entityViewsDBDic) | |||
{ | |||
foreach (var group in groupedEntityViewsToAdd) | |||
{ | |||
AddEntityViewsToGroupDB(groupEntityViewsDB, @group); | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB, entityViewsDBDic); | |||
} | |||
} | |||
@@ -157,6 +158,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,8 +1,6 @@ | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.Utilities; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
{ | |||
@@ -43,7 +41,6 @@ namespace Svelto.ECS | |||
Array.Copy(descriptor.entityViewsToBuild, 0, entityViewsToBuild, 0, length); | |||
Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); | |||
name = descriptor.ToString(); | |||
} | |||
} | |||
@@ -54,219 +51,16 @@ namespace Svelto.ECS.Internal | |||
public class EntityDescriptorInfo:IEntityDescriptorInfo | |||
{ | |||
internal IEntityViewBuilder[] entityViewsToBuild; | |||
internal RemoveEntityImplementor removeEntityImplementor; | |||
internal string name; | |||
internal EntityDescriptorInfo(IEntityDescriptor descriptor) | |||
{ | |||
name = descriptor.ToString(); | |||
entityViewsToBuild = descriptor.entityViewsToBuild; | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); | |||
} | |||
protected EntityDescriptorInfo() | |||
{} | |||
} | |||
static class EntityFactory | |||
{ | |||
internal static void BuildGroupedEntityViews(int entityID, int groupID, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); | |||
} | |||
//I would like to find a better solution for this | |||
var removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); | |||
InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); | |||
} | |||
internal static void BuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
var removeEntityImplementor = entityViewsToBuildDescriptor.removeEntityImplementor; | |||
InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); | |||
} | |||
static void InternalBuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors, RemoveEntityImplementor removeEntityImplementor) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
//only class EntityView will be returned | |||
//struct EntityView cannot be filled so it will be null. | |||
var entityViewObjectToFill = | |||
BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); | |||
//the semantic of this code must still be improved | |||
//but only classes can be filled, so I am aware | |||
//it's a EntityView | |||
if (entityViewObjectToFill != null) | |||
{ | |||
FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, | |||
entityViewsToBuildDescriptor.name); | |||
} | |||
} | |||
} | |||
static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder) | |||
{ | |||
ITypeSafeList entityViewsList; | |||
var entityViewsPoolWillBeCreated = | |||
entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; | |||
IEntityView entityViewObjectToFill; | |||
//passing the undefined entityViewsByType inside the entityViewBuilder will allow | |||
//it to be created with the correct type and casted back to the undefined list. | |||
//that's how the list will be eventually of the target type. | |||
entityViewBuilder.BuildEntityViewAndAddToList(ref entityViewsList, entityID, out entityViewObjectToFill); | |||
if (entityViewsPoolWillBeCreated) | |||
entityViewsByType.Add(entityViewType, entityViewsList); | |||
return entityViewObjectToFill as IEntityView; | |||
} | |||
//this is used to avoid newing a dictionary every time, but it's used locally only and it's clearead for each use | |||
#if DEBUG && !PROFILER | |||
static readonly Dictionary<Type, Tuple<object, int>> implementorsByType = new Dictionary<Type, Tuple<object, int>>(); | |||
#else | |||
static readonly Dictionary<Type, object> implementorsByType = new Dictionary<Type, object>(); | |||
#endif | |||
static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, | |||
string entityDescriptorName) | |||
{ | |||
for (int index = 0; index < implementors.Length; index++) | |||
{ | |||
var implementor = implementors[index]; | |||
if (implementor != null) | |||
{ | |||
var type = implementor.GetType(); | |||
Type[] interfaces; | |||
if (_cachedTypes.TryGetValue(type, out interfaces) == false) | |||
interfaces = _cachedTypes[type] = type.GetInterfacesEx(); | |||
for (int iindex = 0; iindex < interfaces.Length; iindex++) | |||
{ | |||
var componentType = interfaces[iindex]; | |||
#if DEBUG && !PROFILER | |||
Tuple<object, int> implementorHolder; | |||
if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) | |||
implementorHolder.item2++; | |||
else | |||
implementorsByType[componentType] = new Tuple<object, int>(implementor, 1); | |||
#else | |||
implementorsByType[componentType] = implementor; | |||
#endif | |||
} | |||
} | |||
#if DEBUG && !PROFILER | |||
else | |||
Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); | |||
#endif | |||
} | |||
int count; | |||
//Very efficent way to collect the fields of every EntityViewType | |||
KeyValuePair<Type, CastedAction<EntityView>>[] setters = | |||
FasterList<KeyValuePair<Type, CastedAction<EntityView>>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); | |||
var removeEntityComponentType = typeof(IRemoveEntityComponent); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var keyValuePair = setters[i]; | |||
Type fieldType = keyValuePair.Key; | |||
if (fieldType != removeEntityComponentType) | |||
{ | |||
#if DEBUG && !PROFILER | |||
Tuple<object, int> component; | |||
#else | |||
object component; | |||
#endif | |||
if (implementorsByType.TryGetValue(fieldType, out component) == false) | |||
{ | |||
Exception e = new Exception(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
throw e; | |||
} | |||
#if DEBUG && !PROFILER | |||
if (component.item2 > 1) | |||
Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( | |||
"Component Type: ", fieldType.Name, " implementor: ", | |||
component.item1.ToString()) + " - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
#endif | |||
#if DEBUG && !PROFILER | |||
keyValuePair.Value.Call(entityView, component.item1); | |||
#else | |||
keyValuePair.Value.Call(entityView, component); | |||
#endif | |||
} | |||
else | |||
{ | |||
keyValuePair.Value.Call(entityView, removeEntity); | |||
} | |||
} | |||
implementorsByType.Clear(); | |||
} | |||
#if DEBUG && !PROFILER | |||
struct Tuple<T1, T2> | |||
{ | |||
public T1 item1; | |||
public T2 item2; | |||
public Tuple(T1 implementor, T2 v) | |||
{ | |||
item1 = implementor; | |||
item2 = v; | |||
} | |||
} | |||
#endif | |||
static 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. "; | |||
const string NULL_IMPLEMENTOR_ERROR = | |||
"<color=orange>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid performance loss "; | |||
const string NOT_FOUND_EXCEPTION = "<color=orange>Svelto.ECS</color> Implementor not found for an EntityView. "; | |||
} | |||
} | |||
@@ -0,0 +1,216 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
static class EntityFactory | |||
{ | |||
internal static void BuildGroupedEntityViews(int entityID, int groupID, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); | |||
} | |||
InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors); | |||
EntityInfoView removeEntityView = new EntityInfoView(); | |||
removeEntityView.groupID = groupID; | |||
removeEntityView.isInAGroup = true; | |||
removeEntityView.entityViews = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
AddEntityInfoView(groupEntityViewsByType[groupID], removeEntityView); | |||
} | |||
internal static void BuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors); | |||
EntityInfoView removeEntityView = new EntityInfoView(); | |||
removeEntityView.entityViews = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
AddEntityInfoView(entityViewsByType, removeEntityView); | |||
} | |||
static void AddEntityInfoView(Dictionary<Type, ITypeSafeList> entityViewsByType, EntityInfoView removeEntityView) | |||
{ | |||
ITypeSafeList list; | |||
if (entityViewsByType.TryGetValue(typeof(EntityInfoView), out list) == false) | |||
list = entityViewsByType[typeof(EntityInfoView)] = new TypeSafeFasterListForECSForClasses<EntityInfoView>(); | |||
(list as TypeSafeFasterListForECSForClasses<EntityInfoView>).Add(removeEntityView); | |||
} | |||
static void InternalBuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
var entityViewObjectToFill = | |||
BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); | |||
if (entityViewBuilder.mustBeFilled == true) | |||
{ | |||
FillEntityView(entityViewObjectToFill as EntityView | |||
,implementors | |||
,entityViewsToBuildDescriptor.name); | |||
} | |||
} | |||
} | |||
static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder) | |||
{ | |||
ITypeSafeList entityViewsList; | |||
var entityViewsPoolWillBeCreated = | |||
entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; | |||
IEntityView entityViewObjectToFill; | |||
//passing the undefined entityViewsByType inside the entityViewBuilder will allow | |||
//it to be created with the correct type and casted back to the undefined list. | |||
//that's how the list will be eventually of the target type. | |||
entityViewBuilder.BuildEntityViewAndAddToList(ref entityViewsList, entityID, out entityViewObjectToFill); | |||
if (entityViewsPoolWillBeCreated) | |||
entityViewsByType.Add(entityViewType, entityViewsList); | |||
return entityViewObjectToFill; | |||
} | |||
//this is used to avoid newing a dictionary every time, but it's used locally only and it's clearead for each use | |||
#if DEBUG && !PROFILER | |||
static readonly Dictionary<Type, Tuple<object, int>> implementorsByType = new Dictionary<Type, Tuple<object, int>>(); | |||
#else | |||
static readonly Dictionary<Type, object> implementorsByType = new Dictionary<Type, object>(); | |||
#endif | |||
static void FillEntityView(EntityView entityView | |||
, object[] implementors | |||
, string entityDescriptorName) | |||
{ | |||
int count; | |||
//Very efficent way to collect the fields of every EntityViewType | |||
KeyValuePair<Type, CastedAction<EntityView>>[] setters = | |||
FasterList<KeyValuePair<Type, CastedAction<EntityView>>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); | |||
if (count == 0) return; | |||
for (int index = 0; index < implementors.Length; index++) | |||
{ | |||
var implementor = implementors[index]; | |||
if (implementor != null) | |||
{ | |||
var type = implementor.GetType(); | |||
Type[] interfaces; | |||
if (_cachedTypes.TryGetValue(type, out interfaces) == false) | |||
interfaces = _cachedTypes[type] = type.GetInterfacesEx(); | |||
for (int iindex = 0; iindex < interfaces.Length; iindex++) | |||
{ | |||
var componentType = interfaces[iindex]; | |||
#if DEBUG && !PROFILER | |||
Tuple<object, int> implementorHolder; | |||
if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) | |||
implementorHolder.numberOfImplementations++; | |||
else | |||
implementorsByType[componentType] = new Tuple<object, int>(implementor, 1); | |||
#else | |||
implementorsByType[componentType] = implementor; | |||
#endif | |||
} | |||
} | |||
#if DEBUG && !PROFILER | |||
else | |||
Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); | |||
#endif | |||
} | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var fieldSetter = setters[i]; | |||
Type fieldType = fieldSetter.Key; | |||
#if DEBUG && !PROFILER | |||
Tuple<object, int> component; | |||
#else | |||
object component; | |||
#endif | |||
if (implementorsByType.TryGetValue(fieldType, out component) == false) | |||
{ | |||
Exception e = new Exception(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
throw e; | |||
} | |||
#if DEBUG && !PROFILER | |||
if (component.numberOfImplementations > 1) | |||
Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( | |||
"Component Type: ", fieldType.Name, " implementor: ", | |||
component.implementorType.ToString()) + " - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
#endif | |||
#if DEBUG && !PROFILER | |||
fieldSetter.Value.Call(entityView, component.implementorType); | |||
#else | |||
keyValuePair.Value.Call(entityView, component); | |||
#endif | |||
} | |||
implementorsByType.Clear(); | |||
} | |||
#if DEBUG && !PROFILER | |||
struct Tuple<T1, T2> | |||
{ | |||
public T1 implementorType; | |||
public T2 numberOfImplementations; | |||
public Tuple(T1 implementor, T2 v) | |||
{ | |||
implementorType = implementor; | |||
numberOfImplementations = v; | |||
} | |||
} | |||
#endif | |||
static 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. "; | |||
const string NULL_IMPLEMENTOR_ERROR = | |||
"<color=orange>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid performance loss "; | |||
const string NOT_FOUND_EXCEPTION = "<color=orange>Svelto.ECS</color> Implementor not found for an EntityView. "; | |||
} | |||
} |
@@ -0,0 +1,10 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
class EntityInfoView : EntityView | |||
{ | |||
internal IEntityViewBuilder[] entityViews; | |||
internal int groupID; | |||
internal bool isInAGroup; | |||
} | |||
} | |||
@@ -10,6 +10,7 @@ namespace Svelto.ECS | |||
Type GetEntityViewType(); | |||
void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); | |||
bool mustBeFilled { get; } | |||
} | |||
public class EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView, new() | |||
@@ -51,6 +52,11 @@ namespace Svelto.ECS | |||
toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); | |||
} | |||
public bool mustBeFilled | |||
{ | |||
get { return true; } | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
@@ -94,6 +100,11 @@ namespace Svelto.ECS | |||
toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); | |||
} | |||
public bool mustBeFilled | |||
{ | |||
get { return false; } | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
} |
@@ -6,18 +6,22 @@ namespace Svelto.ECS.Internal | |||
{ | |||
class EntityViewsDB : IEntityViewsDB | |||
{ | |||
internal EntityViewsDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
internal EntityViewsDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeList> metaEntityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
Dictionary<Type, ITypeSafeList> metaEntityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> metaEntityViewsDBdic, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB) | |||
{ | |||
_entityViewsDB = entityViewsDB; | |||
_entityViewsDBdic = entityViewsDBdic; | |||
_metaEntityViewsDB = metaEntityViewsDB; | |||
_entityViewsDBdic = entityViewsDBdic; | |||
_metaEntityViewsDBdic = metaEntityViewsDBdic; | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
public FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new() | |||
public FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
@@ -29,7 +33,7 @@ namespace Svelto.ECS.Internal | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
} | |||
public FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int @group) where T:EntityView, new() | |||
public FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int @group) where T:EntityView | |||
{ | |||
Dictionary<Type, ITypeSafeList> entitiesInGroupPerType; | |||
@@ -65,7 +69,7 @@ namespace Svelto.ECS.Internal | |||
return FasterList<T>.NoVirt.ToArrayFast((FasterList<T>)entityViews[type], out count); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T:IEntityView | |||
public ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
@@ -76,60 +80,40 @@ namespace Svelto.ECS.Internal | |||
return new ReadOnlyDictionary<int, T>(entityViews as Dictionary<int, T>); | |||
} | |||
public bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView | |||
public ReadOnlyDictionary<int, T> QueryIndexableMetaEntityViews<T>() where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
_entityViewsDBdic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
{ | |||
entityView = internalEntityView; | |||
return true; | |||
} | |||
entityView = default(T); | |||
if (_metaEntityViewsDBdic.TryGetValue(type, out entityViews) == false) | |||
return TypeSafeDictionary<T>.Default; | |||
return false; | |||
return new ReadOnlyDictionary<int, T>(entityViews as Dictionary<int, T>); | |||
} | |||
public T QueryEntityView<T>(int ID) where T : IEntityView | |||
public T QueryEntityView<T>(int entityID) where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
_entityViewsDBdic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
return (T)internalEntityView; | |||
return QueryEntityView<T>(entityID, _entityViewsDBdic); | |||
} | |||
throw new Exception("EntityView Not Found"); | |||
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, new() | |||
public T QueryMetaEntityView<T>(int metaEntityID) where T:EntityView | |||
{ | |||
return QueryEntityView<T>(metaEntityID); | |||
return QueryEntityView<T>(metaEntityID, _metaEntityViewsDBdic); | |||
} | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView, new() | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView | |||
{ | |||
return TryQueryEntityView(metaEntityID, out entityView); | |||
return TryQueryEntityView(metaEntityID, _metaEntityViewsDBdic, out entityView); | |||
} | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView, new() | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView | |||
{ | |||
var type = typeof(T); | |||
@@ -150,10 +134,55 @@ namespace Svelto.ECS.Internal | |||
{ | |||
return FasterList<T>.DefaultList.ToArrayFast(); | |||
} | |||
static bool TryQueryEntityView<T>(int ID, Dictionary<Type, ITypeSafeDictionary> entityDic, out T entityView) where T : EntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
entityDic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
{ | |||
entityView = internalEntityView; | |||
return true; | |||
} | |||
entityView = default(T); | |||
return false; | |||
} | |||
static T QueryEntityView<T>(int ID, Dictionary<Type, ITypeSafeDictionary> entityDic) where T : EntityView | |||
{ | |||
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"); | |||
} | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _metaEntityViewsDBdic; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
} | |||
} |
@@ -15,14 +15,12 @@ namespace Svelto.ECS | |||
public interface IEntityFunctions | |||
{ | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); | |||
void RemoveEntity<T>(int entityID) where T:IEntityDescriptor, new(); | |||
void RemoveEntity(int entityID); | |||
void RemoveMetaEntity<T>(int metaEntityID) where T:IEntityDescriptor, new(); | |||
void RemoveMetaEntity(int metaEntityID); | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T:IEntityDescriptor, new(); | |||
void RemoveGroupAndEntities(int groupID); | |||
void DeleteEntityGroup(int groupID); | |||
void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID); | |||
} | |||
} |
@@ -4,19 +4,21 @@ namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewsDB | |||
{ | |||
FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new(); | |||
FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T: EntityView, new(); | |||
FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int group) where T: EntityView, new(); | |||
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; | |||
ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T: IEntityView; | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView; | |||
T QueryEntityView<T>(int ID) where T: IEntityView; | |||
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, new(); | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView, new(); | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T: EntityView; | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView; | |||
} | |||
} | |||
@@ -1,36 +0,0 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
sealed class RemoveEntityImplementor : IRemoveEntityComponent | |||
{ | |||
public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) | |||
{ | |||
this.groupID = groupID; | |||
isInAGroup = true; | |||
} | |||
internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) | |||
{ | |||
removeEntityInfo = new RemoveEntityInfo(entityViews); | |||
} | |||
internal readonly RemoveEntityInfo removeEntityInfo; | |||
internal readonly int groupID; | |||
internal readonly bool isInAGroup; | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public interface IRemoveEntityComponent | |||
{} | |||
public struct RemoveEntityInfo | |||
{ | |||
internal readonly IEntityViewBuilder[] entityViewsToBuild; | |||
public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() | |||
{ | |||
this.entityViewsToBuild = entityViews; | |||
} | |||
} | |||
} |