Browse Source

Update to svelto 3.5.2

master
Sebastiano Mandala 2 months ago
parent
commit
259d1fe4c1
21 changed files with 69 additions and 682 deletions
  1. +1
    -1
      com.sebaslab.svelto.common
  2. +9
    -2
      com.sebaslab.svelto.ecs/CHANGELOG.md
  3. +1
    -12
      com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs
  4. +0
    -5
      com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs
  5. +11
    -10
      com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs
  6. +3
    -2
      com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.EntityReferenceMap.cs
  7. +1
    -0
      com.sebaslab.svelto.ecs/Core/EntitySubmissionScheduler.cs
  8. +1
    -2
      com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs
  9. +24
    -25
      com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs
  10. +0
    -213
      com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs
  11. +0
    -214
      com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilterGroup.cs
  12. +0
    -40
      com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilteredIndices.cs
  13. +0
    -106
      com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyGroupFilters.cs
  14. +2
    -2
      com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs
  15. +6
    -4
      com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs
  16. +0
    -18
      com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/EntitiesDBFiltersExtension.cs
  17. +0
    -21
      com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/FilterGroupExtensions.cs
  18. +5
    -3
      com.sebaslab.svelto.ecs/Serialization/DefaultVersioningFactory.cs
  19. +2
    -1
      com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs
  20. +2
    -0
      com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs
  21. +1
    -1
      com.sebaslab.svelto.ecs/package.json

+ 1
- 1
com.sebaslab.svelto.common

@@ -1 +1 @@
Subproject commit e95bcb19dc7aa7eed74f0c099a471b3dcd0ef5a3
Subproject commit 94d4210c6f59ebed95b45ed6bc599d3b255f76ca

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

@@ -1,18 +1,25 @@
# Svelto.ECS Changelog
All notable changes to this project will be documented in this file. Changes are listed in random order of importance.

## [3.5.2] - 07-2024

* Minor serialization code improvements
* Remove legacy filters once for all
* breaking change: GetOrCreate*Filter, Create*Filter, Get*Filter don't return by ref anymore to fix reported bug
* references are now updated at the end of the submission frame so they are accessible inside callbacks

## [3.5.1] - 01-2024

* Remove UnityEntitySubmissionScheduler, it was never needed, the user can use the standard EntitySubmissionScheduler and tick it manually
* Dropped the idea to specialise EntitiesSubmissionScheduler. In hindsight it was never necessary.
* Added better support for range exclusive groups, now they are correctly registered in the group hash map
* Removed announg Group compound/tag {type} is not sealed warning
* Removed annoying Group compound/tag {type} is not sealed warning
* Merged Cuyi's workaround to be able to query compound groups in abstract engine. Never had the time to implement a better solution
* It is now possible again to add an entity multiple times inside a filter (it will be overriden)
* Fixed issue https://github.com/sebas77/Svelto.ECS/issues/123
* Fixed issue https://github.com/sebas77/Svelto.ECS/issues/122
* Fixed issue https://github.com/sebas77/Svelto.ECS/issues/121
* AddEngine now adds engines contained in a GroupEngine to the EnginesGroup optionally~~~~
* AddEngine now adds engines contained in a GroupEngine to the EnginesGroup optionally

## [3.5.0] - 09-2023



+ 1
- 12
com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs View File

@@ -76,10 +76,7 @@ namespace Svelto.ECS
new FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>>();
_groupedEntityToAdd = new DoubleBufferedEntitiesToAdd();
_entityStreams = EntitiesStreams.Create();
#if SVELTO_LEGACY_FILTERS
_groupFilters =
new FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>>();
#endif

_entityLocator.InitEntityReferenceMap();
_entitiesDB = new EntitiesDB(this, _entityLocator);

@@ -296,14 +293,6 @@ namespace Svelto.ECS
foreach (var entityList in groups.value)
entityList.value.Dispose();

#if SVELTO_LEGACY_FILTERS
foreach (var type in _groupFilters)
foreach (var group in type.value)
group.value.Dispose();

_groupFilters.Clear();
#endif

DisposeFilters();

#if UNITY_NATIVE


+ 0
- 5
com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs View File

@@ -205,11 +205,6 @@ namespace Svelto.ECS
// <EntityComponentType <groupID <entityID, EntityComponent>>>
internal readonly FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, ITypeSafeDictionary>>
_groupsPerEntity;
#if SVELTO_LEGACY_FILTERS
//The filters stored for each component and group
internal readonly FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>>
_groupFilters;
#endif

readonly EntitiesDB _entitiesDB;



+ 11
- 10
com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs View File

@@ -51,16 +51,7 @@ namespace Svelto.ECS
{
using (var sampler = new PlatformProfiler("remove Entities"))
{
using (sampler.Sample("Remove Entity References"))
{
var count = entitiesRemoved.count;
for (int i = 0; i < count; i++)
{
enginesRoot._entityLocator.RemoveEntityReference(entitiesRemoved[i]);
}
}

using (sampler.Sample("Execute remove callbacks and remove entities"))
using (sampler.Sample("Execute obsolete remove callbacks"))
{
foreach (var entitiesToRemove in removeOperations)
{
@@ -157,6 +148,16 @@ namespace Svelto.ECS
}
}
}
//doing this at the end to be able to use EGID.ToEntityReference inside callbacks
using (sampler.Sample("Remove Entity References"))
{
var count = entitiesRemoved.count;
for (int i = 0; i < count; i++)
{
enginesRoot._entityLocator.RemoveEntityReference(entitiesRemoved[i]);
}
}
}
}



com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs → com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.EntityReferenceMap.cs View File

@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using Svelto.Common;
using Svelto.DataStructures;
using Svelto.DataStructures.Native;
@@ -6,7 +7,7 @@ using Svelto.ECS.Reference;

namespace Svelto.ECS
{
// The EntityLocatorMap provides a bidirectional map to help locate entities without using an EGID which might
// The EntityReferenceMap provides a bidirectional map to help locate entities without using an EGID which might
// change at runtime. The Entity Locator map uses a reusable unique identifier struct called EntityLocator to
// find the last known EGID from last entity submission.
public partial class EnginesRoot

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

@@ -19,6 +19,7 @@ namespace Svelto.ECS.Schedulers

public void Dispose() { }

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public void SubmitEntities()
{
try


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

@@ -77,8 +77,7 @@ namespace Svelto.ECS
}

//efficient way to collect the fields of every EntityComponentType
var setters = FasterList<KeyValuePair<Type, FastInvokeActionCast<T>>>.NoVirt.ToArrayFast(
entityComponentBlazingFastReflection, out var count);
var setters = entityComponentBlazingFastReflection.ToArrayFast(out var count);

for (var i = 0; i < count; i++)
{


+ 24
- 25
com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs View File

@@ -61,19 +61,19 @@ namespace Svelto.ECS
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID, FilterContextID filterContextId)
public EntityFilterCollection GetOrCreatePersistentFilter<T>(int filterID, FilterContextID filterContextId)
where T : struct, _IInternalEntityComponent
{
return ref GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
return GetOrCreatePersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID) where T : struct, _IInternalEntityComponent
public EntityFilterCollection GetOrCreatePersistentFilter<T>(CombinedFilterID filterID) where T : struct, _IInternalEntityComponent
{
var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);

if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true)
return ref _persistentEntityFilters.GetDirectValueByRef(index);
return _persistentEntityFilters.GetDirectValueByRef(index);

_persistentEntityFilters.Add(componentAndFilterID, new EntityFilterCollection(filterID));

@@ -92,7 +92,7 @@ namespace Svelto.ECS
array.Add(lastIndex);
}

return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
return _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
}

/// <summary>
@@ -107,7 +107,7 @@ namespace Svelto.ECS
[Unity.Burst.BurstDiscard] //not burst compatible because of ComponentTypeID<T>.id and GetOrAdd callback;
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection CreatePersistentFilter<T>(CombinedFilterID filterID)
public EntityFilterCollection CreatePersistentFilter<T>(CombinedFilterID filterID)
where T : struct, _IInternalEntityComponent
{
var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);
@@ -123,7 +123,7 @@ namespace Svelto.ECS

_indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(ComponentTypeID<T>.id, _builder).Add(lastIndex);

return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
return _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex);
}

static NativeDynamicArrayCast<int> Builder()
@@ -132,20 +132,20 @@ namespace Svelto.ECS
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetPersistentFilter<T>(int filterID, FilterContextID filterContextId)
public EntityFilterCollection GetPersistentFilter<T>(int filterID, FilterContextID filterContextId)
where T : struct, _IInternalEntityComponent
{
return ref GetPersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
return GetPersistentFilter<T>(new CombinedFilterID(filterID, filterContextId));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetPersistentFilter<T>(CombinedFilterID filterID)
public EntityFilterCollection GetPersistentFilter<T>(CombinedFilterID filterID)
where T : struct, _IInternalEntityComponent
{
var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);

if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true)
return ref _persistentEntityFilters.GetDirectValueByRef(index);
return _persistentEntityFilters.GetDirectValueByRef(index);

throw new ECSException("filter not found");
}
@@ -220,26 +220,26 @@ namespace Svelto.ECS
/// <typeparam name="T"></typeparam>
/// <returns></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetOrCreateTransientFilter<T>(CombinedFilterID combinedFilterID, bool trackFilter = false)
public EntityFilterCollection GetOrCreateTransientFilter<T>(CombinedFilterID combinedFilterID, bool trackFilter = false)
where T : struct, _IInternalEntityComponent
{
var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(combinedFilterID);

if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index))
return ref _transientEntityFilters.GetDirectValueByRef(index);
return _transientEntityFilters.GetDirectValueByRef(index);

return ref InternalCreateTransientFilter<T>(combinedFilterID, componentAndFilterID, trackFilter);
return InternalCreateTransientFilter<T>(combinedFilterID, componentAndFilterID, trackFilter);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetOrCreateTransientFilter<T>(int filterID, FilterContextID filterContextId)
public EntityFilterCollection GetOrCreateTransientFilter<T>(int filterID, FilterContextID filterContextId)
where T : struct, _IInternalEntityComponent
{
return ref GetOrCreateTransientFilter<T>(new CombinedFilterID(filterID, filterContextId));
return GetOrCreateTransientFilter<T>(new CombinedFilterID(filterID, filterContextId));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection CreateTransientFilter<T>(CombinedFilterID combinedFilterID, bool trackFilter = false)
public EntityFilterCollection CreateTransientFilter<T>(CombinedFilterID combinedFilterID, bool trackFilter = false)
where T : struct, _IInternalEntityComponent
{
CombinedFilterComponentID componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(combinedFilterID);
@@ -247,7 +247,7 @@ namespace Svelto.ECS
if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out _))
throw new ECSException($"filter already exists {TypeCache<T>.name}");
#endif
return ref InternalCreateTransientFilter<T>(combinedFilterID, componentAndFilterID, trackFilter);
return InternalCreateTransientFilter<T>(combinedFilterID, componentAndFilterID, trackFilter);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -267,14 +267,14 @@ namespace Svelto.ECS
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref EntityFilterCollection GetTransientFilter<T>(CombinedFilterID filterID)
public EntityFilterCollection GetTransientFilter<T>(CombinedFilterID filterID)
where T : struct, _IInternalEntityComponent
{
var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID<T>(filterID);

if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index))
{
return ref _transientEntityFilters.GetDirectValueByRef(index);
return _transientEntityFilters.GetDirectValueByRef(index);
}

throw new ECSException($"no filters associated with the type {TypeCache<T>.name}");
@@ -326,7 +326,7 @@ namespace Svelto.ECS
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
ref EntityFilterCollection InternalCreateTransientFilter<T>(CombinedFilterID filterID, CombinedFilterComponentID componentAndFilterID,
EntityFilterCollection InternalCreateTransientFilter<T>(CombinedFilterID filterID, CombinedFilterComponentID componentAndFilterID,
bool trackFilter)
where T : struct, _IInternalEntityComponent
{
@@ -336,12 +336,11 @@ namespace Svelto.ECS

if (trackFilter)
{
var typeRef = ComponentTypeID<T>.id;
var lastIndex = _transientEntityFilters.count - 1;
_indicesOfTransientFiltersUsedByThisComponent.GetOrAdd(ComponentTypeID<T>.id, _builder).Add(lastIndex);
}

return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1));
return _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1));
}

public struct EntityFilterCollectionsEnumerator
@@ -371,10 +370,10 @@ namespace Svelto.ECS
return false;
}

public ref EntityFilterCollection Current
public EntityFilterCollection Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
get => _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1);
}

readonly NativeDynamicArrayCast<int> _getDirectValueByRef;


+ 0
- 213
com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs View File

@@ -1,213 +0,0 @@
#if SVELTO_LEGACY_FILTERS
using DBC.ECS;
using Svelto.DataStructures;
using Svelto.DataStructures.Native;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
/// <summary>
/// This feature must be eventually tied to the new ExclusiveGroup that won't allow the use of
/// custom EntitiesID
/// The filters could be updated when entities buffer changes during the submission, while now this process
/// is completely manual.
/// Making this working properly is not in my priorities right now, as I will need to add the new group type
/// AND optimize the submission process to be able to add more overhead
/// </summary>
public partial class EntitiesDB
{
FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>> _filters =>
_enginesRoot._groupFilters;

public LegacyFilters GetLegacyFilters()
{
return new LegacyFilters(_filters);
}

public readonly struct LegacyFilters
{
public LegacyFilters(
FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>>
filtersLegacy)
{
_filtersLegacy = filtersLegacy;
}

public ref LegacyFilterGroup CreateOrGetFilterForGroup<T>(int filterID, ExclusiveGroupStruct groupID)
where T : struct, _IInternalEntityComponent
{
var refWrapper = ComponentTypeID<T>.id;

return ref CreateOrGetFilterForGroup(filterID, groupID, refWrapper);
}

public bool HasFiltersForGroup<T>(ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary) == false)
return false;

return fasterDictionary.ContainsKey(groupID);
}

public bool HasFilterForGroup<T>(int filterID, ExclusiveGroupStruct groupID)
where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary) == false)
return false;

if (fasterDictionary.TryGetValue(groupID, out var result))
return result.HasFilter(filterID);

return false;
}

public ref LegacyGroupFilters CreateOrGetFiltersForGroup<T>(ExclusiveGroupStruct groupID)
where T : struct, _IInternalEntityComponent
{
var fasterDictionary = _filtersLegacy.GetOrAdd(ComponentTypeID<T>.id,
() => new FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>());

return ref fasterDictionary.GetOrAdd(groupID,
() => new LegacyGroupFilters(new SharedSveltoDictionaryNative<int, LegacyFilterGroup>(0), groupID));
}

public ref LegacyGroupFilters GetFiltersForGroup<T>(ExclusiveGroupStruct groupID)
where T : struct, _IInternalEntityComponent
{
#if DEBUG && !PROFILE_SVELTO
if (_filtersLegacy.ContainsKey(ComponentTypeID<T>.id) == false)
throw new ECSException($"trying to fetch not existing filters, type {typeof(T)}");
if (_filtersLegacy[ComponentTypeID<T>.id].ContainsKey(groupID) == false)
throw new ECSException(
$"trying to fetch not existing filters, type {typeof(T)} group {groupID.ToName()}");
#endif

return ref _filtersLegacy[ComponentTypeID<T>.id].GetValueByRef(groupID);
}

public ref LegacyFilterGroup GetFilterForGroup<T>(int filterId, ExclusiveGroupStruct groupID)
where T : struct, _IInternalEntityComponent
{
#if DEBUG && !PROFILE_SVELTO
if (_filtersLegacy.ContainsKey(ComponentTypeID<T>.id) == false)
throw new ECSException($"trying to fetch not existing filters, type {typeof(T)}");
if (_filtersLegacy[ComponentTypeID<T>.id].ContainsKey(groupID) == false)
throw new ECSException(
$"trying to fetch not existing filters, type {typeof(T)} group {groupID.ToName()}");
#endif
return ref _filtersLegacy[ComponentTypeID<T>.id][groupID].GetFilter(filterId);
}

public bool TryGetFilterForGroup<T>(int filterId, ExclusiveGroupStruct groupID,
out LegacyFilterGroup groupLegacyFilter) where T : struct, _IInternalEntityComponent
{
groupLegacyFilter = default;

if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary) == false)
return false;

if (fasterDictionary.TryGetValue(groupID, out var groupFilters) == false)
return false;

if (groupFilters.TryGetFilter(filterId, out groupLegacyFilter) == false)
return false;

return true;
}

public bool TryGetFiltersForGroup<T>(ExclusiveGroupStruct groupID,
out LegacyGroupFilters legacyGroupFilters) where T : struct, _IInternalEntityComponent
{
legacyGroupFilters = default;

if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary) == false)
return false;

return fasterDictionary.TryGetValue(groupID, out legacyGroupFilters);
}

public void ClearFilter<T>(int filterID, ExclusiveGroupStruct exclusiveGroupStruct)
where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary))
{
Check.Require(fasterDictionary.ContainsKey(exclusiveGroupStruct),
$"trying to clear filter not present in group {exclusiveGroupStruct}");

fasterDictionary[exclusiveGroupStruct].ClearFilter(filterID);
}
}

public void ClearFilters<T>(int filterID) where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary))
foreach (var filtersPerGroup in fasterDictionary)
filtersPerGroup.value.ClearFilter(filterID);
}

public void DisposeFilters<T>(ExclusiveGroupStruct exclusiveGroupStruct) where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary))
{
fasterDictionary[exclusiveGroupStruct].DisposeFilters();
fasterDictionary.Remove(exclusiveGroupStruct);
}
}

public void DisposeFilters<T>() where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary))
foreach (var filtersPerGroup in fasterDictionary)
filtersPerGroup.value.DisposeFilters();

_filtersLegacy.Remove(ComponentTypeID<T>.id);
}

public void DisposeFilterForGroup<T>(int resetFilterID, ExclusiveGroupStruct group) where T : struct, _IInternalEntityComponent
{
if (_filtersLegacy.TryGetValue(ComponentTypeID<T>.id, out var fasterDictionary))
fasterDictionary[@group].DisposeFilter(resetFilterID);
}

public bool TryRemoveEntityFromFilter<T>(int filtersID, EGID egid) where T : struct, _IInternalEntityComponent
{
if (TryGetFilterForGroup<T>(filtersID, egid.groupID, out var filter))
return filter.TryRemove(egid.entityID);

return false;
}

public void RemoveEntityFromFilter<T>(int filtersID, EGID egid) where T : struct, _IInternalEntityComponent
{
ref var filter = ref GetFilterForGroup<T>(filtersID, egid.groupID);

filter.Remove(egid.entityID);
}

public bool AddEntityToFilter<N>(int filtersID, EGID egid, N mapper) where N : IEGIDMapper
{
ref var filter = ref CreateOrGetFilterForGroup(filtersID, egid.groupID, ComponentTypeMap.FetchID(mapper.entityType));

return filter.Add(egid.entityID, mapper);
}

internal ref LegacyFilterGroup CreateOrGetFilterForGroup(int filterID, ExclusiveGroupStruct groupID,
ComponentID refWrapper)
{
var fasterDictionary = _filtersLegacy.GetOrAdd(refWrapper,
() => new FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>());

var filters = fasterDictionary.GetOrAdd(groupID,
(ref ExclusiveGroupStruct gid) =>
new LegacyGroupFilters(new SharedSveltoDictionaryNative<int, LegacyFilterGroup>(0), gid),
ref groupID);

return ref filters.CreateOrGetFilter(filterID);
}

readonly FasterDictionary<ComponentID, FasterDictionary<ExclusiveGroupStruct, LegacyGroupFilters>>
_filtersLegacy;
}
}
}
#endif

+ 0
- 214
com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilterGroup.cs View File

@@ -1,214 +0,0 @@
#if SVELTO_LEGACY_FILTERS
using System.Runtime.CompilerServices;
using Svelto.Common;
using Svelto.DataStructures.Native;
using Svelto.DataStructures;

namespace Svelto.ECS
{
/// <summary>
/// In order to complete this feature, I need to be able to detect if the entity pointed by the filter
/// is still present.
/// This feature should work only with groups where entityID cannot be chosen by the user, so that
/// a real sparse set can be used like explained at: https://skypjack.github.io/2020-08-02-ecs-baf-part-9/
/// For a sparse set to work, the index in the sparse list must coincide with the ID of the entity
/// so that from the dense list (that holds unordered entity index), I can get to the sparse list index
/// sparse[0] = position in the dense list of the entity 0
/// dense[index] = entity ID but also index in the sparse list of the same entity ID
/// </summary>
public struct LegacyFilterGroup
{
internal LegacyFilterGroup(ExclusiveGroupStruct exclusiveGroupStruct, int ID)
{
_denseListOfIndicesToEntityComponentArray =
new NativeDynamicArrayCast<uint>(NativeDynamicArray.Alloc<uint>(Allocator.Persistent));
//from the index, find the entityID
_reverseEIDs = new NativeDynamicArrayCast<uint>(NativeDynamicArray.Alloc<uint>(Allocator.Persistent));
//from the entityID, find the index
_indexOfEntityInDenseList = new SharedSveltoDictionaryNative<uint, uint>(0);
_exclusiveGroupStruct = exclusiveGroupStruct;
_ID = ID;
}

/// <summary>
/// Todo: how to detect if the indices are still pointing to valid entities?
/// </summary>
public LegacyFilteredIndices filteredIndices => new LegacyFilteredIndices(_denseListOfIndicesToEntityComponentArray);

public bool Add<N>(uint entityID, N mapper) where N:IEGIDMapper
{
#if DEBUG && !PROFILE_SVELTO
if (mapper.Exists(entityID) == false)
throw new ECSException(
$"trying adding an entity {entityID} to filter {mapper.entityType} - {_ID} with group {mapper.groupID}, but entity is not found! ");
#endif

return InternalAdd(entityID, mapper.GetIndex(entityID));
}

public void Remove(uint entityID)
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"invalid Filter");
if (_indexOfEntityInDenseList.ContainsKey(entityID) == false)
throw new ECSException(
$"trying to remove a not existing entity {new EGID(entityID, _exclusiveGroupStruct)} from filter");
#endif
InternalRemove(entityID);
}

public bool Exists(uint entityID)
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"invalid Filter");
#endif
return _indexOfEntityInDenseList.ContainsKey(entityID);
}

public bool TryRemove(uint entityID)
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"invalid Filter");
#endif
if (_indexOfEntityInDenseList.ContainsKey(entityID) == false)
return false;

InternalRemove(entityID);

return true;
}

/// <summary>
/// Filters were initially designed to be used for tagging operations within submissions of entities.
/// They were designed as a fast tagging mechanism to be used within the submission frame. However I then
/// extended it, but the extension includes a drawback:
/// If filters are not in sync with the operations of remove and swap, filters may end up pointing to
/// invalid indices. I need to put in place a way to be able to recognised an invalid filter.
/// This is currently a disadvantage of the filters. The filters are not updated by the framework
/// but they must be updated by the user.
/// When to use this method: Add and Removed should be used to add and remove entities in the filters. This is
/// valid as long as no structural changes happen in the group of entities involved.
/// IF structural changes happen, the indices stored in the filters won't be valid anymore as they will possibly
/// point to entities that were not the original ones. On structural changes
/// (specifically entities swapped or removed)
/// the filters must then be rebuilt. It would be too slow to add this in the standard flow of Svelto in
/// the current state, so calling this method is a user responsibility.
/// </summary>
public void RebuildIndicesOnStructuralChange<N>(N mapper) where N:IEGIDMapper
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"invalid Filter");
#endif
_denseListOfIndicesToEntityComponentArray.Clear();
_reverseEIDs.Clear();

foreach (var value in _indexOfEntityInDenseList)
if (mapper.FindIndex(value.key, out var indexOfEntityInBufferComponent) == true)
{
_denseListOfIndicesToEntityComponentArray.Add(indexOfEntityInBufferComponent);
var lastIndex = (uint) (_denseListOfIndicesToEntityComponentArray.Count() - 1);
_reverseEIDs.AddAt(lastIndex) = value.key;
}

_indexOfEntityInDenseList.Clear();

for (uint i = 0; i < _reverseEIDs.Count(); i++)
_indexOfEntityInDenseList[_reverseEIDs[i]] = i;
}

public void Clear()
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"invalid Filter");
#endif
_indexOfEntityInDenseList.Clear();
_reverseEIDs.Clear();
_denseListOfIndicesToEntityComponentArray.Clear();
}

internal void Dispose()
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"invalid Filter");
#endif
_denseListOfIndicesToEntityComponentArray.Dispose();
_indexOfEntityInDenseList.Dispose();
_reverseEIDs.Dispose();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal bool InternalAdd(uint entityID, uint indexOfEntityInBufferComponent)
{
#if DEBUG && !PROFILE_SVELTO
if (_denseListOfIndicesToEntityComponentArray.isValid == false)
throw new ECSException($"using an invalid filter");
#endif
if (_indexOfEntityInDenseList.ContainsKey(entityID) == true)
return false;

//add the index in the list of filtered indices
_denseListOfIndicesToEntityComponentArray.Add(indexOfEntityInBufferComponent);

//inverse map: need to get the entityID from the index. This wouldn't be needed with a real sparseset
var lastIndex = (uint) (_denseListOfIndicesToEntityComponentArray.Count() - 1);
_reverseEIDs.AddAt(lastIndex) = entityID;

//remember the entities indices. This is needed to remove entities from the filter
_indexOfEntityInDenseList.Add(entityID, lastIndex);

return true;
}

void InternalRemove(uint entityID)
{
var count = (uint) _denseListOfIndicesToEntityComponentArray.Count();
if (count > 0)
{
if (count > 1)
{
//get the index in the filter array of the entity to delete
var indexInDenseListFromEGID = _indexOfEntityInDenseList[entityID];
//get the entityID of the last entity in the filter array
uint entityIDToMove = _reverseEIDs[count - 1];

//the last index of the last entity is updated to the slot of the deleted entity
if (entityIDToMove != entityID)
{
_indexOfEntityInDenseList[entityIDToMove] = indexInDenseListFromEGID;
//the reverseEGID is updated accordingly
_reverseEIDs[indexInDenseListFromEGID] = entityIDToMove;
}

//
_reverseEIDs.UnorderedRemoveAt(count - 1);

//finally remove the deleted entity from the filters array
_denseListOfIndicesToEntityComponentArray.UnorderedRemoveAt(indexInDenseListFromEGID);

//remove the entity to delete from the tracked Entity
_indexOfEntityInDenseList.Remove(entityID);
}
else
{
_indexOfEntityInDenseList.Clear();
_reverseEIDs.Clear();
_denseListOfIndicesToEntityComponentArray.Clear();
}
}
}

NativeDynamicArrayCast<uint> _denseListOfIndicesToEntityComponentArray;
NativeDynamicArrayCast<uint> _reverseEIDs; //forced to use this because it's not a real sparse set
SharedSveltoDictionaryNative<uint, uint> _indexOfEntityInDenseList;

internal readonly ExclusiveGroupStruct _exclusiveGroupStruct;
internal readonly int _ID;
}
}
#endif

+ 0
- 40
com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilteredIndices.cs View File

@@ -1,40 +0,0 @@
#if SVELTO_LEGACY_FILTERS
using System.Runtime.CompilerServices;
using Svelto.DataStructures;

namespace Svelto.ECS
{
public readonly struct LegacyFilteredIndices
{
public LegacyFilteredIndices(NativeDynamicArrayCast<uint> denseListOfIndicesToEntityComponentArray)
{
_denseListOfIndicesToEntityComponentArray = denseListOfIndicesToEntityComponentArray;
_count = _denseListOfIndicesToEntityComponentArray.count;
}

public int count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _count; }
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint Get(uint index) => _denseListOfIndicesToEntityComponentArray[index];

public uint this[uint index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _denseListOfIndicesToEntityComponentArray[index];
}

public uint this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _denseListOfIndicesToEntityComponentArray[index];
}

readonly NativeDynamicArrayCast<uint> _denseListOfIndicesToEntityComponentArray;
readonly int _count;
}
}
#endif

+ 0
- 106
com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyGroupFilters.cs View File

@@ -1,106 +0,0 @@
#if SVELTO_LEGACY_FILTERS
using Svelto.DataStructures;
using Svelto.DataStructures.Native;

namespace Svelto.ECS
{
public struct LegacyGroupFilters
{
internal LegacyGroupFilters(SharedSveltoDictionaryNative<int, LegacyFilterGroup> legacyFilters, ExclusiveGroupStruct group)
{
this._legacyFilters = legacyFilters;
_group = @group;
}

public ref LegacyFilterGroup GetFilter(int filterIndex)
{
#if DEBUG && !PROFILE_SVELTO
if (_legacyFilters.isValid == false)
throw new ECSException($"trying to fetch not existing filters {filterIndex} group {_group.ToName()}");
if (_legacyFilters.ContainsKey(filterIndex) == false)
throw new ECSException($"trying to fetch not existing filters {filterIndex} group {_group.ToName()}");
#endif
return ref _legacyFilters.GetValueByRef(filterIndex);
}

public bool HasFilter(int filterIndex) { return _legacyFilters.ContainsKey(filterIndex); }

public void ClearFilter(int filterIndex)
{
if (_legacyFilters.TryFindIndex(filterIndex, out var index))
_legacyFilters.GetValues(out _)[index].Clear();
}

public void ClearFilters()
{
foreach (var filter in _legacyFilters)
filter.value.Clear();
}

public bool TryGetFilter(int filterIndex, out LegacyFilterGroup legacyFilter)
{
return _legacyFilters.TryGetValue(filterIndex, out legacyFilter);
}

public SveltoDictionaryKeyValueEnumerator<int, LegacyFilterGroup, NativeStrategy<SveltoDictionaryNode<int>>, NativeStrategy<LegacyFilterGroup>
, NativeStrategy<int>> GetEnumerator()
{
return _legacyFilters.GetEnumerator();
}
//Note the following methods are internal because I was pondering the idea to be able to return
//the list of LegacyGroupFilters linked to a specific filter ID. However this would mean to be able to
//maintain a revers map which at this moment seems too much and also would need the following
//method to be for ever internal (at this point in time I am not sure it's a good idea)
internal void DisposeFilter(int filterIndex)
{
if (_legacyFilters.TryFindIndex(filterIndex, out var index))
{
ref var filterGroup = ref _legacyFilters.GetValues(out _)[index];
filterGroup.Dispose();

_legacyFilters.Remove(filterIndex);
}
}

internal void DisposeFilters()
{
//must release the native buffers!
foreach (var filter in _legacyFilters)
filter.value.Dispose();

_legacyFilters.Clear();
}

internal ref LegacyFilterGroup CreateOrGetFilter(int filterID)
{
if (_legacyFilters.TryFindIndex(filterID, out var index) == false)
{
var orGetFilterForGroup = new LegacyFilterGroup(_group, filterID);

_legacyFilters[filterID] = orGetFilterForGroup;

return ref _legacyFilters.GetValueByRef(filterID);
}

return ref _legacyFilters.GetValues(out _)[index];
}

internal void Dispose()
{
foreach (var filter in _legacyFilters)
{
filter.value.Dispose();
}

_legacyFilters.Dispose();
}

readonly ExclusiveGroupStruct _group;

//filterID, filter
SharedSveltoDictionaryNative<int, LegacyFilterGroup> _legacyFilters;
}
}
#endif

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

@@ -141,8 +141,8 @@ namespace Svelto.ECS

var nameHash = DesignatedHash.Hash(Encoding.ASCII.GetBytes(name));

if (_groupsByHash.ContainsKey(nameHash))
throw new ECSException($"Group hash collision with {name} and {_groupsByHash[nameHash]}");
if (_groupsByHash.TryGetValue(nameHash, out var value))
throw new ECSException($"Group hash collision with {name} and {value}");

Console.LogDebug($"Registering group {name} with ID {exclusiveGroupStruct.id} to {nameHash}");



+ 6
- 4
com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs View File

@@ -433,10 +433,12 @@ namespace Svelto.ECS.Internal
//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
if (index != fromDictionary.count)
var fromDictionaryCount = fromDictionary.count;
var fromDictionaryUnsafeKeys = fromDictionary.unsafeKeys;
if (index != fromDictionaryCount)
{
fromDictionary.unsafeValues[(uint)fromDictionary.count] = value;
fromDictionary.unsafeKeys[(uint)fromDictionary.count] = new SveltoDictionaryNode<uint>(id, 0);
fromDictionary.unsafeValues[(uint)fromDictionaryCount] = value;
fromDictionaryUnsafeKeys[(uint)fromDictionaryCount] = new SveltoDictionaryNode<uint>(id, 0);
}

//when a component is removed from a component array, a remove swap back happens. This means
@@ -445,7 +447,7 @@ namespace Svelto.ECS.Internal
//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.
entityIDsAffectedByRemoveAtSwapBack[fromDictionary.unsafeKeys[index].key] = index;
entityIDsAffectedByRemoveAtSwapBack[fromDictionaryUnsafeKeys[index].key] = index;
}
#if DEBUG && !PROFILE_SVELTO
}


+ 0
- 18
com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/EntitiesDBFiltersExtension.cs View File

@@ -1,18 +0,0 @@
#if SVELTO_LEGACY_FILTERS
using Svelto.DataStructures;
using Svelto.ECS.Native;

namespace Svelto.ECS
{
public static class EntitiesDBFiltersExtension
{
public static bool AddEntityToFilter<N>(this EntitiesDB.LegacyFilters legacyFilters, int filtersID, EGID egid, N mapper) where N : IEGIDMultiMapper
{
ref var filter =
ref legacyFilters.CreateOrGetFilterForGroup(filtersID, egid.groupID, ComponentTypeMap.FetchID(mapper.entityType));

return filter.Add(egid.entityID, mapper);
}
}
}
#endif

+ 0
- 21
com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/FilterGroupExtensions.cs View File

@@ -1,21 +0,0 @@
#if SVELTO_LEGACY_FILTERS
using Svelto.ECS.Native;

namespace Svelto.ECS
{
public static class FilterGroupExtensions
{
public static bool Add<N>(this LegacyFilterGroup legacyFilter, uint entityID, N mapper) where N : IEGIDMultiMapper
{
#if DEBUG && !PROFILE_SVELTO
if (mapper.Exists(legacyFilter._exclusiveGroupStruct, entityID) == false)
throw new ECSException(
$"trying adding an entity {entityID} to filter {mapper.entityType} - {legacyFilter._ID} with group {legacyFilter._exclusiveGroupStruct}, but entity is not found! ");
#endif

return legacyFilter.InternalAdd(entityID, mapper.GetIndex(new EGID(entityID, legacyFilter._exclusiveGroupStruct)));
}

}
}
#endif

+ 5
- 3
com.sebaslab.svelto.ecs/Serialization/DefaultVersioningFactory.cs View File

@@ -6,15 +6,17 @@ namespace Svelto.ECS.Serialization
#if ENABLE_IL2CPP
[UnityEngine.Scripting.Preserve]
#endif
public class DefaultVersioningFactory<T> : IDeserializationFactory where T : IEntityDescriptor, new()
public class DefaultVersioningFactory<T> : IDeserializationFactory where T : ISerializableEntityDescriptor, new()
{
public EntityInitializer BuildDeserializedEntity(EGID egid, ISerializationData serializationData,
ISerializableEntityDescriptor entityDescriptor, int serializationType,
IEntitySerialization entitySerialization, IEntityFactory factory, bool enginesRootIsDeserializationOnly)
{
var newEntityDescriptor = EntityDescriptorTemplate<T>.realDescriptor as ISerializableEntityDescriptor;
var entityDescriptorEntitiesToSerialize = enginesRootIsDeserializationOnly
? entityDescriptor.componentsToSerialize
: entityDescriptor.componentsToBuild;
? newEntityDescriptor.componentsToSerialize
: newEntityDescriptor.componentsToBuild;

var initializer = (factory as IEntitySerializationFactory).BuildEntity(egid, entityDescriptorEntitiesToSerialize, TypeCache<T>.type);



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

@@ -25,7 +25,8 @@ namespace Svelto.ECS
new SerializableEntityHeader(descriptorHash, egid, (byte)entityComponentsToSerialise.Length);
header.Copy(serializationData);

for (int index = 0; index < entityComponentsToSerialise.Length; index++)
var length = entityComponentsToSerialise.Length;
for (int index = 0; index < length; index++)
{
var entityBuilder = entityComponentsToSerialise[index];



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

@@ -16,6 +16,8 @@ namespace Svelto.ECS.Serialization
where T : unmanaged, IEntityComponent
{
public static uint SIZE => (uint)MemoryUtilities.SizeOf<T>();

protected SerializableComponentBuilder() { }
public void Serialize(uint entityID, ITypeSafeDictionary dictionary, ISerializationData serializationData
, int serializationType)


+ 1
- 1
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.5.1"
"com.sebaslab.svelto.common": "3.5.0"
},
"keywords": [
"svelto",


Loading…
Cancel
Save