From ce29abeedcd7ce2d6db9eb5c9c950b2a451c7ae1 Mon Sep 17 00:00:00 2001 From: Sebastiano Mandala Date: Sat, 4 Mar 2023 18:06:18 +0000 Subject: [PATCH] Update to Svelto.ECS 3.4 --- com.sebaslab.svelto.common | 2 +- com.sebaslab.svelto.ecs/CHANGELOG.md | 21 +- .../Core/CheckEntityUtilities.cs | 7 +- .../Core/ComponentBuilder.cs | 26 +- com.sebaslab.svelto.ecs/Core/EGIDMapper.cs | 2 +- ...EnginesRoot.DoubleBufferedEntitiesToAdd.cs | 8 +- .../Core/EnginesRoot.Engines.cs | 177 +++--- .../Core/EnginesRoot.Entities.cs | 3 +- .../Core/EnginesRoot.GenericEntityFactory.cs | 20 +- .../EnginesRoot.GenericEntityFunctions.cs | 8 +- .../Core/EnginesRoot.Submission.cs | 219 ++++---- com.sebaslab.svelto.ecs/Core/EntitiesDB.cs | 66 ++- .../Core/EntitiesOperations.cs | 213 +++++--- .../Core/EntityCollection.cs | 20 +- .../DynamicEntityDescriptor.cs | 11 +- .../ExtendibleEntityDescriptor.cs | 8 +- .../GenericEntityDescriptor.cs | 96 ++-- .../Core/EntityInfoView.cs | 5 +- .../Core/EntityInitializer.cs | 30 +- .../EntityReference/EnginesRoot.LocatorMap.cs | 81 +-- .../EntityReference/EntitiesDB.References.cs | 6 + .../Core/EntityReference/EntityReference.cs | 11 +- .../Core/EntitySubmitOperation.cs | 10 - .../Core/EntityViewUtility.cs | 4 +- .../Core/Filters/CombinedFilterID.cs | 20 + .../Core/Filters/EnginesRoot.Filters.cs | 8 +- .../Core/Filters/EntitiesDB.Filters.cs | 312 ++++++----- .../Core/Filters/EntityFilterCollection.cs | 34 +- .../Core/Filters/FilterContextID.cs | 19 + .../{ => Legacy}/EntitiesDB.LegacyFilters.cs | 25 +- .../Filters/{ => Legacy}/LegacyFilterGroup.cs | 12 +- .../{ => Legacy}/LegacyFilteredIndices.cs | 8 +- .../{ => Legacy}/LegacyGroupFilters.cs | 8 +- .../Filters/NativeEntityFilterCollection.cs | 7 +- .../Filters/NativeEntityFilterIterator.cs | 6 +- com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs | 9 +- .../Core/Groups/EntitiesDB.FindGroups.cs | 59 +- .../Core/Groups/ExclusiveBuildGroup.cs | 2 +- .../Core/Groups/ExclusiveGroupStruct.cs | 13 +- .../Core/Groups/GroupCompound.cs | 113 ++-- .../Core/Groups/GroupHashMap.cs | 27 +- .../Core/Groups/GroupNamesMap.cs | 4 +- .../Core/Groups/QueryGroups.cs | 7 +- .../Core/Hybrid/IEntityViewComponent.cs | 6 +- .../Core/IBaseEntityComponent.cs | 11 - com.sebaslab.svelto.ecs/Core/IEngine.cs | 38 +- .../Core/IEntityComponent.cs | 9 + .../Core/SetEGIDWithoutBoxing.cs | 6 +- .../DoubleIterationEnumerator.cs | 43 +- .../Core/Streams/Consumer.cs | 11 +- .../Core/Streams/EnginesRoot.Streams.cs | 5 +- .../Core/Streams/EntitiesStreams.cs | 9 +- .../Core/Streams/EntityStream.cs | 3 +- .../GenericentityStreamConsumerFactory.cs | 9 +- .../Core/TypeSafeDictionaryFactory.cs | 12 +- .../Core/_IInternalEntityComponent.cs | 10 + .../DataStructures/ITypeSafeDictionary.cs | 2 +- .../ManagedTypeSafeDictionary.cs | 16 +- .../TypeSafeDictionaryMethods.cs | 38 +- .../TypeSafeDictionaryUtilities.cs | 2 +- .../Unmanaged/AtomicNativeBags.cs | 87 --- .../DataStructures/Unmanaged/NativeBag.cs | 204 ------- .../Unmanaged/NativeDynamicArray.cs | 516 ------------------ .../Unmanaged/NativeDynamicArrayCast.cs | 82 --- .../NativeDynamicArrayUnityExtension.cs | 23 - .../Unmanaged/SharedDisposableNative.cs | 47 -- .../Unmanaged/SharedNativeInt.cs | 127 ----- .../DataStructures/Unmanaged/UnsafeArray.cs | 147 ----- .../DataStructures/Unmanaged/UnsafeBlob.cs | 272 --------- .../UnmanagedTypeSafeDictionary.cs | 9 +- .../ECSResources/ECSResourceManager.cs | 49 ++ .../ECSResources/ECSResources.cs | 9 +- .../ECSResources/ECSString.cs | 2 +- .../Extensions/DisposeDisposablesEngine.cs | 24 - .../Native/EnginesRoot.NativeOperation.cs | 12 +- .../Native/EntityNativeDBExtensions.cs | 10 + .../Extensions/Native/NativeEGIDMapper.cs | 4 +- .../Native/NativeEGIDMultiMapper.cs | 5 +- .../Extensions/Native/NativeEntityFactory.cs | 40 +- .../Native/NativeEntityInitializer.cs | 28 +- .../Extensions/Native/NativeEntityRemove.cs | 4 +- .../Extensions/Native/NativeEntitySwap.cs | 6 +- .../Native/UnityNativeEntityDBExtensions.cs | 3 +- .../Extensions/ProcessorCount.cs | 4 +- .../Extensions/Svelto/AllGroupsEnumerable.cs | 22 +- .../Extensions/Svelto/EGIDMultiMapper.cs | 3 +- .../Svelto/EntityCollectionExtension.cs | 354 ++++++------ .../Svelto/EntityManagedDBExtensions.cs | 5 +- .../Svelto/ExclusiveGroupExtensions.cs | 1 + .../Extensions/Svelto/GroupsEnumerable.cs | 20 +- .../EntitiesDBFiltersExtension.cs | 6 +- .../{ => Legacy}/FilterGroupExtensions.cs | 6 +- .../Unity/DOTS/Jobs/UnityJobExtensions.cs | 6 +- .../DOTS/UECS/DOTSOperationsForSvelto.cs | 257 +++++++++ .../Unity/DOTS/UECS/DOTSSveltoEGID.cs | 55 -- .../DOTS/UECS/EntityCommandBufferForSvelto.cs | 215 -------- .../Unity/DOTS/UECS/SveltoOnDOTSComponents.cs | 61 +++ .../DOTS/UECS/SveltoOnDOTSCreationEngine.cs | 17 + .../DOTS/UECS/SveltoOnDOTSEnginesGroup.cs | 55 +- .../SveltoOnDOTSEntitiesSubmissionGroup.cs | 174 ++---- .../UECS/SveltoOnDOTSHandleCreationEngine.cs | 60 -- .../UECS/SveltoOnDOTSHandleLifeTimeEngine.cs | 57 +- .../Unity/DOTS/UECS/SyncSveltoToDOTSGroup.cs | 9 +- .../GameObjects/EntityDescriptorHolder.cs | 69 --- .../GenericEntityDescriptorHolder.cs | 29 - .../Unity/GameObjects/ListToPopupDrawer.cs | 43 -- .../ComposedComponentSerializer.cs | 5 +- .../Serialization/DefaultSerializer.cs | 13 +- .../Serialization/DefaultSerializerUtils.cs | 6 +- .../Serialization/DontSerialize.cs | 4 +- .../EnginesRoot.GenericEntitySerialization.cs | 7 +- .../EnginesRoot.SerializableEntityHeader.cs | 8 +- .../Serialization/IComponentSerializer.cs | 4 +- .../Serialization/IEntitySerialization.cs | 3 +- .../ISerializableComponentBuilder.cs | 2 +- .../Serialization/PartialSerializer.cs | 3 +- .../SerializableComponentBuilder.cs | 62 +-- .../Serialization/SerializerExt.cs | 6 +- com.sebaslab.svelto.ecs/Svelto.ECS.asmdef | 26 +- com.sebaslab.svelto.ecs/Svelto.ECS.csproj | 12 +- com.sebaslab.svelto.ecs/package.json | 4 +- com.sebaslab.svelto.ecs/version.json | 2 +- 122 files changed, 2087 insertions(+), 3295 deletions(-) delete mode 100644 com.sebaslab.svelto.ecs/Core/EntitySubmitOperation.cs create mode 100644 com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs create mode 100644 com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs rename com.sebaslab.svelto.ecs/Core/Filters/{ => Legacy}/EntitiesDB.LegacyFilters.cs (93%) rename com.sebaslab.svelto.ecs/Core/Filters/{ => Legacy}/LegacyFilterGroup.cs (97%) rename com.sebaslab.svelto.ecs/Core/Filters/{ => Legacy}/LegacyFilteredIndices.cs (92%) rename com.sebaslab.svelto.ecs/Core/Filters/{ => Legacy}/LegacyGroupFilters.cs (97%) delete mode 100644 com.sebaslab.svelto.ecs/Core/IBaseEntityComponent.cs create mode 100644 com.sebaslab.svelto.ecs/Core/IEntityComponent.cs create mode 100644 com.sebaslab.svelto.ecs/Core/_IInternalEntityComponent.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/AtomicNativeBags.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeBag.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArray.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayCast.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayUnityExtension.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedDisposableNative.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedNativeInt.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeArray.cs delete mode 100644 com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeBlob.cs create mode 100644 com.sebaslab.svelto.ecs/ECSResources/ECSResourceManager.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/DisposeDisposablesEngine.cs rename com.sebaslab.svelto.ecs/Extensions/Svelto/{ => Legacy}/EntitiesDBFiltersExtension.cs (88%) rename com.sebaslab.svelto.ecs/Extensions/Svelto/{ => Legacy}/FilterGroupExtensions.cs (91%) create mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSOperationsForSvelto.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSSveltoEGID.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/EntityCommandBufferForSvelto.cs create mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSComponents.cs create mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSCreationEngine.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleCreationEngine.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/EntityDescriptorHolder.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/GenericEntityDescriptorHolder.cs delete mode 100644 com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/ListToPopupDrawer.cs diff --git a/com.sebaslab.svelto.common b/com.sebaslab.svelto.common index d753000..ff24942 160000 --- a/com.sebaslab.svelto.common +++ b/com.sebaslab.svelto.common @@ -1 +1 @@ -Subproject commit d75300010cb12c0aa80e5f7a4c7c425c07f4bcf2 +Subproject commit ff24942680a5e5d257541ed857a140e62525fe45 diff --git a/com.sebaslab.svelto.ecs/CHANGELOG.md b/com.sebaslab.svelto.ecs/CHANGELOG.md index 50e78fe..af6e1a0 100644 --- a/com.sebaslab.svelto.ecs/CHANGELOG.md +++ b/com.sebaslab.svelto.ecs/CHANGELOG.md @@ -1,10 +1,29 @@ # Changelog All notable changes to this project will be documented in this file. Changes are listed in random order of importance. +## [3.4.0] - 03-2023 +~~~~ +* removed static caches used in performance critical paths as they were causing unexpected performance issues (the fetching of static data is slower than i imagined) +* add Native prefix in front of the native memory utilities method names +* largely improved the console logger system +* minor improvements to the platform profiler structs +* improvements to the ThreadSafeObjectPool class (some refactoring too) +* added several datastructures previously belonging to Svelto.ECS +* all the FastClear methods are gone. The standard clear method now is aware of the type used and will clear it in the fastest way possible +* MemClear is added in case memory needs to be cleared explicitly +* added new SveltoStream, Unmanaged and Managed stream classes, their use case will be documented one day +* renamed the Svelto.Common.DataStructures namespace to Svelto.DataStructures +* added FixedTypedArray* methods. Fixed size arrays embedded in structs are now possible +* FasterList extension to convert to Span and ByteSpan +* Fix reported bugs +* Minor Svelto Dictionary improvements +* Added ValueContainer, a simple int, Tvalue dictionary based on sparse set. It has very specific use cases at the moment. Mainly to be used for the new ECS OOP Abstraction resoruce manager + + ## [3.3.2] - 04-06-2022 * Internal refactoring to support future features. Currently it may translate to a small performance boost -* IEntityComponent and IEntityViewComponent now implements IBaseEntityComponent. This shouldn't affect existing code +* IEntityComponent and IEntityViewComponent now implements _IInternalEntityComponent. This shouldn't affect existing code * Improve thread-safety of entity building * Fixed serious bug that affected the integrity of the EntityIDs values during RemoveEX callbacks * The point above may result in a performance boost in the Filters updates during submission diff --git a/com.sebaslab.svelto.ecs/Core/CheckEntityUtilities.cs b/com.sebaslab.svelto.ecs/Core/CheckEntityUtilities.cs index 7d82a4d..77634a3 100644 --- a/com.sebaslab.svelto.ecs/Core/CheckEntityUtilities.cs +++ b/com.sebaslab.svelto.ecs/Core/CheckEntityUtilities.cs @@ -4,7 +4,6 @@ using System.Diagnostics; #endif using System; using System.Collections.Generic; -using Svelto.DataStructures; namespace Svelto.ECS { @@ -86,9 +85,9 @@ namespace Svelto.ECS #if DONT_USE [Conditional("MEANINGLESS")] #endif - void ClearDebugChecks() { _multipleOperationOnSameEGIDChecker.FastClear(); } + void ClearDebugChecks() { _multipleOperationOnSameEGIDChecker.Clear(); } - readonly FasterDictionary _multipleOperationOnSameEGIDChecker; - readonly FasterDictionary> _idChecker; + readonly Svelto.DataStructures.FasterDictionary _multipleOperationOnSameEGIDChecker; + readonly Svelto.DataStructures.FasterDictionary> _idChecker; } } \ 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 75742ce..b601516 100644 --- a/com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs +++ b/com.sebaslab.svelto.ecs/Core/ComponentBuilder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection; using System.Threading; @@ -29,23 +29,30 @@ namespace Svelto.ECS public static int counter; } - public class ComponentID where T : struct, IBaseEntityComponent + public class ComponentID where T : struct, _IInternalEntityComponent { public static readonly SharedStaticWrapper> id; -#if UNITY_BURST + //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() + { + Init(); + } + +#if UNITY_BURST [Unity.Burst.BurstDiscard] //SharedStatic values must be initialized from not burstified code #endif - public static void Init() + static void Init() { id.Data = Interlocked.Increment(ref BurstCompatibleCounter.counter); - + DBC.ECS.Check.Ensure(id.Data < ushort.MaxValue, "too many types registered, HOW :)"); } } - public class ComponentBuilder : IComponentBuilder where T : struct, IBaseEntityComponent + public class ComponentBuilder : IComponentBuilder where T : struct, _IInternalEntityComponent { internal static readonly Type ENTITY_COMPONENT_TYPE; internal static readonly bool IS_ENTITY_VIEW_COMPONENT; @@ -69,9 +76,8 @@ namespace Svelto.ECS SetEGIDWithoutBoxing.Warmup(); #endif - ComponentID.Init(); ENTITY_COMPONENT_NAME = ENTITY_COMPONENT_TYPE.ToString(); - IS_UNMANAGED = TypeType.isUnmanaged(); //attention this is important as it serves as warm up for Type + IS_UNMANAGED = TypeCache.isUnmanaged; //attention this is important as it serves as warm up for Type #if UNITY_NATIVE if (IS_UNMANAGED) EntityComponentIDMap.Register(new Filler()); @@ -86,7 +92,7 @@ namespace Svelto.ECS else { if (ENTITY_COMPONENT_TYPE != ComponentBuilderUtilities.ENTITY_INFO_COMPONENT && - ENTITY_COMPONENT_TYPE.IsUnmanagedEx() == false) + TypeCache.isUnmanaged == false) throw new Exception( $"Entity Component check failed, unexpected struct type (must be unmanaged) {ENTITY_COMPONENT_TYPE}"); } @@ -104,7 +110,7 @@ namespace Svelto.ECS public bool isUnmanaged => IS_UNMANAGED; - static ThreadLocal _localCache = new ThreadLocal(() => new EntityViewComponentCache()); + static readonly ThreadLocal _localCache = new ThreadLocal(() => new EntityViewComponentCache()); public void BuildEntityAndAddToList(ITypeSafeDictionary dictionary, EGID egid, IEnumerable implementors) { diff --git a/com.sebaslab.svelto.ecs/Core/EGIDMapper.cs b/com.sebaslab.svelto.ecs/Core/EGIDMapper.cs index a0a4c54..41305ca 100644 --- a/com.sebaslab.svelto.ecs/Core/EGIDMapper.cs +++ b/com.sebaslab.svelto.ecs/Core/EGIDMapper.cs @@ -8,7 +8,7 @@ namespace Svelto.ECS /// /// /// - public readonly struct EGIDMapper : IEGIDMapper where T : struct, IBaseEntityComponent + public readonly struct EGIDMapper : IEGIDMapper where T : struct, _IInternalEntityComponent { public int count => _map.count; public ExclusiveGroupStruct groupID { get; } diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs index a9ebeb9..0acf4fc 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs @@ -54,8 +54,8 @@ namespace Svelto.ECS } //reset the number of entities created so far - _lastNumberEntitiesCreatedPerGroup.FastClear(); - lastComponentsToAddPerGroup.FastClear(); + _lastNumberEntitiesCreatedPerGroup.Clear(); + lastComponentsToAddPerGroup.Clear(); return; } @@ -81,12 +81,12 @@ namespace Svelto.ECS for (var j = 0; j < componentTypesCount; ++j) componentTypesDictionary[j].Dispose(); - componentDictionariesPerType[i].FastClear(); + componentDictionariesPerType[i].Clear(); } } //reset the number of entities created so far - _lastNumberEntitiesCreatedPerGroup.FastClear(); + _lastNumberEntitiesCreatedPerGroup.Clear(); // _totalEntitiesToAdd = 0; } diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs index d297e77..eb28e5a 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Engines.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using DBC.ECS; using Svelto.Common; -using Svelto.Common.DataStructures; using Svelto.DataStructures; using Svelto.ECS.Internal; using Svelto.ECS.Schedulers; @@ -18,13 +17,13 @@ namespace Svelto.ECS static EnginesRoot() { GroupHashMap.Init(); - SharedDictonary.Init(); + //SharedDictonary.Init(); SerializationDescriptorMap.Init(); - _swapEntities = SwapEntities; + _swapEntities = SwapEntities; _removeEntities = RemoveEntities; - _removeGroup = RemoveGroup; - _swapGroup = SwapGroup; + _removeGroup = RemoveGroup; + _swapGroup = SwapGroup; } /// @@ -37,18 +36,18 @@ namespace Svelto.ECS /// public EnginesRoot(EntitiesSubmissionScheduler entitiesComponentScheduler) { - _entitiesOperations = new EntitiesOperations(); - _idChecker = new FasterDictionary>(); + _entitiesOperations = new EntitiesOperations(); + _idChecker = new FasterDictionary>(); - _cachedRangeOfSubmittedIndices = new FasterList<(uint, uint)>(); - _transientEntityIDsLeftAndAffectedByRemoval = new FasterList(); + _cachedRangeOfSubmittedIndices = new FasterList<(uint, uint)>(); + _transientEntityIDsLeftAndAffectedByRemoval = new FasterList(); _transientEntityIDsLeftWithoutDuplicates = new FasterDictionary(); - - _multipleOperationOnSameEGIDChecker = new FasterDictionary(); + + _multipleOperationOnSameEGIDChecker = new FasterDictionary(); #if UNITY_NATIVE //because of the thread count, ATM this is only for unity - _nativeSwapOperationQueue = new Svelto.ECS.DataStructures.AtomicNativeBags(Allocator.Persistent); - _nativeRemoveOperationQueue = new Svelto.ECS.DataStructures.AtomicNativeBags(Allocator.Persistent); - _nativeAddOperationQueue = new Svelto.ECS.DataStructures.AtomicNativeBags(Allocator.Persistent); + _nativeSwapOperationQueue = new AtomicNativeBags(Allocator.Persistent); + _nativeRemoveOperationQueue = new AtomicNativeBags(Allocator.Persistent); + _nativeAddOperationQueue = new AtomicNativeBags(Allocator.Persistent); #endif _serializationDescriptorMap = new SerializationDescriptorMap(); _reactiveEnginesAdd = new FasterDictionary>>(); @@ -66,24 +65,27 @@ namespace Svelto.ECS new FasterDictionary>>(); _reactiveEnginesSubmission = new FasterList(); - _enginesSet = new FasterList(); - _enginesTypeSet = new HashSet(); - _disposableEngines = new FasterList(); + _reactiveEnginesSubmissionStarted = new FasterList(); + _enginesSet = new FasterList(); + _enginesTypeSet = new HashSet(); + _disposableEngines = new FasterList(); _groupEntityComponentsDB = new FasterDictionary>(); _groupsPerEntity = new FasterDictionary>(); _groupedEntityToAdd = new DoubleBufferedEntitiesToAdd(); - _entityStreams = EntitiesStreams.Create(); + _entityStreams = EntitiesStreams.Create(); +#if SVELTO_LEGACY_FILTERS _groupFilters = new FasterDictionary>(); +#endif _entityLocator.InitEntityReferenceMap(); _entitiesDB = new EntitiesDB(this, _entityLocator); InitFilters(); - scheduler = entitiesComponentScheduler; + scheduler = entitiesComponentScheduler; scheduler.onTick = new EntitiesSubmitter(this); #if UNITY_NATIVE AllocateNativeOperations(); @@ -91,7 +93,7 @@ namespace Svelto.ECS } protected EnginesRoot(EntitiesSubmissionScheduler entitiesComponentScheduler, - EnginesReadyOption enginesWaitForReady) : this(entitiesComponentScheduler) + EnginesReadyOption enginesWaitForReady): this(entitiesComponentScheduler) { _enginesWaitForReady = enginesWaitForReady; } @@ -109,9 +111,14 @@ namespace Svelto.ECS GC.SuppressFinalize(this); } + public bool IsValid() + { + return _isDisposed == false; + } + public void AddEngine(IEngine engine) { - var type = engine.GetType(); + var type = engine.GetType(); var refWrapper = new RefWrapperType(type); Check.Require(engine != null, "Engine to add is invalid or null"); Check.Require( @@ -122,28 +129,42 @@ namespace Svelto.ECS try { if (engine is IReactOnAdd viewEngineAdd) +#pragma warning disable CS0612 CheckReactEngineComponents(typeof(IReactOnAdd<>), viewEngineAdd, _reactiveEnginesAdd, type.Name); +#pragma warning restore CS0612 if (engine is IReactOnAddEx viewEngineAddEx) - CheckReactEngineComponents(typeof(IReactOnAddEx<>), viewEngineAddEx, _reactiveEnginesAddEx, type.Name); + CheckReactEngineComponents( + typeof(IReactOnAddEx<>), viewEngineAddEx, _reactiveEnginesAddEx, type.Name); if (engine is IReactOnRemove viewEngineRemove) - CheckReactEngineComponents(typeof(IReactOnRemove<>), viewEngineRemove, _reactiveEnginesRemove, type.Name); + CheckReactEngineComponents( +#pragma warning disable CS0612 + typeof(IReactOnRemove<>), viewEngineRemove, _reactiveEnginesRemove, type.Name); +#pragma warning restore CS0612 if (engine is IReactOnRemoveEx viewEngineRemoveEx) - CheckReactEngineComponents(typeof(IReactOnRemoveEx<>), viewEngineRemoveEx, _reactiveEnginesRemoveEx, type.Name); + CheckReactEngineComponents( + typeof(IReactOnRemoveEx<>), viewEngineRemoveEx, _reactiveEnginesRemoveEx, type.Name); if (engine is IReactOnDispose viewEngineDispose) - CheckReactEngineComponents(typeof(IReactOnDispose<>), viewEngineDispose, _reactiveEnginesDispose, type.Name); + CheckReactEngineComponents( + typeof(IReactOnDispose<>), viewEngineDispose, _reactiveEnginesDispose, type.Name); if (engine is IReactOnSwap viewEngineSwap) +#pragma warning disable CS0612 CheckReactEngineComponents(typeof(IReactOnSwap<>), viewEngineSwap, _reactiveEnginesSwap, type.Name); +#pragma warning restore CS0612 if (engine is IReactOnSwapEx viewEngineSwapEx) - CheckReactEngineComponents(typeof(IReactOnSwapEx<>), viewEngineSwapEx, _reactiveEnginesSwapEx, type.Name); + CheckReactEngineComponents( + typeof(IReactOnSwapEx<>), viewEngineSwapEx, _reactiveEnginesSwapEx, type.Name); if (engine is IReactOnSubmission submissionEngine) _reactiveEnginesSubmission.Add(submissionEngine); + + if (engine is IReactOnSubmissionStarted submissionEngineStarted) + _reactiveEnginesSubmissionStarted.Add(submissionEngineStarted); _enginesTypeSet.Add(refWrapper); _enginesSet.Add(engine); @@ -159,14 +180,16 @@ namespace Svelto.ECS } catch (Exception e) { - throw new ECSException("Code crashed while adding engine ".FastConcat(engine.GetType().ToString(), " "), + throw new ECSException( + "Code crashed while adding engine ".FastConcat(engine.GetType().ToString(), " "), e); } } public void Ready() { - Check.Require(_enginesWaitForReady == EnginesReadyOption.WaitForReady, + Check.Require( + _enginesWaitForReady == EnginesReadyOption.WaitForReady, "The engine has not been initialise to wait for an external ready trigger"); foreach (var engine in _enginesSet) @@ -212,11 +235,6 @@ namespace Svelto.ECS void Dispose(bool disposing) { - _isDisposing = disposing; - - if (disposing == false) - return; - using (var profiler = new PlatformProfiler("Final Dispose")) { //Note: The engines are disposed before the the remove callback to give the chance to behave @@ -228,6 +246,7 @@ namespace Svelto.ECS { if (engine is IDisposingEngine dengine) dengine.isDisposing = true; + engine.Dispose(); } catch (Exception e) @@ -236,28 +255,31 @@ namespace Svelto.ECS } foreach (var groups in _groupEntityComponentsDB) - foreach (var entityList in groups.value) - try - { - ITypeSafeDictionary typeSafeDictionary = entityList.value; - - typeSafeDictionary.ExecuteEnginesDisposeCallbacks_Group(_reactiveEnginesDispose, groups.key, - profiler); - } - catch (Exception e) - { - Console.LogException(e); - } + foreach (var entityList in groups.value) + try + { + ITypeSafeDictionary typeSafeDictionary = entityList.value; + + typeSafeDictionary.ExecuteEnginesDisposeCallbacks_Group( + _reactiveEnginesDispose, groups.key, + profiler); + } + catch (Exception e) + { + Console.LogException(e); + } foreach (var groups in _groupEntityComponentsDB) - foreach (var entityList in groups.value) - entityList.value.Dispose(); + foreach (var entityList in groups.value) + entityList.value.Dispose(); +#if SVELTO_LEGACY_FILTERS foreach (var type in _groupFilters) - foreach (var group in type.value) - group.value.Dispose(); + foreach (var group in type.value) + group.value.Dispose(); _groupFilters.Clear(); +#endif DisposeFilters(); @@ -277,6 +299,7 @@ namespace Svelto.ECS _reactiveEnginesRemove.Clear(); _reactiveEnginesDispose.Clear(); _reactiveEnginesSubmission.Clear(); + _reactiveEnginesSubmissionStarted.Clear(); _groupedEntityToAdd.Dispose(); @@ -285,6 +308,8 @@ namespace Svelto.ECS _entityStreams.Dispose(); scheduler.Dispose(); } + + _isDisposed = true; } void NotifyReactiveEnginesOnSubmission() @@ -293,10 +318,17 @@ namespace Svelto.ECS for (var i = 0; i < enginesCount; i++) _reactiveEnginesSubmission[i].EntitiesSubmitted(); } + + void NotifyReactiveEnginesOnSubmissionStarted() + { + var enginesCount = _reactiveEnginesSubmissionStarted.count; + for (var i = 0; i < enginesCount; i++) + _reactiveEnginesSubmissionStarted[i].EntitiesSubmissionStarting(); + } public readonly struct EntitiesSubmitter { - public EntitiesSubmitter(EnginesRoot enginesRoot) : this() + public EntitiesSubmitter(EnginesRoot enginesRoot): this() { _enginesRoot = new Svelto.DataStructures.WeakReference(enginesRoot); } @@ -305,18 +337,20 @@ namespace Svelto.ECS { Check.Require(_enginesRoot.IsValid, "ticking an GCed engines root?"); - var enginesRootTarget = _enginesRoot.Target; + var enginesRootTarget = _enginesRoot.Target; var entitiesSubmissionScheduler = enginesRootTarget.scheduler; if (entitiesSubmissionScheduler.paused == false) { - Check.Require(entitiesSubmissionScheduler.isRunning == false, + enginesRootTarget.NotifyReactiveEnginesOnSubmissionStarted(); + Check.Require( + entitiesSubmissionScheduler.isRunning == false, "A submission started while the previous one was still flushing"); entitiesSubmissionScheduler.isRunning = true; using (var profiler = new PlatformProfiler("Svelto.ECS - Entities Submission")) { - var iterations = 0; + var iterations = 0; var hasEverSubmitted = false; // We need to clear transient filters before processing callbacks since the callbacks may add @@ -327,15 +361,14 @@ namespace Svelto.ECS enginesRootTarget.FlushNativeOperations(profiler); #endif //todo: proper unit test structural changes made as result of add/remove callbacks - while (enginesRootTarget.HasMadeNewStructuralChangesInThisIteration() - && iterations++ < MAX_SUBMISSION_ITERATIONS) + while (enginesRootTarget.HasMadeNewStructuralChangesInThisIteration() + && iterations++ < MAX_SUBMISSION_ITERATIONS) { hasEverSubmitted = true; _enginesRoot.Target.SingleSubmission(profiler); #if UNITY_NATIVE - if (enginesRootTarget.HasMadeNewStructuralChangesInThisIteration()) - enginesRootTarget.FlushNativeOperations(profiler); + enginesRootTarget.FlushNativeOperations(profiler); #endif } @@ -364,32 +397,22 @@ namespace Svelto.ECS const int MAX_SUBMISSION_ITERATIONS = 10; - internal bool _isDisposing; readonly FasterList _disposableEngines; - readonly FasterList _enginesSet; - readonly HashSet _enginesTypeSet; - readonly EnginesReadyOption _enginesWaitForReady; + readonly FasterList _enginesSet; + readonly HashSet _enginesTypeSet; + readonly EnginesReadyOption _enginesWaitForReady; readonly FasterDictionary>> _reactiveEnginesAdd; - - readonly FasterDictionary>> - _reactiveEnginesAddEx; - - readonly FasterDictionary>> - _reactiveEnginesRemove; - - readonly FasterDictionary>> - _reactiveEnginesRemoveEx; - + readonly FasterDictionary>> _reactiveEnginesAddEx; + readonly FasterDictionary>> _reactiveEnginesRemove; + readonly FasterDictionary>> _reactiveEnginesRemoveEx; readonly FasterDictionary>> _reactiveEnginesSwap; - - readonly FasterDictionary>> - _reactiveEnginesSwapEx; - - readonly FasterDictionary>> - _reactiveEnginesDispose; + readonly FasterDictionary>> _reactiveEnginesSwapEx; + readonly FasterDictionary>> _reactiveEnginesDispose; readonly FasterList _reactiveEnginesSubmission; + readonly FasterList _reactiveEnginesSubmissionStarted; + bool _isDisposed; } public enum EnginesReadyOption diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs index 82f883f..c7242a4 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Entities.cs @@ -177,10 +177,11 @@ namespace Svelto.ECS // >> internal readonly FasterDictionary> _groupsPerEntity; - +#if SVELTO_LEGACY_FILTERS //The filters stored for each component and group internal readonly FasterDictionary> _groupFilters; +#endif readonly EntitiesDB _entitiesDB; diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs index a68eafa..f3d3d32 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFactory.cs @@ -14,6 +14,7 @@ namespace Svelto.ECS _enginesRoot = new Svelto.DataStructures.WeakReference(weakReference); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityInitializer BuildEntity (uint entityID, ExclusiveBuildGroup groupStructId, IEnumerable implementors = null , [CallerMemberName] string caller = null) where T : IEntityDescriptor, new() @@ -23,6 +24,7 @@ namespace Svelto.ECS , TypeCache.type, implementors, caller); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityInitializer BuildEntity (EGID egid, IEnumerable implementors = null , [CallerMemberName] string caller = null) where T : IEntityDescriptor, new() @@ -31,6 +33,7 @@ namespace Svelto.ECS , TypeCache.type, implementors, caller); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityInitializer BuildEntity (EGID egid, T entityDescriptor, IEnumerable implementors , [CallerMemberName] string caller = null) where T : IEntityDescriptor @@ -39,6 +42,7 @@ namespace Svelto.ECS , implementors, caller); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityInitializer BuildEntity (uint entityID, ExclusiveBuildGroup groupStructId, T descriptorEntity, IEnumerable implementors , [CallerMemberName] string caller = null) where T : IEntityDescriptor @@ -48,6 +52,15 @@ namespace Svelto.ECS , implementors, caller); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntityInitializer BuildEntity + (EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable implementors = null + , [CallerMemberName] string caller = null) + { + return _enginesRoot.Target.BuildEntity(egid, componentsToBuild, type, implementors, caller); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PreallocateEntitySpace(ExclusiveGroupStruct groupStructId, uint numberOfEntities) where T : IEntityDescriptor, new() { @@ -55,13 +68,6 @@ namespace Svelto.ECS , EntityDescriptorTemplate.descriptor.componentsToBuild); } - public EntityInitializer BuildEntity - (EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable implementors = null - , [CallerMemberName] string caller = null) - { - return _enginesRoot.Target.BuildEntity(egid, componentsToBuild, type, implementors, caller); - } - #if UNITY_NATIVE public Native.NativeEntityFactory ToNative ([CallerMemberName] string caller = null) diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs index d5ac6d1..3b3fd0c 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.GenericEntityFunctions.cs @@ -127,26 +127,26 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] void QueueRemoveGroupOperation(ExclusiveBuildGroup groupID, string caller) { - _entitiesOperations.AddRemoveGroupOperation(groupID, caller); + _entitiesOperations.QueueRemoveGroupOperation(groupID, caller); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void QueueSwapGroupOperation(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID, string caller) { - _entitiesOperations.AddSwapGroupOperation(fromGroupID, toGroupID, caller); + _entitiesOperations.QueueSwapGroupOperation(fromGroupID, toGroupID, caller); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void QueueSwapEntityOperation (EGID fromID, EGID toID, IComponentBuilder[] componentBuilders, string caller) { - _entitiesOperations.AddSwapOperation(fromID, toID, componentBuilders, caller); + _entitiesOperations.QueueSwapOperation(fromID, toID, componentBuilders, caller); } [MethodImpl(MethodImplOptions.AggressiveInlining)] void QueueRemoveEntityOperation(EGID entityEGID, IComponentBuilder[] componentBuilders, string caller) { - _entitiesOperations.AddRemoveOperation(entityEGID, componentBuilders, caller); + _entitiesOperations.QueueRemoveOperation(entityEGID, componentBuilders, caller); } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs index 821c1ad..bef5d1d 100644 --- a/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs +++ b/com.sebaslab.svelto.ecs/Core/EnginesRoot.Submission.cs @@ -11,12 +11,16 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] void SingleSubmission(PlatformProfiler profiler) { - ClearDebugChecks(); //this must be done first as I need the carry the last states after the submission - - _entitiesOperations.ExecuteRemoveAndSwappingOperations(_swapEntities, _removeEntities, _removeGroup - , _swapGroup, this); + _entitiesOperations.ExecuteRemoveAndSwappingOperations( + _swapEntities, + _removeEntities, + _removeGroup, + _swapGroup, + this); AddEntities(profiler); + + ClearDebugChecks(); //this must be done first as I need the carry the last states after the submission } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -37,9 +41,9 @@ namespace Svelto.ECS } } - static void RemoveEntities - (FasterDictionary>> - removeOperations, FasterList entitiesRemoved, EnginesRoot enginesRoot) + static void RemoveEntities( + FasterDictionary>> + removeOperations, FasterList entitiesRemoved, EnginesRoot enginesRoot) { using (var sampler = new PlatformProfiler("remove Entities")) { @@ -56,54 +60,60 @@ namespace Svelto.ECS { foreach (var entitiesToRemove in removeOperations) { - ExclusiveGroupStruct group = entitiesToRemove.key; - var fromGroupDictionary = enginesRoot.GetDBGroup(group); + ExclusiveGroupStruct group = entitiesToRemove.key; + var fromGroupDictionary = enginesRoot.GetDBGroup(group); foreach (var groupedEntitiesToRemove in entitiesToRemove.value) { - var componentType = groupedEntitiesToRemove.key; + var componentType = groupedEntitiesToRemove.key; ITypeSafeDictionary fromComponentsDictionary = fromGroupDictionary[componentType]; FasterList<(uint, string)> infosToProcess = groupedEntitiesToRemove.value; fromComponentsDictionary.ExecuteEnginesRemoveCallbacks( - infosToProcess, enginesRoot._reactiveEnginesRemove, group, in sampler); + infosToProcess, + enginesRoot._reactiveEnginesRemove, + group, + in sampler); } } } using (sampler.Sample("Remove Entities")) { - enginesRoot._cachedRangeOfSubmittedIndices.FastClear(); + enginesRoot._cachedRangeOfSubmittedIndices.Clear(); foreach (var entitiesToRemove in removeOperations) { - ExclusiveGroupStruct fromGroup = entitiesToRemove.key; - var fromGroupDictionary = enginesRoot.GetDBGroup(fromGroup); + ExclusiveGroupStruct fromGroup = entitiesToRemove.key; + var fromGroupDictionary = enginesRoot.GetDBGroup(fromGroup); foreach (var groupedEntitiesToRemove in entitiesToRemove.value) { - RefWrapperType componentType = groupedEntitiesToRemove.key; + RefWrapperType componentType = groupedEntitiesToRemove.key; ITypeSafeDictionary fromComponentsDictionary = fromGroupDictionary[componentType]; FasterList<(uint, string)> entityIDsToRemove = groupedEntitiesToRemove.value; - enginesRoot._transientEntityIDsLeftAndAffectedByRemoval.FastClear(); + enginesRoot._transientEntityIDsLeftAndAffectedByRemoval.Clear(); fromComponentsDictionary.RemoveEntitiesFromDictionary( - entityIDsToRemove, enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); + entityIDsToRemove, + enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); //important: remove from the filter must happen after remove from the dictionary //as we need to read the new indices linked to entities after the removal enginesRoot.RemoveEntitiesFromPersistentFilters( - entityIDsToRemove, fromGroup, componentType, fromComponentsDictionary - , enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); + entityIDsToRemove, + fromGroup, + componentType, + fromComponentsDictionary, + enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); //store new database count after the entities are removed from the datatabase, plus the number of entities removed - enginesRoot._cachedRangeOfSubmittedIndices.Add(((uint, uint))( - fromComponentsDictionary.count - , fromComponentsDictionary.count - + entityIDsToRemove.count)); + enginesRoot._cachedRangeOfSubmittedIndices.Add( + ((uint, uint))(fromComponentsDictionary.count, + fromComponentsDictionary.count + entityIDsToRemove.count)); } } } @@ -120,33 +130,36 @@ namespace Svelto.ECS { foreach (var entitiesToRemove in removeOperations) { - ExclusiveGroupStruct group = entitiesToRemove.key; - var fromGroupDictionary = enginesRoot.GetDBGroup(group); + ExclusiveGroupStruct group = entitiesToRemove.key; + var fromGroupDictionary = enginesRoot.GetDBGroup(group); foreach (var groupedEntitiesToRemove in entitiesToRemove.value) { rangeEnumerator.MoveNext(); - var componentType = groupedEntitiesToRemove.key; + var componentType = groupedEntitiesToRemove.key; ITypeSafeDictionary fromComponentsDictionary = fromGroupDictionary[componentType]; //get all the engines linked to TValue if (!enginesRoot._reactiveEnginesRemoveEx.TryGetValue( - componentType, out var entityComponentsEngines)) + componentType, + out var entityComponentsEngines)) continue; fromComponentsDictionary.ExecuteEnginesRemoveCallbacksFast( - entityComponentsEngines, group, rangeEnumerator.Current, in sampler); + entityComponentsEngines, + group, + rangeEnumerator.Current, + in sampler); } } } } } - static void SwapEntities - (FasterDictionary>>> swapEntitiesOperations - , FasterList<(EGID, EGID)> entitiesIDSwaps, EnginesRoot enginesRoot) + static void SwapEntities(FasterDictionary>>> swapEntitiesOperations, + FasterList<(EGID, EGID)> entitiesIDSwaps, EnginesRoot enginesRoot) { using (var sampler = new PlatformProfiler("Swap entities between groups")) { @@ -163,7 +176,7 @@ namespace Svelto.ECS using (sampler.Sample("Swap Entities")) { - enginesRoot._cachedRangeOfSubmittedIndices.FastClear(); + enginesRoot._cachedRangeOfSubmittedIndices.Clear(); //Entities to swap are organised in order to minimise the amount of dictionary lookups. //swapEntitiesOperations iterations happen in the following order: @@ -172,53 +185,62 @@ namespace Svelto.ECS //now swap the set of FromGroup -> ToGroup entities per ID. foreach (var entitiesToSwap in swapEntitiesOperations) { - ExclusiveGroupStruct fromGroup = entitiesToSwap.key; - var fromGroupDictionary = enginesRoot.GetDBGroup(fromGroup); + ExclusiveGroupStruct fromGroup = entitiesToSwap.key; + var fromGroupDictionary = enginesRoot.GetDBGroup(fromGroup); //iterate all the fromgroups foreach (var groupedEntitiesToSwap in entitiesToSwap.value) { - var componentType = groupedEntitiesToSwap.key; - ITypeSafeDictionary fromComponentsDictionary = fromGroupDictionary[componentType]; + var componentType = groupedEntitiesToSwap.key; + ITypeSafeDictionary fromComponentsDictionaryDB = fromGroupDictionary[componentType]; //get the subset of togroups that come from from group foreach (var entitiesInfoToSwap in groupedEntitiesToSwap.value) { ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; - ITypeSafeDictionary toComponentsDictionary = - enginesRoot.GetOrAddTypeSafeDictionary( - toGroup, enginesRoot.GetOrAddDBGroup(toGroup), componentType - , fromComponentsDictionary); + ITypeSafeDictionary toComponentsDictionaryDB = enginesRoot.GetOrAddTypeSafeDictionary( + toGroup, + enginesRoot.GetOrAddDBGroup(toGroup), + componentType, + fromComponentsDictionaryDB); - DBC.ECS.Check.Assert(toComponentsDictionary != null - , "something went wrong with the creation of dictionaries"); + DBC.ECS.Check.Assert( + toComponentsDictionaryDB != null, + "something went wrong with the creation of dictionaries"); //this list represents the set of entities that come from fromGroup and need //to be swapped to toGroup. Most of the times will be 1 of few units. FasterList<(uint, uint, string)> fromEntityToEntityIDs = entitiesInfoToSwap.value; //ensure that to dictionary has enough room to store the new entities - toComponentsDictionary.EnsureCapacity( - (uint)(toComponentsDictionary.count + (uint)fromEntityToEntityIDs.count)); + toComponentsDictionaryDB.EnsureCapacity( + (uint)(toComponentsDictionaryDB.count + (uint)fromEntityToEntityIDs.count)); //fortunately swap means that entities are added at the end of each destination //dictionary list, so we can just iterate the list using the indices ranges added in the //_cachedIndices - enginesRoot._cachedRangeOfSubmittedIndices.Add(((uint, uint))( - toComponentsDictionary.count - , toComponentsDictionary.count - + fromEntityToEntityIDs.count)); + enginesRoot._cachedRangeOfSubmittedIndices.Add( + ((uint, uint))(toComponentsDictionaryDB.count, + toComponentsDictionaryDB.count + fromEntityToEntityIDs.count)); - enginesRoot._transientEntityIDsLeftAndAffectedByRemoval.FastClear(); + enginesRoot._transientEntityIDsLeftAndAffectedByRemoval.Clear(); - fromComponentsDictionary.SwapEntitiesBetweenDictionaries( - fromEntityToEntityIDs, fromGroup, toGroup, toComponentsDictionary - , enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); + fromComponentsDictionaryDB.SwapEntitiesBetweenDictionaries( + fromEntityToEntityIDs, + fromGroup, + toGroup, + toComponentsDictionaryDB, + enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); //important: this must happen after the entities are swapped in the database enginesRoot.SwapEntityBetweenPersistentFilters( - fromEntityToEntityIDs, fromComponentsDictionary, toComponentsDictionary, fromGroup - , toGroup, componentType, enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); + fromEntityToEntityIDs, + fromComponentsDictionaryDB, + toComponentsDictionaryDB, + fromGroup, + toGroup, + componentType, + enginesRoot._transientEntityIDsLeftAndAffectedByRemoval); } } } @@ -236,19 +258,26 @@ namespace Svelto.ECS //get all the engines linked to TValue if (!enginesRoot._reactiveEnginesSwap.TryGetValue( - new RefWrapperType(componentType), out var entityComponentsEngines)) + new RefWrapperType(componentType), + out var entityComponentsEngines)) continue; foreach (var entitiesInfoToSwap in groupedEntitiesToSwap.value) { ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; - ITypeSafeDictionary toComponentsDictionary = - GetTypeSafeDictionary(toGroup, enginesRoot.GetDBGroup(toGroup), componentType); + ITypeSafeDictionary toComponentsDictionary = GetTypeSafeDictionary( + toGroup, + enginesRoot.GetDBGroup(toGroup), + componentType); var infosToProcess = entitiesInfoToSwap.value; toComponentsDictionary.ExecuteEnginesSwapCallbacks( - infosToProcess, entityComponentsEngines, fromGroup, toGroup, in sampler); + infosToProcess, + entityComponentsEngines, + fromGroup, + toGroup, + in sampler); } } } @@ -271,15 +300,22 @@ namespace Svelto.ECS //get all the engines linked to TValue if (!enginesRoot._reactiveEnginesSwapEx.TryGetValue( - new RefWrapperType(componentType), out var entityComponentsEngines)) + new RefWrapperType(componentType), + out var entityComponentsEngines)) continue; ExclusiveGroupStruct toGroup = entitiesInfoToSwap.key; - ITypeSafeDictionary toComponentsDictionary = - GetTypeSafeDictionary(toGroup, enginesRoot.GetDBGroup(toGroup), componentType); + ITypeSafeDictionary toComponentsDictionary = GetTypeSafeDictionary( + toGroup, + enginesRoot.GetDBGroup(toGroup), + componentType); toComponentsDictionary.ExecuteEnginesSwapCallbacksFast( - entityComponentsEngines, fromGroup, toGroup, rangeEnumerator.Current, in sampler); + entityComponentsEngines, + fromGroup, + toGroup, + rangeEnumerator.Current, + in sampler); } } } @@ -295,7 +331,7 @@ namespace Svelto.ECS //I need to iterate the previous current, which is now other if (_groupedEntityToAdd.AnyPreviousEntityCreated()) { - _cachedRangeOfSubmittedIndices.FastClear(); + _cachedRangeOfSubmittedIndices.Clear(); using (sampler.Sample("Add operations")) { try @@ -312,12 +348,11 @@ namespace Svelto.ECS //add the entityComponents in the group foreach (var entityComponentsToSubmit in groupToSubmit.components) { - var type = entityComponentsToSubmit.key; + var type = entityComponentsToSubmit.key; var fromDictionary = entityComponentsToSubmit.value; - var wrapper = new RefWrapperType(type); + var wrapper = new RefWrapperType(type); - var toDictionary = - GetOrAddTypeSafeDictionary(groupID, groupDB, wrapper, fromDictionary); + var toDictionary = GetOrAddTypeSafeDictionary(groupID, groupDB, wrapper, 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 @@ -326,7 +361,7 @@ namespace Svelto.ECS //Fill the DB with the entity components generated this frame. fromDictionary.AddEntitiesToDictionary(toDictionary, groupID #if SLOW_SVELTO_SUBMISSION - , entityLocator + , entityLocator #endif ); } @@ -345,13 +380,12 @@ namespace Svelto.ECS foreach (var entityComponentsToSubmit in groupToSubmit.components) { - var type = entityComponentsToSubmit.key; + var type = entityComponentsToSubmit.key; var wrapper = new RefWrapperType(type); var toDictionary = GetTypeSafeDictionary(groupID, groupDB, wrapper); enumerator.MoveNext(); - toDictionary.ExecuteEnginesAddEntityCallbacksFast( - _reactiveEnginesAddEx, groupID, enumerator.Current, in sampler); + toDictionary.ExecuteEnginesAddEntityCallbacksFast(_reactiveEnginesAddEx, groupID, enumerator.Current, in sampler); } } } @@ -372,7 +406,7 @@ namespace Svelto.ECS //design of the transient buffer of added entities. foreach (var entityComponentsToSubmit in groupToSubmit.components) { - var type = entityComponentsToSubmit.key; + var type = entityComponentsToSubmit.key; var fromDictionary = entityComponentsToSubmit.value; //this contains the total number of components ever submitted in the DB @@ -425,11 +459,10 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - void SwapEntitiesBetweenGroups - (ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, PlatformProfiler platformProfiler) + void SwapEntitiesBetweenGroups(ExclusiveGroupStruct fromGroupId, ExclusiveGroupStruct toGroupId, PlatformProfiler platformProfiler) { FasterDictionary fromGroup = GetDBGroup(fromGroupId); - FasterDictionary toGroup = GetOrAddDBGroup(toGroupId); + FasterDictionary toGroup = GetOrAddDBGroup(toGroupId); _entityLocator.UpdateAllGroupReferenceLocators(fromGroupId, toGroupId); @@ -439,12 +472,11 @@ namespace Svelto.ECS RefWrapperType refWrapperType = dictionaryOfEntities.key; ITypeSafeDictionary fromDictionary = dictionaryOfEntities.value; - ITypeSafeDictionary toDictionary = - GetOrAddTypeSafeDictionary(toGroupId, toGroup, refWrapperType, fromDictionary); + ITypeSafeDictionary toDictionary = GetOrAddTypeSafeDictionary(toGroupId, toGroup, refWrapperType, fromDictionary); fromDictionary.AddEntitiesToDictionary(toDictionary, toGroupId #if SLOW_SVELTO_SUBMISSION - , this.entityLocator + , this.entityLocator #endif ); } @@ -455,12 +487,11 @@ namespace Svelto.ECS RefWrapperType refWrapperType = dictionaryOfEntities.key; ITypeSafeDictionary fromDictionary = dictionaryOfEntities.value; - ITypeSafeDictionary toDictionary = GetTypeSafeDictionary(toGroupId, toGroup, refWrapperType); + ITypeSafeDictionary toDictionary = GetTypeSafeDictionary(toGroupId, toGroup, refWrapperType); //SwapEX happens inside - fromDictionary.ExecuteEnginesSwapCallbacks_Group(_reactiveEnginesSwap, _reactiveEnginesSwapEx - , toDictionary, fromGroupId, toGroupId - , platformProfiler); + fromDictionary.ExecuteEnginesSwapCallbacks_Group(_reactiveEnginesSwap, _reactiveEnginesSwapEx, toDictionary, + fromGroupId, toGroupId, platformProfiler); } //remove entities from dictionaries @@ -473,9 +504,9 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - ITypeSafeDictionary GetOrAddTypeSafeDictionary - (ExclusiveGroupStruct groupId, FasterDictionary groupPerComponentType - , RefWrapperType type, ITypeSafeDictionary fromDictionary) + ITypeSafeDictionary GetOrAddTypeSafeDictionary(ExclusiveGroupStruct groupId, + FasterDictionary groupPerComponentType, RefWrapperType type, + ITypeSafeDictionary fromDictionary) { //be sure that the TypeSafeDictionary for the entity Type exists if (groupPerComponentType.TryGetValue(type, out ITypeSafeDictionary toEntitiesDictionary) == false) @@ -497,9 +528,8 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - static ITypeSafeDictionary GetTypeSafeDictionary - (ExclusiveGroupStruct groupID, FasterDictionary @group - , RefWrapperType refWrapper) + static ITypeSafeDictionary GetTypeSafeDictionary(ExclusiveGroupStruct groupID, + FasterDictionary @group, RefWrapperType refWrapper) { if (@group.TryGetValue(refWrapper, out ITypeSafeDictionary fromTypeSafeDictionary) == false) { @@ -510,25 +540,24 @@ namespace Svelto.ECS } readonly DoubleBufferedEntitiesToAdd _groupedEntityToAdd; - readonly EntitiesOperations _entitiesOperations; + readonly EntitiesOperations _entitiesOperations; //transient caches>>>>>>>>>>>>>>>>>>>>> - readonly FasterList<(uint, uint)> _cachedRangeOfSubmittedIndices; + readonly FasterList<(uint, uint)> _cachedRangeOfSubmittedIndices; readonly FasterDictionary _transientEntityIDsLeftWithoutDuplicates; - readonly FasterList _transientEntityIDsLeftAndAffectedByRemoval; + readonly FasterList _transientEntityIDsLeftAndAffectedByRemoval; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< static readonly Action>>>, FasterList<(EGID, EGID)> - , - EnginesRoot> _swapEntities; + , EnginesRoot> _swapEntities; static readonly Action< FasterDictionary>>, FasterList, EnginesRoot> _removeEntities; - static readonly Action _removeGroup; + static readonly Action _removeGroup; static readonly Action _swapGroup; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs b/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs index 04ce01d..2d5eacf 100644 --- a/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs +++ b/com.sebaslab.svelto.ecs/Core/EntitiesDB.cs @@ -20,7 +20,7 @@ namespace Svelto.ECS EntityCollection InternalQueryEntities (FasterDictionary entitiesInGroupPerType) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { uint count = 0; IBuffer buffer; @@ -46,7 +46,7 @@ namespace Svelto.ECS /// /// public EntityCollection QueryEntities(ExclusiveGroupStruct groupStructId) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { if (groupEntityComponentsDB.TryGetValue(groupStructId, out var entitiesInGroupPerType) == false) { @@ -57,7 +57,7 @@ namespace Svelto.ECS } public EntityCollection QueryEntities(ExclusiveGroupStruct groupStruct) - where T1 : struct, IBaseEntityComponent where T2 : struct, IBaseEntityComponent + where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent { if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false) { @@ -75,16 +75,16 @@ namespace Svelto.ECS .FastConcat("'. Entity 2: ' count: ".FastConcat(T2entities.count) .FastConcat(" ", typeof(T2).ToString()) .FastConcat( - "' group: ", groupStruct.ToName()))); + "' group: ", groupStruct.ToName())).FastConcat(" this means that you are mixing descriptors in the same group that do not share the components that you are querying")); #endif return new EntityCollection(T1entities, T2entities); } public EntityCollection QueryEntities(ExclusiveGroupStruct groupStruct) - where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent + where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent { if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false) { @@ -105,17 +105,17 @@ namespace Svelto.ECS " Entity 2: ".FastConcat(typeof(T2).ToString()).FastConcat(" count: ") .FastConcat(T2entities.count) .FastConcat(" Entity 3: ".FastConcat(typeof(T3).ToString())) - .FastConcat(" count: ").FastConcat(T3entities.count))); + .FastConcat(" count: ").FastConcat(T3entities.count)).FastConcat(" this means that you are mixing descriptors in the same group that do not share the components that you are querying")); #endif return new EntityCollection(T1entities, T2entities, T3entities); } public EntityCollection QueryEntities(ExclusiveGroupStruct groupStruct) - where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent - where T4 : struct, IBaseEntityComponent + where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent + where T4 : struct, _IInternalEntityComponent { if (groupEntityComponentsDB.TryGetValue(groupStruct, out var entitiesInGroupPerType) == false) { @@ -141,49 +141,49 @@ namespace Svelto.ECS .FastConcat(" Entity 3: ".FastConcat(typeof(T3).ToString())) .FastConcat(" count: ").FastConcat(T3entities.count) .FastConcat(" Entity 4: ".FastConcat(typeof(T4).ToString())) - .FastConcat(" count: ").FastConcat(T4entities.count))); + .FastConcat(" count: ").FastConcat(T4entities.count)).FastConcat(" this means that you are mixing descriptors in the same group that do not share the components that you are querying")); #endif return new EntityCollection(T1entities, T2entities, T3entities, T4entities); } public GroupsEnumerable QueryEntities - (in LocalFasterReadOnlyList groups) where T : struct, IBaseEntityComponent + (in LocalFasterReadOnlyList groups) where T : struct, _IInternalEntityComponent { return new GroupsEnumerable(this, groups); } /// /// Note: Remember that EntityViewComponents are always put at the end of the generic parameters tuple. - /// It won't compile otherwise + /// The Query entity code won't inexplicably compile otherwise /// /// public GroupsEnumerable QueryEntities(in LocalFasterReadOnlyList groups) - where T1 : struct, IBaseEntityComponent where T2 : struct, IBaseEntityComponent + where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent { return new GroupsEnumerable(this, groups); } public GroupsEnumerable QueryEntities - (in LocalFasterReadOnlyList groups) where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent + (in LocalFasterReadOnlyList groups) where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent { return new GroupsEnumerable(this, groups); } public GroupsEnumerable QueryEntities - (in LocalFasterReadOnlyList groups) where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent - where T4 : struct, IBaseEntityComponent + (in LocalFasterReadOnlyList groups) where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent + where T4 : struct, _IInternalEntityComponent { return new GroupsEnumerable(this, groups); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public EGIDMapper QueryMappedEntities(ExclusiveGroupStruct groupStructId) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { if (SafeQueryEntityDictionary(groupStructId, out var typeSafeDictionary) == false) throw new EntityGroupNotFoundException(typeof(T), groupStructId.ToName()); @@ -193,7 +193,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool TryQueryMappedEntities - (ExclusiveGroupStruct groupStructId, out EGIDMapper mapper) where T : struct, IBaseEntityComponent + (ExclusiveGroupStruct groupStructId, out EGIDMapper mapper) where T : struct, _IInternalEntityComponent { mapper = default; if (SafeQueryEntityDictionary(groupStructId, out var typeSafeDictionary) == false @@ -206,7 +206,7 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Exists(EGID entityGID) where T : struct, IBaseEntityComponent + public bool Exists(EGID entityGID) where T : struct, _IInternalEntityComponent { if (SafeQueryEntityDictionary(entityGID.groupID, out var casted) == false) return false; @@ -215,7 +215,7 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Exists(uint id, ExclusiveGroupStruct group) where T : struct, IBaseEntityComponent + public bool Exists(uint id, ExclusiveGroupStruct group) where T : struct, _IInternalEntityComponent { if (SafeQueryEntityDictionary(group, out var casted) == false) return false; @@ -236,13 +236,13 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool HasAny(ExclusiveGroupStruct groupStruct) where T : struct, IBaseEntityComponent + public bool HasAny(ExclusiveGroupStruct groupStruct) where T : struct, _IInternalEntityComponent { return Count(groupStruct) > 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Count(ExclusiveGroupStruct groupStruct) where T : struct, IBaseEntityComponent + public int Count(ExclusiveGroupStruct groupStruct) where T : struct, _IInternalEntityComponent { if (SafeQueryEntityDictionary(groupStruct, out var typeSafeDictionary) == false) return 0; @@ -250,17 +250,15 @@ namespace Svelto.ECS return (int)typeSafeDictionary.count; } - public bool FoundInGroups() where T1 : IBaseEntityComponent + public bool FoundInGroups() where T1 : _IInternalEntityComponent { return groupsPerComponent.ContainsKey(TypeRefWrapper.wrapper); } - public bool IsDisposing => _enginesRoot._isDisposing; - [MethodImpl(MethodImplOptions.AggressiveInlining)] bool SafeQueryEntityDictionary (out ITypeSafeDictionary typeSafeDictionary - , FasterDictionary entitiesInGroupPerType) where T : IBaseEntityComponent + , FasterDictionary entitiesInGroupPerType) where T : _IInternalEntityComponent { if (entitiesInGroupPerType.TryGetValue(new RefWrapperType(TypeCache.type), out var safeDictionary) == false) @@ -277,7 +275,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool SafeQueryEntityDictionary - (ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : IBaseEntityComponent + (ExclusiveGroupStruct group, out ITypeSafeDictionary typeSafeDictionary) where T : _IInternalEntityComponent { if (UnsafeQueryEntityDictionary(group, TypeCache.type, out var safeDictionary) == false) { diff --git a/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs b/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs index 4772102..7da09db 100644 --- a/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs +++ b/com.sebaslab.svelto.ecs/Core/EntitiesOperations.cs @@ -1,83 +1,95 @@ using System; +using System.Runtime.CompilerServices; using Svelto.DataStructures; +using Svelto.Utilities; namespace Svelto.ECS { class EntitiesOperations { + /// + /// Todo: need to go back here and add a ton of comments + /// public EntitiesOperations() { _thisSubmissionInfo.Init(); _lastSubmittedInfo.Init(); + _newGroupDictionary = NewGroupDictionary; + _newGroupsDictionary = NewGroupsDictionary; + _recycleDictionary = RecycleDictionary; + _newList = NewList; + _clearList = ClearList; + _newGroupsDictionaryWithCaller = NewGroupsDictionaryWithCaller; + _recycleGroupDictionaryWithCaller = RecycleGroupDictionaryWithCaller; + _recycleDicitionaryWithCaller = RecycleDicitionaryWithCaller; + _newListWithCaller = NewListWithCaller; + _clearListWithCaller = ClearListWithCaller; } - public void AddSwapOperation(EGID fromID, EGID toID, IComponentBuilder[] componentBuilders, string caller) + public void QueueRemoveGroupOperation(ExclusiveBuildGroup groupID, string caller) { - _thisSubmissionInfo._entitiesSwapped.Add((fromID, toID)); - - //todo: limit the number of dictionaries that can be cached - //recycle or create dictionaries of components per group - var swappedComponentsPerType = _thisSubmissionInfo._currentSwapEntitiesOperations.RecycleOrAdd( - fromID.groupID, - () => new FasterDictionary>>(), - (ref FasterDictionary>> recycled) => - recycled.FastClear()); - - foreach (IComponentBuilder operation in componentBuilders) - { - swappedComponentsPerType - //recycle or create dictionaries per component type - .RecycleOrAdd(new RefWrapperType(operation.GetEntityComponentType()), - () => new FasterDictionary>(), - (ref FasterDictionary> target) => - target.FastClear()) - //recycle or create list of entities to swap - .RecycleOrAdd(toID.groupID, () => new FasterList<(uint, uint, string)>(), - (ref FasterList<(uint, uint, string)> target) => target.FastClear()) - //add entity to swap - .Add((fromID.entityID, toID.entityID, caller)); - } + _thisSubmissionInfo._groupsToRemove.Add((groupID, caller)); } - public void AddRemoveOperation(EGID entityEgid, IComponentBuilder[] componentBuilders, string caller) + public void QueueRemoveOperation(EGID entityEgid, IComponentBuilder[] componentBuilders, string caller) { _thisSubmissionInfo._entitiesRemoved.Add(entityEgid); + //todo: limit the number of dictionaries that can be cached //recycle or create dictionaries of components per group var removedComponentsPerType = _thisSubmissionInfo._currentRemoveEntitiesOperations.RecycleOrAdd( - entityEgid.groupID, () => new FasterDictionary>(), - (ref FasterDictionary> recycled) => recycled.FastClear()); + entityEgid.groupID, _newGroupsDictionary, _recycleDictionary); - foreach (IComponentBuilder operation in componentBuilders) + foreach (var operation in componentBuilders) { - removedComponentsPerType - //recycle or create dictionaries per component type - .RecycleOrAdd(new RefWrapperType(operation.GetEntityComponentType()), - () => new FasterList<(uint, string)>(), - (ref FasterList<(uint, string)> target) => target.FastClear()) - //add entity to swap - .Add((entityEgid.entityID, caller)); + removedComponentsPerType //recycle or create dictionaries per component type + .RecycleOrAdd(new RefWrapperType(operation.GetEntityComponentType()), _newList, _clearList) + //add entity to remove + .Add((entityEgid.entityID, caller)); } } - public void AddRemoveGroupOperation(ExclusiveBuildGroup groupID, string caller) + public void QueueSwapGroupOperation(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID, string caller) { - _thisSubmissionInfo._groupsToRemove.Add((groupID, caller)); + _thisSubmissionInfo._groupsToSwap.Add((fromGroupID, toGroupID, caller)); } - public void AddSwapGroupOperation(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID, string caller) + public void QueueSwapOperation(EGID fromID, EGID toID, IComponentBuilder[] componentBuilders, string caller) { - _thisSubmissionInfo._groupsToSwap.Add((fromGroupID, toGroupID, caller)); + _thisSubmissionInfo._entitiesSwapped.Add((fromID, toID)); + + //todo: limit the number of dictionaries that can be cached + //recycle or create dictionaries of components per group + + //Get the dictionary that holds the entities that are swapping from fromID + var swappedComponentsPerType = _thisSubmissionInfo._currentSwapEntitiesOperations.RecycleOrAdd( + fromID.groupID, _newGroupsDictionaryWithCaller, _recycleGroupDictionaryWithCaller); + + var componentBuildersLength = componentBuilders.Length - 1; + for (var index = componentBuildersLength; index >= 0; index--) + { + var operation = componentBuilders[index]; + + //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) + //recycle or create list of entities to swap + .RecycleOrAdd(toID.groupID, _newListWithCaller, _clearListWithCaller) + //add entity to swap + .Add((fromID.entityID, toID.entityID, caller)); + } + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public bool AnyOperationQueued() + { + return _thisSubmissionInfo.AnyOperationQueued(); } - public void ExecuteRemoveAndSwappingOperations( - Action>>>, FasterList<(EGID, EGID)> - , - EnginesRoot> swapEntities, - Action>>, - FasterList, EnginesRoot> removeEntities, Action removeGroup, + public void ExecuteRemoveAndSwappingOperations(Action>>>, FasterList<(EGID, EGID)>, + EnginesRoot> swapEntities, Action>>, + FasterList, EnginesRoot> removeEntities, Action removeGroup, Action swapGroup, EnginesRoot enginesRoot) { (_thisSubmissionInfo, _lastSubmittedInfo) = (_lastSubmittedInfo, _thisSubmissionInfo); @@ -85,7 +97,6 @@ namespace Svelto.ECS /// todo: entity references should be updated before calling all the methods to avoid callbacks handling /// references that should be marked as invalid. foreach (var (group, caller) in _lastSubmittedInfo._groupsToRemove) - { try { removeGroup(group, enginesRoot); @@ -93,16 +104,14 @@ namespace Svelto.ECS catch { var str = "Crash while removing a whole group on ".FastConcat(group.ToString()) - .FastConcat(" from : ", caller); + .FastConcat(" from : ", caller); Console.LogError(str); throw; } - } foreach (var (fromGroup, toGroup, caller) in _lastSubmittedInfo._groupsToSwap) - { try { swapGroup(fromGroup, toGroup, enginesRoot); @@ -110,32 +119,80 @@ namespace Svelto.ECS catch { var str = "Crash while swapping a whole group on " - .FastConcat(fromGroup.ToString(), " ", toGroup.ToString()).FastConcat(" from : ", caller); + .FastConcat(fromGroup.ToString(), " ", toGroup.ToString()).FastConcat(" from : ", caller); Console.LogError(str); throw; } - } if (_lastSubmittedInfo._entitiesSwapped.count > 0) - swapEntities(_lastSubmittedInfo._currentSwapEntitiesOperations, _lastSubmittedInfo._entitiesSwapped, - enginesRoot); + swapEntities(_lastSubmittedInfo._currentSwapEntitiesOperations, _lastSubmittedInfo._entitiesSwapped + , enginesRoot); if (_lastSubmittedInfo._entitiesRemoved.count > 0) - removeEntities(_lastSubmittedInfo._currentRemoveEntitiesOperations, _lastSubmittedInfo._entitiesRemoved, - enginesRoot); + removeEntities(_lastSubmittedInfo._currentRemoveEntitiesOperations, _lastSubmittedInfo._entitiesRemoved + , enginesRoot); _lastSubmittedInfo.Clear(); } + + FasterDictionary> NewGroupsDictionary() + { + return new FasterDictionary>(); + } + + void RecycleDictionary(ref FasterDictionary> recycled) + { + recycled.Recycle(); + } + + FasterList<(uint, string)> NewList() + { + return new FasterList<(uint, string)>(); + } - public bool AnyOperationQueued() => _thisSubmissionInfo.AnyOperationQueued(); + void ClearList(ref FasterList<(uint, string)> target) + { + target.Clear(); + } + + void RecycleDicitionaryWithCaller(ref FasterDictionary> target) + { + target.Recycle(); + } + + void ClearListWithCaller(ref FasterList<(uint, uint, string)> target) + { + target.Clear(); + } + + FasterList<(uint, uint, string)> NewListWithCaller() + { + return new FasterList<(uint, uint, string)>(); + } + + FasterDictionary>> NewGroupsDictionaryWithCaller() + { + return new FasterDictionary>>(); + } + + void RecycleGroupDictionaryWithCaller(ref FasterDictionary>> recycled) + { + recycled.Recycle(); + } + + FasterDictionary> NewGroupDictionary() + { + return new FasterDictionary>(); + } struct Info { - //from group //actual component type + //from group //actual component type internal FasterDictionary>>> _currentSwapEntitiesOperations; @@ -147,18 +204,21 @@ namespace Svelto.ECS public FasterList<(ExclusiveBuildGroup, ExclusiveBuildGroup, string)> _groupsToSwap; public FasterList<(ExclusiveBuildGroup, string)> _groupsToRemove; - internal bool AnyOperationQueued() => - _entitiesSwapped.count > 0 || _entitiesRemoved.count > 0 || _groupsToSwap.count > 0 || - _groupsToRemove.count > 0; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal bool AnyOperationQueued() + { + return _entitiesSwapped.count > 0 || _entitiesRemoved.count > 0 || _groupsToSwap.count > 0 + || _groupsToRemove.count > 0; + } internal void Clear() { - _currentSwapEntitiesOperations.FastClear(); - _currentRemoveEntitiesOperations.FastClear(); - _entitiesSwapped.FastClear(); - _entitiesRemoved.FastClear(); - _groupsToRemove.FastClear(); - _groupsToSwap.FastClear(); + _currentSwapEntitiesOperations.Recycle(); + _currentRemoveEntitiesOperations.Recycle(); + _entitiesSwapped.Clear(); + _entitiesRemoved.Clear(); + _groupsToRemove.Clear(); + _groupsToSwap.Clear(); } internal void Init() @@ -177,7 +237,18 @@ namespace Svelto.ECS } } - Info _thisSubmissionInfo; Info _lastSubmittedInfo; + Info _thisSubmissionInfo; + + readonly Func>> _newGroupDictionary; + readonly Func>> _newGroupsDictionary; + readonly ActionRef>> _recycleDictionary; + readonly Func> _newList; + readonly ActionRef> _clearList; + readonly Func>>> _newGroupsDictionaryWithCaller; + readonly ActionRef>>> _recycleGroupDictionaryWithCaller; + readonly ActionRef>> _recycleDicitionaryWithCaller; + readonly Func> _newListWithCaller; + readonly ActionRef> _clearListWithCaller; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EntityCollection.cs b/com.sebaslab.svelto.ecs/Core/EntityCollection.cs index 0ee2430..fd6a5ff 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityCollection.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityCollection.cs @@ -4,7 +4,7 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - public readonly ref struct EntityCollection where T : struct, IBaseEntityComponent + public readonly ref struct EntityCollection where T : struct, _IInternalEntityComponent { public EntityCollection(IBuffer buffer, IEntityIDs entityIDs, uint count) : this() { @@ -21,8 +21,8 @@ namespace Svelto.ECS internal readonly IEntityIDs _entityIDs; } - public readonly ref struct EntityCollection where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent + public readonly ref struct EntityCollection where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent { internal EntityCollection(in EntityCollection array1, in EntityCollection array2) { @@ -45,9 +45,9 @@ namespace Svelto.ECS } } - public readonly ref struct EntityCollection where T3 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T1 : struct, IBaseEntityComponent + public readonly ref struct EntityCollection where T3 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T1 : struct, _IInternalEntityComponent { internal EntityCollection (in EntityCollection array1, in EntityCollection array2, in EntityCollection array3) @@ -78,10 +78,10 @@ namespace Svelto.ECS public int count => (int)buffer1.count; } - public readonly ref struct EntityCollection where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent - where T4 : struct, IBaseEntityComponent + public readonly ref struct EntityCollection where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent + where T4 : struct, _IInternalEntityComponent { internal EntityCollection (in EntityCollection array1, in EntityCollection array2, in EntityCollection array3 diff --git a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs index a5eab81..3d42ace 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/DynamicEntityDescriptor.cs @@ -1,5 +1,6 @@ using System; using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -70,21 +71,21 @@ namespace Svelto.ECS _componentsToBuild = Construct(extraEntities.count, extraEntities.ToArrayFast(out _)); } - public void Add() where T : struct, IBaseEntityComponent + public void Add() where T : struct, _IInternalEntityComponent { IComponentBuilder[] extraEntities = { new ComponentBuilder() }; _componentsToBuild = Construct(extraEntities.Length, extraEntities); } - public void Add() where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent + public void Add() where T : struct, _IInternalEntityComponent where U : struct, _IInternalEntityComponent { IComponentBuilder[] extraEntities = { new ComponentBuilder(), new ComponentBuilder() }; _componentsToBuild = Construct(extraEntities.Length, extraEntities); } - public void Add() where T : struct, IBaseEntityComponent - where U : struct, IBaseEntityComponent - where V : struct, IBaseEntityComponent + public void Add() where T : struct, _IInternalEntityComponent + where U : struct, _IInternalEntityComponent + where V : struct, _IInternalEntityComponent { IComponentBuilder[] extraEntities = { diff --git a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs index f70f9ce..5ad8f49 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs @@ -1,3 +1,5 @@ +using Svelto.ECS.Internal; + namespace Svelto.ECS { /// @@ -53,15 +55,15 @@ namespace Svelto.ECS return this; } - protected void Add() where T : struct, IBaseEntityComponent + protected void Add() where T : struct, _IInternalEntityComponent { _dynamicDescriptor.Add(); } - protected void Add() where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent + protected void Add() where T : struct, _IInternalEntityComponent where U : struct, _IInternalEntityComponent { _dynamicDescriptor.Add(); } - protected void Add() where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent + protected void Add() where T : struct, _IInternalEntityComponent where U : struct, _IInternalEntityComponent where V : struct, _IInternalEntityComponent { _dynamicDescriptor.Add(); } diff --git a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/GenericEntityDescriptor.cs b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/GenericEntityDescriptor.cs index 0ae3cda..918fd29 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityDescriptor/GenericEntityDescriptor.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityDescriptor/GenericEntityDescriptor.cs @@ -1,28 +1,45 @@ -namespace Svelto.ECS +using Svelto.ECS.Internal; + +namespace Svelto.ECS { - public abstract class GenericEntityDescriptor : IEntityDescriptor where T : struct, IBaseEntityComponent + public abstract class GenericEntityDescriptor: IEntityDescriptor + where T : struct, _IInternalEntityComponent { static readonly IComponentBuilder[] _componentBuilders; - static GenericEntityDescriptor() { _componentBuilders = new IComponentBuilder[] {new ComponentBuilder()}; } + + static GenericEntityDescriptor() + { + _componentBuilders = new IComponentBuilder[] + { + new ComponentBuilder() + }; + } public IComponentBuilder[] componentsToBuild => _componentBuilders; } - public abstract class GenericEntityDescriptor : IEntityDescriptor - where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent + public abstract class GenericEntityDescriptor: IEntityDescriptor + where T : struct, _IInternalEntityComponent + where U : struct, _IInternalEntityComponent { static readonly IComponentBuilder[] _componentBuilders; static GenericEntityDescriptor() { - _componentBuilders = new IComponentBuilder[] {new ComponentBuilder(), new ComponentBuilder()}; + _componentBuilders = new IComponentBuilder[] + { + new ComponentBuilder(), + new ComponentBuilder() + }; } public IComponentBuilder[] componentsToBuild => _componentBuilders; } - public abstract class GenericEntityDescriptor : IEntityDescriptor - where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent + public abstract class GenericEntityDescriptor: IEntityDescriptor + where T : struct, _IInternalEntityComponent + where U : struct, _IInternalEntityComponent + where V : struct, _IInternalEntityComponent { static readonly IComponentBuilder[] _componentBuilders; @@ -30,18 +47,20 @@ { _componentBuilders = new IComponentBuilder[] { - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder() + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder() }; } public IComponentBuilder[] componentsToBuild => _componentBuilders; } - public abstract class GenericEntityDescriptor : IEntityDescriptor - where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent - where W : struct, IBaseEntityComponent + public abstract class GenericEntityDescriptor: IEntityDescriptor + where T : struct, _IInternalEntityComponent + where U : struct, _IInternalEntityComponent + where V : struct, _IInternalEntityComponent + where W : struct, _IInternalEntityComponent { static readonly IComponentBuilder[] _componentBuilders; @@ -49,19 +68,22 @@ { _componentBuilders = new IComponentBuilder[] { - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder() + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder() }; } public IComponentBuilder[] componentsToBuild => _componentBuilders; } - public abstract class GenericEntityDescriptor : IEntityDescriptor - where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent - where W : struct, IBaseEntityComponent where X : struct, IBaseEntityComponent + public abstract class GenericEntityDescriptor: IEntityDescriptor + where T : struct, _IInternalEntityComponent + where U : struct, _IInternalEntityComponent + where V : struct, _IInternalEntityComponent + where W : struct, _IInternalEntityComponent + where X : struct, _IInternalEntityComponent { static readonly IComponentBuilder[] _componentBuilders; @@ -69,20 +91,24 @@ { _componentBuilders = new IComponentBuilder[] { - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder() + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder() }; } public IComponentBuilder[] componentsToBuild => _componentBuilders; } - public abstract class GenericEntityDescriptor : IEntityDescriptor - where T : struct, IBaseEntityComponent where U : struct, IBaseEntityComponent where V : struct, IBaseEntityComponent - where W : struct, IBaseEntityComponent where X : struct, IBaseEntityComponent where Y : struct, IBaseEntityComponent + public abstract class GenericEntityDescriptor: IEntityDescriptor + where T : struct, _IInternalEntityComponent + where U : struct, _IInternalEntityComponent + where V : struct, _IInternalEntityComponent + where W : struct, _IInternalEntityComponent + where X : struct, _IInternalEntityComponent + where Y : struct, _IInternalEntityComponent { static readonly IComponentBuilder[] _componentBuilders; @@ -90,12 +116,12 @@ { _componentBuilders = new IComponentBuilder[] { - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder(), - new ComponentBuilder() + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder(), + new ComponentBuilder() }; } diff --git a/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs b/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs index 50f0003..b6d2852 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityInfoView.cs @@ -1,6 +1,9 @@ +using Svelto.ECS.Hybrid; +using Svelto.ECS.Internal; + namespace Svelto.ECS { - struct EntityInfoComponent: IBaseEntityComponent + struct EntityInfoComponent: IManagedComponent { public IComponentBuilder[] componentsToBuild; } diff --git a/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs b/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs index ba8845c..0bf812a 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityInitializer.cs @@ -1,4 +1,5 @@ -using Svelto.DataStructures; +using Svelto.Common; +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS @@ -8,17 +9,18 @@ namespace Svelto.ECS public EntityInitializer(EGID id, FasterDictionary group, in EntityReference reference) { - _group = group; - _ID = id; + _group = group; + _ID = id; this.reference = reference; } - public EGID EGID => _ID; + public EGID EGID => _ID; public readonly EntityReference reference; - public void Init(T initializer) where T : struct, IBaseEntityComponent + public void Init(T initializer) where T : struct, _IInternalEntityComponent { - if (_group.TryGetValue(new RefWrapperType(ComponentBuilder.ENTITY_COMPONENT_TYPE), + if (_group.TryGetValue( + new RefWrapperType(TypeCache.type), out var typeSafeDictionary) == false) return; @@ -32,24 +34,26 @@ namespace Svelto.ECS dictionary.GetDirectValueByRef(findElementIndex) = initializer; } - public ref T GetOrAdd() where T : struct, IBaseEntityComponent + internal ref T GetOrAdd() where T : unmanaged, IEntityComponent { ref var entityDictionary = ref _group.GetOrAdd( - new RefWrapperType(ComponentBuilder.ENTITY_COMPONENT_TYPE), TypeSafeDictionaryFactory.Create); + new RefWrapperType(ComponentBuilder.ENTITY_COMPONENT_TYPE), + () => new UnmanagedTypeSafeDictionary(1)); var dictionary = (ITypeSafeDictionary)entityDictionary; return ref dictionary.GetOrAdd(_ID.entityID); } - public ref T Get() where T : struct, IBaseEntityComponent + public ref T Get() where T : struct, _IInternalEntityComponent { - return ref (_group[new RefWrapperType(ComponentBuilder.ENTITY_COMPONENT_TYPE)] as ITypeSafeDictionary) + return ref (_group[new RefWrapperType(TypeCache.type)] as ITypeSafeDictionary) .GetValueByRef(_ID.entityID); } - public bool Has() where T : struct, IBaseEntityComponent + public bool Has() where T : struct, _IInternalEntityComponent { - if (_group.TryGetValue(new RefWrapperType(ComponentBuilder.ENTITY_COMPONENT_TYPE), + if (_group.TryGetValue( + new RefWrapperType(TypeCache.type), out var typeSafeDictionary)) { var dictionary = (ITypeSafeDictionary)typeSafeDictionary; @@ -61,7 +65,7 @@ namespace Svelto.ECS return false; } - readonly EGID _ID; + readonly EGID _ID; 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 fed1eb8..6e12be3 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityReference/EnginesRoot.LocatorMap.cs @@ -1,13 +1,14 @@ -using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; using Svelto.Common; +using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; using Svelto.ECS.Reference; namespace Svelto.ECS { // The EntityLocatorMap provides a bidirectional map to help locate entities without using an EGID which might - // change in runtime. The Entity Locator map uses a reusable unique identifier struct called EntityLocator to + // change at runtime. The Entity Locator map uses a reusable unique identifier struct called EntityLocator to // find the last known EGID from last entity submission. public partial class EnginesRoot { @@ -15,8 +16,8 @@ namespace Svelto.ECS { internal EntityReference ClaimReference() { - int tempFreeIndex; - int newFreeIndex; + int tempFreeIndex; + int newFreeIndex; uint version; do @@ -26,14 +27,14 @@ namespace Svelto.ECS if ((uint)tempFreeIndex >= _entityReferenceMap.count) { newFreeIndex = tempFreeIndex + 1; - version = 0; + version = 0; } else { ref EntityReferenceMapElement element = ref _entityReferenceMap[tempFreeIndex]; // The recycle entities form a linked list, using the egid.entityID to store the next element. newFreeIndex = (int)element.egid.entityID; - version = element.version; + version = element.version; } } while (tempFreeIndex != _nextFreeIndex.CompareExchange(newFreeIndex, tempFreeIndex)); @@ -51,7 +52,8 @@ namespace Svelto.ECS internal void SetReference(EntityReference reference, EGID egid) { // Since references can be claimed in parallel now, it might happen that they are set out of order, - // so we need to resize instead of add. + // so we need to resize instead of add. TODO: what did this comment mean? + if (reference.index >= _entityReferenceMap.count) { #if DEBUG && !PROFILE_SVELTO //THIS IS TO VALIDATE DATE DBC LIKE @@ -66,19 +68,18 @@ namespace Svelto.ECS #if DEBUG && !PROFILE_SVELTO // These debug tests should be enough to detect if indices are being used correctly under native factories - if (_entityReferenceMap[reference.index].version != reference.version || - _entityReferenceMap[reference.index].egid.groupID != ExclusiveGroupStruct.Invalid) + ref var entityReferenceMapElement = ref _entityReferenceMap[reference.index]; + if (entityReferenceMapElement.version != reference.version + || entityReferenceMapElement.egid.groupID != ExclusiveGroupStruct.Invalid) { throw new ECSException("Entity reference already set. This should never happen, please report it."); } #endif - _entityReferenceMap[reference.index] = new EntityReferenceMapElement(egid, reference.version); // Update reverse map from egid to locator. - var groupMap = - _egidToReferenceMap.GetOrAdd(egid.groupID - , () => new SharedSveltoDictionaryNative(0)); + var groupMap = _egidToReferenceMap.GetOrAdd( + egid.groupID, () => new SharedSveltoDictionaryNative(0)); groupMap[egid.entityID] = reference; } @@ -89,9 +90,8 @@ namespace Svelto.ECS _entityReferenceMap[reference.index].egid = to; - var groupMap = - _egidToReferenceMap.GetOrAdd( - to.groupID, () => new SharedSveltoDictionaryNative(0)); + var groupMap = _egidToReferenceMap.GetOrAdd( + to.groupID, () => new SharedSveltoDictionaryNative(0)); groupMap[to.entityID] = reference; } @@ -102,7 +102,7 @@ namespace Svelto.ECS // Invalidate the entity locator element by bumping its version and setting the egid to point to a not existing element. ref var entityReferenceMapElement = ref _entityReferenceMap[reference.index]; - entityReferenceMapElement.egid = new EGID((uint)(int)_nextFreeIndex, 0); + entityReferenceMapElement.egid = new EGID((uint)(int)_nextFreeIndex, 0); //keep the free linked list updated entityReferenceMapElement.version++; // Mark the element as the last element used. @@ -112,8 +112,8 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] EntityReference FetchAndRemoveReference(EGID @from) { - var egidToReference = _egidToReferenceMap[@from.groupID]; - var reference = egidToReference[@from.entityID]; + SharedSveltoDictionaryNative egidToReference = _egidToReferenceMap[@from.groupID]; + EntityReference reference = egidToReference[@from.entityID]; //todo: double searching fro entityID egidToReference.Remove(@from.entityID); return reference; @@ -154,12 +154,22 @@ namespace Svelto.ECS if (groupMap.TryGetValue(egid.entityID, out var locator)) return locator; #if DEBUG && !PROFILE_SVELTO - else throw new ECSException($"Entity {egid} does not exist. Are you creating it? Try getting it from initializer.reference."); + else + throw new ECSException( + $"Entity {egid} does not exist. Are you creating it? Try getting it from initializer.reference."); #endif } return EntityReference.Invalid; } + + public SharedSveltoDictionaryNative GetEntityReferenceMap(ExclusiveGroupStruct groupID) + { + if (_egidToReferenceMap.TryGetValue(groupID, out var groupMap) == false) + throw new ECSException("reference group map not found"); + + return groupMap; + } public bool TryGetEGID(EntityReference reference, out EGID egid) { @@ -168,9 +178,10 @@ namespace Svelto.ECS return false; // Make sure we are querying for the current version of the locator. // Otherwise the locator is pointing to a removed entity. - if (_entityReferenceMap[reference.index].version == reference.version) + ref var entityReferenceMapElement = ref _entityReferenceMap[reference.index]; + if (entityReferenceMapElement.version == reference.version) { - egid = _entityReferenceMap[reference.index].egid; + egid = entityReferenceMapElement.egid; return true; } @@ -183,17 +194,17 @@ namespace Svelto.ECS throw new ECSException("Invalid Reference"); // Make sure we are querying for the current version of the locator. // Otherwise the locator is pointing to a removed entity. - if (_entityReferenceMap[reference.index].version != reference.version) + ref var entityReferenceMapElement = ref _entityReferenceMap[reference.index]; + if (entityReferenceMapElement.version != reference.version) throw new ECSException("outdated Reference"); - return _entityReferenceMap[reference.index].egid; + return entityReferenceMapElement.egid; } internal void PreallocateReferenceMaps(ExclusiveGroupStruct groupID, uint size) { - _egidToReferenceMap - .GetOrAdd(groupID, () => new SharedSveltoDictionaryNative(size)) - .EnsureCapacity(size); + _egidToReferenceMap.GetOrAdd( + groupID, () => new SharedSveltoDictionaryNative(size)).EnsureCapacity(size); _entityReferenceMap.Resize(size); } @@ -219,15 +230,21 @@ namespace Svelto.ECS _egidToReferenceMap.Dispose(); } - SharedNativeInt _nextFreeIndex; + SharedNativeInt _nextFreeIndex; NativeDynamicArrayCast _entityReferenceMap; - + + //todo: this should be just one dictionary it's a double one to be + //able to remove entire groups at once. IT's wasteful since the operation is very rare + //we should find an alternative solution + //alternatively since the groups are guaranteed to be sequential an array should be used instead + //than a dictionary for groups. It could be a good case to implement a 4k chunk based sparseset + SharedSveltoDictionaryNative> _egidToReferenceMap; } EntityReferenceMap entityLocator => _entityLocator; - - EntityReferenceMap _entityLocator; + + EntityReferenceMap _entityLocator; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EntityReference/EntitiesDB.References.cs b/com.sebaslab.svelto.ecs/Core/EntityReference/EntitiesDB.References.cs index 735c0e5..a47fea6 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityReference/EntitiesDB.References.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityReference/EntitiesDB.References.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using Svelto.DataStructures.Native; namespace Svelto.ECS { @@ -27,5 +28,10 @@ namespace Svelto.ECS { return _entityReferencesMap.GetEntityReference(egid); } + + public SharedSveltoDictionaryNative GetEntityReferenceMap(ExclusiveGroupStruct groupID) + { + return _entityReferencesMap.GetEntityReferenceMap(groupID); + } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EntityReference/EntityReference.cs b/com.sebaslab.svelto.ecs/Core/EntityReference/EntityReference.cs index a109198..6b5aa99 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityReference/EntityReference.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityReference/EntityReference.cs @@ -9,8 +9,8 @@ namespace Svelto.ECS /// /// Todo: EntityReference shouldn't map EGIDs as dictionaries keys but directly the indices in the EntityDB arrays /// - [Serialization.DoNotSerialize] - [Serializable] + [Serialization.DoNotSerialize] //it's not a serializable field for svelto serializable system + [Serializable] [StructLayout(LayoutKind.Explicit)] public struct EntityReference : IEquatable { @@ -34,6 +34,8 @@ namespace Svelto.ECS public EntityReference(uint uniqueId) : this(uniqueId, 0) {} + public EntityReference(ulong GID):this() { _GID = GID; } + public EntityReference(uint uniqueId, uint version) : this() { _GID = MAKE_GLOBAL_ID(uniqueId, version); @@ -70,6 +72,11 @@ namespace Svelto.ECS return entitiesDB.TryGetEGID(this, out egid); } + public ulong ToULong() + { + return _GID; + } + static ulong MAKE_GLOBAL_ID(uint uniqueId, uint version) { return (ulong)version << 32 | ((ulong)uniqueId & 0xFFFFFFFF); diff --git a/com.sebaslab.svelto.ecs/Core/EntitySubmitOperation.cs b/com.sebaslab.svelto.ecs/Core/EntitySubmitOperation.cs deleted file mode 100644 index 93cb4e6..0000000 --- a/com.sebaslab.svelto.ecs/Core/EntitySubmitOperation.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Svelto.ECS -{ - enum EntitySubmitOperationType - { - Swap, - Remove, - RemoveGroup, - SwapGroup - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs b/com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs index 0023296..b1f7355 100644 --- a/com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs +++ b/com.sebaslab.svelto.ecs/Core/EntityViewUtility.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using Svelto.DataStructures; +using Svelto.ECS.Hybrid; +using Svelto.ECS.Internal; using Svelto.Utilities; namespace Svelto.ECS @@ -34,7 +36,7 @@ namespace Svelto.ECS internal static void SetEntityViewComponentImplementors(this IComponentBuilder componentBuilder, ref T entityComponent, IEnumerable implementors, - ComponentBuilder.EntityViewComponentCache localCache) where T : struct, IBaseEntityComponent + ComponentBuilder.EntityViewComponentCache localCache) where T : struct, _IInternalEntityComponent { DBC.ECS.Check.Require(implementors != null, NULL_IMPLEMENTOR_ERROR.FastConcat(" entityComponent ", diff --git a/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs b/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs new file mode 100644 index 0000000..27508bc --- /dev/null +++ b/com.sebaslab.svelto.ecs/Core/Filters/CombinedFilterID.cs @@ -0,0 +1,20 @@ +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); + + public CombinedFilterID(int filterID, FilterContextID contextID) + { + id = (long)filterID << 32 | (uint)contextID.id << 16; + } + + public static implicit operator CombinedFilterID((int filterID, FilterContextID contextID) data) + { + return new CombinedFilterID(data.filterID, data.contextID); + } + } +} \ 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 c8148c6..71ae6ed 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/EnginesRoot.Filters.cs @@ -1,7 +1,5 @@ -using System.Collections.Generic; -using Svelto.DataStructures; +using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS @@ -67,7 +65,7 @@ namespace Svelto.ECS var filters = _persistentEntityFilters.unsafeValues; //remove duplicates - _transientEntityIDsLeftWithoutDuplicates.FastClear(); + _transientEntityIDsLeftWithoutDuplicates.Clear(); var entityAffectedCount = entityIDsLeftAndAffectedByRemoval.count; for (int i = 0; i < entityAffectedCount; i++) { @@ -129,7 +127,7 @@ namespace Svelto.ECS var numberOfFilters = listOfFilters.count; //remove duplicates - _transientEntityIDsLeftWithoutDuplicates.FastClear(); + _transientEntityIDsLeftWithoutDuplicates.Clear(); var entityAffectedCount = entityIDsLeftAndAffectedByRemoval.count; for (int i = 0; i < entityAffectedCount; i++) { diff --git a/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs b/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs index 0037fbc..8baae31 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.Filters.cs @@ -1,57 +1,24 @@ -using System; +using System; +using System.Runtime.CompilerServices; using System.Threading; using Svelto.Common; using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { - public struct FilterContextID - { - public readonly uint id; - - internal FilterContextID(uint id) - { - DBC.ECS.Check.Require(id < ushort.MaxValue, "too many types registered, HOW :)"); - - this.id = id; - } - - public static FilterContextID GetNewContextID() - { - return EntitiesDB.SveltoFilters.GetNewContextID(); - } - } - - public readonly struct CombinedFilterID - { - internal readonly long id; - - public FilterContextID contextID => new FilterContextID((uint)((id & 0xFFFF0000) >> 16)); - public uint filterID => (uint)(id >> 32); - - public CombinedFilterID(int filterID, FilterContextID contextID) - { - id = (long)filterID << 32 | (uint)contextID.id << 16; - } - - public static implicit operator CombinedFilterID((int filterID, FilterContextID contextID) data) - { - return new CombinedFilterID(data.filterID, data.contextID); - } - } - //this cannot be inside EntitiesDB otherwise it will cause hashing of reference in Burst public class Internal_FilterHelper { //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) where T: struct, IBaseEntityComponent + public static long CombineFilterIDs(CombinedFilterID combinedFilterID) + where T : struct, _IInternalEntityComponent { var id = (uint)ComponentID.id.Data; - + var combineFilterIDs = (long)combinedFilterID.id | id; return combineFilterIDs; @@ -62,7 +29,8 @@ namespace Svelto.ECS { public SveltoFilters GetFilters() { - return new SveltoFilters(_enginesRoot._persistentEntityFilters, + return new SveltoFilters( + _enginesRoot._persistentEntityFilters, _enginesRoot._indicesOfPersistentFiltersUsedByThisComponent, _enginesRoot._transientEntityFilters); } @@ -72,11 +40,11 @@ namespace Svelto.ECS public readonly struct SveltoFilters { static readonly SharedStaticWrapper uniqueContextID; - -#if UNITY_BURST + +#if UNITY_BURST [Unity.Burst.BurstDiscard] //SharedStatic values must be initialized from not burstified code -#endif +#endif public static FilterContextID GetNewContextID() { return new FilterContextID((uint)Interlocked.Increment(ref uniqueContextID.Data)); @@ -84,26 +52,28 @@ namespace Svelto.ECS public SveltoFilters(SharedSveltoDictionaryNative persistentEntityFilters, SharedSveltoDictionaryNative> - indicesOfPersistentFiltersUsedByThisComponent, + indicesOfPersistentFiltersUsedByThisComponent, SharedSveltoDictionaryNative transientEntityFilters) { - _persistentEntityFilters = persistentEntityFilters; + _persistentEntityFilters = persistentEntityFilters; _indicesOfPersistentFiltersUsedByThisComponent = indicesOfPersistentFiltersUsedByThisComponent; - _transientEntityFilters = transientEntityFilters; + _transientEntityFilters = transientEntityFilters; } - -#if UNITY_BURST + +#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 + FilterContextID filterContextId, NativeRefWrapperType typeRef) + where T : unmanaged, IEntityComponent { return ref GetOrCreatePersistentFilter(new CombinedFilterID(filterID, filterContextId), typeRef); } public ref EntityFilterCollection GetOrCreatePersistentFilter(CombinedFilterID filterID, - NativeRefWrapperType typeRef) where T : unmanaged, IEntityComponent + NativeRefWrapperType typeRef) + where T : unmanaged, IEntityComponent { long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); - + if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) return ref _persistentEntityFilters.GetDirectValueByRef(index); @@ -135,59 +105,91 @@ namespace Svelto.ECS /// /// #if UNITY_BURST && UNITY_COLLECTIONS - [Unity.Collections.NotBurstCompatible] + [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper.wrapper; #endif - public ref EntityFilterCollection GetOrCreatePersistentFilter(int filterID, FilterContextID filterContextId) - where T : unmanaged, IBaseEntityComponent + [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.Collections.NotBurstCompatible] + [Unity.Burst.BurstDiscard] //not burst compatible because of TypeRefWrapper.wrapper and GetOrAdd callback; #endif public ref EntityFilterCollection GetOrCreatePersistentFilter(CombinedFilterID filterID) - where T : unmanaged, IBaseEntityComponent + 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 typeRef = TypeRefWrapper.wrapper; var filterCollection = new EntityFilterCollection(filterID); _persistentEntityFilters.Add(combineFilterIDs, filterCollection); var lastIndex = _persistentEntityFilters.count - 1; - _indicesOfPersistentFiltersUsedByThisComponent.GetOrAdd(new NativeRefWrapperType(typeRef), - () => new NativeDynamicArrayCast(1, Svelto.Common.Allocator.Persistent)).Add(lastIndex); + _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 + { + long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) + throw new ECSException("filter already exists"); + + 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); + } + + static NativeDynamicArrayCast Builder() + { + return new NativeDynamicArrayCast(1, Allocator.Persistent); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref EntityFilterCollection GetPersistentFilter(int filterID, FilterContextID filterContextId) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { return ref GetPersistentFilter(new CombinedFilterID(filterID, filterContextId)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref EntityFilterCollection GetPersistentFilter(CombinedFilterID filterID) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); - + if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) return ref _persistentEntityFilters.GetDirectValueByRef(index); - throw new Exception("filter not found"); + throw new ECSException("filter not found"); } - - public bool TryGetPersistentFilter(CombinedFilterID combinedFilterID, out EntityFilterCollection entityCollection) - where T : unmanaged, IBaseEntityComponent + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetPersistentFilter(CombinedFilterID combinedFilterID, + out EntityFilterCollection entityCollection) + where T : unmanaged, _IInternalEntityComponent { long combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(combinedFilterID); - + if (_persistentEntityFilters.TryFindIndex(combineFilterIDs, out var index) == true) { entityCollection = _persistentEntityFilters.GetDirectValueByRef(index); @@ -198,7 +200,9 @@ namespace Svelto.ECS return false; } - public EntityFilterCollectionsEnumerator GetPersistentFilters() where T : unmanaged, IBaseEntityComponent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntityFilterCollectionsEnumerator GetPersistentFilters() + where T : unmanaged, _IInternalEntityComponent { if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true) @@ -206,9 +210,10 @@ namespace Svelto.ECS _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index), _persistentEntityFilters); - throw new Exception($"no filters associated with the type {TypeCache.name}"); + throw new ECSException($"no filters associated with the type {TypeCache.name}"); } - + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EntityFilterCollectionsWithContextEnumerator GetPersistentFilters(FilterContextID filterContextId) { if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( @@ -217,10 +222,12 @@ namespace Svelto.ECS _indicesOfPersistentFiltersUsedByThisComponent.GetDirectValueByRef(index), _persistentEntityFilters, filterContextId); - throw new Exception($"no filters associated with the type {TypeCache.name}"); + throw new ECSException($"no filters associated with the type {TypeCache.name}"); } - - public bool TryGetPersistentFilters(FilterContextID filterContextId, out EntityFilterCollectionsWithContextEnumerator enumerator) + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetPersistentFilters(FilterContextID filterContextId, + out EntityFilterCollectionsWithContextEnumerator enumerator) { if (_indicesOfPersistentFiltersUsedByThisComponent.TryFindIndex( new NativeRefWrapperType(new RefWrapperType(typeof(T))), out var index) == true) @@ -236,12 +243,75 @@ namespace Svelto.ECS return false; } + /// + /// Creates a transient filter. Transient filters are deleted after each submission + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref EntityFilterCollection GetOrCreateTransientFilter(CombinedFilterID filterID) + where T : unmanaged, _IInternalEntityComponent + { + var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + + if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + return ref _transientEntityFilters.GetDirectValueByRef(index); + + var filterCollection = new EntityFilterCollection(filterID); + + _transientEntityFilters.Add(combineFilterIDs, filterCollection); + + return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetTransientFilter(CombinedFilterID filterID, out EntityFilterCollection entityCollection) + where T : unmanaged, _IInternalEntityComponent + { + var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + + if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + { + entityCollection = _transientEntityFilters.GetDirectValueByRef(index); + return true; + } + + entityCollection = default; + return false; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref EntityFilterCollection GetTransientFilter(CombinedFilterID filterID) + where T : unmanaged, _IInternalEntityComponent + { + var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); + + if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + { + return ref _transientEntityFilters.GetDirectValueByRef(index); + } + + throw new ECSException($"no filters associated with the type {TypeCache.name}"); + } + + public void CreateTransientFilter(CombinedFilterID filterID) + 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); + } + public struct EntityFilterCollectionsEnumerator { public EntityFilterCollectionsEnumerator(NativeDynamicArrayCast getDirectValueByRef, - SharedSveltoDictionaryNative sharedSveltoDictionaryNative) : this() + SharedSveltoDictionaryNative sharedSveltoDictionaryNative): this() { - _getDirectValueByRef = getDirectValueByRef; + _getDirectValueByRef = getDirectValueByRef; _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative; } @@ -250,104 +320,84 @@ namespace Svelto.ECS return this; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { if (_currentIndex < _getDirectValueByRef.count) { _currentIndex++; - + return true; } return false; } - public ref EntityFilterCollection Current => - ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); + public ref EntityFilterCollection Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); + } + } - readonly NativeDynamicArrayCast _getDirectValueByRef; + readonly NativeDynamicArrayCast _getDirectValueByRef; readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; - int _currentIndex; + int _currentIndex; } - + public struct EntityFilterCollectionsWithContextEnumerator { public EntityFilterCollectionsWithContextEnumerator(NativeDynamicArrayCast getDirectValueByRef, SharedSveltoDictionaryNative sharedSveltoDictionaryNative, - FilterContextID filterContextId) : this() + FilterContextID filterContextId): this() { - _getDirectValueByRef = getDirectValueByRef; + _getDirectValueByRef = getDirectValueByRef; _sharedSveltoDictionaryNative = sharedSveltoDictionaryNative; - _filterContextId = filterContextId; + _filterContextId = filterContextId; } - + public EntityFilterCollectionsWithContextEnumerator GetEnumerator() { return this; } - + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { while (_currentIndex++ < _getDirectValueByRef.count && _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1).combinedFilterID - .contextID.id != _filterContextId.id) ; - - if (_currentIndex - 1 < _getDirectValueByRef.count) + .contextID.id != _filterContextId.id) ; + + if (_currentIndex - 1 < _getDirectValueByRef.count) return true; - + return false; } - - public ref EntityFilterCollection Current => - ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); - - readonly NativeDynamicArrayCast _getDirectValueByRef; - readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; - readonly FilterContextID _filterContextId; - int _currentIndex; - } - - /// - /// Creates a transient filter. Transient filters are deleted after each submission - /// - /// - /// - public ref EntityFilterCollection GetOrCreateTransientFilter(CombinedFilterID filterID) - where T : unmanaged, IBaseEntityComponent - { - var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); - - if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) - return ref _transientEntityFilters.GetDirectValueByRef(index); - var filterCollection = new EntityFilterCollection(filterID); - - _transientEntityFilters.Add(combineFilterIDs, filterCollection); - - return ref _transientEntityFilters.GetDirectValueByRef((uint)(_transientEntityFilters.count - 1)); - } - - public bool TryGetTransientFilter(CombinedFilterID filterID, out EntityFilterCollection entityCollection) - where T : unmanaged, IBaseEntityComponent - { - var combineFilterIDs = Internal_FilterHelper.CombineFilterIDs(filterID); - - if (_transientEntityFilters.TryFindIndex(combineFilterIDs, out var index)) + public ref EntityFilterCollection Current { - entityCollection = _transientEntityFilters.GetDirectValueByRef(index); - return true; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ref _sharedSveltoDictionaryNative.GetDirectValueByRef((uint)_currentIndex - 1); + } } - entityCollection = default; - return false; + readonly NativeDynamicArrayCast _getDirectValueByRef; + readonly SharedSveltoDictionaryNative _sharedSveltoDictionaryNative; + readonly FilterContextID _filterContextId; + int _currentIndex; } readonly SharedSveltoDictionaryNative _persistentEntityFilters; readonly SharedSveltoDictionaryNative> - _indicesOfPersistentFiltersUsedByThisComponent; + _indicesOfPersistentFiltersUsedByThisComponent; readonly SharedSveltoDictionaryNative _transientEntityFilters; + static readonly Func> _builder = Builder; } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/EntityFilterCollection.cs b/com.sebaslab.svelto.ecs/Core/Filters/EntityFilterCollection.cs index aa673c2..808c61d 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/EntityFilterCollection.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/EntityFilterCollection.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using Svelto.Common; using Svelto.DataStructures.Native; +using Svelto.ECS.Internal; using Svelto.ECS.Native; namespace Svelto.ECS @@ -22,28 +23,28 @@ namespace Svelto.ECS public EntityFilterIterator GetEnumerator() => new EntityFilterIterator(this); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Add(EGID egid, NativeEGIDMapper mmap) where T : unmanaged, IBaseEntityComponent + public bool Add(EGID egid, NativeEGIDMapper mmap) where T : unmanaged, _IInternalEntityComponent { DBC.ECS.Check.Require(mmap.groupID == egid.groupID, "not compatible NativeEgidMapper used"); return Add(egid, mmap.GetIndex(egid.entityID)); } - public bool Add(EGID egid, NativeEGIDMultiMapper mmap) where T : unmanaged, IBaseEntityComponent + public bool Add(EGID egid, NativeEGIDMultiMapper mmap) where T : unmanaged, _IInternalEntityComponent { return Add(egid, mmap.GetIndex(egid)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Add(EGID egid, uint toIndex) + public bool Add(EGID egid, uint indexInComponentArray) { - return GetOrCreateGroupFilter(egid.groupID).Add(egid.entityID, toIndex); + return GetOrCreateGroupFilter(egid.groupID).Add(egid.entityID, indexInComponentArray); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(uint entityID, ExclusiveGroupStruct groupId, uint index) + public void Add(uint entityID, ExclusiveGroupStruct groupId, uint indexInComponentArray) { - Add(new EGID(entityID, groupId), index); + Add(new EGID(entityID, groupId), indexInComponentArray); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -86,6 +87,20 @@ namespace Svelto.ECS return groupFilter; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public GroupFilters CreateGroupFilter(ExclusiveBuildGroup group) + { + if (_filtersPerGroup.TryGetValue(group, out var groupFilter) == false) + { + groupFilter = new GroupFilters(group); + _filtersPerGroup.Add(group, groupFilter); + + return groupFilter; + } + + throw new ECSException("group already linked to filter {group}"); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public GroupFilters GetGroupFilter(ExclusiveGroupStruct group) { @@ -146,10 +161,11 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Add(uint entityId, uint entityIndex) + public bool Add(uint entityId, uint indexInComponentArray) { //TODO: when sentinels are finished, we need to add AsWriter here - return _entityIDToDenseIndex.TryAdd(entityId, entityIndex, out _); + //cannot write in parallel + return _entityIDToDenseIndex.TryAdd(entityId, indexInComponentArray, out _); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -183,7 +199,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void Clear() { - _entityIDToDenseIndex.FastClear(); + _entityIDToDenseIndex.Clear(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs b/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs new file mode 100644 index 0000000..2f286bc --- /dev/null +++ b/com.sebaslab.svelto.ecs/Core/Filters/FilterContextID.cs @@ -0,0 +1,19 @@ +namespace Svelto.ECS +{ + public struct FilterContextID + { + public readonly uint id; + + internal FilterContextID(uint id) + { + DBC.ECS.Check.Require(id < ushort.MaxValue, "too many types registered, HOW :)"); + + this.id = id; + } + + public static FilterContextID GetNewContextID() + { + return EntitiesDB.SveltoFilters.GetNewContextID(); + } + } +} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.LegacyFilters.cs b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs similarity index 93% rename from com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.LegacyFilters.cs rename to com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs index b7e14ac..2a48772 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/EntitiesDB.LegacyFilters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/EntitiesDB.LegacyFilters.cs @@ -1,6 +1,8 @@ +#if SVELTO_LEGACY_FILTERS using DBC.ECS; using Svelto.DataStructures; using Svelto.DataStructures.Native; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -32,14 +34,14 @@ namespace Svelto.ECS } public ref LegacyFilterGroup CreateOrGetFilterForGroup(int filterID, ExclusiveGroupStruct groupID) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { var refWrapper = TypeRefWrapper.wrapper; return ref CreateOrGetFilterForGroup(filterID, groupID, refWrapper); } - public bool HasFiltersForGroup(ExclusiveGroupStruct groupID) where T : struct, IBaseEntityComponent + public bool HasFiltersForGroup(ExclusiveGroupStruct groupID) where T : struct, _IInternalEntityComponent { if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary) == false) return false; @@ -48,7 +50,7 @@ namespace Svelto.ECS } public bool HasFilterForGroup(int filterID, ExclusiveGroupStruct groupID) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { if (_filtersLegacy.TryGetValue(TypeRefWrapper.wrapper, out var fasterDictionary) == false) return false; @@ -60,7 +62,7 @@ namespace Svelto.ECS } public ref LegacyGroupFilters CreateOrGetFiltersForGroup(ExclusiveGroupStruct groupID) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { var fasterDictionary = _filtersLegacy.GetOrAdd(TypeRefWrapper.wrapper, () => new FasterDictionary()); @@ -70,7 +72,7 @@ namespace Svelto.ECS } public ref LegacyGroupFilters GetFiltersForGroup(ExclusiveGroupStruct groupID) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO if (_filtersLegacy.ContainsKey(TypeRefWrapper.wrapper) == false) @@ -84,7 +86,7 @@ namespace Svelto.ECS } public ref LegacyFilterGroup GetFilterForGroup(int filterId, ExclusiveGroupStruct groupID) - where T : struct, IBaseEntityComponent + where T : struct, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO if (_filtersLegacy.ContainsKey(TypeRefWrapper.wrapper) == false) @@ -97,7 +99,7 @@ namespace Svelto.ECS } public bool TryGetFilterForGroup(int filterId, ExclusiveGroupStruct groupID, - out LegacyFilterGroup groupLegacyFilter) where T : struct, IBaseEntityComponent + out LegacyFilterGroup groupLegacyFilter) where T : struct, _IInternalEntityComponent { groupLegacyFilter = default; @@ -114,7 +116,7 @@ namespace Svelto.ECS } public bool TryGetFiltersForGroup(ExclusiveGroupStruct groupID, - out LegacyGroupFilters legacyGroupFilters) where T : struct, IBaseEntityComponent + out LegacyGroupFilters legacyGroupFilters) where T : struct, _IInternalEntityComponent { legacyGroupFilters = default; @@ -166,7 +168,7 @@ namespace Svelto.ECS fasterDictionary[@group].DisposeFilter(resetFilterID); } - public bool TryRemoveEntityFromFilter(int filtersID, EGID egid) where T : struct, IBaseEntityComponent + public bool TryRemoveEntityFromFilter(int filtersID, EGID egid) where T : struct, _IInternalEntityComponent { if (TryGetFilterForGroup(filtersID, egid.groupID, out var filter)) return filter.TryRemove(egid.entityID); @@ -174,7 +176,7 @@ namespace Svelto.ECS return false; } - public void RemoveEntityFromFilter(int filtersID, EGID egid) where T : struct, IBaseEntityComponent + public void RemoveEntityFromFilter(int filtersID, EGID egid) where T : struct, _IInternalEntityComponent { ref var filter = ref GetFilterForGroup(filtersID, egid.groupID); @@ -207,4 +209,5 @@ namespace Svelto.ECS _filtersLegacy; } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/LegacyFilterGroup.cs b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilterGroup.cs similarity index 97% rename from com.sebaslab.svelto.ecs/Core/Filters/LegacyFilterGroup.cs rename to com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilterGroup.cs index b9d2e00..3266c88 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/LegacyFilterGroup.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilterGroup.cs @@ -1,7 +1,8 @@ -using System.Runtime.CompilerServices; +#if SVELTO_LEGACY_FILTERS +using System.Runtime.CompilerServices; using Svelto.Common; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; +using Svelto.DataStructures; namespace Svelto.ECS { @@ -125,7 +126,7 @@ namespace Svelto.ECS if (_denseListOfIndicesToEntityComponentArray.isValid == false) throw new ECSException($"invalid Filter"); #endif - _indexOfEntityInDenseList.FastClear(); + _indexOfEntityInDenseList.Clear(); _reverseEIDs.Clear(); _denseListOfIndicesToEntityComponentArray.Clear(); } @@ -195,7 +196,7 @@ namespace Svelto.ECS } else { - _indexOfEntityInDenseList.FastClear(); + _indexOfEntityInDenseList.Clear(); _reverseEIDs.Clear(); _denseListOfIndicesToEntityComponentArray.Clear(); } @@ -209,4 +210,5 @@ namespace Svelto.ECS internal readonly ExclusiveGroupStruct _exclusiveGroupStruct; internal readonly int _ID; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/LegacyFilteredIndices.cs b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilteredIndices.cs similarity index 92% rename from com.sebaslab.svelto.ecs/Core/Filters/LegacyFilteredIndices.cs rename to com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilteredIndices.cs index ce3dd62..167248b 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/LegacyFilteredIndices.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyFilteredIndices.cs @@ -1,5 +1,6 @@ -using System.Runtime.CompilerServices; -using Svelto.ECS.DataStructures; +#if SVELTO_LEGACY_FILTERS +using System.Runtime.CompilerServices; +using Svelto.DataStructures; namespace Svelto.ECS { @@ -35,4 +36,5 @@ namespace Svelto.ECS readonly NativeDynamicArrayCast _denseListOfIndicesToEntityComponentArray; readonly int _count; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/LegacyGroupFilters.cs b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyGroupFilters.cs similarity index 97% rename from com.sebaslab.svelto.ecs/Core/Filters/LegacyGroupFilters.cs rename to com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyGroupFilters.cs index 48dc864..a4ea677 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/LegacyGroupFilters.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/Legacy/LegacyGroupFilters.cs @@ -1,4 +1,5 @@ -using Svelto.DataStructures; +#if SVELTO_LEGACY_FILTERS +using Svelto.DataStructures; using Svelto.DataStructures.Native; namespace Svelto.ECS @@ -69,7 +70,7 @@ namespace Svelto.ECS foreach (var filter in _legacyFilters) filter.value.Dispose(); - _legacyFilters.FastClear(); + _legacyFilters.Clear(); } internal ref LegacyFilterGroup CreateOrGetFilter(int filterID) @@ -101,4 +102,5 @@ namespace Svelto.ECS //filterID, filter SharedSveltoDictionaryNative _legacyFilters; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterCollection.cs b/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterCollection.cs index d2e0a10..42dfa73 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterCollection.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterCollection.cs @@ -1,10 +1,11 @@ using System.Runtime.CompilerServices; using Svelto.DataStructures.Native; +using Svelto.ECS.Internal; using Svelto.ECS.Native; namespace Svelto.ECS { - public struct NativeEntityFilterCollection where T : unmanaged, IBaseEntityComponent + public struct NativeEntityFilterCollection where T : unmanaged, _IInternalEntityComponent { internal NativeEntityFilterCollection(NativeEGIDMultiMapper mmap) { @@ -114,8 +115,8 @@ namespace Svelto.ECS internal void Clear() { - _indexToEntityId.FastClear(); - _entityIDToDenseIndex.FastClear(); + _indexToEntityId.Clear(); + _entityIDToDenseIndex.Clear(); } internal bool HasEntity(uint entityId) => _entityIDToDenseIndex.ContainsKey(entityId); diff --git a/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterIterator.cs b/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterIterator.cs index 151b882..1513b5e 100644 --- a/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterIterator.cs +++ b/com.sebaslab.svelto.ecs/Core/Filters/NativeEntityFilterIterator.cs @@ -1,6 +1,8 @@ -namespace Svelto.ECS +using Svelto.ECS.Internal; + +namespace Svelto.ECS { - public readonly ref struct NativeEntityFilterIterator where T : unmanaged, IBaseEntityComponent + public readonly ref struct NativeEntityFilterIterator where T : unmanaged, _IInternalEntityComponent { internal NativeEntityFilterIterator(NativeEntityFilterCollection filter) { diff --git a/com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs b/com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs index b59c894..1285ce6 100644 --- a/com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs +++ b/com.sebaslab.svelto.ecs/Core/GlobalTypeID.cs @@ -1,6 +1,7 @@ using System.Threading; using Svelto.Common; -using Svelto.ECS.DataStructures; +using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -18,11 +19,11 @@ namespace Svelto.ECS void FillFromByteArray(EntityInitializer init, NativeBag buffer); } - class Filler : IFiller where T : struct, IBaseEntityComponent + class Filler : IFiller where T : struct, _IInternalEntityComponent { static Filler() { - DBC.ECS.Check.Require(TypeType.isUnmanaged() == true, "invalid type used"); + DBC.ECS.Check.Require(TypeCache.isUnmanaged == true, "invalid type used"); } //it's an internal interface @@ -50,7 +51,7 @@ namespace Svelto.ECS TYPE_IDS = new Svelto.DataStructures.FasterList(); } - internal static void Register(IFiller entityBuilder) where T : struct, IBaseEntityComponent + internal static void Register(IFiller entityBuilder) where T : struct, _IInternalEntityComponent { var location = EntityComponentID.ID.Data = GlobalTypeID.NextID(); TYPE_IDS.AddAt(location, entityBuilder); diff --git a/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs b/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs index 824750a..23adf1a 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/EntitiesDB.FindGroups.cs @@ -7,10 +7,10 @@ namespace Svelto.ECS { public partial class EntitiesDB { - public LocalFasterReadOnlyList FindGroups() where T1 : IBaseEntityComponent + public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) where T1 : _IInternalEntityComponent { FasterList result = localgroups.Value.groupArray; - result.FastClear(); + result.Clear(); if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper , out FasterDictionary result1) == false) @@ -22,20 +22,19 @@ namespace Svelto.ECS for (int j = 0; j < result1Count; j++) { var group = fasterDictionaryNodes1[j].key; - if (group.IsEnabled()) - { - result.Add(group); - } + if (ignoreDisabledBit == false && group.IsEnabled() == false) continue; + + result.Add(group); } return result; } - public LocalFasterReadOnlyList FindGroups() - where T1 : IBaseEntityComponent where T2 : IBaseEntityComponent + public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) + where T1 : _IInternalEntityComponent where T2 : _IInternalEntityComponent { FasterList result = localgroups.Value.groupArray; - result.FastClear(); + result.Clear(); if (groupsPerComponent.TryGetValue(TypeRefWrapper.wrapper , out FasterDictionary result1) == false) @@ -53,7 +52,7 @@ namespace Svelto.ECS for (int i = 0; i < result1Count; i++) { var groupID = fasterDictionaryNodes1[i].key; - if (!groupID.IsEnabled()) continue; + if (ignoreDisabledBit == false && groupID.IsEnabled() == false) continue; for (int j = 0; j < result2Count; j++) { @@ -82,8 +81,8 @@ namespace Svelto.ECS /// /// /// - public LocalFasterReadOnlyList FindGroups() - where T1 : IBaseEntityComponent where T2 : IBaseEntityComponent where T3 : IBaseEntityComponent + public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) + where T1 : _IInternalEntityComponent where T2 : _IInternalEntityComponent where T3 : _IInternalEntityComponent { FasterList> localArray = localgroups.Value.listOfGroups; @@ -98,7 +97,7 @@ namespace Svelto.ECS return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - localgroups.Value.groups.FastClear(); + localgroups.Value.groups.Clear(); FasterDictionary localGroups = localgroups.Value.groups; @@ -114,10 +113,9 @@ namespace Svelto.ECS foreach (var value in localArray[startIndex]) { - if (value.key.IsEnabled()) - { - localGroups.Add(value.key, value.key); - } + if (ignoreDisabledBit == false && value.key.IsEnabled() == false) continue; + + localGroups.Add(value.key, value.key); } var groupData = localArray[++startIndex % 3]; @@ -132,11 +130,11 @@ namespace Svelto.ECS , (uint) localGroups.count); } - public LocalFasterReadOnlyList FindGroups() - where T1 : IBaseEntityComponent - where T2 : IBaseEntityComponent - where T3 : IBaseEntityComponent - where T4 : IBaseEntityComponent + public LocalFasterReadOnlyList FindGroups(bool ignoreDisabledBit = false) + where T1 : _IInternalEntityComponent + where T2 : _IInternalEntityComponent + where T3 : _IInternalEntityComponent + where T4 : _IInternalEntityComponent { FasterList> localArray = localgroups.Value.listOfGroups; @@ -154,26 +152,27 @@ namespace Svelto.ECS return new LocalFasterReadOnlyList( FasterReadOnlyList.DefaultEmptyList); - localgroups.Value.groups.FastClear(); + localgroups.Value.groups.Clear(); - FasterDictionary localGroups = localgroups.Value.groups; + var localGroups = localgroups.Value.groups; int startIndex = 0; int min = int.MaxValue; for (int i = 0; i < 4; i++) - if (localArray[i].count < min) + { + var fasterDictionary = localArray[i]; + if (fasterDictionary.count < min) { - min = localArray[i].count; + min = fasterDictionary.count; startIndex = i; } + } foreach (var value in localArray[startIndex]) { - if (value.key.IsEnabled()) - { - localGroups.Add(value.key, value.key); - } + if (ignoreDisabledBit == false && value.key.IsEnabled() == false) continue; + localGroups.Add(value.key, value.key); } var groupData = localArray[++startIndex & 3]; //&3 == %4 diff --git a/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveBuildGroup.cs b/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveBuildGroup.cs index bbda837..bbacbc6 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveBuildGroup.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveBuildGroup.cs @@ -24,7 +24,7 @@ namespace Svelto.ECS public override string ToString() { - return this.group.ToName(); + return group.ToName(); } internal ExclusiveGroupStruct @group { get; } diff --git a/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveGroupStruct.cs b/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveGroupStruct.cs index c5ef40c..5f3e264 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveGroupStruct.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/ExclusiveGroupStruct.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +#pragma warning disable CS0660, CS0661 namespace Svelto.ECS { @@ -11,7 +12,7 @@ namespace Svelto.ECS //the type doesn't implement IEqualityComparer, what implements it is a custom comparer public readonly struct ExclusiveGroupStruct : IEquatable, IComparable { - public static readonly ExclusiveGroupStruct Invalid = default; //must stay here because of Burst + public static readonly ExclusiveGroupStruct Invalid; //must stay here because of Burst public ExclusiveGroupStruct(byte[] data, uint pos):this() { @@ -24,13 +25,7 @@ namespace Svelto.ECS DBC.ECS.Check.Ensure(id < _globalId, "Invalid group ID deserialiased"); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object obj) - { - return obj is ExclusiveGroupStruct other && Equals(other); - } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { @@ -146,7 +141,7 @@ namespace Svelto.ECS _idInternal = groupID; } - ExclusiveGroupStruct(uint groupID, byte bytemask):this() + internal ExclusiveGroupStruct(uint groupID, byte bytemask):this() { #if DEBUG && !PROFILE_SVELTO if (groupID >= 0xFFFFFF) diff --git a/com.sebaslab.svelto.ecs/Core/Groups/GroupCompound.cs b/com.sebaslab.svelto.ecs/Core/Groups/GroupCompound.cs index 7595819..cc1ef6e 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/GroupCompound.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/GroupCompound.cs @@ -17,14 +17,13 @@ namespace Svelto.ECS internal static readonly ThreadLocal skipStaticCompoundConstructorsWith2Tags = new ThreadLocal(); } - interface ITouchedByReflection - { - } + interface ITouchedByReflection { } - public abstract class GroupCompound : ITouchedByReflection where G1 : GroupTag - where G2 : GroupTag - where G3 : GroupTag - where G4 : GroupTag + public abstract class GroupCompound: ITouchedByReflection + where G1 : GroupTag + where G2 : GroupTag + where G3 : GroupTag + where G4 : GroupTag { static GroupCompound() { @@ -32,22 +31,26 @@ namespace Svelto.ECS if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0 && GroupCompoundInitializer.skipStaticCompoundConstructorsWith4Tags.Value == false) { - var - group = - new ExclusiveGroup(); //todo: it's a bit of a waste to create a class here even if this is a static constructor + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor( + typeof(GroupCompound).TypeHandle); + var group = new ExclusiveGroup( + GroupTag.bitmask | GroupTag.bitmask | GroupTag.bitmask | GroupTag.bitmask + | bitmask); _Groups = new FasterList(1); _Groups.Add(group); -#if DEBUG && !PROFILE_SVELTO +#if DEBUG var name = - $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint)group.id}"; + $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name}-{typeof(G4).Name} ID {(uint)group.id}"; GroupNamesMap.idToName[group] = name; #endif //The hashname is independent from the actual group ID. this is fundamental because it is want //guarantees the hash to be the same across different machines GroupHashMap.RegisterGroup(group, typeof(GroupCompound).FullName); + //ToArrayFast is theoretically not correct, but since multiple 0s are ignored and we don't care if we + //add one, we avoid an allocation _GroupsHashSet = new HashSet(_Groups.ToArrayFast(out _)); GroupCompoundInitializer.skipStaticCompoundConstructorsWith4Tags.Value = true; @@ -127,12 +130,14 @@ namespace Svelto.ECS } public static FasterReadOnlyList Groups => - new FasterReadOnlyList(_Groups); + new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static bool Includes(ExclusiveGroupStruct group) { + DBC.ECS.Check.Require(group != ExclusiveGroupStruct.Invalid, "invalid group passed"); + return _GroupsHashSet.Contains(group); } @@ -149,29 +154,33 @@ namespace Svelto.ECS } static readonly FasterList _Groups; - static readonly HashSet _GroupsHashSet; + static readonly HashSet _GroupsHashSet; //we are changing this with Interlocked, so it cannot be readonly static int isInitializing; + protected internal static ExclusiveGroupBitmask bitmask; } - public abstract class GroupCompound : ITouchedByReflection where G1 : GroupTag - where G2 : GroupTag - where G3 : GroupTag + public abstract class GroupCompound: ITouchedByReflection + where G1 : GroupTag + where G2 : GroupTag + where G3 : GroupTag { static GroupCompound() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0 && GroupCompoundInitializer.skipStaticCompoundConstructorsWith3Tags.Value == false) { - var - group = - new ExclusiveGroup(); //todo: it's a bit of a waste to create a class here even if this is a static constructor + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor( + typeof(GroupCompound).TypeHandle); + + var group = new ExclusiveGroup( + GroupTag.bitmask | GroupTag.bitmask | GroupTag.bitmask | bitmask); _Groups = new FasterList(1); _Groups.Add(group); -#if DEBUG && !PROFILE_SVELTO +#if DEBUG var name = $"Compound: {typeof(G1).Name}-{typeof(G2).Name}-{typeof(G3).Name} ID {(uint)group.id}"; GroupNamesMap.idToName[group] = name; #endif @@ -212,12 +221,14 @@ namespace Svelto.ECS } public static FasterReadOnlyList Groups => - new FasterReadOnlyList(_Groups); + new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static bool Includes(ExclusiveGroupStruct group) { + DBC.ECS.Check.Require(group != ExclusiveGroupStruct.Invalid, "invalid group passed"); + return _GroupsHashSet.Contains(group); } @@ -234,27 +245,31 @@ namespace Svelto.ECS } static readonly FasterList _Groups; - static readonly HashSet _GroupsHashSet; + static readonly HashSet _GroupsHashSet; //we are changing this with Interlocked, so it cannot be readonly static int isInitializing; + protected internal static ExclusiveGroupBitmask bitmask; } - public abstract class GroupCompound : ITouchedByReflection where G1 : GroupTag where G2 : GroupTag + public abstract class GroupCompound: ITouchedByReflection + where G1 : GroupTag + where G2 : GroupTag { static GroupCompound() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0 && GroupCompoundInitializer.skipStaticCompoundConstructorsWith2Tags.Value == false) { - var - group = - new ExclusiveGroup(); //todo: it's a bit of a waste to create a class here even if this is a static constructor + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor( + typeof(GroupCompound).TypeHandle); + + var group = new ExclusiveGroup(GroupTag.bitmask | GroupTag.bitmask | bitmask); _Groups = new FasterList(1); _Groups.Add(group); -#if DEBUG && !PROFILE_SVELTO +#if DEBUG GroupNamesMap.idToName[group] = $"Compound: {typeof(G1).Name}-{typeof(G2).Name} ID {group.id}"; #endif //The hashname is independent from the actual group ID. this is fundamental because it is want @@ -264,9 +279,10 @@ namespace Svelto.ECS _GroupsHashSet = new HashSet(_Groups.ToArrayFast(out _)); GroupCompoundInitializer.skipStaticCompoundConstructorsWith2Tags.Value = true; - GroupCompound._Groups = _Groups; + GroupCompound._Groups = _Groups; GroupCompoundInitializer.skipStaticCompoundConstructorsWith2Tags.Value = false; - GroupCompound._GroupsHashSet = _GroupsHashSet; + + GroupCompound._GroupsHashSet = _GroupsHashSet; //every abstract group preemptively adds this group, it may or may not be empty in future GroupTag.Add(group); @@ -275,12 +291,15 @@ namespace Svelto.ECS } public static FasterReadOnlyList Groups => - new FasterReadOnlyList(_Groups); + new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); + //TODO there is an overlap between this method and ExclusiveGroupExtensions FoundIn public static bool Includes(ExclusiveGroupStruct group) { + DBC.ECS.Check.Require(group != ExclusiveGroupStruct.Invalid, "invalid group passed"); + return _GroupsHashSet.Contains(group); } @@ -297,9 +316,10 @@ namespace Svelto.ECS } static readonly FasterList _Groups; - static readonly HashSet _GroupsHashSet; + static readonly HashSet _GroupsHashSet; static int isInitializing; + protected internal static ExclusiveGroupBitmask bitmask; } /// @@ -309,23 +329,35 @@ namespace Svelto.ECS /// groups with the same adjective, a group tag needs to hold all the groups sharing it. /// /// - public abstract class GroupTag : ITouchedByReflection where T : GroupTag + public abstract class GroupTag: ITouchedByReflection + where T : GroupTag { static GroupTag() { if (Interlocked.CompareExchange(ref isInitializing, 1, 0) == 0) { - var group = new ExclusiveGroup(); + //Allow to call GroupTag static constructors like +// public class Dead: GroupTag +// { +// static Dead() +// { +// bitmask = ExclusiveGroupBitmask.DISABLED_BIT; +// } +// }; + System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(T).TypeHandle); + + var group = new ExclusiveGroup(bitmask); _Groups.Add(group); -#if DEBUG && !PROFILE_SVELTO +#if DEBUG var typeInfo = typeof(T); - var name = $"Compound: {typeInfo.Name} ID {(uint)group.id}"; - + var name = $"Compound: {typeInfo.Name} ID {(uint)group.id}"; +#if !PROFILE_SVELTO var typeInfoBaseType = typeInfo.BaseType; if (typeInfoBaseType.GenericTypeArguments[0] != typeInfo) //todo: this should shield from using a pattern different than public class GROUP_NAME : GroupTag {} however I am not sure it's working throw new ECSException("Invalid Group Tag declared"); +#endif GroupNamesMap.idToName[group] = name; #endif @@ -338,12 +370,14 @@ namespace Svelto.ECS } public static FasterReadOnlyList Groups => - new FasterReadOnlyList(_Groups); + new FasterReadOnlyList(_Groups); public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static bool Includes(ExclusiveGroupStruct group) { + DBC.ECS.Check.Require(group != ExclusiveGroupStruct.Invalid, "invalid group passed"); + return _GroupsHashSet.Contains(group); } @@ -361,9 +395,10 @@ namespace Svelto.ECS } static readonly FasterList _Groups = new FasterList(1); - static readonly HashSet _GroupsHashSet; + static readonly HashSet _GroupsHashSet; //we are changing this with Interlocked, so it cannot be readonly static int isInitializing; + protected internal static ExclusiveGroupBitmask bitmask; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs b/com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs index a70023b..b525fee 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/GroupHashMap.cs @@ -18,9 +18,9 @@ namespace Svelto.ECS { try { - var typeOfExclusiveGroup = typeof(ExclusiveGroup); + var typeOfExclusiveGroup = typeof(ExclusiveGroup); var typeOfExclusiveGroupStruct = typeof(ExclusiveGroupStruct); - var typeOfExclusiveBuildGroup = typeof(ExclusiveBuildGroup); + var typeOfExclusiveBuildGroup = typeof(ExclusiveBuildGroup); foreach (Type type in AssemblyUtility.GetTypesSafe(assembly)) { @@ -40,36 +40,37 @@ namespace Svelto.ECS foreach (var field in fields) { - if (field.IsStatic - && (typeOfExclusiveGroup.IsAssignableFrom(field.FieldType) - || typeOfExclusiveGroupStruct.IsAssignableFrom(field.FieldType) + if (field.IsStatic + && (typeOfExclusiveGroup.IsAssignableFrom(field.FieldType) + || typeOfExclusiveGroupStruct.IsAssignableFrom(field.FieldType) || typeOfExclusiveBuildGroup.IsAssignableFrom(field.FieldType))) { - uint groupID; + uint groupIDAndBitMask; if (typeOfExclusiveGroup.IsAssignableFrom(field.FieldType)) { var group = (ExclusiveGroup)field.GetValue(null); - groupID = ((ExclusiveGroupStruct)@group).id; + groupIDAndBitMask = ((ExclusiveGroupStruct)@group).ToIDAndBitmask(); } - else - if (typeOfExclusiveGroupStruct.IsAssignableFrom(field.FieldType)) + else if (typeOfExclusiveGroupStruct.IsAssignableFrom(field.FieldType)) { var group = (ExclusiveGroupStruct)field.GetValue(null); - groupID = @group.id; + groupIDAndBitMask = @group.ToIDAndBitmask(); } else { var group = (ExclusiveBuildGroup)field.GetValue(null); - groupID = ((ExclusiveGroupStruct)@group).id; + groupIDAndBitMask = ((ExclusiveGroupStruct)@group).ToIDAndBitmask(); } { - ExclusiveGroupStruct group = new ExclusiveGroupStruct(groupID); + var bitMask = (byte)(groupIDAndBitMask >> 24); + var groupID = groupIDAndBitMask & 0xFFFFFF; + ExclusiveGroupStruct group = new ExclusiveGroupStruct(groupID, bitMask); #if DEBUG && !PROFILE_SVELTO if (GroupNamesMap.idToName.ContainsKey(@group) == false) GroupNamesMap.idToName[@group] = - $"{type.FullName}.{field.Name} {@group.id})"; + $"{type.FullName}.{field.Name} {@group.id})"; #endif //The hashname is independent from the actual group ID. this is fundamental because it is want //guarantees the hash to be the same across different machines diff --git a/com.sebaslab.svelto.ecs/Core/Groups/GroupNamesMap.cs b/com.sebaslab.svelto.ecs/Core/Groups/GroupNamesMap.cs index c0bc06c..5df712f 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/GroupNamesMap.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/GroupNamesMap.cs @@ -3,12 +3,12 @@ using Svelto.ECS; static class GroupNamesMap { -#if DEBUG && !PROFILE_SVELTO +#if DEBUG static GroupNamesMap() { idToName = new Dictionary(); } internal static readonly Dictionary idToName; #endif -#if DEBUG && !PROFILE_SVELTO +#if DEBUG public static string ToName(this in ExclusiveGroupStruct group) { Dictionary idToName = GroupNamesMap.idToName; diff --git a/com.sebaslab.svelto.ecs/Core/Groups/QueryGroups.cs b/com.sebaslab.svelto.ecs/Core/Groups/QueryGroups.cs index 99c4bad..fea02ba 100644 --- a/com.sebaslab.svelto.ecs/Core/Groups/QueryGroups.cs +++ b/com.sebaslab.svelto.ecs/Core/Groups/QueryGroups.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS.Experimental { @@ -49,7 +50,7 @@ namespace Svelto.ECS.Experimental public FasterList Evaluate() { - _groups.FastClear(); + _groups.Clear(); foreach (var item in _sets) _groups.Add(item); @@ -210,7 +211,7 @@ namespace Svelto.ECS.Experimental readonly FasterReadOnlyList _group; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Count(EntitiesDB entitiesDB) where T : struct, IBaseEntityComponent + public int Count(EntitiesDB entitiesDB) where T : struct, _IInternalEntityComponent { var count = 0; @@ -220,7 +221,7 @@ namespace Svelto.ECS.Experimental return count; } - public int Max(EntitiesDB entitiesDB) where T : struct, IBaseEntityComponent + public int Max(EntitiesDB entitiesDB) where T : struct, _IInternalEntityComponent { var max = 0; diff --git a/com.sebaslab.svelto.ecs/Core/Hybrid/IEntityViewComponent.cs b/com.sebaslab.svelto.ecs/Core/Hybrid/IEntityViewComponent.cs index 2b5c642..813a99c 100644 --- a/com.sebaslab.svelto.ecs/Core/Hybrid/IEntityViewComponent.cs +++ b/com.sebaslab.svelto.ecs/Core/Hybrid/IEntityViewComponent.cs @@ -1,8 +1,12 @@ +using Svelto.ECS.Internal; + namespace Svelto.ECS.Hybrid { - public interface IManagedComponent:IBaseEntityComponent + ///IManagedComponents are pure struct components stored in managed memory + public interface IManagedComponent:_IInternalEntityComponent {} + /// IEntityViewComponents are components that leverage on the implementers pattern (not recommended in most cases) public interface IEntityViewComponent:IManagedComponent #if SLOW_SVELTO_SUBMISSION ,INeedEGID diff --git a/com.sebaslab.svelto.ecs/Core/IBaseEntityComponent.cs b/com.sebaslab.svelto.ecs/Core/IBaseEntityComponent.cs deleted file mode 100644 index 669c9f9..0000000 --- a/com.sebaslab.svelto.ecs/Core/IBaseEntityComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Svelto.ECS -{ - ///Entity Components MUST implement IEntityComponent - public interface IBaseEntityComponent - { - } - - public interface IEntityComponent:IBaseEntityComponent - { - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/IEngine.cs b/com.sebaslab.svelto.ecs/Core/IEngine.cs index 74c0c35..271e26c 100644 --- a/com.sebaslab.svelto.ecs/Core/IEngine.cs +++ b/com.sebaslab.svelto.ecs/Core/IEngine.cs @@ -1,3 +1,4 @@ +using System; using Svelto.ECS.Internal; namespace Svelto.ECS.Internal @@ -65,14 +66,15 @@ namespace Svelto.ECS /// Interface to mark an Engine as reacting on entities added /// /// - public interface IReactOnAdd : IReactOnAdd where T : IBaseEntityComponent + [Obsolete] + public interface IReactOnAdd : IReactOnAdd where T : _IInternalEntityComponent { void Add(ref T entityComponent, EGID egid); } - public interface IReactOnAddEx : IReactOnAddEx where T : struct, IBaseEntityComponent + public interface IReactOnAddEx : IReactOnAddEx where T : struct, _IInternalEntityComponent { - void Add((uint start, uint end) rangeOfEntities, in EntityCollection collection, + void Add((uint start, uint end) rangeOfEntities, in EntityCollection entities, ExclusiveGroupStruct groupID); } @@ -80,22 +82,24 @@ namespace Svelto.ECS /// Interface to mark an Engine as reacting on entities removed /// /// - public interface IReactOnRemove : IReactOnRemove where T : IBaseEntityComponent + [Obsolete] + public interface IReactOnRemove : IReactOnRemove where T : _IInternalEntityComponent { void Remove(ref T entityComponent, EGID egid); } - public interface IReactOnAddAndRemoveEx : IReactOnAddEx, IReactOnRemoveEx where T : struct, IBaseEntityComponent + public interface IReactOnAddAndRemoveEx : IReactOnAddEx, IReactOnRemoveEx where T : struct, _IInternalEntityComponent { } - public interface IReactOnRemoveEx : IReactOnRemoveEx where T : struct, IBaseEntityComponent + public interface IReactOnRemoveEx : IReactOnRemoveEx where T : struct, _IInternalEntityComponent { - void Remove((uint start, uint end) rangeOfEntities, in EntityCollection collection, + void Remove((uint start, uint end) rangeOfEntities, in EntityCollection entities, ExclusiveGroupStruct groupID); } - public interface IReactOnAddAndRemove : IReactOnAdd, IReactOnRemove where T : IBaseEntityComponent + [Obsolete] + public interface IReactOnAddAndRemove : IReactOnAdd, IReactOnRemove where T : _IInternalEntityComponent { } @@ -104,7 +108,7 @@ namespace Svelto.ECS /// It can work together with IReactOnRemove which normally is not called on enginesroot disposed /// /// - public interface IReactOnDispose : IReactOnDispose where T : IBaseEntityComponent + public interface IReactOnDispose : IReactOnDispose where T : _IInternalEntityComponent { void Remove(ref T entityComponent, EGID egid); } @@ -113,14 +117,19 @@ namespace Svelto.ECS /// Interface to mark an Engine as reacting to entities swapping group /// /// - public interface IReactOnSwap : IReactOnSwap where T : IBaseEntityComponent + [Obsolete] + public interface IReactOnSwap : IReactOnSwap where T : _IInternalEntityComponent { void MovedTo(ref T entityComponent, ExclusiveGroupStruct previousGroup, EGID egid); } - public interface IReactOnSwapEx : IReactOnSwapEx where T : struct, IBaseEntityComponent + /// + /// All the entities have been already submitted in the database (swapped) when this callback is triggered + /// + /// + public interface IReactOnSwapEx : IReactOnSwapEx where T : struct, _IInternalEntityComponent { - void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection collection, + void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection entities, ExclusiveGroupStruct fromGroup, ExclusiveGroupStruct toGroup); } @@ -131,4 +140,9 @@ namespace Svelto.ECS { void EntitiesSubmitted(); } + + public interface IReactOnSubmissionStarted : IReactEngine + { + void EntitiesSubmissionStarting(); + } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/IEntityComponent.cs b/com.sebaslab.svelto.ecs/Core/IEntityComponent.cs new file mode 100644 index 0000000..1426f34 --- /dev/null +++ b/com.sebaslab.svelto.ecs/Core/IEntityComponent.cs @@ -0,0 +1,9 @@ +using Svelto.ECS.Internal; + +namespace Svelto.ECS +{ + ///IEntityComponents are unmanaged struct components stored in native memory. If they are not unmanaged they won't be recognised as IEntityComponent! + public interface IEntityComponent:_IInternalEntityComponent + { + } +} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/SetEGIDWithoutBoxing.cs b/com.sebaslab.svelto.ecs/Core/SetEGIDWithoutBoxing.cs index 0daf562..6788931 100644 --- a/com.sebaslab.svelto.ecs/Core/SetEGIDWithoutBoxing.cs +++ b/com.sebaslab.svelto.ecs/Core/SetEGIDWithoutBoxing.cs @@ -1,10 +1,10 @@ #if SLOW_SVELTO_SUBMISSION namespace Svelto.ECS.Internal { - delegate void SetEGIDWithoutBoxingActionCast(ref T target, EGID egid) where T : struct, IBaseEntityComponent; - delegate void SetReferenceWithoutBoxingActionCast(ref T target, EntityReference egid) where T : struct, IBaseEntityComponent; + delegate void SetEGIDWithoutBoxingActionCast(ref T target, EGID egid) where T : struct, _IInternalEntityComponent; + delegate void SetReferenceWithoutBoxingActionCast(ref T target, EntityReference egid) where T : struct, _IInternalEntityComponent; - static class SetEGIDWithoutBoxing where T : struct, IBaseEntityComponent + static class SetEGIDWithoutBoxing where T : struct, _IInternalEntityComponent { public static readonly SetEGIDWithoutBoxingActionCast SetIDWithoutBoxing = MakeSetter(); public static readonly SetReferenceWithoutBoxingActionCast SetRefWithoutBoxing = MakeSetterReference(); diff --git a/com.sebaslab.svelto.ecs/Core/SpecialEnumerators/DoubleIterationEnumerator.cs b/com.sebaslab.svelto.ecs/Core/SpecialEnumerators/DoubleIterationEnumerator.cs index 9918bfb..88c953c 100644 --- a/com.sebaslab.svelto.ecs/Core/SpecialEnumerators/DoubleIterationEnumerator.cs +++ b/com.sebaslab.svelto.ecs/Core/SpecialEnumerators/DoubleIterationEnumerator.cs @@ -1,8 +1,9 @@ using System; +using Svelto.ECS.Internal; namespace Svelto.ECS { - public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, IBaseEntityComponent + public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, _IInternalEntityComponent { public DoubleEntitiesEnumerator(GroupsEnumerable groupsEnumerable) { _groupsEnumerable = groupsEnumerable; } @@ -90,12 +91,12 @@ namespace Svelto.ECS int _indexB; } - public ref struct ValueRef + public readonly ref struct ValueRef { - public readonly GroupsEnumerable.RefCurrent _current; - public readonly int _indexA; - public readonly GroupsEnumerable.RefCurrent _refCurrent; - public readonly int _indexB; + readonly GroupsEnumerable.RefCurrent _current; + readonly int _indexA; + readonly GroupsEnumerable.RefCurrent _refCurrent; + readonly int _indexB; public ValueRef (GroupsEnumerable.RefCurrent current, int indexA, GroupsEnumerable.RefCurrent refCurrent @@ -130,8 +131,8 @@ namespace Svelto.ECS } } - public readonly ref struct DoubleIterationEnumerator where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent + public readonly ref struct DoubleIterationEnumerator where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent { public DoubleIterationEnumerator(GroupsEnumerable groupsEnumerable) { @@ -222,7 +223,7 @@ namespace Svelto.ECS int _indexB; } - public ref struct ValueRef + public readonly ref struct ValueRef { public readonly GroupsEnumerable.RefCurrent _current; public readonly int _indexA; @@ -268,9 +269,9 @@ namespace Svelto.ECS /// /// /// - public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent + public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent { public DoubleEntitiesEnumerator(GroupsEnumerable groupsEnumerable) { @@ -361,12 +362,12 @@ namespace Svelto.ECS int _indexB; } - public ref struct ValueRef + public readonly ref struct ValueRef { - public readonly GroupsEnumerable.RefCurrent _current; - public readonly int _indexA; - public readonly GroupsEnumerable.RefCurrent _refCurrent; - public readonly int _indexB; + readonly GroupsEnumerable.RefCurrent _current; + readonly int _indexA; + readonly GroupsEnumerable.RefCurrent _refCurrent; + readonly int _indexB; public ValueRef (GroupsEnumerable.RefCurrent current, int indexA @@ -409,10 +410,10 @@ namespace Svelto.ECS /// /// /// - public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent - where T4 : struct, IBaseEntityComponent + public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent + where T4 : struct, _IInternalEntityComponent { public DoubleEntitiesEnumerator(GroupsEnumerable groupsEnumerable) { diff --git a/com.sebaslab.svelto.ecs/Core/Streams/Consumer.cs b/com.sebaslab.svelto.ecs/Core/Streams/Consumer.cs index 561acd4..f2d553d 100644 --- a/com.sebaslab.svelto.ecs/Core/Streams/Consumer.cs +++ b/com.sebaslab.svelto.ecs/Core/Streams/Consumer.cs @@ -1,10 +1,11 @@ using System; using Svelto.Common; using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { - public struct Consumer : IDisposable where T : unmanaged, IBaseEntityComponent + public struct Consumer : IDisposable where T : unmanaged, _IInternalEntityComponent { internal Consumer(string name, uint capacity) : this() { @@ -20,10 +21,10 @@ namespace Svelto.ECS string.Empty #endif ); - mustBeDisposed = MemoryUtilities.Alloc(1, Allocator.Persistent); + mustBeDisposed = MemoryUtilities.NativeAlloc(1, Allocator.Persistent); *(bool*) mustBeDisposed = false; - isActive = MemoryUtilities.Alloc(1, Allocator.Persistent); + isActive = MemoryUtilities.NativeAlloc(1, Allocator.Persistent); *(bool*) isActive = true; } } @@ -79,8 +80,8 @@ namespace Svelto.ECS public void Free() { - MemoryUtilities.Free(mustBeDisposed, Allocator.Persistent); - MemoryUtilities.Free(isActive, Allocator.Persistent); + MemoryUtilities.NativeFree(mustBeDisposed, Allocator.Persistent); + MemoryUtilities.NativeFree(isActive, Allocator.Persistent); } public void Pause() diff --git a/com.sebaslab.svelto.ecs/Core/Streams/EnginesRoot.Streams.cs b/com.sebaslab.svelto.ecs/Core/Streams/EnginesRoot.Streams.cs index 5d1ec94..380efd6 100644 --- a/com.sebaslab.svelto.ecs/Core/Streams/EnginesRoot.Streams.cs +++ b/com.sebaslab.svelto.ecs/Core/Streams/EnginesRoot.Streams.cs @@ -1,18 +1,19 @@ using System.Runtime.CompilerServices; +using Svelto.ECS.Internal; namespace Svelto.ECS { public partial class EnginesRoot { [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Consumer GenerateConsumer(string name, uint capacity) where T : unmanaged, IBaseEntityComponent + internal Consumer GenerateConsumer(string name, uint capacity) where T : unmanaged, _IInternalEntityComponent { return _entityStreams.GenerateConsumer(name, capacity); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Consumer GenerateConsumer(ExclusiveGroupStruct group, string name, uint capacity) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { return _entityStreams.GenerateConsumer(@group, name, capacity); } diff --git a/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs b/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs index 933d0f8..cd93291 100644 --- a/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs +++ b/com.sebaslab.svelto.ecs/Core/Streams/EntitiesStreams.cs @@ -1,5 +1,6 @@ using System; using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -15,7 +16,7 @@ namespace Svelto.ECS struct EntitiesStreams : IDisposable { internal Consumer GenerateConsumer(string name, uint capacity) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { if (_streams.ContainsKey(TypeRefWrapper.wrapper) == false) _streams[TypeRefWrapper.wrapper] = new EntityStream(); @@ -24,7 +25,7 @@ namespace Svelto.ECS } public Consumer GenerateConsumer(ExclusiveGroupStruct group, string name, uint capacity) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { if (_streams.ContainsKey(TypeRefWrapper.wrapper) == false) _streams[TypeRefWrapper.wrapper] = new EntityStream(); @@ -33,12 +34,12 @@ namespace Svelto.ECS return typeSafeStream.GenerateConsumer(group, name, capacity); } - internal void PublishEntity(ref T entity, EGID egid) where T : unmanaged, IBaseEntityComponent + internal void PublishEntity(ref T entity, EGID egid) where T : unmanaged, _IInternalEntityComponent { if (_streams.TryGetValue(TypeRefWrapper.wrapper, out var typeSafeStream)) (typeSafeStream as EntityStream).PublishEntity(ref entity, egid); else - Console.LogDebug("No Consumers are waiting for this entity to change ", typeof(T)); + Console.LogDebug($"No Consumers are waiting for this entity to change {typeof(T)}"); } public void Dispose() diff --git a/com.sebaslab.svelto.ecs/Core/Streams/EntityStream.cs b/com.sebaslab.svelto.ecs/Core/Streams/EntityStream.cs index 6f0fd0c..d8517f7 100644 --- a/com.sebaslab.svelto.ecs/Core/Streams/EntityStream.cs +++ b/com.sebaslab.svelto.ecs/Core/Streams/EntityStream.cs @@ -1,4 +1,5 @@ using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -7,7 +8,7 @@ namespace Svelto.ECS void Dispose(); } - public class EntityStream : ITypeSafeStream where T : unmanaged, IBaseEntityComponent + public class EntityStream : ITypeSafeStream where T : unmanaged, _IInternalEntityComponent { readonly ThreadSafeFasterList> _consumers; diff --git a/com.sebaslab.svelto.ecs/Core/Streams/GenericentityStreamConsumerFactory.cs b/com.sebaslab.svelto.ecs/Core/Streams/GenericentityStreamConsumerFactory.cs index e2e7ae3..47e2577 100644 --- a/com.sebaslab.svelto.ecs/Core/Streams/GenericentityStreamConsumerFactory.cs +++ b/com.sebaslab.svelto.ecs/Core/Streams/GenericentityStreamConsumerFactory.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { @@ -12,14 +13,14 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public Consumer GenerateConsumer(string name, uint capacity) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { return _enginesRoot.Target.GenerateConsumer(name, capacity); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public Consumer GenerateConsumer(ExclusiveGroupStruct @group, string name, uint capacity) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { return _enginesRoot.Target.GenerateConsumer(group, name, capacity); } @@ -31,9 +32,9 @@ namespace Svelto.ECS public interface IEntityStreamConsumerFactory { - Consumer GenerateConsumer(string name, uint capacity) where T : unmanaged, IBaseEntityComponent; + Consumer GenerateConsumer(string name, uint capacity) where T : unmanaged, _IInternalEntityComponent; Consumer GenerateConsumer(ExclusiveGroupStruct @group, string name, uint capacity) - where T : unmanaged, IBaseEntityComponent; + where T : unmanaged, _IInternalEntityComponent; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Core/TypeSafeDictionaryFactory.cs b/com.sebaslab.svelto.ecs/Core/TypeSafeDictionaryFactory.cs index 47b472d..5ed2333 100644 --- a/com.sebaslab.svelto.ecs/Core/TypeSafeDictionaryFactory.cs +++ b/com.sebaslab.svelto.ecs/Core/TypeSafeDictionaryFactory.cs @@ -4,19 +4,11 @@ using Svelto.ECS.Internal; namespace Svelto.ECS { - static class TypeSafeDictionaryFactory where T : struct, IBaseEntityComponent + static class TypeSafeDictionaryFactory where T : struct, _IInternalEntityComponent { - static readonly bool isUnmanaged = typeof(T).IsUnmanagedEx() + static readonly bool isUnmanaged = TypeCache.isUnmanaged && typeof(IEntityViewComponent).IsAssignableFrom(typeof(T)) == false; - public static ITypeSafeDictionary Create() - { - if (isUnmanaged) - return new UnmanagedTypeSafeDictionary(1); - - return new ManagedTypeSafeDictionary(1); - } - public static ITypeSafeDictionary Create(uint size) { if (isUnmanaged) diff --git a/com.sebaslab.svelto.ecs/Core/_IInternalEntityComponent.cs b/com.sebaslab.svelto.ecs/Core/_IInternalEntityComponent.cs new file mode 100644 index 0000000..1d04abe --- /dev/null +++ b/com.sebaslab.svelto.ecs/Core/_IInternalEntityComponent.cs @@ -0,0 +1,10 @@ +namespace Svelto.ECS +{ + namespace Internal + { + ///This interfaces shouldn't be used outside the svelto assembly, use interfaces that inherit from this + public interface _IInternalEntityComponent + { + } + } +} \ 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 d0c9850..9a7a9ec 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/ITypeSafeDictionary.cs @@ -4,7 +4,7 @@ using Svelto.DataStructures; namespace Svelto.ECS.Internal { - public interface ITypeSafeDictionary : ITypeSafeDictionary where TValue : IBaseEntityComponent + public interface ITypeSafeDictionary : ITypeSafeDictionary where TValue : _IInternalEntityComponent { void Add(uint egidEntityId, in TValue entityComponent); diff --git a/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs index 5c29251..1d7b272 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/ManagedTypeSafeDictionary.cs @@ -3,18 +3,12 @@ using System.Runtime.CompilerServices; using System.Threading; using Svelto.Common; using Svelto.DataStructures; -using Svelto.ECS.Hybrid; namespace Svelto.ECS.Internal { - public sealed class ManagedTypeSafeDictionary : ITypeSafeDictionary - where TValue : struct, IBaseEntityComponent + sealed class ManagedTypeSafeDictionary : ITypeSafeDictionary + where TValue : struct, _IInternalEntityComponent { - static readonly Type _type = typeof(TValue); -#if SLOW_SVELTO_SUBMISSION - static readonly bool _hasEgid = typeof(INeedEGID).IsAssignableFrom(_type); - static readonly bool _hasReference = typeof(INeedEntityReference).IsAssignableFrom(_type); -#endif static readonly ThreadLocal cachedEntityIDM = new ThreadLocal(() => new ManagedEntityIDs()); @@ -24,7 +18,7 @@ namespace Svelto.ECS.Internal new SveltoDictionary>, ManagedStrategy, ManagedStrategy>(size, Allocator.Managed); } - + public IEntityIDs entityIDs { get @@ -99,7 +93,7 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public ITypeSafeDictionary Create() { - return TypeSafeDictionaryFactory.Create(1); + return new ManagedTypeSafeDictionary(1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -289,7 +283,7 @@ namespace Svelto.ECS.Internal } /// - /// Execute all the engine IReactOnDispose for eahc component registered in the DB when it's disposed of + /// Execute all the engine IReactOnDispose for each component registered in the DB when it's disposed of /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ExecuteEnginesDisposeCallbacks_Group diff --git a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs index 8d55495..7feaa44 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryMethods.cs @@ -18,7 +18,7 @@ namespace Svelto.ECS.Internal , ExclusiveGroupStruct toGroupID) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { foreach (var tuple in fromDictionary) { @@ -57,7 +57,7 @@ namespace Svelto.ECS.Internal , in PlatformProfiler sampler) where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { if (entitycomponentenginesdb.TryGetValue(new RefWrapperType(TypeCache.type) , out var entityComponentsEngines)) @@ -78,7 +78,9 @@ namespace Svelto.ECS.Internal for (var j = 0; j < entityComponentsEngines.count; j++) using (sampler.Sample(entityComponentsEngines[j].name)) { +#pragma warning disable CS0612 ((IReactOnAdd)entityComponentsEngines[j].engine).Add(ref entity, egid); +#pragma warning restore CS0612 } } catch (Exception e) @@ -99,7 +101,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { if (allEngines.TryGetValue(new RefWrapperType(TypeCache.type), out var entityComponentsEngines) == false) @@ -137,7 +139,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { if (reactiveenginesremove.TryGetValue(new RefWrapperType(TypeCache.type) , out var entityComponentsEngines)) @@ -158,7 +160,9 @@ namespace Svelto.ECS.Internal for (var j = 0; j < entityComponentsEngines.count; j++) using (profiler.Sample(entityComponentsEngines[j].name)) { +#pragma warning disable CS0612 ((IReactOnRemove)entityComponentsEngines[j].engine).Remove(ref entity, egid); +#pragma warning restore CS0612 } } catch @@ -184,7 +188,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { if (reactiveenginesremove.TryGetValue(new RefWrapperType(TypeCache.type) , out var reactiveEnginesRemovePerType)) @@ -201,7 +205,9 @@ namespace Svelto.ECS.Internal using (sampler.Sample(reactiveEnginesRemovePerType[i].name)) { +#pragma warning disable CS0612 ((IReactOnRemove)reactiveEnginesRemovePerType[i].engine).Remove( +#pragma warning restore CS0612 ref entity, egid); } } @@ -250,7 +256,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { if (reactiveenginesswap.count == 0) return; @@ -268,7 +274,9 @@ namespace Svelto.ECS.Internal for (var j = 0; j < reactiveenginesswap.count; j++) using (sampler.Sample(reactiveenginesswap[j].name)) { +#pragma warning disable CS0612 ((IReactOnSwap)reactiveenginesswap[j].engine).MovedTo( +#pragma warning restore CS0612 ref entityComponent, fromgroup, newEgid); } } @@ -295,7 +303,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { //get all the engines linked to TValue if (!reactiveenginesswap.TryGetValue(new RefWrapperType(TypeCache.type) @@ -314,7 +322,9 @@ namespace Svelto.ECS.Internal using (sampler.Sample(reactiveEnginesSwapPerType[i].name)) { +#pragma warning disable CS0612 ((IReactOnSwap)reactiveEnginesSwapPerType[i].engine).MovedTo( +#pragma warning restore CS0612 ref entityComponent, fromgroup, newEgid); } } @@ -361,7 +371,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { var iterations = infostoprocess.count; @@ -409,7 +419,7 @@ namespace Svelto.ECS.Internal where Strategy1 : struct, IBufferStrategy> where Strategy2 : struct, IBufferStrategy where Strategy3 : struct, IBufferStrategy - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { var iterations = infostoprocess.count; @@ -455,9 +465,9 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ExecuteEnginesAddEntityCallbacksFast (FasterDictionary>> fasterDictionary - , ExclusiveGroupStruct groupId, (uint, uint) valueTuple, IEntityIDs entityids + , ExclusiveGroupStruct groupId, (uint, uint) rangeTuple, IEntityIDs entityids , ITypeSafeDictionary typeSafeDictionary, PlatformProfiler profiler) - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { //get all the engines linked to TValue if (!fasterDictionary.TryGetValue(new RefWrapperType(TypeCache.type) @@ -470,7 +480,7 @@ namespace Svelto.ECS.Internal using (profiler.Sample(entityComponentsEngines[i].name)) { ((IReactOnAddEx)entityComponentsEngines[i].engine).Add( - valueTuple + rangeTuple , new EntityCollection(typeSafeDictionary.GetValues(out var count), entityids, count) , groupId); } @@ -489,7 +499,7 @@ namespace Svelto.ECS.Internal (FasterList> fasterList, ExclusiveGroupStruct fromGroup , ExclusiveGroupStruct toGroup, IEntityIDs entityids, ITypeSafeDictionary typeSafeDictionary , (uint, uint) rangeofsubmittedentitiesindicies, PlatformProfiler sampler) - where TValue : struct, IBaseEntityComponent + where TValue : struct, _IInternalEntityComponent { for (var i = 0; i < fasterList.count; i++) try @@ -515,7 +525,7 @@ namespace Svelto.ECS.Internal public static void ExecuteEnginesRemoveCallbacksFast (FasterList> fasterList, ExclusiveGroupStruct exclusiveGroupStruct , (uint, uint) valueTuple, IEntityIDs entityids, ITypeSafeDictionary typeSafeDictionary - , PlatformProfiler sampler) where TValue : struct, IBaseEntityComponent + , PlatformProfiler sampler) where TValue : struct, _IInternalEntityComponent { for (var i = 0; i < fasterList.count; i++) try diff --git a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryUtilities.cs b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryUtilities.cs index 716b755..56ef2a5 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryUtilities.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/TypeSafeDictionaryUtilities.cs @@ -3,7 +3,7 @@ namespace Svelto.ECS.Internal static class TypeSafeDictionaryUtilities { internal static EGIDMapper ToEGIDMapper(this ITypeSafeDictionary dic, - ExclusiveGroupStruct groupStructId) where T:struct, IBaseEntityComponent + ExclusiveGroupStruct groupStructId) where T:struct, _IInternalEntityComponent { var mapper = new EGIDMapper(groupStructId, dic); diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/AtomicNativeBags.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/AtomicNativeBags.cs deleted file mode 100644 index f614c3a..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/AtomicNativeBags.cs +++ /dev/null @@ -1,87 +0,0 @@ -#if UNITY_NATIVE //because of the thread count, ATM this is only for unity -using System; -using System.Runtime.CompilerServices; -using Svelto.Common; -using Unity.Jobs.LowLevel.Unsafe; -using Allocator = Svelto.Common.Allocator; - -namespace Svelto.ECS.DataStructures -{ - public unsafe struct AtomicNativeBags:IDisposable - { - public uint count => _threadsCount; - - public AtomicNativeBags(Allocator allocator) - { - _allocator = allocator; - _threadsCount = JobsUtility.MaxJobThreadCount + 1; - - var bufferSize = MemoryUtilities.SizeOf(); - var bufferCount = _threadsCount; - var allocationSize = bufferSize * bufferCount; - - var ptr = (byte*)MemoryUtilities.Alloc((uint) allocationSize, allocator); - // MemoryUtilities.MemClear((IntPtr) ptr, (uint) allocationSize); - - for (int i = 0; i < bufferCount; i++) - { - var bufferPtr = (NativeBag*)(ptr + bufferSize * i); - var buffer = new NativeBag(allocator); - MemoryUtilities.CopyStructureToPtr(ref buffer, (IntPtr) bufferPtr); - } - - _data = (NativeBag*)ptr; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly ref NativeBag GetBuffer(int index) - { -#if DEBUG - if (_data == null) - throw new Exception("using invalid AtomicNativeBags"); -#endif - - return ref MemoryUtilities.ArrayElementAsRef((IntPtr) _data, index); - } - - public void Dispose() - { -#if DEBUG - if (_data == null) - throw new Exception("using invalid AtomicNativeBags"); -#endif - - for (int i = 0; i < _threadsCount; i++) - { - GetBuffer(i).Dispose(); - } - MemoryUtilities.Free((IntPtr) _data, _allocator); - _data = null; - } - - public void Clear() - { -#if DEBUG - if (_data == null) - throw new Exception("using invalid AtomicNativeBags"); -#endif - - for (int i = 0; i < _threadsCount; i++) - { - GetBuffer(i).Clear(); - } - } - - readonly Allocator _allocator; - readonly uint _threadsCount; - -#if UNITY_COLLECTIONS || UNITY_JOBS || UNITY_BURST -#if UNITY_BURST - [Unity.Burst.NoAlias] -#endif - [Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] -#endif - NativeBag* _data; - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeBag.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeBag.cs deleted file mode 100644 index b0cab53..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeBag.cs +++ /dev/null @@ -1,204 +0,0 @@ -#if DEBUG && !PROFILE_SVELTO -#define ENABLE_DEBUG_CHECKS -#endif -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using Svelto.Common; -using Svelto.Common.DataStructures; - -namespace Svelto.ECS.DataStructures -{ - /// - /// Burst friendly RingBuffer on steroid: - /// it can: Enqueue/Dequeue, it wraps around if there is enough space after dequeuing - /// It resizes if there isn't enough space left. - /// It's a "bag", you can queue and dequeue any type and mix them. Just be sure that you dequeue what you queue! No check on type - /// is done. - /// You can reserve a position in the queue to update it later. - /// The datastructure is a struct and it's "copiable" - /// I eventually decided to call it NativeBag and not NativeBag because it can also be used as - /// a preallocated memory pool where any kind of T can be stored as long as T is unmanaged - /// - public struct NativeBag : IDisposable - { - public uint count - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - return _queue->size; - } - } - } - } - - public uint capacity - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - return _queue->capacity; - } - } - } - } - - public NativeBag(Allocator allocator):this() - { - unsafe - { - var listData = (UnsafeBlob*)MemoryUtilities.Alloc((uint)1, allocator); - - listData->allocator = allocator; - _queue = listData; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool IsEmpty() - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - if (_queue == null || _queue->ptr == null) - return true; - } - } - - return count == 0; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void Dispose() - { - if (_queue != null) - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - _queue->Dispose(); - MemoryUtilities.Free((IntPtr)_queue, _queue->allocator); - _queue = null; - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T ReserveEnqueue - (out UnsafeArrayIndex index) - where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - BasicTests(); - - var sizeOf = MemoryUtilities.SizeOf(); - - using (_threadSentinel.TestThreadSafety()) - { - if (_queue->availableSpace - sizeOf < 0) - { - _queue->Grow(); - } - - return ref _queue->Reserve(out index); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Enqueue - (in T item) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - var sizeOf = MemoryUtilities.SizeOf(); - if (_queue->availableSpace - sizeOf < 0) - { - _queue->Grow(); - } - - _queue->Enqueue(item); - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - _queue->Clear(); - } - } - } - - public T Dequeue() where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - return _queue->Dequeue(); - } - } - } - - public ref T AccessReserved(UnsafeArrayIndex reservedIndex) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - BasicTests(); - - using (_threadSentinel.TestThreadSafety()) - { - return ref _queue->AccessReserved(reservedIndex); - } - } - } - - [Conditional("ENABLE_DEBUG_CHECKS")] - unsafe void BasicTests() - { - if (_queue == null) - throw new Exception("SimpleNativeArray: null-access"); - } - - readonly Sentinel _threadSentinel; - -#if UNITY_COLLECTIONS || UNITY_JOBS || UNITY_BURST -#if UNITY_BURST - [Unity.Burst.NoAlias] -#endif - [Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] -#endif - unsafe UnsafeBlob* _queue; - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArray.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArray.cs deleted file mode 100644 index d41adc1..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArray.cs +++ /dev/null @@ -1,516 +0,0 @@ -#if DEBUG && !PROFILE_SVELTO -#define ENABLE_DEBUG_CHECKS -#endif - -using System; -using System.Runtime.CompilerServices; -using Svelto.Common; -using Svelto.Common.DataStructures; -using Allocator = Svelto.Common.Allocator; - -namespace Svelto.ECS.DataStructures -{ - public struct NativeDynamicArray : IDisposable - { - public bool isValid - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - unsafe - { - return _list != null; - } - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Count() where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception($"NativeDynamicArray: not expected type used"); - -#endif - return (_list->count / MemoryUtilities.SizeOf()); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int SizeInBytes() - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - -#endif - return (_list->count); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Capacity() where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - -#endif - return (_list->capacity / MemoryUtilities.SizeOf()); - } - } - - public static NativeDynamicArray Alloc(uint newLength = 0) where T : struct - { - return Alloc(Allocator.Persistent, newLength); - } - - public static NativeDynamicArray Alloc(Allocator allocator, uint newLength = 0) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - var rtnStruc = new NativeDynamicArray - { - _hashType = TypeHash.hash, - }; -#else - NativeDynamicArray rtnStruc = default; -#endif - UnsafeArray* listData = (UnsafeArray*)MemoryUtilities.Alloc(1, allocator); - - //clear to nullify the pointers - //MemoryUtilities.MemClear((IntPtr) listData, structSize); - - rtnStruc._allocator = allocator; - listData->Realloc(newLength, allocator); - - rtnStruc._list = listData; - - return rtnStruc; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get(uint index) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - if (index >= Count()) - throw new Exception($"NativeDynamicArray: out of bound access, index {index} count {Count()}"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - return ref _list->Get(index); -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get(int index) where T : struct - { - return ref Get((uint)index); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(uint index, in T value) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - if (index >= Capacity()) - throw new Exception( - $"NativeDynamicArray: out of bound access, index {index} capacity {Capacity()}"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - _list->Set(index, value); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - public unsafe void Dispose() - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - _list->Dispose(_allocator); - MemoryUtilities.Free((IntPtr)_list, _allocator); - -#if ENABLE_DEBUG_CHECKS - } -#endif - _list = null; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T item) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - if (Count() == Capacity()) - { - _list->Realloc((uint)((Capacity() + 1) * 1.5f), _allocator); - } - - _list->Add(item); -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T AddAt(uint index) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); -#endif - var structSize = (uint)MemoryUtilities.SizeOf(); - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - if (index >= Capacity()) - _list->Realloc((uint)((index + 1) * 1.5f), _allocator); - - var writeIndex = (index + 1) * structSize; - if (_list->count < writeIndex) - _list->SetCountTo(writeIndex); - - return ref _list->Get(index); -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - public void Resize(uint newCapacity) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - _list->Realloc((uint)newCapacity, _allocator); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - public void SetCount(uint count) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); -#endif - uint structSize = (uint)MemoryUtilities.SizeOf(); - uint size = (uint)(count * structSize); - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - _list->SetCountTo((uint)size); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddWithoutGrow(in T item) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - - var structSize = (uint)MemoryUtilities.SizeOf(); - - if (_list->space - (int)structSize < 0) - throw new Exception("NativeDynamicArray: no writing authorized"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - _list->Add(item); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void UnorderedRemoveAt(uint index) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - if (Count() == 0) - throw new Exception("NativeDynamicArray: empty array invalid operation"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - var indexToMove = Count() - 1; - if (index < indexToMove) - { - Set(index, Get((uint)indexToMove)); - } - - _list->Pop(); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FastClear() - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - _list->Clear(); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - public unsafe T* ToPTR() where T : unmanaged - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - -#endif - return (T*)_list->ptr; - } - - public IntPtr ToIntPTR() where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - -#endif - return (IntPtr)_list->ptr; - } - } - - public T[] ToManagedArray() where T : unmanaged - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); - -#endif - var count = Count(); - var ret = new T[count]; - var lengthToCopyInBytes = count * MemoryUtilities.SizeOf(); - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - fixed (void* handle = ret) - { - Unsafe.CopyBlock(handle, _list->ptr, (uint)lengthToCopyInBytes); - } - - return ret; - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - public T[] ToManagedArrayUntrimmed() where T : unmanaged - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); -#endif - var capacity = Capacity(); - var ret = new T[capacity]; - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - fixed (void* handle = ret) - { - MemoryUtilities.MemCpy((IntPtr)_list->ptr, 0, (IntPtr)handle, 0, (uint)capacity); - } - -#if ENABLE_DEBUG_CHECKS - } -#endif - - return ret; - } - } - - public void RemoveAt(uint index) where T : struct - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - if (_list == null) - throw new Exception("NativeDynamicArray: null-access"); - if (_hashType != TypeHash.hash) - throw new Exception("NativeDynamicArray: not expected type used"); -#endif - -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - MemoryUtilities.MemMove((IntPtr)_list->ptr, index + 1, index, (uint)(Count() - (index + 1))); - - _list->Pop(); - -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - - public void MemClear() - { - unsafe - { -#if ENABLE_DEBUG_CHECKS - using (_threadSentinel.TestThreadSafety()) - { -#endif - MemoryUtilities.MemClear((IntPtr)_list->ptr, (uint)_list->capacity); -#if ENABLE_DEBUG_CHECKS - } -#endif - } - } - -#if UNITY_COLLECTIONS || UNITY_JOBS || UNITY_BURST -#if UNITY_BURST - [Unity.Burst.NoAlias] -#endif - [Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] -#endif - unsafe UnsafeArray* _list; -#if DEBUG && !PROFILE_SVELTO - int _hashType; -#endif - - Sentinel _threadSentinel; - - Allocator _allocator; - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayCast.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayCast.cs deleted file mode 100644 index 4957926..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayCast.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Svelto.Common; - -namespace Svelto.ECS.DataStructures -{ - public struct NativeDynamicArrayCast:IDisposable where T : struct - { - public NativeDynamicArrayCast(uint size, Allocator allocator) - { - _array = NativeDynamicArray.Alloc(allocator, size); - } - public NativeDynamicArrayCast(NativeDynamicArray array) : this() { _array = array; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Count() => _array.Count(); - - public int count - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _array.Count(); - } - - public int capacity - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _array.Capacity(); - } - - public ref T this[int index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _array.Get((uint) index); - } - - public ref T this[uint index] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => ref _array.Get(index); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T id) { _array.Add(id); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void UnorderedRemoveAt(uint index) { _array.UnorderedRemoveAt(index); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveAt(uint index) { _array.RemoveAt(index); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() { _array.FastClear(); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() { _array.Dispose(); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T AddAt(uint lastIndex) { return ref _array.AddAt(lastIndex); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Resize(uint newSize) { _array.Resize(newSize); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public NativeDynamicArray ToNativeArray() { return _array; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(uint index, in T value) - { - _array.Set(index, value); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(int index, in T value) - { - _array.Set((uint)index, value); - } - - public bool isValid => _array.isValid; - - NativeDynamicArray _array; - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayUnityExtension.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayUnityExtension.cs deleted file mode 100644 index 3688940..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/NativeDynamicArrayUnityExtension.cs +++ /dev/null @@ -1,23 +0,0 @@ -#if UNITY_COLLECTIONS -using Unity.Collections; -using Unity.Collections.LowLevel.Unsafe; - -namespace Svelto.ECS.DataStructures -{ - public static class NativeDynamicArrayUnityExtension - { - public static NativeArray ToNativeArray(this NativeDynamicArray array) where T : struct - { - unsafe - { - var nativeArray = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray( - (void*) array.ToIntPTR(), (int) array.Count(), Allocator.None); -#if ENABLE_UNITY_COLLECTIONS_CHECKS - NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref nativeArray, AtomicSafetyHandle.Create()); -#endif - return nativeArray; - } - } - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedDisposableNative.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedDisposableNative.cs deleted file mode 100644 index 42a2fa5..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedDisposableNative.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Svelto.Common; - -namespace Svelto.ECS.DataStructures -{ - public struct SharedDisposableNative : IDisposable where T : unmanaged, IDisposable - { -#if UNITY_COLLECTIONS || (UNITY_JOBS || UNITY_BURST) - [global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] -#endif - unsafe IntPtr ptr; - - public SharedDisposableNative(in T value) - { - unsafe - { - ptr = MemoryUtilities.Alloc(1, Allocator.Persistent); - Unsafe.Write((void*)ptr, value); - } - } - - public void Dispose() - { - unsafe - { - Unsafe.AsRef((void*)ptr).Dispose(); - - MemoryUtilities.Free((IntPtr)ptr, Allocator.Persistent); - ptr = IntPtr.Zero; - } - } - - public ref T value - { - get - { - unsafe - { - DBC.ECS.Check.Require(ptr != null, "SharedNative has not been initialized"); - - return ref Unsafe.AsRef((void*)ptr); - } - } - } - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedNativeInt.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedNativeInt.cs deleted file mode 100644 index 04d09fc..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/SharedNativeInt.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using System.Threading; -using Svelto.Common; - -namespace Svelto.ECS.DataStructures -{ - public struct SharedNativeInt: IDisposable - { -#if UNITY_COLLECTIONS || (UNITY_JOBS || UNITY_BURST) - [global::Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] -#endif - unsafe int* data; - - Allocator _allocator; - - public SharedNativeInt(Allocator allocator) - { - unsafe - { - _allocator = allocator; - data = (int*) MemoryUtilities.Alloc(sizeof(int), allocator); - } - } - - public static SharedNativeInt Create(int t, Allocator allocator) - { - unsafe - { - var current = new SharedNativeInt(); - current._allocator = allocator; - current.data = (int*) MemoryUtilities.Alloc(sizeof(int), allocator); - *current.data = t; - - return current; - } - } - - public static implicit operator int(SharedNativeInt t) - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - if (t.data == null) - throw new Exception("using disposed SharedInt"); -#endif - return *t.data; - } - } - - public void Dispose() - { - unsafe - { - if (data != null) - { - MemoryUtilities.Free((IntPtr) data, _allocator); - data = null; - } - } - } - - public int Decrement() - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - if (data == null) - throw new Exception("null-access"); -#endif - - return Interlocked.Decrement(ref *data); - } - } - - public int Increment() - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - if (data == null) - throw new Exception("null-access"); -#endif - - return Interlocked.Increment(ref *data); - } - } - - public int Add(int val) - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - if (data == null) - throw new Exception("null-access"); -#endif - - return Interlocked.Add(ref *data, val); - } - } - - public int CompareExchange(int value, int compare) - { - unsafe - { - #if DEBUG && !PROFILE_SVELTO - if (data == null) - throw new Exception("null-access"); - #endif - - return Interlocked.CompareExchange(ref *data, value, compare); - } - } - - public void Set(int val) - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - if (data == null) - throw new Exception("null-access"); -#endif - - Volatile.Write(ref *data, val); - } - } - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeArray.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeArray.cs deleted file mode 100644 index d0fa110..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeArray.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Svelto.Common; - -namespace Svelto.ECS.DataStructures -{ - struct UnsafeArray - { - internal unsafe byte* ptr => _ptr; - - //expressed in bytes - internal int capacity => (int) _capacity; - - //expressed in bytes - internal int count => (int) _writeIndex; - - //expressed in bytes - internal int space => capacity - count; - -#if DEBUG && !PROFILE_SVELTO -#pragma warning disable 649 - internal uint id; -#pragma warning restore 649 -#endif - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Get(uint index) where T : struct - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - uint sizeOf = (uint) MemoryUtilities.SizeOf(); - if (index + sizeOf > _writeIndex) - throw new Exception("no reading authorized"); -#endif - return ref Unsafe.AsRef(Unsafe.Add(ptr, (int) index)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Set(uint index, in T value) where T : struct - { - unsafe - { - uint sizeOf = (uint) MemoryUtilities.SizeOf(); - uint writeIndex = (uint) (index * sizeOf); - -#if DEBUG && !PROFILE_SVELTO - if (_capacity < writeIndex + sizeOf) - throw new Exception("no writing authorized"); -#endif - Unsafe.AsRef(Unsafe.Add(_ptr, (int) index)) = value; - - if (_writeIndex < writeIndex + sizeOf) - _writeIndex = (uint) (writeIndex + sizeOf); - } - } - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(in T value) where T : struct - { - unsafe - { - var structSize = MemoryUtilities.SizeOf(); - -#if DEBUG && !PROFILE_SVELTO - if (space - structSize < 0) - throw new Exception("no writing authorized"); -#endif - Unsafe.Write(ptr + _writeIndex, value); - - _writeIndex += (uint)structSize; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref T Pop() where T : struct - { - unsafe - { - var structSize = MemoryUtilities.SizeOf(); - - _writeIndex -= (uint)structSize; - - return ref Unsafe.AsRef(ptr + _writeIndex); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Realloc(uint newCapacity, Allocator allocator) where T : struct - { - unsafe - { - var structSize = (uint) MemoryUtilities.SizeOf(); - - uint newCapacityInBytes = structSize * newCapacity; - if (_ptr == null) - _ptr = (byte*) MemoryUtilities.Alloc(newCapacityInBytes, allocator); - else - _ptr = (byte*) MemoryUtilities.Realloc((IntPtr) _ptr, newCapacityInBytes, allocator, (uint) count); - - _capacity = newCapacityInBytes; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose(Allocator allocator) - { - unsafe - { -#if DEBUG && !PROFILE_SVELTO - if (ptr == null) - throw new Exception("UnsafeArray: try to dispose an already disposed array"); -#endif - MemoryUtilities.Free((IntPtr) ptr, allocator); - - _ptr = null; - _writeIndex = 0; - _capacity = 0; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - _writeIndex = 0; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetCountTo(uint count) - { - _writeIndex = count; - } - -#if UNITY_COLLECTIONS || UNITY_JOBS || UNITY_BURST -#if UNITY_BURST - [Unity.Burst.NoAlias] -#endif - [Unity.Collections.LowLevel.Unsafe.NativeDisableUnsafePtrRestriction] -#endif - unsafe byte* _ptr; - - uint _writeIndex; - uint _capacity; - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeBlob.cs b/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeBlob.cs deleted file mode 100644 index 899021f..0000000 --- a/com.sebaslab.svelto.ecs/DataStructures/Unmanaged/UnsafeBlob.cs +++ /dev/null @@ -1,272 +0,0 @@ -using System; -using System.Runtime.CompilerServices; -using Svelto.Common; - -namespace Svelto.ECS.DataStructures -{ - //Necessary to be sure that the user won't pass random values - public struct UnsafeArrayIndex - { - internal uint index; - } - - /// - /// Note: this must work inside burst, so it must follow burst restrictions - /// It's a typeless native queue based on a ring-buffer model. This means that the writing head and the - /// reading head always advance independently. If there is enough space left by dequeued elements, - /// the writing head will wrap around. The writing head cannot ever surpass the reading head. - /// - /// - struct UnsafeBlob : IDisposable - { - internal unsafe byte* ptr { get; set; } - - //expressed in bytes - internal uint capacity { get; private set; } - - //expressed in bytes - internal uint size - { - get - { - var currentSize = (uint) _writeIndex - _readIndex; -#if DEBUG && !PROFILE_SVELTO - if ((currentSize & (4 - 1)) != 0) - throw new Exception("size is expected to be a multiple of 4"); -#endif - - return currentSize; - } - } - - //expressed in bytes - internal uint availableSpace => capacity - size; - - /// - /// - internal Allocator allocator; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Enqueue(in T item) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - var structSize = (uint) MemoryUtilities.SizeOf(); - var writeHead = _writeIndex % capacity; - -#if DEBUG && !PROFILE_SVELTO - var size = _writeIndex - _readIndex; - var spaceAvailable = capacity - size; - if (spaceAvailable - (int) structSize < 0) - throw new Exception("no writing authorized"); - - if ((writeHead & (4 - 1)) != 0) - throw new Exception("write head is expected to be a multiple of 4"); -#endif - if (writeHead + structSize <= capacity) - { - Unsafe.Write(ptr + writeHead, item); - } - else //copy with wrap, will start to copy and wrap for the remainder - { - var byteCountToEnd = capacity - writeHead; - - var localCopyToAvoidGcIssues = item; - //read and copy the first portion of Item until the end of the stream - Unsafe.CopyBlock(ptr + writeHead, Unsafe.AsPointer(ref localCopyToAvoidGcIssues) - , (uint) byteCountToEnd); - - var restCount = structSize - byteCountToEnd; - - //read and copy the remainder - Unsafe.CopyBlock(ptr, (byte*) Unsafe.AsPointer(ref localCopyToAvoidGcIssues) + byteCountToEnd - , (uint) restCount); - } - - //this is may seems a waste if you are going to use an unsafeBlob just for bytes, but it's necessary for mixed types. - //it's still possible to use WriteUnaligned though - uint paddedStructSize = (uint) (structSize + (int) MemoryUtilities.Pad4(structSize)); - - _writeIndex += paddedStructSize; //we want _writeIndex to be always aligned by 4 - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - //The index returned is the index of the unwrapped ring. It must be wrapped again before to be used - internal ref T Reserve(out UnsafeArrayIndex index) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - var structSize = (uint) MemoryUtilities.SizeOf(); - var wrappedIndex = _writeIndex % capacity; -#if DEBUG && !PROFILE_SVELTO - var size = _writeIndex - _readIndex; - var spaceAvailable = capacity - size; - if (spaceAvailable - (int) structSize < 0) - throw new Exception("no writing authorized"); - - if ((wrappedIndex & (4 - 1)) != 0) - throw new Exception("write head is expected to be a multiple of 4"); -#endif - ref var buffer = ref Unsafe.AsRef(ptr + wrappedIndex); - - index.index = _writeIndex; - - _writeIndex += structSize + MemoryUtilities.Pad4(structSize); - - return ref buffer; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref T AccessReserved(UnsafeArrayIndex index) where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - var wrappedIndex = index.index % capacity; -#if DEBUG && !PROFILE_SVELTO - if ((index.index & 3) != 0) - throw new Exception($"invalid index detected"); -#endif - return ref Unsafe.AsRef(ptr + wrappedIndex); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal T Dequeue() where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - var structSize = (uint) MemoryUtilities.SizeOf(); - var readHead = _readIndex % capacity; - -#if DEBUG && !PROFILE_SVELTO - var size = _writeIndex - _readIndex; - if (size < structSize) //are there enough bytes to read? - throw new Exception("dequeuing empty queue or unexpected type dequeued"); - if (_readIndex > _writeIndex) - throw new Exception("unexpected read"); - if ((readHead & (4 - 1)) != 0) - throw new Exception("read head is expected to be a multiple of 4"); -#endif - var paddedStructSize = structSize + MemoryUtilities.Pad4(structSize); - _readIndex += paddedStructSize; - - if (_readIndex == _writeIndex) - { - //resetting the Indices has the benefit to let the Reserve work in more occasions and - //the rapping happening less often. If the _readIndex reached the _writeIndex, it means - //that there is no data left to read, so we can start to write again from the begin of the memory - _writeIndex = 0; - _readIndex = 0; - } - - if (readHead + paddedStructSize <= capacity) - return Unsafe.Read(ptr + readHead); - - //handle the case the structure wraps around so it must be reconstructed from the part at the - //end of the stream and the part starting from the begin. - T item = default; - var byteCountToEnd = capacity - readHead; - Unsafe.CopyBlock(Unsafe.AsPointer(ref item), ptr + readHead, byteCountToEnd); - - var restCount = structSize - byteCountToEnd; - Unsafe.CopyBlock((byte*) Unsafe.AsPointer(ref item) + byteCountToEnd, ptr, restCount); - - return item; - } - } - - /// - /// This code unwraps the queue and resizes the array, but doesn't change the unwrapped index of existing elements. - /// In this way the previously reserved indices will remain valid - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Grow() where T : struct //should be unmanaged, but it's not due to Svelto.ECS constraints. - { - unsafe - { - var sizeOf = MemoryUtilities.SizeOf(); - - var oldCapacity = capacity; - - uint newCapacity = (uint) ((oldCapacity + sizeOf) << 1); - //be sure it's multiple of 4. Assuming that what we write is aligned to 4, then we will always have aligned wrapped heads - //the reading and writing head always increment in multiple of 4 - newCapacity += MemoryUtilities.Pad4(newCapacity); - - byte* newPointer = null; - newPointer = (byte*) MemoryUtilities.Alloc(newCapacity, allocator); - - //copy wrapped content if there is any - var currentSize = _writeIndex - _readIndex; - if (currentSize > 0) - { - var oldReaderHead = _readIndex % oldCapacity; - var oldWriterHead = _writeIndex % oldCapacity; - - //Remembering that the unwrapped reader cannot ever surpass the unwrapped writer, if the reader is behind the writer - //it means that the writer didn't wrap. It's the natural position so the data can be copied with - //a single memcpy - if (oldReaderHead < oldWriterHead) - { - var newReaderHead = _readIndex % newCapacity; - - Unsafe.CopyBlock(newPointer + newReaderHead, ptr + oldReaderHead, (uint) currentSize); - } - else - { - //if the wrapped writer is behind the wrapped reader, it means the writer wrapped. Therefore - //I need to copy the data from the current wrapped reader to the end and then from the - //begin of the array to the current wrapped writer. - - var byteCountToEnd = oldCapacity - oldReaderHead; //bytes to copy from the reader to the end - var newReaderHead = _readIndex % newCapacity; - -#if DEBUG && !PROFILE_SVELTO - if (newReaderHead + byteCountToEnd + oldWriterHead > newCapacity) //basically the test is the old size must be less than the new capacity. - throw new Exception("something is wrong with my previous assumptions"); -#endif - //I am leaving on purpose gap at the begin of the new array if there is any, it will be - //anyway used once it's time to wrap. - Unsafe.CopyBlock(newPointer + newReaderHead, ptr + oldReaderHead, byteCountToEnd); //from the old reader head to the end of the old array - Unsafe.CopyBlock(newPointer + newReaderHead + byteCountToEnd, ptr + 0, (uint) oldWriterHead); //from the begin of the old array to the old writer head (rember the writerHead wrapped) - } - } - - if (ptr != null) - MemoryUtilities.Free((IntPtr) ptr, allocator); - - ptr = newPointer; - capacity = newCapacity; - - //_readIndex = 0; the idea is that the old readIndex should remain unchanged. Remember this is the unwrapped index. - _writeIndex = _readIndex + currentSize; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dispose() - { - unsafe - { - if (ptr != null) - MemoryUtilities.Free((IntPtr) ptr, allocator); - - ptr = null; - _writeIndex = 0; - capacity = 0; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Clear() - { - _writeIndex = 0; - _readIndex = 0; - } - - uint _writeIndex; - uint _readIndex; - } -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs b/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs index 83656b3..ea50b28 100644 --- a/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs +++ b/com.sebaslab.svelto.ecs/DataStructures/UnmanagedTypeSafeDictionary.cs @@ -8,7 +8,6 @@ using System.Threading; using Svelto.Common; using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; namespace Svelto.ECS.Internal { @@ -20,8 +19,8 @@ namespace Svelto.ECS.Internal } #endif - public sealed class UnmanagedTypeSafeDictionary : ITypeSafeDictionary - where TValue : struct, IBaseEntityComponent + sealed class UnmanagedTypeSafeDictionary : ITypeSafeDictionary + where TValue : struct, _IInternalEntityComponent { static readonly ThreadLocal cachedEntityIDN = new ThreadLocal(() => new NativeEntityIDs()); @@ -106,13 +105,13 @@ namespace Svelto.ECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] public ITypeSafeDictionary Create() { - return TypeSafeDictionaryFactory.Create(1); + return new UnmanagedTypeSafeDictionary(1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear() { - implUnmgd.dictionary.FastClear(); + implUnmgd.dictionary.Clear(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/com.sebaslab.svelto.ecs/ECSResources/ECSResourceManager.cs b/com.sebaslab.svelto.ecs/ECSResources/ECSResourceManager.cs new file mode 100644 index 0000000..599e015 --- /dev/null +++ b/com.sebaslab.svelto.ecs/ECSResources/ECSResourceManager.cs @@ -0,0 +1,49 @@ +using System.Runtime.CompilerServices; +using Svelto.DataStructures; +using Svelto.DataStructures.Experimental; +using Svelto.DataStructures.Native; + +namespace Svelto.ECS.ResourceManager +{ + /// + /// Inherit this class to have the base functionalities to implement a custom ECS compatible resource manager + /// + public class ECSResourceManager where T : class + { + protected ECSResourceManager() + { + _sparse = new ValueContainer, NativeStrategy>(16); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueIndex Add(in T resource) + { + return _sparse.Add(resource); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Remove(ValueIndex index) + { + _sparse.Remove(index); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _sparse.Clear(); + } + + public T this[ValueIndex index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _sparse[index]; + } + + ~ECSResourceManager() + { + _sparse.Dispose(); + } + + ValueContainer, NativeStrategy> _sparse; + } +} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/ECSResources/ECSResources.cs b/com.sebaslab.svelto.ecs/ECSResources/ECSResources.cs index 6824dd5..046265b 100644 --- a/com.sebaslab.svelto.ecs/ECSResources/ECSResources.cs +++ b/com.sebaslab.svelto.ecs/ECSResources/ECSResources.cs @@ -1,14 +1,7 @@ using Svelto.DataStructures; -namespace Svelto.ECS.Experimental +namespace Svelto.ECS.ResourceManager { - // struct ECSResources - // { - // internal uint id; - // - // public static implicit operator T(ECSResources ecsString) { return ResourcesECSDB.FromECS(ecsString.id); } - // } - /// /// To do. Or we reuse the ID or we need to clear this /// diff --git a/com.sebaslab.svelto.ecs/ECSResources/ECSString.cs b/com.sebaslab.svelto.ecs/ECSResources/ECSString.cs index 339ca8b..9720d5b 100644 --- a/com.sebaslab.svelto.ecs/ECSResources/ECSString.cs +++ b/com.sebaslab.svelto.ecs/ECSResources/ECSString.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace Svelto.ECS.Experimental +namespace Svelto.ECS.ResourceManager { /// /// Todo: the entityDB should be aware of the ECSString and recycle it on entity removal diff --git a/com.sebaslab.svelto.ecs/Extensions/DisposeDisposablesEngine.cs b/com.sebaslab.svelto.ecs/Extensions/DisposeDisposablesEngine.cs deleted file mode 100644 index ff9daaa..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/DisposeDisposablesEngine.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -namespace Svelto.ECS -{ - [AllowMultiple] - public class DisposeDisposablesEngine : IEngine, IDisposable - { - public DisposeDisposablesEngine(IDisposable[] disposable) - { - _disposable = disposable; - } - - public void Dispose() - { - foreach (var d in _disposable) - { - d.Dispose(); - } - } - - IDisposable[] _disposable; - } - -} \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs b/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs index 62895df..79b1a7c 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/EnginesRoot.NativeOperation.cs @@ -3,7 +3,6 @@ using System; using DBC.ECS; using Svelto.Common; using Svelto.DataStructures; -using Svelto.ECS.DataStructures; using Svelto.ECS.Internal; using Svelto.ECS.Native; @@ -17,8 +16,10 @@ namespace Svelto.ECS //todo: remove operation array and store entity descriptor hash in the return value //todo I maybe able to provide a _nativeSwap.SwapEntity //todo make this work with base descriptors too + var descriptorComponentsToRemove = EntityDescriptorTemplate.descriptor.componentsToBuild; + _nativeRemoveOperations.Add(new NativeOperationRemove( - EntityDescriptorTemplate.descriptor.componentsToBuild, TypeCache.type + descriptorComponentsToRemove, TypeCache.type , memberName)); return new NativeEntityRemove(_nativeRemoveOperationQueue, _nativeRemoveOperations.count - 1); @@ -54,7 +55,7 @@ namespace Svelto.ECS //todo, I don't like that this scans all the queues even if they are empty for (int i = 0; i < removeBuffersCount; i++) { - ref var buffer = ref _nativeRemoveOperationQueue.GetBuffer(i); + ref var buffer = ref _nativeRemoveOperationQueue.GetBag(i); while (buffer.IsEmpty() == false) { @@ -78,7 +79,7 @@ namespace Svelto.ECS var swapBuffersCount = _nativeSwapOperationQueue.count; for (int i = 0; i < swapBuffersCount; i++) { - ref var buffer = ref _nativeSwapOperationQueue.GetBuffer(i); + ref var buffer = ref _nativeSwapOperationQueue.GetBag(i); while (buffer.IsEmpty() == false) { @@ -105,7 +106,7 @@ namespace Svelto.ECS var addBuffersCount = _nativeAddOperationQueue.count; for (int i = 0; i < addBuffersCount; i++) { - ref var buffer = ref _nativeAddOperationQueue.GetBuffer(i); + ref var buffer = ref _nativeAddOperationQueue.GetBag(i); //todo: I don't like to iterate a constant number of buffer and skip the empty ones while (buffer.IsEmpty() == false) { @@ -162,7 +163,6 @@ namespace Svelto.ECS FasterList _nativeSwapOperations; FasterList _nativeAddOperations; - //todo: I very likely don't need to create one for each native entity factory, the same can be reused readonly AtomicNativeBags _nativeAddOperationQueue; readonly AtomicNativeBags _nativeRemoveOperationQueue; readonly AtomicNativeBags _nativeSwapOperationQueue; diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/EntityNativeDBExtensions.cs b/com.sebaslab.svelto.ecs/Extensions/Native/EntityNativeDBExtensions.cs index 8b01184..208cf00 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/EntityNativeDBExtensions.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/EntityNativeDBExtensions.cs @@ -104,6 +104,9 @@ namespace Svelto.ECS return ref entitiesDb.QueryEntity(new EGID(id, group)); } + /// + /// Expects that only one entity of type T exists in the group + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T QueryUniqueEntity (this EntitiesDB entitiesDb, ExclusiveGroupStruct group) where T : unmanaged, IEntityComponent @@ -147,5 +150,12 @@ namespace Svelto.ECS array = default; return false; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AllGroupsEnumerable QueryEntities(this EntitiesDB db) + where T1 :unmanaged, IEntityComponent + { + return new AllGroupsEnumerable(db); + } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMapper.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMapper.cs index f90e3cf..3e25075 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMapper.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMapper.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; using Svelto.Common; using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS.Native { @@ -13,7 +13,7 @@ namespace Svelto.ECS.Native /// that a job can use it as long as nothing else is modifying the entities database and the NativeEGIDMapper /// is disposed right after the use. /// - public readonly struct NativeEGIDMapper : IEGIDMapper where T : unmanaged, IBaseEntityComponent + public readonly struct NativeEGIDMapper : IEGIDMapper where T : unmanaged, _IInternalEntityComponent { public static readonly NativeEGIDMapper empty = new NativeEGIDMapper (default, new SharedSveltoDictionaryNative(0, Allocator.Persistent)); diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMultiMapper.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMultiMapper.cs index f525db0..2b5fe39 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMultiMapper.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEGIDMultiMapper.cs @@ -1,7 +1,6 @@ using System; -using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS.Native { @@ -14,7 +13,7 @@ namespace Svelto.ECS.Native ///WARNING: REMEMBER THIS MUST BE DISPOSED OF, AS IT USES NATIVE MEMORY. IT WILL LEAK MEMORY OTHERWISE /// /// - public struct NativeEGIDMultiMapper : IDisposable where T : unmanaged, IBaseEntityComponent + public struct NativeEGIDMultiMapper : IDisposable where T : unmanaged, _IInternalEntityComponent { public NativeEGIDMultiMapper(in SveltoDictionaryNative> dictionary) { diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs index 1a01731..f8ce312 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityFactory.cs @@ -1,27 +1,42 @@ #if UNITY_NATIVE -using Svelto.ECS.DataStructures; +using System.Runtime.CompilerServices; +using Svelto.DataStructures; namespace Svelto.ECS.Native { public readonly struct NativeEntityFactory { - internal NativeEntityFactory(AtomicNativeBags addOperationQueue, int index, EnginesRoot.EntityReferenceMap entityLocator) + internal NativeEntityFactory(AtomicNativeBags addOperationQueue, int operationIndex, EnginesRoot.EntityReferenceMap entityLocator) { - _index = index; + _operationIndex = operationIndex; _addOperationQueue = addOperationQueue; - _entityLocator = entityLocator; + _entityLocator = entityLocator; } - public NativeEntityInitializer BuildEntity - (uint eindex, ExclusiveBuildGroup exclusiveBuildGroup, int threadIndex) + /// + /// TODO is this still true?: + /// + /// var entity1Init = nativeFactory.BuildEntity(new EGID(1, Group.TestGroupA), threadIndex); + /// var entity2Init = nativeFactory.BuildEntity(new EGID(2, Group.TestGroupA), threadIndex); + /// and expect that entity1Init is still valid and I have to invalidate it + /// I think I fixed it, but needs more test + /// However we should remove atomicBags and use svelto dictionar + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeEntityInitializer BuildEntity(uint eindex, ExclusiveBuildGroup exclusiveBuildGroup, int threadIndex) { EntityReference reference = _entityLocator.ClaimReference(); - NativeBag bagPerEntityPerThread = _addOperationQueue.GetBuffer(threadIndex + 1); + NativeBag bagPerEntityPerThread = _addOperationQueue.GetBag(threadIndex + 1); - bagPerEntityPerThread.Enqueue(_index); //each native ECS 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); - + //NativeEntityInitializer is quite a complex beast. It holds the starting values of the component set by the user. These components must be later dequeued and in order to know how many components //must be dequeued, a count must be used. The space to hold the count is then reserved in the queue and index will be used access the count later on through NativeEntityInitializer so it can increment it. //index is not the number of components of the entity, it's just the number of components that the user decide to initialise @@ -30,14 +45,15 @@ namespace Svelto.ECS.Native return new NativeEntityInitializer(bagPerEntityPerThread, index, reference); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public NativeEntityInitializer BuildEntity(EGID egid, int threadIndex) { return BuildEntity(egid.entityID, egid.groupID, threadIndex); } - readonly EnginesRoot.EntityReferenceMap _entityLocator; - readonly AtomicNativeBags _addOperationQueue; - readonly int _index; + readonly EnginesRoot.EntityReferenceMap _entityLocator; + readonly AtomicNativeBags _addOperationQueue; + readonly int _operationIndex; } } #endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs index d4b1000..4e72dcd 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityInitializer.cs @@ -1,31 +1,35 @@ #if UNITY_NATIVE //at the moment I am still considering NativeOperations useful only for Unity -using Svelto.ECS.DataStructures; +using System.Runtime.CompilerServices; +using Svelto.DataStructures; namespace Svelto.ECS.Native { public readonly ref struct NativeEntityInitializer { - readonly NativeBag _unsafeBuffer; - readonly UnsafeArrayIndex _index; - readonly EntityReference _reference; + readonly NativeBag _unsafeBuffer; + readonly UnsafeArrayIndex _componentsToInitializeCounterRef; + readonly EntityReference _reference; - public NativeEntityInitializer(in NativeBag unsafeBuffer, UnsafeArrayIndex index, EntityReference reference) + public NativeEntityInitializer(in NativeBag unsafeBuffer, UnsafeArrayIndex componentsToInitializeCounterRef, EntityReference reference) { _unsafeBuffer = unsafeBuffer; - _index = index; - _reference = reference; + _componentsToInitializeCounterRef = componentsToInitializeCounterRef; + _reference = reference; } - public void Init(in T component) where T : unmanaged, IEntityComponent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref T Init(in T component) where T : unmanaged, IEntityComponent { - uint id = EntityComponentID.ID.Data; + uint componentID = EntityComponentID.ID.Data; - _unsafeBuffer.AccessReserved(_index)++; //number of components added so far + _unsafeBuffer.AccessReserved(_componentsToInitializeCounterRef)++; //increase the number of components that have been initialised by the user //Since NativeEntityInitializer is a ref struct, it guarantees that I am enqueueing components of the //last entity built - _unsafeBuffer.Enqueue(id); - _unsafeBuffer.Enqueue(component); + _unsafeBuffer.Enqueue(componentID); //to know what component it's being stored + _unsafeBuffer.ReserveEnqueue(out var index) = component; + + return ref _unsafeBuffer.AccessReserved(index); } public EntityReference reference => _reference; diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityRemove.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityRemove.cs index e214255..c0e7f5d 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityRemove.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntityRemove.cs @@ -1,5 +1,5 @@ #if UNITY_NATIVE -using Svelto.ECS.DataStructures; +using Svelto.DataStructures; namespace Svelto.ECS.Native { @@ -16,7 +16,7 @@ namespace Svelto.ECS.Native public void RemoveEntity(EGID egid, int threadIndex) { - var simpleNativeBag = _removeQueue.GetBuffer(threadIndex); + var simpleNativeBag = _removeQueue.GetBag(threadIndex); simpleNativeBag.Enqueue(_indexRemove); simpleNativeBag.Enqueue(egid); diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntitySwap.cs b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntitySwap.cs index 0b39d6f..8e87a5d 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntitySwap.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/NativeEntitySwap.cs @@ -1,5 +1,5 @@ #if UNITY_NATIVE -using Svelto.ECS.DataStructures; +using Svelto.DataStructures; namespace Svelto.ECS.Native { @@ -16,7 +16,7 @@ namespace Svelto.ECS.Native public void SwapEntity(EGID from, EGID to, int threadIndex) { - var simpleNativeBag = _swapQueue.GetBuffer(threadIndex); + var simpleNativeBag = _swapQueue.GetBag(threadIndex); simpleNativeBag.Enqueue(_indexSwap); simpleNativeBag.Enqueue(new DoubleEGID(from, to)); @@ -24,7 +24,7 @@ namespace Svelto.ECS.Native public void SwapEntity(EGID from, ExclusiveBuildGroup to, int threadIndex) { - var simpleNativeBag = _swapQueue.GetBuffer(threadIndex); + var simpleNativeBag = _swapQueue.GetBag(threadIndex); simpleNativeBag.Enqueue(_indexSwap); simpleNativeBag.Enqueue(new DoubleEGID(from, new EGID(from.entityID, to))); } diff --git a/com.sebaslab.svelto.ecs/Extensions/Native/UnityNativeEntityDBExtensions.cs b/com.sebaslab.svelto.ecs/Extensions/Native/UnityNativeEntityDBExtensions.cs index 1da6269..ddf355e 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Native/UnityNativeEntityDBExtensions.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Native/UnityNativeEntityDBExtensions.cs @@ -2,7 +2,6 @@ using System.Runtime.CompilerServices; using Svelto.Common; using Svelto.DataStructures; using Svelto.DataStructures.Native; -using Svelto.ECS.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS.Native @@ -49,7 +48,7 @@ namespace Svelto.ECS.Native /// must be unit tested! public static NativeEGIDMultiMapper QueryNativeMappedEntities(this EntitiesDB entitiesDb, LocalFasterReadOnlyList groups, Allocator allocator) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { var dictionary = new SveltoDictionaryNative> ((uint) groups.count, allocator); diff --git a/com.sebaslab.svelto.ecs/Extensions/ProcessorCount.cs b/com.sebaslab.svelto.ecs/Extensions/ProcessorCount.cs index 5fdbb53..7e3584a 100644 --- a/com.sebaslab.svelto.ecs/Extensions/ProcessorCount.cs +++ b/com.sebaslab.svelto.ecs/Extensions/ProcessorCount.cs @@ -10,8 +10,8 @@ namespace Svelto.ECS { var iterationsPerBatch = totalIterations / processorCount; - if (iterationsPerBatch < 32) - return 32; + if (iterationsPerBatch < 64) + return 64; return (int) iterationsPerBatch; } diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs index 14f31b7..ebf231e 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/AllGroupsEnumerable.cs @@ -9,12 +9,18 @@ namespace Svelto.ECS /// that can be burstifiable /// /// - public readonly struct AllGroupsEnumerable where T1 : struct, IBaseEntityComponent + public readonly ref struct AllGroupsEnumerable where T1 : struct, _IInternalEntityComponent { - public ref struct GroupCollection + public readonly ref struct GroupCollection { - internal EntityCollection collection; - internal ExclusiveGroupStruct group; + readonly EntityCollection collection; + readonly ExclusiveGroupStruct group; + + public GroupCollection(EntityCollection entityCollection, ExclusiveGroupStruct groupKey) + { + collection = entityCollection; + group = groupKey; + } public void Deconstruct(out EntityCollection collection, out ExclusiveGroupStruct group) { @@ -45,9 +51,11 @@ namespace Svelto.ECS if (typeSafeDictionary.count == 0) continue; - _array.collection = new EntityCollection(typeSafeDictionary.GetValues(out var count), - typeSafeDictionary.entityIDs, count); - _array.@group = group.key; + + _array = new GroupCollection( + new EntityCollection( + typeSafeDictionary.GetValues(out var count), + typeSafeDictionary.entityIDs, count), group.key); return true; } diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/EGIDMultiMapper.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/EGIDMultiMapper.cs index 55468ed..4eac41c 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/EGIDMultiMapper.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/EGIDMultiMapper.cs @@ -4,12 +4,13 @@ using Svelto.Common; using Svelto.DataStructures; using Svelto.DataStructures.Native; using Svelto.ECS.Hybrid; +using Svelto.ECS.Internal; namespace Svelto.ECS { namespace Native { - public struct EGIDMultiMapper where T : unmanaged, IBaseEntityComponent + public struct EGIDMultiMapper where T : unmanaged, _IInternalEntityComponent { public EGIDMultiMapper (SveltoDictionary(in this EntityCollection ec, out NB buffer, out int count) - where T1 : unmanaged, IEntityComponent + where T1 : unmanaged, IEntityComponent { if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer = default; - count = 0; + count = 0; return; } - + buffer = (NB)ec._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer, - out NativeEntityIDs entityIDs, out int count) where T1 : unmanaged, IEntityComponent + out NativeEntityIDs entityIDs, out int count) + where T1 : unmanaged, IEntityComponent { if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer = default; - count = 0; + buffer = default; + count = 0; entityIDs = default; return; } - - buffer = (NB)ec._buffer; - count = (int)ec.count; + + buffer = (NB)ec._buffer; + count = (int)ec.count; entityIDs = (NativeEntityIDs)ec._entityIDs; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, - out NB buffer2, out NativeEntityIDs entityIDs, out int count) where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent + out NB buffer2, out NativeEntityIDs entityIDs, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer1 = default; - buffer2 = default; - count = 0; + buffer1 = default; + buffer2 = default; + count = 0; entityIDs = default; return; } - - buffer1 = (NB)ec.buffer1._buffer; - buffer2 = (NB)ec.buffer2._buffer; - count = ec.count; + + buffer1 = (NB)ec.buffer1._buffer; + buffer2 = (NB)ec.buffer2._buffer; + count = ec.count; entityIDs = (NativeEntityIDs)ec.buffer1._entityIDs; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, - out NB buffer2, out int count) where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent + out NB buffer2, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer1 = default; - buffer2 = default; - count = 0; + buffer1 = default; + buffer2 = default; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (NB)ec.buffer2._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, - out NB buffer2, out NB buffer3, out int count) where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : unmanaged, IEntityComponent + out NB buffer2, out NB buffer3, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : unmanaged, IEntityComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; - count = 0; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (NB)ec.buffer2._buffer; buffer3 = (NB)ec.buffer3._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, out NB buffer2, out NB buffer3, out NativeEntityIDs entityIDs, out int count) - where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : unmanaged, IEntityComponent + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : unmanaged, IEntityComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer1 = default; - buffer2 = default; - buffer3 = default; - count = 0; + buffer1 = default; + buffer2 = default; + buffer3 = default; + count = 0; entityIDs = default; return; } - - buffer1 = (NB)ec.buffer1._buffer; - buffer2 = (NB)ec.buffer2._buffer; - buffer3 = (NB)ec.buffer3._buffer; - count = (int)ec.count; + + buffer1 = (NB)ec.buffer1._buffer; + buffer2 = (NB)ec.buffer2._buffer; + buffer3 = (NB)ec.buffer3._buffer; + count = (int)ec.count; entityIDs = (NativeEntityIDs)ec.buffer1._entityIDs; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, out NB buffer2, out NB buffer3, out NB buffer4, out int count) - where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : unmanaged, IEntityComponent - where T4 : unmanaged, IEntityComponent + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : unmanaged, IEntityComponent + where T4 : unmanaged, IEntityComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; buffer4 = default; - count = 0; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (NB)ec.buffer2._buffer; buffer3 = (NB)ec.buffer3._buffer; buffer4 = (NB)ec.buffer4._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, out NB buffer2, out NB buffer3, out NB buffer4, out NativeEntityIDs entityIDs, out int count) - where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : unmanaged, IEntityComponent - where T4 : unmanaged, IEntityComponent + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : unmanaged, IEntityComponent + where T4 : unmanaged, IEntityComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer1 = default; - buffer2 = default; - buffer3 = default; - buffer4 = default; - count = 0; + buffer1 = default; + buffer2 = default; + buffer3 = default; + buffer4 = default; + count = 0; entityIDs = default; return; } - - buffer1 = (NB)ec.buffer1._buffer; - buffer2 = (NB)ec.buffer2._buffer; - buffer3 = (NB)ec.buffer3._buffer; - buffer4 = (NB)ec.buffer4._buffer; + + buffer1 = (NB)ec.buffer1._buffer; + buffer2 = (NB)ec.buffer2._buffer; + buffer3 = (NB)ec.buffer3._buffer; + buffer4 = (NB)ec.buffer4._buffer; entityIDs = (NativeEntityIDs)ec.buffer1._entityIDs; - count = (int)ec.count; + count = (int)ec.count; } } @@ -179,115 +189,124 @@ namespace Svelto.ECS { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out MB buffer, out int count) - where T1 : struct, IEntityViewComponent + where T1 : struct, IEntityViewComponent { if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer = default; - count = 0; + count = 0; return; } - + buffer = (MB)ec._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out MB buffer, - out ManagedEntityIDs entityIDs, out int count) where T1 : struct, IEntityViewComponent + out ManagedEntityIDs entityIDs, out int count) + where T1 : struct, IEntityViewComponent { if (ec._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer = default; - count = 0; + buffer = default; + count = 0; entityIDs = default; return; } - buffer = (MB)ec._buffer; - count = (int)ec.count; + + buffer = (MB)ec._buffer; + count = (int)ec.count; entityIDs = (ManagedEntityIDs)ec._entityIDs; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out MB buffer1, - out MB buffer2, out int count) where T1 : struct, IEntityViewComponent - where T2 : struct, IEntityViewComponent + out MB buffer2, out int count) + where T1 : struct, IEntityViewComponent + where T2 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; - count = 0; + count = 0; return; } - + buffer1 = (MB)ec.buffer1._buffer; buffer2 = (MB)ec.buffer2._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out MB buffer1, - out MB buffer2, out ManagedEntityIDs entityIDs, out int count) where T1 : struct, IEntityViewComponent - where T2 : struct, IEntityViewComponent + out MB buffer2, out ManagedEntityIDs entityIDs, out int count) + where T1 : struct, IEntityViewComponent + where T2 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer1 = default; - buffer2 = default; - count = 0; + buffer1 = default; + buffer2 = default; + count = 0; entityIDs = default; return; } - - buffer1 = (MB)ec.buffer1._buffer; - buffer2 = (MB)ec.buffer2._buffer; - count = (int)ec.count; + + buffer1 = (MB)ec.buffer1._buffer; + buffer2 = (MB)ec.buffer2._buffer; + count = (int)ec.count; entityIDs = (ManagedEntityIDs)ec.buffer1._entityIDs; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out MB buffer1, - out MB buffer2, out MB buffer3, out int count) where T1 : struct, IEntityViewComponent - where T2 : struct, IEntityViewComponent - where T3 : struct, IEntityViewComponent + out MB buffer2, out MB buffer3, out int count) + where T1 : struct, IEntityViewComponent + where T2 : struct, IEntityViewComponent + where T3 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; - count = 0; + count = 0; return; } - + buffer1 = (MB)ec.buffer1._buffer; buffer2 = (MB)ec.buffer2._buffer; buffer3 = (MB)ec.buffer3._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out MB buffer1, out MB buffer2, out MB buffer3, out ManagedEntityIDs entityIDs, out int count) - where T1 : struct, IEntityViewComponent - where T2 : struct, IEntityViewComponent - where T3 : struct, IEntityViewComponent + where T1 : struct, IEntityViewComponent + where T2 : struct, IEntityViewComponent + where T3 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { - buffer1 = default; - buffer2 = default; - buffer3 = default; + buffer1 = default; + buffer2 = default; + buffer3 = default; entityIDs = default; - count = 0; + count = 0; return; } - - buffer1 = (MB)ec.buffer1._buffer; - buffer2 = (MB)ec.buffer2._buffer; - buffer3 = (MB)ec.buffer3._buffer; - count = (int)ec.count; + + buffer1 = (MB)ec.buffer1._buffer; + buffer2 = (MB)ec.buffer2._buffer; + buffer3 = (MB)ec.buffer3._buffer; + count = (int)ec.count; entityIDs = (ManagedEntityIDs)ec.buffer1._entityIDs; } } @@ -296,66 +315,92 @@ namespace Svelto.ECS { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, - out MB buffer2, out int count) where T1 : unmanaged, IEntityComponent - where T2 : struct, IEntityViewComponent + out MB buffer2, out ManagedEntityIDs entityIDs, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : struct, IEntityViewComponent + { + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + { + buffer1 = default; + buffer2 = default; + count = 0; + return; + } + + buffer1 = (NB)ec.buffer1._buffer; + buffer2 = (MB)ec.buffer2._buffer; + count = (int)ec.count; + entityIDs = (ManagedEntityIDs)ec.buffer2._entityIDs; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Deconstruct(in this EntityCollection ec, out NB buffer1, + out MB buffer2, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; - count = 0; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (MB)ec.buffer2._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, - out MB buffer2, out MB buffer3, out int count) where T1 : unmanaged, IEntityComponent - where T2 : struct, IEntityViewComponent - where T3 : struct, IEntityViewComponent + out MB buffer2, out MB buffer3, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : struct, IEntityViewComponent + where T3 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; - count = 0; + count = 0; return; - } + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (MB)ec.buffer2._buffer; buffer3 = (MB)ec.buffer3._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, out NB buffer2, out NB buffer3, out MB buffer4, out int count) - where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : unmanaged, IEntityComponent - where T4 : struct, IEntityViewComponent + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : unmanaged, IEntityComponent + where T4 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; buffer4 = default; - count = 0; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (NB)ec.buffer2._buffer; buffer3 = (NB)ec.buffer3._buffer; buffer4 = (MB)ec.buffer4._buffer; - count = (int)ec.count; + count = (int)ec.count; } } @@ -363,48 +408,51 @@ namespace Svelto.ECS { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, - out NB buffer2, out MB buffer3, out int count) where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : struct, IEntityViewComponent + out NB buffer2, out MB buffer3, out int count) + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; - count = 0; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (NB)ec.buffer2._buffer; buffer3 = (MB)ec.buffer3._buffer; - count = (int)ec.count; + count = (int)ec.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Deconstruct(in this EntityCollection ec, out NB buffer1, out NB buffer2, out MB buffer3, out MB buffer4, out int count) - where T1 : unmanaged, IEntityComponent - where T2 : unmanaged, IEntityComponent - where T3 : struct, IEntityViewComponent - where T4 : struct, IEntityViewComponent + where T1 : unmanaged, IEntityComponent + where T2 : unmanaged, IEntityComponent + where T3 : struct, IEntityViewComponent + where T4 : struct, IEntityViewComponent { - if (ec.buffer1._buffer == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 + if (ec.buffer1._buffer + == null) //I cannot test 0, as buffer can be valid and processed by removeEx with count 0 { buffer1 = default; buffer2 = default; buffer3 = default; buffer4 = default; - count = 0; + count = 0; return; } - + buffer1 = (NB)ec.buffer1._buffer; buffer2 = (NB)ec.buffer2._buffer; buffer3 = (MB)ec.buffer3._buffer; buffer4 = (MB)ec.buffer4._buffer; - count = (int)ec.count; + count = (int)ec.count; } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/EntityManagedDBExtensions.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/EntityManagedDBExtensions.cs index 28eb6c4..3262c98 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/EntityManagedDBExtensions.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/EntityManagedDBExtensions.cs @@ -73,6 +73,9 @@ namespace Svelto.ECS return ref entitiesDb.QueryEntity(new EGID(id, group)); } + /// + /// Expects that only one entity of type T exists in the group + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T QueryUniqueEntity (this EntitiesDB entitiesDb, ExclusiveGroupStruct group) where T : struct, IEntityViewComponent @@ -119,7 +122,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AllGroupsEnumerable QueryEntities(this EntitiesDB db) - where T1 :struct, IBaseEntityComponent + where T1 :struct, IEntityViewComponent { return new AllGroupsEnumerable(db); } diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/ExclusiveGroupExtensions.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/ExclusiveGroupExtensions.cs index eb9b61e..2e22c26 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/ExclusiveGroupExtensions.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/ExclusiveGroupExtensions.cs @@ -3,6 +3,7 @@ using Svelto.DataStructures; namespace Svelto.ECS { + //TODO there is an overlap between these methods and Group Compound Includes public static class ExclusiveGroupExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/GroupsEnumerable.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/GroupsEnumerable.cs index 38661a3..b102c86 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/GroupsEnumerable.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/GroupsEnumerable.cs @@ -1,20 +1,20 @@ using Svelto.DataStructures; +using Svelto.ECS.Internal; namespace Svelto.ECS { /// /// NOTE THESE ENUMERABLES EXIST TO AVOID BOILERPLATE CODE AS THEY SKIP 0 SIZED GROUPS /// However if the normal pattern with the double foreach is used, this is not necessary - /// Note: atm cannot be ref structs because they are returned in a valuetuple /// /// /// /// /// - public readonly ref struct GroupsEnumerable where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent - where T4 : struct, IBaseEntityComponent + public readonly ref struct GroupsEnumerable where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent + where T4 : struct, _IInternalEntityComponent { public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList groups) { @@ -92,9 +92,9 @@ namespace Svelto.ECS } } - public readonly ref struct GroupsEnumerable where T1 : struct, IBaseEntityComponent - where T2 : struct, IBaseEntityComponent - where T3 : struct, IBaseEntityComponent + public readonly ref struct GroupsEnumerable where T1 : struct, _IInternalEntityComponent + where T2 : struct, _IInternalEntityComponent + where T3 : struct, _IInternalEntityComponent { public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList groups) { @@ -175,7 +175,7 @@ namespace Svelto.ECS } public readonly ref struct GroupsEnumerable - where T1 : struct, IBaseEntityComponent where T2 : struct, IBaseEntityComponent + where T1 : struct, _IInternalEntityComponent where T2 : struct, _IInternalEntityComponent { public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList groups) { @@ -253,7 +253,7 @@ namespace Svelto.ECS } } - public readonly ref struct GroupsEnumerable where T1 : struct, IBaseEntityComponent + public readonly ref struct GroupsEnumerable where T1 : struct, _IInternalEntityComponent { public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList groups) { diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/EntitiesDBFiltersExtension.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/EntitiesDBFiltersExtension.cs similarity index 88% rename from com.sebaslab.svelto.ecs/Extensions/Svelto/EntitiesDBFiltersExtension.cs rename to com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/EntitiesDBFiltersExtension.cs index 5699381..7f9ddaf 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/EntitiesDBFiltersExtension.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/EntitiesDBFiltersExtension.cs @@ -1,4 +1,5 @@ -using Svelto.DataStructures; +#if SVELTO_LEGACY_FILTERS +using Svelto.DataStructures; using Svelto.ECS.Native; namespace Svelto.ECS @@ -13,4 +14,5 @@ namespace Svelto.ECS return filter.Add(egid.entityID, mapper); } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Svelto/FilterGroupExtensions.cs b/com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/FilterGroupExtensions.cs similarity index 91% rename from com.sebaslab.svelto.ecs/Extensions/Svelto/FilterGroupExtensions.cs rename to com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/FilterGroupExtensions.cs index 108f203..a2db2e2 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Svelto/FilterGroupExtensions.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Svelto/Legacy/FilterGroupExtensions.cs @@ -1,4 +1,5 @@ -using Svelto.ECS.Native; +#if SVELTO_LEGACY_FILTERS +using Svelto.ECS.Native; namespace Svelto.ECS { @@ -16,4 +17,5 @@ namespace Svelto.ECS } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/Jobs/UnityJobExtensions.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/Jobs/UnityJobExtensions.cs index 9a365fa..272e9d5 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/Jobs/UnityJobExtensions.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/Jobs/UnityJobExtensions.cs @@ -3,6 +3,7 @@ using System; using Svelto.ECS.SveltoOnDOTS; using Unity.Jobs; +//note can't change namespace, too late for old projects namespace Svelto.ECS { public static class UnityJobExtensions @@ -44,7 +45,7 @@ namespace Svelto.ECS (this JOB job, int iterations, JobHandle inputDeps, JobHandle combinedDeps) where JOB: struct, IJobParallelFor { if (iterations == 0) - return inputDeps; + return combinedDeps; var innerloopBatchCount = ProcessorCount.BatchSize((uint)iterations); var jobDeps = job.Schedule(iterations, innerloopBatchCount, inputDeps); @@ -62,6 +63,9 @@ namespace Svelto.ECS public static JobHandle ScheduleAndCombine (this JOB job, int arrayLength, JobHandle inputDeps, JobHandle combinedDeps) where JOB : struct, IJobFor { + if (arrayLength == 0) + return combinedDeps; + var jobDeps = job.Schedule(arrayLength, inputDeps); return JobHandle.CombineDependencies(combinedDeps, jobDeps); } diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSOperationsForSvelto.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSOperationsForSvelto.cs new file mode 100644 index 0000000..238187e --- /dev/null +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSOperationsForSvelto.cs @@ -0,0 +1,257 @@ +#if UNITY_ECS +using System.Runtime.CompilerServices; +using Svelto.DataStructures; +using Svelto.DataStructures.Native; +using Svelto.ECS.Internal; +using Unity.Burst; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Entities; +using Unity.Jobs; + +namespace Svelto.ECS.SveltoOnDOTS +{ + public readonly struct DOTSOperationsForSvelto + { + internal unsafe DOTSOperationsForSvelto(EntityManager manager, JobHandle* jobHandle) + { + _EManager = manager; + _jobHandle = jobHandle; + } + + public EntityArchetype CreateArchetype(params ComponentType[] types) + { + return _EManager.CreateArchetype(types); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetComponent(Entity e, in T component) + where T : unmanaged, IComponentData + { + _EManager.SetComponentData(e, component); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetSharedComponent(Entity e, in T component) + where T : unmanaged, ISharedComponentData + { + _EManager.SetSharedComponent(e, component); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Entity CreateDOTSEntityFromSvelto(Entity prefabEntity, ExclusiveGroupStruct groupID, EntityReference reference) + { + Entity dotsEntity = _EManager.Instantiate(prefabEntity); + + //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones + _EManager.AddSharedComponent(dotsEntity, new DOTSSveltoGroupID(groupID)); + _EManager.AddComponent(dotsEntity); + _EManager.SetComponentData(dotsEntity, new DOTSSveltoReference(reference)); + + return dotsEntity; + } + + /// + /// This method assumes that the Svelto entity with EGID egid has also dotsEntityComponent + /// among the descriptors + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Entity CreateDOTSEntityFromSvelto(EntityArchetype archetype, ExclusiveGroupStruct groupID, EntityReference reference) + { + Entity dotsEntity = _EManager.CreateEntity(archetype); + + //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones + _EManager.AddSharedComponent(dotsEntity, new DOTSSveltoGroupID(groupID)); + _EManager.AddComponent(dotsEntity); + _EManager.SetComponentData(dotsEntity, new DOTSSveltoReference(reference)); + + return dotsEntity; + } + + /// + /// in this case the user decided to create a DOTS entity that is self managed and not managed + /// by the framework + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Entity CreateDOTSEntity(EntityArchetype archetype) + { + return _EManager.CreateEntity(archetype); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void DestroyEntity(Entity e) + { + _EManager.DestroyEntity(e); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveComponent(Entity dotsEntity) + { + _EManager.RemoveComponent(dotsEntity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddComponent(Entity dotsEntity) + where T : unmanaged, IComponentData + { + _EManager.AddComponent(dotsEntity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddComponent(Entity dotsEntity, in T component) + where T : unmanaged, IComponentData + { + _EManager.AddComponent(dotsEntity); + _EManager.SetComponentData(dotsEntity, component); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddSharedComponent(Entity dotsEntity, in T component) + where T : unmanaged, ISharedComponentData + { + _EManager.AddSharedComponent(dotsEntity, component); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddBuffer(Entity dotsEntity) + where T : unmanaged, IBufferElementData + { + _EManager.AddBuffer(dotsEntity); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetSharedComponentBatched(NativeArray nativeArray, SharedComponentData SCD) + where SharedComponentData : unmanaged, ISharedComponentData + { + _EManager.SetSharedComponent(nativeArray, SCD); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddComponentBatched(NativeArray DOTSEntities) + { + _EManager.AddComponent(DOTSEntities); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray CreateDOTSEntityFromSveltoBatched(Entity prefab, (uint rangeStart, uint rangeEnd) range, + ExclusiveGroupStruct groupID, NB DOSTEntityComponents) + { + unsafe + { + _jobHandle->Complete(); + + var count = (int)(range.rangeEnd - range.rangeStart); + var nativeArray = _EManager.Instantiate(prefab, count, _EManager.World.UpdateAllocator.ToAllocator); + _EManager.AddSharedComponent(nativeArray, new DOTSSveltoGroupID(groupID)); + + var setDOTSEntityComponentsJob = new SetDOTSEntityComponents + { + sveltoStartIndex = range.rangeStart, + createdEntities = nativeArray, + DOSTEntityComponents = DOSTEntityComponents + }; + *_jobHandle = JobHandle.CombineDependencies(*_jobHandle, setDOTSEntityComponentsJob.ScheduleParallel(count, default)); + + return nativeArray; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray CreateDOTSEntityFromSveltoBatched(Entity prefab, (uint rangeStart, uint rangeEnd) range, + ExclusiveGroupStruct groupID, NB DOSTEntityComponents, + SharedSveltoDictionaryNative referenceMap, NativeEntityIDs sveltoIds, out JobHandle creationJob) + { + var nativeArray = CreateDOTSEntityFromSveltoBatched(prefab, range, groupID, DOSTEntityComponents); + unsafe + { + var count = (int)(range.rangeEnd - range.rangeStart); + + _EManager.AddComponent(nativeArray); + + var SetDOTSSveltoReferenceJob = new SetDOTSSveltoReference + { + sveltoStartIndex = range.rangeStart, + createdEntities = nativeArray, + entityManager = _EManager, + ids = sveltoIds, + entityReferenceMap = referenceMap, + }; + creationJob = *_jobHandle = JobHandle.CombineDependencies(*_jobHandle, SetDOTSSveltoReferenceJob.ScheduleParallel(count, default)); + + return nativeArray; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddJobToComplete(JobHandle jobHandle) + { + unsafe + { + *_jobHandle = JobHandle.CombineDependencies(*_jobHandle, jobHandle); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void DestroyEntitiesBatched(NativeArray nativeArray) + { + _EManager.DestroyEntity(nativeArray); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Complete() + { + unsafe + { + _jobHandle->Complete(); + } + } + + [BurstCompile] + struct SetDOTSEntityComponents: IJobParallelFor + { + public uint sveltoStartIndex; + [ReadOnly] public NativeArray createdEntities; + public NB DOSTEntityComponents; + + public void Execute(int currentIndex) + { + int index = (int)(sveltoStartIndex + currentIndex); + var dotsEntity = createdEntities[currentIndex]; + + DOSTEntityComponents[index].dotsEntity = dotsEntity; + } + } + + [BurstCompile] + public struct SetDOTSSveltoReference: IJobParallelFor + { + public uint sveltoStartIndex; + [ReadOnly] public NativeArray createdEntities; + [NativeDisableParallelForRestriction] public EntityManager entityManager; + public NativeEntityIDs ids; + public SharedSveltoDictionaryNative entityReferenceMap; + + public void Execute(int currentIndex) + { + int index = (int)(sveltoStartIndex + currentIndex); + var dotsEntity = createdEntities[currentIndex]; + + entityManager.SetComponentData( + dotsEntity, new DOTSSveltoReference + { + entityReference = entityReferenceMap[ids[index]] + }); + } + } + + readonly EntityManager _EManager; + [NativeDisableUnsafePtrRestriction] readonly unsafe JobHandle* _jobHandle; + } +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSSveltoEGID.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSSveltoEGID.cs deleted file mode 100644 index 2fddcf5..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/DOTSSveltoEGID.cs +++ /dev/null @@ -1,55 +0,0 @@ -#if UNITY_ECS -using Unity.Entities; - -namespace Svelto.ECS.SveltoOnDOTS -{ - /// - /// DOTS component to keep track of the associated Svelto.ECS entity - /// - public struct DOTSSveltoEGID : IComponentData - { - public EGID egid; - - public DOTSSveltoEGID(EGID egid) { this.egid = egid; } - } - - /// - /// DOTS component to be able to query all the DOTS entities found in a Svelto.ECS group - /// - public readonly struct DOTSSveltoGroupID : ISharedComponentData - { - readonly ExclusiveGroupStruct group; - - public DOTSSveltoGroupID(ExclusiveGroupStruct exclusiveGroup) - { - @group = exclusiveGroup; - } - - public static implicit operator ExclusiveGroupStruct(DOTSSveltoGroupID group) - { - return group.@group; - } - } - - struct DOTSEntityToSetup : ISharedComponentData - { - internal readonly ExclusiveGroupStruct group; - - public DOTSEntityToSetup(ExclusiveGroupStruct exclusiveGroup) - { - @group = exclusiveGroup; - } - } - - public interface IEntityComponentForDOTS: IEntityComponent - { - public Entity dotsEntity { get; set; } - } - - - public struct DOTSEntityComponent:IEntityComponentForDOTS - { - public Entity dotsEntity { get; set; } - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/EntityCommandBufferForSvelto.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/EntityCommandBufferForSvelto.cs deleted file mode 100644 index b5d8907..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/EntityCommandBufferForSvelto.cs +++ /dev/null @@ -1,215 +0,0 @@ -#if UNITY_ECS -//#if !UNITY_ECS_050 -#define SLOW_SVELTO_ECB //Using EntityManager directly is much faster than using ECB because of the shared components -//#endif -using System; -using System.Runtime.CompilerServices; -using Unity.Entities; - -namespace Svelto.ECS.SveltoOnDOTS -{ - public readonly struct EntityCommandBufferForSvelto - { - internal EntityCommandBufferForSvelto(EntityCommandBuffer value, EntityManager manager) - { - _ECB = value; - _EManager = manager; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Entity CreatePureDOTSEntity(EntityArchetype jointArchetype) - { -#if SLOW_SVELTO_ECB - return _EManager.CreateEntity(jointArchetype); -#else - return _ECB.CreateEntity(jointArchetype); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetComponent(Entity e, in T component) where T : struct, IComponentData - { -#if SLOW_SVELTO_ECB - _EManager.SetComponentData(e, component); -#else - _ECB.SetComponent(e, component); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SetSharedComponent(Entity e, in T component) where T : struct, ISharedComponentData - { -#if SLOW_SVELTO_ECB - _EManager.SetSharedComponentData(e, component); -#else - _ECB.SetSharedComponent(e, component); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - ///Not ready for prime time with BURST yet, maybe with DOTS 1.0 - public static Entity CreateDOTSEntityOnSvelto(int sortKey, EntityCommandBuffer.ParallelWriter writer, - Entity entityComponentPrefabEntity, EGID egid, bool mustHandleDOTSComponent) - { -#if !SLOW_SVELTO_ECB - Entity dotsEntity = writer.Instantiate(sortKey, entityComponentPrefabEntity); - - //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones - writer.AddSharedComponent(sortKey, dotsEntity, new DOTSSveltoGroupID(egid.groupID)); - writer.AddComponent(sortKey, dotsEntity, new DOTSSveltoEGID(egid)); - if (mustHandleDOTSComponent) - writer.AddSharedComponent(sortKey, dotsEntity, new DOTSEntityToSetup(egid.groupID)); - - return dotsEntity; -#endif - throw new NotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Entity CreateDOTSEntityOnSvelto(Entity entityComponentPrefabEntity, EGID egid, - bool mustHandleDOTSComponent) - { -#if SLOW_SVELTO_ECB - Entity dotsEntity = _EManager.Instantiate(entityComponentPrefabEntity); - - //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones - _EManager.AddSharedComponentData(dotsEntity, new DOTSSveltoGroupID(egid.groupID)); - _EManager.AddComponentData(dotsEntity, new DOTSSveltoEGID(egid)); - if (mustHandleDOTSComponent) - _EManager.AddSharedComponentData(dotsEntity, new DOTSEntityToSetup(egid.groupID)); -#else - Entity dotsEntity = _ECB.Instantiate(entityComponentPrefabEntity); - - //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones - _ECB.AddSharedComponent(dotsEntity, new DOTSSveltoGroupID(egid.groupID)); - _ECB.AddComponent(dotsEntity, new DOTSSveltoEGID(egid)); - if (mustHandleDOTSComponent) - _ECB.AddSharedComponent(dotsEntity, new DOTSEntityToSetup(egid.groupID)); -#endif - - return dotsEntity; - } - - /// - /// This method assumes that the Svelto entity with EGID egid has also dotsEntityComponent - /// among the descriptors - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Entity CreateDOTSEntityOnSvelto(EntityArchetype archetype, EGID egid, bool mustHandleDOTSComponent) - { -#if SLOW_SVELTO_ECB - Entity dotsEntity = _EManager.CreateEntity(archetype); - - //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones - _EManager.AddSharedComponentData(dotsEntity, new DOTSSveltoGroupID(egid.groupID)); - _EManager.AddComponentData(dotsEntity, new DOTSSveltoEGID(egid)); - if (mustHandleDOTSComponent) - _EManager.AddSharedComponentData(dotsEntity, new DOTSEntityToSetup(egid.groupID)); -#else - Entity dotsEntity = _ECB.CreateEntity(archetype); - - //SharedComponentData can be used to group the DOTS ECS entities exactly like the Svelto ones - _ECB.AddSharedComponent(dotsEntity, new DOTSSveltoGroupID(egid.groupID)); - _ECB.AddComponent(dotsEntity, new DOTSSveltoEGID(egid)); - if (mustHandleDOTSComponent) - _ECB.AddSharedComponent(dotsEntity, new DOTSEntityToSetup(egid.groupID)); -#endif - - return dotsEntity; - } - - /// - /// in this case the user decided to create a DOTS entity that is self managed and not managed - /// by the framework - /// - /// - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Entity CreateDOTSEntityUnmanaged(EntityArchetype archetype) - { -#if SLOW_SVELTO_ECB - return _EManager.CreateEntity(archetype); -#else - return _ECB.CreateEntity(archetype); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void DestroyEntity(Entity e) - { -#if SLOW_SVELTO_ECB - _EManager.DestroyEntity(e); -#else - _ECB.DestroyEntity(e); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveComponent(Entity dotsEntity) - { -#if SLOW_SVELTO_ECB - _EManager.RemoveComponent(dotsEntity); -#else - _ECB.RemoveComponent(dotsEntity); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddComponent(Entity dotsEntity) where T : struct, IComponentData - { -#if SLOW_SVELTO_ECB - _EManager.AddComponent(dotsEntity); -#else - _ECB.AddComponent(dotsEntity); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddComponent(Entity dotsEntity, in T component) where T : struct, IComponentData - { -#if SLOW_SVELTO_ECB - _EManager.AddComponentData(dotsEntity, component); -#else - _ECB.AddComponent(dotsEntity, component); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddSharedComponent(Entity dotsEntity, in T component) where T : struct, ISharedComponentData - { -#if SLOW_SVELTO_ECB - _EManager.AddSharedComponentData(dotsEntity, component); -#else - _ECB.AddSharedComponent(dotsEntity, component); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void AddBuffer(Entity dotsEntity) where T : struct, IBufferElementData - { -#if SLOW_SVELTO_ECB - _EManager.AddBuffer(dotsEntity); -#else - _ECB.AddBuffer(dotsEntity); -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EntityCommandBuffer.ParallelWriter AsParallelWriter() - { -#if SLOW_SVELTO_ECB - throw new System.Exception(); -#else - return _ECB.AsParallelWriter(); -#endif - } - - readonly EntityCommandBuffer _ECB; - readonly EntityManager _EManager; - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSComponents.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSComponents.cs new file mode 100644 index 0000000..fd4fc0a --- /dev/null +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSComponents.cs @@ -0,0 +1,61 @@ +#if UNITY_ECS +using Unity.Entities; + +namespace Svelto.ECS.SveltoOnDOTS +{ + /// + /// If for some reason the user needs the DOTS entities to be grouped like the Svelto Entities, then this descriptor can be extended + /// which will automatically enable the SveltoOnDOTSHandleLifeTimeEngine synchronization. + /// This will also handle entities destruction. + /// + public class SveltoOnDotsSynchedEntityDescriptor: GenericEntityDescriptor { } + + public interface IEntityComponentForDOTS: IEntityComponent + { + public Entity dotsEntity { get; set; } + } + + public struct DOTSEntityComponent:IEntityComponentForDOTS + { + public DOTSEntityComponent(Entity entity) + { + dotsEntity = entity; + } + + public Entity dotsEntity { get; set; } + } + + //DOTS COMPONENTS: + + /// + /// DOTS component to keep track of the associated Svelto.ECS entity + /// + public struct DOTSSveltoReference: IComponentData + { + public EntityReference entityReference; + + public DOTSSveltoReference(EntityReference eEntityReference) + { + entityReference = eEntityReference; + } + } + + /// + /// DOTS component to be able to query all the DOTS entities found in a Svelto.ECS group + /// + public readonly struct DOTSSveltoGroupID: ISharedComponentData + { + readonly ExclusiveGroupStruct group; + + public DOTSSveltoGroupID(ExclusiveGroupStruct exclusiveGroup) + { + @group = exclusiveGroup; + } + + public static implicit operator ExclusiveGroupStruct(DOTSSveltoGroupID group) + { + return group.@group; + } + } +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSCreationEngine.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSCreationEngine.cs new file mode 100644 index 0000000..afd0420 --- /dev/null +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSCreationEngine.cs @@ -0,0 +1,17 @@ +#if UNITY_ECS +namespace Svelto.ECS.SveltoOnDOTS +{ + /// + /// SubmissionEngine is a dedicated DOTS ECS Svelto.ECS engine that allows using the DOTS ECS + /// EntityCommandBuffer for fast creation of DOTS entities + /// + public interface ISveltoOnDOTSStructuralEngine + { + DOTSOperationsForSvelto DOTSOperations { get; set; } + + string name { get; } + + void OnPostSubmission(); + } +} +#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEnginesGroup.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEnginesGroup.cs index 360e644..3b6d0f2 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEnginesGroup.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEnginesGroup.cs @@ -8,8 +8,7 @@ namespace Svelto.ECS.SveltoOnDOTS { /// /// This is a high level class to abstract the complexity of creating a Svelto ECS application that interacts - /// with DOTS ECS. However this is designed to make it work almost out of the box, but it should be eventually - /// substituted by project customized code. + /// with DOTS ECS. /// This is a JobifiedEngine and as such it expect to be ticked. Normally it must be executed in a /// SortedEnginesGroup as step that happens after the Svelto jobified engines run. /// @@ -20,21 +19,25 @@ namespace Svelto.ECS.SveltoOnDOTS /// Synchronizations engines to be executed (Svelto to DOTS ECS) /// Submission of Entities to be executed /// Svelto Add/Remove callbacks to be called - /// ISubmissionEngines to be executed + /// ISveltoOnDOTSStructuralEngine to be executed /// DOTS ECS engines to executed /// Synchronizations engines to be executed (DOTS ECS To Svelto) /// [Sequenced(nameof(JobifiedSveltoEngines.SveltoOnDOTS))] - public class SveltoOnDOTSEnginesGroup : IJobifiedEngine + public class SveltoOnDOTSEnginesGroup: IJobifiedEngine { public SveltoOnDOTSEnginesGroup(EnginesRoot enginesRoot) { - DBC.ECS.Check.Require(enginesRoot.scheduler is SimpleEntitiesSubmissionScheduler - , "The Engines root must use a EntitiesSubmissionScheduler scheduler implementation"); + DBC.ECS.Check.Require( + enginesRoot.scheduler is SimpleEntitiesSubmissionScheduler + , "The Engines root must use a EntitiesSubmissionScheduler scheduler implementation"); CreateUnityECSWorldForSvelto(enginesRoot.scheduler as SimpleEntitiesSubmissionScheduler, enginesRoot); } - + + /// + /// for the user to add pure DOTS ECS SystemBase/ISystem systems to the DOTS ECS world + /// public World world { get; private set; } public JobHandle Execute(JobHandle inputDeps) @@ -56,28 +59,29 @@ namespace Svelto.ECS.SveltoOnDOTS public string name => nameof(SveltoOnDOTSEnginesGroup); - public void AddSveltoToDOTSEngine(SyncSveltoToDOTSEngine engine) + public void AddSveltoToDOTSSyncEngine(SyncSveltoToDOTSEngine engine) { //it's a Svelto Engine/DOTS ECS SystemBase so it must be added in the DOTS ECS world AND svelto enginesRoot - world.AddSystem(engine); + world.AddSystemManaged(engine); + _enginesRoot.AddEngine(engine); _syncSveltoToDotsGroup.Add(engine); } - public void AddDOTSToSveltoEngine(SyncDOTSToSveltoEngine engine) + public void AddDOTSToSveltoSyncEngine(SyncDOTSToSveltoEngine engine) { //it's a Svelto Engine/DOTS ECS SystemBase so it must be added in the DOTS ECS world AND svelto enginesRoot - world.AddSystem(engine); + world.AddSystemManaged(engine); _enginesRoot.AddEngine(engine); _syncDotsToSveltoGroup.Add(engine); } - - public void AddDOTSSubmissionEngine(SveltoOnDOTSHandleCreationEngine submissionEngine) + + public void AddSveltoOnDOTSSubmissionEngine(ISveltoOnDOTSStructuralEngine submissionEngine) { _sveltoDotsEntitiesSubmissionGroup.Add(submissionEngine); - + if (submissionEngine is IEngine enginesRootEngine) _enginesRoot.AddEngine(enginesRootEngine); } @@ -96,17 +100,24 @@ namespace Svelto.ECS.SveltoOnDOTS World.DefaultGameObjectInjectionWorld = world; //This is the DOTS ECS group that takes care of all the DOTS ECS systems that creates entities - //it also submits Svelto entities - _sveltoDotsEntitiesSubmissionGroup = new SveltoOnDOTSEntitiesSubmissionGroup(scheduler, enginesRoot); - //This is the group that handles the DOTS ECS sync systems that copy the svelto entities values to DOTS ECS entities + //it also submits Svelto entities through the scheduler + var defaultSveltoOnDotsHandleLifeTimeEngine = new SveltoOnDOTSHandleLifeTimeEngine(); + _sveltoDotsEntitiesSubmissionGroup = new SveltoOnDOTSEntitiesSubmissionGroup(scheduler); + + enginesRoot.AddEngine(defaultSveltoOnDotsHandleLifeTimeEngine); + _sveltoDotsEntitiesSubmissionGroup.Add(defaultSveltoOnDotsHandleLifeTimeEngine); + enginesRoot.AddEngine(_sveltoDotsEntitiesSubmissionGroup); - world.AddSystem(_sveltoDotsEntitiesSubmissionGroup); + world.AddSystemManaged(_sveltoDotsEntitiesSubmissionGroup); + + //This is the group that handles the DOTS ECS sync systems that copy the svelto entities values to DOTS ECS entities _syncSveltoToDotsGroup = new SyncSveltoToDOTSGroup(); enginesRoot.AddEngine(_syncSveltoToDotsGroup); + + //This is the group that handles the DOTS ECS sync systems that copy the DOTS ECS entities values to svelto entities _syncDotsToSveltoGroup = new SyncDOTSToSveltoGroup(); enginesRoot.AddEngine(_syncDotsToSveltoGroup); - //This is the group that handles the DOTS ECS sync systems that copy the DOTS ECS entities values to svelto entities - //enginesRoot.AddEngine(new SveltoDOTS ECSEntitiesSubmissionGroup(scheduler, world)); + enginesRoot.AddEngine(this); _enginesRoot = enginesRoot; @@ -115,8 +126,8 @@ namespace Svelto.ECS.SveltoOnDOTS EnginesRoot _enginesRoot; SveltoOnDOTSEntitiesSubmissionGroup _sveltoDotsEntitiesSubmissionGroup; - SyncSveltoToDOTSGroup _syncSveltoToDotsGroup; - SyncDOTSToSveltoGroup _syncDotsToSveltoGroup; + SyncSveltoToDOTSGroup _syncSveltoToDotsGroup; + SyncDOTSToSveltoGroup _syncDotsToSveltoGroup; } } #endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEntitiesSubmissionGroup.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEntitiesSubmissionGroup.cs index 2a41d1e..5ef1553 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEntitiesSubmissionGroup.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSEntitiesSubmissionGroup.cs @@ -1,196 +1,104 @@ #if UNITY_ECS +#if !UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP_RUNTIME_WORLD +#error SveltoOnDOTS required the user to take over the DOTS world control and explicitly create it. UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP must be defined +#endif using System; -using System.Collections.Generic; using Svelto.Common; using Svelto.DataStructures; -using Svelto.ECS.Native; using Svelto.ECS.Schedulers; +using Unity.Collections.LowLevel.Unsafe; using Unity.Entities; using Unity.Jobs; -using Allocator = Unity.Collections.Allocator; namespace Svelto.ECS.SveltoOnDOTS { /// - /// SveltoDOTS ECSEntitiesSubmissionGroup expand the _submissionScheduler responsibility to integrate the - /// submission of Svelto entities with the submission of DOTS ECS entities using EntityCommandBuffer. + /// SveltoDOTS ECSEntitiesSubmissionGroup extends the _submissionScheduler responsibility to integrate the + /// submission of Svelto entities with the submission of DOTS ECS entities using DOTSOperationsForSvelto. /// As there is just one submissionScheduler per enginesRoot, there should be only one SveltoDOTS - /// ECSEntitiesSubmissionGroup - /// per engines group. It's expected use is showed in the class SveltoOnDOTS ECSEnginesGroup which should be used - /// instead of using this class directly. - /// Groups DOTS ECS/Svelto SystemBase engines that creates DOTS ECS entities. + /// ECSEntitiesSubmissionGroup. + /// initialise DOTS ECS/Svelto systems/engines that handles DOTS ECS entities structural changes. /// Flow: /// Complete all the jobs used as input dependencies (this is a sync point) - /// Create the new frame Command Buffer to use /// Svelto entities are submitted /// Svelto Add and remove callback are called - /// ECB is injected in all the registered engines - /// all the OnUpdate of the registered engines/systems are called - /// the DOTS ECS command buffer is flushed - /// all the DOTS ECS entities created that need Svelto information will be processed + /// ISveltoOnDOTSStructuralEngine can use DOTSOperationsForSvelto in their add/remove/moove callbacks /// [DisableAutoCreation] - public sealed partial class SveltoOnDOTSEntitiesSubmissionGroup : SystemBase, IQueryingEntitiesEngine, - ISveltoOnDOTSSubmission + public sealed partial class SveltoOnDOTSEntitiesSubmissionGroup: SystemBase, IQueryingEntitiesEngine, ISveltoOnDOTSSubmission { - public SveltoOnDOTSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler, - EnginesRoot enginesRoot) + public SveltoOnDOTSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler) { - _submissionScheduler = submissionScheduler; - _submissionEngines = new FasterList(); - _cachedList = new List(); - _sveltoOnDotsHandleLifeTimeEngines = new FasterList(); - - var defaultSveltoOnDotsHandleLifeTimeEngine = new SveltoOnDOTSHandleLifeTimeEngine(); - - enginesRoot.AddEngine(defaultSveltoOnDotsHandleLifeTimeEngine); - _sveltoOnDotsHandleLifeTimeEngines.Add(defaultSveltoOnDotsHandleLifeTimeEngine); + _submissionScheduler = submissionScheduler; + _submissionEngines = new FasterList(); } public EntitiesDB entitiesDB { get; set; } public void Ready() { } - //Right, when you record a command outside of a job using the regular ECB, you don't pass it a sort key. - //We instead use a constant for the main thread that is actually set to Int32.MaxValue. Where as the commands - //that are recording from jobs with the ParallelWriter, get a lower value sort key from the job. Because we - //playback the commands in order based on this sort key, the ParallelWriter commands end up happening before - //the main thread commands. This is where your error is coming from because the Instantiate command happens at - //the end because it's sort key is Int32.MaxValue. - //We don't recommend mixing the main thread and ParallelWriter commands in a single ECB for this reason. public void SubmitEntities(JobHandle jobHandle) { - if (_submissionScheduler.paused == true) + if (_submissionScheduler.paused == true || World.EntityManager == default) return; using (var profiler = new PlatformProfiler("SveltoDOTSEntitiesSubmissionGroup")) { - using (profiler.Sample("PreSubmissionPhase")) + using (profiler.Sample("Complete All Pending Jobs")) { - PreSubmissionPhase(ref jobHandle, profiler); + jobHandle.Complete(); //sync-point + EntityManager.CompleteAllTrackedJobs(); } - //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IDOTS ECSSubmissionEngines + //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the DOTS ECSSubmissionEngines _submissionScheduler.SubmitEntities(); - using (profiler.Sample("AfterSubmissionPhase")) - { - AfterSubmissionPhase(profiler); - } + foreach (var engine in _submissionEngines) + engine.OnPostSubmission(); + + _dotsOperationsForSvelto.Complete(); } } - public void Add(SveltoOnDOTSHandleCreationEngine engine) + public void Add(ISveltoOnDOTSStructuralEngine engine) { - // Console.LogDebug($"Add Submission Engine {engine} to the DOTS world {_ECBSystem.World.Name}"); - - //this is temporary enabled because of engines that needs EntityManagers for the wrong reasons. _submissionEngines.Add(engine); - engine.entityManager = EntityManager; - engine.OnCreate(); + if (World != null) + engine.DOTSOperations = _dotsOperationsForSvelto; } - public void Add(ISveltoOnDOTSHandleLifeTimeEngine engine) - { - // Console.LogDebug($"Add Submission Engine {engine} to the DOTS world {_ECBSystem.World.Name}"); - - _sveltoOnDotsHandleLifeTimeEngines.Add(engine); - } - - void PreSubmissionPhase(ref JobHandle jobHandle, PlatformProfiler profiler) - { - using (profiler.Sample("Complete All Pending Jobs")) jobHandle.Complete(); //sync-point - - _entityCommandBuffer = new EntityCommandBuffer((Allocator)Common.Allocator.TempJob); - - foreach (var system in _submissionEngines) - system.entityCommandBuffer = - new EntityCommandBufferForSvelto(_entityCommandBuffer, World.EntityManager); - - foreach (var system in _sveltoOnDotsHandleLifeTimeEngines) - system.entityCommandBuffer = - new EntityCommandBufferForSvelto(_entityCommandBuffer, World.EntityManager); - } - - void AfterSubmissionPhase(PlatformProfiler profiler) + protected override void OnCreate() { - JobHandle combinedHandle = default; - for (var i = 0; i < _submissionEngines.count; i++) + unsafe { - try - { - combinedHandle = JobHandle.CombineDependencies(combinedHandle, _submissionEngines[i].OnUpdate()); - } - catch (Exception e) - { - Console.LogException(e, _submissionEngines[i].name); - - throw; - } - } - - using (profiler.Sample("Playback Command Buffer")) - { - _entityCommandBuffer.Playback(EntityManager); - _entityCommandBuffer.Dispose(); + _jobHandle = (JobHandle*) MemoryUtilities.NativeAlloc((uint)MemoryUtilities.SizeOf(), Allocator.Persistent); + _dotsOperationsForSvelto = new DOTSOperationsForSvelto(World.EntityManager, _jobHandle); + + //initialise engines field while world was null + foreach (var engine in _submissionEngines) + engine.DOTSOperations = _dotsOperationsForSvelto; } - - using (profiler.Sample("ConvertPendingEntities")) - ConvertPendingEntities(combinedHandle); } - //Note: when this is called, the CommandBuffer is flushed so the not temporary DOTS entity ID will be used - void ConvertPendingEntities(JobHandle combinedHandle) + protected override void OnDestroy() { - var entityCommandBuffer = new EntityCommandBuffer((Allocator)Common.Allocator.TempJob); - var cmd = entityCommandBuffer.AsParallelWriter(); - - _cachedList.Clear(); - - //note with DOTS 0.17 unfortunately this allocates a lot :( - EntityManager.GetAllUniqueSharedComponentData(_cachedList); - - Dependency = JobHandle.CombineDependencies(Dependency, combinedHandle); - - for (int i = 0; i < _cachedList.Count; i++) + unsafe { - var dotsEntityToSetup = _cachedList[i]; - if (dotsEntityToSetup.@group == ExclusiveGroupStruct.Invalid) continue; - - var mapper = entitiesDB.QueryNativeMappedEntities(dotsEntityToSetup.@group); - - //Note: for some reason GetAllUniqueSharedComponentData returns DOTSEntityToSetup with valid values - //that are not used anymore by any entity. Something to keep an eye on if fixed on future versions - //of DOTS - - Entities.ForEach((Entity entity, int entityInQueryIndex, in DOTSSveltoEGID egid) => - { - mapper.Entity(egid.egid.entityID).dotsEntity = entity; - cmd.RemoveComponent(entityInQueryIndex, entity); - }).WithSharedComponentFilter(dotsEntityToSetup).ScheduleParallel(); + base.OnDestroy(); + + MemoryUtilities.NativeFree((IntPtr)_jobHandle, Allocator.Persistent); } - - Dependency.Complete(); - - entityCommandBuffer.Playback(EntityManager); - entityCommandBuffer.Dispose(); - } - - protected override void OnCreate() - { } protected override void OnUpdate() { throw new NotSupportedException("if this is called something broke the original design"); } - - readonly FasterList _submissionEngines; - readonly FasterList _sveltoOnDotsHandleLifeTimeEngines; + readonly FasterList _submissionEngines; readonly SimpleEntitiesSubmissionScheduler _submissionScheduler; - readonly List _cachedList; - EntityCommandBuffer _entityCommandBuffer; + DOTSOperationsForSvelto _dotsOperationsForSvelto; + unsafe JobHandle* _jobHandle; } } #endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleCreationEngine.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleCreationEngine.cs deleted file mode 100644 index 8247cc8..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleCreationEngine.cs +++ /dev/null @@ -1,60 +0,0 @@ -#if UNITY_ECS -using System; -using System.Runtime.CompilerServices; -using Unity.Entities; -using Unity.Jobs; - -namespace Svelto.ECS.SveltoOnDOTS -{ - /// - /// SubmissionEngine is a dedicated DOTS ECS Svelto.ECS engine that allows using the DOTS ECS - /// EntityCommandBuffer for fast creation of DOTS entities - /// - public abstract class SveltoOnDOTSHandleCreationEngine - { - protected EntityCommandBufferForSvelto ECB { get; private set; } - - protected internal EntityManager entityManager - { - // [Obsolete( - // "Attention: the use of EntityManager directly is deprecated. ECB MUST BE USED INSTEAD")] - get; - internal set; - } - - internal EntityCommandBufferForSvelto entityCommandBuffer - { - set => ECB = value; - } - - protected EntityArchetype CreateArchetype(params ComponentType[] types) - { - return entityManager.CreateArchetype(types); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected Entity CreateDOTSEntityOnSvelto(Entity entityComponentPrefabEntity, EGID egid, - bool mustHandleDOTSComponent) - { - return ECB.CreateDOTSEntityOnSvelto(entityComponentPrefabEntity, egid, mustHandleDOTSComponent); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected Entity CreateDOTSEntityOnSvelto(EntityArchetype archetype, EGID egid, bool mustHandleDOTSComponent) - { - return ECB.CreateDOTSEntityOnSvelto(archetype, egid, mustHandleDOTSComponent); - } - - protected internal virtual void OnCreate() - { - } - - protected internal virtual JobHandle OnUpdate() - { - return default; - } - - public abstract string name { get; } - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleLifeTimeEngine.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleLifeTimeEngine.cs index 8832d68..c637edb 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleLifeTimeEngine.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SveltoOnDOTSHandleLifeTimeEngine.cs @@ -1,44 +1,49 @@ #if UNITY_ECS +using Unity.Collections; +using Unity.Entities; namespace Svelto.ECS.SveltoOnDOTS { - public interface ISveltoOnDOTSHandleLifeTimeEngine + /// + /// Automatic Svelto Group -> DOTS archetype synchronization when necessary + /// + /// + class SveltoOnDOTSHandleLifeTimeEngine: ISveltoOnDOTSStructuralEngine, IReactOnRemoveEx, + IReactOnSwapEx where DOTSEntityComponent : unmanaged, IEntityComponentForDOTS { - EntityCommandBufferForSvelto entityCommandBuffer { set; } - } - - public class SveltoOnDOTSHandleLifeTimeEngine : ISveltoOnDOTSHandleLifeTimeEngine, - IReactOnRemove, - IReactOnSwapEx where DOTSEntityComponent : unmanaged, IEntityComponentForDOTS - { - public void Remove(ref DOTSEntityComponent entityComponent, EGID egid) + public void Remove((uint start, uint end) rangeOfEntities, in EntityCollection entities, ExclusiveGroupStruct groupID) { - ECB.DestroyEntity(entityComponent.dotsEntity); - } + var (buffer, _) = entities; - EntityCommandBufferForSvelto ECB { get; set; } + var nativeArray = new NativeArray((int)(rangeOfEntities.end - rangeOfEntities.start), Allocator.Temp); - public EntityCommandBufferForSvelto entityCommandBuffer - { - set => ECB = value; + //todo this could be burstified or memcpied + int counter = 0; + for (uint i = rangeOfEntities.start; i < rangeOfEntities.end; i++) + nativeArray[counter++] = buffer[i].dotsEntity; + + DOTSOperations.DestroyEntitiesBatched(nativeArray); } - public void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection collection, + public void MovedTo((uint start, uint end) rangeOfEntities, in EntityCollection entities, ExclusiveGroupStruct _, ExclusiveGroupStruct toGroup) { - var (entities, entityIDs, _) = collection; + var (buffer, _) = entities; + + var nativeArray = new NativeArray((int)(rangeOfEntities.end - rangeOfEntities.start), Allocator.Temp); + //todo this could be burstified or memcpied + int counter = 0; for (uint i = rangeOfEntities.start; i < rangeOfEntities.end; i++) - { - ref var entityComponent = ref entities[i]; - ECB.SetSharedComponent(entityComponent.dotsEntity, new DOTSSveltoGroupID(toGroup)); - - ECB.SetComponent(entityComponent.dotsEntity, new DOTSSveltoEGID - { - egid = new EGID(entityIDs[i], toGroup) - }); - } + nativeArray[counter++] = buffer[i].dotsEntity; + + DOTSOperations.SetSharedComponentBatched(nativeArray, new DOTSSveltoGroupID(toGroup)); } + + public void OnPostSubmission() { } + + public DOTSOperationsForSvelto DOTSOperations { get; set; } + public string name => nameof(SveltoOnDOTSHandleLifeTimeEngine); } } #endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SyncSveltoToDOTSGroup.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SyncSveltoToDOTSGroup.cs index 6427e30..29f03b4 100644 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SyncSveltoToDOTSGroup.cs +++ b/com.sebaslab.svelto.ecs/Extensions/Unity/DOTS/UECS/SyncSveltoToDOTSGroup.cs @@ -49,10 +49,9 @@ namespace Svelto.ECS.SveltoOnDOTS // // Tim Johansson 2 hours ago // Yes, you would have to do it every time + public class SyncSveltoToDOTSGroup: UnsortedJobifiedEnginesGroup { } - public class SyncSveltoToDOTSGroup : UnsortedJobifiedEnginesGroup {} - - public abstract partial class SyncSveltoToDOTSEngine : SystemBase, IJobifiedEngine + public abstract partial class SyncSveltoToDOTSEngine: SystemBase, IJobifiedEngine { //The dependency returned is enough for the Svelto Engines running after this to take in consideration //the Systembase jobs. The svelto engines do not need to take in consideration the new dependencies created @@ -71,14 +70,14 @@ namespace Svelto.ECS.SveltoOnDOTS { //SysteBase jobs that will use this Dependency will wait for inputDeps to be completed before to execute Dependency = JobHandle.CombineDependencies(Dependency, _inputDeps); - + OnSveltoUpdate(); } protected abstract void OnSveltoUpdate(); public abstract string name { get; } - + JobHandle _inputDeps; } } diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/EntityDescriptorHolder.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/EntityDescriptorHolder.cs deleted file mode 100644 index 1ee8d37..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/EntityDescriptorHolder.cs +++ /dev/null @@ -1,69 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -using System; -using System.Collections.Generic; -using Svelto.ECS.Hybrid; -using UnityEngine; - -namespace Svelto.ECS.Extensions.Unity -{ - public class ListToPopupAttribute : PropertyAttribute - { - public Type classType; - public string listName; - - public ListToPopupAttribute(Type classType, string listName) - { - this.classType = classType; - this.listName = listName; - } - } - /// - /// I introduced this option thinking it could be a good idea, but I am not sure anymore. Although it's slightly - /// more annoying, extending GenericEntityDescriptorHolder is wiser than using this class. - /// Consider this experimental - /// Todo: sort in alphabetic order - /// Todo: hide inner descriptors - /// - public class EntityDescriptorHolder : MonoBehaviour, IEntityDescriptorHolder - { - public IEntityDescriptor GetDescriptor() { return type; } - - public string groupName => _groupName; - public ushort id => _id; - - [Tooltip( - "it's possible to name groups and query group by name. This entity will be created in a named group if inserted")] - [SerializeField] - string _groupName; - - [Tooltip("this entity will be created with the selected ID, if inserted. An ID must be unique in each group")] - [SerializeField] - ushort _id; - - [Tooltip("choose the entity type, not optional")] - [ListToPopup(typeof(EntityDescriptorHolder), "DescriptorList")] - [SerializeField] - string Descriptor; - - internal IEntityDescriptor type; - - static List DescriptorList = new List(); - - static EntityDescriptorHolder() - { - var assemblies = AssemblyUtility.GetCompatibleAssemblies(); - Type d1 = typeof(IEntityDescriptor); - - foreach (var assembly in assemblies) - foreach (Type type in AssemblyUtility.GetTypesSafe(assembly)) - { - if (type != null && d1.IsAssignableFrom(type) && type.IsAbstract == false) - { - DescriptorList.Add(type); - } - } - } - } -} - -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/GenericEntityDescriptorHolder.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/GenericEntityDescriptorHolder.cs deleted file mode 100644 index c000153..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/GenericEntityDescriptorHolder.cs +++ /dev/null @@ -1,29 +0,0 @@ -#if UNITY_5 || UNITY_5_3_OR_NEWER -using Svelto.ECS.Hybrid; -using UnityEngine; - -namespace Svelto.ECS.Extensions.Unity -{ - public abstract class GenericEntityDescriptorHolder: MonoBehaviour, IEntityDescriptorHolder - where T: IEntityDescriptor, new() - { - public IEntityDescriptor GetDescriptor() - { - return EntityDescriptorTemplate.descriptor; - } - - public T GetRealDescriptor() - { - return EntityDescriptorTemplate.realDescriptor; - } - - public string groupName => _groupName; - public ushort id => _id; - -#pragma warning disable 649 - [SerializeField] string _groupName; - [SerializeField] ushort _id; -#pragma warning restore 649 - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/ListToPopupDrawer.cs b/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/ListToPopupDrawer.cs deleted file mode 100644 index 214862d..0000000 --- a/com.sebaslab.svelto.ecs/Extensions/Unity/GameObjects/ListToPopupDrawer.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if UNITY_EDITOR -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Svelto.ECS; -using Svelto.ECS.Extensions.Unity; -using UnityEditor; -using UnityEngine; - -[CustomPropertyDrawer(typeof(ListToPopupAttribute))] -public class ListToPopupDrawer : PropertyDrawer -{ - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - ListToPopupAttribute atb = attribute as ListToPopupAttribute; - List stringList = null; - - if (atb.classType.GetField(atb.listName, BindingFlags.Static | BindingFlags.NonPublic) != null) - { - stringList = - atb.classType.GetField(atb.listName, BindingFlags.Static | BindingFlags.NonPublic) - .GetValue(atb.classType) as List; - } - - if (stringList != null && stringList.Count != 0) - { - int selectedIndex = Mathf.Max(0, stringList.FindIndex(t => t.Name == property.stringValue)); - - selectedIndex = EditorGUI.Popup(position, property.name, selectedIndex - , stringList.Select(t => t.Name).ToArray()); - - property.stringValue = stringList[selectedIndex].Name; - (property.serializedObject.targetObject as EntityDescriptorHolder).type = - Activator.CreateInstance(stringList[selectedIndex]) as IEntityDescriptor; - } - else - { - EditorGUI.TextArea(position, "Error - no valid entity descriptors found"); - } - } -} -#endif \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Serialization/ComposedComponentSerializer.cs b/com.sebaslab.svelto.ecs/Serialization/ComposedComponentSerializer.cs index ba82b64..69f4b47 100644 --- a/com.sebaslab.svelto.ecs/Serialization/ComposedComponentSerializer.cs +++ b/com.sebaslab.svelto.ecs/Serialization/ComposedComponentSerializer.cs @@ -1,9 +1,10 @@ using System; +using Svelto.ECS.Internal; namespace Svelto.ECS.Serialization { public class ComposedComponentSerializer : IComponentSerializer - where T : unmanaged, IBaseEntityComponent where X : class, IComponentSerializer, new() + where T : unmanaged, _IInternalEntityComponent where X : class, IComponentSerializer, new() where Y : class, IComponentSerializer, new() { public ComposedComponentSerializer() @@ -17,7 +18,7 @@ namespace Svelto.ECS.Serialization { foreach (IComponentSerializer s in _serializers) { - serializationData.data.IncrementCountBy(s.size); + serializationData.data.IncrementCountBy((uint)s.size); if (s.SerializeSafe(value, serializationData)) return true; } diff --git a/com.sebaslab.svelto.ecs/Serialization/DefaultSerializer.cs b/com.sebaslab.svelto.ecs/Serialization/DefaultSerializer.cs index 22fa0f2..08ded65 100644 --- a/com.sebaslab.svelto.ecs/Serialization/DefaultSerializer.cs +++ b/com.sebaslab.svelto.ecs/Serialization/DefaultSerializer.cs @@ -1,9 +1,10 @@ +using Svelto.Common; +using Svelto.ECS.Internal; + namespace Svelto.ECS.Serialization { - public class DefaultSerializer : IComponentSerializer where T : unmanaged, IBaseEntityComponent + public class DefaultSerializer : IComponentSerializer where T : unmanaged, _IInternalEntityComponent { - static readonly uint SIZEOFT = SerializableComponentBuilder.SIZE; - static DefaultSerializer() { var _type = typeof(T); @@ -21,14 +22,14 @@ namespace Svelto.ECS.Serialization #endif } - public uint size => SIZEOFT; + public uint size => (uint)MemoryUtilities.SizeOf(); public bool Serialize(in T value, ISerializationData serializationData) { DefaultSerializerUtils.CopyToByteArray(value, serializationData.data.ToArrayFast(out _), serializationData.dataPos); - serializationData.dataPos += SIZEOFT; + serializationData.dataPos += (uint)size; return true; } @@ -38,7 +39,7 @@ namespace Svelto.ECS.Serialization value = DefaultSerializerUtils.CopyFromByteArray(serializationData.data.ToArrayFast(out _), serializationData.dataPos); - serializationData.dataPos += SIZEOFT; + serializationData.dataPos += (uint)size; return true; } diff --git a/com.sebaslab.svelto.ecs/Serialization/DefaultSerializerUtils.cs b/com.sebaslab.svelto.ecs/Serialization/DefaultSerializerUtils.cs index 0d5e6a9..10461fb 100644 --- a/com.sebaslab.svelto.ecs/Serialization/DefaultSerializerUtils.cs +++ b/com.sebaslab.svelto.ecs/Serialization/DefaultSerializerUtils.cs @@ -1,9 +1,9 @@ using System; -using Svelto.ECS; +using Svelto.ECS.Internal; public static class DefaultSerializerUtils { - public static unsafe void CopyToByteArray(in T src, byte[] data, uint offsetDst) where T : unmanaged, IBaseEntityComponent + public static unsafe void CopyToByteArray(in T src, byte[] data, uint offsetDst) where T : unmanaged, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO if (data.Length - offsetDst < sizeof(T)) @@ -29,7 +29,7 @@ public static class DefaultSerializerUtils } } - public static unsafe T CopyFromByteArray(byte[] data, uint offsetSrc) where T : unmanaged, IBaseEntityComponent + public static unsafe T CopyFromByteArray(byte[] data, uint offsetSrc) where T : unmanaged, _IInternalEntityComponent { T dst = default; diff --git a/com.sebaslab.svelto.ecs/Serialization/DontSerialize.cs b/com.sebaslab.svelto.ecs/Serialization/DontSerialize.cs index 38f5b02..ba69532 100644 --- a/com.sebaslab.svelto.ecs/Serialization/DontSerialize.cs +++ b/com.sebaslab.svelto.ecs/Serialization/DontSerialize.cs @@ -1,6 +1,8 @@ +using Svelto.ECS.Internal; + namespace Svelto.ECS.Serialization { - public class DontSerialize : IComponentSerializer where T : unmanaged, IBaseEntityComponent + public class DontSerialize : IComponentSerializer where T : unmanaged, _IInternalEntityComponent { public uint size => 0; diff --git a/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs b/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs index c7a1765..6e0820c 100644 --- a/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs +++ b/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.GenericEntitySerialization.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using Svelto.DataStructures; +using Svelto.ECS.Internal; using Svelto.ECS.Serialization; namespace Svelto.ECS @@ -89,7 +90,7 @@ namespace Svelto.ECS /// public T DeserializeEntityComponent(ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, IEntityComponent { var readPos = serializationData.dataPos; T entityComponent = default; @@ -103,7 +104,7 @@ namespace Svelto.ECS break; } else - serializationData.dataPos += serializableEntityBuilder.Size(serializationType); + serializationData.dataPos += (uint)serializableEntityBuilder.Size(serializationType); } serializationData.dataPos = readPos; @@ -169,7 +170,7 @@ namespace Svelto.ECS foreach (var serializableEntityBuilder in entityDescriptor.componentsToSerialize) { - componentSizeTotal += serializableEntityBuilder.Size(serializationType); + componentSizeTotal += (uint)serializableEntityBuilder.Size(serializationType); } //When constructing an SerializableEntityHeader the data position of the serializationData is incremented by the size of the header. diff --git a/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.SerializableEntityHeader.cs b/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.SerializableEntityHeader.cs index 868a4d1..efa9517 100644 --- a/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.SerializableEntityHeader.cs +++ b/com.sebaslab.svelto.ecs/Serialization/EnginesRoot.SerializableEntityHeader.cs @@ -31,14 +31,14 @@ namespace Svelto.ECS | serializationData.data[serializationData.dataPos++] << 24); uint groupID = (uint) - (serializationData.data[serializationData.dataPos++] + (serializationData.data[serializationData.dataPos++] | serializationData.data[serializationData.dataPos++] << 8 - | serializationData.data[serializationData.dataPos++] << 16 - | serializationData.data[serializationData.dataPos++] << 24); + | serializationData.data[serializationData.dataPos++] << 16); + var byteMask = serializationData.data[serializationData.dataPos++]; entityComponentsCount = serializationData.data[serializationData.dataPos++]; - egid = new EGID(entityID, new ExclusiveGroupStruct(groupID)); + egid = new EGID(entityID, new ExclusiveGroupStruct(groupID, byteMask)); } internal void Copy(ISerializationData serializationData) diff --git a/com.sebaslab.svelto.ecs/Serialization/IComponentSerializer.cs b/com.sebaslab.svelto.ecs/Serialization/IComponentSerializer.cs index 48e2c1d..31675b3 100644 --- a/com.sebaslab.svelto.ecs/Serialization/IComponentSerializer.cs +++ b/com.sebaslab.svelto.ecs/Serialization/IComponentSerializer.cs @@ -1,8 +1,9 @@ +using Svelto.ECS.Internal; #if DEBUG && !PROFILE_SVELTO #endif namespace Svelto.ECS.Serialization { - public interface IComponentSerializer where T : unmanaged, IBaseEntityComponent + public interface IComponentSerializer where T : unmanaged, _IInternalEntityComponent { bool Serialize(in T value, ISerializationData serializationData); bool Deserialize(ref T value, ISerializationData serializationData); @@ -10,6 +11,7 @@ namespace Svelto.ECS.Serialization //Todo: We currently use the value 0 (which I am not even sure if it's not ambiguous) to mark an entity as dynamic size. If zero the systems assumes that the first word to deserialize //is the size of the entity. However this means that this field cannot reliably be used to know the size of the entity before hand, we need to either remove all the ambiguities in //this sense or find another way to serialise dynamic size entities. + //note must stay uint because it's too late to convert it for old projects uint size { get; } } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs b/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs index f2d39ce..08b68b7 100644 --- a/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs +++ b/com.sebaslab.svelto.ecs/Serialization/IEntitySerialization.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using Svelto.ECS.Internal; namespace Svelto.ECS.Serialization { @@ -84,6 +85,6 @@ namespace Svelto.ECS.Serialization T DeserializeEntityComponent(ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, int serializationType) - where T : unmanaged, IBaseEntityComponent; + where T : unmanaged, IEntityComponent; } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Serialization/ISerializableComponentBuilder.cs b/com.sebaslab.svelto.ecs/Serialization/ISerializableComponentBuilder.cs index 2b5ab89..7fecda6 100644 --- a/com.sebaslab.svelto.ecs/Serialization/ISerializableComponentBuilder.cs +++ b/com.sebaslab.svelto.ecs/Serialization/ISerializableComponentBuilder.cs @@ -13,6 +13,6 @@ namespace Svelto.ECS.Serialization void Deserialize(ISerializationData serializationData, in EntityInitializer initializer , int serializationType); - uint Size(int serializationType); + int Size(int serializationType); } } \ No newline at end of file diff --git a/com.sebaslab.svelto.ecs/Serialization/PartialSerializer.cs b/com.sebaslab.svelto.ecs/Serialization/PartialSerializer.cs index 4653925..8a3d026 100644 --- a/com.sebaslab.svelto.ecs/Serialization/PartialSerializer.cs +++ b/com.sebaslab.svelto.ecs/Serialization/PartialSerializer.cs @@ -2,6 +2,7 @@ using System; using System.Reflection; using System.Runtime.InteropServices; using Svelto.DataStructures; +using Svelto.ECS.Internal; using Attribute = System.Attribute; namespace Svelto.ECS.Serialization @@ -11,7 +12,7 @@ namespace Svelto.ECS.Serialization {} public class PartialSerializer : IComponentSerializer - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { static PartialSerializer() { diff --git a/com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs b/com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs index 7db46b4..7c9988d 100644 --- a/com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs +++ b/com.sebaslab.svelto.ecs/Serialization/SerializableComponentBuilder.cs @@ -4,105 +4,105 @@ using Svelto.ECS.Internal; namespace Svelto.ECS.Serialization { - public struct SerializersInfo where SerializationEnum:Enum + public struct SerializersInfo + where SerializationEnum : Enum { - public uint numberOfSerializationTypes => (uint) length; + public uint numberOfSerializationTypes => (uint)length; static readonly int length = Enum.GetNames(typeof(SerializationEnum)).Length; } - public class SerializableComponentBuilder : ComponentBuilder, ISerializableComponentBuilder - where T : unmanaged, IBaseEntityComponent + public class SerializableComponentBuilder: ComponentBuilder, ISerializableComponentBuilder + where T : unmanaged, IEntityComponent { - public static readonly uint SIZE = (uint) MemoryUtilities.SizeOf(); + public static uint SIZE => (uint)MemoryUtilities.SizeOf(); - public void Serialize(uint entityID, ITypeSafeDictionary dictionary, ISerializationData serializationData - , int serializationType) + public void Serialize(uint entityID, ITypeSafeDictionary dictionary, ISerializationData serializationData + , int serializationType) { IComponentSerializer componentSerializer = _serializers[serializationType]; - var safeDictionary = (ITypeSafeDictionary) dictionary; + var safeDictionary = (ITypeSafeDictionary)dictionary; if (safeDictionary.TryFindIndex(entityID, out uint index) == false) { throw new ECSException("Entity Serialization failed"); } - ref T val = ref safeDictionary.GetDirectValueByRef(index); + ref T val = ref safeDictionary.GetDirectValueByRef(index); - serializationData.dataPos = (uint) serializationData.data.count; + serializationData.dataPos = (uint)serializationData.data.count; - serializationData.data.IncrementCountBy(componentSerializer.size); + serializationData.data.IncrementCountBy((uint)componentSerializer.size); componentSerializer.SerializeSafe(val, serializationData); } public void Deserialize(uint entityID, ITypeSafeDictionary dictionary, ISerializationData serializationData - , int serializationType) + , int serializationType) { - IComponentSerializer componentSerializer = _serializers[(int) serializationType]; + IComponentSerializer componentSerializer = _serializers[(int)serializationType]; // Handle the case when an entity struct is gone - var safeDictionary = (ITypeSafeDictionary) dictionary; + var safeDictionary = (ITypeSafeDictionary)dictionary; if (safeDictionary.TryFindIndex(entityID, out uint index) == false) { throw new ECSException("Entity Deserialization failed"); } - ref T val = ref safeDictionary.GetDirectValueByRef(index); + ref T val = ref safeDictionary.GetDirectValueByRef(index); componentSerializer.DeserializeSafe(ref val, serializationData); } - public void Deserialize - (ISerializationData serializationData, in EntityInitializer initializer - , int serializationType) + public void Deserialize(ISerializationData serializationData, in EntityInitializer initializer + , int serializationType) { - IComponentSerializer componentSerializer = _serializers[(int) serializationType]; + IComponentSerializer componentSerializer = _serializers[(int)serializationType]; componentSerializer.DeserializeSafe(ref initializer.GetOrAdd(), serializationData); } - public uint Size(int serializationType) + public int Size(int serializationType) { - return _serializers[(int) serializationType].size; + return (int)_serializers[(int)serializationType].size; } - public void Deserialize - (ISerializationData serializationData, ref T entityComponent, int serializationType) + public void Deserialize(ISerializationData serializationData, ref T entityComponent, int serializationType) { - IComponentSerializer componentSerializer = _serializers[(int) serializationType]; + IComponentSerializer componentSerializer = _serializers[(int)serializationType]; componentSerializer.DeserializeSafe(ref entityComponent, serializationData); } private protected IComponentSerializer[] _serializers; } - - public class SerializableComponentBuilder : SerializableComponentBuilder - where T : unmanaged, IBaseEntityComponent where SerializationType : Enum + + public class SerializableComponentBuilder: SerializableComponentBuilder + where T : unmanaged, IEntityComponent + where SerializationType : Enum { static SerializableComponentBuilder() { } public SerializableComponentBuilder(params ValueTuple>[] serializers) { var length = new SerializersInfo().numberOfSerializationTypes; - + _serializers = new IComponentSerializer[(int)length]; for (int i = 0; i < serializers.Length; i++) { ref (int, IComponentSerializer) s = ref serializers[i]; - _serializers[(int) s.Item1] = s.Item2; + _serializers[(int)s.Item1] = s.Item2; } // Just in case the above are the same type if (serializers.Length > 0) { - for (int i = 0; i < (int) length; i++) + for (int i = 0; i < (int)length; i++) { if (_serializers[i] == null) _serializers[i] = new DontSerialize(); } } else - for (int i = 0; i < (int) length; i++) + for (int i = 0; i < (int)length; i++) { _serializers[i] = new DefaultSerializer(); } diff --git a/com.sebaslab.svelto.ecs/Serialization/SerializerExt.cs b/com.sebaslab.svelto.ecs/Serialization/SerializerExt.cs index 1487488..6eb31a3 100644 --- a/com.sebaslab.svelto.ecs/Serialization/SerializerExt.cs +++ b/com.sebaslab.svelto.ecs/Serialization/SerializerExt.cs @@ -1,10 +1,12 @@ +using Svelto.ECS.Internal; + namespace Svelto.ECS.Serialization { public static class SerializerExt { public static bool SerializeSafe (this IComponentSerializer componentSerializer, in T value, ISerializationData serializationData) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO uint posBefore = serializationData.dataPos; @@ -24,7 +26,7 @@ namespace Svelto.ECS.Serialization public static bool DeserializeSafe (this IComponentSerializer componentSerializer, ref T value, ISerializationData serializationData) - where T : unmanaged, IBaseEntityComponent + where T : unmanaged, _IInternalEntityComponent { #if DEBUG && !PROFILE_SVELTO uint posBefore = serializationData.dataPos; diff --git a/com.sebaslab.svelto.ecs/Svelto.ECS.asmdef b/com.sebaslab.svelto.ecs/Svelto.ECS.asmdef index b04a2ef..21c789e 100644 --- a/com.sebaslab.svelto.ecs/Svelto.ECS.asmdef +++ b/com.sebaslab.svelto.ecs/Svelto.ECS.asmdef @@ -2,10 +2,10 @@ "name": "Svelto.ECS", "rootNamespace": "", "references": [ - "Unity.Entities", "Unity.Collections", "Unity.Burst", - "Unity.Jobs", + "Unity.Entities", + "Unity.Mathematics", "Svelto.Common" ], "includePlatforms": [], @@ -23,11 +23,6 @@ "expression": "2019.3", "define": "UNITY_JOBS" }, - { - "name": "com.unity.entities", - "expression": "", - "define": "UNITY_ECS" - }, { "name": "com.unity.burst", "expression": "", @@ -39,24 +34,29 @@ "define": "UNITY_COLLECTIONS" }, { - "name": "com.unity.entities", + "name": "com.unity.burst", "expression": "", "define": "UNITY_NATIVE" }, { - "name": "com.unity.burst", + "name": "com.unity.collections", "expression": "", "define": "UNITY_NATIVE" }, { - "name": "com.unity.collections", + "name": "com.unity.entities", "expression": "", - "define": "UNITY_NATIVE" + "define": "UNITY_ECS" }, { "name": "com.unity.entities", - "expression": "0.45", - "define": "UNITY_ECS_050" + "expression": "0.90", + "define": "UNITY_ECS_100" + }, + { + "name": "com.unity.entities", + "expression": "", + "define": "UNITY_NATIVE" } ], "noEngineReferences": false diff --git a/com.sebaslab.svelto.ecs/Svelto.ECS.csproj b/com.sebaslab.svelto.ecs/Svelto.ECS.csproj index e8abc68..f3eafd1 100644 --- a/com.sebaslab.svelto.ecs/Svelto.ECS.csproj +++ b/com.sebaslab.svelto.ecs/Svelto.ECS.csproj @@ -1,11 +1,11 @@ - + Svelto.ECS - 8 - netstandard2.0 + 9 + netstandard2.1 Svelto - 3.3.0 - 3.3.0 + 3.4.0 + 3.4.0 true Debug;Release;SlowSubmissionRelease;SlowSubmissionDebug AnyCPU @@ -43,7 +43,7 @@ true - + diff --git a/com.sebaslab.svelto.ecs/package.json b/com.sebaslab.svelto.ecs/package.json index 9c6d1f8..db4568e 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.3.2" + "com.sebaslab.svelto.common": "3.4.0" }, "keywords": [ "svelto", @@ -19,7 +19,7 @@ "svelto.ecs" ], "name": "com.sebaslab.svelto.ecs", - "version": "3.3.2", + "version": "3.4.0", "type": "library", "unity": "2019.3" } diff --git a/com.sebaslab.svelto.ecs/version.json b/com.sebaslab.svelto.ecs/version.json index 3160839..2d946b1 100644 --- a/com.sebaslab.svelto.ecs/version.json +++ b/com.sebaslab.svelto.ecs/version.json @@ -1,3 +1,3 @@ { - "version": "3.3.2" + "version": "3.4.0" }