From 5e316edb62bb9ae3ee2de3a7be7e58b5b334ca84 Mon Sep 17 00:00:00 2001 From: Sebastiano Mandala Date: Fri, 31 Mar 2023 13:05:22 +0100 Subject: [PATCH 1/2] move away from RefWrapperType to the new ComponentID key type. The former was GUID based the latter is counter based added warmup of the entity descriptor to reduce the overhead when an entity descriptor is used for the first time at run time added the option to iterate transient filters per component like it was already possible for persistent filters. Transient filters are tracked optionally. fixed huge bug in the filter enumerator, truly surprised this never showed up --- com.sebaslab.svelto.common | 2 +- .../Core/ComponentBuilder.CheckFields.cs | 9 + .../Core/ComponentBuilder.cs | 91 +++++- ...EnginesRoot.DoubleBufferedEntitiesToAdd.cs | 26 +- .../Core/EnginesRoot.Engines.cs | 46 +-- .../Core/EnginesRoot.Entities.cs | 31 +- .../Core/EnginesRoot.GenericEntityFactory.cs | 6 +- .../EnginesRoot.GenericEntityFunctions.cs | 2 +- .../Core/EnginesRoot.Submission.cs | 45 ++- com.sebaslab.svelto.ecs/Core/EntitiesDB.cs | 24 +- .../Core/EntitiesOperations.cs | 36 +-- .../Core/EntityCollection.cs | 4 +- .../DynamicEntityDescriptor.cs | 4 +- .../EntityDescriptor/IEntityDescriptor.cs | 15 + com.sebaslab.svelto.ecs/Core/EntityFactory.cs | 15 +- .../Core/EntityInfoView.cs | 1 - .../Core/EntityInitializer.cs | 14 +- .../EntityReference/EnginesRoot.LocatorMap.cs | 3 +- .../Core/Filters/CombinedFilterID.cs | 95 +++++- .../Core/Filters/EnginesRoot.Filters.cs | 32 +- .../Core/Filters/EntitiesDB.Filters.cs | 295 ++++++++++-------- .../Core/Filters/FilterContextID.cs | 4 +- .../Legacy/EntitiesDB.LegacyFilters.cs | 42 +-- .../Core/Groups/EntitiesDB.FindGroups.cs | 40 +-- .../Core/Groups/EntityDescriptorsWarmup.cs | 50 +++ .../Core/IComponentBuilder.cs | 1 + .../Core/Streams/EntitiesStreams.cs | 22 +- .../DataStructures/ITypeSafeDictionary.cs | 16 +- .../ManagedTypeSafeDictionary.cs | 20 +- .../TypeSafeDictionaryMethods.cs | 32 +- .../UnmanagedTypeSafeDictionary.cs | 20 +- .../Native/EnginesRoot.NativeOperation.cs | 4 +- .../Native/NativeComponentFiller.cs} | 20 +- .../Extensions/Native/NativeEntityFactory.cs | 3 +- .../Native/NativeEntityInitializer.cs | 2 +- .../Extensions/Svelto/AllGroupsEnumerable.cs | 2 +- .../EnginesRoot.GenericEntitySerialization.cs | 5 +- .../Serialization/IEntitySerialization.cs | 1 - .../SerializableEntityDescriptor.cs | 9 +- com.sebaslab.svelto.ecs/Svelto.ECS.csproj | 6 +- com.sebaslab.svelto.ecs/package.json | 4 +- com.sebaslab.svelto.ecs/version.json | 2 +- 42 files changed, 677 insertions(+), 424 deletions(-) create mode 100644 com.sebaslab.svelto.ecs/Core/Groups/EntityDescriptorsWarmup.cs rename com.sebaslab.svelto.ecs/{Core/GlobalTypeID.cs => Extensions/Native/NativeComponentFiller.cs} (66%) diff --git a/com.sebaslab.svelto.common b/com.sebaslab.svelto.common index 13c4f38..9a74e5c 160000 --- a/com.sebaslab.svelto.common +++ b/com.sebaslab.svelto.common @@ -1 +1 @@ -Subproject commit 13c4f38c44fac08914d3ed26723e6134a53c30c0 +Subproject commit 9a74e5c70681d4f2f5156b48cdd578dfcf6cfc4e diff --git a/com.sebaslab.svelto.ecs/Core/ComponentBuilder.CheckFields.cs b/com.sebaslab.svelto.ecs/Core/ComponentBuilder.CheckFields.cs index 57faef5..9e76063 100644 --- a/com.sebaslab.svelto.ecs/Core/ComponentBuilder.CheckFields.cs +++ b/com.sebaslab.svelto.ecs/Core/ComponentBuilder.CheckFields.cs @@ -4,6 +4,7 @@ using System.Diagnostics; #endif using System; using System.Reflection; +using System.Runtime.CompilerServices; using Svelto.ECS.Hybrid; namespace Svelto.ECS @@ -153,5 +154,13 @@ namespace Svelto.ECS static readonly Type STRINGBUILDERTYPE = typeof(System.Text.StringBuilder); internal static readonly Type ENTITY_INFO_COMPONENT = typeof(EntityInfoComponent); + public static ComponentID ENTITY_INFO_COMPONENT_ID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ComponentTypeID.id; + } + } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs b/com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs index 3b38b38..2ccafdc 100644 --- a/com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs +++ b/com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; using DBC.ECS; using Svelto.Common; @@ -28,14 +30,42 @@ namespace Svelto.ECS { public static int counter; } - - public class ComponentID where T : struct, _IInternalEntityComponent + + static public class ComponentTypeMap + { + static readonly FasterDictionary, ComponentID> _componentTypeMap = new FasterDictionary, ComponentID>(); + static readonly FasterDictionary _reverseComponentTypeMap = new FasterDictionary(); + + public static void Add(Type type, ComponentID idData) + { + _componentTypeMap.Add(type, idData); + _reverseComponentTypeMap.Add(idData, type); + } + + public static ComponentID FetchID(Type type) + { + return _componentTypeMap[type]; + } + + public static Type FetchType(ComponentID id) + { + return _reverseComponentTypeMap[id]; + } + } + + public class ComponentTypeID where T : struct, _IInternalEntityComponent { - public static readonly SharedStaticWrapper> id; + static readonly SharedStaticWrapper> _id; + + public static ComponentID id + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _id.Data; + } //todo: any reason to not do this? If I don't, I cannot Create filters in ready functions and //I have to remove the CreateFilter method - static ComponentID() + static ComponentTypeID() { Init(); } @@ -46,10 +76,52 @@ namespace Svelto.ECS #endif static void Init() { - id.Data = Interlocked.Increment(ref BurstCompatibleCounter.counter); - - Check.Ensure(id.Data < ushort.MaxValue, "too many types registered, HOW :)"); + _id.Data = Interlocked.Increment(ref BurstCompatibleCounter.counter); + ComponentTypeMap.Add(typeof(T), id); + } + } + + sealed class ComponentIDDebugProxy + { + public ComponentIDDebugProxy(ComponentID id) + { + this._id = id; + } + + public Type type => ComponentTypeMap.FetchType(_id); + + readonly ComponentID _id; + } + + [DebuggerTypeProxy(typeof(ComponentIDDebugProxy))] + public struct ComponentID: IEquatable + { + public static implicit operator int(ComponentID id) + { + return id._id; + } + + public static implicit operator uint(ComponentID id) + { + return (uint)id._id; + } + + public static implicit operator ComponentID(int id) + { + return new ComponentID() {_id = id}; + } + + public bool Equals(ComponentID other) + { + return _id == other._id; + } + + public override int GetHashCode() + { + return _id; } + + int _id; } public class ComponentBuilder : IComponentBuilder where T : struct, _IInternalEntityComponent @@ -57,7 +129,6 @@ namespace Svelto.ECS internal static readonly Type ENTITY_COMPONENT_TYPE; internal static readonly bool IS_ENTITY_VIEW_COMPONENT; - static readonly T DEFAULT_IT; static readonly string ENTITY_COMPONENT_NAME; static readonly bool IS_UNMANAGED; #if SLOW_SVELTO_SUBMISSION @@ -68,7 +139,6 @@ namespace Svelto.ECS static ComponentBuilder() { ENTITY_COMPONENT_TYPE = typeof(T); - DEFAULT_IT = default; IS_ENTITY_VIEW_COMPONENT = typeof(IEntityViewComponent).IsAssignableFrom(ENTITY_COMPONENT_TYPE); #if SLOW_SVELTO_SUBMISSION HAS_EGID = typeof(INeedEGID).IsAssignableFrom(ENTITY_COMPONENT_TYPE); @@ -100,7 +170,7 @@ namespace Svelto.ECS public ComponentBuilder() { - _initializer = DEFAULT_IT; + _initializer = default; } public ComponentBuilder(in T initializer) : this() @@ -109,6 +179,7 @@ namespace Svelto.ECS } public bool isUnmanaged => IS_UNMANAGED; + public ComponentID getComponentID => ComponentTypeID.id; static readonly ThreadLocal _localCache = new ThreadLocal(() => new EntityViewComponentCache()); diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs index 0acf4fc..c3495b6 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs @@ -1,4 +1,5 @@ -using Svelto.DataStructures; +using System; +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS @@ -18,9 +19,9 @@ namespace Svelto.ECS var entitiesCreatedPerGroupA = new FasterDictionary(); var entitiesCreatedPerGroupB = new FasterDictionary(); var entityComponentsToAddBufferA = - new FasterDictionary>(); + new FasterDictionary>(); var entityComponentsToAddBufferB = - new FasterDictionary>(); + new FasterDictionary>(); _currentNumberEntitiesCreatedPerGroup = entitiesCreatedPerGroupA; _lastNumberEntitiesCreatedPerGroup = entitiesCreatedPerGroupB; @@ -149,17 +150,14 @@ namespace Svelto.ECS (ExclusiveGroupStruct groupID, uint numberOfEntities, IComponentBuilder[] entityComponentsToBuild) { void PreallocateDictionaries - (FasterDictionary> dic) + (FasterDictionary> dic) { var group = dic.GetOrAdd( - groupID, () => new FasterDictionary()); + groupID, () => new FasterDictionary()); foreach (var componentBuilder in entityComponentsToBuild) { - var entityComponentType = componentBuilder.GetEntityComponentType(); - var safeDictionary = group.GetOrAdd(new RefWrapperType(entityComponentType) - , () => componentBuilder - .CreateDictionary(numberOfEntities)); + var safeDictionary = group.GetOrAdd(componentBuilder.getComponentID, () => componentBuilder.CreateDictionary(numberOfEntities)); componentBuilder.Preallocate(safeDictionary, numberOfEntities); } } @@ -191,10 +189,10 @@ namespace Svelto.ECS //Before I tried for the third time to use a SparseSet instead of FasterDictionary, remember that //while group indices are sequential, they may not be used in a sequential order. Sparseset needs //entities to be created sequentially (the index cannot be managed externally) - internal FasterDictionary> + internal FasterDictionary> currentComponentsToAddPerGroup; - FasterDictionary> + FasterDictionary> lastComponentsToAddPerGroup; /// @@ -212,7 +210,7 @@ namespace Svelto.ECS struct OtherComponentsToAddPerGroupEnumerator { public OtherComponentsToAddPerGroupEnumerator - (FasterDictionary> + (FasterDictionary> lastComponentsToAddPerGroup , FasterDictionary otherNumberEntitiesCreatedPerGroup) { @@ -246,7 +244,7 @@ namespace Svelto.ECS public GroupInfo Current { get; private set; } //cannot be read only as they will be modified by MoveNext - readonly FasterDictionary> + readonly FasterDictionary> _lastComponentsToAddPerGroup; SveltoDictionaryKeyValueEnumerator components; + public FasterDictionary components; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs index a25c40c..18e7fc3 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs @@ -16,6 +16,7 @@ namespace Svelto.ECS { static EnginesRoot() { + EntityDescriptorsWarmup.Init(); GroupHashMap.Init(); //SharedDictonary.Init(); SerializationDescriptorMap.Init(); @@ -50,19 +51,19 @@ namespace Svelto.ECS _nativeAddOperationQueue = new AtomicNativeBags(Allocator.Persistent); #endif _serializationDescriptorMap = new SerializationDescriptorMap(); - _reactiveEnginesAdd = new FasterDictionary>>(); + _reactiveEnginesAdd = new FasterDictionary>>(); _reactiveEnginesAddEx = - new FasterDictionary>>(); + new FasterDictionary>>(); _reactiveEnginesRemove = - new FasterDictionary>>(); + new FasterDictionary>>(); _reactiveEnginesRemoveEx = - new FasterDictionary>>(); + new FasterDictionary>>(); _reactiveEnginesSwap = - new FasterDictionary>>(); + new FasterDictionary>>(); _reactiveEnginesSwapEx = - new FasterDictionary>>(); + new FasterDictionary>>(); _reactiveEnginesDispose = - new FasterDictionary>>(); + new FasterDictionary>>(); _reactiveEnginesSubmission = new FasterList(); _reactiveEnginesSubmissionStarted = new FasterList(); @@ -71,14 +72,14 @@ namespace Svelto.ECS _disposableEngines = new FasterList(); _groupEntityComponentsDB = - new FasterDictionary>(); + new FasterDictionary>(); _groupsPerEntity = - new FasterDictionary>(); + new FasterDictionary>(); _groupedEntityToAdd = new DoubleBufferedEntitiesToAdd(); _entityStreams = EntitiesStreams.Create(); #if SVELTO_LEGACY_FILTERS _groupFilters = - new FasterDictionary>(); + new FasterDictionary>(); #endif _entityLocator.InitEntityReferenceMap(); _entitiesDB = new EntitiesDB(this, _entityLocator); @@ -198,18 +199,19 @@ namespace Svelto.ECS } static void AddEngineToList(T engine, Type[] entityComponentTypes, - FasterDictionary>> engines, string typeName) + FasterDictionary>> engines, string typeName) where T : class, IReactEngine { for (var i = 0; i < entityComponentTypes.Length; i++) { var type = entityComponentTypes[i]; - if (engines.TryGetValue(new RefWrapperType(type), out var list) == false) + var componentID = ComponentTypeMap.FetchID(type); + if (engines.TryGetValue(componentID, out var list) == false) { list = new FasterList>(); - engines.Add(new RefWrapperType(type), list); + engines.Add(componentID, list); } list.Add(new ReactEngineContainer(engine, typeName)); @@ -217,7 +219,7 @@ namespace Svelto.ECS } void CheckReactEngineComponents(Type genericDefinition, T engine, - FasterDictionary>> engines, string typeName) + FasterDictionary>> engines, string typeName) where T : class, IReactEngine { var interfaces = engine.GetType().GetInterfaces(); @@ -226,7 +228,7 @@ namespace Svelto.ECS { if (interf.IsGenericTypeEx() && interf.GetGenericTypeDefinition() == genericDefinition) { - var genericArguments = interf.GetGenericArgumentsEx(); + Type[] genericArguments = interf.GetGenericArgumentsEx(); AddEngineToList(engine, genericArguments, engines, typeName); } @@ -401,13 +403,13 @@ namespace Svelto.ECS readonly HashSet _enginesTypeSet; readonly EnginesReadyOption _enginesWaitForReady; - readonly FasterDictionary>> _reactiveEnginesAdd; - readonly FasterDictionary>> _reactiveEnginesAddEx; - readonly FasterDictionary>> _reactiveEnginesRemove; - readonly FasterDictionary>> _reactiveEnginesRemoveEx; - readonly FasterDictionary>> _reactiveEnginesSwap; - readonly FasterDictionary>> _reactiveEnginesSwapEx; - readonly FasterDictionary>> _reactiveEnginesDispose; + readonly FasterDictionary>> _reactiveEnginesAdd; + readonly FasterDictionary>> _reactiveEnginesAddEx; + readonly FasterDictionary>> _reactiveEnginesRemove; + readonly FasterDictionary>> _reactiveEnginesRemoveEx; + readonly FasterDictionary>> _reactiveEnginesSwap; + readonly FasterDictionary>> _reactiveEnginesSwapEx; + readonly FasterDictionary>> _reactiveEnginesDispose; readonly FasterList _reactiveEnginesSubmission; readonly FasterList _reactiveEnginesSubmissionStarted; diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs index c7242a4..0c25bc8 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs @@ -62,19 +62,18 @@ namespace Svelto.ECS void PreallocateDBGroup() { var numberOfEntityComponents = entityComponentsToBuild.Length; - FasterDictionary group = GetOrAddDBGroup(groupID); + FasterDictionary group = GetOrAddDBGroup(groupID); for (var index = 0; index < numberOfEntityComponents; index++) { var entityComponentBuilder = entityComponentsToBuild[index]; - var entityComponentType = entityComponentBuilder.GetEntityComponentType(); + var entityComponentType = entityComponentBuilder.getComponentID; - var refWrapper = new RefWrapperType(entityComponentType); - var dbList = group.GetOrAdd(refWrapper, () => entityComponentBuilder.CreateDictionary(size)); + var dbList = group.GetOrAdd(entityComponentType, () => entityComponentBuilder.CreateDictionary(size)); entityComponentBuilder.Preallocate(dbList, size); - if (_groupsPerEntity.TryGetValue(refWrapper, out var groupedGroup) == false) - groupedGroup = _groupsPerEntity[refWrapper] = + if (_groupsPerEntity.TryGetValue(entityComponentType, out var groupedGroup) == false) + groupedGroup = _groupsPerEntity[entityComponentType] = new FasterDictionary(); groupedGroup[groupID] = dbList; @@ -87,27 +86,27 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - FasterDictionary GetDBGroup(ExclusiveGroupStruct fromIdGroupId) + FasterDictionary GetDBGroup(ExclusiveGroupStruct fromIdGroupId) { if (_groupEntityComponentsDB.TryGetValue(fromIdGroupId, - out FasterDictionary fromGroup) == false) + out FasterDictionary fromGroup) == false) throw new ECSException("Group doesn't exist: ".FastConcat(fromIdGroupId.ToName())); return fromGroup; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - FasterDictionary GetOrAddDBGroup(ExclusiveGroupStruct toGroupId) + FasterDictionary GetOrAddDBGroup(ExclusiveGroupStruct toGroupId) { return _groupEntityComponentsDB.GetOrAdd(toGroupId, - () => new FasterDictionary()); + () => new FasterDictionary()); } IComponentBuilder[] FindRealComponents(EGID fromEntityGID) where T : IEntityDescriptor, new() { var fromGroup = GetDBGroup(fromEntityGID.groupID); - if (fromGroup.TryGetValue(new RefWrapperType(ComponentBuilderUtilities.ENTITY_INFO_COMPONENT), + if (fromGroup.TryGetValue(ComponentBuilderUtilities.ENTITY_INFO_COMPONENT_ID, out var entityInfoDic) // && ((ITypeSafeDictionary)entityInfoDic).TryGetValue(fromEntityGID.entityID, out var entityInfo)) //there could be multiple entity descriptors registered in the same group, so it's necessary to check if the entity registered in the group has entityInfoComponent @@ -129,14 +128,14 @@ namespace Svelto.ECS return entityInfo.componentsToBuild; } - return EntityDescriptorTemplate.descriptor.componentsToBuild; + return EntityDescriptorTemplate.realDescriptor.componentsToBuild; } IComponentBuilder[] FindRealComponents(EGID fromEntityGID, IComponentBuilder[] baseComponents) { var fromGroup = GetDBGroup(fromEntityGID.groupID); - if (fromGroup.TryGetValue(new RefWrapperType(ComponentBuilderUtilities.ENTITY_INFO_COMPONENT), + if (fromGroup.TryGetValue(ComponentBuilderUtilities.ENTITY_INFO_COMPONENT_ID, out var entityInfoDic) // && ((ITypeSafeDictionary)entityInfoDic).TryGetValue(fromEntityGID.entityID, out var entityInfo)) //there could be multiple entity descriptors registered in the same group, so it's necessary to check if the entity registered in the group has entityInfoComponent @@ -168,18 +167,18 @@ namespace Svelto.ECS //ID. This ID doesn't need to be the EGID, it can be just the entityID //for each group id, save a dictionary indexed by entity type of entities indexed by id // group EntityComponentType entityID, EntityComponent - internal readonly FasterDictionary> + internal readonly FasterDictionary> _groupEntityComponentsDB; //for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are //found indexed by group id. TypeSafeDictionary are never created, they instead point to the ones hold //by _groupEntityComponentsDB // >> - internal readonly FasterDictionary> + internal readonly FasterDictionary> _groupsPerEntity; #if SVELTO_LEGACY_FILTERS //The filters stored for each component and group - internal readonly FasterDictionary> + internal readonly FasterDictionary> _groupFilters; #endif diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs index f3d3d32..8577dff 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs @@ -20,7 +20,7 @@ namespace Svelto.ECS , [CallerMemberName] string caller = null) where T : IEntityDescriptor, new() { return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId) - , EntityDescriptorTemplate.descriptor.componentsToBuild + , EntityDescriptorTemplate.realDescriptor.componentsToBuild , TypeCache.type, implementors, caller); } @@ -29,7 +29,7 @@ namespace Svelto.ECS (EGID egid, IEnumerable implementors = null , [CallerMemberName] string caller = null) where T : IEntityDescriptor, new() { - return _enginesRoot.Target.BuildEntity(egid, EntityDescriptorTemplate.descriptor.componentsToBuild + return _enginesRoot.Target.BuildEntity(egid, EntityDescriptorTemplate.realDescriptor.componentsToBuild , TypeCache.type, implementors, caller); } @@ -65,7 +65,7 @@ namespace Svelto.ECS where T : IEntityDescriptor, new() { _enginesRoot.Target.Preallocate(groupStructId, numberOfEntities - , EntityDescriptorTemplate.descriptor.componentsToBuild); + , EntityDescriptorTemplate.realDescriptor.componentsToBuild); } #if UNITY_NATIVE diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs index 2e780c5..2c03ed1 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs @@ -48,7 +48,7 @@ namespace Svelto.ECS { if (_enginesRoot.Target._groupEntityComponentsDB.TryGetValue( fromGroupID.group - , out FasterDictionary entitiesInGroupPerType) == true) + , out FasterDictionary entitiesInGroupPerType) == true) { #if DEBUG && !PROFILE_SVELTO ITypeSafeDictionary dictionary = entitiesInGroupPerType.unsafeValues[0]; diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs index bf3c91a..d267c48 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs @@ -46,7 +46,7 @@ namespace Svelto.ECS } static void RemoveEntities( - FasterDictionary>> + FasterDictionary>> removeOperations, FasterList entitiesRemoved, EnginesRoot enginesRoot) { using (var sampler = new PlatformProfiler("remove Entities")) @@ -94,7 +94,7 @@ namespace Svelto.ECS foreach (var groupedEntitiesToRemove in entitiesToRemove.value) { - RefWrapperType componentType = groupedEntitiesToRemove.key; + ComponentID componentType = groupedEntitiesToRemove.key; ITypeSafeDictionary fromComponentsDictionary = fromGroupDictionary[componentType]; FasterList<(uint, string)> entityIDsToRemove = groupedEntitiesToRemove.value; @@ -161,7 +161,7 @@ namespace Svelto.ECS } } - static void SwapEntities(FasterDictionary>>> swapEntitiesOperations, FasterList<(EGID, EGID)> entitiesIDSwaps, EnginesRoot enginesRoot) { @@ -262,7 +262,7 @@ namespace Svelto.ECS //get all the engines linked to TValue if (!enginesRoot._reactiveEnginesSwap.TryGetValue( - new RefWrapperType(componentType), + componentType, out var entityComponentsEngines)) continue; @@ -304,8 +304,7 @@ namespace Svelto.ECS //get all the engines linked to TValue if (!enginesRoot._reactiveEnginesSwapEx.TryGetValue( - new RefWrapperType(componentType), - out var entityComponentsEngines)) + componentType, out var entityComponentsEngines)) continue; ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; @@ -354,9 +353,8 @@ namespace Svelto.ECS { var type = entityComponentsToSubmit.key; var fromDictionary = entityComponentsToSubmit.value; - var wrapper = new RefWrapperType(type); - - var toDictionary = GetOrAddTypeSafeDictionary(groupID, groupDB, wrapper, fromDictionary); + + var toDictionary = GetOrAddTypeSafeDictionary(groupID, groupDB, type, fromDictionary); //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 @@ -385,9 +383,8 @@ namespace Svelto.ECS foreach (var entityComponentsToSubmit in groupToSubmit.components) { var type = entityComponentsToSubmit.key; - var wrapper = new RefWrapperType(type); - - var toDictionary = GetTypeSafeDictionary(groupID, groupDB, wrapper); + + var toDictionary = GetTypeSafeDictionary(groupID, groupDB, type); enumerator.MoveNext(); toDictionary.ExecuteEnginesAddEntityCallbacksFast(_reactiveEnginesAddEx, groupID, enumerator.Current, in sampler); } @@ -465,15 +462,15 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] void SwapEntitiesBetweenGroups(ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, PlatformProfiler platformProfiler) { - FasterDictionary fromGroup = GetDBGroup(fromGroupId); - FasterDictionary toGroup = GetOrAddDBGroup(toGroupId); + FasterDictionary fromGroup = GetDBGroup(fromGroupId); + FasterDictionary toGroup = GetOrAddDBGroup(toGroupId); _entityLocator.UpdateAllGroupReferenceLocators(fromGroupId, toGroupId); //remove entities from dictionaries foreach (var dictionaryOfEntities in fromGroup) { - RefWrapperType refWrapperType = dictionaryOfEntities.key; + var refWrapperType = dictionaryOfEntities.key; ITypeSafeDictionary fromDictionary = dictionaryOfEntities.value; ITypeSafeDictionary toDictionary = GetOrAddTypeSafeDictionary(toGroupId, toGroup, refWrapperType, fromDictionary); @@ -488,7 +485,7 @@ namespace Svelto.ECS //Call all the callbacks foreach (var dictionaryOfEntities in fromGroup) { - RefWrapperType refWrapperType = dictionaryOfEntities.key; + var refWrapperType = dictionaryOfEntities.key; ITypeSafeDictionary fromDictionary = dictionaryOfEntities.value; ITypeSafeDictionary toDictionary = GetTypeSafeDictionary(toGroupId, toGroup, refWrapperType); @@ -509,20 +506,20 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] ITypeSafeDictionary GetOrAddTypeSafeDictionary(ExclusiveGroupStruct groupId, - FasterDictionary groupPerComponentType, RefWrapperType type, + FasterDictionary groupPerComponentType, ComponentID typeID, ITypeSafeDictionary fromDictionary) { //be sure that the TypeSafeDictionary for the entity Type exists - if (groupPerComponentType.TryGetValue(type, out ITypeSafeDictionary toEntitiesDictionary) == false) + if (groupPerComponentType.TryGetValue(typeID, out ITypeSafeDictionary toEntitiesDictionary) == false) { toEntitiesDictionary = fromDictionary.Create(); - groupPerComponentType.Add(type, toEntitiesDictionary); + groupPerComponentType.Add(typeID, toEntitiesDictionary); } { //update GroupsPerEntity - if (_groupsPerEntity.TryGetValue(type, out var groupedGroup) == false) - groupedGroup = _groupsPerEntity[type] = + if (_groupsPerEntity.TryGetValue(typeID, out var groupedGroup) == false) + groupedGroup = _groupsPerEntity[typeID] = new FasterDictionary(); groupedGroup[groupId] = toEntitiesDictionary; @@ -533,7 +530,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] static ITypeSafeDictionary GetTypeSafeDictionary(ExclusiveGroupStruct groupID, - FasterDictionary @group, RefWrapperType refWrapper) + FasterDictionary @group, ComponentID refWrapper) { if (@group.TryGetValue(refWrapper, out ITypeSafeDictionary fromTypeSafeDictionary) == false) { @@ -553,12 +550,12 @@ namespace Svelto.ECS //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< static readonly - Action>>>, FasterList<(EGID, EGID)> , EnginesRoot> _swapEntities; static readonly Action< - FasterDictionary>>, + FasterDictionary>>, FasterList, EnginesRoot> _removeEntities; static readonly Action _removeGroup; diff --git a/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs b/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs index 7d13aa8..e271f1d 100644 --- a/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs +++ b/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs @@ -19,7 +19,7 @@ namespace Svelto.ECS } EntityCollection InternalQueryEntities - (FasterDictionary entitiesInGroupPerType) + (FasterDictionary entitiesInGroupPerType) where T : struct, _IInternalEntityComponent { uint count = 0; @@ -236,7 +236,7 @@ namespace Svelto.ECS public bool ExistsAndIsNotEmpty(ExclusiveGroupStruct gid) { if (groupEntityComponentsDB.TryGetValue( - gid, out FasterDictionary group) == true) + gid, out FasterDictionary group) == true) { return group.count > 0; } @@ -265,17 +265,17 @@ namespace Svelto.ECS return (int)typeSafeDictionary.count; } - public bool FoundInGroups() where T1 : _IInternalEntityComponent + public bool FoundInGroups() where T : struct, _IInternalEntityComponent { - return groupsPerComponent.ContainsKey(TypeRefWrapper.wrapper); + return groupsPerComponent.ContainsKey(ComponentTypeID.id); } [MethodImpl(MethodImplOptions.AggressiveInlining)] bool SafeQueryEntityDictionary (out ITypeSafeDictionary typeSafeDictionary - , FasterDictionary entitiesInGroupPerType) where T : _IInternalEntityComponent + , FasterDictionary entitiesInGroupPerType) where T : struct, _IInternalEntityComponent { - if (entitiesInGroupPerType.TryGetValue(new RefWrapperType(TypeCache.type), out var safeDictionary) + if (entitiesInGroupPerType.TryGetValue(ComponentTypeID.id, out var safeDictionary) == false) { typeSafeDictionary = default; @@ -290,9 +290,9 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool SafeQueryEntityDictionary - (ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : _IInternalEntityComponent + (ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : struct, _IInternalEntityComponent { - if (UnsafeQueryEntityDictionary(group, TypeCache.type, out var safeDictionary) == false) + if (UnsafeQueryEntityDictionary(group, ComponentTypeID.id, out var safeDictionary) == false) { typeSafeDictionary = default; return false; @@ -306,7 +306,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool UnsafeQueryEntityDictionary - (ExclusiveGroupStruct group, Type type, out ITypeSafeDictionary typeSafeDictionary) + (ExclusiveGroupStruct group, ComponentID id, out ITypeSafeDictionary typeSafeDictionary) { //search for the group if (groupEntityComponentsDB.TryGetValue(group, out var entitiesInGroupPerType) == false) @@ -316,7 +316,7 @@ namespace Svelto.ECS } //search for the indexed entities in the group - return entitiesInGroupPerType.TryGetValue(new RefWrapperType(type), out typeSafeDictionary); + return entitiesInGroupPerType.TryGetValue(id, out typeSafeDictionary); } static readonly FasterDictionary _emptyDictionary = @@ -330,14 +330,14 @@ namespace Svelto.ECS //group, then indexable per type, then indexable per EGID. however the TypeSafeDictionary can return an array of //values directly, that can be iterated over, so that is possible to iterate over all the entity components of //a specific type inside a specific group. - FasterDictionary> + FasterDictionary> groupEntityComponentsDB => _enginesRoot._groupEntityComponentsDB; //for each entity view type, return the groups (dictionary of entities indexed by entity id) where they are //found indexed by group id. TypeSafeDictionary are never created, they instead point to the ones hold //by _groupEntityComponentsDB // >> - FasterDictionary> groupsPerComponent => + FasterDictionary> groupsPerComponent => _enginesRoot._groupsPerEntity; EnginesRoot.EntityReferenceMap _entityReferencesMap; diff --git a/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs b/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs index 7da09db..f6364cf 100644 --- a/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs +++ b/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs @@ -43,7 +43,7 @@ namespace Svelto.ECS foreach (var operation in componentBuilders) { removedComponentsPerType //recycle or create dictionaries per component type - .RecycleOrAdd(new RefWrapperType(operation.GetEntityComponentType()), _newList, _clearList) + .RecycleOrAdd(operation.getComponentID, _newList, _clearList) //add entity to remove .Add((entityEgid.entityID, caller)); } @@ -72,7 +72,7 @@ namespace Svelto.ECS //Get the dictionary for each component that holds the list of entities to swap swappedComponentsPerType //recycle or create dictionaries per component type - .RecycleOrAdd(new RefWrapperType(operation.GetEntityComponentType()), _newGroupDictionary, _recycleDicitionaryWithCaller) + .RecycleOrAdd(operation.getComponentID, _newGroupDictionary, _recycleDicitionaryWithCaller) //recycle or create list of entities to swap .RecycleOrAdd(toID.groupID, _newListWithCaller, _clearListWithCaller) //add entity to swap @@ -86,9 +86,9 @@ namespace Svelto.ECS return _thisSubmissionInfo.AnyOperationQueued(); } - public void ExecuteRemoveAndSwappingOperations(Action>>>, FasterList<(EGID, EGID)>, - EnginesRoot> swapEntities, Action>>, + EnginesRoot> swapEntities, Action>>, FasterList, EnginesRoot> removeEntities, Action removeGroup, Action swapGroup, EnginesRoot enginesRoot) { @@ -137,12 +137,12 @@ namespace Svelto.ECS _lastSubmittedInfo.Clear(); } - FasterDictionary> NewGroupsDictionary() + FasterDictionary> NewGroupsDictionary() { - return new FasterDictionary>(); + return new FasterDictionary>(); } - void RecycleDictionary(ref FasterDictionary> recycled) + void RecycleDictionary(ref FasterDictionary> recycled) { recycled.Recycle(); } @@ -172,13 +172,13 @@ namespace Svelto.ECS return new FasterList<(uint, uint, string)>(); } - FasterDictionary>> NewGroupsDictionaryWithCaller() + FasterDictionary>> NewGroupsDictionaryWithCaller() { - return new FasterDictionary>>(); } - void RecycleGroupDictionaryWithCaller(ref FasterDictionary>> recycled) + void RecycleGroupDictionaryWithCaller(ref FasterDictionary>> recycled) { recycled.Recycle(); } @@ -191,13 +191,13 @@ namespace Svelto.ECS struct Info { //from group //actual component type - internal FasterDictionary>>> _currentSwapEntitiesOperations; internal FasterDictionary>> _currentRemoveEntitiesOperations; + FasterDictionary>> _currentRemoveEntitiesOperations; internal FasterList<(EGID, EGID)> _entitiesSwapped; internal FasterList _entitiesRemoved; @@ -229,11 +229,11 @@ namespace Svelto.ECS _groupsToSwap = new FasterList<(ExclusiveBuildGroup, ExclusiveBuildGroup, string)>(); _currentSwapEntitiesOperations = - new FasterDictionary>>>(); _currentRemoveEntitiesOperations = new FasterDictionary>>(); + FasterDictionary>>(); } } @@ -241,12 +241,12 @@ namespace Svelto.ECS Info _thisSubmissionInfo; readonly Func>> _newGroupDictionary; - readonly Func>> _newGroupsDictionary; - readonly ActionRef>> _recycleDictionary; + readonly Func>> _newGroupsDictionary; + readonly ActionRef>> _recycleDictionary; readonly Func> _newList; readonly ActionRef> _clearList; - readonly Func>>> _newGroupsDictionaryWithCaller; - readonly ActionRef>>> _recycleGroupDictionaryWithCaller; + readonly Func>>> _newGroupsDictionaryWithCaller; + readonly ActionRef>>> _recycleGroupDictionaryWithCaller; readonly ActionRef>> _recycleDicitionaryWithCaller; readonly Func> _newListWithCaller; readonly ActionRef> _clearListWithCaller; diff --git a/com.sebaslab.svelto.ecs/Core/EntityCollection.cs b/com.sebaslab.svelto.ecs/Core/EntityCollection.cs index fd6a5ff..1875918 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityCollection.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityCollection.cs @@ -17,8 +17,8 @@ namespace Svelto.ECS public uint count { get; } - internal readonly IBufferBase _buffer; - internal readonly IEntityIDs _entityIDs; + public readonly IBufferBase _buffer; + public readonly IEntityIDs _entityIDs; } public readonly ref struct EntityCollection where T1 : struct, _IInternalEntityComponent diff --git a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs index 3d42ace..ea65ef8 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs @@ -16,7 +16,7 @@ namespace Svelto.ECS { internal DynamicEntityDescriptor(bool isExtendible) : this() { - var defaultEntities = EntityDescriptorTemplate.descriptor.componentsToBuild; + var defaultEntities = EntityDescriptorTemplate.realDescriptor.componentsToBuild; var length = defaultEntities.Length; if (FetchEntityInfoComponent(defaultEntities) == -1) @@ -56,7 +56,7 @@ namespace Svelto.ECS public void ExtendWith() where T : IEntityDescriptor, new() { - var extraEntities = EntityDescriptorTemplate.descriptor.componentsToBuild; + var extraEntities = EntityDescriptorTemplate.realDescriptor.componentsToBuild; _componentsToBuild = Construct(extraEntities.Length, extraEntities); } diff --git a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/IEntityDescriptor.cs b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/IEntityDescriptor.cs index 45674f2..490df42 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/IEntityDescriptor.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/IEntityDescriptor.cs @@ -1,5 +1,20 @@ namespace Svelto.ECS { + /// + /// When implementing IEntityDescriptor directly the pattern to use is the following: + /// + /// class DoofusEntityDescriptor: IEntityDescriptor +/// { +/// public IComponentBuilder[] componentsToBuild { get; } = +/// { +/// new ComponentBuilder() +/// , new ComponentBuilder() +/// , new ComponentBuilder() +/// , new ComponentBuilder() +/// , ... +/// }; +/// } + /// public interface IEntityDescriptor { IComponentBuilder[] componentsToBuild { get; } diff --git a/com.sebaslab.svelto.ecs/Core/EntityFactory.cs b/com.sebaslab.svelto.ecs/Core/EntityFactory.cs index ff86957..4fd4d89 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityFactory.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityFactory.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Svelto.DataStructures; @@ -5,7 +6,7 @@ namespace Svelto.ECS.Internal { static class EntityFactory { - public static FasterDictionary BuildGroupedEntities + public static FasterDictionary BuildGroupedEntities (EGID egid, EnginesRoot.DoubleBufferedEntitiesToAdd groupEntitiesToAdd, IComponentBuilder[] componentsToBuild , IEnumerable implementors #if DEBUG && !PROFILE_SVELTO @@ -14,7 +15,7 @@ namespace Svelto.ECS.Internal ) { var group = groupEntitiesToAdd.currentComponentsToAddPerGroup.GetOrAdd( - egid.groupID, () => new FasterDictionary()); + egid.groupID, () => new FasterDictionary()); //track the number of entities created so far in the group. groupEntitiesToAdd.IncrementEntityCount(egid.groupID); @@ -29,7 +30,7 @@ namespace Svelto.ECS.Internal } static void BuildEntitiesAndAddToGroup - (EGID entityID, FasterDictionary @group + (EGID entityID, FasterDictionary @group , IComponentBuilder[] componentBuilders, IEnumerable implementors #if DEBUG && !PROFILE_SVELTO , System.Type descriptorType @@ -64,12 +65,10 @@ namespace Svelto.ECS.Internal } } - static void BuildEntity - (EGID entityID, FasterDictionary group - , IComponentBuilder componentBuilder, IEnumerable implementors) + static void BuildEntity(EGID entityID, FasterDictionary group, + IComponentBuilder componentBuilder, IEnumerable implementors) { - var entityComponentType = componentBuilder.GetEntityComponentType(); - ITypeSafeDictionary safeDictionary = group.GetOrAdd(new RefWrapperType(entityComponentType) + ITypeSafeDictionary safeDictionary = group.GetOrAdd(componentBuilder.getComponentID , (ref IComponentBuilder cb) => cb.CreateDictionary(1) , ref componentBuilder); diff --git a/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs b/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs index b6d2852..cb5ef3e 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs @@ -1,5 +1,4 @@ using Svelto.ECS.Hybrid; -using Svelto.ECS.Internal; namespace Svelto.ECS { diff --git a/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs b/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs index 0bf812a..f50c49d 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs @@ -6,7 +6,7 @@ namespace Svelto.ECS { public readonly ref struct EntityInitializer { - public EntityInitializer(EGID id, FasterDictionary group, + public EntityInitializer(EGID id, FasterDictionary group, in EntityReference reference) { _group = group; @@ -20,7 +20,7 @@ namespace Svelto.ECS public void Init(T initializer) where T : struct, _IInternalEntityComponent { if (_group.TryGetValue( - new RefWrapperType(TypeCache.type), + ComponentTypeID.id, out var typeSafeDictionary) == false) return; @@ -34,10 +34,10 @@ namespace Svelto.ECS dictionary.GetDirectValueByRef(findElementIndex) = initializer; } - internal ref T GetOrAdd() where T : unmanaged, IEntityComponent + internal ref T GetOrAdd() where T : struct, _IInternalEntityComponent { ref var entityDictionary = ref _group.GetOrAdd( - new RefWrapperType(ComponentBuilder.ENTITY_COMPONENT_TYPE), + ComponentTypeID.id, () => new UnmanagedTypeSafeDictionary(1)); var dictionary = (ITypeSafeDictionary)entityDictionary; @@ -46,14 +46,14 @@ namespace Svelto.ECS public ref T Get() where T : struct, _IInternalEntityComponent { - return ref (_group[new RefWrapperType(TypeCache.type)] as ITypeSafeDictionary) + return ref (_group[ComponentTypeID.id] as ITypeSafeDictionary) .GetValueByRef(_ID.entityID); } public bool Has() where T : struct, _IInternalEntityComponent { if (_group.TryGetValue( - new RefWrapperType(TypeCache.type), + ComponentTypeID.id, out var typeSafeDictionary)) { var dictionary = (ITypeSafeDictionary)typeSafeDictionary; @@ -66,6 +66,6 @@ namespace Svelto.ECS } readonly EGID _ID; - readonly FasterDictionary _group; + readonly FasterDictionary _group; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs b/com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs index 175a3f0..dfa9f60 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using Svelto.Common; using Svelto.DataStructures; using Svelto.DataStructures.Native; diff --git a/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs b/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs index 27508bc..2196c31 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs @@ -1,15 +1,30 @@ -namespace Svelto.ECS +using System; +using System.Runtime.CompilerServices; +using Svelto.ECS.Internal; + +namespace Svelto.ECS { public readonly struct CombinedFilterID { - internal readonly long id; - - public FilterContextID contextID => new FilterContextID((uint)((id & 0xFFFF0000) >> 16)); - public uint filterID => (uint)(id >> 32); + //filter (32) | contextID (16) | component type (16) + readonly long id; + + //a context ID is 16bit + public FilterContextID contextID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => new FilterContextID((ushort)((id & 0xFFFF0000) >> 16)); + } + + public uint filterID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (uint)(id >> 32); + } public CombinedFilterID(int filterID, FilterContextID contextID) { - id = (long)filterID << 32 | (uint)contextID.id << 16; + id = (long)filterID << 32 | (long)contextID.id << 16; } public static implicit operator CombinedFilterID((int filterID, FilterContextID contextID) data) @@ -17,4 +32,72 @@ return new CombinedFilterID(data.filterID, data.contextID); } } + + readonly struct CombinedFilterComponentID: IEquatable + { + //filter (32) | contextID (16) | component type (16) + internal readonly long id; + + //a context ID is 16bit + public FilterContextID contextID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return new FilterContextID((ushort)((id & 0xFFFF0000) >> 16)); + } + } + + public uint filterID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (uint)(id >> 32); + } + } + + public uint contextComponentID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (uint)(id & 0xFFFF); + } + } + + public CombinedFilterComponentID(int filterID, FilterContextID contextID) + { + id = (long)filterID << 32 | (uint)contextID.id << 16; + } + + public CombinedFilterComponentID(uint filterIdFilterId, FilterContextID filterIdContextId, ComponentID componentid) + { + id = (long)filterIdFilterId << 32 | (long)filterIdContextId.id << 16 | (long)(uint)componentid; + } + + public bool Equals(CombinedFilterComponentID other) + { + return id == other.id; + } + + public override int GetHashCode() + { + return id.GetHashCode(); + } + } + + public static class CombinedFilterIDExtensions + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static CombinedFilterComponentID CombineComponent(this CombinedFilterID filterID) + where T : struct, _IInternalEntityComponent + { + var componentid = ComponentTypeID.id; + + DBC.ECS.Check.Require(componentid < ushort.MaxValue, "too many component types registered, HOW :)"); + + return new CombinedFilterComponentID(filterID.filterID, filterID.contextID, componentid); + } + } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs b/com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs index 71ae6ed..305f329 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs @@ -8,10 +8,12 @@ namespace Svelto.ECS { void InitFilters() { - _transientEntityFilters = new SharedSveltoDictionaryNative(0); - _persistentEntityFilters = new SharedSveltoDictionaryNative(0); + _transientEntityFilters = new SharedSveltoDictionaryNative(0); + _persistentEntityFilters = new SharedSveltoDictionaryNative(0); _indicesOfPersistentFiltersUsedByThisComponent = - new SharedSveltoDictionaryNative>(0); + new SharedSveltoDictionaryNative>(0); + _indicesOfTransientFiltersUsedByThisComponent = + new SharedSveltoDictionaryNative>(0); } void DisposeFilters() @@ -20,7 +22,12 @@ namespace Svelto.ECS { filter.value.Dispose(); } - + + foreach (var filter in _indicesOfTransientFiltersUsedByThisComponent) + { + filter.value.Dispose(); + } + foreach (var filter in _persistentEntityFilters) { filter.value.Dispose(); @@ -34,6 +41,7 @@ namespace Svelto.ECS _transientEntityFilters.Dispose(); _persistentEntityFilters.Dispose(); _indicesOfPersistentFiltersUsedByThisComponent.Dispose(); + _indicesOfTransientFiltersUsedByThisComponent.Dispose(); } void ClearTransientFilters() @@ -54,12 +62,12 @@ namespace Svelto.ECS /// /// void RemoveEntitiesFromPersistentFilters - (FasterList<(uint entityID, string)> entityIDsRemoved, ExclusiveGroupStruct fromGroup, RefWrapperType refWrapperType + (FasterList<(uint entityID, string)> entityIDsRemoved, ExclusiveGroupStruct fromGroup, ComponentID refWrapperType , ITypeSafeDictionary fromDic, FasterList entityIDsLeftAndAffectedByRemoval) { //is there any filter used by this component? if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue( - new NativeRefWrapperType(refWrapperType), out NativeDynamicArrayCast listOfFilters) == true) + refWrapperType, out NativeDynamicArrayCast listOfFilters) == true) { var numberOfFilters = listOfFilters.count; var filters = _persistentEntityFilters.unsafeValues; @@ -117,11 +125,11 @@ namespace Svelto.ECS void SwapEntityBetweenPersistentFilters (FasterList<(uint, uint, string)> fromEntityToEntityIDs, ITypeSafeDictionary fromDic , ITypeSafeDictionary toDic, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup - , RefWrapperType refWrapperType, FasterList entityIDsLeftAndAffectedByRemoval) + , ComponentID refWrapperType, FasterList entityIDsLeftAndAffectedByRemoval) { //is there any filter used by this component? if (_indicesOfPersistentFiltersUsedByThisComponent.TryGetValue( - new NativeRefWrapperType(refWrapperType), out NativeDynamicArrayCast listOfFilters) == true) + refWrapperType, out NativeDynamicArrayCast listOfFilters) == true) { DBC.ECS.Check.Require(listOfFilters.count > 0, "why are you calling this with an empty list?"); var numberOfFilters = listOfFilters.count; @@ -181,10 +189,10 @@ namespace Svelto.ECS } } - internal SharedSveltoDictionaryNative _transientEntityFilters; - internal SharedSveltoDictionaryNative _persistentEntityFilters; + internal SharedSveltoDictionaryNative _transientEntityFilters; + internal SharedSveltoDictionaryNative _persistentEntityFilters; - internal SharedSveltoDictionaryNative> - _indicesOfPersistentFiltersUsedByThisComponent; + internal SharedSveltoDictionaryNative> _indicesOfPersistentFiltersUsedByThisComponent; + public SharedSveltoDictionaryNative> _indicesOfTransientFiltersUsedByThisComponent; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs b/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs index 8baae31..4a81f21 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs @@ -13,15 +13,12 @@ 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(CombinedFilterID combinedFilterID) + //ComponentTypeID + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static CombinedFilterComponentID CombineFilterIDWithComponentID(CombinedFilterID combinedFilterID) where T : struct, _IInternalEntityComponent { - var id = (uint)ComponentID.id.Data; - - var combineFilterIDs = (long)combinedFilterID.id | id; - - return combineFilterIDs; + return combinedFilterID.CombineComponent(); } } @@ -31,7 +28,9 @@ namespace Svelto.ECS { return new SveltoFilters( _enginesRoot._persistentEntityFilters, - _enginesRoot._indicesOfPersistentFiltersUsedByThisComponent, _enginesRoot._transientEntityFilters); + _enginesRoot._indicesOfPersistentFiltersUsedByThisComponent, + _enginesRoot._transientEntityFilters, + _enginesRoot._indicesOfTransientFiltersUsedByThisComponent); } /// @@ -47,45 +46,45 @@ namespace Svelto.ECS #endif public static FilterContextID GetNewContextID() { - return new FilterContextID((uint)Interlocked.Increment(ref uniqueContextID.Data)); + return new FilterContextID((ushort)Interlocked.Increment(ref uniqueContextID.Data)); } - public SveltoFilters(SharedSveltoDictionaryNative persistentEntityFilters, - SharedSveltoDictionaryNative> - indicesOfPersistentFiltersUsedByThisComponent, - SharedSveltoDictionaryNative transientEntityFilters) + internal SveltoFilters(SharedSveltoDictionaryNative persistentEntityFilters, + SharedSveltoDictionaryNative> indicesOfPersistentFiltersUsedByThisComponent, + SharedSveltoDictionaryNative transientEntityFilters, + SharedSveltoDictionaryNative> indicesOfTransientFiltersUsedByThisComponent) { _persistentEntityFilters = persistentEntityFilters; _indicesOfPersistentFiltersUsedByThisComponent = indicesOfPersistentFiltersUsedByThisComponent; _transientEntityFilters = transientEntityFilters; + _indicesOfTransientFiltersUsedByThisComponent = indicesOfTransientFiltersUsedByThisComponent; } -#if UNITY_BURST //the following methods do not make sense without burst as they are workaround for burst - public ref EntityFilterCollection GetOrCreatePersistentFilter(int filterID, - FilterContextID filterContextId, NativeRefWrapperType typeRef) - where T : unmanaged, IEntityComponent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref EntityFilterCollection GetOrCreatePersistentFilter(int filterID, FilterContextID filterContextId) + where T : struct, _IInternalEntityComponent { - return ref GetOrCreatePersistentFilter(new CombinedFilterID(filterID, filterContextId), typeRef); + return ref GetOrCreatePersistentFilter(new CombinedFilterID(filterID, filterContextId)); } - public ref EntityFilterCollection GetOrCreatePersistentFilter(CombinedFilterID filterID, - NativeRefWrapperType typeRef) - where T : unmanaged, IEntityComponent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref EntityFilterCollection GetOrCreatePersistentFilter(CombinedFilterID filterID) where T : struct, _IInternalEntityComponent { - long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(filterID); - if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) + if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true) return ref _persistentEntityFilters.GetDirectValueByRef(index); - _persistentEntityFilters.Add(combineFilterIDs, new EntityFilterCollection(filterID)); + _persistentEntityFilters.Add(componentAndFilterID, new EntityFilterCollection(filterID)); var lastIndex = _persistentEntityFilters.count - 1; - if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(typeRef, out var getIndex) == false) + var componentId = ComponentTypeID.id; + if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(componentId, out var getIndex) == false) { var newArray = new NativeDynamicArrayCast(1, Allocator.Persistent); newArray.Add(lastIndex); - _indicesOfPersistentFiltersUsedByThisComponent.Add(typeRef, newArray); + _indicesOfPersistentFiltersUsedByThisComponent.Add(componentId, newArray); } else { @@ -95,7 +94,6 @@ namespace Svelto.ECS return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex); } -#endif /// /// Create a persistent filter. Persistent filters are not deleted after each submission, @@ -104,57 +102,26 @@ namespace Svelto.ECS /// /// /// + #if UNITY_BURST && UNITY_COLLECTIONS - [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper.wrapper; + [Unity.Burst.BurstDiscard] //not burst compatible because of ComponentTypeID.id and GetOrAdd callback; #endif [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref EntityFilterCollection GetOrCreatePersistentFilter(int filterID, - FilterContextID filterContextId) - where T : unmanaged, _IInternalEntityComponent - { - return ref GetOrCreatePersistentFilter(new CombinedFilterID(filterID, filterContextId)); - } -#if UNITY_BURST && UNITY_COLLECTIONS - [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper.wrapper and GetOrAdd callback; -#endif - public ref EntityFilterCollection GetOrCreatePersistentFilter(CombinedFilterID filterID) - where T : unmanaged, _IInternalEntityComponent - { - long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); - - if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) - return ref _persistentEntityFilters.GetDirectValueByRef(index); - - var typeRef = TypeRefWrapper.wrapper; - var filterCollection = new EntityFilterCollection(filterID); - - _persistentEntityFilters.Add(combineFilterIDs, filterCollection); - - var lastIndex = _persistentEntityFilters.count - 1; - - _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(new NativeRefWrapperType(typeRef), _builder).Add(lastIndex); - - return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex); - } -#if UNITY_BURST && UNITY_COLLECTIONS - [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper.wrapper and GetOrAdd callback; -#endif public ref EntityFilterCollection CreatePersistentFilter(CombinedFilterID filterID) - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { - long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(filterID); - if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) + if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true) throw new ECSException("filter already exists"); - var typeRef = TypeRefWrapper.wrapper; var filterCollection = new EntityFilterCollection(filterID); - _persistentEntityFilters.Add(combineFilterIDs, filterCollection); + _persistentEntityFilters.Add(componentAndFilterID, filterCollection); var lastIndex = _persistentEntityFilters.count - 1; - _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(new NativeRefWrapperType(typeRef), _builder).Add(lastIndex); + _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(ComponentTypeID.id, _builder).Add(lastIndex); return ref _persistentEntityFilters.GetDirectValueByRef((uint)lastIndex); } @@ -166,18 +133,18 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref EntityFilterCollection GetPersistentFilter(int filterID, FilterContextID filterContextId) - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { return ref GetPersistentFilter(new CombinedFilterID(filterID, filterContextId)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref EntityFilterCollection GetPersistentFilter(CombinedFilterID filterID) - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { - long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(filterID); - if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) + if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true) return ref _persistentEntityFilters.GetDirectValueByRef(index); throw new ECSException("filter not found"); @@ -186,11 +153,11 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetPersistentFilter(CombinedFilterID combinedFilterID, out EntityFilterCollection entityCollection) - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { - long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(combinedFilterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(combinedFilterID); - if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) + if (_persistentEntityFilters.TryFindIndex(componentAndFilterID, out var index) == true) { entityCollection = _persistentEntityFilters.GetDirectValueByRef(index); return true; @@ -200,12 +167,15 @@ namespace Svelto.ECS return false; } + /// + /// Svelto.ECS tracks the filters linked to each + /// component. This allows to iterate over all the filters of a given filter context linked to a component. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityFilterCollectionsEnumerator GetPersistentFilters() - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { - if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( - new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true) + if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID.id, out var index) == true) return new EntityFilterCollectionsEnumerator( _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index), _persistentEntityFilters); @@ -215,9 +185,9 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityFilterCollectionsWithContextEnumerator GetPersistentFilters(FilterContextID filterContextId) + where T : struct, _IInternalEntityComponent { - if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( - new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true) + if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID.id, out var index) == true) return new EntityFilterCollectionsWithContextEnumerator( _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index), _persistentEntityFilters, filterContextId); @@ -228,13 +198,12 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetPersistentFilters(FilterContextID filterContextId, out EntityFilterCollectionsWithContextEnumerator enumerator) + where T : struct, _IInternalEntityComponent { - if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( - new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true) + if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID.id, out var index) == true) { - enumerator = new EntityFilterCollectionsWithContextEnumerator( - _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index), - _persistentEntityFilters, filterContextId); + ref var filterIndices = ref _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index); + enumerator = new EntityFilterCollectionsWithContextEnumerator(filterIndices, _persistentEntityFilters, filterContextId); return true; } @@ -245,32 +214,49 @@ namespace Svelto.ECS /// /// Creates a transient filter. Transient filters are deleted after each submission + /// transient filters are identified by filterID and Context and can be linked to several groups. + /// So for each group there can be as many as necessary transient filters with different ID and contextID /// /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref EntityFilterCollection GetOrCreateTransientFilter(CombinedFilterID filterID) - where T : unmanaged, _IInternalEntityComponent + public ref EntityFilterCollection GetOrCreateTransientFilter(CombinedFilterID combinedFilterID, bool trackFilter = false) + where T : struct, _IInternalEntityComponent { - var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(combinedFilterID); - if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index)) return ref _transientEntityFilters.GetDirectValueByRef(index); - var filterCollection = new EntityFilterCollection(filterID); + return ref InternalCreateTransientFilter(combinedFilterID, componentAndFilterID, trackFilter); + } - _transientEntityFilters.Add(combineFilterIDs, filterCollection); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref EntityFilterCollection GetOrCreateTransientFilter(int filterID, FilterContextID filterContextId) + where T : struct, _IInternalEntityComponent + { + return ref GetOrCreateTransientFilter(new CombinedFilterID(filterID, filterContextId)); + } - return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref EntityFilterCollection CreateTransientFilter(CombinedFilterID combinedFilterID, bool trackFilter = false) + where T : struct, _IInternalEntityComponent + { + CombinedFilterComponentID componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(combinedFilterID); +#if DEBUG && !PROFILE_SVELTO + if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out _)) + throw new ECSException($"filter already exists {TypeCache.name}"); +#endif + return ref InternalCreateTransientFilter(combinedFilterID, componentAndFilterID, trackFilter); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryGetTransientFilter(CombinedFilterID filterID, out EntityFilterCollection entityCollection) - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { - var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(filterID); - if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index)) { entityCollection = _transientEntityFilters.GetDirectValueByRef(index); return true; @@ -279,37 +265,89 @@ namespace Svelto.ECS entityCollection = default; return false; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref EntityFilterCollection GetTransientFilter(CombinedFilterID filterID) - where T : unmanaged, _IInternalEntityComponent + where T : struct, _IInternalEntityComponent { - var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + var componentAndFilterID = Internal_FilterHelper.CombineFilterIDWithComponentID(filterID); - if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + if (_transientEntityFilters.TryFindIndex(componentAndFilterID, out var index)) { return ref _transientEntityFilters.GetDirectValueByRef(index); } - + throw new ECSException($"no filters associated with the type {TypeCache.name}"); } - - public void CreateTransientFilter(CombinedFilterID filterID) + + /// + /// Svelto.ECS tracks the filters linked to each + /// component. This allows to iterate over all the filters of a given filter context linked to a component. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntityFilterCollectionsEnumerator GetTransientFilters() + where T : struct, _IInternalEntityComponent + { + if (_indicesOfTransientFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID.id, out var index) == true) + return new EntityFilterCollectionsEnumerator( + _indicesOfTransientFiltersUsedByThisComponent.GetDirectValueByRef(index), + _transientEntityFilters); + + throw new ECSException($"no filters associated with the type {TypeCache.name}"); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntityFilterCollectionsWithContextEnumerator GetTransientFilters(FilterContextID filterContextId) + where T : struct, _IInternalEntityComponent + { + if (_indicesOfTransientFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID.id, out var index) == true) + return new EntityFilterCollectionsWithContextEnumerator( + _indicesOfTransientFiltersUsedByThisComponent.GetDirectValueByRef(index), + _transientEntityFilters, filterContextId); + + throw new ECSException($"no filters associated with the type {TypeCache.name}"); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetTransientFilters(FilterContextID filterContextId, out EntityFilterCollectionsWithContextEnumerator enumerator) + where T : struct, _IInternalEntityComponent + { + if (_indicesOfTransientFiltersUsedByThisComponent.TryFindIndex(ComponentTypeID.id, out var index) == true) + { + enumerator = new EntityFilterCollectionsWithContextEnumerator( + _indicesOfTransientFiltersUsedByThisComponent.GetDirectValueByRef(index), + _transientEntityFilters, filterContextId); + + return true; + } + + enumerator = default; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + ref EntityFilterCollection InternalCreateTransientFilter(CombinedFilterID filterID, CombinedFilterComponentID componentAndFilterID, + bool trackFilter) where T : struct, _IInternalEntityComponent { - var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); -#if DEBUG && !PROFILE_SVELTO - if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out _)) - throw new ECSException($"filter already exists {TypeCache.name}"); -#endif var filterCollection = new EntityFilterCollection(filterID); - _transientEntityFilters.Add(combineFilterIDs, filterCollection); + _transientEntityFilters.Add(componentAndFilterID, filterCollection); + + if (trackFilter) + { + var typeRef = ComponentTypeID.id; + var lastIndex = _transientEntityFilters.count - 1; + _indicesOfTransientFiltersUsedByThisComponent.GetOrAdd(ComponentTypeID.id, _builder).Add(lastIndex); + } + + return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1)); } - + public struct EntityFilterCollectionsEnumerator { - public EntityFilterCollectionsEnumerator(NativeDynamicArrayCast getDirectValueByRef, - SharedSveltoDictionaryNative sharedSveltoDictionaryNative): this() + internal EntityFilterCollectionsEnumerator(NativeDynamicArrayCast getDirectValueByRef, + SharedSveltoDictionaryNative sharedSveltoDictionaryNative): this() { _getDirectValueByRef = getDirectValueByRef; _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative; @@ -336,24 +374,24 @@ namespace Svelto.ECS public ref EntityFilterCollection Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); - } + get => ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); } readonly NativeDynamicArrayCast _getDirectValueByRef; - readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; + readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; int _currentIndex; } + /// + /// TODO: ABSOLUTELY UNIT TEST THIS AS THE CODE WAS WRONG!!! + /// public struct EntityFilterCollectionsWithContextEnumerator { - public EntityFilterCollectionsWithContextEnumerator(NativeDynamicArrayCast getDirectValueByRef, - SharedSveltoDictionaryNative sharedSveltoDictionaryNative, + internal EntityFilterCollectionsWithContextEnumerator(NativeDynamicArrayCast filterIndices, + SharedSveltoDictionaryNative sharedSveltoDictionaryNative, FilterContextID filterContextId): this() { - _getDirectValueByRef = getDirectValueByRef; + _filterIndices = filterIndices; _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative; _filterContextId = filterContextId; } @@ -366,11 +404,11 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { - while (_currentIndex++ < _getDirectValueByRef.count && - _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1).combinedFilterID - .contextID.id != _filterContextId.id) ; + while (_currentIndex++ < _filterIndices.count && + _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_filterIndices[(uint)_currentIndex - 1]).combinedFilterID + .contextID.id != _filterContextId.id); - if (_currentIndex - 1 < _getDirectValueByRef.count) + if (_currentIndex - 1 < _filterIndices.count) return true; return false; @@ -379,24 +417,25 @@ namespace Svelto.ECS public ref EntityFilterCollection Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); - } + get => ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_filterIndices[(uint)_currentIndex - 1]); } - readonly NativeDynamicArrayCast _getDirectValueByRef; - readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; + readonly NativeDynamicArrayCast _filterIndices; + readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; readonly FilterContextID _filterContextId; int _currentIndex; } - readonly SharedSveltoDictionaryNative _persistentEntityFilters; + readonly SharedSveltoDictionaryNative _persistentEntityFilters; - readonly SharedSveltoDictionaryNative> + readonly SharedSveltoDictionaryNative> _indicesOfPersistentFiltersUsedByThisComponent; - readonly SharedSveltoDictionaryNative _transientEntityFilters; + readonly SharedSveltoDictionaryNative _transientEntityFilters; + + readonly SharedSveltoDictionaryNative> + _indicesOfTransientFiltersUsedByThisComponent; + static readonly Func> _builder = Builder; } } diff --git a/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs b/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs index 2f286bc..abf051b 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs @@ -2,9 +2,9 @@ { public struct FilterContextID { - public readonly uint id; + public readonly ushort id; - internal FilterContextID(uint id) + internal FilterContextID(ushort id) { DBC.ECS.Check.Require(id < ushort.MaxValue, "too many types registered, HOW :)"); diff --git a/com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs index 2a48772..bc2e74f 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs @@ -16,7 +16,7 @@ namespace Svelto.ECS /// public partial class EntitiesDB { - FasterDictionary> _filters => + FasterDictionary> _filters => _enginesRoot._groupFilters; public LegacyFilters GetLegacyFilters() @@ -27,7 +27,7 @@ namespace Svelto.ECS public readonly struct LegacyFilters { public LegacyFilters( - FasterDictionary> + FasterDictionary> filtersLegacy) { _filtersLegacy = filtersLegacy; @@ -36,14 +36,14 @@ namespace Svelto.ECS public ref LegacyFilterGroup CreateOrGetFilterForGroup(int filterID, ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent { - var refWrapper = TypeRefWrapper.wrapper; + var refWrapper = ComponentTypeID.id; return ref CreateOrGetFilterForGroup(filterID, groupID, refWrapper); } public bool HasFiltersForGroup(ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary) == false) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary) == false) return false; return fasterDictionary.ContainsKey(groupID); @@ -52,7 +52,7 @@ namespace Svelto.ECS public bool HasFilterForGroup(int filterID, ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary) == false) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary) == false) return false; if (fasterDictionary.TryGetValue(groupID, out var result)) @@ -64,7 +64,7 @@ namespace Svelto.ECS public ref LegacyGroupFilters CreateOrGetFiltersForGroup(ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent { - var fasterDictionary = _filtersLegacy.GetOrAdd(TypeRefWrapper.wrapper, + var fasterDictionary = _filtersLegacy.GetOrAdd(ComponentTypeID.id, () => new FasterDictionary()); return ref fasterDictionary.GetOrAdd(groupID, @@ -75,27 +75,27 @@ namespace Svelto.ECS where T : struct, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO - if (_filtersLegacy.ContainsKey(TypeRefWrapper.wrapper) == false) + if (_filtersLegacy.ContainsKey(ComponentTypeID.id) == false) throw new ECSException($"trying to fetch not existing filters, type {typeof(T)}"); - if (_filtersLegacy[TypeRefWrapper.wrapper].ContainsKey(groupID) == false) + if (_filtersLegacy[ComponentTypeID.id].ContainsKey(groupID) == false) throw new ECSException( $"trying to fetch not existing filters, type {typeof(T)} group {groupID.ToName()}"); #endif - return ref _filtersLegacy[TypeRefWrapper.wrapper].GetValueByRef(groupID); + return ref _filtersLegacy[ComponentTypeID.id].GetValueByRef(groupID); } public ref LegacyFilterGroup GetFilterForGroup(int filterId, ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO - if (_filtersLegacy.ContainsKey(TypeRefWrapper.wrapper) == false) + if (_filtersLegacy.ContainsKey(ComponentTypeID.id) == false) throw new ECSException($"trying to fetch not existing filters, type {typeof(T)}"); - if (_filtersLegacy[TypeRefWrapper.wrapper].ContainsKey(groupID) == false) + if (_filtersLegacy[ComponentTypeID.id].ContainsKey(groupID) == false) throw new ECSException( $"trying to fetch not existing filters, type {typeof(T)} group {groupID.ToName()}"); #endif - return ref _filtersLegacy[TypeRefWrapper.wrapper][groupID].GetFilter(filterId); + return ref _filtersLegacy[ComponentTypeID.id][groupID].GetFilter(filterId); } public bool TryGetFilterForGroup(int filterId, ExclusiveGroupStruct groupID, @@ -103,7 +103,7 @@ namespace Svelto.ECS { groupLegacyFilter = default; - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary) == false) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary) == false) return false; if (fasterDictionary.TryGetValue(groupID, out var groupFilters) == false) @@ -120,7 +120,7 @@ namespace Svelto.ECS { legacyGroupFilters = default; - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary) == false) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary) == false) return false; return fasterDictionary.TryGetValue(groupID, out legacyGroupFilters); @@ -128,7 +128,7 @@ namespace Svelto.ECS public void ClearFilter(int filterID, ExclusiveGroupStruct exclusiveGroupStruct) { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary)) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary)) { Check.Require(fasterDictionary.ContainsKey(exclusiveGroupStruct), $"trying to clear filter not present in group {exclusiveGroupStruct}"); @@ -139,14 +139,14 @@ namespace Svelto.ECS public void ClearFilters(int filterID) { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary)) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary)) foreach (var filtersPerGroup in fasterDictionary) filtersPerGroup.value.ClearFilter(filterID); } public void DisposeFilters(ExclusiveGroupStruct exclusiveGroupStruct) { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary)) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary)) { fasterDictionary[exclusiveGroupStruct].DisposeFilters(); fasterDictionary.Remove(exclusiveGroupStruct); @@ -155,16 +155,16 @@ namespace Svelto.ECS public void DisposeFilters() { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary)) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary)) foreach (var filtersPerGroup in fasterDictionary) filtersPerGroup.value.DisposeFilters(); - _filtersLegacy.Remove(TypeRefWrapper.wrapper); + _filtersLegacy.Remove(ComponentTypeID.id); } public void DisposeFilterForGroup(int resetFilterID, ExclusiveGroupStruct group) { - if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary)) + if (_filtersLegacy.TryGetValue(ComponentTypeID.id, out var fasterDictionary)) fasterDictionary[@group].DisposeFilter(resetFilterID); } @@ -205,7 +205,7 @@ namespace Svelto.ECS return ref filters.CreateOrGetFilter(filterID); } - readonly FasterDictionary> + readonly FasterDictionary> _filtersLegacy; } } diff --git a/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs b/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs index 23adf1a..397b21d 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs @@ -7,11 +7,11 @@ namespace Svelto.ECS { public partial class EntitiesDB { - public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) where T1 : _IInternalEntityComponent + public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) where T1 : struct, _IInternalEntityComponent { FasterList result = localgroups.Value.groupArray; result.Clear(); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper + if (groupsPerComponent.TryGetValue(ComponentTypeID.id , out FasterDictionary result1) == false) return result; @@ -31,15 +31,15 @@ namespace Svelto.ECS } public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) - where T1 : _IInternalEntityComponent where T2 : _IInternalEntityComponent + where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent { FasterList result = localgroups.Value.groupArray; result.Clear(); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper + if (groupsPerComponent.TryGetValue(ComponentTypeID.id , out FasterDictionary result1) == false) return result; - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper + if (groupsPerComponent.TryGetValue(ComponentTypeID.id , out FasterDictionary result2) == false) return result; @@ -82,18 +82,18 @@ namespace Svelto.ECS /// /// public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) - where T1 : _IInternalEntityComponent where T2 : _IInternalEntityComponent where T3 : _IInternalEntityComponent + where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent where T3 : struct, _IInternalEntityComponent { FasterList> localArray = localgroups.Value.listOfGroups; - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[0]) == false || localArray[0].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[0]) == false || localArray[0].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[1]) == false || localArray[1].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[1]) == false || localArray[1].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[2]) == false || localArray[2].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[2]) == false || localArray[2].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); @@ -131,24 +131,24 @@ namespace Svelto.ECS } public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) - where T1 : _IInternalEntityComponent - where T2 : _IInternalEntityComponent - where T3 : _IInternalEntityComponent - where T4 : _IInternalEntityComponent + where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent + where T4 : struct, _IInternalEntityComponent { FasterList> localArray = localgroups.Value.listOfGroups; - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[0]) == false || localArray[0].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[0]) == false || localArray[0].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[1]) == false || localArray[1].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[1]) == false || localArray[1].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[2]) == false || localArray[2].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[2]) == false || localArray[2].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper, out localArray[3]) == false || localArray[3].count == 0) + if (groupsPerComponent.TryGetValue(ComponentTypeID.id, out localArray[3]) == false || localArray[3].count == 0) return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); @@ -192,12 +192,12 @@ namespace Svelto.ECS , (uint) localGroups.count); } - internal FasterDictionary FindGroups_INTERNAL(Type type) + internal FasterDictionary FindGroups_INTERNAL(ComponentID type) { - if (groupsPerComponent.ContainsKey(new RefWrapperType(type)) == false) + if (groupsPerComponent.ContainsKey(type) == false) return _emptyDictionary; - return groupsPerComponent[new RefWrapperType(type)]; + return groupsPerComponent[type]; } struct GroupsList diff --git a/com.sebaslab.svelto.ecs/Core/Groups/EntityDescriptorsWarmup.cs b/com.sebaslab.svelto.ecs/Core/Groups/EntityDescriptorsWarmup.cs new file mode 100644 index 0000000..7125bfb --- /dev/null +++ b/com.sebaslab.svelto.ecs/Core/Groups/EntityDescriptorsWarmup.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Svelto.ECS +{ + public static class EntityDescriptorsWarmup + { + /// + /// c# Static constructors are guaranteed to be thread safe + /// Warmup all EntityDescriptors and ComponentTypeID classes to avoid huge overheads when they are first used + /// + internal static void Init() + { + List assemblies = AssemblyUtility.GetCompatibleAssemblies(); + foreach (Assembly assembly in assemblies) + { + var typeOfEntityDescriptors = typeof(IEntityDescriptor); + + foreach (Type type in AssemblyUtility.GetTypesSafe(assembly)) + { + if (typeOfEntityDescriptors.IsAssignableFrom(type)) //IsClass and IsSealed and IsAbstract means only static classes + { + var warmup = typeof(EntityDescriptorTemplate<>).MakeGenericType(type); + try + { + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(warmup.TypeHandle); + } + catch + { + continue; + } + + PropertyInfo field = warmup.GetProperty("descriptor", BindingFlags.Static | BindingFlags.Public); + object value = field.GetValue(null); // pass null because the field is static + +// cast the value to your descriptor type + IEntityDescriptor descriptor = (IEntityDescriptor)value; + foreach (IComponentBuilder component in descriptor.componentsToBuild) + { + var typeArguments = component.GetEntityComponentType(); + var warmup2 = typeof(ComponentTypeID<>).MakeGenericType(typeArguments); + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(warmup2.TypeHandle); + } + } + } + } + } + } +} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/IComponentBuilder.cs b/com.sebaslab.svelto.ecs/Core/IComponentBuilder.cs index a1fb0db..ce1f4de 100644 --- a/com.sebaslab.svelto.ecs/Core/IComponentBuilder.cs +++ b/com.sebaslab.svelto.ecs/Core/IComponentBuilder.cs @@ -12,5 +12,6 @@ namespace Svelto.ECS Type GetEntityComponentType(); bool isUnmanaged { get; } + ComponentID getComponentID { get; } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs b/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs index cd93291..7129a62 100644 --- a/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs +++ b/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs @@ -18,25 +18,29 @@ namespace Svelto.ECS internal Consumer GenerateConsumer(string name, uint capacity) where T : unmanaged, _IInternalEntityComponent { - if (_streams.ContainsKey(TypeRefWrapper.wrapper) == false) - _streams[TypeRefWrapper.wrapper] = new EntityStream(); + var componentId = ComponentTypeID.id; + + if (_streams.ContainsKey(componentId) == false) + _streams[componentId] = new EntityStream(); - return (_streams[TypeRefWrapper.wrapper] as EntityStream).GenerateConsumer(name, capacity); + return (_streams[componentId] as EntityStream).GenerateConsumer(name, capacity); } public Consumer GenerateConsumer(ExclusiveGroupStruct group, string name, uint capacity) where T : unmanaged, _IInternalEntityComponent { - if (_streams.ContainsKey(TypeRefWrapper.wrapper) == false) - _streams[TypeRefWrapper.wrapper] = new EntityStream(); + var componentId = ComponentTypeID.id; + + if (_streams.ContainsKey(componentId) == false) + _streams[componentId] = new EntityStream(); - var typeSafeStream = (EntityStream) _streams[TypeRefWrapper.wrapper]; + var typeSafeStream = (EntityStream) _streams[componentId]; return typeSafeStream.GenerateConsumer(group, name, capacity); } internal void PublishEntity(ref T entity, EGID egid) where T : unmanaged, _IInternalEntityComponent { - if (_streams.TryGetValue(TypeRefWrapper.wrapper, out var typeSafeStream)) + if (_streams.TryGetValue(ComponentTypeID.id, out var typeSafeStream)) (typeSafeStream as EntityStream).PublishEntity(ref entity, egid); else Console.LogDebug($"No Consumers are waiting for this entity to change {typeof(T)}"); @@ -51,11 +55,11 @@ namespace Svelto.ECS public static EntitiesStreams Create() { var stream = new EntitiesStreams(); - stream._streams = FasterDictionary.Construct(); + stream._streams = FasterDictionary.Construct(); return stream; } - FasterDictionary _streams; + FasterDictionary _streams; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs index 2a9fb81..d93dd5a 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs @@ -39,11 +39,11 @@ namespace Svelto.ECS.Internal //This is now obsolete, but I cannot mark it as such because it's heavily used by legacy projects void ExecuteEnginesAddCallbacks - (FasterDictionary>> entityComponentEnginesDb + (FasterDictionary>> entityComponentEnginesDb , ITypeSafeDictionary destinationDatabase, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler); //Version to use void ExecuteEnginesAddEntityCallbacksFast( - FasterDictionary>> reactiveEnginesAdd, + FasterDictionary>> reactiveEnginesAdd, ExclusiveGroupStruct groupID, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler profiler); //------------ @@ -61,7 +61,7 @@ namespace Svelto.ECS.Internal //This is now obsolete, but I cannot mark it as such because it's heavily used by legacy projects void ExecuteEnginesRemoveCallbacks(FasterList<(uint, string)> infosToProcess, - FasterDictionary>> reactiveEnginesRemove, + FasterDictionary>> reactiveEnginesRemove, ExclusiveGroupStruct fromGroup, in PlatformProfiler sampler); //Version to use void ExecuteEnginesRemoveCallbacksFast(FasterList> reactiveEnginesRemoveEx, @@ -71,16 +71,16 @@ namespace Svelto.ECS.Internal //------------ void ExecuteEnginesSwapCallbacks_Group( - FasterDictionary>> reactiveEnginesSwap, - FasterDictionary>> reactiveEnginesSwapEx, + FasterDictionary>> reactiveEnginesSwap, + FasterDictionary>> reactiveEnginesSwapEx, ITypeSafeDictionary toEntitiesDictionary, ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, in PlatformProfiler platformProfiler); void ExecuteEnginesRemoveCallbacks_Group( - FasterDictionary>> engines, - FasterDictionary>> reactiveEnginesRemoveEx, + FasterDictionary>> engines, + FasterDictionary>> reactiveEnginesRemoveEx, ExclusiveGroupStruct @group, in PlatformProfiler profiler); void ExecuteEnginesDisposeCallbacks_Group - (FasterDictionary>> engines + (FasterDictionary>> engines , ExclusiveGroupStruct group, in PlatformProfiler profiler); void IncreaseCapacityBy(uint size); diff --git a/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs index 1d7b272..44825c5 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs @@ -9,13 +9,13 @@ namespace Svelto.ECS.Internal sealed class ManagedTypeSafeDictionary : ITypeSafeDictionary where TValue : struct, _IInternalEntityComponent { + //todo: would this be better to not be static to avoid overhead? static readonly ThreadLocal cachedEntityIDM = new ThreadLocal(() => new ManagedEntityIDs()); public ManagedTypeSafeDictionary(uint size) { - implMgd = - new SveltoDictionary>, ManagedStrategy, + implMgd = new SveltoDictionary>, ManagedStrategy, ManagedStrategy>(size, Allocator.Managed); } @@ -181,7 +181,7 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesAddCallbacks - (FasterDictionary>> entityComponentEnginesDB + (FasterDictionary>> entityComponentEnginesDB , ITypeSafeDictionary toDic, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesAddCallbacks(ref implMgd, (ITypeSafeDictionary)toDic @@ -207,7 +207,7 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesRemoveCallbacks (FasterList<(uint, string)> infosToProcess - , FasterDictionary>> reactiveEnginesRemove + , FasterDictionary>> reactiveEnginesRemove , ExclusiveGroupStruct fromGroup, in PlatformProfiler sampler) { TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks(infosToProcess, ref implMgd, reactiveEnginesRemove @@ -219,7 +219,7 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesAddEntityCallbacksFast - (FasterDictionary>> reactiveEnginesAdd + (FasterDictionary>> reactiveEnginesAdd , ExclusiveGroupStruct groupID, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesAddEntityCallbacksFast( @@ -257,8 +257,8 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesSwapCallbacks_Group - (FasterDictionary>> reactiveEnginesSwap - , FasterDictionary>> reactiveEnginesSwapEx + (FasterDictionary>> reactiveEnginesSwap + , FasterDictionary>> reactiveEnginesSwapEx , ITypeSafeDictionary toDictionary, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup , in PlatformProfiler profiler) { @@ -273,8 +273,8 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesRemoveCallbacks_Group - (FasterDictionary>> reactiveEnginesRemove - , FasterDictionary>> reactiveEnginesRemoveEx + (FasterDictionary>> reactiveEnginesRemove + , FasterDictionary>> reactiveEnginesRemoveEx , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks_Group( @@ -287,7 +287,7 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesDisposeCallbacks_Group - (FasterDictionary>> engines + (FasterDictionary>> engines , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group(ref implMgd, engines, group, in profiler); diff --git a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs index 10ccded..f00ceac 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs @@ -57,7 +57,7 @@ namespace Svelto.ECS.Internal public static void ExecuteEnginesAddCallbacks( ref SveltoDictionary fromDictionary , ITypeSafeDictionary todic, ExclusiveGroupStruct togroup - , FasterDictionary>> entitycomponentenginesdb + , FasterDictionary>> entitycomponentenginesdb , in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy @@ -65,7 +65,7 @@ namespace Svelto.ECS.Internal where TValue : struct, _IInternalEntityComponent { if (entitycomponentenginesdb.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var entityComponentsEngines)) { if (entityComponentsEngines.count == 0) @@ -101,14 +101,14 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ExecuteEnginesDisposeCallbacks_Group( ref SveltoDictionary fromDictionary - , FasterDictionary>> allEngines + , FasterDictionary>> allEngines , ExclusiveGroupStruct inGroup, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy where TValue : struct, _IInternalEntityComponent { - if (allEngines.TryGetValue(new RefWrapperType(TypeCache.type), out var entityComponentsEngines) + if (allEngines.TryGetValue(ComponentTypeID.id, out var entityComponentsEngines) == false) return; @@ -137,7 +137,7 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ExecuteEnginesRemoveCallbacks(FasterList<(uint, string)> infostoprocess , ref SveltoDictionary fromDictionary - , FasterDictionary>> reactiveenginesremove + , FasterDictionary>> reactiveenginesremove , ExclusiveGroupStruct fromgroup, in PlatformProfiler profiler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy @@ -145,7 +145,7 @@ namespace Svelto.ECS.Internal where TValue : struct, _IInternalEntityComponent { if (reactiveenginesremove.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var entityComponentsEngines)) { if (entityComponentsEngines.count == 0) @@ -186,8 +186,8 @@ namespace Svelto.ECS.Internal public static void ExecuteEnginesRemoveCallbacks_Group( ref SveltoDictionary fromDictionary , ITypeSafeDictionary typeSafeDictionary - , FasterDictionary>> reactiveenginesremove - , FasterDictionary>> reactiveenginesremoveex + , FasterDictionary>> reactiveenginesremove + , FasterDictionary>> reactiveenginesremoveex , int count, IEntityIDs entityids, ExclusiveGroupStruct group, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy @@ -195,7 +195,7 @@ namespace Svelto.ECS.Internal where TValue : struct, _IInternalEntityComponent { if (reactiveenginesremove.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var reactiveEnginesRemovePerType)) { var enginesCount = reactiveEnginesRemovePerType.count; @@ -226,7 +226,7 @@ namespace Svelto.ECS.Internal } if (reactiveenginesremoveex.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var reactiveEnginesRemoveExPerType)) { var enginesCount = reactiveEnginesRemoveExPerType.count; @@ -301,8 +301,8 @@ namespace Svelto.ECS.Internal ref SveltoDictionary fromDictionary , ITypeSafeDictionary toDic, ExclusiveGroupStruct togroup, ExclusiveGroupStruct fromgroup , ITypeSafeDictionary typeSafeDictionary - , FasterDictionary>> reactiveenginesswap - , FasterDictionary>> reactiveenginesswapex + , FasterDictionary>> reactiveenginesswap + , FasterDictionary>> reactiveenginesswapex , int count, IEntityIDs entityids, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy @@ -311,7 +311,7 @@ namespace Svelto.ECS.Internal { //get all the engines linked to TValue if (!reactiveenginesswap.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var reactiveEnginesSwapPerType)) return; @@ -342,7 +342,7 @@ namespace Svelto.ECS.Internal } if (reactiveenginesswapex.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var reactiveEnginesRemoveExPerType)) { var enginesCount = reactiveEnginesRemoveExPerType.count; @@ -467,14 +467,14 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ExecuteEnginesAddEntityCallbacksFast( - FasterDictionary>> fasterDictionary + FasterDictionary>> fasterDictionary , ExclusiveGroupStruct groupId, (uint, uint) rangeTuple, IEntityIDs entityids , ITypeSafeDictionary typeSafeDictionary, PlatformProfiler profiler) where TValue : struct, _IInternalEntityComponent { //get all the engines linked to TValue if (!fasterDictionary.TryGetValue( - new RefWrapperType(TypeCache.type) + ComponentTypeID.id , out var entityComponentsEngines)) return; diff --git a/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs index ea50b28..5359cd4 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs @@ -22,13 +22,13 @@ namespace Svelto.ECS.Internal sealed class UnmanagedTypeSafeDictionary : ITypeSafeDictionary where TValue : struct, _IInternalEntityComponent { + //todo: would this be better to not be static to avoid overhead? static readonly ThreadLocal cachedEntityIDN = new ThreadLocal(() => new NativeEntityIDs()); public UnmanagedTypeSafeDictionary(uint size) { - implUnmgd = - new SharedSveltoDictionaryNative(size, Allocator.Persistent); + implUnmgd = new SharedSveltoDictionaryNative(size, Allocator.Persistent); } public IEntityIDs entityIDs @@ -193,7 +193,7 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesAddCallbacks - (FasterDictionary>> entityComponentEnginesDB + (FasterDictionary>> entityComponentEnginesDB , ITypeSafeDictionary toDic, ExclusiveGroupStruct toGroup, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesAddCallbacks(ref implUnmgd.dictionary, (ITypeSafeDictionary)toDic @@ -219,7 +219,7 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesRemoveCallbacks (FasterList<(uint, string)> infosToProcess - , FasterDictionary>> reactiveEnginesRemove + , FasterDictionary>> reactiveEnginesRemove , ExclusiveGroupStruct fromGroup, in PlatformProfiler sampler) { TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks(infosToProcess, ref implUnmgd.dictionary @@ -231,7 +231,7 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesAddEntityCallbacksFast - (FasterDictionary>> reactiveEnginesAdd + (FasterDictionary>> reactiveEnginesAdd , ExclusiveGroupStruct groupID, (uint, uint) rangeOfSubmittedEntitiesIndicies, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesAddEntityCallbacksFast( @@ -269,8 +269,8 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesSwapCallbacks_Group - (FasterDictionary>> reactiveEnginesSwap - , FasterDictionary>> reactiveEnginesSwapEx + (FasterDictionary>> reactiveEnginesSwap + , FasterDictionary>> reactiveEnginesSwapEx , ITypeSafeDictionary toDictionary, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup , in PlatformProfiler profiler) { @@ -285,8 +285,8 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesRemoveCallbacks_Group - (FasterDictionary>> reactiveEnginesRemove - , FasterDictionary>> reactiveEnginesRemoveEx + (FasterDictionary>> reactiveEnginesRemove + , FasterDictionary>> reactiveEnginesRemoveEx , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks_Group( @@ -299,7 +299,7 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesDisposeCallbacks_Group - (FasterDictionary>> engines + (FasterDictionary>> engines , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group( diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs b/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs index 79b1a7c..a838428 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs @@ -143,9 +143,9 @@ namespace Svelto.ECS var typeID = buffer.Dequeue(); - IFiller entityBuilder = EntityComponentIDMap.GetTypeFromID(typeID); + IFiller componentBuilder = EntityComponentIDMap.GetBuilderFromID(typeID); //after the typeID, I expect the serialized component - entityBuilder.FillFromByteArray(init, buffer); + componentBuilder.FillFromByteArray(init, buffer); } } } diff --git a/com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeComponentFiller.cs similarity index 66% rename from com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs rename to com.sebaslab.svelto.ecs/Extensions/Native/NativeComponentFiller.cs index 1285ce6..2b860c7 100644 --- a/com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeComponentFiller.cs @@ -1,19 +1,9 @@ -using System.Threading; using Svelto.Common; using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public class GlobalTypeID - { - internal static uint NextID() { return (uint) (Interlocked.Increment(ref value) - 1); } - - static GlobalTypeID() { value = 0; } - - static int value; - } - interface IFiller { void FillFromByteArray(EntityInitializer init, NativeBag buffer); @@ -36,12 +26,6 @@ namespace Svelto.ECS } #if UNITY_NATIVE //at the moment I am still considering NativeOperations useful only for Unity - static class EntityComponentID - { - internal static readonly Unity.Burst.SharedStatic ID = - Unity.Burst.SharedStatic.GetOrCreate(); - } - static class EntityComponentIDMap { static readonly Svelto.DataStructures.FasterList TYPE_IDS; @@ -53,11 +37,11 @@ namespace Svelto.ECS internal static void Register(IFiller entityBuilder) where T : struct, _IInternalEntityComponent { - var location = EntityComponentID.ID.Data = GlobalTypeID.NextID(); + ComponentID location = ComponentTypeID.id; TYPE_IDS.AddAt(location, entityBuilder); } - internal static IFiller GetTypeFromID(uint typeId) { return TYPE_IDS[typeId]; } + internal static IFiller GetBuilderFromID(uint typeId) { return TYPE_IDS[typeId]; } } #endif } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs index f8ce312..46f4888 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs @@ -32,8 +32,7 @@ namespace Svelto.ECS.Native EntityReference reference = _entityLocator.ClaimReference(); NativeBag bagPerEntityPerThread = _addOperationQueue.GetBag(threadIndex + 1); - bagPerEntityPerThread.Enqueue( - _operationIndex); //each native operation is stored in an array, each request to perform a native operation in a queue. _index is the index of the operation in the array that will be dequeued later + bagPerEntityPerThread.Enqueue(_operationIndex); //each native operation is stored in an array, each request to perform a native operation in a queue. _index is the index of the operation in the array that will be dequeued later bagPerEntityPerThread.Enqueue(new EGID(eindex, exclusiveBuildGroup)); bagPerEntityPerThread.Enqueue(reference); diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs index 4e72dcd..d013a45 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs @@ -20,7 +20,7 @@ namespace Svelto.ECS.Native [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref T Init(in T component) where T : unmanaged, IEntityComponent { - uint componentID = EntityComponentID.ID.Data; + uint componentID = ComponentTypeID.id; _unsafeBuffer.AccessReserved(_componentsToInitializeCounterRef)++; //increase the number of components that have been initialised by the user diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs index ebf231e..4214679 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs @@ -35,7 +35,7 @@ namespace Svelto.ECS { public GroupsIterator(EntitiesDB db) : this() { - _db = db.FindGroups_INTERNAL(TypeCache.type).GetEnumerator(); + _db = db.FindGroups_INTERNAL(ComponentTypeID.id).GetEnumerator(); } public bool MoveNext() diff --git a/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs b/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs index 8e1c8d8..cb47353 100644 --- a/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs +++ b/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.CompilerServices; using Svelto.DataStructures; -using Svelto.ECS.Internal; using Svelto.ECS.Serialization; namespace Svelto.ECS @@ -208,7 +207,7 @@ namespace Svelto.ECS ISerializationData serializationData, int serializationType) { ExclusiveGroupStruct groupId = entityGID.groupID; - Type entityType = componentBuilder.GetEntityComponentType(); + var entityType = componentBuilder.getComponentID; if (!_enginesRoot._entitiesDB.UnsafeQueryEntityDictionary(groupId, entityType, out var safeDictionary)) { throw new Exception("Entity Serialization failed"); @@ -230,7 +229,7 @@ namespace Svelto.ECS foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize) { entitiesInGroupPerType.TryGetValue( - new RefWrapperType(serializableEntityBuilder.GetEntityComponentType()), out var safeDictionary); + serializableEntityBuilder.getComponentID, out var safeDictionary); serializationData.BeginNextEntityComponent(); serializableEntityBuilder.Deserialize(egid.entityID, safeDictionary, serializationData, diff --git a/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs b/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs index 08b68b7..c1bf424 100644 --- a/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs +++ b/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs @@ -1,5 +1,4 @@ using System.Runtime.CompilerServices; -using Svelto.ECS.Internal; namespace Svelto.ECS.Serialization { diff --git a/com.sebaslab.svelto.ecs/Serialization/SerializableEntityDescriptor.cs b/com.sebaslab.svelto.ecs/Serialization/SerializableEntityDescriptor.cs index 7878d4b..b0613f3 100644 --- a/com.sebaslab.svelto.ecs/Serialization/SerializableEntityDescriptor.cs +++ b/com.sebaslab.svelto.ecs/Serialization/SerializableEntityDescriptor.cs @@ -16,7 +16,7 @@ namespace Svelto.ECS.Serialization { static SerializableEntityDescriptor() { - IComponentBuilder[] defaultEntities = EntityDescriptorTemplate.descriptor.componentsToBuild; + IComponentBuilder[] defaultEntities = EntityDescriptorTemplate.realDescriptor.componentsToBuild; var hashNameAttribute = Type.GetCustomAttribute(); if (hashNameAttribute == null) @@ -49,13 +49,12 @@ namespace Svelto.ECS.Serialization ///// var entitiesToSerialize = new FasterList(); - EntityComponentsToSerializeMap = new FasterDictionary(); + EntityComponentsToSerializeMap = new FasterDictionary(); foreach (IComponentBuilder e in defaultEntities) { if (e is ISerializableComponentBuilder serializableEntityBuilder) { - var entityType = serializableEntityBuilder.GetEntityComponentType(); - EntityComponentsToSerializeMap[new RefWrapperType(entityType)] = serializableEntityBuilder; + EntityComponentsToSerializeMap[serializableEntityBuilder.getComponentID] = serializableEntityBuilder; entitiesToSerialize.Add(serializableEntityBuilder); } } @@ -99,7 +98,7 @@ namespace Svelto.ECS.Serialization public ISerializableComponentBuilder[] componentsToSerialize => EntitiesToSerialize; static readonly IComponentBuilder[] ComponentsToBuild; - static readonly FasterDictionary EntityComponentsToSerializeMap; + static readonly FasterDictionary EntityComponentsToSerializeMap; static readonly ISerializableComponentBuilder[] EntitiesToSerialize; static readonly uint Hash; diff --git a/com.sebaslab.svelto.ecs/Svelto.ECS.csproj b/com.sebaslab.svelto.ecs/Svelto.ECS.csproj index f68ec94..87fa700 100644 --- a/com.sebaslab.svelto.ecs/Svelto.ECS.csproj +++ b/com.sebaslab.svelto.ecs/Svelto.ECS.csproj @@ -1,11 +1,11 @@  Svelto.ECS - 9 + 10 netstandard2.1 Svelto - 3.4.3 - 3.4.3 + 3.4 + true Debug;Release;SlowSubmissionRelease;SlowSubmissionDebug AnyCPU diff --git a/com.sebaslab.svelto.ecs/package.json b/com.sebaslab.svelto.ecs/package.json index 0ad09cd..8cc7fb1 100644 --- a/com.sebaslab.svelto.ecs/package.json +++ b/com.sebaslab.svelto.ecs/package.json @@ -11,7 +11,7 @@ "url": "https://github.com/sebas77/Svelto.ECS.git" }, "dependencies": { - "com.sebaslab.svelto.common": "3.4.1" + "com.sebaslab.svelto.common": "3.4.2" }, "keywords": [ "svelto", @@ -19,7 +19,7 @@ "svelto.ecs" ], "name": "com.sebaslab.svelto.ecs", - "version": "3.4.3", + "version": "3.4.4", "type": "library", "unity": "2020.3" } diff --git a/com.sebaslab.svelto.ecs/version.json b/com.sebaslab.svelto.ecs/version.json index 4c49bb1..28ff4ef 100644 --- a/com.sebaslab.svelto.ecs/version.json +++ b/com.sebaslab.svelto.ecs/version.json @@ -1,3 +1,3 @@ { - "version": "3.4.3" + "version": "3.4.4" } From 193e0f99a01da5587a5e54da810d37e3fc26cd53 Mon Sep 17 00:00:00 2001 From: Sebastiano Mandala Date: Sat, 1 Apr 2023 19:23:47 +0100 Subject: [PATCH 2/2] add IReactOnDisposeEx interface --- com.sebaslab.svelto.common | 2 +- .../Core/EnginesRoot.Engines.cs | 10 +++- com.sebaslab.svelto.ecs/Core/IEngine.cs | 10 ++++ .../DataStructures/ITypeSafeDictionary.cs | 7 +-- .../ManagedTypeSafeDictionary.cs | 14 +++--- .../TypeSafeDictionaryMethods.cs | 50 +++++++++++++++---- .../UnmanagedTypeSafeDictionary.cs | 11 ++-- 7 files changed, 78 insertions(+), 26 deletions(-) diff --git a/com.sebaslab.svelto.common b/com.sebaslab.svelto.common index 9a74e5c..114ce56 160000 --- a/com.sebaslab.svelto.common +++ b/com.sebaslab.svelto.common @@ -1 +1 @@ -Subproject commit 9a74e5c70681d4f2f5156b48cdd578dfcf6cfc4e +Subproject commit 114ce56f5efe5b5a2a8326ef55587ca668e72503 diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs index 18e7fc3..e196789 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs @@ -64,6 +64,8 @@ namespace Svelto.ECS new FasterDictionary>>(); _reactiveEnginesDispose = new FasterDictionary>>(); + _reactiveEnginesDisposeEx = + new FasterDictionary>>(); _reactiveEnginesSubmission = new FasterList(); _reactiveEnginesSubmissionStarted = new FasterList(); @@ -151,6 +153,10 @@ namespace Svelto.ECS if (engine is IReactOnDispose viewEngineDispose) CheckReactEngineComponents( typeof(IReactOnDispose<>), viewEngineDispose, _reactiveEnginesDispose, type.Name); + + if (engine is IReactOnDisposeEx viewEngineDisposeEx) + CheckReactEngineComponents( + typeof(IReactOnDisposeEx<>), viewEngineDisposeEx, _reactiveEnginesDisposeEx, type.Name); if (engine is IReactOnSwap viewEngineSwap) #pragma warning disable CS0612 @@ -263,7 +269,7 @@ namespace Svelto.ECS ITypeSafeDictionary typeSafeDictionary = entityList.value; typeSafeDictionary.ExecuteEnginesDisposeCallbacks_Group( - _reactiveEnginesDispose, groups.key, + _reactiveEnginesDispose, _reactiveEnginesDisposeEx, groups.key, profiler); } catch (Exception e) @@ -300,6 +306,7 @@ namespace Svelto.ECS _reactiveEnginesAdd.Clear(); _reactiveEnginesRemove.Clear(); _reactiveEnginesDispose.Clear(); + _reactiveEnginesDisposeEx.Clear(); _reactiveEnginesSubmission.Clear(); _reactiveEnginesSubmissionStarted.Clear(); @@ -410,6 +417,7 @@ namespace Svelto.ECS readonly FasterDictionary>> _reactiveEnginesSwap; readonly FasterDictionary>> _reactiveEnginesSwapEx; readonly FasterDictionary>> _reactiveEnginesDispose; + readonly FasterDictionary>> _reactiveEnginesDisposeEx; readonly FasterList _reactiveEnginesSubmission; readonly FasterList _reactiveEnginesSubmissionStarted; diff --git a/com.sebaslab.svelto.ecs/Core/IEngine.cs b/com.sebaslab.svelto.ecs/Core/IEngine.cs index 271e26c..c622fc1 100644 --- a/com.sebaslab.svelto.ecs/Core/IEngine.cs +++ b/com.sebaslab.svelto.ecs/Core/IEngine.cs @@ -40,6 +40,10 @@ namespace Svelto.ECS.Internal public interface IReactOnSwapEx : IReactEngine { } + + public interface IReactOnDisposeEx : IReactEngine + { + } public interface IReactOnDispose : IReactEngine { @@ -132,6 +136,12 @@ namespace Svelto.ECS void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection entities, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup); } + + public interface IReactOnDisposeEx : IReactOnDisposeEx where T : struct, _IInternalEntityComponent + { + void Remove((uint start, uint end) rangeOfEntities, in EntityCollection entities, + ExclusiveGroupStruct groupID); + } /// /// Interface to mark an Engine as reacting after each entities submission phase diff --git a/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs index d93dd5a..5ad6fb5 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs @@ -76,12 +76,13 @@ namespace Svelto.ECS.Internal ITypeSafeDictionary toEntitiesDictionary, ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, in PlatformProfiler platformProfiler); void ExecuteEnginesRemoveCallbacks_Group( - FasterDictionary>> engines, + FasterDictionary>> reactiveEnginesRemove, FasterDictionary>> reactiveEnginesRemoveEx, ExclusiveGroupStruct @group, in PlatformProfiler profiler); void ExecuteEnginesDisposeCallbacks_Group - (FasterDictionary>> engines - , ExclusiveGroupStruct group, in PlatformProfiler profiler); + (FasterDictionary>> reactiveEnginesDispose, + FasterDictionary>> reactiveEnginesDisposeEx, + ExclusiveGroupStruct group, in PlatformProfiler profiler); void IncreaseCapacityBy(uint size); void EnsureCapacity(uint size); diff --git a/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs index 44825c5..1581585 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs @@ -263,8 +263,8 @@ namespace Svelto.ECS.Internal , in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacks_Group( - ref implMgd, (ITypeSafeDictionary)toDictionary, toGroup, fromGroup, this, reactiveEnginesSwap - , reactiveEnginesSwapEx, count, entityIDs, in profiler); + ref implMgd, (ITypeSafeDictionary)toDictionary, toGroup, fromGroup, reactiveEnginesSwap + , reactiveEnginesSwapEx, entityIDs, in profiler); } /// @@ -278,7 +278,7 @@ namespace Svelto.ECS.Internal , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks_Group( - ref implMgd, this, reactiveEnginesRemove, reactiveEnginesRemoveEx, count, entityIDs, group + ref implMgd, reactiveEnginesRemove, reactiveEnginesRemoveEx, entityIDs, group , in profiler); } @@ -287,10 +287,12 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesDisposeCallbacks_Group - (FasterDictionary>> engines - , ExclusiveGroupStruct group, in PlatformProfiler profiler) + (FasterDictionary>> reactiveEnginesDispose, + FasterDictionary>> reactiveEnginesDisposeEx, + ExclusiveGroupStruct group, in PlatformProfiler profiler) { - TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group(ref implMgd, engines, group, in profiler); + TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group( + ref implMgd, reactiveEnginesDispose, reactiveEnginesDisposeEx, entityIDs, group, in profiler); } SveltoDictionary>, ManagedStrategy, diff --git a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs index f00ceac..b58844c 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs @@ -101,14 +101,15 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ExecuteEnginesDisposeCallbacks_Group( ref SveltoDictionary fromDictionary - , FasterDictionary>> allEngines - , ExclusiveGroupStruct inGroup, in PlatformProfiler sampler) + , FasterDictionary>> reactiveEnginesDispose + , FasterDictionary>> reactiveEnginesDisposeEx + , IEntityIDs entityids, ExclusiveGroupStruct group, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy where TValue : struct, _IInternalEntityComponent { - if (allEngines.TryGetValue(ComponentTypeID.id, out var entityComponentsEngines) + if (reactiveEnginesDispose.TryGetValue(ComponentTypeID.id, out var entityComponentsEngines) == false) return; @@ -120,7 +121,7 @@ namespace Svelto.ECS.Internal foreach (var value in fromDictionary) { ref var entity = ref value.value; - var egid = new EGID(value.key, inGroup); + var egid = new EGID(value.key, group); var reactOnRemove = (IReactOnDispose)entityComponentsEngines[i].engine; reactOnRemove.Remove(ref entity, egid); } @@ -132,6 +133,35 @@ namespace Svelto.ECS.Internal throw; } + + + var count = fromDictionary.count; + + if (reactiveEnginesDisposeEx.TryGetValue( + ComponentTypeID.id + , out var reactiveEnginesDisposeExPerType)) + { + var enginesCount = reactiveEnginesDisposeExPerType.count; + + for (var i = 0; i < enginesCount; i++) + try + { + using (sampler.Sample(reactiveEnginesDisposeExPerType[i].name)) + { + ((IReactOnDisposeEx)reactiveEnginesDisposeExPerType[i].engine).Remove( + (0, (uint)count) + , new EntityCollection( + fromDictionary.UnsafeGetValues(out _), entityids + , (uint)count), group); + } + } + catch + { + Console.LogError("Code crashed inside Remove callback ".FastConcat(reactiveEnginesDisposeExPerType[i].name)); + + throw; + } + } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -185,10 +215,9 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ExecuteEnginesRemoveCallbacks_Group( ref SveltoDictionary fromDictionary - , ITypeSafeDictionary typeSafeDictionary , FasterDictionary>> reactiveenginesremove , FasterDictionary>> reactiveenginesremoveex - , int count, IEntityIDs entityids, ExclusiveGroupStruct group, in PlatformProfiler sampler) + , IEntityIDs entityids, ExclusiveGroupStruct group, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy @@ -229,6 +258,7 @@ namespace Svelto.ECS.Internal ComponentTypeID.id , out var reactiveEnginesRemoveExPerType)) { + var count = fromDictionary.count; var enginesCount = reactiveEnginesRemoveExPerType.count; for (var i = 0; i < enginesCount; i++) @@ -239,7 +269,7 @@ namespace Svelto.ECS.Internal ((IReactOnRemoveEx)reactiveEnginesRemoveExPerType[i].engine).Remove( (0, (uint)count) , new EntityCollection( - typeSafeDictionary.GetValues(out _), entityids + fromDictionary.UnsafeGetValues(out _), entityids , (uint)count), group); } } @@ -300,10 +330,9 @@ namespace Svelto.ECS.Internal public static void ExecuteEnginesSwapCallbacks_Group( ref SveltoDictionary fromDictionary , ITypeSafeDictionary toDic, ExclusiveGroupStruct togroup, ExclusiveGroupStruct fromgroup - , ITypeSafeDictionary typeSafeDictionary , FasterDictionary>> reactiveenginesswap , FasterDictionary>> reactiveenginesswapex - , int count, IEntityIDs entityids, in PlatformProfiler sampler) + , IEntityIDs entityids, in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy @@ -346,6 +375,7 @@ namespace Svelto.ECS.Internal , out var reactiveEnginesRemoveExPerType)) { var enginesCount = reactiveEnginesRemoveExPerType.count; + var count = fromDictionary.count; for (var i = 0; i < enginesCount; i++) try @@ -355,7 +385,7 @@ namespace Svelto.ECS.Internal ((IReactOnSwapEx)reactiveEnginesRemoveExPerType[i].engine).MovedTo( (0, (uint)count) , new EntityCollection( - typeSafeDictionary.GetValues(out _), entityids + fromDictionary.UnsafeGetValues(out _), entityids , (uint)count), fromgroup, togroup); } } diff --git a/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs index 5359cd4..2a2ae60 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs @@ -275,8 +275,8 @@ namespace Svelto.ECS.Internal , in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesSwapCallbacks_Group( - ref implUnmgd.dictionary, (ITypeSafeDictionary)toDictionary, toGroup, fromGroup, this - , reactiveEnginesSwap, reactiveEnginesSwapEx, count, entityIDs, in profiler); + ref implUnmgd.dictionary, (ITypeSafeDictionary)toDictionary, toGroup, fromGroup + , reactiveEnginesSwap, reactiveEnginesSwapEx, entityIDs, in profiler); } /// @@ -290,7 +290,7 @@ namespace Svelto.ECS.Internal , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesRemoveCallbacks_Group( - ref implUnmgd.dictionary, this, reactiveEnginesRemove, reactiveEnginesRemoveEx, count, entityIDs, group + ref implUnmgd.dictionary, reactiveEnginesRemove, reactiveEnginesRemoveEx, entityIDs, group , in profiler); } @@ -299,11 +299,12 @@ namespace Svelto.ECS.Internal /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesDisposeCallbacks_Group - (FasterDictionary>> engines + ( FasterDictionary>> reactiveEnginesDispose + , FasterDictionary>> reactiveEnginesDisposeEx , ExclusiveGroupStruct group, in PlatformProfiler profiler) { TypeSafeDictionaryMethods.ExecuteEnginesDisposeCallbacks_Group( - ref implUnmgd.dictionary, engines, group, in profiler); + ref implUnmgd.dictionary, reactiveEnginesDispose, reactiveEnginesDisposeEx, entityIDs, group, in profiler); } internal SharedSveltoDictionaryNative implUnmgd;