Browse Source

release Svelto.ECS 3.3.2

pull/107/head
Sebastiano Mandalà 2 years ago
parent
commit
30d53fb5cc
78 changed files with 2157 additions and 1647 deletions
  1. +13
    -2
      com.sebaslab.svelto.ecs/CHANGELOG.md
  2. +88
    -0
      com.sebaslab.svelto.ecs/Core/BT.cs
  3. +13
    -16
      com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs
  4. +1
    -1
      com.sebaslab.svelto.ecs/Core/EGIDMapper.cs
  5. +3
    -4
      com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs
  6. +112
    -95
      com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs
  7. +48
    -75
      com.sebaslab.svelto.ecs/Core/EntitiesDB.cs
  8. +2
    -10
      com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs
  9. +31
    -140
      com.sebaslab.svelto.ecs/Core/EntityCollection.cs
  10. +5
    -5
      com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs
  11. +3
    -3
      com.sebaslab.svelto.ecs/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs
  12. +9
    -9
      com.sebaslab.svelto.ecs/Core/EntityDescriptor/GenericEntityDescriptor.cs
  13. +1
    -1
      com.sebaslab.svelto.ecs/Core/EntityInfoView.cs
  14. +4
    -4
      com.sebaslab.svelto.ecs/Core/EntityInitializer.cs
  15. +19
    -22
      com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs
  16. +107
    -75
      com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs
  17. +14
    -10
      com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs
  18. +10
    -10
      com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.LegacyFilters.cs
  19. +31
    -38
      com.sebaslab.svelto.ecs/Core/Filters/EntityFilterCollection.cs
  20. +1
    -1
      com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterCollection.cs
  21. +1
    -1
      com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterIterator.cs
  22. +2
    -2
      com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs
  23. +19
    -19
      com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs
  24. +0
    -0
      com.sebaslab.svelto.ecs/Core/Groups/EntityGroupNotFoundException.cs
  25. +0
    -0
      com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs
  26. +0
    -0
      com.sebaslab.svelto.ecs/Core/Groups/GroupNamesMap.cs
  27. +2
    -2
      com.sebaslab.svelto.ecs/Core/Groups/QueryGroups.cs
  28. +1
    -1
      com.sebaslab.svelto.ecs/Core/Hybrid/IEntityViewComponent.cs
  29. +11
    -0
      com.sebaslab.svelto.ecs/Core/IBaseEntityComponent.cs
  30. +12
    -8
      com.sebaslab.svelto.ecs/Core/IEngine.cs
  31. +0
    -7
      com.sebaslab.svelto.ecs/Core/IEntityComponent.cs
  32. +3
    -3
      com.sebaslab.svelto.ecs/Core/SetEGIDWithoutBoxing.cs
  33. +10
    -10
      com.sebaslab.svelto.ecs/Core/SpecialEnumerators/DoubleIterationEnumerator.cs
  34. +1
    -1
      com.sebaslab.svelto.ecs/Core/Streams/Consumer.cs
  35. +2
    -2
      com.sebaslab.svelto.ecs/Core/Streams/EnginesRoot.Streams.cs
  36. +1
    -1
      com.sebaslab.svelto.ecs/Core/Streams/EntitiesDB.Streams.cs
  37. +3
    -3
      com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs
  38. +1
    -1
      com.sebaslab.svelto.ecs/Core/Streams/EntityStream.cs
  39. +4
    -4
      com.sebaslab.svelto.ecs/Core/Streams/GenericentityStreamConsumerFactory.cs
  40. +15
    -4
      com.sebaslab.svelto.ecs/Core/TypeSafeDictionaryFactory.cs
  41. +4
    -0
      com.sebaslab.svelto.ecs/DataStructures/EntityIDs/IEntityIDs.cs
  42. +22
    -0
      com.sebaslab.svelto.ecs/DataStructures/EntityIDs/ManagedEntityIDs.cs
  43. +22
    -0
      com.sebaslab.svelto.ecs/DataStructures/EntityIDs/NativeEntityIDs.cs
  44. +12
    -6
      com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs
  45. +305
    -0
      com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs
  46. +0
    -800
      com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionary.cs
  47. +539
    -0
      com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs
  48. +1
    -1
      com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryUtilities.cs
  49. +47
    -0
      com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedDisposableNative.cs
  50. +0
    -42
      com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedNativeInt.cs
  51. +312
    -0
      com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs
  52. +13
    -18
      com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMapper.cs
  53. +7
    -19
      com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMultiMapper.cs
  54. +8
    -12
      com.sebaslab.svelto.ecs/Extensions/Native/UnityNativeEntityDBExtensions.cs
  55. +3
    -3
      com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs
  56. +1
    -1
      com.sebaslab.svelto.ecs/Extensions/Svelto/EGIDMultiMapper.cs
  57. +223
    -55
      com.sebaslab.svelto.ecs/Extensions/Svelto/EntityCollectionExtension.cs
  58. +1
    -1
      com.sebaslab.svelto.ecs/Extensions/Svelto/EntityManagedDBExtensions.cs
  59. +9
    -9
      com.sebaslab.svelto.ecs/Extensions/Svelto/GroupsEnumerable.cs
  60. +1
    -1
      com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEntitiesSubmissionGroup.cs
  61. +2
    -2
      com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleLifeTimeEngine.cs
  62. +0
    -31
      com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/AbstractionLayer/GOManager.cs
  63. +0
    -13
      com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/EntityReferenceHolderImplementor.cs
  64. +0
    -6
      com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/IECSManager.cs
  65. +0
    -9
      com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/IUseMultipleResourceManagerImplementor.cs
  66. +0
    -9
      com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/IUseResourceManagerImplementor.cs
  67. +7
    -4
      com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/ListToPopupDrawer.cs
  68. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/ComposedComponentSerializer.cs
  69. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/DefaultSerializer.cs
  70. +2
    -2
      com.sebaslab.svelto.ecs/Serialization/DefaultSerializerUtils.cs
  71. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/DontSerialize.cs
  72. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs
  73. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/IComponentSerializer.cs
  74. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs
  75. +1
    -1
      com.sebaslab.svelto.ecs/Serialization/PartialSerializer.cs
  76. +2
    -2
      com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs
  77. +2
    -2
      com.sebaslab.svelto.ecs/Serialization/SerializerExt.cs
  78. +2
    -2
      com.sebaslab.svelto.ecs/package.json

+ 13
- 2
com.sebaslab.svelto.ecs/CHANGELOG.md View File

@@ -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


+ 88
- 0
com.sebaslab.svelto.ecs/Core/BT.cs View File

@@ -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);
}
}
}

+ 13
- 16
com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs View File

@@ -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>>>();



+ 1
- 1
com.sebaslab.svelto.ecs/Core/EGIDMapper.cs View File

@@ -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; }


+ 3
- 4
com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs View File

@@ -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>>>();



+ 112
- 95
com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs View File

@@ -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,


+ 48
- 75
com.sebaslab.svelto.ecs/Core/EntitiesDB.cs View File

@@ -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;


+ 2
- 10
com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs View File

@@ -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


+ 31
- 140
com.sebaslab.svelto.ecs/Core/EntityCollection.cs View File

@@ -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;
}
}

+ 5
- 5
com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs View File

@@ -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 =
{


+ 3
- 3
com.sebaslab.svelto.ecs/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs View File

@@ -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>();
}


+ 9
- 9
com.sebaslab.svelto.ecs/Core/EntityDescriptor/GenericEntityDescriptor.cs View File

@@ -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
- 1
com.sebaslab.svelto.ecs/Core/EntityInfoView.cs View File

@@ -1,6 +1,6 @@
namespace Svelto.ECS
{
struct EntityInfoComponent: IEntityComponent
struct EntityInfoComponent: IBaseEntityComponent
{
public IComponentBuilder[] componentsToBuild;
}

+ 4
- 4
com.sebaslab.svelto.ecs/Core/EntityInitializer.cs View File

@@ -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))


+ 19
- 22
com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs View File

@@ -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);


+ 107
- 75
com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs View File

@@ -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;
}
}
}
}
}


+ 14
- 10
com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs View File

@@ -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);



+ 10
- 10
com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.LegacyFilters.cs View File

@@ -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);



+ 31
- 38
com.sebaslab.svelto.ecs/Core/Filters/EntityFilterCollection.cs View File

@@ -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;
}


+ 1
- 1
com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterCollection.cs View File

@@ -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
- 1
com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterIterator.cs View File

@@ -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)
{


+ 2
- 2
com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs View File

@@ -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);


com.sebaslab.svelto.ecs/Core/EntitiesDB.FindGroups.cs → com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs View File

@@ -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

com.sebaslab.svelto.ecs/Core/EntityGroupNotFoundException.cs → com.sebaslab.svelto.ecs/Core/Groups/EntityGroupNotFoundException.cs View File


com.sebaslab.svelto.ecs/Core/GroupHashMap.cs → com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs View File


com.sebaslab.svelto.ecs/Core/GroupNamesMap.cs → com.sebaslab.svelto.ecs/Core/Groups/GroupNamesMap.cs View File


com.sebaslab.svelto.ecs/Core/QueryGroups.cs → com.sebaslab.svelto.ecs/Core/Groups/QueryGroups.cs View File

@@ -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
- 1
com.sebaslab.svelto.ecs/Core/Hybrid/IEntityViewComponent.cs View File

@@ -1,6 +1,6 @@
namespace Svelto.ECS.Hybrid
{
public interface IManagedComponent:IEntityComponent
public interface IManagedComponent:IBaseEntityComponent
{}
public interface IEntityViewComponent:IManagedComponent


+ 11
- 0
com.sebaslab.svelto.ecs/Core/IBaseEntityComponent.cs View File

@@ -0,0 +1,11 @@
namespace Svelto.ECS
{
///<summary>Entity Components MUST implement IEntityComponent</summary>
public interface IBaseEntityComponent
{
}
public interface IEntityComponent:IBaseEntityComponent
{
}
}

+ 12
- 8
com.sebaslab.svelto.ecs/Core/IEngine.cs View File

@@ -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);


+ 0
- 7
com.sebaslab.svelto.ecs/Core/IEntityComponent.cs View File

@@ -1,7 +0,0 @@
namespace Svelto.ECS
{
///<summary>Entity Components MUST implement IEntityComponent</summary>
public interface IEntityComponent
{
}
}

+ 3
- 3
com.sebaslab.svelto.ecs/Core/SetEGIDWithoutBoxing.cs View File

@@ -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();


+ 10
- 10
com.sebaslab.svelto.ecs/Core/SpecialEnumerators/DoubleIterationEnumerator.cs View File

@@ -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)
{


+ 1
- 1
com.sebaslab.svelto.ecs/Core/Streams/Consumer.cs View File

@@ -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()
{


+ 2
- 2
com.sebaslab.svelto.ecs/Core/Streams/EnginesRoot.Streams.cs View File

@@ -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);
}


+ 1
- 1
com.sebaslab.svelto.ecs/Core/Streams/EntitiesDB.Streams.cs View File

@@ -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


+ 3
- 3
com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs View File

@@ -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);


+ 1
- 1
com.sebaslab.svelto.ecs/Core/Streams/EntityStream.cs View File

@@ -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;



+ 4
- 4
com.sebaslab.svelto.ecs/Core/Streams/GenericentityStreamConsumerFactory.cs View File

@@ -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;
}
}

+ 15
- 4
com.sebaslab.svelto.ecs/Core/TypeSafeDictionaryFactory.cs View File

@@ -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);
}
}
}

+ 4
- 0
com.sebaslab.svelto.ecs/DataStructures/EntityIDs/IEntityIDs.cs View File

@@ -0,0 +1,4 @@
namespace Svelto.ECS.Internal
{
public interface IEntityIDs { }
}

+ 22
- 0
com.sebaslab.svelto.ecs/DataStructures/EntityIDs/ManagedEntityIDs.cs View File

@@ -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;
}
}

+ 22
- 0
com.sebaslab.svelto.ecs/DataStructures/EntityIDs/NativeEntityIDs.cs View File

@@ -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;
}
}

+ 12
- 6
com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs View File

@@ -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);
//------------



+ 305
- 0
com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs View File

@@ -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;
}
}

+ 0
- 800
com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionary.cs View File

@@ -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;
}
}

+ 539
- 0
com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs View File

@@ -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;
}
}
}
}

+ 1
- 1
com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryUtilities.cs View File

@@ -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);



+ 47
- 0
com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedDisposableNative.cs View File

@@ -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);
}
}
}
}
}

+ 0
- 42
com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedNativeInt.cs View File

@@ -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)


+ 312
- 0
com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs View File

@@ -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
- 18
com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMapper.cs View File

@@ -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;
}
}

+ 7
- 19
com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMultiMapper.cs View File

@@ -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;
}
}

+ 8
- 12
com.sebaslab.svelto.ecs/Extensions/Native/UnityNativeEntityDBExtensions.cs View File

@@ -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);


+ 3
- 3
com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs View File

@@ -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;
}


+ 1
- 1
com.sebaslab.svelto.ecs/Extensions/Svelto/EGIDMultiMapper.cs View File

@@ -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,


+ 223
- 55
com.sebaslab.svelto.ecs/Extensions/Svelto/EntityCollectionExtension.cs View File

@@ -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;
}
}

+ 1
- 1
com.sebaslab.svelto.ecs/Extensions/Svelto/EntityManagedDBExtensions.cs View File

@@ -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);
}


+ 9
- 9
com.sebaslab.svelto.ecs/Extensions/Svelto/GroupsEnumerable.cs View File

@@ -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)
{


+ 1
- 1
com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEntitiesSubmissionGroup.cs View File

@@ -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);


+ 2
- 2
com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleLifeTimeEngine.cs View File

@@ -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


+ 0
- 31
com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/AbstractionLayer/GOManager.cs View File

@@ -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

+ 0
- 13
com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/EntityReferenceHolderImplementor.cs View File

@@ -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

+ 0
- 6
com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/IECSManager.cs View File

@@ -1,6 +0,0 @@
namespace Svelto.ECS.Extensions.Unity
{
public interface IECSManager
{
}
}

+ 0
- 9
com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/IUseMultipleResourceManagerImplementor.cs View File

@@ -1,9 +0,0 @@
using Svelto.ECS.Hybrid;

namespace Svelto.ECS.Extensions.Unity
{
public interface IUseMultipleResourceManagerImplementor: IImplementor
{
IECSManager[] resourceManager { set; }
}
}

+ 0
- 9
com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/Implementors/IUseResourceManagerImplementor.cs View File

@@ -1,9 +0,0 @@
using Svelto.ECS.Hybrid;

namespace Svelto.ECS.Extensions.Unity
{
public interface IUseResourceManagerImplementor: IImplementor
{
IECSManager resourceManager { set; }
}
}

+ 7
- 4
com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/ListToPopupDrawer.cs View File

@@ -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 =


+ 1
- 1
com.sebaslab.svelto.ecs/Serialization/ComposedComponentSerializer.cs View File

@@ -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
- 1
com.sebaslab.svelto.ecs/Serialization/DefaultSerializer.cs View File

@@ -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;



+ 2
- 2
com.sebaslab.svelto.ecs/Serialization/DefaultSerializerUtils.cs View File

@@ -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
- 1
com.sebaslab.svelto.ecs/Serialization/DontSerialize.cs View File

@@ -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;



+ 1
- 1
com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs View File

@@ -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;


+ 1
- 1
com.sebaslab.svelto.ecs/Serialization/IComponentSerializer.cs View File

@@ -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);


+ 1
- 1
com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs View File

@@ -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;
}
}

+ 1
- 1
com.sebaslab.svelto.ecs/Serialization/PartialSerializer.cs View File

@@ -11,7 +11,7 @@ namespace Svelto.ECS.Serialization
{}

public class PartialSerializer<T> : IComponentSerializer<T>
where T : unmanaged, IEntityComponent
where T : unmanaged, IBaseEntityComponent
{
static PartialSerializer()
{


+ 2
- 2
com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs View File

@@ -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() { }



+ 2
- 2
com.sebaslab.svelto.ecs/Serialization/SerializerExt.cs View File

@@ -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;


+ 2
- 2
com.sebaslab.svelto.ecs/package.json View File

@@ -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"
}

Loading…
Cancel
Save