- reworked IEntityViewsDB interface, some breaking renaming and added more functions - added two struct friendly functions as workaround while we wait for the c# byref keyworkd: QueryEntities<T> and ExecutOnEntity<T> - fix the SwapEntityGroup function - various optimizations - implement a simple and efficient way to initialize entity struct values (EntityStructInitializer) - check (in debug only) if entitystruct has only value and primitive types, otherwise throw exception -tags/Rel25a
@@ -1,6 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
@@ -13,24 +14,26 @@ namespace Svelto.ECS.Internal | |||
/// </summary> | |||
public interface ITypeSafeDictionary | |||
{ | |||
ITypeSafeDictionary Create(); | |||
void RemoveEntitiesFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> | |||
entityViewEnginesDB); | |||
void RemoveEntityFromEngines(EGID entityGid, | |||
Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> | |||
entityViewEnginesDB); | |||
void FillWithIndexedEntityViews(ITypeSafeDictionary entityViews); | |||
void AddEntityViewsToEngines(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB); | |||
void AddCapacity(int size); | |||
bool Remove(int idGid); | |||
ITypeSafeDictionary Create(); | |||
int Count { get; } | |||
void FillWithIndexedEntityViews(ITypeSafeDictionary entityViews); | |||
void AddEntityViewsToEngines(Dictionary<Type, FasterList<IHandleEntityViewEngineAbstracted>> entityViewEnginesDB); | |||
} | |||
class TypeSafeDictionary<TValue> : FasterDictionary<int, TValue>, ITypeSafeDictionary where TValue : IEntityData | |||
{ | |||
static Type _type = typeof(TValue); | |||
public TypeSafeDictionary(int size):base(size) | |||
{} | |||
@@ -115,5 +118,32 @@ namespace Svelto.ECS.Internal | |||
{ | |||
return new TypeSafeDictionary<TValue>(); | |||
} | |||
public void ExecuteOnEntityView<W>(int entityGidEntityId, ref W value, ActionRef<TValue, W> action) | |||
{ | |||
uint findIndex; | |||
if (FindIndex(entityGidEntityId, out findIndex)) | |||
{ | |||
action(ref _values[findIndex], ref value); | |||
} | |||
} | |||
public void ExecuteOnEntityView(int entityGidEntityId, ActionRef<TValue> action) | |||
{ | |||
uint findIndex; | |||
if (FindIndex(entityGidEntityId, out findIndex)) | |||
{ | |||
action(ref _values[findIndex]); | |||
} | |||
} | |||
public uint FindElementIndex(int entityGidEntityId) | |||
{ | |||
uint findIndex; | |||
if (FindIndex(entityGidEntityId, out findIndex) == false) throw new Exception(""); | |||
return findIndex; | |||
} | |||
static readonly Type _type = typeof(TValue); | |||
} | |||
} |
@@ -23,7 +23,6 @@ namespace Svelto.ECS | |||
public EGID(int entityID, int groupID) : this() | |||
{ | |||
DBC.Check.Require(groupID != ExclusiveGroups.StandardEntity, "can't use an exclusive group ID"); | |||
_GID = MAKE_GLOBAL_ID(entityID, groupID); | |||
} | |||
@@ -13,17 +13,18 @@ namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
/// <summary> | |||
/// I still need to find a good solution for this. Need to move somewhere else | |||
/// </summary> | |||
static EnginesRoot() | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
/// <summary> | |||
/// I still need to find a good solution for this. Need to move somewhere else | |||
/// </summary> | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Svelto.ECS.Profiler"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
UnityEngine.GameObject.DontDestroyOnLoad(debugEngineObject); | |||
#endif | |||
} | |||
#endif | |||
/// <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 |
@@ -37,23 +37,26 @@ namespace Svelto.ECS | |||
///-------------------------------------------- | |||
void BuildEntity<T>(EGID entityID, object[] implementors) | |||
where T : IEntityDescriptor, new() | |||
EntityStructInitializer BuildEntity<T>(EGID entityID, object[] implementors) | |||
where T : class, IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, | |||
var dic = EntityFactory.BuildGroupedEntityViews(entityID, | |||
_groupedEntityToAdd.current, | |||
EntityDescriptorTemplate<T>.Info, | |||
EntityDescriptorTemplate<T>.Info.entityViewsToBuild, | |||
implementors); | |||
return new EntityStructInitializer(entityID, dic); | |||
} | |||
void BuildEntity(EGID entityID, EntityDescriptorInfo entityDescriptorInfo, | |||
EntityStructInitializer BuildEntity(EGID entityID, IEntityViewBuilder[] entityViewsToBuild, | |||
object[] implementors) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, | |||
var dic = EntityFactory.BuildGroupedEntityViews(entityID, | |||
_groupedEntityToAdd.current, | |||
entityDescriptorInfo, | |||
entityViewsToBuild, | |||
implementors); | |||
return new EntityStructInitializer(entityID, dic); | |||
} | |||
///-------------------------------------------- | |||
@@ -64,7 +67,7 @@ namespace Svelto.ECS | |||
/// TODO: understand if this method is useful in a performance critical | |||
/// scenario | |||
/// </summary> | |||
void Preallocate<T>(int groupID, int size) where T : IEntityDescriptor, new() | |||
void Preallocate<T>(int groupID, int size) where T : class, IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = EntityDescriptorTemplate<T>.Info.entityViewsToBuild; | |||
var count = entityViewsToBuild.Length; | |||
@@ -145,12 +148,10 @@ namespace Svelto.ECS | |||
"can't move an entity to the same group where it already belongs to"); | |||
var entityegid = new EGID(entityID, fromGroupID); | |||
var entityViewBuilders = | |||
((TypeSafeDictionary<EntityInfoView>) _groupEntityDB[fromGroupID][_typeEntityInfoView]) | |||
[entityegid.entityID].entityToBuild; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
var groupedEntities = _groupEntityDB[fromGroupID]; | |||
var entityInfoViewDictionary = (TypeSafeDictionary<EntityInfoView>) groupedEntities[_typeEntityInfoView]; | |||
var entityViewBuilders = entityInfoViewDictionary[entityegid.entityID].entityToBuild; | |||
var entityViewBuildersCount = entityViewBuilders.Length; | |||
Dictionary<Type, ITypeSafeDictionary> groupedEntityViewsTyped; | |||
if (_groupEntityDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) | |||
@@ -159,21 +160,37 @@ namespace Svelto.ECS | |||
_groupEntityDB.Add(toGroupID, groupedEntityViewsTyped); | |||
} | |||
ITypeSafeDictionary toSafeList; | |||
for (var i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
var entityViewBuilder = entityViewBuilders[i]; | |||
var entityViewType = entityViewBuilder.GetEntityType(); | |||
var fromSafeList = groupedEntities[entityViewType]; | |||
ITypeSafeDictionary toSafeList; | |||
var fromSafeList = groupedEntities[entityViewType]; | |||
if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) | |||
groupedEntityViewsTyped[entityViewType] = toSafeList = fromSafeList.Create(); | |||
entityViewBuilder.MoveEntityView(entityegid, fromSafeList, toSafeList); | |||
entityViewBuilder.MoveEntityView(entityegid, toGroupID, fromSafeList, toSafeList); | |||
fromSafeList.Remove(entityegid.entityID); | |||
} | |||
if (groupedEntityViewsTyped.TryGetValue(_typeEntityInfoView, out toSafeList) == false) | |||
groupedEntityViewsTyped[_typeEntityInfoView] = toSafeList = entityInfoViewDictionary.Create(); | |||
EntityViewBuilder<EntityInfoView>.MoveEntityView(entityegid, toGroupID, entityInfoViewDictionary, toSafeList); | |||
entityInfoViewDictionary.Remove(entityegid.entityID); | |||
} | |||
EGID SwapFirstEntityGroup(int fromGroupID, int toGroupId) | |||
{ | |||
var firstID = | |||
((TypeSafeDictionary<EntityInfoView>) _groupEntityDB[fromGroupID][_typeEntityInfoView]).FasterValues[0].ID.entityID; | |||
SwapEntityGroup(firstID, fromGroupID, toGroupId); | |||
return new EGID(firstID, toGroupId); | |||
} | |||
readonly EntityViewsDB _DB; | |||
@@ -182,4 +199,25 @@ namespace Svelto.ECS | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> _groupEntityDB; | |||
static readonly Type _typeEntityInfoView = typeof(EntityInfoView); | |||
} | |||
public struct EntityStructInitializer | |||
{ | |||
public EntityStructInitializer(EGID id, Dictionary<Type, ITypeSafeDictionary> current) | |||
{ | |||
_current = current; | |||
_id = id; | |||
} | |||
public void Init<T>(ref T initializer) where T: struct, IEntityData | |||
{ | |||
var typeSafeDictionary = (TypeSafeDictionary<T>) _current[typeof(T)]; | |||
initializer.ID = _id; | |||
typeSafeDictionary.GetFasterValuesBuffer()[typeSafeDictionary.FindElementIndex(_id.entityID)] = initializer; | |||
} | |||
readonly Dictionary<Type, ITypeSafeDictionary> _current; | |||
readonly EGID _id; | |||
} | |||
} |
@@ -17,44 +17,42 @@ namespace Svelto.ECS | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors) where T : IEntityDescriptor, new() | |||
public EntityStructInitializer BuildEntity<T>(int entityID, object[] implementors) where T : class, IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(new EGID(entityID), implementors); | |||
return _weakEngine.Target.BuildEntity<T>(new EGID(entityID), implementors); | |||
} | |||
public void BuildEntity<T>(int entityID, int groupID, object[] implementors) where T : IEntityDescriptor, new() | |||
public EntityStructInitializer BuildEntity<T>(int entityID, int groupID, object[] implementors) where T : class, IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(new EGID(entityID, groupID), implementors); | |||
return _weakEngine.Target.BuildEntity<T>(new EGID(entityID, groupID), implementors); | |||
} | |||
public void BuildEntity<T>(EGID egid, object[] implementors) where T : IEntityDescriptor, new() | |||
public EntityStructInitializer BuildEntity<T>(EGID egid, object[] implementors) where T : class, IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(egid, implementors); | |||
return _weakEngine.Target.BuildEntity<T>(egid, implementors); | |||
} | |||
public void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors) | |||
public EntityStructInitializer BuildEntity(int entityID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) | |||
{ | |||
_weakEngine.Target.BuildEntity(new EGID(entityID), entityDescriptorInfo, implementors); | |||
return _weakEngine.Target.BuildEntity(new EGID(entityID), entityViewsToBuild, implementors); | |||
} | |||
public void BuildEntity(EGID egid, EntityDescriptorInfo entityDescriptorInfo, object[] implementors) | |||
public EntityStructInitializer BuildEntity(EGID egid, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) | |||
{ | |||
_weakEngine.Target.BuildEntity(egid, entityDescriptorInfo, implementors); | |||
return _weakEngine.Target.BuildEntity(egid, entityViewsToBuild, implementors); | |||
} | |||
public void BuildEntity(int entityID, int groupID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors) | |||
public EntityStructInitializer BuildEntity(int entityID, int groupID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors) | |||
{ | |||
_weakEngine.Target.BuildEntity(new EGID(entityID, groupID), entityDescriptorInfo, implementors); | |||
return _weakEngine.Target.BuildEntity(new EGID(entityID, groupID), entityViewsToBuild, implementors); | |||
} | |||
public void PreallocateEntitySpace<T>(int size) where T : IEntityDescriptor, new() | |||
public void PreallocateEntitySpace<T>(int size) where T : class, IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(ExclusiveGroups.StandardEntity, size); | |||
} | |||
public void PreallocateEntitySpace<T>(int groupID, int size) where T : IEntityDescriptor, new() | |||
public void PreallocateEntitySpace<T>(int groupID, int size) where T : class, IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(groupID, size); | |||
} | |||
@@ -12,7 +12,7 @@ namespace Svelto.ECS | |||
{ | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
internal GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
@@ -46,6 +46,11 @@ namespace Svelto.ECS | |||
{ | |||
_weakReference.Target.SwapEntityGroup(entityID, ExclusiveGroups.StandardEntity, toGroupID); | |||
} | |||
public EGID SwapFirstEntityGroup(int fromGroupID, int toGroupID) | |||
{ | |||
return _weakReference.Target.SwapFirstEntityGroup( fromGroupID, toGroupID); | |||
} | |||
} | |||
} | |||
} |
@@ -19,13 +19,15 @@ namespace Svelto.ECS | |||
public IEntityViewBuilder[] entityViewsToBuild { get; } | |||
} | |||
public static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
public static class EntityDescriptorTemplate<TType> where TType : class, IEntityDescriptor, new() | |||
{ | |||
public static readonly EntityDescriptorInfo Info = new EntityDescriptorInfo(new TType()); | |||
} | |||
public class DynamicEntityDescriptorInfo<TType> : EntityDescriptorInfo where TType : IEntityDescriptor, new() | |||
public struct DynamicEntityDescriptorInfo<TType> where TType : class, IEntityDescriptor, new() | |||
{ | |||
public readonly IEntityViewBuilder[] entityViewsToBuild; | |||
public DynamicEntityDescriptorInfo(FasterList<IEntityViewBuilder> extraEntityViews) | |||
{ | |||
Check.Require(extraEntityViews.Count > 0, | |||
@@ -38,23 +40,16 @@ namespace Svelto.ECS | |||
Array.Copy(defaultEntityViewsToBuild, 0, entityViewsToBuild, 0, length); | |||
Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); | |||
name = EntityDescriptorTemplate<TType>.Info.name; | |||
} | |||
} | |||
public class EntityDescriptorInfo | |||
public struct EntityDescriptorInfo | |||
{ | |||
internal IEntityViewBuilder[] entityViewsToBuild; | |||
internal string name; | |||
public readonly IEntityViewBuilder[] entityViewsToBuild; | |||
internal EntityDescriptorInfo(IEntityDescriptor descriptor) | |||
{ | |||
name = descriptor.ToString(); | |||
entityViewsToBuild = descriptor.entityViewsToBuild; | |||
} | |||
protected EntityDescriptorInfo() | |||
{ } | |||
} | |||
} |
@@ -5,14 +5,16 @@ namespace Svelto.ECS.Internal | |||
{ | |||
static class EntityFactory | |||
{ | |||
internal static void BuildGroupedEntityViews(EGID egid, | |||
internal static Dictionary<Type, ITypeSafeDictionary> BuildGroupedEntityViews(EGID egid, | |||
Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsByType, | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
IEntityViewBuilder[] entityViewsToBuild, | |||
object[] implementors) | |||
{ | |||
var @group = FetchEntityViewGroup(egid.groupID, groupEntityViewsByType); | |||
BuildEntityViewsAndAddToGroup(egid, group, entityViewsToBuildDescriptor, implementors); | |||
BuildEntityViewsAndAddToGroup(egid, group, entityViewsToBuild, implementors); | |||
return group; | |||
} | |||
static Dictionary<Type, ITypeSafeDictionary> FetchEntityViewGroup(int groupID, Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsByType) | |||
@@ -29,32 +31,31 @@ namespace Svelto.ECS.Internal | |||
} | |||
static void BuildEntityViewsAndAddToGroup(EGID entityID, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsByType, | |||
EntityDescriptorInfo entityViewsToBuildDescriptor, | |||
Dictionary<Type, ITypeSafeDictionary> @group, | |||
IEntityViewBuilder[] entityViewsToBuild, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
var count = entityViewsToBuild.Length; | |||
var count = entityViewsToBuild.Length; | |||
for (var index = 0; index < count; ++index) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityType(); | |||
BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder, implementors); | |||
BuildEntityView(entityID, @group, entityViewType, entityViewBuilder, implementors); | |||
} | |||
_viewBuilder._initializer = new EntityInfoView {entityToBuild = entityViewsToBuild}; | |||
BuildEntityView(entityID, entityViewsByType, _viewType, _viewBuilder, null); | |||
BuildEntityView(entityID, @group, _viewType, _viewBuilder, null); | |||
} | |||
static void BuildEntityView(EGID entityID, Dictionary<Type, ITypeSafeDictionary> entityViewsByType, | |||
static void BuildEntityView(EGID entityID, Dictionary<Type, ITypeSafeDictionary> @group, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder, object[] implementors) | |||
{ | |||
ITypeSafeDictionary safeDictionary; | |||
var entityViewsPoolWillBeCreated = | |||
entityViewsByType.TryGetValue(entityViewType, out safeDictionary) == false; | |||
@group.TryGetValue(entityViewType, out safeDictionary) == false; | |||
//passing the undefined entityViewsByType inside the entityViewBuilder will allow | |||
//it to be created with the correct type and casted back to the undefined list. | |||
@@ -62,7 +63,7 @@ namespace Svelto.ECS.Internal | |||
entityViewBuilder.BuildEntityViewAndAddToList(ref safeDictionary, entityID, implementors); | |||
if (entityViewsPoolWillBeCreated) | |||
entityViewsByType.Add(entityViewType, safeDictionary); | |||
@group.Add(entityViewType, safeDictionary); | |||
} | |||
static readonly EntityViewBuilder<EntityInfoView> _viewBuilder = new EntityViewBuilder<EntityInfoView>(); | |||
@@ -1,5 +1,8 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
#if DEBUG && !PROFILER | |||
using System.Reflection; | |||
#endif | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.Utilities; | |||
@@ -8,14 +11,33 @@ namespace Svelto.ECS | |||
{ | |||
public class EntityViewBuilder<T> : IEntityViewBuilder where T : IEntityData, new() | |||
{ | |||
public EntityViewBuilder(ref T initializer) | |||
{ | |||
_initializer = initializer; | |||
} | |||
public EntityViewBuilder() | |||
{ | |||
_initializer = default(T); | |||
#if DEBUG && !PROFILER | |||
if (needsReflection == false && typeof(T) != typeof(EntityInfoView)) | |||
{ | |||
var type = typeof(T); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
if (field.FieldType.IsPrimitive == true || field.FieldType.IsValueType == true) | |||
continue; | |||
throw new EntityStructException(); | |||
} | |||
} | |||
#endif | |||
if (needsReflection == true) | |||
{ | |||
EntityView<T>.InitCache(); | |||
} | |||
} | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors) | |||
@@ -62,24 +84,37 @@ namespace Svelto.ECS | |||
return ENTITY_VIEW_TYPE; | |||
} | |||
public void MoveEntityView(EGID entityID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic) | |||
void IEntityViewBuilder.MoveEntityView(EGID entityID, int toGroupID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic) | |||
{ | |||
MoveEntityView(entityID, toGroupID, fromSafeDic, toSafeDic); | |||
} | |||
public static void MoveEntityView(EGID entityID, int toGroupID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic) | |||
{ | |||
var fromCastedDic = fromSafeDic as TypeSafeDictionary<T>; | |||
var toCastedDic = toSafeDic as TypeSafeDictionary<T>; | |||
toCastedDic.Add(entityID.entityID, fromCastedDic[entityID.entityID]); | |||
var entity = fromCastedDic[entityID.entityID]; | |||
entity.ID = new EGID(entityID.entityID, toGroupID); | |||
toCastedDic.Add(entityID.entityID, entity); | |||
fromCastedDic.Remove(entityID.entityID); | |||
} | |||
FasterList<KeyValuePair<Type, ActionRef<T>>> entityViewBlazingFastReflection | |||
static FasterList<KeyValuePair<Type, ActionCast<T>>> entityViewBlazingFastReflection | |||
{ | |||
get { return EntityView<T>.FieldCache.list; } | |||
get { return EntityView<T>.cachedFields; } | |||
} | |||
static readonly Type ENTITY_VIEW_TYPE = typeof(T); | |||
static string DESCRIPTOR_NAME = ENTITY_VIEW_TYPE.ToString(); | |||
static readonly string DESCRIPTOR_NAME = ENTITY_VIEW_TYPE.ToString(); | |||
static readonly bool needsReflection = typeof(IEntityView).IsAssignableFrom(typeof(T)); | |||
internal T _initializer; | |||
readonly bool needsReflection = typeof(IEntityView).IsAssignableFrom(typeof(T)); | |||
} | |||
public class EntityStructException : Exception | |||
{ | |||
public EntityStructException():base("EntityStruct must contains only value types!") | |||
{} | |||
} | |||
} |
@@ -9,7 +9,7 @@ static class EntityViewUtility | |||
{ | |||
public static void FillEntityView<T>(this IEntityViewBuilder entityViewBuilder | |||
, ref T entityView | |||
, FasterList<KeyValuePair<Type, ActionRef<T>>> entityViewBlazingFastReflection | |||
, FasterList<KeyValuePair<Type, ActionCast<T>>> entityViewBlazingFastReflection | |||
, object[] implementors | |||
, string entityDescriptorName) | |||
{ | |||
@@ -17,7 +17,7 @@ static class EntityViewUtility | |||
//Very efficent way to collect the fields of every EntityViewType | |||
var setters = | |||
FasterList<KeyValuePair<Type, ActionRef<T>>> | |||
FasterList<KeyValuePair<Type, ActionCast<T>>> | |||
.NoVirt.ToArrayFast(entityViewBlazingFastReflection, out count); | |||
#if DEBUG && !PROFILER | |||
if (count == 0) | |||
@@ -1,22 +1,23 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
class EntityViewsDB : IEntityViewsDB | |||
{ | |||
internal EntityViewsDB(Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsDB) | |||
internal EntityViewsDB(Dictionary<int, Dictionary<Type, ITypeSafeDictionary>> groupEntityViewsDB) | |||
{ | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
public ReadOnlyCollectionStruct<T> QueryEntities<T>() where T:IEntityData | |||
public ReadOnlyCollectionStruct<T> QueryEntityViews<T>() where T:class, IEntityData | |||
{ | |||
return QueryEntities<T>(ExclusiveGroups.StandardEntity); | |||
return QueryEntityViews<T>(ExclusiveGroups.StandardEntity); | |||
} | |||
public ReadOnlyCollectionStruct<T> QueryEntities<T>(int @group) where T:IEntityData | |||
public ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int @group) where T:class, IEntityData | |||
{ | |||
Dictionary<Type, ITypeSafeDictionary> entitiesInGroupPerType; | |||
@@ -30,12 +31,12 @@ namespace Svelto.ECS.Internal | |||
return (outList as TypeSafeDictionary<T>).FasterValues; | |||
} | |||
public T[] QueryEntitiesCacheFriendly<T>(out int count) where T : struct, IEntityData | |||
public T[] QueryEntities<T>(out int count) where T : IEntityData | |||
{ | |||
return QueryEntitiesCacheFriendly<T>(ExclusiveGroups.StandardEntity, out count); | |||
return QueryEntities<T>(ExclusiveGroups.StandardEntity, out count); | |||
} | |||
public T[] QueryEntitiesCacheFriendly<T>(int @group, out int count) where T : struct, IEntityData | |||
public T[] QueryEntities<T>(int @group, out int count) where T : IEntityData | |||
{ | |||
count = 0; | |||
@@ -51,6 +52,28 @@ namespace Svelto.ECS.Internal | |||
return ((TypeSafeDictionary<T>)typeSafeDictionary).GetFasterValuesBuffer(out count); | |||
} | |||
public T[] QueryEntities<T>(EGID entityGID, out uint index) where T : IEntityData | |||
{ | |||
TypeSafeDictionary<T> casted; | |||
if (!FindSafeDictionary(entityGID, out casted)) | |||
{ | |||
index = 0; | |||
return null; | |||
} | |||
if (casted != null) | |||
index = casted.FindElementIndex(entityGID.entityID); | |||
else | |||
{ | |||
index = 0; | |||
return null; | |||
} | |||
int count; | |||
return QueryEntities<T>(out count); | |||
} | |||
public T QueryEntityView<T>(EGID entityGID) where T : class, IEntityData | |||
{ | |||
T entityView; | |||
@@ -60,61 +83,84 @@ namespace Svelto.ECS.Internal | |||
return entityView; | |||
} | |||
public void ExecuteOnEntity<T, W>(EGID entityGID, ref W value, ActionRef<T, W> action) where T : IEntityData | |||
{ | |||
TypeSafeDictionary<T> casted; | |||
if (!FindSafeDictionary(entityGID, out casted)) return; | |||
if (casted != null) | |||
casted.ExecuteOnEntityView(entityGID.entityID, ref value, action); | |||
} | |||
public void ExecuteOnEntity<T>(EGID entityGID, ActionRef<T> action) where T : IEntityData | |||
{ | |||
TypeSafeDictionary<T> casted; | |||
if (!FindSafeDictionary(entityGID, out casted)) return; | |||
if (casted != null) | |||
casted.ExecuteOnEntityView(entityGID.entityID, action); | |||
} | |||
public bool Exists<T>(EGID entityGID) where T : IEntityData | |||
{ | |||
TypeSafeDictionary<T> casted; | |||
if (!FindSafeDictionary(entityGID, out casted)) return false; | |||
if (casted != null && | |||
casted.ContainsKey(entityGID.entityID)) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool FindSafeDictionary<T>(EGID entityGID, out TypeSafeDictionary<T> casted) where T : IEntityData | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary entityViews; | |||
Dictionary<Type, ITypeSafeDictionary> entitiesInGroupPerType; | |||
if (_groupEntityViewsDB.TryGetValue(entityGID.groupID, out entitiesInGroupPerType) == false) | |||
{ | |||
casted = null; | |||
return false; | |||
} | |||
entitiesInGroupPerType.TryGetValue(type, out entityViews); | |||
var casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.ContainsKey(entityGID.entityID)) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
return true; | |||
} | |||
public void Fetch<T>(out T entity) where T : IEntityData | |||
public bool HasAny<T>() where T : IEntityData | |||
{ | |||
entity = QueryEntities<T>()[0]; | |||
int count; | |||
QueryEntities<T>(out count); | |||
return count > 0; | |||
} | |||
public bool Has<T>() where T : IEntityData | |||
public bool HasAny<T>(int @group) where T : IEntityData | |||
{ | |||
return QueryEntities<T>().Count > 0; | |||
int count; | |||
QueryEntities<T>(group, out count); | |||
return count > 0; | |||
} | |||
public bool TryQueryEntityView<T>(EGID entityegid, out T entityView) where T : IEntityData | |||
public bool TryQueryEntityView<T>(EGID entityegid, out T entityView) where T : class, IEntityData | |||
{ | |||
return TryQueryEntityViewInGroup(entityegid, out entityView); | |||
} | |||
bool TryQueryEntityViewInGroup<T>(EGID entityGID, out T entityView) where T:IEntityData | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary entityViews; | |||
Dictionary<Type, ITypeSafeDictionary> entitiesInGroupPerType; | |||
if (_groupEntityViewsDB.TryGetValue(entityGID.groupID, out entitiesInGroupPerType) == false) | |||
TypeSafeDictionary<T> casted; | |||
if (!FindSafeDictionary(entityGID, out casted)) | |||
{ | |||
entityView = default(T); | |||
return false; | |||
} | |||
entitiesInGroupPerType.TryGetValue(type, out entityViews); | |||
var casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(entityGID.entityID, out entityView)) | |||
{ | |||
@@ -13,7 +13,6 @@ | |||
} | |||
static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public abstract class GenericEntityDescriptor<T, U> : IEntityDescriptor where T : IEntityData, new() | |||
@@ -16,8 +16,8 @@ namespace Svelto.ECS | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="size"></param> | |||
void PreallocateEntitySpace<T>(int size) where T : IEntityDescriptor, new(); | |||
void PreallocateEntitySpace<T>(int groupID, int size) where T : IEntityDescriptor, new(); | |||
void PreallocateEntitySpace<T>(int size) where T : class, IEntityDescriptor, new(); | |||
void PreallocateEntitySpace<T>(int groupID, int size) where T : class, IEntityDescriptor, new(); | |||
/// <summary> | |||
/// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity | |||
@@ -28,7 +28,7 @@ namespace Svelto.ECS | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity<T>(int entityID, object[] implementors) where T:IEntityDescriptor, new(); | |||
EntityStructInitializer BuildEntity<T>(int entityID, object[] implementors) where T:class, IEntityDescriptor, new(); | |||
/// <summary> | |||
@@ -41,9 +41,9 @@ namespace Svelto.ECS | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity<T>(int entityID, int groupID, object[] implementors) where T:IEntityDescriptor, new(); | |||
EntityStructInitializer BuildEntity<T>(int entityID, int groupID, object[] implementors) where T:class, IEntityDescriptor, new(); | |||
void BuildEntity<T>(EGID egid, object[] implementors) where T:IEntityDescriptor, new(); | |||
EntityStructInitializer BuildEntity<T>(EGID egid, object[] implementors) where T:class, IEntityDescriptor, new(); | |||
/// <summary> | |||
@@ -54,8 +54,8 @@ namespace Svelto.ECS | |||
/// <param name="entityDescriptor"></param> | |||
/// <param name="implementors"></param> | |||
/// | |||
void BuildEntity(int entityID, int groupID, EntityDescriptorInfo entityDescriptor, object[] implementors); | |||
void BuildEntity(int entityID, EntityDescriptorInfo entityDescriptorInfo, object[] implementors); | |||
void BuildEntity(EGID egid, EntityDescriptorInfo entityDescriptorInfo, object[] implementors); | |||
EntityStructInitializer BuildEntity(int entityID, int groupID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors); | |||
EntityStructInitializer BuildEntity(int entityID, IEntityViewBuilder[] entityViewsToBuild, object[] implementors); | |||
EntityStructInitializer BuildEntity(EGID egid, IEntityViewBuilder[] entityViewsToBuild, object[] implementors); | |||
} | |||
} |
@@ -1,3 +1,5 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityFunctions | |||
@@ -11,7 +13,8 @@ namespace Svelto.ECS | |||
void RemoveGroupAndEntities(int groupID); | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID); | |||
void SwapEntityGroup(int entityID, int fromGroupID, int toGroupID = ExclusiveGroups.StandardEntity); | |||
void SwapEntityGroup(int entityID, int toGroupID); | |||
EGID SwapFirstEntityGroup(int fromGroupID = ExclusiveGroups.StandardEntity, int toGroupID = ExclusiveGroups.StandardEntity); | |||
} | |||
} |
@@ -6,7 +6,6 @@ using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
//todo: can I remove the ID from the struct? | |||
public interface IEntityData | |||
{ | |||
EGID ID { get; set; } | |||
@@ -35,33 +34,33 @@ namespace Svelto.ECS | |||
public static class EntityView<T> where T: IEntityData, new() | |||
{ | |||
internal static void BuildEntityView(EGID ID, out T entityView) | |||
internal static readonly FasterList<KeyValuePair<Type, ActionCast<T>>> cachedFields; | |||
static EntityView() | |||
{ | |||
if (FieldCache.list == null) | |||
{ | |||
FieldCache.list = new FasterList<KeyValuePair<Type, ActionRef<T>>>(); | |||
cachedFields = new FasterList<KeyValuePair<Type, ActionCast<T>>>(); | |||
var type = typeof(T); | |||
var type = typeof(T); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
ActionRef<T> setter = FastInvoke<T>.MakeSetter(field); | |||
ActionCast<T> setter = FastInvoke<T>.MakeSetter(field); | |||
FieldCache.list.Add(new KeyValuePair<Type, ActionRef<T>>(field.FieldType, setter)); | |||
} | |||
cachedFields.Add(new KeyValuePair<Type, ActionCast<T>>(field.FieldType, setter)); | |||
} | |||
entityView = new T { ID = ID }; | |||
} | |||
public static class FieldCache | |||
internal static void InitCache() | |||
{} | |||
internal static void BuildEntityView(EGID ID, out T entityView) | |||
{ | |||
public static FasterList<KeyValuePair<Type, ActionRef<T>>> list; | |||
entityView = new T { ID = ID }; | |||
} | |||
} | |||
} | |||
@@ -9,6 +9,6 @@ namespace Svelto.ECS | |||
ITypeSafeDictionary Preallocate(ref ITypeSafeDictionary dictionary, int size); | |||
Type GetEntityType(); | |||
void MoveEntityView(EGID entityID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic); | |||
void MoveEntityView(EGID entityID, int toGroupID, ITypeSafeDictionary fromSafeDic, ITypeSafeDictionary toSafeDic); | |||
} | |||
} |
@@ -1,23 +1,31 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewsDB | |||
{ | |||
//to use with EntityViews, EntityStructs and EntityViewStructs | |||
ReadOnlyCollectionStruct<T> QueryEntities<T>() where T : IEntityData; | |||
ReadOnlyCollectionStruct<T> QueryEntities<T>(int group) where T : IEntityData; | |||
//to use with EntityViews | |||
ReadOnlyCollectionStruct<T> QueryEntityViews<T>() where T : class, IEntityData; | |||
ReadOnlyCollectionStruct<T> QueryEntityViews<T>(int group) where T : class, IEntityData; | |||
//to use with EntityStructs and EntityViewStructs | |||
T[] QueryEntitiesCacheFriendly<T>(out int count) where T : struct, IEntityData; | |||
T[] QueryEntitiesCacheFriendly<T>(int group, out int count) where T : struct, IEntityData; | |||
//to use with EntityViews, EntityStructs and EntityViewStructs | |||
T[] QueryEntities<T>(out int count) where T : IEntityData; | |||
T[] QueryEntities<T>(int group, out int count) where T : IEntityData; | |||
T[] QueryEntities<T>(EGID entityGID, out uint index) where T : IEntityData; | |||
//to use with EntityViews | |||
bool TryQueryEntityView<T>(EGID egid, out T entityView) where T : IEntityData; | |||
bool TryQueryEntityView<T>(EGID egid, out T entityView) where T : class, IEntityData; | |||
T QueryEntityView<T>(EGID egid) where T : class, IEntityData; | |||
//to use with EntityViews, EntityStructs and EntityViewStructs | |||
void ExecuteOnEntity<T, W>(EGID egid, ref W value, ActionRef<T, W> action) where T : IEntityData; | |||
void ExecuteOnEntity<T>(EGID egid, ActionRef<T> action) where T : IEntityData; | |||
bool Exists<T>(EGID egid) where T : IEntityData; | |||
void Fetch<T>(out T entity) where T:IEntityData; | |||
bool Has<T>() where T:IEntityData; | |||
bool HasAny<T>() where T:IEntityData; | |||
bool HasAny<T>(int group) where T:IEntityData; | |||
} | |||
} |
@@ -1,9 +1,10 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
{ | |||
public class Steps : Dictionary<IEngine, Dictionary<int, IStep[]>> | |||
public class Steps : Dictionary<IEngine, IDictionary> | |||
{} | |||
public class To : Dictionary<int, IStep[]> | |||
@@ -18,6 +19,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public class To<C> : Dictionary<C, IStep[]> where C:struct,IConvertible | |||
{} | |||
public interface IStep | |||
{} | |||
@@ -26,11 +30,18 @@ namespace Svelto.ECS | |||
void Step(ref T token, int condition); | |||
} | |||
public interface IStep<T, in C>:IStep where C:struct,IConvertible | |||
{ | |||
void Step(ref T token, C condition); | |||
} | |||
public interface ISequencer | |||
{ | |||
void Next<T>(IEngine engine, ref T param); | |||
void Next<T>(IEngine engine, ref T param, int condition); | |||
void Next<T, C>(IEngine engine, ref T param, C condition) where C : struct, IConvertible; | |||
} | |||
public class Sequencer : ISequencer | |||
@@ -48,13 +59,23 @@ namespace Svelto.ECS | |||
public void Next<T>(IEngine engine, ref T param, int condition) | |||
{ | |||
int branch = condition; | |||
var steps = _steps[engine][branch]; | |||
var steps = (_steps[engine] as Dictionary<int, IStep[]>)[branch]; | |||
if (steps != null) | |||
for (int i = 0; i < steps.Length; i++) | |||
((IStep<T>)steps[i]).Step(ref param, condition); | |||
} | |||
public void Next<T, C>(IEngine engine, ref T param, C condition) where C:struct,IConvertible | |||
{ | |||
C branch = condition; | |||
var steps = (_steps[engine] as Dictionary<C, IStep[]>)[branch]; | |||
if (steps != null) | |||
for (int i = 0; i < steps.Length; i++) | |||
((IStep<T, C>)steps[i]).Step(ref param, condition); | |||
} | |||
Steps _steps; | |||
} | |||