split EngineRoot for better readability and add commentstags/Rel2b
@@ -18,7 +18,7 @@ namespace Svelto.ECS | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
public FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView<T>, new() | |||
public FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new() | |||
{ | |||
var type = typeof(T); | |||
@@ -30,7 +30,7 @@ namespace Svelto.ECS | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
} | |||
public FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int @group) where T:EntityView<T>, new() | |||
public FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int @group) where T:EntityView, new() | |||
{ | |||
Dictionary<Type, ITypeSafeList> entityViews; | |||
@@ -128,17 +128,17 @@ namespace Svelto.ECS | |||
throw new Exception("EntityView Not Found"); | |||
} | |||
public T QueryMetaEntityView<T>(int metaEntityID) where T:EntityView<T>, new() | |||
public T QueryMetaEntityView<T>(int metaEntityID) where T:EntityView, new() | |||
{ | |||
return QueryEntityView<T>(metaEntityID); | |||
} | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView<T>, new() | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView, new() | |||
{ | |||
return TryQueryEntityView(metaEntityID, out entityView); | |||
} | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView<T>, new() | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView, new() | |||
{ | |||
var type = typeof(T); | |||
@@ -1,665 +0,0 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Schedulers; | |||
using Svelto.Utilities; | |||
using Svelto.WeakEvents; | |||
#if EXPERIMENTAL | |||
using Svelto.ECS.Experimental; | |||
using Svelto.ECS.Experimental.Internal; | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public sealed class EnginesRoot : IDisposable | |||
{ | |||
public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) | |||
{ | |||
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_entityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_metaEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_entityViewsDBdic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_entityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_metaEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
_addEntityViewToEngine = AddEntityViewToEngine; | |||
_removeEntityViewFromEngine = RemoveEntityViewFromEngine; | |||
#endif | |||
_engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.Schedule(new WeakAction(SubmitEntityViews)); | |||
#if EXPERIMENTAL | |||
_sharedStructEntityViewLists = new SharedStructEntityViewLists(); | |||
_sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); | |||
_structEntityViewEngineType = typeof(IStructEntityViewEngine<>); | |||
_groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); | |||
_implementedInterfaceTypes = new Dictionary<Type, Type[]>(); | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
#endif | |||
} | |||
public IEntityFactory GenerateEntityFactory() | |||
{ | |||
return new GenericEntityFactory(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
public IEntityFunctions GenerateEntityFunctions() | |||
{ | |||
return new GenericEntityFunctions(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
void BuildEntity<T>(int entityID, object[] implementors = null) where T:IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, 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, _entityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
/// <summary> | |||
/// Using this function is like building a normal entity, but the entityViews | |||
/// are grouped by groupID to be better processed inside engines and | |||
/// improve cache locality. Only IGroupStructEntityViewWithID entityViews are grouped | |||
/// other entityViews are managed as usual. | |||
/// </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 = null) where T:IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, | |||
implementors); | |||
} | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
entityDescriptor, implementors); | |||
} | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
var removeEntityImplementor = removeInfo as RemoveEntityImplementor; | |||
if (removeEntityImplementor.removeEntityInfo.isInAGroup) | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, removeEntityImplementor.removeEntityInfo.groupID, _entityViewsDB); | |||
else | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.descriptor.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); | |||
} | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); | |||
} | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.Default.descriptor.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
ITypeSafeList dbList; | |||
if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsDB[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); | |||
else | |||
dbList.ReserveCapacity(size); | |||
} | |||
} | |||
public void AddEngine(IEngine engine) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
Profiler.EngineProfiler.AddEngine(engine); | |||
#endif | |||
var engineType = engine.GetType(); | |||
#if EXPERIMENTAL | |||
bool engineAdded; | |||
var implementedInterfaces = engineType.GetInterfaces(); | |||
CollectImplementedInterfaces(implementedInterfaces); | |||
engineAdded = CheckSpecialEngine(engine); | |||
#endif | |||
var viewEngine = engine as IHandleEntityViewEngine; | |||
if (viewEngine != null) | |||
CheckEntityViewsEngine(viewEngine, engineType); | |||
else | |||
_otherEngines.Add(engine); | |||
var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; | |||
if (queryableEntityViewEngine != null) | |||
{ | |||
queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; | |||
queryableEntityViewEngine.Ready(); | |||
} | |||
} | |||
#if EXPERIMENTAL | |||
void CollectImplementedInterfaces(Type[] implementedInterfaces) | |||
{ | |||
_implementedInterfaceTypes.Clear(); | |||
var type = typeof(IHandleEntityViewEngine); | |||
for (int index = 0; index < implementedInterfaces.Length; index++) | |||
{ | |||
var interfaceType = implementedInterfaces[index]; | |||
if (type.IsAssignableFrom(interfaceType) == false) | |||
continue; | |||
if (false == interfaceType.IsGenericTypeEx()) | |||
{ | |||
continue; | |||
} | |||
var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); | |||
_implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); | |||
} | |||
} | |||
bool CheckSpecialEngine(IEngine engine) | |||
{ | |||
if (_implementedInterfaceTypes.Count == 0) return false; | |||
bool engineAdded = false; | |||
if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) | |||
{ | |||
((IStructEntityViewEngine)engine).CreateStructEntityViews | |||
(_sharedStructEntityViewLists); | |||
} | |||
if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) | |||
{ | |||
((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews | |||
(_sharedGroupedStructEntityViewLists); | |||
} | |||
return engineAdded; | |||
} | |||
#endif | |||
void CheckEntityViewsEngine(IEngine engine, Type engineType) | |||
{ | |||
var baseType = engineType.GetBaseType(); | |||
if (baseType.IsGenericTypeEx()) | |||
{ | |||
var genericArguments = baseType.GetGenericArguments(); | |||
AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); | |||
#if EXPERIMENTAL | |||
var activableEngine = engine as IHandleActivableEntityEngine; | |||
if (activableEngine != null) | |||
AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); | |||
#endif | |||
return; | |||
} | |||
throw new Exception("Not Supported Engine"); | |||
} | |||
static void AddEngine<T>(T engine, Type[] types, | |||
Dictionary<Type, FasterList<T>> engines) | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
FasterList<T> list; | |||
var type = types[i]; | |||
if (engines.TryGetValue(type, out list) == false) | |||
{ | |||
list = new FasterList<T>(); | |||
engines.Add(type, list); | |||
} | |||
list.Add(engine); | |||
} | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> entityViewsToAdd, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
AddEntityViewToDB(entityViewsDB, entityViewList); | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); | |||
} | |||
} | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, | |||
entityViewList.Key); | |||
} | |||
} | |||
} | |||
void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedEntityViewsToAdd, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var group in groupedEntityViewsToAdd) | |||
{ | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); | |||
AddEntityViewsToGroupDB(groupEntityViewsDB, @group); | |||
} | |||
} | |||
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>(); | |||
foreach (var entityView in @group.Value) | |||
{ | |||
groupedEntityViewsByType.Add(entityView.Key, entityView.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) | |||
{ | |||
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) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int viewsCount; | |||
var entityViews = entityViewsList.ToArrayFast(out viewsCount); | |||
for (int i = 0; i < viewsCount; i++) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
IEntityView entityView = entityViews[i]; | |||
for (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); | |||
#else | |||
fastList[j].Add(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
ITypeSafeList entityViews = entityViewsDB[entityViewType]; | |||
if (entityViews.UnorderedRemove(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); | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); | |||
} | |||
} | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[groupID]; | |||
if (dictionary[entityViewType].UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); | |||
} | |||
InternalRemove(entityViewBuilders, entityID, entityViewsDB); | |||
} | |||
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 (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); | |||
#else | |||
fastList[j].Remove(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) | |||
{ | |||
engine.Add(entityView); | |||
} | |||
static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) | |||
{ | |||
engine.Remove(entityView); | |||
} | |||
#endif | |||
void SubmitEntityViews() | |||
{ | |||
bool newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
int numberOfReenteringLoops = 0; | |||
while (newEntityViewsHaveBeenAddedWhileIterating) | |||
{ | |||
//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); | |||
if ( _metaEntityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); | |||
if (_groupedEntityViewsToAdd.other.Count > 0) | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); | |||
//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; | |||
if (numberOfReenteringLoops > 5) | |||
throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); | |||
numberOfReenteringLoops++; | |||
} | |||
} | |||
readonly Dictionary<Type, FasterList<IHandleEntityViewEngine>> _entityViewEngines; | |||
readonly FasterList<IEngine> _otherEngines; | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _entityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _metaEntityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedEntityViewsToAdd; | |||
readonly EntitySubmissionScheduler _scheduler; | |||
#if EXPERIMENTAL | |||
readonly Type _structEntityViewEngineType; | |||
readonly Type _groupedStructEntityViewsEngineType; | |||
readonly SharedStructEntityViewLists _sharedStructEntityViewLists; | |||
readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
static Action<IHandleEntityViewEngine, IEntityView> _addEntityViewToEngine; | |||
static Action<IHandleEntityViewEngine, IEntityView> _removeEntityViewFromEngine; | |||
#endif | |||
readonly EngineEntityViewDB _engineEntityViewDB; | |||
class DoubleBufferedEntityViews<T> where T : class, IDictionary, new() | |||
{ | |||
readonly T _entityViewsToAddBufferA = new T(); | |||
readonly T _entityViewsToAddBufferB = new T(); | |||
public DoubleBufferedEntityViews() | |||
{ | |||
this.other = _entityViewsToAddBufferA; | |||
this.current = _entityViewsToAddBufferB; | |||
} | |||
public T other { get; private set; } | |||
public T current { get; private set; } | |||
public void Swap() | |||
{ | |||
var toSwap = other; | |||
other = current; | |||
current = toSwap; | |||
} | |||
} | |||
class GenericEntityFactory : IEntityFactory | |||
{ | |||
DataStructures.WeakReference<EnginesRoot> _weakEngine; | |||
public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors = null) 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 BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors); | |||
} | |||
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors); | |||
} | |||
public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); | |||
} | |||
public void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(size); | |||
} | |||
} | |||
class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
public void RemoveEntity(int entityID, IRemoveEntityComponent entityTemplate) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, entityTemplate); | |||
} | |||
public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(metaEntityID); | |||
} | |||
public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
} | |||
public void Dispose() | |||
{ | |||
foreach (var entity in _entityViewsDB) | |||
{ | |||
if (entity.Value.isQueryiableEntityView == true) | |||
{ | |||
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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,238 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Schedulers; | |||
using Svelto.Utilities; | |||
using Svelto.WeakEvents; | |||
#if EXPERIMENTAL | |||
using Svelto.ECS.Experimental; | |||
using Svelto.ECS.Experimental.Internal; | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <summary> | |||
/// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot | |||
/// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks | |||
/// periodically if new entity must be submited to the database and the engines. It's an external | |||
/// dependencies to be indipendent by the running platform as the user can define it. | |||
/// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why | |||
/// it must receive a weak reference of the EnginesRoot callback. | |||
/// </summary> | |||
public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) | |||
{ | |||
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_entityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_metaEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_entityViewsDBdic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_entityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_metaEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_engineEntityViewDB = new EngineEntityViewDB(_entityViewsDB, _entityViewsDBdic, _metaEntityViewsDB, _groupEntityViewsDB); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.Schedule(new WeakAction(SubmitEntityViews)); | |||
#if EXPERIMENTAL | |||
_sharedStructEntityViewLists = new SharedStructEntityViewLists(); | |||
_sharedGroupedStructEntityViewLists = new SharedGroupedStructEntityViewsLists(); | |||
_structEntityViewEngineType = typeof(IStructEntityViewEngine<>); | |||
_groupedStructEntityViewsEngineType = typeof(IGroupedStructEntityViewsEngine<>); | |||
_implementedInterfaceTypes = new Dictionary<Type, Type[]>(); | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
_addEntityViewToEngine = AddEntityViewToEngine; | |||
_removeEntityViewFromEngine = RemoveEntityViewFromEngine; | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
#endif | |||
} | |||
public void AddEngine(IEngine engine) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
Profiler.EngineProfiler.AddEngine(engine); | |||
#endif | |||
var engineType = engine.GetType(); | |||
#if EXPERIMENTAL | |||
bool engineAdded; | |||
var implementedInterfaces = engineType.GetInterfaces(); | |||
CollectImplementedInterfaces(implementedInterfaces); | |||
engineAdded = CheckSpecialEngine(engine); | |||
#endif | |||
var viewEngine = engine as IHandleEntityViewEngine; | |||
if (viewEngine != null) | |||
CheckEntityViewsEngine(viewEngine, engineType); | |||
else | |||
_otherEngines.Add(engine); | |||
var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; | |||
if (queryableEntityViewEngine != null) | |||
{ | |||
queryableEntityViewEngine.entityViewsDB = _engineEntityViewDB; | |||
queryableEntityViewEngine.Ready(); | |||
} | |||
} | |||
#if EXPERIMENTAL | |||
void CollectImplementedInterfaces(Type[] implementedInterfaces) | |||
{ | |||
_implementedInterfaceTypes.Clear(); | |||
var type = typeof(IHandleEntityViewEngine); | |||
for (int index = 0; index < implementedInterfaces.Length; index++) | |||
{ | |||
var interfaceType = implementedInterfaces[index]; | |||
if (type.IsAssignableFrom(interfaceType) == false) | |||
continue; | |||
if (false == interfaceType.IsGenericTypeEx()) | |||
{ | |||
continue; | |||
} | |||
var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); | |||
_implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); | |||
} | |||
} | |||
bool CheckSpecialEngine(IEngine engine) | |||
{ | |||
if (_implementedInterfaceTypes.Count == 0) return false; | |||
bool engineAdded = false; | |||
if (_implementedInterfaceTypes.ContainsKey(_structEntityViewEngineType)) | |||
{ | |||
((IStructEntityViewEngine)engine).CreateStructEntityViews | |||
(_sharedStructEntityViewLists); | |||
} | |||
if (_implementedInterfaceTypes.ContainsKey(_groupedStructEntityViewsEngineType)) | |||
{ | |||
((IGroupedStructEntityViewsEngine)engine).CreateStructEntityViews | |||
(_sharedGroupedStructEntityViewLists); | |||
} | |||
return engineAdded; | |||
} | |||
#endif | |||
void CheckEntityViewsEngine(IEngine engine, Type engineType) | |||
{ | |||
var baseType = engineType.GetBaseType(); | |||
if (baseType.IsGenericTypeEx()) | |||
{ | |||
var genericArguments = baseType.GetGenericArguments(); | |||
AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); | |||
#if EXPERIMENTAL | |||
var activableEngine = engine as IHandleActivableEntityEngine; | |||
if (activableEngine != null) | |||
AddEngine(activableEngine, genericArguments, _activableViewEntitiesEngines); | |||
#endif | |||
return; | |||
} | |||
throw new Exception("Not Supported Engine"); | |||
} | |||
//The T parameter allows to pass datastructure sthat not necessarly are | |||
//defined with IEngine, but must be defined with IEngine implementations | |||
static void AddEngine<T>(T engine, Type[] types, | |||
Dictionary<Type, FasterList<T>> engines) where T:IEngine | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
FasterList<T> list; | |||
var type = types[i]; | |||
if (engines.TryGetValue(type, out list) == false) | |||
{ | |||
list = new FasterList<T>(); | |||
engines.Add(type, list); | |||
} | |||
list.Add(engine); | |||
} | |||
} | |||
readonly Dictionary<Type, FasterList<IHandleEntityViewEngine>> _entityViewEngines; | |||
readonly FasterList<IEngine> _otherEngines; | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _entityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _metaEntityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedEntityViewsToAdd; | |||
readonly EntitySubmissionScheduler _scheduler; | |||
#if EXPERIMENTAL | |||
readonly Type _structEntityViewEngineType; | |||
readonly Type _groupedStructEntityViewsEngineType; | |||
readonly SharedStructEntityViewLists _sharedStructEntityViewLists; | |||
readonly SharedGroupedStructEntityViewsLists _sharedGroupedStructEntityViewLists; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
static Action<IHandleEntityViewEngine, IEntityView> _addEntityViewToEngine; | |||
static Action<IHandleEntityViewEngine, IEntityView> _removeEntityViewFromEngine; | |||
#endif | |||
readonly EngineEntityViewDB _engineEntityViewDB; | |||
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,337 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
#if EXPERIMENTAL | |||
using Svelto.ECS.Experimental; | |||
using Svelto.ECS.Experimental.Internal; | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <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)); | |||
} | |||
public IEntityFunctions GenerateEntityFunctions() | |||
{ | |||
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); | |||
} | |||
/// <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 entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, 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, _entityViewsToAdd.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. | |||
/// </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 = null) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, | |||
implementors); | |||
} | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
entityDescriptor, implementors); | |||
} | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.Default.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
ITypeSafeList dbList; | |||
if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsDB[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); | |||
else | |||
dbList.ReserveCapacity(size); | |||
} | |||
} | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
var removeEntityImplementor = removeInfo as RemoveEntityImplementor; | |||
if (removeEntityImplementor.isInAGroup) | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); | |||
else | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, metaEntityID, _metaEntityViewsDB); | |||
} | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemove(EntityDescriptorTemplate<T>.Default.entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
ITypeSafeList entityViews = entityViewsDB[entityViewType]; | |||
if (entityViews.UnorderedRemove(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); | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, entityViewType); | |||
} | |||
} | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[groupID]; | |||
if (dictionary[entityViewType].UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); | |||
} | |||
InternalRemove(entityViewBuilders, entityID, entityViewsDB); | |||
} | |||
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 (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(_removeEntityViewFromEngine, fastList[j], entityView); | |||
#else | |||
fastList[j].Remove(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
static void AddEntityViewToEngine(IHandleEntityViewEngine engine, IEntityView entityView) | |||
{ | |||
engine.Add(entityView); | |||
} | |||
static void RemoveEntityViewFromEngine(IHandleEntityViewEngine engine, IEntityView entityView) | |||
{ | |||
engine.Remove(entityView); | |||
} | |||
#endif | |||
class GenericEntityFactory : IEntityFactory | |||
{ | |||
DataStructures.WeakReference<EnginesRoot> _weakEngine; | |||
public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors = null) 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 BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors); | |||
} | |||
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors); | |||
} | |||
public void BuildEntityInGroup(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); | |||
} | |||
public void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(size); | |||
} | |||
} | |||
class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, removeInfo); | |||
} | |||
public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(metaEntityID); | |||
} | |||
public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
} | |||
public void Dispose() | |||
{ | |||
foreach (var entity in _entityViewsDB) | |||
{ | |||
if (entity.Value.isQueryiableEntityView == true) | |||
{ | |||
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); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,160 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
#if EXPERIMENTAL | |||
using Svelto.ECS.Experimental; | |||
using Svelto.ECS.Experimental.Internal; | |||
#endif | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
void SubmitEntityViews() | |||
{ | |||
bool newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
int numberOfReenteringLoops = 0; | |||
while (newEntityViewsHaveBeenAddedWhileIterating) | |||
{ | |||
//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); | |||
if (_metaEntityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); | |||
if (_groupedEntityViewsToAdd.other.Count > 0) | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); | |||
//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; | |||
if (numberOfReenteringLoops > 5) | |||
throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); | |||
numberOfReenteringLoops++; | |||
} | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> entityViewsToAdd, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
AddEntityViewToDB(entityViewsDB, entityViewList); | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToEntityViewsDictionary(_entityViewsDBdic, entityViewList.Value, entityViewList.Key); | |||
} | |||
} | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, | |||
entityViewList.Key); | |||
} | |||
} | |||
} | |||
void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedEntityViewsToAdd, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var group in groupedEntityViewsToAdd) | |||
{ | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); | |||
AddEntityViewsToGroupDB(groupEntityViewsDB, @group); | |||
} | |||
} | |||
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>(); | |||
foreach (var entityView in @group.Value) | |||
{ | |||
groupedEntityViewsByType.Add(entityView.Key, entityView.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) | |||
{ | |||
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) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int viewsCount; | |||
var entityViews = entityViewsList.ToArrayFast(out viewsCount); | |||
for (int i = 0; i < viewsCount; i++) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
IEntityView entityView = entityViews[i]; | |||
for (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorAddDuration(_addEntityViewToEngine, fastList[j], entityView); | |||
#else | |||
fastList[j].Add(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,3 +1,5 @@ | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using System; | |||
using System.Collections.Generic; | |||
@@ -8,20 +10,22 @@ namespace Svelto.ECS | |||
IEntityViewBuilder[] entityViewsToBuild { get; } | |||
} | |||
static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
internal static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
{ | |||
public static readonly EntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); | |||
} | |||
public class EntityDescriptorInfo | |||
{ | |||
public readonly IEntityDescriptor descriptor; | |||
public readonly string name; | |||
readonly internal IEntityViewBuilder[] entityViewsToBuild; | |||
readonly internal RemoveEntityImplementor removeEntityImplementor; | |||
internal readonly string name; | |||
public EntityDescriptorInfo(IEntityDescriptor entityDescriptor) | |||
internal EntityDescriptorInfo(IEntityDescriptor descriptor) | |||
{ | |||
descriptor = entityDescriptor; | |||
name = descriptor.ToString(); | |||
entityViewsToBuild = descriptor.entityViewsToBuild; | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); | |||
} | |||
} | |||
} | |||
@@ -31,11 +35,11 @@ namespace Svelto.ECS.Internal | |||
static class EntityFactory | |||
{ | |||
internal static void BuildGroupedEntityViews(int entityID, int groupID, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType, | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
RemoveEntityImplementor removeEntityImplementor = null; | |||
@@ -53,6 +57,8 @@ namespace Svelto.ECS.Internal | |||
groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); | |||
} | |||
//only class EntityView will be returned | |||
//struct EntityView cannot be filled so it will be null. | |||
var entityViewObjectToFill = | |||
BuildEntityView(entityID, groupedEntityViewsTyped, entityViewType, entityViewBuilder); | |||
@@ -62,7 +68,7 @@ namespace Svelto.ECS.Internal | |||
if (entityViewObjectToFill != null) | |||
{ | |||
if (removeEntityImplementor == null) | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor, groupID); | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); | |||
FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, | |||
entityViewsToBuildDescriptor.name); | |||
@@ -70,20 +76,21 @@ namespace Svelto.ECS.Internal | |||
} | |||
} | |||
internal static void BuildEntityViews(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
internal static void BuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.descriptor.entityViewsToBuild; | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
RemoveEntityImplementor removeEntityImplementor = null; | |||
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); | |||
@@ -92,23 +99,26 @@ namespace Svelto.ECS.Internal | |||
//it's a EntityView | |||
if (entityViewObjectToFill != null) | |||
{ | |||
if (removeEntityImplementor == null) | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.descriptor); | |||
FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, | |||
FillEntityView(entityViewObjectToFill as EntityView, implementors, entityViewsToBuildDescriptor.removeEntityImplementor, | |||
entityViewsToBuildDescriptor.name); | |||
} | |||
} | |||
} | |||
static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilderId) | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder) | |||
{ | |||
ITypeSafeList entityViewsList; | |||
var entityViewsPoolWillBeCreated = | |||
entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; | |||
var entityViewObjectToFill = entityViewBuilderId.BuildEntityViewAndAddToList(ref entityViewsList, entityID); | |||
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); | |||
@@ -116,6 +126,13 @@ namespace Svelto.ECS.Internal | |||
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) | |||
{ | |||
@@ -136,12 +153,16 @@ namespace Svelto.ECS.Internal | |||
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 | |||
implementorsByType[componentType] = new Tuple<object, int>(implementor, 0); | |||
} | |||
} | |||
#if DEBUG && !PROFILER | |||
@@ -153,8 +174,8 @@ namespace Svelto.ECS.Internal | |||
int count; | |||
//Very efficent way to collect the fields of every EntityViewType | |||
KeyValuePair<Type, Action<EntityView, object>>[] setters = | |||
entityView.EntityViewBlazingFastReflection(out count); | |||
KeyValuePair<Type, Action<EntityView, object>>[] setters = | |||
FasterList<KeyValuePair<Type, Action<EntityView, object>>>.NoVirt.ToArrayFast(entityView.EntityViewBlazingFastReflection, out count); | |||
var removeEntityComponentType = typeof(IRemoveEntityComponent); | |||
@@ -211,13 +232,7 @@ namespace Svelto.ECS.Internal | |||
item2 = v; | |||
} | |||
} | |||
#endif | |||
//this is used to avoid newing a dictionary every time, but it's used locally only | |||
#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 | |||
#endif | |||
static Dictionary<Type, Type[]> _cachedTypes = new Dictionary<Type, Type[]>(); | |||
const string DUPLICATE_IMPLEMENTOR_ERROR = | |||
@@ -20,19 +20,17 @@ namespace Svelto.ECS | |||
{ | |||
public int ID { get { return _ID; } } | |||
abstract internal KeyValuePair<Type, Action<EntityView, object>>[] | |||
EntityViewBlazingFastReflection(out int count); | |||
protected int _ID; | |||
internal FasterList<KeyValuePair<Type, Action<EntityView, object>>> EntityViewBlazingFastReflection; | |||
internal int _ID; | |||
} | |||
public class EntityView<T>: EntityView where T: EntityView | |||
internal static class EntityView<T> where T: EntityView, new() | |||
{ | |||
internal static TEntityViewType BuildEntityView<TEntityViewType>(int ID) where TEntityViewType: EntityView<T>, new() | |||
internal static T BuildEntityView(int ID) | |||
{ | |||
if (FieldCache.list.Count == 0) | |||
if (FieldCache<T>.list.Count == 0) | |||
{ | |||
var type = typeof(TEntityViewType); | |||
var type = typeof(T); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
@@ -43,26 +41,15 @@ namespace Svelto.ECS | |||
Action<EntityView, object> setter = FastInvoke<EntityView>.MakeSetter(field); | |||
FieldCache.Add(new KeyValuePair<Type, Action<EntityView, object>>(field.FieldType, setter)); | |||
FieldCache<T>.list.Add(new KeyValuePair<Type, Action<EntityView, object>>(field.FieldType, setter)); | |||
} | |||
} | |||
return new TEntityViewType { _ID = ID }; | |||
} | |||
override internal KeyValuePair<Type, Action<EntityView, object>>[] | |||
EntityViewBlazingFastReflection(out int count) | |||
{ | |||
return FasterList<KeyValuePair<Type, Action<EntityView, object>>>.NoVirt.ToArrayFast(FieldCache.list, out count); | |||
return new T { _ID = ID, EntityViewBlazingFastReflection = FieldCache<T>.list }; | |||
} | |||
static class FieldCache | |||
static class FieldCache<W> where W:T | |||
{ | |||
internal static void Add(KeyValuePair<Type, Action<EntityView, object>> setter) | |||
{ | |||
list.Add(setter); | |||
} | |||
internal static readonly FasterList<KeyValuePair<Type, Action<EntityView, object>>> list = new FasterList<KeyValuePair<Type, Action<EntityView, object>>>(); | |||
} | |||
} | |||
@@ -5,26 +5,26 @@ namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewBuilder | |||
{ | |||
IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID); | |||
void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); | |||
ITypeSafeList Preallocate(ref ITypeSafeList list, int size); | |||
Type GetEntityViewType(); | |||
} | |||
public class EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView<EntityViewType>, new() | |||
public class EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView, new() | |||
{ | |||
public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
var entityView = EntityView<EntityViewType>.BuildEntityView<EntityViewType>(entityID); | |||
var lentityView = EntityView<EntityViewType>.BuildEntityView(entityID); | |||
castedList.Add(entityView); | |||
castedList.Add(lentityView); | |||
return entityView; | |||
entityView = lentityView; | |||
} | |||
public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) | |||
@@ -47,19 +47,19 @@ namespace Svelto.ECS | |||
public class EntityStructBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : struct, IEntityStruct | |||
{ | |||
public IEntityView BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID) | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
{ | |||
var entityView = default(EntityViewType); | |||
entityView.ID = entityID; | |||
var lentityView = default(EntityViewType); | |||
lentityView.ID = entityID; | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
castedList.Add(entityView); | |||
castedList.Add(lentityView); | |||
return null; | |||
entityView = null; | |||
} | |||
public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) | |||
@@ -13,7 +13,7 @@ namespace Svelto.ECS.Schedulers | |||
//the entityViews immediatly just because convenient for your game | |||
//logic. This is not how it works. | |||
public class UnitySumbmissionEntityViewScheduler : EntityViewSubmissionScheduler | |||
public class UnitySumbmissionEntityViewScheduler : EntitySubmissionScheduler | |||
{ | |||
public UnitySumbmissionEntityViewScheduler() | |||
{ | |||
@@ -2,7 +2,7 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public class GenericEntityDescriptor<T>:IEntityDescriptor where T : EntityView<T>, new() | |||
public class GenericEntityDescriptor<T>:IEntityDescriptor where T : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
@@ -18,8 +18,8 @@ namespace Svelto.ECS | |||
} | |||
public class GenericEntityDescriptor<T, U> : IEntityDescriptor where T : EntityView<T>, new() | |||
where U : EntityView<U>, new() | |||
public class GenericEntityDescriptor<T, U> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
@@ -34,9 +34,9 @@ namespace Svelto.ECS | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V> : IEntityDescriptor where T : EntityView<T>, new() | |||
where U : EntityView<U>, new() | |||
where V : EntityView<V>, new() | |||
public class GenericEntityDescriptor<T, U, V> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
@@ -51,10 +51,10 @@ namespace Svelto.ECS | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor where T : EntityView<T>, new() | |||
where U : EntityView<U>, new() | |||
where V : EntityView<V>, new() | |||
where W : EntityView<W>, new() | |||
public class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
where W : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
@@ -69,11 +69,11 @@ namespace Svelto.ECS | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor where T : EntityView<T>, new() | |||
where U : EntityView<U>, new() | |||
where V : EntityView<V>, new() | |||
where W : EntityView<W>, new() | |||
where X : EntityView<X>, new() | |||
public class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
where W : EntityView, new() | |||
where X : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
@@ -88,12 +88,12 @@ namespace Svelto.ECS | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor where T : EntityView<T>, new() | |||
where U : EntityView<U>, new() | |||
where V : EntityView<V>, new() | |||
where W : EntityView<W>, new() | |||
where X : EntityView<X>, new() | |||
where Y : EntityView<Y>, new() | |||
public class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
where W : EntityView, new() | |||
where X : EntityView, new() | |||
where Y : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
@@ -4,9 +4,9 @@ namespace Svelto.ECS | |||
{ | |||
public interface IEngineEntityViewDB | |||
{ | |||
FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView<T>, new(); | |||
FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T: EntityView<T>, new(); | |||
FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int group) where T: EntityView<T>, new(); | |||
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(); | |||
T[] QueryEntityViewsAsArray<T>(out int count) where T: IEntityView; | |||
T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T: IEntityView; | |||
@@ -15,8 +15,8 @@ namespace Svelto.ECS | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView; | |||
T QueryEntityView<T>(int ID) where T: IEntityView; | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T: EntityView<T>, new(); | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView<T>, new(); | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T: EntityView, new(); | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView, new(); | |||
} | |||
} | |||
@@ -15,7 +15,7 @@ namespace Svelto.ECS | |||
public interface IEntityFunctions | |||
{ | |||
void RemoveEntity(int entityID, IRemoveEntityComponent template); | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); | |||
void RemoveEntity<T>(int entityID) where T:IEntityDescriptor, new(); | |||
@@ -2,7 +2,7 @@ using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public abstract class MultiEntityViewsEngine<T>:IHandleEntityViewEngine where T:EntityView<T>, new() | |||
public abstract class MultiEntityViewsEngine<T>:IHandleEntityViewEngine where T:EntityView, new() | |||
{ | |||
protected abstract void Add(T entityView); | |||
protected abstract void Remove(T entityView); | |||
@@ -22,8 +22,8 @@ namespace Svelto.ECS.Internal | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class MultiEntityViewsEngine<T, U> : MultiEntityViewsEngine<T> | |||
where T:EntityView<T>, new() | |||
where U:EntityView<U>, new() | |||
where T:EntityView, new() | |||
where U:EntityView, new() | |||
{ | |||
protected abstract void Add(U entityView); | |||
protected abstract void Remove(U entityView); | |||
@@ -55,9 +55,9 @@ namespace Svelto.ECS | |||
} | |||
public abstract class MultiEntityViewsEngine<T, U, V> : MultiEntityViewsEngine<T, U> | |||
where T : EntityView<T>, new() | |||
where U : EntityView<U>, new() | |||
where V : EntityView<V>, new() | |||
where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
{ | |||
protected abstract void Add(V entityView); | |||
protected abstract void Remove(V entityView); | |||
@@ -2,17 +2,20 @@ | |||
{ | |||
sealed class RemoveEntityImplementor : IRemoveEntityComponent | |||
{ | |||
public RemoveEntityImplementor(IEntityDescriptor descriptor, int groupID) : this(descriptor) | |||
public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) | |||
{ | |||
removeEntityInfo = new RemoveEntityInfo(descriptor, groupID); | |||
this.groupID = groupID; | |||
isInAGroup = true; | |||
} | |||
internal RemoveEntityImplementor(IEntityDescriptor descriptor) | |||
internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) | |||
{ | |||
removeEntityInfo = new RemoveEntityInfo(descriptor); | |||
removeEntityInfo = new RemoveEntityInfo(entityViews); | |||
} | |||
internal RemoveEntityInfo removeEntityInfo; | |||
readonly internal RemoveEntityInfo removeEntityInfo; | |||
readonly internal int groupID; | |||
readonly internal bool isInAGroup; | |||
} | |||
} | |||
@@ -23,20 +26,11 @@ namespace Svelto.ECS | |||
public struct RemoveEntityInfo | |||
{ | |||
readonly public IEntityDescriptor descriptor; | |||
readonly public int groupID; | |||
readonly public bool isInAGroup; | |||
public RemoveEntityInfo(IEntityDescriptor descriptor) : this() | |||
{ | |||
this.descriptor = descriptor; | |||
} | |||
public RemoveEntityInfo(IEntityDescriptor descriptor, int groupID) | |||
readonly internal IEntityViewBuilder[] entityViewsToBuild; | |||
public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() | |||
{ | |||
this.descriptor = descriptor; | |||
this.groupID = groupID; | |||
isInAGroup = true; | |||
this.entityViewsToBuild = entityViews; | |||
} | |||
} | |||
} |
@@ -2,7 +2,7 @@ using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class SingleEntityViewEngine<T> : IHandleEntityViewEngine where T:EntityView<T>, new() | |||
public abstract class SingleEntityViewEngine<T> : IHandleEntityViewEngine where T:EntityView, new() | |||
{ | |||
public void Add(IEntityView entityView) | |||
{ | |||