@@ -1,11 +1,22 @@ | |||
# Changelog | |||
All notable changes to this project will be documented in this file. Changes are listed in random order of importance. | |||
## [3.3.1] - 26-2022 | |||
## [3.3.2] - 04-06-2022 | |||
* Internal refactoring to support future features. Currently it may translate to a small performance boost | |||
* IEntityComponent and IEntityViewComponent now implements IBaseEntityComponent. This shouldn't affect existing code | |||
* Improve thread-safety of entity building | |||
* Fixed serious bug that affected the integrity of the EntityIDs values during RemoveEX callbacks | |||
* The point above may result in a performance boost in the Filters updates during submission | |||
* Code is again 2019 compatible (this may have been broken for a while) | |||
* Fix a crash wit the EntityCollection deconstruction while trying to deconstruct an empty collection | |||
## [3.3.1] - 26-04-2022 | |||
* Fixed serious bug that would affect the new IReactOnRemoveEx callbacks | |||
## [3.3.0] - 04-2022 | |||
## [3.3.0] - 11-04-2022 | |||
* INeedEGID and INeedEntityReference interfaces are not deprecated, but still available for backwards compatibility through the define SLOW_SVELTO_SUBMISSION | |||
* There are some minor breaking changes, you may need to rename a bunch of methods calls | |||
@@ -0,0 +1,88 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public readonly struct BT<BufferT1, BufferT2, BufferT3, BufferT4> | |||
{ | |||
public readonly BufferT1 buffer1; | |||
public readonly BufferT2 buffer2; | |||
public readonly BufferT3 buffer3; | |||
public readonly BufferT4 buffer4; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, BufferT4 bufferT4, int count) buffer) : | |||
this() | |||
{ | |||
buffer1 = buffer.bufferT1; | |||
buffer2 = buffer.bufferT2; | |||
buffer3 = buffer.bufferT3; | |||
buffer4 = buffer.bufferT4; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1, BufferT2, BufferT3, BufferT4>( | |||
in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, BufferT4 bufferT4, int count) buffer) | |||
{ | |||
return new BT<BufferT1, BufferT2, BufferT3, BufferT4>(buffer); | |||
} | |||
} | |||
public readonly struct BT<BufferT1, BufferT2, BufferT3> | |||
{ | |||
public readonly BufferT1 buffer1; | |||
public readonly BufferT2 buffer2; | |||
public readonly BufferT3 buffer3; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, int count) buffer) : this() | |||
{ | |||
buffer1 = buffer.bufferT1; | |||
buffer2 = buffer.bufferT2; | |||
buffer3 = buffer.bufferT3; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1, BufferT2, BufferT3>( | |||
in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, int count) buffer) | |||
{ | |||
return new BT<BufferT1, BufferT2, BufferT3>(buffer); | |||
} | |||
} | |||
public readonly struct BT<BufferT1> | |||
{ | |||
public readonly BufferT1 buffer; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, int count) buffer) : this() | |||
{ | |||
this.buffer = buffer.bufferT1; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1>(in (BufferT1 bufferT1, int count) buffer) | |||
{ | |||
return new BT<BufferT1>(buffer); | |||
} | |||
public static implicit operator BufferT1(BT<BufferT1> t) => t.buffer; | |||
} | |||
public readonly struct BT<BufferT1, BufferT2> | |||
{ | |||
public readonly BufferT1 buffer1; | |||
public readonly BufferT2 buffer2; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, BufferT2 bufferT2, int count) buffer) : this() | |||
{ | |||
buffer1 = buffer.bufferT1; | |||
buffer2 = buffer.bufferT2; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1, BufferT2>( | |||
in (BufferT1 bufferT1, BufferT2 bufferT2, int count) buffer) | |||
{ | |||
return new BT<BufferT1, BufferT2>(buffer); | |||
} | |||
} | |||
} |
@@ -29,7 +29,7 @@ namespace Svelto.ECS | |||
public static int counter; | |||
} | |||
public class ComponentID<T> where T : struct, IEntityComponent | |||
public class ComponentID<T> where T : struct, IBaseEntityComponent | |||
{ | |||
public static readonly SharedStaticWrapper<int, ComponentID<T>> id; | |||
@@ -45,7 +45,7 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public class ComponentBuilder<T> : IComponentBuilder where T : struct, IEntityComponent | |||
public class ComponentBuilder<T> : IComponentBuilder where T : struct, IBaseEntityComponent | |||
{ | |||
internal static readonly Type ENTITY_COMPONENT_TYPE; | |||
internal static readonly bool IS_ENTITY_VIEW_COMPONENT; | |||
@@ -104,6 +104,8 @@ namespace Svelto.ECS | |||
public bool isUnmanaged => IS_UNMANAGED; | |||
static ThreadLocal<EntityViewComponentCache> _localCache = new ThreadLocal<EntityViewComponentCache>(() => new EntityViewComponentCache()); | |||
public void BuildEntityAndAddToList(ITypeSafeDictionary dictionary, EGID egid, IEnumerable<object> implementors) | |||
{ | |||
var castedDic = dictionary as ITypeSafeDictionary<T>; | |||
@@ -115,8 +117,7 @@ namespace Svelto.ECS | |||
Check.Require(castedDic.ContainsKey(egid.entityID) == false, | |||
$"building an entity with already used entity id! id: '{(ulong)egid}', {ENTITY_COMPONENT_NAME}"); | |||
this.SetEntityViewComponentImplementors(ref entityComponent, EntityViewComponentCache.cachedFields, | |||
implementors, EntityViewComponentCache.implementorsByType, EntityViewComponentCache.cachedTypes); | |||
this.SetEntityViewComponentImplementors(ref entityComponent, implementors, _localCache.Value); | |||
castedDic.Add(egid.entityID, entityComponent); | |||
} | |||
@@ -156,22 +157,18 @@ namespace Svelto.ECS | |||
readonly T _initializer; | |||
/// <summary> | |||
/// Note: this static class will hold forever the references of the entities implementors. These references | |||
/// are not even cleared when the engines root is destroyed, as they are static references. | |||
/// It must be seen as an application-wide cache system. Honestly, I am not sure if this may cause leaking | |||
/// issues in some kind of applications. To remember. | |||
/// </summary> | |||
static class EntityViewComponentCache | |||
internal class EntityViewComponentCache | |||
{ | |||
internal static readonly FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>> cachedFields; | |||
internal static readonly Dictionary<Type, Type[]> cachedTypes; | |||
internal readonly FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>> cachedFields; | |||
internal readonly Dictionary<Type, Type[]> cachedTypes; | |||
//this is just a local static cache that is cleared after every use | |||
#if DEBUG && !PROFILE_SVELTO | |||
internal static readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType; | |||
internal readonly Dictionary<Type, ECSTuple<object, int>> implementorsByType; | |||
#else | |||
internal static readonly Dictionary<Type, object> implementorsByType; | |||
internal readonly Dictionary<Type, object> implementorsByType; | |||
#endif | |||
static EntityViewComponentCache() | |||
internal EntityViewComponentCache() | |||
{ | |||
cachedFields = new FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>>(); | |||
@@ -8,7 +8,7 @@ namespace Svelto.ECS | |||
/// <summary> | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
public readonly struct EGIDMapper<T> : IEGIDMapper where T : struct, IEntityComponent | |||
public readonly struct EGIDMapper<T> : IEGIDMapper where T : struct, IBaseEntityComponent | |||
{ | |||
public int count => _map.count; | |||
public ExclusiveGroupStruct groupID { get; } | |||
@@ -21,7 +21,6 @@ namespace Svelto.ECS | |||
SharedDictonary.Init(); | |||
SerializationDescriptorMap.Init(); | |||
_swapEntities = SwapEntities; | |||
_removeEntities = RemoveEntities; | |||
_removeGroup = RemoveGroup; | |||
@@ -41,8 +40,9 @@ namespace Svelto.ECS | |||
_entitiesOperations = new EntitiesOperations(); | |||
_idChecker = new FasterDictionary<ExclusiveGroupStruct, HashSet<uint>>(); | |||
_cachedRangeOfSubmittedIndices = new FasterList<(uint, uint)>(); | |||
_cachedIndicesToSwapBeforeSubmissionForFilters = new FasterDictionary<uint, uint>(); | |||
_cachedRangeOfSubmittedIndices = new FasterList<(uint, uint)>(); | |||
_transientEntityIDsLeftAndAffectedByRemoval = new FasterList<uint>(); | |||
_transientEntityIDsLeftWithoutDuplicates = new FasterDictionary<uint, int>(); | |||
_multipleOperationOnSameEGIDChecker = new FasterDictionary<EGID, uint>(); | |||
#if UNITY_NATIVE //because of the thread count, ATM this is only for unity | |||
@@ -62,7 +62,6 @@ namespace Svelto.ECS | |||
new FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwap>>>(); | |||
_reactiveEnginesSwapEx = | |||
new FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwapEx>>>(); | |||
_reactiveEnginesDispose = | |||
new FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>>(); | |||
@@ -2,7 +2,6 @@ | |||
using System.Runtime.CompilerServices; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
@@ -14,8 +13,8 @@ namespace Svelto.ECS | |||
{ | |||
ClearDebugChecks(); //this must be done first as I need the carry the last states after the submission | |||
_entitiesOperations.ExecuteRemoveAndSwappingOperations(_swapEntities, _removeEntities, _removeGroup, | |||
_swapGroup, this); | |||
_entitiesOperations.ExecuteRemoveAndSwappingOperations(_swapEntities, _removeEntities, _removeGroup | |||
, _swapGroup, this); | |||
AddEntities(profiler); | |||
} | |||
@@ -38,9 +37,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
static void RemoveEntities( | |||
FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, FasterList<(uint, string)>>> | |||
removeOperations, FasterList<EGID> entitiesRemoved, EnginesRoot enginesRoot) | |||
static void RemoveEntities | |||
(FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, FasterList<(uint, string)>>> | |||
removeOperations, FasterList<EGID> entitiesRemoved, EnginesRoot enginesRoot) | |||
{ | |||
using (var sampler = new PlatformProfiler("remove Entities")) | |||
{ | |||
@@ -67,8 +66,8 @@ namespace Svelto.ECS | |||
FasterList<(uint, string)> infosToProcess = groupedEntitiesToRemove.value; | |||
fromComponentsDictionary.ExecuteEnginesRemoveCallbacks(infosToProcess, | |||
enginesRoot._reactiveEnginesRemove, group, in sampler); | |||
fromComponentsDictionary.ExecuteEnginesRemoveCallbacks( | |||
infosToProcess, enginesRoot._reactiveEnginesRemove, group, in sampler); | |||
} | |||
} | |||
} | |||
@@ -89,20 +88,34 @@ namespace Svelto.ECS | |||
FasterList<(uint, string)> entityIDsToRemove = groupedEntitiesToRemove.value; | |||
enginesRoot.RemoveEntityFromPersistentFilters(entityIDsToRemove, fromGroup, | |||
componentType, fromComponentsDictionary); | |||
fromComponentsDictionary.RemoveEntitiesFromDictionary(entityIDsToRemove); | |||
//store new count after the entities are removed, plus the number of entities removed | |||
enginesRoot._transientEntityIDsLeftAndAffectedByRemoval.FastClear(); | |||
fromComponentsDictionary.RemoveEntitiesFromDictionary( | |||
entityIDsToRemove, enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); | |||
//important: remove from the filter must happen after remove from the dictionary | |||
//as we need to read the new indices linked to entities after the removal | |||
enginesRoot.RemoveEntitiesFromPersistentFilters( | |||
entityIDsToRemove, fromGroup, componentType, fromComponentsDictionary | |||
, enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); | |||
//store new database count after the entities are removed from the datatabase, plus the number of entities removed | |||
enginesRoot._cachedRangeOfSubmittedIndices.Add(((uint, uint))( | |||
fromComponentsDictionary.count, | |||
fromComponentsDictionary.count + entityIDsToRemove.count)); | |||
fromComponentsDictionary.count | |||
, fromComponentsDictionary.count | |||
+ entityIDsToRemove.count)); | |||
} | |||
} | |||
} | |||
var rangeEnumerator = enginesRoot._cachedRangeOfSubmittedIndices.GetEnumerator(); | |||
//Note, very important: This is exploiting a trick of the removal operation (RemoveEntitiesFromDictionary) | |||
//You may wonder: how can the remove callbacks iterate entities that have been just removed | |||
//from the database? This works just because during a remove, entities are put at the end of the | |||
//array and not actually removed. The entities are not iterated anymore in future just because | |||
//the count of the array decreases. This means that at the end of the array, after the remove | |||
//operations, we will find the collection of entities just removed. The remove callbacks are | |||
//going to iterate the array from the new count to the new count + the number of entities removed | |||
using (sampler.Sample("Execute remove Callbacks Fast")) | |||
{ | |||
foreach (var entitiesToRemove in removeOperations) | |||
@@ -113,27 +126,27 @@ namespace Svelto.ECS | |||
foreach (var groupedEntitiesToRemove in entitiesToRemove.value) | |||
{ | |||
rangeEnumerator.MoveNext(); | |||
var componentType = groupedEntitiesToRemove.key; | |||
ITypeSafeDictionary fromComponentsDictionary = fromGroupDictionary[componentType]; | |||
//get all the engines linked to TValue | |||
if (!enginesRoot._reactiveEnginesRemoveEx.TryGetValue(new RefWrapperType(componentType), | |||
out var entityComponentsEngines)) | |||
if (!enginesRoot._reactiveEnginesRemoveEx.TryGetValue( | |||
componentType, out var entityComponentsEngines)) | |||
continue; | |||
fromComponentsDictionary.ExecuteEnginesRemoveCallbacksFast(entityComponentsEngines, | |||
group, rangeEnumerator.Current, in sampler); | |||
fromComponentsDictionary.ExecuteEnginesRemoveCallbacksFast( | |||
entityComponentsEngines, group, rangeEnumerator.Current, in sampler); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
static void SwapEntities( | |||
FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, | |||
FasterDictionary<ExclusiveGroupStruct, FasterList<(uint, uint, string)>>>> swapEntitiesOperations, | |||
FasterList<(EGID, EGID)> entitiesIDSwaps, EnginesRoot enginesRoot) | |||
static void SwapEntities | |||
(FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, | |||
FasterDictionary<ExclusiveGroupStruct, FasterList<(uint, uint, string)>>>> swapEntitiesOperations | |||
, FasterList<(EGID, EGID)> entitiesIDSwaps, EnginesRoot enginesRoot) | |||
{ | |||
using (var sampler = new PlatformProfiler("Swap entities between groups")) | |||
{ | |||
@@ -151,6 +164,7 @@ namespace Svelto.ECS | |||
using (sampler.Sample("Swap Entities")) | |||
{ | |||
enginesRoot._cachedRangeOfSubmittedIndices.FastClear(); | |||
//Entities to swap are organised in order to minimise the amount of dictionary lookups. | |||
//swapEntitiesOperations iterations happen in the following order: | |||
//for each fromGroup, get all the entities to swap for each component type. | |||
@@ -172,52 +186,39 @@ namespace Svelto.ECS | |||
{ | |||
ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; | |||
ITypeSafeDictionary toComponentsDictionary = | |||
enginesRoot.GetOrAddTypeSafeDictionary(toGroup, | |||
enginesRoot.GetOrAddDBGroup(toGroup), componentType, fromComponentsDictionary); | |||
enginesRoot.GetOrAddTypeSafeDictionary( | |||
toGroup, enginesRoot.GetOrAddDBGroup(toGroup), componentType | |||
, fromComponentsDictionary); | |||
DBC.ECS.Check.Assert(toComponentsDictionary != null, | |||
"something went wrong with the creation of dictionaries"); | |||
DBC.ECS.Check.Assert(toComponentsDictionary != null | |||
, "something went wrong with the creation of dictionaries"); | |||
//this list represents the set of entities that come from fromGroup and need | |||
//to be swapped to toGroup. Most of the times will be 1 of few units. | |||
FasterList<(uint, uint, string)> fromEntityToEntityIDs = entitiesInfoToSwap.value; | |||
int fromDictionaryCountBeforeSubmission = -1; | |||
if (enginesRoot._indicesOfPersistentFiltersUsedByThisComponent.TryGetValue( | |||
new NativeRefWrapperType(componentType), | |||
out NativeDynamicArrayCast<int> listOfFilters)) | |||
{ | |||
enginesRoot._cachedIndicesToSwapBeforeSubmissionForFilters.FastClear(); | |||
fromDictionaryCountBeforeSubmission = fromComponentsDictionary.count - 1; | |||
//add the index of the entities in the component array for each entityID | |||
//BEFORE the submission, as after that the ID will be different | |||
foreach (var (fromEntityID, _, _) in fromEntityToEntityIDs) | |||
enginesRoot._cachedIndicesToSwapBeforeSubmissionForFilters.Add(fromEntityID, | |||
fromComponentsDictionary.GetIndex(fromEntityID)); | |||
} | |||
//ensure that to dictionary has enough room to store the new entities` | |||
toComponentsDictionary.EnsureCapacity((uint)(toComponentsDictionary.count + | |||
(uint)fromEntityToEntityIDs.count)); | |||
//ensure that to dictionary has enough room to store the new entities | |||
toComponentsDictionary.EnsureCapacity( | |||
(uint)(toComponentsDictionary.count + (uint)fromEntityToEntityIDs.count)); | |||
//fortunately swap means that entities are added at the end of each destination | |||
//dictionary list, so we can just iterate the list using the indices ranges added in the | |||
//_cachedIndices | |||
enginesRoot._cachedRangeOfSubmittedIndices.Add(((uint, uint))( | |||
toComponentsDictionary.count, | |||
toComponentsDictionary.count + fromEntityToEntityIDs.count)); | |||
toComponentsDictionary.count | |||
, toComponentsDictionary.count | |||
+ fromEntityToEntityIDs.count)); | |||
fromComponentsDictionary.SwapEntitiesBetweenDictionaries(fromEntityToEntityIDs, | |||
fromGroup, toGroup, toComponentsDictionary); | |||
enginesRoot._transientEntityIDsLeftAndAffectedByRemoval.FastClear(); | |||
if (fromDictionaryCountBeforeSubmission != -1) //this if skips the swap if there are no filters linked to the component | |||
enginesRoot.SwapEntityBetweenPersistentFilters(fromEntityToEntityIDs, | |||
enginesRoot._cachedIndicesToSwapBeforeSubmissionForFilters, | |||
toComponentsDictionary, fromGroup, toGroup, | |||
(uint)fromDictionaryCountBeforeSubmission, listOfFilters); | |||
fromComponentsDictionary.SwapEntitiesBetweenDictionaries( | |||
fromEntityToEntityIDs, fromGroup, toGroup, toComponentsDictionary | |||
, enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); | |||
//important: this must happen after the entities are swapped in the database | |||
enginesRoot.SwapEntityBetweenPersistentFilters( | |||
fromEntityToEntityIDs, fromComponentsDictionary, toComponentsDictionary, fromGroup | |||
, toGroup, componentType, enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); | |||
} | |||
} | |||
} | |||
@@ -234,20 +235,20 @@ namespace Svelto.ECS | |||
var componentType = groupedEntitiesToSwap.key; | |||
//get all the engines linked to TValue | |||
if (!enginesRoot._reactiveEnginesSwap.TryGetValue(new RefWrapperType(componentType), | |||
out var entityComponentsEngines)) | |||
if (!enginesRoot._reactiveEnginesSwap.TryGetValue( | |||
new RefWrapperType(componentType), out var entityComponentsEngines)) | |||
continue; | |||
foreach (var entitiesInfoToSwap in groupedEntitiesToSwap.value) | |||
{ | |||
ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; | |||
ITypeSafeDictionary toComponentsDictionary = GetTypeSafeDictionary(toGroup, | |||
enginesRoot.GetDBGroup(toGroup), componentType); | |||
ITypeSafeDictionary toComponentsDictionary = | |||
GetTypeSafeDictionary(toGroup, enginesRoot.GetDBGroup(toGroup), componentType); | |||
var infosToProcess = entitiesInfoToSwap.value; | |||
toComponentsDictionary.ExecuteEnginesSwapCallbacks(infosToProcess, | |||
entityComponentsEngines, fromGroup, toGroup, in sampler); | |||
toComponentsDictionary.ExecuteEnginesSwapCallbacks( | |||
infosToProcess, entityComponentsEngines, fromGroup, toGroup, in sampler); | |||
} | |||
} | |||
} | |||
@@ -269,16 +270,16 @@ namespace Svelto.ECS | |||
rangeEnumerator.MoveNext(); | |||
//get all the engines linked to TValue | |||
if (!enginesRoot._reactiveEnginesSwapEx.TryGetValue(new RefWrapperType(componentType), | |||
out var entityComponentsEngines)) | |||
if (!enginesRoot._reactiveEnginesSwapEx.TryGetValue( | |||
new RefWrapperType(componentType), out var entityComponentsEngines)) | |||
continue; | |||
ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; | |||
ITypeSafeDictionary toComponentsDictionary = GetTypeSafeDictionary(toGroup, | |||
enginesRoot.GetDBGroup(toGroup), componentType); | |||
ITypeSafeDictionary toComponentsDictionary = | |||
GetTypeSafeDictionary(toGroup, enginesRoot.GetDBGroup(toGroup), componentType); | |||
toComponentsDictionary.ExecuteEnginesSwapCallbacksFast(entityComponentsEngines, | |||
fromGroup, toGroup, rangeEnumerator.Current, in sampler); | |||
toComponentsDictionary.ExecuteEnginesSwapCallbacksFast( | |||
entityComponentsEngines, fromGroup, toGroup, rangeEnumerator.Current, in sampler); | |||
} | |||
} | |||
} | |||
@@ -320,10 +321,14 @@ namespace Svelto.ECS | |||
//all the new entities are added at the end of each dictionary list, so we can | |||
//just iterate the list using the indices ranges added in the _cachedIndices | |||
_cachedRangeOfSubmittedIndices.Add(((uint, uint))(toDictionary.count, | |||
toDictionary.count + fromDictionary.count)); | |||
_cachedRangeOfSubmittedIndices.Add( | |||
((uint, uint))(toDictionary.count, toDictionary.count + fromDictionary.count)); | |||
//Fill the DB with the entity components generated this frame. | |||
fromDictionary.AddEntitiesToDictionary(toDictionary, groupID, entityLocator); | |||
fromDictionary.AddEntitiesToDictionary(toDictionary, groupID | |||
#if SLOW_SVELTO_SUBMISSION | |||
, entityLocator | |||
#endif | |||
); | |||
} | |||
} | |||
} | |||
@@ -345,8 +350,8 @@ namespace Svelto.ECS | |||
var toDictionary = GetTypeSafeDictionary(groupID, groupDB, wrapper); | |||
enumerator.MoveNext(); | |||
toDictionary.ExecuteEnginesAddEntityCallbacksFast(_reactiveEnginesAddEx, groupID, | |||
enumerator.Current, in sampler); | |||
toDictionary.ExecuteEnginesAddEntityCallbacksFast( | |||
_reactiveEnginesAddEx, groupID, enumerator.Current, in sampler); | |||
} | |||
} | |||
} | |||
@@ -373,8 +378,8 @@ namespace Svelto.ECS | |||
//this contains the total number of components ever submitted in the DB | |||
ITypeSafeDictionary toDictionary = GetTypeSafeDictionary(groupID, groupDB, type); | |||
fromDictionary.ExecuteEnginesAddCallbacks(_reactiveEnginesAdd, toDictionary, | |||
groupID, in sampler); | |||
fromDictionary.ExecuteEnginesAddCallbacks( | |||
_reactiveEnginesAdd, toDictionary, groupID, in sampler); | |||
} | |||
} | |||
} | |||
@@ -396,6 +401,7 @@ namespace Svelto.ECS | |||
return _groupedEntityToAdd.AnyEntityCreated() || _entitiesOperations.AnyOperationQueued(); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
void RemoveEntitiesFromGroup(ExclusiveGroupStruct groupID, in PlatformProfiler profiler) | |||
{ | |||
_entityLocator.RemoveAllGroupReferenceLocators(groupID); | |||
@@ -405,8 +411,8 @@ namespace Svelto.ECS | |||
foreach (var dictionaryOfEntities in dictionariesOfEntities) | |||
{ | |||
//RemoveEX happens inside | |||
dictionaryOfEntities.value.ExecuteEnginesRemoveCallbacks_Group(_reactiveEnginesRemove, | |||
_reactiveEnginesRemoveEx, groupID, profiler); | |||
dictionaryOfEntities.value.ExecuteEnginesRemoveCallbacks_Group( | |||
_reactiveEnginesRemove, _reactiveEnginesRemoveEx, groupID, profiler); | |||
} | |||
foreach (var dictionaryOfEntities in dictionariesOfEntities) | |||
@@ -418,8 +424,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
void SwapEntitiesBetweenGroups(ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, | |||
PlatformProfiler platformProfiler) | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
void SwapEntitiesBetweenGroups | |||
(ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, PlatformProfiler platformProfiler) | |||
{ | |||
FasterDictionary<RefWrapperType, ITypeSafeDictionary> fromGroup = GetDBGroup(fromGroupId); | |||
FasterDictionary<RefWrapperType, ITypeSafeDictionary> toGroup = GetOrAddDBGroup(toGroupId); | |||
@@ -435,7 +442,11 @@ namespace Svelto.ECS | |||
ITypeSafeDictionary toDictionary = | |||
GetOrAddTypeSafeDictionary(toGroupId, toGroup, refWrapperType, fromDictionary); | |||
fromDictionary.AddEntitiesToDictionary(toDictionary, toGroupId, this.entityLocator); | |||
fromDictionary.AddEntitiesToDictionary(toDictionary, toGroupId | |||
#if SLOW_SVELTO_SUBMISSION | |||
, this.entityLocator | |||
#endif | |||
); | |||
} | |||
//Call all the callbacks | |||
@@ -447,8 +458,9 @@ namespace Svelto.ECS | |||
ITypeSafeDictionary toDictionary = GetTypeSafeDictionary(toGroupId, toGroup, refWrapperType); | |||
//SwapEX happens inside | |||
fromDictionary.ExecuteEnginesSwapCallbacks_Group(_reactiveEnginesSwap, | |||
_reactiveEnginesSwapEx, toDictionary, fromGroupId, toGroupId, platformProfiler); | |||
fromDictionary.ExecuteEnginesSwapCallbacks_Group(_reactiveEnginesSwap, _reactiveEnginesSwapEx | |||
, toDictionary, fromGroupId, toGroupId | |||
, platformProfiler); | |||
} | |||
//remove entities from dictionaries | |||
@@ -461,9 +473,9 @@ namespace Svelto.ECS | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
ITypeSafeDictionary GetOrAddTypeSafeDictionary(ExclusiveGroupStruct groupId, | |||
FasterDictionary<RefWrapperType, ITypeSafeDictionary> groupPerComponentType, RefWrapperType type, | |||
ITypeSafeDictionary fromDictionary) | |||
ITypeSafeDictionary GetOrAddTypeSafeDictionary | |||
(ExclusiveGroupStruct groupId, FasterDictionary<RefWrapperType, ITypeSafeDictionary> groupPerComponentType | |||
, RefWrapperType type, ITypeSafeDictionary fromDictionary) | |||
{ | |||
//be sure that the TypeSafeDictionary for the entity Type exists | |||
if (groupPerComponentType.TryGetValue(type, out ITypeSafeDictionary toEntitiesDictionary) == false) | |||
@@ -485,8 +497,9 @@ namespace Svelto.ECS | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
static ITypeSafeDictionary GetTypeSafeDictionary(ExclusiveGroupStruct groupID, | |||
FasterDictionary<RefWrapperType, ITypeSafeDictionary> @group, RefWrapperType refWrapper) | |||
static ITypeSafeDictionary GetTypeSafeDictionary | |||
(ExclusiveGroupStruct groupID, FasterDictionary<RefWrapperType, ITypeSafeDictionary> @group | |||
, RefWrapperType refWrapper) | |||
{ | |||
if (@group.TryGetValue(refWrapper, out ITypeSafeDictionary fromTypeSafeDictionary) == false) | |||
{ | |||
@@ -496,10 +509,14 @@ namespace Svelto.ECS | |||
return fromTypeSafeDictionary; | |||
} | |||
readonly DoubleBufferedEntitiesToAdd _groupedEntityToAdd; | |||
readonly EntitiesOperations _entitiesOperations; | |||
readonly FasterList<(uint, uint)> _cachedRangeOfSubmittedIndices; | |||
readonly FasterDictionary<uint, uint> _cachedIndicesToSwapBeforeSubmissionForFilters; | |||
readonly DoubleBufferedEntitiesToAdd _groupedEntityToAdd; | |||
readonly EntitiesOperations _entitiesOperations; | |||
//transient caches>>>>>>>>>>>>>>>>>>>>> | |||
readonly FasterList<(uint, uint)> _cachedRangeOfSubmittedIndices; | |||
readonly FasterDictionary<uint, int> _transientEntityIDsLeftWithoutDuplicates; | |||
readonly FasterList<uint> _transientEntityIDsLeftAndAffectedByRemoval; | |||
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< | |||
static readonly | |||
Action<FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, | |||
@@ -14,19 +14,19 @@ namespace Svelto.ECS | |||
{ | |||
internal EntitiesDB(EnginesRoot enginesRoot, EnginesRoot.EntityReferenceMap entityReferencesMap) | |||
{ | |||
_enginesRoot = enginesRoot; | |||
_enginesRoot = enginesRoot; | |||
_entityReferencesMap = entityReferencesMap; | |||
} | |||
EntityCollection<T> InternalQueryEntities<T> | |||
(FasterDictionary<RefWrapperType, ITypeSafeDictionary> entitiesInGroupPerType) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
uint count = 0; | |||
IBuffer<T> buffer; | |||
EntityIDs ids = default; | |||
IEntityIDs ids = default; | |||
if (SafeQueryEntityDictionary<T>(out var typeSafeDictionary, entitiesInGroupPerType) == false) | |||
buffer = RetrieveEmptyEntityComponentArray<T>(); | |||
buffer = default; | |||
else | |||
{ | |||
ITypeSafeDictionary<T> safeDictionary = (typeSafeDictionary as ITypeSafeDictionary<T>); | |||
@@ -34,7 +34,7 @@ namespace Svelto.ECS | |||
ids = safeDictionary.entityIDs; | |||
} | |||
return new EntityCollection<T>(buffer, count, ids); | |||
return new EntityCollection<T>(buffer, ids, count); | |||
} | |||
/// <summary> | |||
@@ -46,25 +46,24 @@ namespace Svelto.ECS | |||
/// <typeparam name="T"></typeparam> | |||
/// <returns></returns> | |||
public EntityCollection<T> QueryEntities<T>(ExclusiveGroupStruct groupStructId) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
if (groupEntityComponentsDB.TryGetValue(groupStructId, out var entitiesInGroupPerType) == false) | |||
{ | |||
var buffer = RetrieveEmptyEntityComponentArray<T>(); | |||
return new EntityCollection<T>(buffer, 0); | |||
return new EntityCollection<T>(default, default, 0); | |||
} | |||
return InternalQueryEntities<T>(entitiesInGroupPerType); | |||
} | |||
public EntityCollection<T1, T2> QueryEntities<T1, T2>(ExclusiveGroupStruct groupStruct) | |||
where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent | |||
where T1 : struct, IBaseEntityComponent where T2 : struct, IBaseEntityComponent | |||
{ | |||
if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false) | |||
{ | |||
return new EntityCollection<T1, T2>(new EntityCollection<T1>(RetrieveEmptyEntityComponentArray<T1>(), 0) | |||
, new EntityCollection<T2>( | |||
RetrieveEmptyEntityComponentArray<T2>(), 0)); | |||
return new EntityCollection<T1, T2>( | |||
new EntityCollection<T1>(default, default, 0) | |||
, new EntityCollection<T2>(default, default, 0)); | |||
} | |||
var T1entities = InternalQueryEntities<T1>(entitiesInGroupPerType); | |||
@@ -81,16 +80,18 @@ namespace Svelto.ECS | |||
return new EntityCollection<T1, T2>(T1entities, T2entities); | |||
} | |||
public EntityCollection<T1, T2, T3> QueryEntities<T1, T2, T3>(ExclusiveGroupStruct groupStruct) | |||
where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent where T3 : struct, IEntityComponent | |||
where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
{ | |||
if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false) | |||
{ | |||
return new EntityCollection<T1, T2, T3>( | |||
new EntityCollection<T1>(RetrieveEmptyEntityComponentArray<T1>(), 0) | |||
, new EntityCollection<T2>(RetrieveEmptyEntityComponentArray<T2>(), 0) | |||
, new EntityCollection<T3>(RetrieveEmptyEntityComponentArray<T3>(), 0)); | |||
new EntityCollection<T1>(default, default, 0) | |||
, new EntityCollection<T2>(default, default, 0) | |||
, new EntityCollection<T3>(default, default, 0)); | |||
} | |||
var T1entities = InternalQueryEntities<T1>(entitiesInGroupPerType); | |||
@@ -111,18 +112,18 @@ namespace Svelto.ECS | |||
} | |||
public EntityCollection<T1, T2, T3, T4> QueryEntities<T1, T2, T3, T4>(ExclusiveGroupStruct groupStruct) | |||
where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
where T4 : struct, IBaseEntityComponent | |||
{ | |||
if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false) | |||
{ | |||
return new EntityCollection<T1, T2, T3, T4>( | |||
new EntityCollection<T1>(RetrieveEmptyEntityComponentArray<T1>(), 0) | |||
, new EntityCollection<T2>(RetrieveEmptyEntityComponentArray<T2>(), 0) | |||
, new EntityCollection<T3>(RetrieveEmptyEntityComponentArray<T3>(), 0) | |||
, new EntityCollection<T4>(RetrieveEmptyEntityComponentArray<T4>(), 0)); | |||
new EntityCollection<T1>(default, default, 0) | |||
, new EntityCollection<T2>(default, default, 0) | |||
, new EntityCollection<T3>(default, default, 0) | |||
, new EntityCollection<T4>(default, default, 0)); | |||
} | |||
var T1entities = InternalQueryEntities<T1>(entitiesInGroupPerType); | |||
@@ -147,7 +148,7 @@ namespace Svelto.ECS | |||
} | |||
public GroupsEnumerable<T> QueryEntities<T> | |||
(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T : struct, IEntityComponent | |||
(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T : struct, IBaseEntityComponent | |||
{ | |||
return new GroupsEnumerable<T>(this, groups); | |||
} | |||
@@ -158,32 +159,31 @@ namespace Svelto.ECS | |||
/// </summary> | |||
/// <returns></returns> | |||
public GroupsEnumerable<T1, T2> QueryEntities<T1, T2>(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent | |||
where T1 : struct, IBaseEntityComponent where T2 : struct, IBaseEntityComponent | |||
{ | |||
return new GroupsEnumerable<T1, T2>(this, groups); | |||
} | |||
public GroupsEnumerable<T1, T2, T3> QueryEntities<T1, T2, T3> | |||
(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent where T3 : struct, IEntityComponent | |||
(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
{ | |||
return new GroupsEnumerable<T1, T2, T3>(this, groups); | |||
} | |||
public GroupsEnumerable<T1, T2, T3, T4> QueryEntities<T1, T2, T3, T4> | |||
(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
(in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
where T4 : struct, IBaseEntityComponent | |||
{ | |||
return new GroupsEnumerable<T1, T2, T3, T4>(this, groups); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public EGIDMapper<T> QueryMappedEntities<T>(ExclusiveGroupStruct groupStructId) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
if (SafeQueryEntityDictionary<T>(groupStructId, out var typeSafeDictionary) == false) | |||
throw new EntityGroupNotFoundException(typeof(T), groupStructId.ToName()); | |||
@@ -193,7 +193,7 @@ namespace Svelto.ECS | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryQueryMappedEntities<T> | |||
(ExclusiveGroupStruct groupStructId, out EGIDMapper<T> mapper) where T : struct, IEntityComponent | |||
(ExclusiveGroupStruct groupStructId, out EGIDMapper<T> mapper) where T : struct, IBaseEntityComponent | |||
{ | |||
mapper = default; | |||
if (SafeQueryEntityDictionary<T>(groupStructId, out var typeSafeDictionary) == false | |||
@@ -206,7 +206,7 @@ namespace Svelto.ECS | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists<T>(EGID entityGID) where T : struct, IEntityComponent | |||
public bool Exists<T>(EGID entityGID) where T : struct, IBaseEntityComponent | |||
{ | |||
if (SafeQueryEntityDictionary<T>(entityGID.groupID, out var casted) == false) | |||
return false; | |||
@@ -215,7 +215,7 @@ namespace Svelto.ECS | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists<T>(uint id, ExclusiveGroupStruct group) where T : struct, IEntityComponent | |||
public bool Exists<T>(uint id, ExclusiveGroupStruct group) where T : struct, IBaseEntityComponent | |||
{ | |||
if (SafeQueryEntityDictionary<T>(group, out var casted) == false) | |||
return false; | |||
@@ -227,7 +227,7 @@ namespace Svelto.ECS | |||
public bool ExistsAndIsNotEmpty(ExclusiveGroupStruct gid) | |||
{ | |||
if (groupEntityComponentsDB.TryGetValue( | |||
gid, out FasterDictionary<RefWrapperType, ITypeSafeDictionary> group) == true) | |||
gid, out FasterDictionary<RefWrapperType, ITypeSafeDictionary> group) == true) | |||
{ | |||
return group.count > 0; | |||
} | |||
@@ -236,23 +236,23 @@ namespace Svelto.ECS | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool HasAny<T>(ExclusiveGroupStruct groupStruct) where T : struct, IEntityComponent | |||
public bool HasAny<T>(ExclusiveGroupStruct groupStruct) where T : struct, IBaseEntityComponent | |||
{ | |||
return Count<T>(groupStruct) > 0; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public int Count<T>(ExclusiveGroupStruct groupStruct) where T : struct, IEntityComponent | |||
public int Count<T>(ExclusiveGroupStruct groupStruct) where T : struct, IBaseEntityComponent | |||
{ | |||
if (SafeQueryEntityDictionary<T>(groupStruct, out var typeSafeDictionary) == false) | |||
return 0; | |||
return (int) typeSafeDictionary.count; | |||
return (int)typeSafeDictionary.count; | |||
} | |||
public bool FoundInGroups<T1>() where T1 : IEntityComponent | |||
public bool FoundInGroups<T1>() where T1 : IBaseEntityComponent | |||
{ | |||
return groupsPerEntity.ContainsKey(TypeRefWrapper<T1>.wrapper); | |||
return groupsPerComponent.ContainsKey(TypeRefWrapper<T1>.wrapper); | |||
} | |||
public bool IsDisposing => _enginesRoot._isDisposing; | |||
@@ -260,7 +260,7 @@ namespace Svelto.ECS | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
bool SafeQueryEntityDictionary<T> | |||
(out ITypeSafeDictionary typeSafeDictionary | |||
, FasterDictionary<RefWrapperType, ITypeSafeDictionary> entitiesInGroupPerType) where T : IEntityComponent | |||
, FasterDictionary<RefWrapperType, ITypeSafeDictionary> entitiesInGroupPerType) where T : IBaseEntityComponent | |||
{ | |||
if (entitiesInGroupPerType.TryGetValue(new RefWrapperType(TypeCache<T>.type), out var safeDictionary) | |||
== false) | |||
@@ -277,7 +277,7 @@ namespace Svelto.ECS | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
internal bool SafeQueryEntityDictionary<T> | |||
(ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : IEntityComponent | |||
(ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : IBaseEntityComponent | |||
{ | |||
if (UnsafeQueryEntityDictionary(group, TypeCache<T>.type, out var safeDictionary) == false) | |||
{ | |||
@@ -306,33 +306,6 @@ namespace Svelto.ECS | |||
return entitiesInGroupPerType.TryGetValue(new RefWrapperType(type), out typeSafeDictionary); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
static IBuffer<T> RetrieveEmptyEntityComponentArray<T>() where T : struct, IEntityComponent | |||
{ | |||
return EmptyList<T>.emptyArray; | |||
} | |||
static class EmptyList<T> where T : struct, IEntityComponent | |||
{ | |||
internal static readonly IBuffer<T> emptyArray; | |||
static EmptyList() | |||
{ | |||
if (ComponentBuilder<T>.IS_ENTITY_VIEW_COMPONENT) | |||
{ | |||
MB<T> b = default; | |||
emptyArray = b; | |||
} | |||
else | |||
{ | |||
NB<T> b = default; | |||
emptyArray = b; | |||
} | |||
} | |||
} | |||
static readonly FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary> _emptyDictionary = | |||
new FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>(); | |||
@@ -351,7 +324,7 @@ namespace Svelto.ECS | |||
//found indexed by group id. TypeSafeDictionary are never created, they instead point to the ones hold | |||
//by _groupEntityComponentsDB | |||
// <EntityComponentType <groupID <entityID, EntityComponent>>> | |||
FasterDictionary<RefWrapperType, FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>> groupsPerEntity => | |||
FasterDictionary<RefWrapperType, FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>> groupsPerComponent => | |||
_enginesRoot._groupsPerEntity; | |||
EnginesRoot.EntityReferenceMap _entityReferencesMap; | |||
@@ -82,16 +82,8 @@ namespace Svelto.ECS | |||
{ | |||
(_thisSubmissionInfo, _lastSubmittedInfo) = (_lastSubmittedInfo, _thisSubmissionInfo); | |||
///todo: we found a case where entities with reference to other entities were removed | |||
/// in the same frame where the referenced entities are remove too. | |||
/// the callback of the referencing entities were assuming that the reference at that point | |||
/// would be invalid. However since the callbacks were called before the groups are removed | |||
/// the reference were still valid, which was not expected. | |||
/// If the referenced entities were removed one by one instead that with the group, by chance | |||
/// it instead worked because the entities were removed before the callbacks were called. | |||
/// this is why RemoveGroup is happeing before RemoveEntities, however the real fix | |||
/// should be to update all the references before removing the entities from the dictionaries | |||
/// and call the callbacks | |||
/// todo: entity references should be updated before calling all the methods to avoid callbacks handling | |||
/// references that should be marked as invalid. | |||
foreach (var (group, caller) in _lastSubmittedInfo._groupsToRemove) | |||
{ | |||
try | |||
@@ -4,49 +4,25 @@ using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public readonly ref struct EntityCollection<T> where T : struct, IEntityComponent | |||
public readonly ref struct EntityCollection<T> where T : struct, IBaseEntityComponent | |||
{ | |||
static readonly bool IsUnmanaged = TypeSafeDictionary<T>.isUnmanaged; | |||
public EntityCollection(IBuffer<T> buffer, uint count, EntityIDs entityIDs) : this() | |||
{ | |||
DBC.ECS.Check.Require(count == 0 || buffer.isValid, "Buffer is found in impossible state"); | |||
if (IsUnmanaged) | |||
{ | |||
_nativedBuffer = (NB<T>)buffer; | |||
_nativedIndices = entityIDs.nativeIDs; | |||
} | |||
else | |||
{ | |||
_managedBuffer = (MB<T>)buffer; | |||
_managedIndices = entityIDs.managedIDs; | |||
} | |||
this.count = count; | |||
} | |||
public EntityCollection(IBuffer<T> buffer, uint count) : this() | |||
public EntityCollection(IBuffer<T> buffer, IEntityIDs entityIDs, uint count) : this() | |||
{ | |||
DBC.ECS.Check.Require(count == 0 || buffer.isValid, "Buffer is found in impossible state"); | |||
if (IsUnmanaged) | |||
_nativedBuffer = (NB<T>)buffer; | |||
else | |||
_managedBuffer = (MB<T>)buffer; | |||
_buffer = buffer; | |||
_entityIDs = entityIDs; | |||
this.count = count; | |||
} | |||
public uint count { get; } | |||
internal readonly MB<T> _managedBuffer; | |||
internal readonly NB<T> _nativedBuffer; | |||
internal readonly NativeEntityIDs _nativedIndices; | |||
internal readonly ManagedEntityIDs _managedIndices; | |||
internal readonly IBufferBase _buffer; | |||
internal readonly IEntityIDs _entityIDs; | |||
} | |||
public readonly ref struct EntityCollection<T1, T2> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
public readonly ref struct EntityCollection<T1, T2> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
{ | |||
internal EntityCollection(in EntityCollection<T1> array1, in EntityCollection<T2> array2) | |||
{ | |||
@@ -56,59 +32,60 @@ namespace Svelto.ECS | |||
public int count => (int)buffer1.count; | |||
internal EntityCollection<T2> buffer2 | |||
public EntityCollection<T2> buffer2 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal EntityCollection<T1> buffer1 | |||
public EntityCollection<T1> buffer1 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
} | |||
public readonly ref struct EntityCollection<T1, T2, T3> where T3 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T1 : struct, IEntityComponent | |||
public readonly ref struct EntityCollection<T1, T2, T3> where T3 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T1 : struct, IBaseEntityComponent | |||
{ | |||
internal EntityCollection(in EntityCollection<T1> array1, in EntityCollection<T2> array2, | |||
in EntityCollection<T3> array3) | |||
internal EntityCollection | |||
(in EntityCollection<T1> array1, in EntityCollection<T2> array2, in EntityCollection<T3> array3) | |||
{ | |||
buffer1 = array1; | |||
buffer2 = array2; | |||
buffer3 = array3; | |||
} | |||
internal EntityCollection<T1> buffer1 | |||
public EntityCollection<T1> buffer1 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal EntityCollection<T2> buffer2 | |||
public EntityCollection<T2> buffer2 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal EntityCollection<T3> buffer3 | |||
public EntityCollection<T3> buffer3 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal int count => (int)buffer1.count; | |||
public int count => (int)buffer1.count; | |||
} | |||
public readonly ref struct EntityCollection<T1, T2, T3, T4> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
public readonly ref struct EntityCollection<T1, T2, T3, T4> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
where T4 : struct, IBaseEntityComponent | |||
{ | |||
internal EntityCollection(in EntityCollection<T1> array1, in EntityCollection<T2> array2, | |||
in EntityCollection<T3> array3, in EntityCollection<T4> array4) | |||
internal EntityCollection | |||
(in EntityCollection<T1> array1, in EntityCollection<T2> array2, in EntityCollection<T3> array3 | |||
, in EntityCollection<T4> array4) | |||
{ | |||
buffer1 = array1; | |||
buffer2 = array2; | |||
@@ -116,116 +93,30 @@ namespace Svelto.ECS | |||
buffer4 = array4; | |||
} | |||
internal EntityCollection<T1> buffer1 | |||
public EntityCollection<T1> buffer1 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal EntityCollection<T2> buffer2 | |||
public EntityCollection<T2> buffer2 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal EntityCollection<T3> buffer3 | |||
public EntityCollection<T3> buffer3 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal EntityCollection<T4> buffer4 | |||
public EntityCollection<T4> buffer4 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get; | |||
} | |||
internal int count => (int)buffer1.count; | |||
} | |||
public readonly struct BT<BufferT1, BufferT2, BufferT3, BufferT4> | |||
{ | |||
public readonly BufferT1 buffer1; | |||
public readonly BufferT2 buffer2; | |||
public readonly BufferT3 buffer3; | |||
public readonly BufferT4 buffer4; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, BufferT4 bufferT4, int count) buffer) : | |||
this() | |||
{ | |||
buffer1 = buffer.bufferT1; | |||
buffer2 = buffer.bufferT2; | |||
buffer3 = buffer.bufferT3; | |||
buffer4 = buffer.bufferT4; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1, BufferT2, BufferT3, BufferT4>( | |||
in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, BufferT4 bufferT4, int count) buffer) | |||
{ | |||
return new BT<BufferT1, BufferT2, BufferT3, BufferT4>(buffer); | |||
} | |||
} | |||
public readonly struct BT<BufferT1, BufferT2, BufferT3> | |||
{ | |||
public readonly BufferT1 buffer1; | |||
public readonly BufferT2 buffer2; | |||
public readonly BufferT3 buffer3; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, int count) buffer) : this() | |||
{ | |||
buffer1 = buffer.bufferT1; | |||
buffer2 = buffer.bufferT2; | |||
buffer3 = buffer.bufferT3; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1, BufferT2, BufferT3>( | |||
in (BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, int count) buffer) | |||
{ | |||
return new BT<BufferT1, BufferT2, BufferT3>(buffer); | |||
} | |||
} | |||
public readonly struct BT<BufferT1> | |||
{ | |||
public readonly BufferT1 buffer; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, int count) buffer) : this() | |||
{ | |||
this.buffer = buffer.bufferT1; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1>(in (BufferT1 bufferT1, int count) buffer) | |||
{ | |||
return new BT<BufferT1>(buffer); | |||
} | |||
public static implicit operator BufferT1(BT<BufferT1> t) => t.buffer; | |||
} | |||
public readonly struct BT<BufferT1, BufferT2> | |||
{ | |||
public readonly BufferT1 buffer1; | |||
public readonly BufferT2 buffer2; | |||
public readonly int count; | |||
BT(in (BufferT1 bufferT1, BufferT2 bufferT2, int count) buffer) : this() | |||
{ | |||
buffer1 = buffer.bufferT1; | |||
buffer2 = buffer.bufferT2; | |||
count = buffer.count; | |||
} | |||
public static implicit operator BT<BufferT1, BufferT2>( | |||
in (BufferT1 bufferT1, BufferT2 bufferT2, int count) buffer) | |||
{ | |||
return new BT<BufferT1, BufferT2>(buffer); | |||
} | |||
public int count => (int)buffer1.count; | |||
} | |||
} |
@@ -70,21 +70,21 @@ namespace Svelto.ECS | |||
_componentsToBuild = Construct(extraEntities.count, extraEntities.ToArrayFast(out _)); | |||
} | |||
public void Add<T>() where T : struct, IEntityComponent | |||
public void Add<T>() where T : struct, IBaseEntityComponent | |||
{ | |||
IComponentBuilder[] extraEntities = { new ComponentBuilder<T>() }; | |||
_componentsToBuild = Construct(extraEntities.Length, extraEntities); | |||
} | |||
public void Add<T, U>() where T : struct, IEntityComponent where U : struct, IEntityComponent | |||
public void Add<T, U>() where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent | |||
{ | |||
IComponentBuilder[] extraEntities = { new ComponentBuilder<T>(), new ComponentBuilder<U>() }; | |||
_componentsToBuild = Construct(extraEntities.Length, extraEntities); | |||
} | |||
public void Add<T, U, V>() where T : struct, IEntityComponent | |||
where U : struct, IEntityComponent | |||
where V : struct, IEntityComponent | |||
public void Add<T, U, V>() where T : struct, IBaseEntityComponent | |||
where U : struct, IBaseEntityComponent | |||
where V : struct, IBaseEntityComponent | |||
{ | |||
IComponentBuilder[] extraEntities = | |||
{ | |||
@@ -53,15 +53,15 @@ namespace Svelto.ECS | |||
return this; | |||
} | |||
protected void Add<T>() where T : struct, IEntityComponent | |||
protected void Add<T>() where T : struct, IBaseEntityComponent | |||
{ | |||
_dynamicDescriptor.Add<T>(); | |||
} | |||
protected void Add<T, U>() where T : struct, IEntityComponent where U : struct, IEntityComponent | |||
protected void Add<T, U>() where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent | |||
{ | |||
_dynamicDescriptor.Add<T, U>(); | |||
} | |||
protected void Add<T, U, V>() where T : struct, IEntityComponent where U : struct, IEntityComponent where V : struct, IEntityComponent | |||
protected void Add<T, U, V>() where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent | |||
{ | |||
_dynamicDescriptor.Add<T, U, V>(); | |||
} | |||
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class GenericEntityDescriptor<T> : IEntityDescriptor where T : struct, IEntityComponent | |||
public abstract class GenericEntityDescriptor<T> : IEntityDescriptor where T : struct, IBaseEntityComponent | |||
{ | |||
static readonly IComponentBuilder[] _componentBuilders; | |||
static GenericEntityDescriptor() { _componentBuilders = new IComponentBuilder[] {new ComponentBuilder<T>()}; } | |||
@@ -9,7 +9,7 @@ | |||
} | |||
public abstract class GenericEntityDescriptor<T, U> : IEntityDescriptor | |||
where T : struct, IEntityComponent where U : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent | |||
{ | |||
static readonly IComponentBuilder[] _componentBuilders; | |||
@@ -22,7 +22,7 @@ | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V> : IEntityDescriptor | |||
where T : struct, IEntityComponent where U : struct, IEntityComponent where V : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent | |||
{ | |||
static readonly IComponentBuilder[] _componentBuilders; | |||
@@ -40,8 +40,8 @@ | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor | |||
where T : struct, IEntityComponent where U : struct, IEntityComponent where V : struct, IEntityComponent | |||
where W : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent | |||
where W : struct, IBaseEntityComponent | |||
{ | |||
static readonly IComponentBuilder[] _componentBuilders; | |||
@@ -60,8 +60,8 @@ | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor | |||
where T : struct, IEntityComponent where U : struct, IEntityComponent where V : struct, IEntityComponent | |||
where W : struct, IEntityComponent where X : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent | |||
where W : struct, IBaseEntityComponent where X : struct, IBaseEntityComponent | |||
{ | |||
static readonly IComponentBuilder[] _componentBuilders; | |||
@@ -81,8 +81,8 @@ | |||
} | |||
public abstract class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor | |||
where T : struct, IEntityComponent where U : struct, IEntityComponent where V : struct, IEntityComponent | |||
where W : struct, IEntityComponent where X : struct, IEntityComponent where Y : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent | |||
where W : struct, IBaseEntityComponent where X : struct, IBaseEntityComponent where Y : struct, IBaseEntityComponent | |||
{ | |||
static readonly IComponentBuilder[] _componentBuilders; | |||
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS | |||
{ | |||
struct EntityInfoComponent: IEntityComponent | |||
struct EntityInfoComponent: IBaseEntityComponent | |||
{ | |||
public IComponentBuilder[] componentsToBuild; | |||
} |
@@ -16,7 +16,7 @@ namespace Svelto.ECS | |||
public EGID EGID => _ID; | |||
public readonly EntityReference reference; | |||
public void Init<T>(T initializer) where T : struct, IEntityComponent | |||
public void Init<T>(T initializer) where T : struct, IBaseEntityComponent | |||
{ | |||
if (_group.TryGetValue(new RefWrapperType(ComponentBuilder<T>.ENTITY_COMPONENT_TYPE), | |||
out var typeSafeDictionary) == false) | |||
@@ -32,7 +32,7 @@ namespace Svelto.ECS | |||
dictionary.GetDirectValueByRef(findElementIndex) = initializer; | |||
} | |||
public ref T GetOrAdd<T>() where T : struct, IEntityComponent | |||
public ref T GetOrAdd<T>() where T : struct, IBaseEntityComponent | |||
{ | |||
ref var entityDictionary = ref _group.GetOrAdd( | |||
new RefWrapperType(ComponentBuilder<T>.ENTITY_COMPONENT_TYPE), TypeSafeDictionaryFactory<T>.Create); | |||
@@ -41,13 +41,13 @@ namespace Svelto.ECS | |||
return ref dictionary.GetOrAdd(_ID.entityID); | |||
} | |||
public ref T Get<T>() where T : struct, IEntityComponent | |||
public ref T Get<T>() where T : struct, IBaseEntityComponent | |||
{ | |||
return ref (_group[new RefWrapperType(ComponentBuilder<T>.ENTITY_COMPONENT_TYPE)] as ITypeSafeDictionary<T>) | |||
.GetValueByRef(_ID.entityID); | |||
} | |||
public bool Has<T>() where T : struct, IEntityComponent | |||
public bool Has<T>() where T : struct, IBaseEntityComponent | |||
{ | |||
if (_group.TryGetValue(new RefWrapperType(ComponentBuilder<T>.ENTITY_COMPONENT_TYPE), | |||
out var typeSafeDictionary)) | |||
@@ -13,7 +13,7 @@ namespace Svelto.ECS | |||
public ECSTuple(T1 implementor, T2 v) | |||
{ | |||
instance = implementor; | |||
instance = implementor; | |||
numberOfImplementations = v; | |||
} | |||
} | |||
@@ -22,31 +22,28 @@ namespace Svelto.ECS | |||
static class EntityComponentUtility | |||
{ | |||
const string DUPLICATE_IMPLEMENTOR_ERROR = | |||
"<color=teal>Svelto.ECS</color> the same component is implemented with more than one implementor. This is " | |||
+ "considered an error and MUST be fixed. "; | |||
"<color=teal>Svelto.ECS</color> the same component is implemented with more than one implementor. This is " + | |||
"considered an error and MUST be fixed. "; | |||
const string NULL_IMPLEMENTOR_ERROR = | |||
"<color=teal>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid " | |||
+ "performance loss "; | |||
"<color=teal>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid " + | |||
"performance loss "; | |||
const string NOT_FOUND_EXCEPTION = | |||
"<color=teal>Svelto.ECS</color> Implementor not found for an EntityComponent. "; | |||
public static void SetEntityViewComponentImplementors<T> | |||
(this IComponentBuilder componentBuilder, ref T entityComponent | |||
, FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>> entityComponentBlazingFastReflection | |||
, IEnumerable<object> implementors | |||
#if DEBUG && !PROFILE_SVELTO | |||
,Dictionary<Type, ECSTuple<object, int>> implementorsByType | |||
#else | |||
, Dictionary<Type, object> implementorsByType | |||
#endif | |||
, Dictionary<Type, Type[]> cachedTypeInterfaces) | |||
internal static void SetEntityViewComponentImplementors<T>(this IComponentBuilder componentBuilder, | |||
ref T entityComponent, IEnumerable<object> implementors, | |||
ComponentBuilder<T>.EntityViewComponentCache localCache) where T : struct, IBaseEntityComponent | |||
{ | |||
DBC.ECS.Check.Require(implementors != null, NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent " | |||
, componentBuilder | |||
.GetEntityComponentType().ToString())); | |||
DBC.ECS.Check.Require(implementors != null, | |||
NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent ", | |||
componentBuilder.GetEntityComponentType().ToString())); | |||
var cachedTypeInterfaces = localCache.cachedTypes; | |||
var implementorsByType = localCache.implementorsByType; | |||
var entityComponentBlazingFastReflection = localCache.cachedFields; | |||
foreach (var implementor in implementors) | |||
{ | |||
DBC.ECS.Check.Require(implementor != null, "invalid null implementor used to build an entity"); | |||
@@ -95,16 +92,16 @@ namespace Svelto.ECS | |||
if (implementorsByType.TryGetValue(fieldType, out implementor) == false) | |||
{ | |||
var e = new ECSException(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name | |||
+ " - EntityComponent: " + componentBuilder.GetEntityComponentType().Name); | |||
var e = new ECSException(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + | |||
" - EntityComponent: " + componentBuilder.GetEntityComponentType().Name); | |||
throw e; | |||
} | |||
#if DEBUG && !PROFILE_SVELTO | |||
if (implementor.numberOfImplementations > 1) | |||
throw new ECSException(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( | |||
"Component Type: ", fieldType.Name, " implementor: ", implementor.instance.ToString()) + | |||
" - EntityComponent: " + componentBuilder.GetEntityComponentType().Name); | |||
"Component Type: ", fieldType.Name, " implementor: ", implementor.instance.ToString()) + | |||
" - EntityComponent: " + componentBuilder.GetEntityComponentType().Name); | |||
#endif | |||
#if DEBUG && !PROFILE_SVELTO | |||
fieldSetter.Value(ref entityComponent, implementor.instance); | |||
@@ -1,4 +1,5 @@ | |||
using Svelto.DataStructures; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.DataStructures.Native; | |||
using Svelto.ECS.DataStructures; | |||
using Svelto.ECS.Internal; | |||
@@ -45,33 +46,69 @@ namespace Svelto.ECS | |||
} | |||
} | |||
void RemoveEntityFromPersistentFilters(FasterList<(uint, string)> entityIDs, ExclusiveGroupStruct fromGroup, | |||
RefWrapperType refWrapperType, ITypeSafeDictionary fromDic) | |||
/// <summary> | |||
/// Persistent filters are automatically updated by the framework. If entities are removed from the database | |||
/// the filters are updated consequentially. | |||
/// </summary> | |||
/// <param name="entityIDsRemoved"></param> | |||
/// <param name="fromGroup"></param> | |||
/// <param name="refWrapperType"></param> | |||
/// <param name="fromDic"></param> | |||
/// <param name="entityIDsLeftAndAffectedByRemoval"></param> | |||
void RemoveEntitiesFromPersistentFilters | |||
(FasterList<(uint entityID, string)> entityIDsRemoved, ExclusiveGroupStruct fromGroup, RefWrapperType refWrapperType | |||
, ITypeSafeDictionary fromDic, FasterList<uint> entityIDsLeftAndAffectedByRemoval) | |||
{ | |||
//is there any filter used by this component? | |||
if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue(new NativeRefWrapperType(refWrapperType), | |||
out NativeDynamicArrayCast<int> listOfFilters)) | |||
if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue( | |||
new NativeRefWrapperType(refWrapperType), out NativeDynamicArrayCast<int> listOfFilters) == true) | |||
{ | |||
var numberOfFilters = listOfFilters.count; | |||
var filters = _persistentEntityFilters.unsafeValues; | |||
//remove duplicates | |||
_transientEntityIDsLeftWithoutDuplicates.FastClear(); | |||
var entityAffectedCount = entityIDsLeftAndAffectedByRemoval.count; | |||
for (int i = 0; i < entityAffectedCount; i++) | |||
{ | |||
_transientEntityIDsLeftWithoutDuplicates[entityIDsLeftAndAffectedByRemoval[i]] = -1; | |||
} | |||
for (int filterIndex = 0; filterIndex < numberOfFilters; ++filterIndex) | |||
{ | |||
//we are going to remove multiple entities, this means that the dictionary count would decrease | |||
//for each entity removed from each filter | |||
//we need to keep a copy to reset to the original count for each filter | |||
var currentLastIndex = (uint)fromDic.count - 1; | |||
var filters = _persistentEntityFilters.unsafeValues; | |||
var persistentFilter = filters[listOfFilters[filterIndex]]._filtersPerGroup; | |||
if (persistentFilter.TryGetValue(fromGroup, out var groupFilter)) | |||
//foreach filter linked to this component | |||
var persistentFiltersPerGroup = filters[listOfFilters[filterIndex]]._filtersPerGroup; | |||
//get the filter linked to this group | |||
if (persistentFiltersPerGroup.TryGetValue(fromGroup, out var fromGroupFilter)) | |||
{ | |||
var entitiesCount = entityIDs.count; | |||
var entitiesCount = entityIDsRemoved.count; | |||
//foreach entity to remove, remove it from the filter (if present) | |||
for (int entityIndex = 0; entityIndex < entitiesCount; ++entityIndex) | |||
{ | |||
uint fromentityID = entityIDs[entityIndex].Item1; | |||
var fromIndex = fromDic.GetIndex(fromentityID); | |||
//the current entity id to remove | |||
uint fromEntityID = entityIDsRemoved[entityIndex].entityID; | |||
groupFilter.RemoveWithSwapBack(fromentityID, fromIndex, currentLastIndex--); | |||
fromGroupFilter.Remove(fromEntityID); //Remove works even if the ID is not found (just returns false) | |||
} | |||
//when a component is removed from a component array, a remove swap back happens. This means | |||
//that not only we have to remove the index of the component of the entity deleted from the array | |||
//but we need also to update the index of the component that has been swapped in the cell | |||
//of the deleted component | |||
//entityIDsAffectedByRemoval tracks all the entitiesID of the components that need to be updated | |||
//in the filters because their indices in the array changed. | |||
foreach (var entity in _transientEntityIDsLeftWithoutDuplicates) | |||
{ | |||
var entityId = entity.key; | |||
if (fromGroupFilter.Exists(entityId)) //does the entityID that has been swapped exist in the filter? | |||
{ | |||
if (entity.value == -1) | |||
entity.value = (int)fromDic.GetIndex(entityId); //let's find the index of the entityID in the dictionary only once | |||
fromGroupFilter._entityIDToDenseIndex[entityId] = (uint) entity.value; //update the index in the filter of the component that has been swapped | |||
} | |||
} | |||
} | |||
} | |||
@@ -79,73 +116,68 @@ namespace Svelto.ECS | |||
} | |||
//this method is called by the framework only if listOfFilters.count > 0 | |||
void SwapEntityBetweenPersistentFilters(FasterList<(uint, uint, string)> fromEntityToEntityIDs, | |||
FasterDictionary<uint, uint> beforeSubmissionFromIDs, ITypeSafeDictionary toComponentsDictionary, | |||
ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup, uint fromDictionaryCount, | |||
NativeDynamicArrayCast<int> listOfFilters) | |||
void SwapEntityBetweenPersistentFilters | |||
(FasterList<(uint, uint, string)> fromEntityToEntityIDs, ITypeSafeDictionary fromDic | |||
, ITypeSafeDictionary toDic, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup | |||
, RefWrapperType refWrapperType, FasterList<uint> entityIDsLeftAndAffectedByRemoval) | |||
{ | |||
DBC.ECS.Check.Require(listOfFilters.count > 0, "why are you calling this with an empty list?"); | |||
var numberOfFilters = listOfFilters.count; | |||
/// fromEntityToEntityIDs are the ID of the entities to swap from the from group to the to group. | |||
/// for this component type. for each component type, there is only one set of fromEntityToEntityIDs | |||
/// per from/to group. | |||
/// The complexity of this function is that the ToDictionary is already updated, so the toIndex | |||
/// is actually correct and guaranteed to be valid. However the beforeSubmissionFromIDs are the | |||
/// indices of the entities in the FromDictionary BEFORE the submission happens, so before the | |||
/// entities are actually removed from the dictionary. | |||
for (int filterIndex = 0; filterIndex < numberOfFilters; ++filterIndex) | |||
//is there any filter used by this component? | |||
if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue( | |||
new NativeRefWrapperType(refWrapperType), out NativeDynamicArrayCast<int> listOfFilters) == true) | |||
{ | |||
//we are going to remove multiple entities, this means that the dictionary count would decrease | |||
//for each entity removed from each filter | |||
//we need to keep a copy to reset to the original count for each filter | |||
var currentLastIndex = fromDictionaryCount; | |||
//if the group has a filter linked: | |||
EntityFilterCollection persistentFilter = | |||
_persistentEntityFilters.unsafeValues[listOfFilters[filterIndex]]; | |||
if (persistentFilter._filtersPerGroup.TryGetValue(fromGroup, out var fromGroupFilter)) | |||
DBC.ECS.Check.Require(listOfFilters.count > 0, "why are you calling this with an empty list?"); | |||
var numberOfFilters = listOfFilters.count; | |||
//remove duplicates | |||
_transientEntityIDsLeftWithoutDuplicates.FastClear(); | |||
var entityAffectedCount = entityIDsLeftAndAffectedByRemoval.count; | |||
for (int i = 0; i < entityAffectedCount; i++) | |||
{ | |||
EntityFilterCollection.GroupFilters groupFilterTo = default; | |||
_transientEntityIDsLeftWithoutDuplicates[entityIDsLeftAndAffectedByRemoval[i]] = -1; | |||
} | |||
foreach (var (fromEntityID, toEntityID, _) in fromEntityToEntityIDs) | |||
/// fromEntityToEntityIDs are the IDs of the entities to swap from the from group to the to group. | |||
/// for this component type. for each component type, there is only one set of fromEntityToEntityIDs | |||
/// per from/to group. | |||
for (int filterIndex = 0; filterIndex < numberOfFilters; ++filterIndex) | |||
{ | |||
//if the group has a filter linked: | |||
EntityFilterCollection persistentFilter = | |||
_persistentEntityFilters.unsafeValues[listOfFilters[filterIndex]]; | |||
if (persistentFilter._filtersPerGroup.TryGetValue(fromGroup, out var fromGroupFilter)) | |||
{ | |||
//if there is an entity, it must be moved to the to filter | |||
if (fromGroupFilter.Exists(fromEntityID) == true) | |||
{ | |||
var toIndex = toComponentsDictionary.GetIndex(toEntityID); | |||
EntityFilterCollection.GroupFilters groupFilterTo = default; | |||
if (groupFilterTo.isValid == false) | |||
groupFilterTo = persistentFilter.GetOrCreateGroupFilter(toGroup); | |||
groupFilterTo.Add(toEntityID, toIndex); | |||
foreach (var (fromEntityID, toEntityID, _) in fromEntityToEntityIDs) | |||
{ | |||
var toIndex = toDic.GetIndex(toEntityID); //todo: optimize this should be calculated only once and not once per filter | |||
//if there is an entity, it must be moved to the to filter | |||
if (fromGroupFilter.Exists(fromEntityID) == true) | |||
{ | |||
if (groupFilterTo.isValid == false) | |||
groupFilterTo = persistentFilter.GetOrCreateGroupFilter(toGroup); | |||
groupFilterTo.Add(toEntityID, toIndex); | |||
} | |||
} | |||
} | |||
foreach (var (fromEntityID, _, _) in fromEntityToEntityIDs) | |||
{ | |||
//fromIndex is the same of the index in the filter if the entity is in the filter, but | |||
//we need to update the entity index of the last entity swapped from the dictionary even | |||
//in the case when the fromEntity is not present in the filter. | |||
uint fromIndex; //index in the from dictionary | |||
if (fromGroupFilter.Exists(fromEntityID)) | |||
fromIndex = fromGroupFilter._entityIDToDenseIndex[fromEntityID]; | |||
else | |||
fromIndex = beforeSubmissionFromIDs[fromEntityID]; | |||
//Removing an entity from the dictionary may affect the index of the last entity in the | |||
//values dictionary array, so we need to to update the indices of the affected entities. | |||
//must be outside because from may not be present in the filter, but last index is | |||
//for each entity removed from the from group, I have to update it's index in the | |||
//from filter. An entity removed from the DB is always swapped back, which means | |||
//it's current position is taken by the last entity in the dictionary array. | |||
//this means that the index of the last entity will change to the index of the | |||
//replaced entity | |||
foreach (var (fromEntityID, _, _) in fromEntityToEntityIDs) | |||
{ | |||
fromGroupFilter.Remove(fromEntityID); //Remove works even if the ID is not found (just returns false) | |||
} | |||
fromGroupFilter.RemoveWithSwapBack(fromEntityID, fromIndex, currentLastIndex--); | |||
foreach (var entity in _transientEntityIDsLeftWithoutDuplicates) | |||
{ | |||
var entityId = entity.key; | |||
if (fromGroupFilter.Exists(entityId)) | |||
{ | |||
if (entity.value == -1) | |||
entity.value = (int)fromDic.GetIndex(entityId); | |||
fromGroupFilter._entityIDToDenseIndex[entityId] = (uint) entity.value; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -5,7 +5,6 @@ using Svelto.DataStructures; | |||
using Svelto.DataStructures.Native; | |||
using Svelto.ECS.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public struct FilterContextID | |||
@@ -18,6 +17,11 @@ namespace Svelto.ECS | |||
this.id = id; | |||
} | |||
public static FilterContextID GetNewContextID() | |||
{ | |||
return EntitiesDB.SveltoFilters.GetNewContextID(); | |||
} | |||
} | |||
public readonly struct CombinedFilterID | |||
@@ -44,7 +48,7 @@ namespace Svelto.ECS | |||
//since the user can choose their own filterID, in order to avoid collisions between | |||
//filters of the same type, the FilterContext is provided. The type is identified through | |||
//TypeCounter | |||
public static long CombineFilterIDs<T>(CombinedFilterID combinedFilterID) where T: struct, IEntityComponent | |||
public static long CombineFilterIDs<T>(CombinedFilterID combinedFilterID) where T: struct, IBaseEntityComponent | |||
{ | |||
var id = (uint)ComponentID<T>.id.Data; | |||
@@ -134,7 +138,7 @@ namespace Svelto.ECS | |||
[Unity.Collections.NotBurstCompatible] | |||
#endif | |||
public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID, FilterContextID filterContextId) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId)); | |||
} | |||
@@ -142,7 +146,7 @@ namespace Svelto.ECS | |||
[Unity.Collections.NotBurstCompatible] | |||
#endif | |||
public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID); | |||
@@ -163,13 +167,13 @@ namespace Svelto.ECS | |||
} | |||
public ref EntityFilterCollection GetPersistentFilter<T>(int filterID, FilterContextID filterContextId) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return ref GetPersistentFilter<T>(new CombinedFilterID(filterID, filterContextId)); | |||
} | |||
public ref EntityFilterCollection GetPersistentFilter<T>(CombinedFilterID filterID) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID); | |||
@@ -180,7 +184,7 @@ namespace Svelto.ECS | |||
} | |||
public bool TryGetPersistentFilter<T>(CombinedFilterID combinedFilterID, out EntityFilterCollection entityCollection) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(combinedFilterID); | |||
@@ -194,7 +198,7 @@ namespace Svelto.ECS | |||
return false; | |||
} | |||
public EntityFilterCollectionsEnumerator GetPersistentFilters<T>() where T : unmanaged, IEntityComponent | |||
public EntityFilterCollectionsEnumerator GetPersistentFilters<T>() where T : unmanaged, IBaseEntityComponent | |||
{ | |||
if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( | |||
new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true) | |||
@@ -309,7 +313,7 @@ namespace Svelto.ECS | |||
/// <typeparam name="T"></typeparam> | |||
/// <returns></returns> | |||
public ref EntityFilterCollection GetOrCreateTransientFilter<T>(CombinedFilterID filterID) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID); | |||
@@ -324,7 +328,7 @@ namespace Svelto.ECS | |||
} | |||
public bool TryGetTransientFilter<T>(CombinedFilterID filterID, out EntityFilterCollection entityCollection) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs<T>(filterID); | |||
@@ -32,14 +32,14 @@ namespace Svelto.ECS | |||
} | |||
public ref LegacyFilterGroup CreateOrGetFilterForGroup<T>(int filterID, ExclusiveGroupStruct groupID) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
var refWrapper = TypeRefWrapper<T>.wrapper; | |||
return ref CreateOrGetFilterForGroup(filterID, groupID, refWrapper); | |||
} | |||
public bool HasFiltersForGroup<T>(ExclusiveGroupStruct groupID) where T : struct, IEntityComponent | |||
public bool HasFiltersForGroup<T>(ExclusiveGroupStruct groupID) where T : struct, IBaseEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(TypeRefWrapper<T>.wrapper, out var fasterDictionary) == false) | |||
return false; | |||
@@ -48,7 +48,7 @@ namespace Svelto.ECS | |||
} | |||
public bool HasFilterForGroup<T>(int filterID, ExclusiveGroupStruct groupID) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
if (_filtersLegacy.TryGetValue(TypeRefWrapper<T>.wrapper, out var fasterDictionary) == false) | |||
return false; | |||
@@ -60,7 +60,7 @@ namespace Svelto.ECS | |||
} | |||
public ref LegacyGroupFilters CreateOrGetFiltersForGroup<T>(ExclusiveGroupStruct groupID) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
var fasterDictionary = _filtersLegacy.GetOrAdd(TypeRefWrapper<T>.wrapper, | |||
() => new FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>()); | |||
@@ -70,7 +70,7 @@ namespace Svelto.ECS | |||
} | |||
public ref LegacyGroupFilters GetFiltersForGroup<T>(ExclusiveGroupStruct groupID) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
#if DEBUG && !PROFILE_SVELTO | |||
if (_filtersLegacy.ContainsKey(TypeRefWrapper<T>.wrapper) == false) | |||
@@ -84,7 +84,7 @@ namespace Svelto.ECS | |||
} | |||
public ref LegacyFilterGroup GetFilterForGroup<T>(int filterId, ExclusiveGroupStruct groupID) | |||
where T : struct, IEntityComponent | |||
where T : struct, IBaseEntityComponent | |||
{ | |||
#if DEBUG && !PROFILE_SVELTO | |||
if (_filtersLegacy.ContainsKey(TypeRefWrapper<T>.wrapper) == false) | |||
@@ -97,7 +97,7 @@ namespace Svelto.ECS | |||
} | |||
public bool TryGetFilterForGroup<T>(int filterId, ExclusiveGroupStruct groupID, | |||
out LegacyFilterGroup groupLegacyFilter) where T : struct, IEntityComponent | |||
out LegacyFilterGroup groupLegacyFilter) where T : struct, IBaseEntityComponent | |||
{ | |||
groupLegacyFilter = default; | |||
@@ -114,7 +114,7 @@ namespace Svelto.ECS | |||
} | |||
public bool TryGetFiltersForGroup<T>(ExclusiveGroupStruct groupID, | |||
out LegacyGroupFilters legacyGroupFilters) where T : struct, IEntityComponent | |||
out LegacyGroupFilters legacyGroupFilters) where T : struct, IBaseEntityComponent | |||
{ | |||
legacyGroupFilters = default; | |||
@@ -166,7 +166,7 @@ namespace Svelto.ECS | |||
fasterDictionary[@group].DisposeFilter(resetFilterID); | |||
} | |||
public bool TryRemoveEntityFromFilter<T>(int filtersID, EGID egid) where T : struct, IEntityComponent | |||
public bool TryRemoveEntityFromFilter<T>(int filtersID, EGID egid) where T : struct, IBaseEntityComponent | |||
{ | |||
if (TryGetFilterForGroup<T>(filtersID, egid.groupID, out var filter)) | |||
return filter.TryRemove(egid.entityID); | |||
@@ -174,7 +174,7 @@ namespace Svelto.ECS | |||
return false; | |||
} | |||
public void RemoveEntityFromFilter<T>(int filtersID, EGID egid) where T : struct, IEntityComponent | |||
public void RemoveEntityFromFilter<T>(int filtersID, EGID egid) where T : struct, IBaseEntityComponent | |||
{ | |||
ref var filter = ref GetFilterForGroup<T>(filtersID, egid.groupID); | |||
@@ -1,4 +1,5 @@ | |||
using System.Runtime.CompilerServices; | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.Common; | |||
using Svelto.DataStructures.Native; | |||
using Svelto.ECS.Native; | |||
@@ -21,14 +22,14 @@ namespace Svelto.ECS | |||
public EntityFilterIterator GetEnumerator() => new EntityFilterIterator(this); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Add<T>(EGID egid, NativeEGIDMapper<T> mmap) where T : unmanaged, IEntityComponent | |||
public bool Add<T>(EGID egid, NativeEGIDMapper<T> mmap) where T : unmanaged, IBaseEntityComponent | |||
{ | |||
DBC.ECS.Check.Require(mmap.groupID == egid.groupID, "not compatible NativeEgidMapper used"); | |||
return Add(egid, mmap.GetIndex(egid.entityID)); | |||
} | |||
public bool Add<T>(EGID egid, NativeEGIDMultiMapper<T> mmap) where T : unmanaged, IEntityComponent | |||
public bool Add<T>(EGID egid, NativeEGIDMultiMapper<T> mmap) where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return Add(egid, mmap.GetIndex(egid)); | |||
} | |||
@@ -50,6 +51,12 @@ namespace Svelto.ECS | |||
{ | |||
_filtersPerGroup[egid.groupID].Remove(egid.entityID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Remove(uint entityID, ExclusiveGroupStruct groupID) | |||
{ | |||
_filtersPerGroup[groupID].Remove(entityID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists(EGID egid) | |||
@@ -78,6 +85,15 @@ namespace Svelto.ECS | |||
return groupFilter; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public GroupFilters GetGroupFilter(ExclusiveGroupStruct group) | |||
{ | |||
if (_filtersPerGroup.TryGetValue(group, out var groupFilter) == true) | |||
return groupFilter; | |||
throw new Exception($"no filter linked to group {group}"); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Clear() | |||
@@ -126,32 +142,28 @@ namespace Svelto.ECS | |||
internal GroupFilters(ExclusiveGroupStruct group) : this() | |||
{ | |||
_entityIDToDenseIndex = new SharedSveltoDictionaryNative<uint, uint>(1); | |||
_indexToEntityId = new SharedSveltoDictionaryNative<uint, uint>(1); | |||
_group = group; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Add(uint entityId, uint entityIndex) | |||
{ | |||
//TODO: when sentinels are finished, we need to add AsWriter here | |||
if (_entityIDToDenseIndex.TryAdd(entityId, entityIndex, out _)) | |||
{ | |||
_indexToEntityId[entityIndex] = entityId; | |||
return true; | |||
} | |||
return false; | |||
return _entityIDToDenseIndex.TryAdd(entityId, entityIndex, out _); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists(uint entityId) => _entityIDToDenseIndex.ContainsKey(entityId); | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Remove(uint entityId) | |||
{ | |||
_indexToEntityId.Remove(_entityIDToDenseIndex[entityId]); | |||
_entityIDToDenseIndex.Remove(entityId); | |||
} | |||
public EntityFilterIndices indices | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get | |||
{ | |||
var values = _entityIDToDenseIndex.GetValues(out var count); | |||
@@ -159,48 +171,29 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public uint this[uint entityId] | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _entityIDToDenseIndex[entityId]; | |||
} | |||
public int count => _entityIDToDenseIndex.count; | |||
public bool isValid => _entityIDToDenseIndex.isValid; | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
internal void RemoveWithSwapBack(uint entityId, uint entityIndex, uint lastIndex) | |||
{ | |||
// Check if the last index is part of the filter as an entity, in that case | |||
//we need to update the filter | |||
if (entityIndex != lastIndex && _indexToEntityId.TryGetValue(lastIndex, out var lastEntityID)) | |||
{ | |||
_entityIDToDenseIndex[lastEntityID] = entityIndex; | |||
_indexToEntityId[entityIndex] = lastEntityID; | |||
_indexToEntityId.Remove(lastIndex); | |||
} | |||
else | |||
{ | |||
// We don't need to check if the entityIndex is a part of the dictionary. | |||
// The Remove function will check for us. | |||
_indexToEntityId.Remove(entityIndex); | |||
} | |||
// We don't need to check if the entityID is part of the dictionary. | |||
// The Remove function will check for us. | |||
_entityIDToDenseIndex.Remove(entityId); | |||
} | |||
internal void Clear() | |||
{ | |||
_indexToEntityId.FastClear(); | |||
_entityIDToDenseIndex.FastClear(); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
internal void Dispose() | |||
{ | |||
_entityIDToDenseIndex.Dispose(); | |||
_indexToEntityId.Dispose(); | |||
} | |||
internal ExclusiveGroupStruct group => _group; | |||
SharedSveltoDictionaryNative<uint, uint> _indexToEntityId; | |||
internal SharedSveltoDictionaryNative<uint, uint> _entityIDToDenseIndex; | |||
readonly ExclusiveGroupStruct _group; | |||
} | |||
@@ -4,7 +4,7 @@ using Svelto.ECS.Native; | |||
namespace Svelto.ECS | |||
{ | |||
public struct NativeEntityFilterCollection<T> where T : unmanaged, IEntityComponent | |||
public struct NativeEntityFilterCollection<T> where T : unmanaged, IBaseEntityComponent | |||
{ | |||
internal NativeEntityFilterCollection(NativeEGIDMultiMapper<T> mmap) | |||
{ | |||
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public readonly ref struct NativeEntityFilterIterator<T> where T : unmanaged, IEntityComponent | |||
public readonly ref struct NativeEntityFilterIterator<T> where T : unmanaged, IBaseEntityComponent | |||
{ | |||
internal NativeEntityFilterIterator(NativeEntityFilterCollection<T> filter) | |||
{ | |||
@@ -18,7 +18,7 @@ namespace Svelto.ECS | |||
void FillFromByteArray(EntityInitializer init, NativeBag buffer); | |||
} | |||
class Filler<T> : IFiller where T : struct, IEntityComponent | |||
class Filler<T> : IFiller where T : struct, IBaseEntityComponent | |||
{ | |||
static Filler() | |||
{ | |||
@@ -50,7 +50,7 @@ namespace Svelto.ECS | |||
TYPE_IDS = new Svelto.DataStructures.FasterList<IFiller>(); | |||
} | |||
internal static void Register<T>(IFiller entityBuilder) where T : struct, IEntityComponent | |||
internal static void Register<T>(IFiller entityBuilder) where T : struct, IBaseEntityComponent | |||
{ | |||
var location = EntityComponentID<T>.ID.Data = GlobalTypeID.NextID<T>(); | |||
TYPE_IDS.AddAt(location, entityBuilder); | |||
@@ -7,11 +7,11 @@ namespace Svelto.ECS | |||
{ | |||
public partial class EntitiesDB | |||
{ | |||
public LocalFasterReadOnlyList<ExclusiveGroupStruct> FindGroups<T1>() where T1 : IEntityComponent | |||
public LocalFasterReadOnlyList<ExclusiveGroupStruct> FindGroups<T1>() where T1 : IBaseEntityComponent | |||
{ | |||
FasterList<ExclusiveGroupStruct> result = localgroups.Value.groupArray; | |||
result.FastClear(); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T1>.wrapper | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T1>.wrapper | |||
, out FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary> result1) | |||
== false) | |||
return result; | |||
@@ -32,15 +32,15 @@ namespace Svelto.ECS | |||
} | |||
public LocalFasterReadOnlyList<ExclusiveGroupStruct> FindGroups<T1, T2>() | |||
where T1 : IEntityComponent where T2 : IEntityComponent | |||
where T1 : IBaseEntityComponent where T2 : IBaseEntityComponent | |||
{ | |||
FasterList<ExclusiveGroupStruct> result = localgroups.Value.groupArray; | |||
result.FastClear(); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T1>.wrapper | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T1>.wrapper | |||
, out FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary> result1) | |||
== false) | |||
return result; | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T2>.wrapper | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T2>.wrapper | |||
, out FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary> result2) | |||
== false) | |||
return result; | |||
@@ -83,18 +83,18 @@ namespace Svelto.ECS | |||
/// <typeparam name="T3"></typeparam> | |||
/// <returns></returns> | |||
public LocalFasterReadOnlyList<ExclusiveGroupStruct> FindGroups<T1, T2, T3>() | |||
where T1 : IEntityComponent where T2 : IEntityComponent where T3 : IEntityComponent | |||
where T1 : IBaseEntityComponent where T2 : IBaseEntityComponent where T3 : IBaseEntityComponent | |||
{ | |||
FasterList<FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>> localArray = | |||
localgroups.Value.listOfGroups; | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T1>.wrapper, out localArray[0]) == false || localArray[0].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T1>.wrapper, out localArray[0]) == false || localArray[0].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T2>.wrapper, out localArray[1]) == false || localArray[1].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T2>.wrapper, out localArray[1]) == false || localArray[1].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T3>.wrapper, out localArray[2]) == false || localArray[2].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T3>.wrapper, out localArray[2]) == false || localArray[2].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
@@ -133,24 +133,24 @@ namespace Svelto.ECS | |||
} | |||
public LocalFasterReadOnlyList<ExclusiveGroupStruct> FindGroups<T1, T2, T3, T4>() | |||
where T1 : IEntityComponent | |||
where T2 : IEntityComponent | |||
where T3 : IEntityComponent | |||
where T4 : IEntityComponent | |||
where T1 : IBaseEntityComponent | |||
where T2 : IBaseEntityComponent | |||
where T3 : IBaseEntityComponent | |||
where T4 : IBaseEntityComponent | |||
{ | |||
FasterList<FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>> localArray = | |||
localgroups.Value.listOfGroups; | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T1>.wrapper, out localArray[0]) == false || localArray[0].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T1>.wrapper, out localArray[0]) == false || localArray[0].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T2>.wrapper, out localArray[1]) == false || localArray[1].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T2>.wrapper, out localArray[1]) == false || localArray[1].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T3>.wrapper, out localArray[2]) == false || localArray[2].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T3>.wrapper, out localArray[2]) == false || localArray[2].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
if (groupsPerEntity.TryGetValue(TypeRefWrapper<T4>.wrapper, out localArray[3]) == false || localArray[3].count == 0) | |||
if (groupsPerComponent.TryGetValue(TypeRefWrapper<T4>.wrapper, out localArray[3]) == false || localArray[3].count == 0) | |||
return new LocalFasterReadOnlyList<ExclusiveGroupStruct>( | |||
FasterReadOnlyList<ExclusiveGroupStruct>.DefaultEmptyList); | |||
@@ -195,10 +195,10 @@ namespace Svelto.ECS | |||
internal FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary> FindGroups_INTERNAL(Type type) | |||
{ | |||
if (groupsPerEntity.ContainsKey(new RefWrapperType(type)) == false) | |||
if (groupsPerComponent.ContainsKey(new RefWrapperType(type)) == false) | |||
return _emptyDictionary; | |||
return groupsPerEntity[new RefWrapperType(type)]; | |||
return groupsPerComponent[new RefWrapperType(type)]; | |||
} | |||
struct GroupsList |
@@ -210,7 +210,7 @@ namespace Svelto.ECS.Experimental | |||
readonly FasterReadOnlyList<ExclusiveGroupStruct> _group; | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public int Count<T>(EntitiesDB entitiesDB) where T : struct, IEntityComponent | |||
public int Count<T>(EntitiesDB entitiesDB) where T : struct, IBaseEntityComponent | |||
{ | |||
var count = 0; | |||
@@ -220,7 +220,7 @@ namespace Svelto.ECS.Experimental | |||
return count; | |||
} | |||
public int Max<T>(EntitiesDB entitiesDB) where T : struct, IEntityComponent | |||
public int Max<T>(EntitiesDB entitiesDB) where T : struct, IBaseEntityComponent | |||
{ | |||
var max = 0; | |||
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS.Hybrid | |||
{ | |||
public interface IManagedComponent:IEntityComponent | |||
public interface IManagedComponent:IBaseEntityComponent | |||
{} | |||
public interface IEntityViewComponent:IManagedComponent | |||
@@ -0,0 +1,11 @@ | |||
namespace Svelto.ECS | |||
{ | |||
///<summary>Entity Components MUST implement IEntityComponent</summary> | |||
public interface IBaseEntityComponent | |||
{ | |||
} | |||
public interface IEntityComponent:IBaseEntityComponent | |||
{ | |||
} | |||
} |
@@ -65,12 +65,12 @@ namespace Svelto.ECS | |||
/// Interface to mark an Engine as reacting on entities added | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
public interface IReactOnAdd<T> : IReactOnAdd where T : IEntityComponent | |||
public interface IReactOnAdd<T> : IReactOnAdd where T : IBaseEntityComponent | |||
{ | |||
void Add(ref T entityComponent, EGID egid); | |||
} | |||
public interface IReactOnAddEx<T> : IReactOnAddEx where T : struct, IEntityComponent | |||
public interface IReactOnAddEx<T> : IReactOnAddEx where T : struct, IBaseEntityComponent | |||
{ | |||
void Add((uint start, uint end) rangeOfEntities, in EntityCollection<T> collection, | |||
ExclusiveGroupStruct groupID); | |||
@@ -80,18 +80,22 @@ namespace Svelto.ECS | |||
/// Interface to mark an Engine as reacting on entities removed | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
public interface IReactOnRemove<T> : IReactOnRemove where T : IEntityComponent | |||
public interface IReactOnRemove<T> : IReactOnRemove where T : IBaseEntityComponent | |||
{ | |||
void Remove(ref T entityComponent, EGID egid); | |||
} | |||
public interface IReactOnAddAndRemoveEx<T> : IReactOnAddEx<T>, IReactOnRemoveEx<T> where T : struct, IBaseEntityComponent | |||
{ | |||
} | |||
public interface IReactOnRemoveEx<T> : IReactOnRemoveEx where T : struct, IEntityComponent | |||
public interface IReactOnRemoveEx<T> : IReactOnRemoveEx where T : struct, IBaseEntityComponent | |||
{ | |||
void Remove((uint start, uint end) rangeOfEntities, in EntityCollection<T> collection, | |||
ExclusiveGroupStruct groupID); | |||
} | |||
public interface IReactOnAddAndRemove<T> : IReactOnAdd<T>, IReactOnRemove<T> where T : IEntityComponent | |||
public interface IReactOnAddAndRemove<T> : IReactOnAdd<T>, IReactOnRemove<T> where T : IBaseEntityComponent | |||
{ | |||
} | |||
@@ -100,7 +104,7 @@ namespace Svelto.ECS | |||
/// It can work together with IReactOnRemove which normally is not called on enginesroot disposed | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
public interface IReactOnDispose<T> : IReactOnDispose where T : IEntityComponent | |||
public interface IReactOnDispose<T> : IReactOnDispose where T : IBaseEntityComponent | |||
{ | |||
void Remove(ref T entityComponent, EGID egid); | |||
} | |||
@@ -109,12 +113,12 @@ namespace Svelto.ECS | |||
/// Interface to mark an Engine as reacting to entities swapping group | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
public interface IReactOnSwap<T> : IReactOnSwap where T : IEntityComponent | |||
public interface IReactOnSwap<T> : IReactOnSwap where T : IBaseEntityComponent | |||
{ | |||
void MovedTo(ref T entityComponent, ExclusiveGroupStruct previousGroup, EGID egid); | |||
} | |||
public interface IReactOnSwapEx<T> : IReactOnSwapEx where T : struct, IEntityComponent | |||
public interface IReactOnSwapEx<T> : IReactOnSwapEx where T : struct, IBaseEntityComponent | |||
{ | |||
void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection<T> collection, | |||
ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup); | |||
@@ -1,7 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
///<summary>Entity Components MUST implement IEntityComponent</summary> | |||
public interface IEntityComponent | |||
{ | |||
} | |||
} |
@@ -1,10 +1,10 @@ | |||
#if SLOW_SVELTO_SUBMISSION | |||
namespace Svelto.ECS.Internal | |||
{ | |||
delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid) where T : struct, IEntityComponent; | |||
delegate void SetReferenceWithoutBoxingActionCast<T>(ref T target, EntityReference egid) where T : struct, IEntityComponent; | |||
delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid) where T : struct, IBaseEntityComponent; | |||
delegate void SetReferenceWithoutBoxingActionCast<T>(ref T target, EntityReference egid) where T : struct, IBaseEntityComponent; | |||
static class SetEGIDWithoutBoxing<T> where T : struct, IEntityComponent | |||
static class SetEGIDWithoutBoxing<T> where T : struct, IBaseEntityComponent | |||
{ | |||
public static readonly SetEGIDWithoutBoxingActionCast<T> SetIDWithoutBoxing = MakeSetter(); | |||
public static readonly SetReferenceWithoutBoxingActionCast<T> SetRefWithoutBoxing = MakeSetterReference(); | |||
@@ -2,7 +2,7 @@ using System; | |||
namespace Svelto.ECS | |||
{ | |||
public readonly ref struct DoubleEntitiesEnumerator<T1> where T1 : struct, IEntityComponent | |||
public readonly ref struct DoubleEntitiesEnumerator<T1> where T1 : struct, IBaseEntityComponent | |||
{ | |||
public DoubleEntitiesEnumerator(GroupsEnumerable<T1> groupsEnumerable) { _groupsEnumerable = groupsEnumerable; } | |||
@@ -130,8 +130,8 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public readonly ref struct DoubleIterationEnumerator<T1, T2> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
public readonly ref struct DoubleIterationEnumerator<T1, T2> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
{ | |||
public DoubleIterationEnumerator(GroupsEnumerable<T1, T2> groupsEnumerable) | |||
{ | |||
@@ -268,9 +268,9 @@ namespace Svelto.ECS | |||
/// <typeparam name="T1"></typeparam> | |||
/// <typeparam name="T2"></typeparam> | |||
/// <typeparam name="T3"></typeparam> | |||
public readonly ref struct DoubleEntitiesEnumerator<T1, T2, T3> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
public readonly ref struct DoubleEntitiesEnumerator<T1, T2, T3> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
{ | |||
public DoubleEntitiesEnumerator(GroupsEnumerable<T1, T2, T3> groupsEnumerable) | |||
{ | |||
@@ -409,10 +409,10 @@ namespace Svelto.ECS | |||
/// <typeparam name="T2"></typeparam> | |||
/// <typeparam name="T3"></typeparam> | |||
/// <typeparam name="T4"></typeparam> | |||
public readonly ref struct DoubleEntitiesEnumerator<T1, T2, T3, T4> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
public readonly ref struct DoubleEntitiesEnumerator<T1, T2, T3, T4> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
where T4 : struct, IBaseEntityComponent | |||
{ | |||
public DoubleEntitiesEnumerator(GroupsEnumerable<T1, T2, T3, T4> groupsEnumerable) | |||
{ | |||
@@ -4,7 +4,7 @@ using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public struct Consumer<T> : IDisposable where T : unmanaged, IEntityComponent | |||
public struct Consumer<T> : IDisposable where T : unmanaged, IBaseEntityComponent | |||
{ | |||
internal Consumer(string name, uint capacity) : this() | |||
{ | |||
@@ -5,14 +5,14 @@ namespace Svelto.ECS | |||
public partial class EnginesRoot | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
internal Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IEntityComponent | |||
internal Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return _entityStreams.GenerateConsumer<T>(name, capacity); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
internal Consumer<T> GenerateConsumer<T>(ExclusiveGroupStruct group, string name, uint capacity) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return _entityStreams.GenerateConsumer<T>(@group, name, capacity); | |||
} | |||
@@ -5,7 +5,7 @@ namespace Svelto.ECS | |||
public partial class EntitiesDB | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
//Todo I should rename this method to reflect it's original intention | |||
//Todo I should rename this method to reflect its original intention | |||
public void PublishEntityChange<T>(EGID egid) where T : unmanaged, IEntityComponent | |||
{ | |||
//Note: it is correct to publish the EGID at the moment of the publishing, as the responsibility of | |||
@@ -15,7 +15,7 @@ namespace Svelto.ECS | |||
struct EntitiesStreams : IDisposable | |||
{ | |||
internal Consumer<T> GenerateConsumer<T>(string name, uint capacity) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
if (_streams.ContainsKey(TypeRefWrapper<T>.wrapper) == false) | |||
_streams[TypeRefWrapper<T>.wrapper] = new EntityStream<T>(); | |||
@@ -24,7 +24,7 @@ namespace Svelto.ECS | |||
} | |||
public Consumer<T> GenerateConsumer<T>(ExclusiveGroupStruct group, string name, uint capacity) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
if (_streams.ContainsKey(TypeRefWrapper<T>.wrapper) == false) | |||
_streams[TypeRefWrapper<T>.wrapper] = new EntityStream<T>(); | |||
@@ -33,7 +33,7 @@ namespace Svelto.ECS | |||
return typeSafeStream.GenerateConsumer(group, name, capacity); | |||
} | |||
internal void PublishEntity<T>(ref T entity, EGID egid) where T : unmanaged, IEntityComponent | |||
internal void PublishEntity<T>(ref T entity, EGID egid) where T : unmanaged, IBaseEntityComponent | |||
{ | |||
if (_streams.TryGetValue(TypeRefWrapper<T>.wrapper, out var typeSafeStream)) | |||
(typeSafeStream as EntityStream<T>).PublishEntity(ref entity, egid); | |||
@@ -7,7 +7,7 @@ namespace Svelto.ECS | |||
void Dispose(); | |||
} | |||
public class EntityStream<T> : ITypeSafeStream where T : unmanaged, IEntityComponent | |||
public class EntityStream<T> : ITypeSafeStream where T : unmanaged, IBaseEntityComponent | |||
{ | |||
readonly ThreadSafeFasterList<Consumer<T>> _consumers; | |||
@@ -12,14 +12,14 @@ namespace Svelto.ECS | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public Consumer<T> GenerateConsumer<T>(string name, uint capacity) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return _enginesRoot.Target.GenerateConsumer<T>(name, capacity); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public Consumer<T> GenerateConsumer<T>(ExclusiveGroupStruct @group, string name, uint capacity) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
return _enginesRoot.Target.GenerateConsumer<T>(group, name, capacity); | |||
} | |||
@@ -31,9 +31,9 @@ namespace Svelto.ECS | |||
public interface IEntityStreamConsumerFactory | |||
{ | |||
Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IEntityComponent; | |||
Consumer<T> GenerateConsumer<T>(string name, uint capacity) where T : unmanaged, IBaseEntityComponent; | |||
Consumer<T> GenerateConsumer<T>(ExclusiveGroupStruct @group, string name, uint capacity) | |||
where T : unmanaged, IEntityComponent; | |||
where T : unmanaged, IBaseEntityComponent; | |||
} | |||
} |
@@ -1,17 +1,28 @@ | |||
using Svelto.Common; | |||
using Svelto.ECS.Hybrid; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
static class TypeSafeDictionaryFactory<T> where T : struct, IEntityComponent | |||
static class TypeSafeDictionaryFactory<T> where T : struct, IBaseEntityComponent | |||
{ | |||
static readonly bool isUnmanaged = typeof(T).IsUnmanagedEx() | |||
&& typeof(IEntityViewComponent).IsAssignableFrom(typeof(T)) == false; | |||
public static ITypeSafeDictionary Create() | |||
{ | |||
return new TypeSafeDictionary<T>(1); | |||
if (isUnmanaged) | |||
return new UnmanagedTypeSafeDictionary<T>(1); | |||
return new ManagedTypeSafeDictionary<T>(1); | |||
} | |||
public static ITypeSafeDictionary Create(uint size) | |||
{ | |||
return new TypeSafeDictionary<T>(size); | |||
if (isUnmanaged) | |||
return new UnmanagedTypeSafeDictionary<T>(size); | |||
return new ManagedTypeSafeDictionary<T>(size); | |||
} | |||
} | |||
} |
@@ -0,0 +1,4 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface IEntityIDs { } | |||
} |
@@ -0,0 +1,22 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public struct ManagedEntityIDs: IEntityIDs | |||
{ | |||
public ManagedEntityIDs(MB<SveltoDictionaryNode<uint>> managed) | |||
{ | |||
_managed = managed; | |||
} | |||
public void Update(MB<SveltoDictionaryNode<uint>> managed) | |||
{ | |||
_managed = managed; | |||
} | |||
public uint this[uint index] => _managed[index].key; | |||
public uint this[int index] => _managed[index].key; | |||
MB<SveltoDictionaryNode<uint>> _managed; | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public struct NativeEntityIDs: IEntityIDs | |||
{ | |||
public NativeEntityIDs(NB<SveltoDictionaryNode<uint>> native) | |||
{ | |||
_native = native; | |||
} | |||
public void Update(in NB<SveltoDictionaryNode<uint>> unsafeKeys) | |||
{ | |||
_native = unsafeKeys; | |||
} | |||
public uint this[uint index] => _native[index].key; | |||
public uint this[int index] => _native[index].key; | |||
NB<SveltoDictionaryNode<uint>> _native; | |||
} | |||
} |
@@ -4,7 +4,7 @@ using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface ITypeSafeDictionary<TValue> : ITypeSafeDictionary where TValue : IEntityComponent | |||
public interface ITypeSafeDictionary<TValue> : ITypeSafeDictionary where TValue : IBaseEntityComponent | |||
{ | |||
void Add(uint egidEntityId, in TValue entityComponent); | |||
@@ -14,7 +14,7 @@ namespace Svelto.ECS.Internal | |||
IBuffer<TValue> GetValues(out uint count); | |||
ref TValue GetDirectValueByRef(uint key); | |||
ref TValue GetValueByRef(uint key); | |||
EntityIDs entityIDs { get; } | |||
IEntityIDs entityIDs { get; } | |||
} | |||
public interface ITypeSafeDictionary : IDisposable | |||
@@ -24,10 +24,16 @@ namespace Svelto.ECS.Internal | |||
ITypeSafeDictionary Create(); | |||
void AddEntitiesToDictionary | |||
(ITypeSafeDictionary toDictionary, ExclusiveGroupStruct groupId, in EnginesRoot.EntityReferenceMap entityLocator); | |||
void RemoveEntitiesFromDictionary(FasterList<(uint, string)> infosToProcess); | |||
void SwapEntitiesBetweenDictionaries(FasterList<(uint, uint, string)> infosToProcess, | |||
ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup, ITypeSafeDictionary toComponentsDictionary); | |||
(ITypeSafeDictionary toDictionary, ExclusiveGroupStruct groupId | |||
#if SLOW_SVELTO_SUBMISSION | |||
, in EnginesRoot.EntityReferenceMap entityLocator | |||
#endif | |||
); | |||
void RemoveEntitiesFromDictionary | |||
(FasterList<(uint, string)> infosToProcess, FasterList<uint> entityIDsAffectedByRemoval); | |||
void SwapEntitiesBetweenDictionaries | |||
(FasterList<(uint, uint, string)> infosToProcess, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup | |||
, ITypeSafeDictionary toComponentsDictionary, FasterList<uint> entityIDsAffectedByRemoval); | |||
//------------ | |||
@@ -0,0 +1,305 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using System.Threading; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Hybrid; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public sealed class ManagedTypeSafeDictionary<TValue> : ITypeSafeDictionary<TValue> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
static readonly Type _type = typeof(TValue); | |||
#if SLOW_SVELTO_SUBMISSION | |||
static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type); | |||
static readonly bool _hasReference = typeof(INeedEntityReference).IsAssignableFrom(_type); | |||
#endif | |||
static readonly ThreadLocal<IEntityIDs> cachedEntityIDM = | |||
new ThreadLocal<IEntityIDs>(() => new ManagedEntityIDs()); | |||
public ManagedTypeSafeDictionary(uint size) | |||
{ | |||
implMgd = | |||
new SveltoDictionary<uint, TValue, ManagedStrategy<SveltoDictionaryNode<uint>>, ManagedStrategy<TValue>, | |||
ManagedStrategy<int>>(size, Allocator.Managed); | |||
} | |||
public IEntityIDs entityIDs | |||
{ | |||
get | |||
{ | |||
ref var unboxed = ref Unsafe.Unbox<ManagedEntityIDs>(cachedEntityIDM.Value); | |||
unboxed.Update(implMgd.unsafeKeys.ToRealBuffer()); | |||
return cachedEntityIDM.Value; | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool ContainsKey(uint egidEntityId) | |||
{ | |||
return implMgd.ContainsKey(egidEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public uint GetIndex(uint valueEntityId) | |||
{ | |||
return implMgd.GetIndex(valueEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref TValue GetOrAdd(uint idEntityId) | |||
{ | |||
return ref implMgd.GetOrAdd(idEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public IBuffer<TValue> GetValues(out uint count) | |||
{ | |||
return implMgd.UnsafeGetValues(out count); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref TValue GetDirectValueByRef(uint key) | |||
{ | |||
return ref implMgd.GetDirectValueByRef(key); | |||
} | |||
public ref TValue GetValueByRef(uint key) | |||
{ | |||
return ref implMgd.GetValueByRef(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Has(uint key) | |||
{ | |||
return implMgd.ContainsKey(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryFindIndex(uint entityId, out uint index) | |||
{ | |||
return implMgd.TryFindIndex(entityId, out index); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryGetValue(uint entityId, out TValue item) | |||
{ | |||
return implMgd.TryGetValue(entityId, out item); | |||
} | |||
public int count | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => implMgd.count; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ITypeSafeDictionary Create() | |||
{ | |||
return TypeSafeDictionaryFactory<TValue>.Create(1); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Clear() | |||
{ | |||
implMgd.Clear(); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void EnsureCapacity(uint size) | |||
{ | |||
implMgd.EnsureCapacity(size); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void IncreaseCapacityBy(uint size) | |||
{ | |||
implMgd.IncreaseCapacityBy(size); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Trim() | |||
{ | |||
implMgd.Trim(); | |||
} | |||
public void KeysEvaluator(Action<uint> action) | |||
{ | |||
foreach (var key in implMgd.keys) | |||
action(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Add(uint egidEntityId, in TValue entityComponent) | |||
{ | |||
implMgd.Add(egidEntityId, entityComponent); | |||
} | |||
public void Dispose() | |||
{ | |||
implMgd.Dispose(); | |||
GC.SuppressFinalize(this); | |||
} | |||
/// ********************************* | |||
/// the following methods are executed during the submission of entities | |||
/// ********************************* | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void AddEntitiesToDictionary | |||
(ITypeSafeDictionary toDictionary, ExclusiveGroupStruct groupId | |||
#if SLOW_SVELTO_SUBMISSION | |||
, in EnginesRoot.EntityReferenceMap entityLocator | |||
#endif | |||
) | |||
{ | |||
TypeSafeDictionaryMethods.AddEntitiesToDictionary(implMgd, toDictionary as ITypeSafeDictionary<TValue> | |||
#if SLOW_SVELTO_SUBMISSION | |||
, entityLocator | |||
#endif | |||
, groupId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveEntitiesFromDictionary | |||
(FasterList<(uint, string)> infosToProcess, FasterList<uint> entityIDsAffectedByRemoval) | |||
{ | |||
TypeSafeDictionaryMethods.RemoveEntitiesFromDictionary(infosToProcess, ref implMgd, entityIDsAffectedByRemoval); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntitiesBetweenDictionaries | |||
(FasterList<(uint, uint, string)> infosToProcess, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, ITypeSafeDictionary toComponentsDictionary | |||
, FasterList<uint> entityIDsAffectedByRemoval) | |||
{ | |||
TypeSafeDictionaryMethods.SwapEntitiesBetweenDictionaries(infosToProcess, ref implMgd | |||
, toComponentsDictionary as | |||
ITypeSafeDictionary<TValue>, fromGroup | |||
, toGroup, entityIDsAffectedByRemoval); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnAdd callbacks linked to components added this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesAddCallbacks | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAdd>>> entityComponentEnginesDB | |||
, ITypeSafeDictionary toDic, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesAddCallbacks(ref implMgd, (ITypeSafeDictionary<TValue>)toDic | |||
, toGroup, entityComponentEnginesDB, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnSwap callbacks linked to components swapped this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesSwapCallbacks | |||
(FasterList<(uint, uint, string)> infosToProcess | |||
, FasterList<ReactEngineContainer<IReactOnSwap>> reactiveEnginesSwap, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacks(infosToProcess, ref implMgd, reactiveEnginesSwap | |||
, toGroup, fromGroup, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnREmove callbacks linked to components removed this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesRemoveCallbacks | |||
(FasterList<(uint, string)> infosToProcess | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveEnginesRemove | |||
, ExclusiveGroupStruct fromGroup, in PlatformProfiler sampler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks(infosToProcess, ref implMgd, reactiveEnginesRemove | |||
, fromGroup, in sampler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnAddEx callbacks linked to components added this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesAddEntityCallbacksFast | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAddEx>>> reactiveEnginesAdd | |||
, ExclusiveGroupStruct groupID, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesAddEntityCallbacksFast( | |||
reactiveEnginesAdd, groupID, rangeOfSubmittedEntitiesIndicies, entityIDs, this, profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnSwapEx callbacks linked to components swapped this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesSwapCallbacksFast | |||
(FasterList<ReactEngineContainer<IReactOnSwapEx>> reactiveEnginesSwap, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler sampler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacksFast(reactiveEnginesSwap, fromGroup, toGroup, entityIDs | |||
, this, rangeOfSubmittedEntitiesIndicies, sampler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnRemoveEx callbacks linked to components removed this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesRemoveCallbacksFast | |||
(FasterList<ReactEngineContainer<IReactOnRemoveEx>> reactiveEnginesRemoveEx, ExclusiveGroupStruct fromGroup | |||
, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler sampler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacksFast(reactiveEnginesRemoveEx, fromGroup | |||
, rangeOfSubmittedEntitiesIndicies, entityIDs | |||
, this, sampler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnSwap and IReactOnSwapEx callbacks linked to components swapped between | |||
/// whole groups swapped during this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesSwapCallbacks_Group | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwap>>> reactiveEnginesSwap | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwapEx>>> reactiveEnginesSwapEx | |||
, ITypeSafeDictionary toDictionary, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup | |||
, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacks_Group( | |||
ref implMgd, (ITypeSafeDictionary<TValue>)toDictionary, toGroup, fromGroup, this, reactiveEnginesSwap | |||
, reactiveEnginesSwapEx, count, entityIDs, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnRemove and IReactOnRemoveEx callbacks linked to components remove from | |||
/// whole groups removed during this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesRemoveCallbacks_Group | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveEnginesRemove | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemoveEx>>> reactiveEnginesRemoveEx | |||
, ExclusiveGroupStruct group, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks_Group( | |||
ref implMgd, this, reactiveEnginesRemove, reactiveEnginesRemoveEx, count, entityIDs, group | |||
, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnDispose for eahc component registered in the DB when it's disposed of | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesDisposeCallbacks_Group | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>> engines | |||
, ExclusiveGroupStruct group, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group(ref implMgd, engines, group, in profiler); | |||
} | |||
SveltoDictionary<uint, TValue, ManagedStrategy<SveltoDictionaryNode<uint>>, ManagedStrategy<TValue>, | |||
ManagedStrategy<int>> implMgd; | |||
} | |||
} |
@@ -1,800 +0,0 @@ | |||
#if DEBUG && !PROFILE_SVELTO | |||
//#define PARANOID_CHECK | |||
#endif | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using DBC.ECS; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.DataStructures.Native; | |||
using Svelto.ECS.DataStructures; | |||
using Svelto.ECS.Hybrid; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public readonly struct NativeEntityIDs | |||
{ | |||
public NativeEntityIDs(NB<SveltoDictionaryNode<uint>> native) | |||
{ | |||
_native = native; | |||
} | |||
public uint this[uint index] => _native[index].key; | |||
public uint this[int index] => _native[index].key; | |||
readonly NB<SveltoDictionaryNode<uint>> _native; | |||
} | |||
public readonly struct ManagedEntityIDs | |||
{ | |||
public ManagedEntityIDs(MB<SveltoDictionaryNode<uint>> managed) | |||
{ | |||
_managed = managed; | |||
} | |||
public uint this[uint index] => _managed[index].key; | |||
public uint this[int index] => _managed[index].key; | |||
readonly MB<SveltoDictionaryNode<uint>> _managed; | |||
} | |||
public readonly struct EntityIDs | |||
{ | |||
readonly NB<SveltoDictionaryNode<uint>> _native; | |||
readonly MB<SveltoDictionaryNode<uint>> _managed; | |||
public EntityIDs(NativeStrategy<SveltoDictionaryNode<uint>> unmanagedKeys) : this() | |||
{ | |||
_native = unmanagedKeys.ToRealBuffer(); | |||
} | |||
public EntityIDs(ManagedStrategy<SveltoDictionaryNode<uint>> managedKeys) : this() | |||
{ | |||
_managed = managedKeys.ToRealBuffer(); | |||
} | |||
public NativeEntityIDs nativeIDs => new NativeEntityIDs(_native); | |||
public ManagedEntityIDs managedIDs => new ManagedEntityIDs(_managed); | |||
} | |||
public sealed class TypeSafeDictionary<TValue> : ITypeSafeDictionary<TValue> where TValue : struct, IEntityComponent | |||
{ | |||
static readonly Type _type = typeof(TValue); | |||
#if SLOW_SVELTO_SUBMISSION | |||
static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type); | |||
static readonly bool _hasReference = typeof(INeedEntityReference).IsAssignableFrom(_type); | |||
#endif | |||
internal static readonly bool isUnmanaged = | |||
_type.IsUnmanagedEx() && typeof(IEntityViewComponent).IsAssignableFrom(_type) == false; | |||
public TypeSafeDictionary(uint size) | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd = | |||
new SharedNative<SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<TValue>, NativeStrategy<int>>>( | |||
new SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<TValue>, NativeStrategy<int>>(size, Allocator.Persistent)); | |||
else | |||
implMgd = | |||
new SveltoDictionary<uint, TValue, ManagedStrategy<SveltoDictionaryNode<uint>>, | |||
ManagedStrategy<TValue>, ManagedStrategy<int>>(size, Allocator.Managed); | |||
} | |||
public EntityIDs entityIDs | |||
{ | |||
get | |||
{ | |||
if (isUnmanaged) | |||
return new EntityIDs(implUnmgd.value.unsafeKeys); | |||
return new EntityIDs(implMgd.unsafeKeys); | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool ContainsKey(uint egidEntityId) | |||
{ | |||
return isUnmanaged ? implUnmgd.value.ContainsKey(egidEntityId) : implMgd.ContainsKey(egidEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public uint GetIndex(uint valueEntityId) | |||
{ | |||
return isUnmanaged ? implUnmgd.value.GetIndex(valueEntityId) : implMgd.GetIndex(valueEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref TValue GetOrAdd(uint idEntityId) | |||
{ | |||
return ref isUnmanaged ? ref implUnmgd.value.GetOrAdd(idEntityId) : ref implMgd.GetOrAdd(idEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public IBuffer<TValue> GetValues(out uint count) | |||
{ | |||
return isUnmanaged ? implUnmgd.value.UnsafeGetValues(out count) : implMgd.UnsafeGetValues(out count); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref TValue GetDirectValueByRef(uint key) | |||
{ | |||
return ref isUnmanaged | |||
? ref implUnmgd.value.GetDirectValueByRef(key) | |||
: ref implMgd.GetDirectValueByRef(key); | |||
} | |||
public ref TValue GetValueByRef(uint key) | |||
{ | |||
return ref isUnmanaged ? ref implUnmgd.value.GetValueByRef(key) : ref implMgd.GetValueByRef(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Has(uint key) | |||
{ | |||
return isUnmanaged ? implUnmgd.value.ContainsKey(key) : implMgd.ContainsKey(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryFindIndex(uint entityId, out uint index) | |||
{ | |||
return isUnmanaged | |||
? implUnmgd.value.TryFindIndex(entityId, out index) | |||
: implMgd.TryFindIndex(entityId, out index); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryGetValue(uint entityId, out TValue item) | |||
{ | |||
return isUnmanaged | |||
? implUnmgd.value.TryGetValue(entityId, out item) | |||
: implMgd.TryGetValue(entityId, out item); | |||
} | |||
public int count | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => isUnmanaged ? implUnmgd.value.count : implMgd.count; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ITypeSafeDictionary Create() | |||
{ | |||
return TypeSafeDictionaryFactory<TValue>.Create(1); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Clear() | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd.value.FastClear(); | |||
else | |||
implMgd.Clear(); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void EnsureCapacity(uint size) | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd.value.EnsureCapacity(size); | |||
else | |||
implMgd.EnsureCapacity(size); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void IncreaseCapacityBy(uint size) | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd.value.IncreaseCapacityBy(size); | |||
else | |||
implMgd.IncreaseCapacityBy(size); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Trim() | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd.value.Trim(); | |||
else | |||
implMgd.Trim(); | |||
} | |||
public void KeysEvaluator(Action<uint> action) | |||
{ | |||
if (isUnmanaged) | |||
foreach (var key in implUnmgd.value.keys) | |||
action(key); | |||
else | |||
foreach (var key in implMgd.keys) | |||
action(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Add(uint egidEntityId, in TValue entityComponent) | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd.value.Add(egidEntityId, entityComponent); | |||
else | |||
implMgd.Add(egidEntityId, entityComponent); | |||
} | |||
public void Dispose() | |||
{ | |||
if (isUnmanaged) | |||
implUnmgd.Dispose(); | |||
else | |||
implMgd.Dispose(); | |||
GC.SuppressFinalize(this); | |||
} | |||
public void AddEntitiesToDictionary(ITypeSafeDictionary toDictionary, ExclusiveGroupStruct groupId, | |||
in EnginesRoot.EntityReferenceMap entityLocator) | |||
{ | |||
void SharedAddEntitiesFromDictionary<Strategy1, Strategy2, Strategy3>( | |||
in SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
ITypeSafeDictionary<TValue> toDic, in EnginesRoot.EntityReferenceMap locator, | |||
ExclusiveGroupStruct toGroupID) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
foreach (var tuple in fromDictionary) | |||
{ | |||
#if SLOW_SVELTO_SUBMISSION | |||
var egid = new EGID(tuple.key, toGroupID); | |||
if (_hasEgid) | |||
SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref tuple.value, egid); | |||
//todo: temporary code that will eventually be removed | |||
if (_hasReference) | |||
SetEGIDWithoutBoxing<TValue>.SetRefWithoutBoxing(ref tuple.value, | |||
locator.GetEntityReference(egid)); | |||
#endif | |||
try | |||
{ | |||
toDic.Add(tuple.key, tuple.value); | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, | |||
"trying to add an EntityComponent with the same ID more than once Entity: " | |||
.FastConcat(typeof(TValue).ToString()).FastConcat(", group ") | |||
.FastConcat(toGroupID.ToName()).FastConcat(", id ").FastConcat(tuple.key)); | |||
throw; | |||
} | |||
#if PARANOID_CHECK && SLOW_SVELTO_SUBMISSION | |||
DBC.ECS.Check.Ensure(_hasEgid == false || ((INeedEGID)fromDictionary[egid.entityID]).ID == egid, "impossible situation happened during swap"); | |||
#endif | |||
} | |||
} | |||
var destinationDictionary = toDictionary as ITypeSafeDictionary<TValue>; | |||
if (isUnmanaged) | |||
SharedAddEntitiesFromDictionary(implUnmgd.value, destinationDictionary, entityLocator, groupId); | |||
else | |||
SharedAddEntitiesFromDictionary(implMgd, destinationDictionary, entityLocator, groupId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveEntitiesFromDictionary(FasterList<(uint, string)> infosToProcess) | |||
{ | |||
void AgnosticMethod<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
var iterations = infosToProcess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (id, trace) = infosToProcess[i]; | |||
try | |||
{ | |||
if (fromDictionary.Remove(id, out var value)) | |||
//Note I am doing this to be able to use a range of values even with the | |||
//remove Ex callbacks. Basically I am copying back the deleted value | |||
//at the end of the array, so I can use as range | |||
//count, count + number of deleted entities | |||
fromDictionary.GetDirectValueByRef((uint)fromDictionary.count) = value; | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Remove Entity operation on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
if (isUnmanaged) | |||
AgnosticMethod(ref implUnmgd.value); | |||
else | |||
AgnosticMethod(ref implMgd); | |||
} | |||
public void SwapEntitiesBetweenDictionaries(FasterList<(uint, uint, string)> infosToProcess, | |||
ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup, ITypeSafeDictionary toComponentsDictionary) | |||
{ | |||
void SharedSwapEntityInDictionary<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
ITypeSafeDictionary<TValue> toDictionary) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
var iterations = infosToProcess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (fromID, toID, trace) = infosToProcess[i]; | |||
try | |||
{ | |||
var fromEntityGid = new EGID(fromID, fromGroup); | |||
var toEntityEgid = new EGID(toID, toGroup); | |||
Check.Require(toGroup.isInvalid == false, "Invalid To Group"); | |||
var isFound = fromDictionary.Remove(fromEntityGid.entityID, out var entity); | |||
Check.Assert(isFound, "Swapping an entity that doesn't exist"); | |||
#if SLOW_SVELTO_SUBMISSION | |||
if (_hasEgid) | |||
SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref entity, toEntityEgid); | |||
#endif | |||
toDictionary.Add(toEntityEgid.entityID, entity); | |||
#if PARANOID_CHECK | |||
DBC.ECS.Check.Ensure(_hasEgid == false || ((INeedEGID)toGroupCasted[toEntityEGID.entityID]).ID == toEntityEGID, "impossible situation happened during swap"); | |||
#endif | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Swap Entity operation on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
var toGroupCasted = toComponentsDictionary as ITypeSafeDictionary<TValue>; | |||
if (isUnmanaged) | |||
SharedSwapEntityInDictionary(ref implUnmgd.value, toGroupCasted); | |||
else | |||
SharedSwapEntityInDictionary(ref implMgd, toGroupCasted); | |||
} | |||
public void ExecuteEnginesAddCallbacks( | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAdd>>> entityComponentEnginesDB, | |||
ITypeSafeDictionary toDic, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) | |||
{ | |||
void AgnosticMethod<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
ITypeSafeDictionary<TValue> todic, in PlatformProfiler sampler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
if (entityComponentEnginesDB.TryGetValue(new RefWrapperType(_type), out var entityComponentsEngines)) | |||
{ | |||
if (entityComponentsEngines.count == 0) return; | |||
var dictionaryKeyEnumerator = fromDictionary.unsafeKeys; | |||
var count = fromDictionary.count; | |||
for (var i = 0; i < count; ++i) | |||
try | |||
{ | |||
var key = dictionaryKeyEnumerator[i].key; | |||
ref var entity = ref todic.GetValueByRef(key); | |||
var egid = new EGID(key, toGroup); | |||
//get all the engines linked to TValue | |||
for (var j = 0; j < entityComponentsEngines.count; j++) | |||
using (sampler.Sample(entityComponentsEngines[j].name)) | |||
{ | |||
((IReactOnAdd<TValue>)entityComponentsEngines[j].engine).Add(ref entity, egid); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, | |||
"Code crashed inside Add callback with Type ".FastConcat(TypeCache<TValue>.name)); | |||
throw; | |||
} | |||
} | |||
} | |||
var toDictionary = (ITypeSafeDictionary<TValue>)toDic; | |||
if (isUnmanaged) | |||
AgnosticMethod(ref implUnmgd.value, toDictionary, in profiler); | |||
else | |||
AgnosticMethod(ref implMgd, toDictionary, in profiler); | |||
} | |||
public void ExecuteEnginesSwapCallbacks(FasterList<(uint, uint, string)> infosToProcess, | |||
FasterList<ReactEngineContainer<IReactOnSwap>> reactiveEnginesSwap, ExclusiveGroupStruct fromGroup, | |||
ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) | |||
{ | |||
void AgnosticMethod<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
if (reactiveEnginesSwap.count == 0) return; | |||
var iterations = infosToProcess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (fromEntityID, toEntityID, trace) = infosToProcess[i]; | |||
try | |||
{ | |||
ref var entityComponent = ref fromDictionary.GetValueByRef(fromEntityID); | |||
var newEgid = new EGID(toEntityID, toGroup); | |||
for (var j = 0; j < reactiveEnginesSwap.count; j++) | |||
using (sampler.Sample(reactiveEnginesSwap[j].name)) | |||
{ | |||
((IReactOnSwap<TValue>)reactiveEnginesSwap[j].engine).MovedTo(ref entityComponent, | |||
fromGroup, newEgid); | |||
} | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Swap Entity callback on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
if (isUnmanaged) | |||
AgnosticMethod(ref implUnmgd.value, in profiler); | |||
else | |||
AgnosticMethod(ref implMgd, in profiler); | |||
} | |||
public void ExecuteEnginesRemoveCallbacks(FasterList<(uint, string)> infosToProcess, | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveEnginesRemove, | |||
ExclusiveGroupStruct fromGroup, in PlatformProfiler sampler) | |||
{ | |||
void AgnosticMethod<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
in PlatformProfiler profiler) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
if (reactiveEnginesRemove.TryGetValue(new RefWrapperType(_type), out var entityComponentsEngines)) | |||
{ | |||
if (entityComponentsEngines.count == 0) return; | |||
var iterations = infosToProcess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (entityID, trace) = infosToProcess[i]; | |||
try | |||
{ | |||
ref var entity = ref fromDictionary.GetValueByRef(entityID); | |||
var egid = new EGID(entityID, fromGroup); | |||
for (var j = 0; j < entityComponentsEngines.count; j++) | |||
using (profiler.Sample(entityComponentsEngines[j].name)) | |||
{ | |||
((IReactOnRemove<TValue>)entityComponentsEngines[j].engine).Remove(ref entity, | |||
egid); | |||
} | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Remove Entity callback on " | |||
.FastConcat(TypeCache<TValue>.name).FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
} | |||
if (isUnmanaged) | |||
AgnosticMethod(ref implUnmgd.value, in sampler); | |||
else | |||
AgnosticMethod(ref implMgd, in sampler); | |||
} | |||
public void ExecuteEnginesAddEntityCallbacksFast( | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAddEx>>> reactiveEnginesAdd, | |||
ExclusiveGroupStruct groupID, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler profiler) | |||
{ | |||
//get all the engines linked to TValue | |||
if (!reactiveEnginesAdd.TryGetValue(new RefWrapperType(_type), out var entityComponentsEngines)) | |||
return; | |||
for (var i = 0; i < entityComponentsEngines.count; i++) | |||
try | |||
{ | |||
using (profiler.Sample(entityComponentsEngines[i].name)) | |||
{ | |||
((IReactOnAddEx<TValue>)entityComponentsEngines[i].engine).Add(rangeOfSubmittedEntitiesIndicies, | |||
new EntityCollection<TValue>(GetValues(out var count), count, entityIDs), groupID); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, | |||
"Code crashed inside Add callback ".FastConcat(entityComponentsEngines[i].name)); | |||
throw; | |||
} | |||
} | |||
public void ExecuteEnginesSwapCallbacksFast( | |||
FasterList<ReactEngineContainer<IReactOnSwapEx>> reactiveEnginesSwap, ExclusiveGroupStruct fromGroup, | |||
ExclusiveGroupStruct toGroup, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler sampler) | |||
{ | |||
for (var i = 0; i < reactiveEnginesSwap.count; i++) | |||
try | |||
{ | |||
using (sampler.Sample(reactiveEnginesSwap[i].name)) | |||
{ | |||
((IReactOnSwapEx<TValue>)reactiveEnginesSwap[i].engine).MovedTo( | |||
rangeOfSubmittedEntitiesIndicies, | |||
new EntityCollection<TValue>(GetValues(out var count), count, entityIDs), fromGroup, | |||
toGroup); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, | |||
"Code crashed inside Add callback ".FastConcat(reactiveEnginesSwap[i].name)); | |||
throw; | |||
} | |||
} | |||
public void ExecuteEnginesRemoveCallbacksFast( | |||
FasterList<ReactEngineContainer<IReactOnRemoveEx>> reactiveEnginesRemoveEx, ExclusiveGroupStruct fromGroup, | |||
(uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler sampler) | |||
{ | |||
for (var i = 0; i < reactiveEnginesRemoveEx.count; i++) | |||
try | |||
{ | |||
using (sampler.Sample(reactiveEnginesRemoveEx[i].name)) | |||
{ | |||
((IReactOnRemoveEx<TValue>)reactiveEnginesRemoveEx[i].engine).Remove( | |||
rangeOfSubmittedEntitiesIndicies, | |||
new EntityCollection<TValue>(GetValues(out var count), count, entityIDs), fromGroup); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, | |||
"Code crashed inside Add callback ".FastConcat(reactiveEnginesRemoveEx[i].name)); | |||
throw; | |||
} | |||
} | |||
public void ExecuteEnginesSwapCallbacks_Group( | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwap>>> reactiveEnginesSwap, | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwapEx>>> reactiveEnginesSwapEx, | |||
ITypeSafeDictionary toDictionary, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup, | |||
in PlatformProfiler profiler) | |||
{ | |||
void AgnosticMethod<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
ITypeSafeDictionary<TValue> toDic, in PlatformProfiler sampler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
//get all the engines linked to TValue | |||
if (!reactiveEnginesSwap.TryGetValue(new RefWrapperType(_type), out var reactiveEnginesSwapPerType)) | |||
return; | |||
var componentsEnginesCount = reactiveEnginesSwapPerType.count; | |||
for (var i = 0; i < componentsEnginesCount; i++) | |||
try | |||
{ | |||
foreach (var value in fromDictionary) | |||
{ | |||
ref var entityComponent = ref toDic.GetValueByRef(value.key); | |||
var newEgid = new EGID(value.key, toGroup); | |||
using (sampler.Sample(reactiveEnginesSwapPerType[i].name)) | |||
{ | |||
((IReactOnSwap<TValue>)reactiveEnginesSwapPerType[i].engine).MovedTo( | |||
ref entityComponent, fromGroup, newEgid); | |||
} | |||
} | |||
} | |||
catch (Exception) | |||
{ | |||
Console.LogError( | |||
"Code crashed inside MoveTo callback ".FastConcat(reactiveEnginesSwapPerType[i].name)); | |||
throw; | |||
} | |||
if (reactiveEnginesSwapEx.TryGetValue(new RefWrapperType(_type), | |||
out var reactiveEnginesRemoveExPerType)) | |||
{ | |||
var enginesCount = reactiveEnginesRemoveExPerType.count; | |||
for (var i = 0; i < enginesCount; i++) | |||
try | |||
{ | |||
using (sampler.Sample(reactiveEnginesRemoveExPerType[i].name)) | |||
{ | |||
((IReactOnSwapEx<TValue>)reactiveEnginesRemoveExPerType[i].engine).MovedTo( | |||
(0, (uint)count), | |||
new EntityCollection<TValue>(GetValues(out _), (uint)count, entityIDs), fromGroup, | |||
toGroup); | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat( | |||
reactiveEnginesRemoveExPerType[i].name)); | |||
throw; | |||
} | |||
} | |||
} | |||
var toEntitiesDictionary = (ITypeSafeDictionary<TValue>)toDictionary; | |||
if (isUnmanaged) | |||
AgnosticMethod(ref implUnmgd.value, toEntitiesDictionary, in profiler); | |||
else | |||
AgnosticMethod(ref implMgd, toEntitiesDictionary, in profiler); | |||
} | |||
public void ExecuteEnginesRemoveCallbacks_Group( | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveEnginesRemove, | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemoveEx>>> | |||
reactiveEnginesRemoveEx, ExclusiveGroupStruct group, in PlatformProfiler profiler) | |||
{ | |||
void AgnosticMethod<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
if (reactiveEnginesRemove.TryGetValue(new RefWrapperType(_type), out var reactiveEnginesRemovePerType)) | |||
{ | |||
var enginesCount = reactiveEnginesRemovePerType.count; | |||
for (var i = 0; i < enginesCount; i++) | |||
try | |||
{ | |||
foreach (var value in fromDictionary) | |||
{ | |||
ref var entity = ref value.value; | |||
var egid = new EGID(value.key, group); | |||
using (sampler.Sample(reactiveEnginesRemovePerType[i].name)) | |||
{ | |||
((IReactOnRemove<TValue>)reactiveEnginesRemovePerType[i].engine).Remove(ref entity, | |||
egid); | |||
} | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemovePerType[i] | |||
.name)); | |||
throw; | |||
} | |||
} | |||
if (reactiveEnginesRemoveEx.TryGetValue(new RefWrapperType(_type), | |||
out var reactiveEnginesRemoveExPerType)) | |||
{ | |||
var enginesCount = reactiveEnginesRemoveExPerType.count; | |||
for (var i = 0; i < enginesCount; i++) | |||
try | |||
{ | |||
using (sampler.Sample(reactiveEnginesRemoveExPerType[i].name)) | |||
{ | |||
((IReactOnRemoveEx<TValue>)reactiveEnginesRemoveExPerType[i].engine).Remove( | |||
(0, (uint)count), | |||
new EntityCollection<TValue>(GetValues(out _), (uint)count, entityIDs), group); | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat( | |||
reactiveEnginesRemoveExPerType[i].name)); | |||
throw; | |||
} | |||
} | |||
} | |||
if (isUnmanaged) | |||
AgnosticMethod(ref implUnmgd.value, in profiler); | |||
else | |||
AgnosticMethod(ref implMgd, in profiler); | |||
} | |||
public void ExecuteEnginesDisposeCallbacks_Group( | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>> engines, | |||
ExclusiveGroupStruct group, in PlatformProfiler profiler) | |||
{ | |||
void ExecuteEnginesDisposeEntityCallback<Strategy1, Strategy2, Strategy3>( | |||
ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary, | |||
FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>> allEngines, | |||
in PlatformProfiler sampler, ExclusiveGroupStruct inGroup) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
{ | |||
if (allEngines.TryGetValue(new RefWrapperType(_type), out var entityComponentsEngines) == false) | |||
return; | |||
for (var i = 0; i < entityComponentsEngines.count; i++) | |||
try | |||
{ | |||
using (sampler.Sample(entityComponentsEngines[i].name)) | |||
{ | |||
foreach (var value in fromDictionary) | |||
{ | |||
ref var entity = ref value.value; | |||
var egid = new EGID(value.key, inGroup); | |||
var reactOnRemove = ((IReactOnDispose<TValue>)entityComponentsEngines[i].engine); | |||
reactOnRemove.Remove(ref entity, egid); | |||
} | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat(entityComponentsEngines[i].name)); | |||
throw; | |||
} | |||
} | |||
if (isUnmanaged) | |||
ExecuteEnginesDisposeEntityCallback(ref implUnmgd.value, engines, in profiler, @group); | |||
else | |||
ExecuteEnginesDisposeEntityCallback(ref implMgd, engines, in profiler, @group); | |||
} | |||
SveltoDictionary<uint, TValue, ManagedStrategy<SveltoDictionaryNode<uint>>, ManagedStrategy<TValue>, | |||
ManagedStrategy<int>> implMgd; | |||
internal SharedNative<SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<TValue>, NativeStrategy<int>>> implUnmgd; | |||
} | |||
} |
@@ -0,0 +1,539 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using DBC.ECS; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public static class TypeSafeDictionaryMethods | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void AddEntitiesToDictionary<Strategy1, Strategy2, Strategy3, TValue> | |||
(in SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, ITypeSafeDictionary<TValue> toDic | |||
#if SLOW_SVELTO_SUBMISSION | |||
, in EnginesRoot.EntityReferenceMap entityLocator | |||
#endif | |||
, ExclusiveGroupStruct toGroupID) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
foreach (var tuple in fromDictionary) | |||
{ | |||
#if SLOW_SVELTO_SUBMISSION | |||
var egid = new EGID(tuple.key, toGroupID); | |||
if (SlowSubmissionInfo<TValue>.hasEgid) | |||
SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref tuple.value, egid); | |||
if (SlowSubmissionInfo<TValue>.hasReference) | |||
SetEGIDWithoutBoxing<TValue>.SetRefWithoutBoxing(ref tuple.value, | |||
entityLocator.GetEntityReference(egid)); | |||
#endif | |||
try | |||
{ | |||
toDic.Add(tuple.key, tuple.value); | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException( | |||
e, "trying to add an EntityComponent with the same ID more than once Entity: ".FastConcat(typeof(TValue).ToString()).FastConcat(", group ").FastConcat(toGroupID.ToName()).FastConcat(", id ").FastConcat(tuple.key)); | |||
throw; | |||
} | |||
#if PARANOID_CHECK && SLOW_SVELTO_SUBMISSION | |||
DBC.ECS.Check.Ensure(_hasEgid == false || ((INeedEGID)fromDictionary[egid.entityID]).ID == egid, "impossible situation happened during swap"); | |||
#endif | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesAddCallbacks<Strategy1, Strategy2, Strategy3, TValue> | |||
(ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, ITypeSafeDictionary<TValue> todic, ExclusiveGroupStruct togroup | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAdd>>> entitycomponentenginesdb | |||
, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
if (entitycomponentenginesdb.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var entityComponentsEngines)) | |||
{ | |||
if (entityComponentsEngines.count == 0) | |||
return; | |||
var dictionaryKeyEnumerator = fromDictionary.unsafeKeys; | |||
var count = fromDictionary.count; | |||
for (var i = 0; i < count; ++i) | |||
try | |||
{ | |||
var key = dictionaryKeyEnumerator[i].key; | |||
ref var entity = ref todic.GetValueByRef(key); | |||
var egid = new EGID(key, togroup); | |||
//get all the engines linked to TValue | |||
for (var j = 0; j < entityComponentsEngines.count; j++) | |||
using (sampler.Sample(entityComponentsEngines[j].name)) | |||
{ | |||
((IReactOnAdd<TValue>)entityComponentsEngines[j].engine).Add(ref entity, egid); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException( | |||
e, "Code crashed inside Add callback with Type ".FastConcat(TypeCache<TValue>.name)); | |||
throw; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesDisposeCallbacks_Group<Strategy1, Strategy2, Strategy3, TValue> | |||
(ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>> allEngines | |||
, ExclusiveGroupStruct inGroup, in PlatformProfiler sampler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
if (allEngines.TryGetValue(new RefWrapperType(TypeCache<TValue>.type), out var entityComponentsEngines) | |||
== false) | |||
return; | |||
for (var i = 0; i < entityComponentsEngines.count; i++) | |||
try | |||
{ | |||
using (sampler.Sample(entityComponentsEngines[i].name)) | |||
{ | |||
foreach (var value in fromDictionary) | |||
{ | |||
ref var entity = ref value.value; | |||
var egid = new EGID(value.key, inGroup); | |||
var reactOnRemove = (IReactOnDispose<TValue>)entityComponentsEngines[i].engine; | |||
reactOnRemove.Remove(ref entity, egid); | |||
} | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat(entityComponentsEngines[i].name)); | |||
throw; | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesRemoveCallbacks<Strategy1, Strategy2, Strategy3, TValue> | |||
(FasterList<(uint, string)> infostoprocess | |||
, ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveenginesremove | |||
, ExclusiveGroupStruct fromgroup, in PlatformProfiler profiler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
if (reactiveenginesremove.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var entityComponentsEngines)) | |||
{ | |||
if (entityComponentsEngines.count == 0) | |||
return; | |||
var iterations = infostoprocess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (entityID, trace) = infostoprocess[i]; | |||
try | |||
{ | |||
ref var entity = ref fromDictionary.GetValueByRef(entityID); | |||
var egid = new EGID(entityID, fromgroup); | |||
for (var j = 0; j < entityComponentsEngines.count; j++) | |||
using (profiler.Sample(entityComponentsEngines[j].name)) | |||
{ | |||
((IReactOnRemove<TValue>)entityComponentsEngines[j].engine).Remove(ref entity, egid); | |||
} | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Remove Entity callback on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesRemoveCallbacks_Group<Strategy1, Strategy2, Strategy3, TValue> | |||
(ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, ITypeSafeDictionary<TValue> typeSafeDictionary | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveenginesremove | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemoveEx>>> reactiveenginesremoveex | |||
, int count, IEntityIDs entityids, ExclusiveGroupStruct group, in PlatformProfiler sampler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
if (reactiveenginesremove.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var reactiveEnginesRemovePerType)) | |||
{ | |||
var enginesCount = reactiveEnginesRemovePerType.count; | |||
for (var i = 0; i < enginesCount; i++) | |||
try | |||
{ | |||
foreach (var value in fromDictionary) | |||
{ | |||
ref var entity = ref value.value; | |||
var egid = new EGID(value.key, group); | |||
using (sampler.Sample(reactiveEnginesRemovePerType[i].name)) | |||
{ | |||
((IReactOnRemove<TValue>)reactiveEnginesRemovePerType[i].engine).Remove( | |||
ref entity, egid); | |||
} | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemovePerType[i].name)); | |||
throw; | |||
} | |||
} | |||
if (reactiveenginesremoveex.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var reactiveEnginesRemoveExPerType)) | |||
{ | |||
var enginesCount = reactiveEnginesRemoveExPerType.count; | |||
for (var i = 0; i < enginesCount; i++) | |||
try | |||
{ | |||
using (sampler.Sample(reactiveEnginesRemoveExPerType[i].name)) | |||
{ | |||
((IReactOnRemoveEx<TValue>)reactiveEnginesRemoveExPerType[i].engine).Remove( | |||
(0, (uint)count) | |||
, new EntityCollection<TValue>(typeSafeDictionary.GetValues(out _), entityids | |||
, (uint)count), group); | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemoveExPerType[i].name)); | |||
throw; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesSwapCallbacks<Strategy1, Strategy2, Strategy3, TValue> | |||
(FasterList<(uint, uint, string)> infostoprocess | |||
, ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, FasterList<ReactEngineContainer<IReactOnSwap>> reactiveenginesswap, ExclusiveGroupStruct togroup | |||
, ExclusiveGroupStruct fromgroup, in PlatformProfiler sampler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
if (reactiveenginesswap.count == 0) | |||
return; | |||
var iterations = infostoprocess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (fromEntityID, toEntityID, trace) = infostoprocess[i]; | |||
try | |||
{ | |||
ref var entityComponent = ref fromDictionary.GetValueByRef(fromEntityID); | |||
var newEgid = new EGID(toEntityID, togroup); | |||
for (var j = 0; j < reactiveenginesswap.count; j++) | |||
using (sampler.Sample(reactiveenginesswap[j].name)) | |||
{ | |||
((IReactOnSwap<TValue>)reactiveenginesswap[j].engine).MovedTo( | |||
ref entityComponent, fromgroup, newEgid); | |||
} | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Swap Entity callback on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesSwapCallbacks_Group<Strategy1, Strategy2, Strategy3, TValue> | |||
(ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, ITypeSafeDictionary<TValue> toDic, ExclusiveGroupStruct togroup, ExclusiveGroupStruct fromgroup | |||
, ITypeSafeDictionary<TValue> typeSafeDictionary | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwap>>> reactiveenginesswap | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwapEx>>> reactiveenginesswapex | |||
, int count, IEntityIDs entityids, in PlatformProfiler sampler) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
//get all the engines linked to TValue | |||
if (!reactiveenginesswap.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var reactiveEnginesSwapPerType)) | |||
return; | |||
var componentsEnginesCount = reactiveEnginesSwapPerType.count; | |||
for (var i = 0; i < componentsEnginesCount; i++) | |||
try | |||
{ | |||
foreach (var value in fromDictionary) | |||
{ | |||
ref var entityComponent = ref toDic.GetValueByRef(value.key); | |||
var newEgid = new EGID(value.key, togroup); | |||
using (sampler.Sample(reactiveEnginesSwapPerType[i].name)) | |||
{ | |||
((IReactOnSwap<TValue>)reactiveEnginesSwapPerType[i].engine).MovedTo( | |||
ref entityComponent, fromgroup, newEgid); | |||
} | |||
} | |||
} | |||
catch (Exception) | |||
{ | |||
Console.LogError( | |||
"Code crashed inside MoveTo callback ".FastConcat(reactiveEnginesSwapPerType[i].name)); | |||
throw; | |||
} | |||
if (reactiveenginesswapex.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var reactiveEnginesRemoveExPerType)) | |||
{ | |||
var enginesCount = reactiveEnginesRemoveExPerType.count; | |||
for (var i = 0; i < enginesCount; i++) | |||
try | |||
{ | |||
using (sampler.Sample(reactiveEnginesRemoveExPerType[i].name)) | |||
{ | |||
((IReactOnSwapEx<TValue>)reactiveEnginesRemoveExPerType[i].engine).MovedTo( | |||
(0, (uint)count) | |||
, new EntityCollection<TValue>(typeSafeDictionary.GetValues(out _), entityids | |||
, (uint)count), fromgroup, togroup); | |||
} | |||
} | |||
catch | |||
{ | |||
Console.LogError( | |||
"Code crashed inside Remove callback ".FastConcat(reactiveEnginesRemoveExPerType[i].name)); | |||
throw; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void RemoveEntitiesFromDictionary<Strategy1, Strategy2, Strategy3, TValue> | |||
(FasterList<(uint, string)> infostoprocess | |||
, ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, FasterList<uint> entityIDsAffectedByRemoval) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
var iterations = infostoprocess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (id, trace) = infostoprocess[i]; | |||
try | |||
{ | |||
if (fromDictionary.Remove(id, out var index, out var value)) | |||
{ | |||
//Note I am doing this to be able to use a range of values even with the | |||
//remove Ex callbacks. Basically I am copying back the deleted value | |||
//at the end of the array, so I can use as range count, count + number of deleted entities | |||
//I need to swap the keys too to have matching EntityIDs | |||
fromDictionary.unsafeValues[(uint)fromDictionary.count] = value; | |||
fromDictionary.unsafeKeys[(uint)fromDictionary.count] = new SveltoDictionaryNode<uint>(ref id, 0); | |||
//when a component is removed from a component array, a remove swap back happens. This means | |||
//that not only we have to remove the index of the component of the entity deleted from the array | |||
//but we need also to update the index of the component that has been swapped in the cell | |||
//of the deleted component | |||
//entityIDsAffectedByRemoval tracks all the entitiesID of the components that need to be updated | |||
//in the filters because their indices in the array changed. | |||
entityIDsAffectedByRemoval.Add(fromDictionary.unsafeKeys[index].key); | |||
} | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Remove Entity operation on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void SwapEntitiesBetweenDictionaries<Strategy1, Strategy2, Strategy3, TValue> | |||
(FasterList<(uint, uint, string)> infostoprocess | |||
, ref SveltoDictionary<uint, TValue, Strategy1, Strategy2, Strategy3> fromDictionary | |||
, ITypeSafeDictionary<TValue> toDictionary, ExclusiveGroupStruct fromgroup, ExclusiveGroupStruct togroup | |||
, FasterList<uint> entityIDsAffectedByRemoval) | |||
where Strategy1 : struct, IBufferStrategy<SveltoDictionaryNode<uint>> | |||
where Strategy2 : struct, IBufferStrategy<TValue> | |||
where Strategy3 : struct, IBufferStrategy<int> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
var iterations = infostoprocess.count; | |||
for (var i = 0; i < iterations; i++) | |||
{ | |||
var (fromID, toID, trace) = infostoprocess[i]; | |||
try | |||
{ | |||
var fromEntityGid = new EGID(fromID, fromgroup); | |||
var toEntityEgid = new EGID(toID, togroup); | |||
Check.Require(togroup.isInvalid == false, "Invalid To Group"); | |||
if (fromDictionary.Remove(fromEntityGid.entityID, out var index, out var value)) | |||
entityIDsAffectedByRemoval.Add(fromDictionary.unsafeKeys[index].key); | |||
else | |||
Check.Assert(false, "Swapping an entity that doesn't exist"); | |||
#if SLOW_SVELTO_SUBMISSION | |||
if (SlowSubmissionInfo<TValue>.hasEgid) | |||
SetEGIDWithoutBoxing<TValue>.SetIDWithoutBoxing(ref value, toEntityEgid); | |||
#endif | |||
toDictionary.Add(toEntityEgid.entityID, value); | |||
#if PARANOID_CHECK | |||
DBC.ECS.Check.Ensure(_hasEgid == false || ((INeedEGID)toGroupCasted[toEntityEGID.entityID]).ID == toEntityEGID, "impossible situation happened during swap"); | |||
#endif | |||
} | |||
catch | |||
{ | |||
var str = "Crash while executing Swap Entity operation on ".FastConcat(TypeCache<TValue>.name) | |||
.FastConcat(" from : ", trace); | |||
Console.LogError(str); | |||
throw; | |||
} | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesAddEntityCallbacksFast<TValue> | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAddEx>>> fasterDictionary | |||
, ExclusiveGroupStruct groupId, (uint, uint) valueTuple, IEntityIDs entityids | |||
, ITypeSafeDictionary<TValue> typeSafeDictionary, PlatformProfiler profiler) | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
//get all the engines linked to TValue | |||
if (!fasterDictionary.TryGetValue(new RefWrapperType(TypeCache<TValue>.type) | |||
, out var entityComponentsEngines)) | |||
return; | |||
for (var i = 0; i < entityComponentsEngines.count; i++) | |||
try | |||
{ | |||
using (profiler.Sample(entityComponentsEngines[i].name)) | |||
{ | |||
((IReactOnAddEx<TValue>)entityComponentsEngines[i].engine).Add( | |||
valueTuple | |||
, new EntityCollection<TValue>(typeSafeDictionary.GetValues(out var count), entityids, count) | |||
, groupId); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException( | |||
e, "Code crashed inside Add callback ".FastConcat(entityComponentsEngines[i].name)); | |||
throw; | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesSwapCallbacksFast<TValue> | |||
(FasterList<ReactEngineContainer<IReactOnSwapEx>> fasterList, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, IEntityIDs entityids, ITypeSafeDictionary<TValue> typeSafeDictionary | |||
, (uint, uint) rangeofsubmittedentitiesindicies, PlatformProfiler sampler) | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
for (var i = 0; i < fasterList.count; i++) | |||
try | |||
{ | |||
using (sampler.Sample(fasterList[i].name)) | |||
{ | |||
((IReactOnSwapEx<TValue>)fasterList[i].engine).MovedTo(rangeofsubmittedentitiesindicies | |||
, new EntityCollection<TValue>( | |||
typeSafeDictionary.GetValues( | |||
out var count), entityids, count) | |||
, fromGroup, toGroup); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, "Code crashed inside Add callback ".FastConcat(fasterList[i].name)); | |||
throw; | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static void ExecuteEnginesRemoveCallbacksFast<TValue> | |||
(FasterList<ReactEngineContainer<IReactOnRemoveEx>> fasterList, ExclusiveGroupStruct exclusiveGroupStruct | |||
, (uint, uint) valueTuple, IEntityIDs entityids, ITypeSafeDictionary<TValue> typeSafeDictionary | |||
, PlatformProfiler sampler) where TValue : struct, IBaseEntityComponent | |||
{ | |||
for (var i = 0; i < fasterList.count; i++) | |||
try | |||
{ | |||
using (sampler.Sample(fasterList[i].name)) | |||
{ | |||
((IReactOnRemoveEx<TValue>)fasterList[i].engine).Remove( | |||
valueTuple | |||
, new EntityCollection<TValue>(typeSafeDictionary.GetValues(out var count), entityids, count) | |||
, exclusiveGroupStruct); | |||
} | |||
} | |||
catch (Exception e) | |||
{ | |||
Console.LogException(e, "Code crashed inside Add callback ".FastConcat(fasterList[i].name)); | |||
throw; | |||
} | |||
} | |||
} | |||
} |
@@ -3,7 +3,7 @@ namespace Svelto.ECS.Internal | |||
static class TypeSafeDictionaryUtilities | |||
{ | |||
internal static EGIDMapper<T> ToEGIDMapper<T>(this ITypeSafeDictionary<T> dic, | |||
ExclusiveGroupStruct groupStructId) where T:struct, IEntityComponent | |||
ExclusiveGroupStruct groupStructId) where T:struct, IBaseEntityComponent | |||
{ | |||
var mapper = new EGIDMapper<T>(groupStructId, dic); | |||
@@ -0,0 +1,47 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.Common; | |||
namespace Svelto.ECS.DataStructures | |||
{ | |||
public struct SharedDisposableNative<T> : IDisposable where T : unmanaged, IDisposable | |||
{ | |||
#if UNITY_COLLECTIONS || (UNITY_JOBS || UNITY_BURST) | |||
[global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] | |||
#endif | |||
unsafe IntPtr ptr; | |||
public SharedDisposableNative(in T value) | |||
{ | |||
unsafe | |||
{ | |||
ptr = MemoryUtilities.Alloc<T>(1, Allocator.Persistent); | |||
Unsafe.Write((void*)ptr, value); | |||
} | |||
} | |||
public void Dispose() | |||
{ | |||
unsafe | |||
{ | |||
Unsafe.AsRef<T>((void*)ptr).Dispose(); | |||
MemoryUtilities.Free((IntPtr)ptr, Allocator.Persistent); | |||
ptr = IntPtr.Zero; | |||
} | |||
} | |||
public ref T value | |||
{ | |||
get | |||
{ | |||
unsafe | |||
{ | |||
DBC.ECS.Check.Require(ptr != null, "SharedNative has not been initialized"); | |||
return ref Unsafe.AsRef<T>((void*)ptr); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,51 +1,9 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using System.Threading; | |||
using Svelto.Common; | |||
namespace Svelto.ECS.DataStructures | |||
{ | |||
public struct SharedNative<T> : IDisposable where T : struct, IDisposable | |||
{ | |||
#if UNITY_COLLECTIONS || (UNITY_JOBS || UNITY_BURST) | |||
[global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] | |||
#endif | |||
unsafe IntPtr ptr; | |||
public SharedNative(in T value) | |||
{ | |||
unsafe | |||
{ | |||
ptr = MemoryUtilities.Alloc<T>(1, Allocator.Persistent); | |||
Unsafe.Write((void*)ptr, value); | |||
} | |||
} | |||
public void Dispose() | |||
{ | |||
unsafe | |||
{ | |||
Unsafe.AsRef<T>((void*)ptr).Dispose(); | |||
MemoryUtilities.Free((IntPtr)ptr, Allocator.Persistent); | |||
ptr = IntPtr.Zero; | |||
} | |||
} | |||
public ref T value | |||
{ | |||
get | |||
{ | |||
unsafe | |||
{ | |||
DBC.ECS.Check.Require(ptr != null, "SharedNative has not been initialized"); | |||
return ref Unsafe.AsRef<T>((void*)ptr); | |||
} | |||
} | |||
} | |||
} | |||
public struct SharedNativeInt: IDisposable | |||
{ | |||
#if UNITY_COLLECTIONS || (UNITY_JOBS || UNITY_BURST) | |||
@@ -0,0 +1,312 @@ | |||
#if DEBUG && !PROFILE_SVELTO | |||
//#define PARANOID_CHECK | |||
#endif | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using System.Threading; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.DataStructures.Native; | |||
using Svelto.ECS.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
#if SLOW_SVELTO_SUBMISSION | |||
static class SlowSubmissionInfo<T> | |||
{ | |||
internal static readonly bool hasEgid = typeof(INeedEGID).IsAssignableFrom(TypeCache<T>.type); | |||
internal static readonly bool hasReference = typeof(INeedEntityReference).IsAssignableFrom(TypeCache<T>.type); | |||
} | |||
#endif | |||
public sealed class UnmanagedTypeSafeDictionary<TValue> : ITypeSafeDictionary<TValue> | |||
where TValue : struct, IBaseEntityComponent | |||
{ | |||
static readonly ThreadLocal<IEntityIDs> cachedEntityIDN = | |||
new ThreadLocal<IEntityIDs>(() => new NativeEntityIDs()); | |||
public UnmanagedTypeSafeDictionary(uint size) | |||
{ | |||
implUnmgd = | |||
new SharedSveltoDictionaryNative<uint, TValue>(size, Allocator.Persistent); | |||
} | |||
public IEntityIDs entityIDs | |||
{ | |||
get | |||
{ | |||
ref var unboxed = ref Unsafe.Unbox<NativeEntityIDs>(cachedEntityIDN.Value); | |||
unboxed.Update(implUnmgd.dictionary.unsafeKeys.ToRealBuffer()); | |||
return cachedEntityIDN.Value; | |||
} | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool ContainsKey(uint egidEntityId) | |||
{ | |||
return implUnmgd.dictionary.ContainsKey(egidEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public uint GetIndex(uint valueEntityId) | |||
{ | |||
return implUnmgd.dictionary.GetIndex(valueEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref TValue GetOrAdd(uint idEntityId) | |||
{ | |||
return ref implUnmgd.dictionary.GetOrAdd(idEntityId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public IBuffer<TValue> GetValues(out uint count) | |||
{ | |||
return implUnmgd.dictionary.UnsafeGetValues(out count); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref TValue GetDirectValueByRef(uint key) | |||
{ | |||
return ref implUnmgd.dictionary.GetDirectValueByRef(key); | |||
} | |||
public ref TValue GetValueByRef(uint key) | |||
{ | |||
return ref implUnmgd.dictionary.GetValueByRef(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Has(uint key) | |||
{ | |||
return implUnmgd.dictionary.ContainsKey(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryFindIndex(uint entityId, out uint index) | |||
{ | |||
return implUnmgd.dictionary.TryFindIndex(entityId, out index); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryGetValue(uint entityId, out TValue item) | |||
{ | |||
return implUnmgd.dictionary.TryGetValue(entityId, out item); | |||
} | |||
public int count | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => implUnmgd.dictionary.count; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ITypeSafeDictionary Create() | |||
{ | |||
return TypeSafeDictionaryFactory<TValue>.Create(1); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Clear() | |||
{ | |||
implUnmgd.dictionary.FastClear(); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void EnsureCapacity(uint size) | |||
{ | |||
implUnmgd.dictionary.EnsureCapacity(size); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void IncreaseCapacityBy(uint size) | |||
{ | |||
implUnmgd.dictionary.IncreaseCapacityBy(size); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Trim() | |||
{ | |||
implUnmgd.dictionary.Trim(); | |||
} | |||
public void KeysEvaluator(Action<uint> action) | |||
{ | |||
foreach (var key in implUnmgd.dictionary.keys) | |||
action(key); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void Add(uint egidEntityId, in TValue entityComponent) | |||
{ | |||
implUnmgd.dictionary.Add(egidEntityId, entityComponent); | |||
} | |||
public void Dispose() | |||
{ | |||
implUnmgd.Dispose(); //SharedDisposableNative already calls the dispose of the underlying value | |||
GC.SuppressFinalize(this); | |||
} | |||
/// ********************************* | |||
/// the following methods are executed during the submission of entities | |||
/// ********************************* | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void AddEntitiesToDictionary | |||
(ITypeSafeDictionary toDictionary, ExclusiveGroupStruct groupId | |||
#if SLOW_SVELTO_SUBMISSION | |||
, in EnginesRoot.EntityReferenceMap entityLocator | |||
#endif | |||
) | |||
{ | |||
TypeSafeDictionaryMethods.AddEntitiesToDictionary(implUnmgd.dictionary | |||
, toDictionary as ITypeSafeDictionary<TValue> | |||
#if SLOW_SVELTO_SUBMISSION | |||
, entityLocator | |||
#endif | |||
, groupId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveEntitiesFromDictionary | |||
(FasterList<(uint, string)> infosToProcess, FasterList<uint> entityIDsAffectedByRemoval) | |||
{ | |||
TypeSafeDictionaryMethods.RemoveEntitiesFromDictionary(infosToProcess, ref implUnmgd.dictionary | |||
, entityIDsAffectedByRemoval); | |||
} | |||
public void SwapEntitiesBetweenDictionaries | |||
(FasterList<(uint, uint, string)> infosToProcess, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, ITypeSafeDictionary toComponentsDictionary | |||
, FasterList<uint> entityIDsAffectedByRemoval) | |||
{ | |||
TypeSafeDictionaryMethods.SwapEntitiesBetweenDictionaries(infosToProcess, ref implUnmgd.dictionary | |||
,toComponentsDictionary as ITypeSafeDictionary<TValue>, fromGroup, toGroup, entityIDsAffectedByRemoval); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnAdd callbacks linked to components added this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesAddCallbacks | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAdd>>> entityComponentEnginesDB | |||
, ITypeSafeDictionary toDic, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesAddCallbacks(ref implUnmgd.dictionary, (ITypeSafeDictionary<TValue>)toDic | |||
, toGroup, entityComponentEnginesDB, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnSwap callbacks linked to components swapped this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesSwapCallbacks | |||
(FasterList<(uint, uint, string)> infosToProcess | |||
, FasterList<ReactEngineContainer<IReactOnSwap>> reactiveEnginesSwap, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacks(infosToProcess, ref implUnmgd.dictionary | |||
, reactiveEnginesSwap, toGroup, fromGroup, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnREmove callbacks linked to components removed this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesRemoveCallbacks | |||
(FasterList<(uint, string)> infosToProcess | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveEnginesRemove | |||
, ExclusiveGroupStruct fromGroup, in PlatformProfiler sampler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks(infosToProcess, ref implUnmgd.dictionary | |||
, reactiveEnginesRemove, fromGroup, in sampler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnAddEx callbacks linked to components added this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesAddEntityCallbacksFast | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnAddEx>>> reactiveEnginesAdd | |||
, ExclusiveGroupStruct groupID, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesAddEntityCallbacksFast( | |||
reactiveEnginesAdd, groupID, rangeOfSubmittedEntitiesIndicies, entityIDs, this, profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnSwapEx callbacks linked to components swapped this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesSwapCallbacksFast | |||
(FasterList<ReactEngineContainer<IReactOnSwapEx>> reactiveEnginesSwap, ExclusiveGroupStruct fromGroup | |||
, ExclusiveGroupStruct toGroup, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler sampler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacksFast(reactiveEnginesSwap, fromGroup, toGroup, entityIDs | |||
, this, rangeOfSubmittedEntitiesIndicies, sampler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnRemoveEx callbacks linked to components removed this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesRemoveCallbacksFast | |||
(FasterList<ReactEngineContainer<IReactOnRemoveEx>> reactiveEnginesRemoveEx, ExclusiveGroupStruct fromGroup | |||
, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler sampler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacksFast(reactiveEnginesRemoveEx, fromGroup | |||
, rangeOfSubmittedEntitiesIndicies, entityIDs | |||
, this, sampler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnSwap and IReactOnSwapEx callbacks linked to components swapped between | |||
/// whole groups swapped during this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesSwapCallbacks_Group | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwap>>> reactiveEnginesSwap | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnSwapEx>>> reactiveEnginesSwapEx | |||
, ITypeSafeDictionary toDictionary, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup | |||
, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacks_Group( | |||
ref implUnmgd.dictionary, (ITypeSafeDictionary<TValue>)toDictionary, toGroup, fromGroup, this | |||
, reactiveEnginesSwap, reactiveEnginesSwapEx, count, entityIDs, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnRemove and IReactOnRemoveEx callbacks linked to components remove from | |||
/// whole groups removed during this submit | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesRemoveCallbacks_Group | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemove>>> reactiveEnginesRemove | |||
, FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnRemoveEx>>> reactiveEnginesRemoveEx | |||
, ExclusiveGroupStruct group, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks_Group( | |||
ref implUnmgd.dictionary, this, reactiveEnginesRemove, reactiveEnginesRemoveEx, count, entityIDs, group | |||
, in profiler); | |||
} | |||
/// <summary> | |||
/// Execute all the engine IReactOnDispose for eahc component registered in the DB when it's disposed of | |||
/// </summary> | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void ExecuteEnginesDisposeCallbacks_Group | |||
(FasterDictionary<RefWrapperType, FasterList<ReactEngineContainer<IReactOnDispose>>> engines | |||
, ExclusiveGroupStruct group, in PlatformProfiler profiler) | |||
{ | |||
TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group( | |||
ref implUnmgd.dictionary, engines, group, in profiler); | |||
} | |||
internal SharedSveltoDictionaryNative<uint, TValue> implUnmgd; | |||
} | |||
} |
@@ -13,30 +13,26 @@ namespace Svelto.ECS.Native | |||
/// that a job can use it as long as nothing else is modifying the entities database and the NativeEGIDMapper | |||
/// is disposed right after the use. | |||
/// </summary> | |||
public readonly struct NativeEGIDMapper<T> : IEGIDMapper where T : unmanaged, IEntityComponent | |||
public readonly struct NativeEGIDMapper<T> : IEGIDMapper where T : unmanaged, IBaseEntityComponent | |||
{ | |||
public static readonly NativeEGIDMapper<T> empty = new NativeEGIDMapper<T> | |||
(default, new SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, NativeStrategy<int>>>( | |||
new SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, NativeStrategy<int>>(0, Allocator.Persistent))); | |||
(default, new SharedSveltoDictionaryNative<uint, T>(0, Allocator.Persistent)); | |||
public NativeEGIDMapper(ExclusiveGroupStruct groupStructId, | |||
in SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, | |||
NativeStrategy<int>>> toNative) : this() | |||
in SharedSveltoDictionaryNative<uint, T> toDisposableNative) : this() | |||
{ | |||
groupID = groupStructId; | |||
_map = toNative; | |||
_map = toDisposableNative; | |||
} | |||
public int count => _map.value.count; | |||
public int count => _map.dictionary.count; | |||
public Type entityType => TypeCache<T>.type; | |||
public ExclusiveGroupStruct groupID { get; } | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public ref T Entity(uint entityID) | |||
{ | |||
var sveltoDictionary = _map.value; | |||
var sveltoDictionary = _map.dictionary; | |||
#if DEBUG && !PROFILE_SVELTO | |||
if (sveltoDictionary.TryFindIndex(entityID, out var findIndex) == false) | |||
@@ -50,7 +46,7 @@ namespace Svelto.ECS.Native | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool TryGetEntity(uint entityID, out T value) | |||
{ | |||
var sveltoDictionary = _map.value; | |||
var sveltoDictionary = _map.dictionary; | |||
if (sveltoDictionary.count > 0 && sveltoDictionary.TryFindIndex(entityID, out var index)) | |||
{ | |||
var values = sveltoDictionary.unsafeValues.ToRealBuffer(); | |||
@@ -65,7 +61,7 @@ namespace Svelto.ECS.Native | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public NB<T> GetArrayAndEntityIndex(uint entityID, out uint index) | |||
{ | |||
var sveltoDictionary = _map.value; | |||
var sveltoDictionary = _map.dictionary; | |||
if (sveltoDictionary.TryFindIndex(entityID, out index)) | |||
return sveltoDictionary.unsafeValues.ToRealBuffer(); | |||
@@ -80,7 +76,7 @@ namespace Svelto.ECS.Native | |||
public bool TryGetArrayAndEntityIndex(uint entityID, out uint index, out NB<T> array) | |||
{ | |||
index = 0; | |||
var sveltoDictionary = _map.value; | |||
var sveltoDictionary = _map.dictionary; | |||
if (sveltoDictionary.count > 0 && sveltoDictionary.TryFindIndex(entityID, out index)) | |||
{ | |||
@@ -95,23 +91,22 @@ namespace Svelto.ECS.Native | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool Exists(uint idEntityId) | |||
{ | |||
var sveltoDictionary = _map.value; | |||
var sveltoDictionary = _map.dictionary; | |||
return sveltoDictionary.count > 0 && sveltoDictionary.TryFindIndex(idEntityId, out _); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public uint GetIndex(uint entityID) | |||
{ | |||
return _map.value.GetIndex(entityID); | |||
return _map.dictionary.GetIndex(entityID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public bool FindIndex(uint valueKey, out uint index) | |||
{ | |||
return _map.value.TryFindIndex(valueKey, out index); | |||
return _map.dictionary.TryFindIndex(valueKey, out index); | |||
} | |||
readonly SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, | |||
NativeStrategy<int>>> _map; | |||
readonly SharedSveltoDictionaryNative<uint, T> _map; | |||
} | |||
} |
@@ -14,17 +14,9 @@ namespace Svelto.ECS.Native | |||
///WARNING: REMEMBER THIS MUST BE DISPOSED OF, AS IT USES NATIVE MEMORY. IT WILL LEAK MEMORY OTHERWISE | |||
/// | |||
/// </summary> | |||
public struct NativeEGIDMultiMapper<T> : IDisposable where T : unmanaged, IEntityComponent | |||
public struct NativeEGIDMultiMapper<T> : IDisposable where T : unmanaged, IBaseEntityComponent | |||
{ | |||
public NativeEGIDMultiMapper(in SveltoDictionary< | |||
/*key */ExclusiveGroupStruct, | |||
/*value*/ | |||
SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, | |||
NativeStrategy<int>>>, | |||
/*strategy to store the key*/ NativeStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, | |||
/*strategy to store the value*/ | |||
NativeStrategy<SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, NativeStrategy<int>>>>, NativeStrategy<int>> dictionary) | |||
public NativeEGIDMultiMapper(in SveltoDictionaryNative<ExclusiveGroupStruct, SharedSveltoDictionaryNative<uint, T>> dictionary) | |||
{ | |||
_dic = dictionary; | |||
} | |||
@@ -43,7 +35,7 @@ namespace Svelto.ECS.Native | |||
throw new Exception($"NativeEGIDMultiMapper: Entity not found {entity}"); | |||
#endif | |||
ref var sveltoDictionary = ref _dic.GetValueByRef(entity.groupID); | |||
return ref sveltoDictionary.value.GetValueByRef(entity.entityID); | |||
return ref sveltoDictionary.dictionary.GetValueByRef(entity.entityID); | |||
} | |||
public uint GetIndex(EGID entity) | |||
@@ -53,26 +45,22 @@ namespace Svelto.ECS.Native | |||
throw new Exception($"NativeEGIDMultiMapper: Entity not found {entity}"); | |||
#endif | |||
ref var sveltoDictionary = ref _dic.GetValueByRef(entity.groupID); | |||
return sveltoDictionary.value.GetIndex(entity.entityID); | |||
return sveltoDictionary.dictionary.GetIndex(entity.entityID); | |||
} | |||
public bool Exists(EGID entity) | |||
{ | |||
return _dic.TryFindIndex(entity.groupID, out var index) && | |||
_dic.GetDirectValueByRef(index).value.ContainsKey(entity.entityID); | |||
_dic.GetDirectValueByRef(index).dictionary.ContainsKey(entity.entityID); | |||
} | |||
public bool TryGetEntity(EGID entity, out T component) | |||
{ | |||
component = default; | |||
return _dic.TryFindIndex(entity.groupID, out var index) && | |||
_dic.GetDirectValueByRef(index).value.TryGetValue(entity.entityID, out component); | |||
_dic.GetDirectValueByRef(index).dictionary.TryGetValue(entity.entityID, out component); | |||
} | |||
SveltoDictionary<ExclusiveGroupStruct, | |||
SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, | |||
NativeStrategy<int>>>, NativeStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, NativeStrategy< | |||
SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, | |||
NativeStrategy<int>>>>, NativeStrategy<int>> _dic; | |||
SveltoDictionaryNative<ExclusiveGroupStruct, SharedSveltoDictionaryNative<uint, T>> _dic; | |||
} | |||
} |
@@ -9,7 +9,7 @@ namespace Svelto.ECS.Native | |||
{ | |||
public static class UnityNativeEntityDBExtensions | |||
{ | |||
static NativeEGIDMapper<T> ToNativeEGIDMapper<T>(this TypeSafeDictionary<T> dic, | |||
static NativeEGIDMapper<T> ToNativeEGIDMapper<T>(this UnmanagedTypeSafeDictionary<T> dic, | |||
ExclusiveGroupStruct groupStructId) where T : unmanaged, IEntityComponent | |||
{ | |||
var mapper = new NativeEGIDMapper<T>(groupStructId, dic.implUnmgd); | |||
@@ -24,7 +24,7 @@ namespace Svelto.ECS.Native | |||
if (entitiesDb.SafeQueryEntityDictionary<T>(groupStructId, out var typeSafeDictionary) == false) | |||
throw new EntityGroupNotFoundException(typeof(T), groupStructId.ToName()); | |||
return (typeSafeDictionary as TypeSafeDictionary<T>).ToNativeEGIDMapper(groupStructId); | |||
return (typeSafeDictionary as UnmanagedTypeSafeDictionary<T>).ToNativeEGIDMapper(groupStructId); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
@@ -37,7 +37,7 @@ namespace Svelto.ECS.Native | |||
typeSafeDictionary.count == 0) | |||
return false; | |||
mapper = (typeSafeDictionary as TypeSafeDictionary<T>).ToNativeEGIDMapper(groupStructId); | |||
mapper = (typeSafeDictionary as UnmanagedTypeSafeDictionary<T>).ToNativeEGIDMapper(groupStructId); | |||
return true; | |||
} | |||
@@ -45,24 +45,20 @@ namespace Svelto.ECS.Native | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
///Note: if I use a SharedNativeSveltoDictionary for implUnmg, I may be able to cache NativeEGIDMultiMapper | |||
/// and reuse it | |||
/// TODO: the ability to retain a NativeEGIDMultiMapper thanks to the use of shareable arrays | |||
/// must be unit tested! | |||
public static NativeEGIDMultiMapper<T> QueryNativeMappedEntities<T>(this EntitiesDB entitiesDb, | |||
LocalFasterReadOnlyList<ExclusiveGroupStruct> groups, Allocator allocator) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
var dictionary = new SveltoDictionary< | |||
/*key */ExclusiveGroupStruct, | |||
/*value*/SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, NativeStrategy<int>>>, | |||
/*strategy to store the key*/ NativeStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, | |||
/*strategy to store the value*/NativeStrategy< | |||
SharedNative<SveltoDictionary<uint, T, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<T>, NativeStrategy<int>>>> | |||
, NativeStrategy<int>> | |||
var dictionary = new SveltoDictionaryNative<ExclusiveGroupStruct, SharedSveltoDictionaryNative<uint, T>> | |||
((uint) groups.count, allocator); | |||
foreach (var group in groups) | |||
{ | |||
if (entitiesDb.SafeQueryEntityDictionary<T>(group, out var typeSafeDictionary) == true) | |||
//if (typeSafeDictionary.count > 0) | |||
dictionary.Add(group, ((TypeSafeDictionary<T>)typeSafeDictionary).implUnmgd); | |||
dictionary.Add(group, ((UnmanagedTypeSafeDictionary<T>)typeSafeDictionary).implUnmgd); | |||
} | |||
return new NativeEGIDMultiMapper<T>(dictionary); | |||
@@ -9,7 +9,7 @@ namespace Svelto.ECS | |||
/// that can be burstifiable | |||
/// </summary> | |||
/// <typeparam name="T1"></typeparam> | |||
public readonly struct AllGroupsEnumerable<T1> where T1 : struct, IEntityComponent | |||
public readonly struct AllGroupsEnumerable<T1> where T1 : struct, IBaseEntityComponent | |||
{ | |||
public ref struct GroupCollection | |||
{ | |||
@@ -45,8 +45,8 @@ namespace Svelto.ECS | |||
if (typeSafeDictionary.count == 0) | |||
continue; | |||
_array.collection = new EntityCollection<T1>(typeSafeDictionary.GetValues(out var count), count, | |||
typeSafeDictionary.entityIDs); | |||
_array.collection = new EntityCollection<T1>(typeSafeDictionary.GetValues(out var count), | |||
typeSafeDictionary.entityIDs, count); | |||
_array.@group = group.key; | |||
return true; | |||
} | |||
@@ -9,7 +9,7 @@ namespace Svelto.ECS | |||
{ | |||
namespace Native | |||
{ | |||
public struct EGIDMultiMapper<T> where T : unmanaged, IEntityComponent | |||
public struct EGIDMultiMapper<T> where T : unmanaged, IBaseEntityComponent | |||
{ | |||
public EGIDMultiMapper | |||
(SveltoDictionary<ExclusiveGroupStruct, | |||
@@ -11,7 +11,14 @@ namespace Svelto.ECS | |||
public static void Deconstruct<T1>(in this EntityCollection<T1> ec, out NB<T1> buffer, out int count) | |||
where T1 : unmanaged, IEntityComponent | |||
{ | |||
buffer = ec._nativedBuffer; | |||
if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer = (NB<T1>)ec._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -19,9 +26,17 @@ namespace Svelto.ECS | |||
public static void Deconstruct<T1>(in this EntityCollection<T1> ec, out NB<T1> buffer, | |||
out NativeEntityIDs entityIDs, out int count) where T1 : unmanaged, IEntityComponent | |||
{ | |||
buffer = ec._nativedBuffer; | |||
if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer = default; | |||
count = 0; | |||
entityIDs = default; | |||
return; | |||
} | |||
buffer = (NB<T1>)ec._buffer; | |||
count = (int)ec.count; | |||
entityIDs = ec._nativedIndices; | |||
entityIDs = (NativeEntityIDs)ec._entityIDs; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
@@ -29,10 +44,19 @@ namespace Svelto.ECS | |||
out NB<T2> buffer2, out NativeEntityIDs entityIDs, out int count) where T1 : unmanaged, IEntityComponent | |||
where T2 : unmanaged, IEntityComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
count = 0; | |||
entityIDs = default; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
count = ec.count; | |||
entityIDs = ec.buffer1._nativedIndices; | |||
entityIDs = (NativeEntityIDs)ec.buffer1._entityIDs; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
@@ -40,8 +64,16 @@ namespace Svelto.ECS | |||
out NB<T2> buffer2, out int count) where T1 : unmanaged, IEntityComponent | |||
where T2 : unmanaged, IEntityComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -51,9 +83,18 @@ namespace Svelto.ECS | |||
where T2 : unmanaged, IEntityComponent | |||
where T3 : unmanaged, IEntityComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._nativedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (NB<T3>)ec.buffer3._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -64,11 +105,21 @@ namespace Svelto.ECS | |||
where T2 : unmanaged, IEntityComponent | |||
where T3 : unmanaged, IEntityComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._nativedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
count = 0; | |||
entityIDs = default; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (NB<T3>)ec.buffer3._buffer; | |||
count = (int)ec.count; | |||
entityIDs = ec.buffer1._nativedIndices; | |||
entityIDs = (NativeEntityIDs)ec.buffer1._entityIDs; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
@@ -79,10 +130,20 @@ namespace Svelto.ECS | |||
where T3 : unmanaged, IEntityComponent | |||
where T4 : unmanaged, IEntityComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._nativedBuffer; | |||
buffer4 = ec.buffer4._nativedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
buffer4 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (NB<T3>)ec.buffer3._buffer; | |||
buffer4 = (NB<T4>)ec.buffer4._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -94,11 +155,22 @@ namespace Svelto.ECS | |||
where T3 : unmanaged, IEntityComponent | |||
where T4 : unmanaged, IEntityComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._nativedBuffer; | |||
buffer4 = ec.buffer4._nativedBuffer; | |||
entityIDs = ec.buffer1._nativedIndices; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
buffer4 = default; | |||
count = 0; | |||
entityIDs = default; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (NB<T3>)ec.buffer3._buffer; | |||
buffer4 = (NB<T4>)ec.buffer4._buffer; | |||
entityIDs = (NativeEntityIDs)ec.buffer1._entityIDs; | |||
count = (int)ec.count; | |||
} | |||
} | |||
@@ -109,7 +181,14 @@ namespace Svelto.ECS | |||
public static void Deconstruct<T1>(in this EntityCollection<T1> ec, out MB<T1> buffer, out int count) | |||
where T1 : struct, IEntityViewComponent | |||
{ | |||
buffer = ec._managedBuffer; | |||
if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer = (MB<T1>)ec._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -117,9 +196,16 @@ namespace Svelto.ECS | |||
public static void Deconstruct<T1>(in this EntityCollection<T1> ec, out MB<T1> buffer, | |||
out ManagedEntityIDs entityIDs, out int count) where T1 : struct, IEntityViewComponent | |||
{ | |||
buffer = ec._managedBuffer; | |||
if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer = default; | |||
count = 0; | |||
entityIDs = default; | |||
return; | |||
} | |||
buffer = (MB<T1>)ec._buffer; | |||
count = (int)ec.count; | |||
entityIDs = ec._managedIndices; | |||
entityIDs = (ManagedEntityIDs)ec._entityIDs; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
@@ -127,8 +213,16 @@ namespace Svelto.ECS | |||
out MB<T2> buffer2, out int count) where T1 : struct, IEntityViewComponent | |||
where T2 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._managedBuffer; | |||
buffer2 = ec.buffer2._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (MB<T1>)ec.buffer1._buffer; | |||
buffer2 = (MB<T2>)ec.buffer2._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -137,10 +231,19 @@ namespace Svelto.ECS | |||
out MB<T2> buffer2, out ManagedEntityIDs entityIDs, out int count) where T1 : struct, IEntityViewComponent | |||
where T2 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._managedBuffer; | |||
buffer2 = ec.buffer2._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
count = 0; | |||
entityIDs = default; | |||
return; | |||
} | |||
buffer1 = (MB<T1>)ec.buffer1._buffer; | |||
buffer2 = (MB<T2>)ec.buffer2._buffer; | |||
count = (int)ec.count; | |||
entityIDs = ec.buffer1._managedIndices; | |||
entityIDs = (ManagedEntityIDs)ec.buffer1._entityIDs; | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
@@ -149,9 +252,18 @@ namespace Svelto.ECS | |||
where T2 : struct, IEntityViewComponent | |||
where T3 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._managedBuffer; | |||
buffer2 = ec.buffer2._managedBuffer; | |||
buffer3 = ec.buffer3._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (MB<T1>)ec.buffer1._buffer; | |||
buffer2 = (MB<T2>)ec.buffer2._buffer; | |||
buffer3 = (MB<T3>)ec.buffer3._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -162,11 +274,21 @@ namespace Svelto.ECS | |||
where T2 : struct, IEntityViewComponent | |||
where T3 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._managedBuffer; | |||
buffer2 = ec.buffer2._managedBuffer; | |||
buffer3 = ec.buffer3._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
entityIDs = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (MB<T1>)ec.buffer1._buffer; | |||
buffer2 = (MB<T2>)ec.buffer2._buffer; | |||
buffer3 = (MB<T3>)ec.buffer3._buffer; | |||
count = (int)ec.count; | |||
entityIDs = ec.buffer1._managedIndices; | |||
entityIDs = (ManagedEntityIDs)ec.buffer1._entityIDs; | |||
} | |||
} | |||
@@ -177,8 +299,16 @@ namespace Svelto.ECS | |||
out MB<T2> buffer2, out int count) where T1 : unmanaged, IEntityComponent | |||
where T2 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (MB<T2>)ec.buffer2._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -188,9 +318,18 @@ namespace Svelto.ECS | |||
where T2 : struct, IEntityViewComponent | |||
where T3 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._managedBuffer; | |||
buffer3 = ec.buffer3._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (MB<T2>)ec.buffer2._buffer; | |||
buffer3 = (MB<T3>)ec.buffer3._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -202,10 +341,20 @@ namespace Svelto.ECS | |||
where T3 : unmanaged, IEntityComponent | |||
where T4 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._nativedBuffer; | |||
buffer4 = ec.buffer4._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
buffer4 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (NB<T3>)ec.buffer3._buffer; | |||
buffer4 = (MB<T4>)ec.buffer4._buffer; | |||
count = (int)ec.count; | |||
} | |||
} | |||
@@ -218,9 +367,18 @@ namespace Svelto.ECS | |||
where T2 : unmanaged, IEntityComponent | |||
where T3 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (MB<T3>)ec.buffer3._buffer; | |||
count = (int)ec.count; | |||
} | |||
@@ -232,10 +390,20 @@ namespace Svelto.ECS | |||
where T3 : struct, IEntityViewComponent | |||
where T4 : struct, IEntityViewComponent | |||
{ | |||
buffer1 = ec.buffer1._nativedBuffer; | |||
buffer2 = ec.buffer2._nativedBuffer; | |||
buffer3 = ec.buffer3._managedBuffer; | |||
buffer4 = ec.buffer4._managedBuffer; | |||
if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 | |||
{ | |||
buffer1 = default; | |||
buffer2 = default; | |||
buffer3 = default; | |||
buffer4 = default; | |||
count = 0; | |||
return; | |||
} | |||
buffer1 = (NB<T1>)ec.buffer1._buffer; | |||
buffer2 = (NB<T2>)ec.buffer2._buffer; | |||
buffer3 = (MB<T3>)ec.buffer3._buffer; | |||
buffer4 = (MB<T4>)ec.buffer4._buffer; | |||
count = (int)ec.count; | |||
} | |||
} |
@@ -119,7 +119,7 @@ namespace Svelto.ECS | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static AllGroupsEnumerable<T1> QueryEntities<T1>(this EntitiesDB db) | |||
where T1 :struct, IEntityComponent | |||
where T1 :struct, IBaseEntityComponent | |||
{ | |||
return new AllGroupsEnumerable<T1>(db); | |||
} | |||
@@ -11,10 +11,10 @@ namespace Svelto.ECS | |||
/// <typeparam name="T2"></typeparam> | |||
/// <typeparam name="T3"></typeparam> | |||
/// <typeparam name="T4"></typeparam> | |||
public readonly ref struct GroupsEnumerable<T1, T2, T3, T4> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
public readonly ref struct GroupsEnumerable<T1, T2, T3, T4> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
where T4 : struct, IBaseEntityComponent | |||
{ | |||
public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
{ | |||
@@ -92,9 +92,9 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public readonly ref struct GroupsEnumerable<T1, T2, T3> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
public readonly ref struct GroupsEnumerable<T1, T2, T3> where T1 : struct, IBaseEntityComponent | |||
where T2 : struct, IBaseEntityComponent | |||
where T3 : struct, IBaseEntityComponent | |||
{ | |||
public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
{ | |||
@@ -175,7 +175,7 @@ namespace Svelto.ECS | |||
} | |||
public readonly ref struct GroupsEnumerable<T1, T2> | |||
where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent | |||
where T1 : struct, IBaseEntityComponent where T2 : struct, IBaseEntityComponent | |||
{ | |||
public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
{ | |||
@@ -253,7 +253,7 @@ namespace Svelto.ECS | |||
} | |||
} | |||
public readonly ref struct GroupsEnumerable<T1> where T1 : struct, IEntityComponent | |||
public readonly ref struct GroupsEnumerable<T1> where T1 : struct, IBaseEntityComponent | |||
{ | |||
public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
{ | |||
@@ -99,7 +99,7 @@ namespace Svelto.ECS.SveltoOnDOTS | |||
void PreSubmissionPhase(ref JobHandle jobHandle, PlatformProfiler profiler) | |||
{ | |||
using (profiler.Sample("Complete All Pending Jobs")) jobHandle.Complete(); | |||
using (profiler.Sample("Complete All Pending Jobs")) jobHandle.Complete(); //sync-point | |||
_entityCommandBuffer = new EntityCommandBuffer((Allocator)Common.Allocator.TempJob); | |||
@@ -26,11 +26,11 @@ namespace Svelto.ECS.SveltoOnDOTS | |||
public void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection<DOTSEntityComponent> collection, | |||
ExclusiveGroupStruct _, ExclusiveGroupStruct toGroup) | |||
{ | |||
var (buffer, entityIDs, _) = collection; | |||
var (entities, entityIDs, _) = collection; | |||
for (uint i = rangeOfEntities.start; i < rangeOfEntities.end; i++) | |||
{ | |||
ref var entityComponent = ref buffer[i]; | |||
ref var entityComponent = ref entities[i]; | |||
ECB.SetSharedComponent(entityComponent.dotsEntity, new DOTSSveltoGroupID(toGroup)); | |||
ECB.SetComponent(entityComponent.dotsEntity, new DOTSSveltoEGID | |||
@@ -1,31 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using Svelto.DataStructures; | |||
using UnityEngine; | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
///The class that wrap the OOP library must be known by the package only as much as possible. | |||
///what cannot be use through the package, is exposed through a public interface. Note though that this may | |||
///be considered a work around to better design. In this case, no methods are exposed. | |||
public class GOManager | |||
{ | |||
public uint RegisterEntity(PrimitiveType type) | |||
{ | |||
var cubeObject = GameObject.CreatePrimitive(type); | |||
objects.Add(cubeObject.transform); | |||
return (uint) (objects.count - 1); | |||
} | |||
public void SetParent(uint index, in uint parent) | |||
{ | |||
objects[index].SetParent(objects[parent], false); | |||
} | |||
public void SetPosition(uint index, in Vector3 position) { objects[index].localPosition = position; } | |||
readonly FasterList<Transform> objects = new FasterList<Transform>(); | |||
} | |||
} | |||
#endif |
@@ -1,13 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using Svelto.ECS.Hybrid; | |||
using UnityEngine; | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
[DisallowMultipleComponent] | |||
public class EntityReferenceHolderImplementor : MonoBehaviour, IImplementor | |||
{ | |||
public EntityReference reference { get; set; } | |||
} | |||
} | |||
#endif |
@@ -1,6 +0,0 @@ | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
public interface IECSManager | |||
{ | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
using Svelto.ECS.Hybrid; | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
public interface IUseMultipleResourceManagerImplementor: IImplementor | |||
{ | |||
IECSManager[] resourceManager { set; } | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
using Svelto.ECS.Hybrid; | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
public interface IUseResourceManagerImplementor: IImplementor | |||
{ | |||
IECSManager resourceManager { set; } | |||
} | |||
} |
@@ -18,14 +18,17 @@ public class ListToPopupDrawer : PropertyDrawer | |||
if (atb.classType.GetField(atb.listName, BindingFlags.Static | BindingFlags.NonPublic) != null) | |||
{ | |||
stringList = atb.classType.GetField(atb.listName, BindingFlags.Static | BindingFlags.NonPublic).GetValue(atb.classType) as List<Type>; | |||
stringList = | |||
atb.classType.GetField(atb.listName, BindingFlags.Static | BindingFlags.NonPublic) | |||
.GetValue(atb.classType) as List<Type>; | |||
} | |||
if (stringList != null && stringList.Count != 0) | |||
{ | |||
int selectedIndex = Mathf.Max(0, stringList.FindIndex(t => t.Name == property.stringValue)); | |||
selectedIndex = EditorGUI.Popup(position, property.name, selectedIndex, stringList.Select(t => t.Name).ToArray()); | |||
int selectedIndex = Mathf.Max(0, stringList.FindIndex(t => t.Name == property.stringValue)); | |||
selectedIndex = EditorGUI.Popup(position, property.name, selectedIndex | |||
, stringList.Select(t => t.Name).ToArray()); | |||
property.stringValue = stringList[selectedIndex].Name; | |||
(property.serializedObject.targetObject as EntityDescriptorHolder).type = | |||
@@ -3,7 +3,7 @@ using System; | |||
namespace Svelto.ECS.Serialization | |||
{ | |||
public class ComposedComponentSerializer<T, X, Y> : IComponentSerializer<T> | |||
where T : unmanaged, IEntityComponent where X : class, IComponentSerializer<T>, new() | |||
where T : unmanaged, IBaseEntityComponent where X : class, IComponentSerializer<T>, new() | |||
where Y : class, IComponentSerializer<T>, new() | |||
{ | |||
public ComposedComponentSerializer() | |||
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS.Serialization | |||
{ | |||
public class DefaultSerializer<T> : IComponentSerializer<T> where T : unmanaged, IEntityComponent | |||
public class DefaultSerializer<T> : IComponentSerializer<T> where T : unmanaged, IBaseEntityComponent | |||
{ | |||
static readonly uint SIZEOFT = SerializableComponentBuilder<T>.SIZE; | |||
@@ -3,7 +3,7 @@ using Svelto.ECS; | |||
public static class DefaultSerializerUtils | |||
{ | |||
public static unsafe void CopyToByteArray<T>(in T src, byte[] data, uint offsetDst) where T : unmanaged, IEntityComponent | |||
public static unsafe void CopyToByteArray<T>(in T src, byte[] data, uint offsetDst) where T : unmanaged, IBaseEntityComponent | |||
{ | |||
#if DEBUG && !PROFILE_SVELTO | |||
if (data.Length - offsetDst < sizeof(T)) | |||
@@ -29,7 +29,7 @@ public static class DefaultSerializerUtils | |||
} | |||
} | |||
public static unsafe T CopyFromByteArray<T>(byte[] data, uint offsetSrc) where T : unmanaged, IEntityComponent | |||
public static unsafe T CopyFromByteArray<T>(byte[] data, uint offsetSrc) where T : unmanaged, IBaseEntityComponent | |||
{ | |||
T dst = default; | |||
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS.Serialization | |||
{ | |||
public class DontSerialize<T> : IComponentSerializer<T> where T : unmanaged, IEntityComponent | |||
public class DontSerialize<T> : IComponentSerializer<T> where T : unmanaged, IBaseEntityComponent | |||
{ | |||
public uint size => 0; | |||
@@ -89,7 +89,7 @@ namespace Svelto.ECS | |||
/// <returns></returns> | |||
public T DeserializeEntityComponent<T>(ISerializationData serializationData, | |||
ISerializableEntityDescriptor entityDescriptor, int serializationType) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
var readPos = serializationData.dataPos; | |||
T entityComponent = default; | |||
@@ -2,7 +2,7 @@ | |||
#endif | |||
namespace Svelto.ECS.Serialization | |||
{ | |||
public interface IComponentSerializer<T> where T : unmanaged, IEntityComponent | |||
public interface IComponentSerializer<T> where T : unmanaged, IBaseEntityComponent | |||
{ | |||
bool Serialize(in T value, ISerializationData serializationData); | |||
bool Deserialize(ref T value, ISerializationData serializationData); | |||
@@ -84,6 +84,6 @@ namespace Svelto.ECS.Serialization | |||
T DeserializeEntityComponent<T>(ISerializationData serializationData, | |||
ISerializableEntityDescriptor entityDescriptor, int serializationType) | |||
where T : unmanaged, IEntityComponent; | |||
where T : unmanaged, IBaseEntityComponent; | |||
} | |||
} |
@@ -11,7 +11,7 @@ namespace Svelto.ECS.Serialization | |||
{} | |||
public class PartialSerializer<T> : IComponentSerializer<T> | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
static PartialSerializer() | |||
{ | |||
@@ -12,7 +12,7 @@ namespace Svelto.ECS.Serialization | |||
} | |||
public class SerializableComponentBuilder<T> : ComponentBuilder<T>, ISerializableComponentBuilder | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
public static readonly uint SIZE = (uint) MemoryUtilities.SizeOf<T>(); | |||
@@ -77,7 +77,7 @@ namespace Svelto.ECS.Serialization | |||
} | |||
public class SerializableComponentBuilder<SerializationType, T> : SerializableComponentBuilder<T> | |||
where T : unmanaged, IEntityComponent where SerializationType : Enum | |||
where T : unmanaged, IBaseEntityComponent where SerializationType : Enum | |||
{ | |||
static SerializableComponentBuilder() { } | |||
@@ -4,7 +4,7 @@ namespace Svelto.ECS.Serialization | |||
{ | |||
public static bool SerializeSafe<T> | |||
(this IComponentSerializer<T> componentSerializer, in T value, ISerializationData serializationData) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
#if DEBUG && !PROFILE_SVELTO | |||
uint posBefore = serializationData.dataPos; | |||
@@ -24,7 +24,7 @@ namespace Svelto.ECS.Serialization | |||
public static bool DeserializeSafe<T> | |||
(this IComponentSerializer<T> componentSerializer, ref T value, ISerializationData serializationData) | |||
where T : unmanaged, IEntityComponent | |||
where T : unmanaged, IBaseEntityComponent | |||
{ | |||
#if DEBUG && !PROFILE_SVELTO | |||
uint posBefore = serializationData.dataPos; | |||
@@ -11,7 +11,7 @@ | |||
"url": "https://github.com/sebas77/Svelto.ECS.git" | |||
}, | |||
"dependencies": { | |||
"com.sebaslab.svelto.common": "3.3.0" | |||
"com.sebaslab.svelto.common": "3.3.2" | |||
}, | |||
"keywords": [ | |||
"svelto", | |||
@@ -19,7 +19,7 @@ | |||
"svelto.ecs" | |||
], | |||
"name": "com.sebaslab.svelto.ecs", | |||
"version": "3.3.1", | |||
"version": "3.3.2", | |||
"type": "library", | |||
"unity": "2019.3" | |||
} |