diff --git a/Svelto.Common b/Svelto.Common index ee4913b..d0e0823 160000 --- a/Svelto.Common +++ b/Svelto.Common @@ -1 +1 @@ -Subproject commit ee4913b173b844afcce2ec017abcb0845764db40 +Subproject commit d0e08231b4464226b04c81b6a9aaaf5250200e36 diff --git a/Svelto.ECS/CHANGELOG.md b/Svelto.ECS/CHANGELOG.md new file mode 100644 index 0000000..dd5f969 --- /dev/null +++ b/Svelto.ECS/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog +All notable changes to this project will be documented in this file. I created this file with Svelto.ECS version 3.1. + +## [0.3.1] + +### Changed + +* rearrange folders structures for clarity +* added DoubleEntitiesEnumerator, as seen in MiniExample 4, to allow a double iteration of the same group skipping already checked tuples +* reengineered the behaviour of WaitForSubmissionEnumerator +* removed redudant ISimpleEntitySubmissionScheduler interface +* renamed BuildGroup in to ExclusiveBuildGroup +* renamed EntityComponentInitializer to EntityInitializer +* Entity Submission now can optionally be time slices (based on number of entities to submit per slice) +* working on the Unity extension Submission Engine, still wip +* added the possibility to hold a reference in a EntityViewComponent. This reference cannot be accesses as an object, but can be converted to the original object in OOP abstract layers +* renamed NativeEntityComponentInitializer to NativeEntityInitializer +* + +### Fixed + diff --git a/Svelto.ECS/AllowMultipleAttribute.cs b/Svelto.ECS/Core/AllowMultipleAttribute.cs similarity index 100% rename from Svelto.ECS/AllowMultipleAttribute.cs rename to Svelto.ECS/Core/AllowMultipleAttribute.cs diff --git a/Svelto.ECS/CheckEntityUtilities.cs b/Svelto.ECS/Core/CheckEntityUtilities.cs similarity index 97% rename from Svelto.ECS/CheckEntityUtilities.cs rename to Svelto.ECS/Core/CheckEntityUtilities.cs index 020b4b2..0016ac8 100644 --- a/Svelto.ECS/CheckEntityUtilities.cs +++ b/Svelto.ECS/Core/CheckEntityUtilities.cs @@ -3,7 +3,6 @@ #endif using System; using System.Collections.Generic; -using System.Diagnostics; using Svelto.DataStructures; namespace Svelto.ECS @@ -72,7 +71,7 @@ namespace Svelto.ECS #if DONT_USE [Conditional("CHECK_ALL")] #endif - void RemoveGroupID(BuildGroup groupID) { _idChecker.Remove(groupID); } + void RemoveGroupID(ExclusiveBuildGroup groupID) { _idChecker.Remove(groupID); } #if DONT_USE [Conditional("CHECK_ALL")] diff --git a/Svelto.ECS/ComponentBuilder.CheckFields.cs b/Svelto.ECS/Core/ComponentBuilder.CheckFields.cs similarity index 100% rename from Svelto.ECS/ComponentBuilder.CheckFields.cs rename to Svelto.ECS/Core/ComponentBuilder.CheckFields.cs diff --git a/Svelto.ECS/ComponentBuilder.cs b/Svelto.ECS/Core/ComponentBuilder.cs similarity index 100% rename from Svelto.ECS/ComponentBuilder.cs rename to Svelto.ECS/Core/ComponentBuilder.cs diff --git a/Svelto.ECS/DBC.cs b/Svelto.ECS/Core/DBC.cs similarity index 100% rename from Svelto.ECS/DBC.cs rename to Svelto.ECS/Core/DBC.cs diff --git a/Svelto.ECS/ECSException.cs b/Svelto.ECS/Core/ECSException.cs similarity index 100% rename from Svelto.ECS/ECSException.cs rename to Svelto.ECS/Core/ECSException.cs diff --git a/Svelto.ECS/EGID.cs b/Svelto.ECS/Core/EGID.cs similarity index 96% rename from Svelto.ECS/EGID.cs rename to Svelto.ECS/Core/EGID.cs index e2a0f77..fc50271 100644 --- a/Svelto.ECS/EGID.cs +++ b/Svelto.ECS/Core/EGID.cs @@ -31,7 +31,7 @@ namespace Svelto.ECS _GID = MAKE_GLOBAL_ID(entityID, groupID); } - public EGID(uint entityID, BuildGroup groupID) : this() + public EGID(uint entityID, ExclusiveBuildGroup groupID) : this() { _GID = MAKE_GLOBAL_ID(entityID, groupID.group); } diff --git a/Svelto.ECS/EGIDMapper.cs b/Svelto.ECS/Core/EGIDMapper.cs similarity index 98% rename from Svelto.ECS/EGIDMapper.cs rename to Svelto.ECS/Core/EGIDMapper.cs index 3596a9d..bfadf1c 100644 --- a/Svelto.ECS/EGIDMapper.cs +++ b/Svelto.ECS/Core/EGIDMapper.cs @@ -1,7 +1,6 @@ using System; using System.Runtime.CompilerServices; using Svelto.Common; -using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS diff --git a/Svelto.ECS/Core/EnginesGroup/IStepEngine.cs b/Svelto.ECS/Core/EnginesGroup/IStepEngine.cs new file mode 100644 index 0000000..bf4c249 --- /dev/null +++ b/Svelto.ECS/Core/EnginesGroup/IStepEngine.cs @@ -0,0 +1,25 @@ +namespace Svelto.ECS +{ + public interface IStepEngine : IEngine + { + void Step(); + + string name { get; } + } + + public interface IStepEngine : IEngine + { + void Step(in T _param); + + string name { get; } + } + + //this must stay IStep Engine as it may be part of a group itself + public interface IStepGroupEngine : IStepEngine + { + } + + public interface IStepGroupEngine : IStepEngine + { + } +} \ No newline at end of file diff --git a/Svelto.ECS/SortedEnginesGroup.cs b/Svelto.ECS/Core/EnginesGroup/SortedEnginesGroup.cs similarity index 80% rename from Svelto.ECS/SortedEnginesGroup.cs rename to Svelto.ECS/Core/EnginesGroup/SortedEnginesGroup.cs index dc4d7ec..e2d9224 100644 --- a/Svelto.ECS/SortedEnginesGroup.cs +++ b/Svelto.ECS/Core/EnginesGroup/SortedEnginesGroup.cs @@ -3,28 +3,6 @@ using Svelto.Common; namespace Svelto.ECS { - public interface IStepEngine : IEngine - { - void Step(); - - string name { get; } - } - - public interface IStepEngine : IEngine - { - void Step(ref T _param); - - string name { get; } - } - - public interface IStepGroupEngine : IStepEngine - { - } - - public interface IStepGroupEngine : IStepEngine - { - } - public abstract class SortedEnginesGroup : IStepGroupEngine where SequenceOrder : struct, ISequenceOrder where Interface : IStepEngine { @@ -47,7 +25,7 @@ namespace Svelto.ECS } } - public string name => _name; + public string name => _name; readonly string _name; readonly Sequence _instancedSequence; @@ -62,7 +40,7 @@ namespace Svelto.ECS _instancedSequence = new Sequence(engines); } - public void Step(ref Parameter param) + public void Step(in Parameter param) { var sequenceItems = _instancedSequence.items; using (var profiler = new PlatformProfiler(_name)) @@ -70,7 +48,7 @@ namespace Svelto.ECS for (var index = 0; index < sequenceItems.count; index++) { var engine = sequenceItems[index]; - using (profiler.Sample(engine.name)) engine.Step(ref param); + using (profiler.Sample(engine.name)) engine.Step(param); } } } diff --git a/Svelto.ECS/UnsortedEnginesGroup.cs b/Svelto.ECS/Core/EnginesGroup/UnsortedEnginesGroup.cs similarity index 50% rename from Svelto.ECS/UnsortedEnginesGroup.cs rename to Svelto.ECS/Core/EnginesGroup/UnsortedEnginesGroup.cs index 2362f80..c36572a 100644 --- a/Svelto.ECS/UnsortedEnginesGroup.cs +++ b/Svelto.ECS/Core/EnginesGroup/UnsortedEnginesGroup.cs @@ -30,4 +30,32 @@ namespace Svelto.ECS readonly string _name; readonly FasterList _instancedSequence; } + + public abstract class UnsortedEnginesGroup : IStepGroupEngine + where Interface : IStepEngine + { + protected UnsortedEnginesGroup(FasterList engines) + { + _name = "UnsortedEnginesGroup - "+this.GetType().Name; + _instancedSequence = engines; + } + + public void Step(in Parameter param) + { + var sequenceItems = _instancedSequence; + using (var profiler = new PlatformProfiler(_name)) + { + for (var index = 0; index < sequenceItems.count; index++) + { + var engine = sequenceItems[index]; + using (profiler.Sample(engine.name)) engine.Step(param); + } + } + } + + public string name => _name; + + readonly string _name; + readonly FasterList _instancedSequence; + } } \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.DoubleBufferedEntitiesToAdd.cs b/Svelto.ECS/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs similarity index 99% rename from Svelto.ECS/EnginesRoot.DoubleBufferedEntitiesToAdd.cs rename to Svelto.ECS/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs index 86322d4..d62f522 100644 --- a/Svelto.ECS/EnginesRoot.DoubleBufferedEntitiesToAdd.cs +++ b/Svelto.ECS/Core/EnginesRoot.DoubleBufferedEntitiesToAdd.cs @@ -1,5 +1,4 @@ -using System; -using Svelto.DataStructures; +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS diff --git a/Svelto.ECS/EnginesRoot.Engines.cs b/Svelto.ECS/Core/EnginesRoot.Engines.cs similarity index 70% rename from Svelto.ECS/EnginesRoot.Engines.cs rename to Svelto.ECS/Core/EnginesRoot.Engines.cs index 7b3b388..b7f7e8c 100644 --- a/Svelto.ECS/EnginesRoot.Engines.cs +++ b/Svelto.ECS/Core/EnginesRoot.Engines.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using Svelto.Common; using Svelto.DataStructures; @@ -9,26 +10,38 @@ namespace Svelto.ECS { public sealed partial class EnginesRoot { - public readonly struct EntitiesSubmitter + public struct EntitiesSubmitter { - public EntitiesSubmitter(EnginesRoot enginesRoot) + public EntitiesSubmitter(EnginesRoot enginesRoot) : this() { _weakReference = new Svelto.DataStructures.WeakReference(enginesRoot); } public bool IsUnused => _weakReference.IsValid == false; - public void Invoke() + public IEnumerator Invoke(uint maxNumberOfOperationsPerFrame) { - if (_weakReference.IsValid) - _weakReference.Target.SubmitEntityComponents(); + var entitiesSubmissionScheduler = _weakReference.Target._scheduler; + if (_weakReference.IsValid && entitiesSubmissionScheduler.paused == false) + { + var submitEntityComponents = + _weakReference.Target.SubmitEntityComponents(maxNumberOfOperationsPerFrame); + DBC.ECS.Check.Require(entitiesSubmissionScheduler.isRunning == false + , "A submission started while the previous one was still flushing"); + entitiesSubmissionScheduler.isRunning = true; + while (submitEntityComponents.MoveNext() == true) + yield return null; + + entitiesSubmissionScheduler.isRunning = false; + ++entitiesSubmissionScheduler.iteration; + } } readonly Svelto.DataStructures.WeakReference _weakReference; } - readonly EntitiesSubmissionScheduler _scheduler; - public IEntitiesSubmissionScheduler scheduler => _scheduler; + readonly EntitiesSubmissionScheduler _scheduler; + public EntitiesSubmissionScheduler scheduler => _scheduler; /// /// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot @@ -40,15 +53,16 @@ namespace Svelto.ECS /// public EnginesRoot(EntitiesSubmissionScheduler entitiesComponentScheduler) { - _entitiesOperations = new ThreadSafeDictionary(); - serializationDescriptorMap = new SerializationDescriptorMap(); - _reactiveEnginesAddRemove = new FasterDictionary>(); - _reactiveEnginesSwap = new FasterDictionary>(); - _reactiveEnginesSubmission = new FasterList(); - _enginesSet = new FasterList(); - _enginesTypeSet = new HashSet(); - _disposableEngines = new FasterList(); - _transientEntitiesOperations = new FasterList(); + _entitiesOperations = new FasterDictionary(); + serializationDescriptorMap = new SerializationDescriptorMap(); + _reactiveEnginesAddRemove = new FasterDictionary>(); + _reactiveEnginesAddRemoveOnDispose = new FasterDictionary>(); + _reactiveEnginesSwap = new FasterDictionary>(); + _reactiveEnginesSubmission = new FasterList(); + _enginesSet = new FasterList(); + _enginesTypeSet = new HashSet(); + _disposableEngines = new FasterList(); + _transientEntitiesOperations = new FasterList(); _groupEntityComponentsDB = new FasterDictionary>(); @@ -104,15 +118,13 @@ namespace Svelto.ECS } } - foreach (FasterDictionary>. - KeyValuePairFast groups in _groupEntityComponentsDB) + foreach (var groups in _groupEntityComponentsDB) { - foreach (FasterDictionary.KeyValuePairFast entityList in groups - .Value) + foreach (var entityList in groups.Value) try { - entityList.Value.ExecuteEnginesRemoveCallbacks(_reactiveEnginesAddRemove, profiler - , new ExclusiveGroupStruct(groups.Key)); + entityList.Value.ExecuteEnginesRemoveCallbacks(_reactiveEnginesAddRemoveOnDispose, profiler + , new ExclusiveGroupStruct(groups.Key)); } catch (Exception e) { @@ -120,18 +132,15 @@ namespace Svelto.ECS } } - foreach (FasterDictionary>. - KeyValuePairFast groups in _groupEntityComponentsDB) + foreach (var groups in _groupEntityComponentsDB) { - foreach (FasterDictionary.KeyValuePairFast entityList in groups - .Value) + foreach (var entityList in groups.Value) entityList.Value.Dispose(); } - foreach (FasterDictionary>. - KeyValuePairFast type in _groupFilters) - foreach (FasterDictionary.KeyValuePairFast group in type.Value) - group.Value.Dispose(); + foreach (var type in _groupFilters) + foreach (var group in type.Value) + group.Value.Dispose(); _groupFilters.Clear(); @@ -148,6 +157,7 @@ namespace Svelto.ECS _enginesTypeSet.Clear(); _reactiveEnginesSwap.Clear(); _reactiveEnginesAddRemove.Clear(); + _reactiveEnginesAddRemoveOnDispose.Clear(); _reactiveEnginesSubmission.Clear(); _entitiesOperations.Clear(); @@ -183,6 +193,9 @@ namespace Svelto.ECS if (engine is IReactOnAddAndRemove viewEngine) CheckReactEngineComponents(viewEngine, _reactiveEnginesAddRemove); + if (engine is IReactOnDispose viewEngineDispose) + CheckReactEngineComponents(viewEngineDispose, _reactiveEnginesAddRemoveOnDispose); + if (engine is IReactOnSwap viewEngineSwap) CheckReactEngineComponents(viewEngineSwap, _reactiveEnginesSwap); @@ -219,12 +232,12 @@ namespace Svelto.ECS { var genericArguments = interf.GetGenericArgumentsEx(); - AddEngine(engine, genericArguments, engines); + AddEngineToList(engine, genericArguments, engines); } } } - static void AddEngine + static void AddEngineToList (T engine, Type[] entityComponentTypes, FasterDictionary> engines) where T : class, IReactEngine { @@ -232,29 +245,24 @@ namespace Svelto.ECS { var type = entityComponentTypes[i]; - AddEngine(engine, engines, type); - } - } + if (engines.TryGetValue(new RefWrapperType(type), out var list) == false) + { + list = new FasterList(); - static void AddEngine(T engine, FasterDictionary> engines, Type type) - where T : class, IReactEngine - { - if (engines.TryGetValue(new RefWrapperType(type), out var list) == false) - { - list = new FasterList(); + engines.Add(new RefWrapperType(type), list); + } - engines.Add(new RefWrapperType(type), list); + list.Add(engine); } - - list.Add(engine); } readonly FasterDictionary> _reactiveEnginesAddRemove; + readonly FasterDictionary> _reactiveEnginesAddRemoveOnDispose; readonly FasterDictionary> _reactiveEnginesSwap; - readonly FasterList _reactiveEnginesSubmission; - readonly FasterList _disposableEngines; - readonly FasterList _enginesSet; - readonly HashSet _enginesTypeSet; - internal bool _isDisposing; + readonly FasterList _reactiveEnginesSubmission; + readonly FasterList _disposableEngines; + readonly FasterList _enginesSet; + readonly HashSet _enginesTypeSet; + internal bool _isDisposing; } } \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.Entities.cs b/Svelto.ECS/Core/EnginesRoot.Entities.cs similarity index 98% rename from Svelto.ECS/EnginesRoot.Entities.cs rename to Svelto.ECS/Core/EnginesRoot.Entities.cs index fadbabb..1192ae2 100644 --- a/Svelto.ECS/EnginesRoot.Entities.cs +++ b/Svelto.ECS/Core/EnginesRoot.Entities.cs @@ -29,7 +29,7 @@ namespace Svelto.ECS ///-------------------------------------------- [MethodImpl(MethodImplOptions.AggressiveInlining)] - EntityComponentInitializer BuildEntity + EntityInitializer BuildEntity (EGID entityID, IComponentBuilder[] componentsToBuild, Type descriptorType, IEnumerable implementors = null) { @@ -39,7 +39,7 @@ namespace Svelto.ECS var dic = EntityFactory.BuildGroupedEntities(entityID, _groupedEntityToAdd, componentsToBuild , implementors, descriptorType); - return new EntityComponentInitializer(entityID, dic); + return new EntityInitializer(entityID, dic); } ///-------------------------------------------- @@ -285,8 +285,7 @@ namespace Svelto.ECS { if (_groupEntityComponentsDB.TryGetValue(groupID, out var dictionariesOfEntities)) { - foreach (FasterDictionary.KeyValuePairFast dictionaryOfEntities - in dictionariesOfEntities) + foreach (var dictionaryOfEntities in dictionariesOfEntities) { dictionaryOfEntities.Value.ExecuteEnginesRemoveCallbacks(_reactiveEnginesAddRemove, profiler , new ExclusiveGroupStruct(groupID)); diff --git a/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs b/Svelto.ECS/Core/EnginesRoot.GenericEntityFactory.cs similarity index 75% rename from Svelto.ECS/EnginesRoot.GenericEntityFactory.cs rename to Svelto.ECS/Core/EnginesRoot.GenericEntityFactory.cs index e13432b..fc0a80e 100644 --- a/Svelto.ECS/EnginesRoot.GenericEntityFactory.cs +++ b/Svelto.ECS/Core/EnginesRoot.GenericEntityFactory.cs @@ -13,8 +13,8 @@ namespace Svelto.ECS _enginesRoot = new Svelto.DataStructures.WeakReference(weakReference); } - public EntityComponentInitializer BuildEntity - (uint entityID, BuildGroup groupStructId, IEnumerable implementors = null) + public EntityInitializer BuildEntity + (uint entityID, ExclusiveBuildGroup groupStructId, IEnumerable implementors = null) where T : IEntityDescriptor, new() { return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId) @@ -22,26 +22,26 @@ namespace Svelto.ECS , TypeCache.type, implementors); } - public EntityComponentInitializer BuildEntity(EGID egid, IEnumerable implementors = null) + public EntityInitializer BuildEntity(EGID egid, IEnumerable implementors = null) where T : IEntityDescriptor, new() { return _enginesRoot.Target.BuildEntity( egid, EntityDescriptorTemplate.descriptor.componentsToBuild, TypeCache.type, implementors); } - public EntityComponentInitializer BuildEntity + public EntityInitializer BuildEntity (EGID egid, T entityDescriptor, IEnumerable implementors) where T : IEntityDescriptor { return _enginesRoot.Target.BuildEntity(egid, entityDescriptor.componentsToBuild, TypeCache.type, implementors); } #if UNITY_NATIVE - public NativeEntityFactory ToNative(string memberName) where T : IEntityDescriptor, new() + public NativeEntityFactory ToNative(string callerName) where T : IEntityDescriptor, new() { - return _enginesRoot.Target.ProvideNativeEntityFactoryQueue(memberName); + return _enginesRoot.Target.ProvideNativeEntityFactoryQueue(callerName); } #endif - public EntityComponentInitializer BuildEntity - (uint entityID, BuildGroup groupStructId, T descriptorEntity, IEnumerable implementors) + public EntityInitializer BuildEntity + (uint entityID, ExclusiveBuildGroup groupStructId, T descriptorEntity, IEnumerable implementors) where T : IEntityDescriptor { return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId) @@ -54,7 +54,7 @@ namespace Svelto.ECS _enginesRoot.Target.Preallocate(groupStructId, size); } - public EntityComponentInitializer BuildEntity(EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable implementors = null) + public EntityInitializer BuildEntity(EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable implementors = null) { return _enginesRoot.Target.BuildEntity(egid, componentsToBuild, type, implementors); } diff --git a/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs b/Svelto.ECS/Core/EnginesRoot.GenericEntityFunctions.cs similarity index 88% rename from Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs rename to Svelto.ECS/Core/EnginesRoot.GenericEntityFunctions.cs index 8b9a537..801700d 100644 --- a/Svelto.ECS/EnginesRoot.GenericEntityFunctions.cs +++ b/Svelto.ECS/Core/EnginesRoot.GenericEntityFunctions.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; using Svelto.Common; using Svelto.DataStructures; using Svelto.ECS.Internal; @@ -20,18 +19,18 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveEntity(uint entityID, BuildGroup groupID) where T : + public void RemoveEntity(uint entityID, ExclusiveBuildGroup groupID, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new() { - RemoveEntity(new EGID(entityID, groupID)); + RemoveEntity(new EGID(entityID, groupID), memberName); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveEntity(EGID entityEGID) where T : IEntityDescriptor, new() + public void RemoveEntity(EGID entityEGID, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new() { DBC.ECS.Check.Require(entityEGID.groupID != 0, "invalid group detected"); var descriptorComponentsToBuild = EntityDescriptorTemplate.descriptor.componentsToBuild; - _enginesRoot.Target.CheckRemoveEntityID(entityEGID, TypeCache.type); + _enginesRoot.Target.CheckRemoveEntityID(entityEGID, TypeCache.type, memberName); _enginesRoot.Target.QueueEntitySubmitOperation( new EntitySubmitOperation(EntitySubmitOperationType.Remove, entityEGID, entityEGID, @@ -39,7 +38,7 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveEntitiesFromGroup(BuildGroup groupID) + public void RemoveEntitiesFromGroup(ExclusiveBuildGroup groupID) { DBC.ECS.Check.Require(groupID != 0, "invalid group detected"); _enginesRoot.Target.RemoveGroupID(groupID); @@ -73,7 +72,7 @@ namespace Svelto.ECS // } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SwapEntitiesInGroup(BuildGroup fromGroupID, BuildGroup toGroupID) + public void SwapEntitiesInGroup(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new() { if (_enginesRoot.Target._groupEntityComponentsDB.TryGetValue( @@ -98,23 +97,23 @@ namespace Svelto.ECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SwapEntityGroup(uint entityID, BuildGroup fromGroupID, - BuildGroup toGroupID) + public void SwapEntityGroup(uint entityID, ExclusiveBuildGroup fromGroupID, + ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new() { SwapEntityGroup(new EGID(entityID, fromGroupID), toGroupID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SwapEntityGroup(EGID fromID, BuildGroup toGroupID) + public void SwapEntityGroup(EGID fromID, ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new() { SwapEntityGroup(fromID, new EGID(fromID.entityID, (uint) toGroupID)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void SwapEntityGroup(EGID fromID, BuildGroup toGroupID - , BuildGroup mustBeFromGroup) + public void SwapEntityGroup(EGID fromID, ExclusiveBuildGroup toGroupID + , ExclusiveBuildGroup mustBeFromGroup) where T : IEntityDescriptor, new() { if (fromID.groupID != mustBeFromGroup) @@ -125,7 +124,7 @@ namespace Svelto.ECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SwapEntityGroup(EGID fromID, EGID toID - , BuildGroup mustBeFromGroup) + , ExclusiveBuildGroup mustBeFromGroup) where T : IEntityDescriptor, new() { if (fromID.groupID != mustBeFromGroup) @@ -196,7 +195,7 @@ namespace Svelto.ECS } else #endif - _entitiesOperations.Set((ulong) entitySubmitOperation.fromID, entitySubmitOperation); + _entitiesOperations[(ulong) entitySubmitOperation.fromID] = entitySubmitOperation; } } } \ No newline at end of file diff --git a/Svelto.ECS/EnginesRoot.Submission.cs b/Svelto.ECS/Core/EnginesRoot.Submission.cs similarity index 53% rename from Svelto.ECS/EnginesRoot.Submission.cs rename to Svelto.ECS/Core/EnginesRoot.Submission.cs index 559c800..8c22000 100644 --- a/Svelto.ECS/EnginesRoot.Submission.cs +++ b/Svelto.ECS/Core/EnginesRoot.Submission.cs @@ -1,4 +1,4 @@ -using System; +using System.Collections; using Svelto.Common; using Svelto.DataStructures; using Svelto.ECS.Internal; @@ -9,16 +9,18 @@ namespace Svelto.ECS { readonly FasterList _transientEntitiesOperations; - void SubmitEntityComponents() + IEnumerator SubmitEntityComponents(uint maxNumberOfOperations) { using (var profiler = new PlatformProfiler("Svelto.ECS - Entities Submission")) { int iterations = 0; do { - SingleSubmission(profiler); + var submitEntityComponents = SingleSubmission(profiler, maxNumberOfOperations); + while (submitEntityComponents.MoveNext() == true) + yield return null; } while ((_groupedEntityToAdd.currentEntitiesCreatedPerGroup.count > 0 || - _entitiesOperations.Count > 0) && ++iterations < 5); + _entitiesOperations.count > 0) && ++iterations < 5); #if DEBUG && !PROFILE_SVELTO if (iterations == 5) @@ -32,7 +34,8 @@ namespace Svelto.ECS /// Something to do when I will optimize the callbacks /// /// - void SingleSubmission(in PlatformProfiler profiler) + /// + IEnumerator SingleSubmission(PlatformProfiler profiler, uint maxNumberOfOperations) { #if UNITY_NATIVE NativeOperationSubmission(profiler); @@ -40,8 +43,9 @@ namespace Svelto.ECS ClearChecks(); bool entitiesAreSubmitted = false; + uint numberOfOperations = 0; - if (_entitiesOperations.Count > 0) + if (_entitiesOperations.count > 0) { using (profiler.Sample("Remove and Swap operations")) { @@ -88,6 +92,16 @@ namespace Svelto.ECS throw; } + + ++numberOfOperations; + + if ((uint)numberOfOperations >= (uint)maxNumberOfOperations) + { + yield return null; + + numberOfOperations = 0; + + } } } @@ -102,11 +116,61 @@ namespace Svelto.ECS { try { - AddEntityComponentsToTheDBAndSuitableEngines(profiler); + using (profiler.Sample("Add entities to database")) + { + //each group is indexed by entity view type. for each type there is a dictionary indexed by entityID + foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) + { + var groupID = groupToSubmit.Key; + var groupDB = GetOrCreateGroup(groupID, profiler); + + //add the entityComponents in the group + foreach (var entityComponentsToSubmit in _groupedEntityToAdd.other[groupID]) + { + var type = entityComponentsToSubmit.Key; + var targetTypeSafeDictionary = entityComponentsToSubmit.Value; + var wrapper = new RefWrapperType(type); + + ITypeSafeDictionary dbDic = GetOrCreateTypeSafeDictionary(groupID, groupDB, wrapper, + targetTypeSafeDictionary); + + //Fill the DB with the entity components generate this frame. + dbDic.AddEntitiesFromDictionary(targetTypeSafeDictionary, groupID); + } + } + } + + //then submit everything in the engines, so that the DB is up to date with all the entity components + //created by the entity built + using (profiler.Sample("Add entities to engines")) + { + foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) + { + var groupID = groupToSubmit.Key; + var groupDB = _groupEntityComponentsDB[groupID]; + + foreach (var entityComponentsToSubmit in _groupedEntityToAdd.other[groupID]) + { + var realDic = groupDB[new RefWrapperType(entityComponentsToSubmit.Key)]; + + entityComponentsToSubmit.Value.ExecuteEnginesAddOrSwapCallbacks(_reactiveEnginesAddRemove, realDic, + null, new ExclusiveGroupStruct(groupID), in profiler); + + ++numberOfOperations; + + if (numberOfOperations >= maxNumberOfOperations) + { + yield return null; + + numberOfOperations = 0; + } + } + } + } } finally { - using (profiler.Sample("clear 6operates double buffering")) + using (profiler.Sample("clear double buffering")) { //other can be cleared now, but let's avoid deleting the dictionary every time _groupedEntityToAdd.ClearOther(); @@ -125,54 +189,7 @@ namespace Svelto.ECS } } - void AddEntityComponentsToTheDBAndSuitableEngines(in PlatformProfiler profiler) - { - using (profiler.Sample("Add entities to database")) - { - //each group is indexed by entity view type. for each type there is a dictionary indexed by entityID - foreach (var groupOfEntitiesToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) - { - var groupID = groupOfEntitiesToSubmit.Key; - - var groupDB = GetOrCreateGroup(groupID, profiler); - - //add the entityComponents in the group - foreach (var entityComponentsToSubmit in _groupedEntityToAdd.other[groupID]) - { - var type = entityComponentsToSubmit.Key; - var targetTypeSafeDictionary = entityComponentsToSubmit.Value; - var wrapper = new RefWrapperType(type); - - ITypeSafeDictionary dbDic = GetOrCreateTypeSafeDictionary(groupID, groupDB, wrapper, - targetTypeSafeDictionary); - - //Fill the DB with the entity components generate this frame. - dbDic.AddEntitiesFromDictionary(targetTypeSafeDictionary, groupID); - } - } - } - - //then submit everything in the engines, so that the DB is up to date with all the entity components - //created by the entity built - using (profiler.Sample("Add entities to engines")) - { - foreach (var groupToSubmit in _groupedEntityToAdd.otherEntitiesCreatedPerGroup) - { - var groupID = groupToSubmit.Key; - var groupDB = _groupEntityComponentsDB[groupID]; - - foreach (var entityComponentsToSubmit in _groupedEntityToAdd.other[groupID]) - { - var realDic = groupDB[new RefWrapperType(entityComponentsToSubmit.Key)]; - - entityComponentsToSubmit.Value.ExecuteEnginesAddOrSwapCallbacks(_reactiveEnginesAddRemove, realDic, - null, new ExclusiveGroupStruct(groupToSubmit.Key), in profiler); - } - } - } - } - readonly DoubleBufferedEntitiesToAdd _groupedEntityToAdd; - readonly ThreadSafeDictionary _entitiesOperations; + readonly FasterDictionary _entitiesOperations; } } \ No newline at end of file diff --git a/Svelto.ECS/EntitiesDB.FindGroups.cs b/Svelto.ECS/Core/EntitiesDB.FindGroups.cs similarity index 100% rename from Svelto.ECS/EntitiesDB.FindGroups.cs rename to Svelto.ECS/Core/EntitiesDB.FindGroups.cs diff --git a/Svelto.ECS/EntitiesDB.cs b/Svelto.ECS/Core/EntitiesDB.cs similarity index 100% rename from Svelto.ECS/EntitiesDB.cs rename to Svelto.ECS/Core/EntitiesDB.cs diff --git a/Svelto.ECS/EntityCollection.cs b/Svelto.ECS/Core/EntityCollection.cs similarity index 82% rename from Svelto.ECS/EntityCollection.cs rename to Svelto.ECS/Core/EntityCollection.cs index c39ed69..803328f 100644 --- a/Svelto.ECS/EntityCollection.cs +++ b/Svelto.ECS/Core/EntityCollection.cs @@ -6,16 +6,17 @@ namespace Svelto.ECS { public readonly ref struct EntityCollection where T : struct, IEntityComponent { - static readonly bool IsUnmanaged = TypeSafeDictionary.IsUnmanaged; - - public EntityCollection(IBuffer buffer, uint count):this() + static readonly bool IsUnmanaged = TypeSafeDictionary.IsUnmanaged; + + public EntityCollection(IBuffer buffer, uint count) : this() { + DBC.ECS.Check.Require(count == 0 || buffer.isValid, "Buffer is found in impossible state"); if (IsUnmanaged) _nativedBuffer = (NB) buffer; else _managedBuffer = (MB) buffer; - - _count = count; + + _count = count; } public uint count => _count; @@ -26,7 +27,8 @@ namespace Svelto.ECS readonly uint _count; } - public readonly ref struct EntityCollection where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent + public readonly ref struct EntityCollection + where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent { internal EntityCollection(in EntityCollection array1, in EntityCollection array2) { @@ -89,14 +91,14 @@ namespace Svelto.ECS readonly EntityCollection _array3; } - public readonly ref struct EntityCollection - where T1 : struct, IEntityComponent - where T2 : struct, IEntityComponent - where T3 : struct, IEntityComponent - where T4 : struct, IEntityComponent + public readonly ref struct EntityCollection where T1 : struct, IEntityComponent + where T2 : struct, IEntityComponent + where T3 : struct, IEntityComponent + where T4 : struct, IEntityComponent { internal EntityCollection - (in EntityCollection array1, in EntityCollection array2, in EntityCollection array3, in EntityCollection array4) + (in EntityCollection array1, in EntityCollection array2, in EntityCollection array3 + , in EntityCollection array4) { _array1 = array1; _array2 = array2; @@ -104,25 +106,25 @@ namespace Svelto.ECS _array4 = array4; } - internal EntityCollection Item1 + internal EntityCollection buffer1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _array1; } - internal EntityCollection Item2 + internal EntityCollection buffer2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _array2; } - internal EntityCollection Item3 + internal EntityCollection buffer3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _array3; } - - internal EntityCollection Item4 + + internal EntityCollection buffer4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _array4; @@ -142,7 +144,7 @@ namespace Svelto.ECS public readonly BufferT2 buffer2; public readonly BufferT3 buffer3; public readonly BufferT4 buffer4; - public readonly int count; + public readonly int count; public BT(BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, BufferT4 bufferT4, uint count) : this() { @@ -159,7 +161,7 @@ namespace Svelto.ECS public readonly BufferT1 buffer1; public readonly BufferT2 buffer2; public readonly BufferT3 buffer3; - public readonly int count; + public readonly int count; public BT(BufferT1 bufferT1, BufferT2 bufferT2, BufferT3 bufferT3, uint count) : this() { @@ -174,27 +176,27 @@ namespace Svelto.ECS bufferT1 = buffer1; bufferT2 = buffer2; bufferT3 = buffer3; - count = this.count; + count = this.count; } } public readonly struct BT { public readonly BufferT1 buffer; - public readonly int count; + public readonly int count; public BT(BufferT1 bufferT1, uint count) : this() { this.buffer = bufferT1; this.count = (int) count; } - + public void Deconstruct(out BufferT1 bufferT1, out int count) { bufferT1 = buffer; count = this.count; } - + public static implicit operator BufferT1(BT t) => t.buffer; } @@ -202,7 +204,7 @@ namespace Svelto.ECS { public readonly BufferT1 buffer1; public readonly BufferT2 buffer2; - public readonly int count; + public readonly int count; public BT(BufferT1 bufferT1, BufferT2 bufferT2, uint count) : this() { @@ -210,7 +212,7 @@ namespace Svelto.ECS this.buffer2 = bufferT2; this.count = (int) count; } - + public void Deconstruct(out BufferT1 bufferT1, out BufferT2 bufferT2, out int count) { bufferT1 = buffer1; @@ -218,4 +220,4 @@ namespace Svelto.ECS count = this.count; } } -} +} \ No newline at end of file diff --git a/Svelto.ECS/DynamicEntityDescriptor.cs b/Svelto.ECS/Core/EntityDescriptor/DynamicEntityDescriptor.cs similarity index 100% rename from Svelto.ECS/DynamicEntityDescriptor.cs rename to Svelto.ECS/Core/EntityDescriptor/DynamicEntityDescriptor.cs diff --git a/Svelto.ECS/ExtendibleEntityDescriptor.cs b/Svelto.ECS/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs similarity index 77% rename from Svelto.ECS/ExtendibleEntityDescriptor.cs rename to Svelto.ECS/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs index 384823c..6e479f8 100644 --- a/Svelto.ECS/ExtendibleEntityDescriptor.cs +++ b/Svelto.ECS/Core/EntityDescriptor/ExtendibleEntityDescriptor.cs @@ -6,6 +6,19 @@ namespace Svelto.ECS /// /// Inherit from an ExtendibleEntityDescriptor to extend a base entity descriptor that can be used /// to swap and remove specialized entities from abstract engines + /// + /// Usage Example: + /// + /// class SpecialisedDescriptor : ExtendibleEntityDescriptor + /// { + /// public SpecialisedDescriptor() : base (new IComponentBuilder[] + /// { + /// new ComponentBuilder() //add more components to the base descriptor + /// }) + /// { + /// ExtendWith(); //add extra components from descriptors that act as contract + /// } + /// } /// /// public class ExtendibleEntityDescriptor : IDynamicEntityDescriptor where TType : IEntityDescriptor, new() diff --git a/Svelto.ECS/GenericEntityDescriptor.cs b/Svelto.ECS/Core/EntityDescriptor/GenericEntityDescriptor.cs similarity index 100% rename from Svelto.ECS/GenericEntityDescriptor.cs rename to Svelto.ECS/Core/EntityDescriptor/GenericEntityDescriptor.cs diff --git a/Svelto.ECS/Core/EntityDescriptor/IDynamicEntityDescriptor.cs b/Svelto.ECS/Core/EntityDescriptor/IDynamicEntityDescriptor.cs new file mode 100644 index 0000000..f7889de --- /dev/null +++ b/Svelto.ECS/Core/EntityDescriptor/IDynamicEntityDescriptor.cs @@ -0,0 +1,6 @@ +namespace Svelto.ECS +{ + public interface IDynamicEntityDescriptor: IEntityDescriptor + { + } +} \ No newline at end of file diff --git a/Svelto.ECS/Core/EntityDescriptor/IEntityDescriptor.cs b/Svelto.ECS/Core/EntityDescriptor/IEntityDescriptor.cs new file mode 100644 index 0000000..45674f2 --- /dev/null +++ b/Svelto.ECS/Core/EntityDescriptor/IEntityDescriptor.cs @@ -0,0 +1,7 @@ +namespace Svelto.ECS +{ + public interface IEntityDescriptor + { + IComponentBuilder[] componentsToBuild { get; } + } +} \ No newline at end of file diff --git a/Svelto.ECS/EntityDescriptorTemplate.cs b/Svelto.ECS/Core/EntityDescriptorTemplate.cs similarity index 72% rename from Svelto.ECS/EntityDescriptorTemplate.cs rename to Svelto.ECS/Core/EntityDescriptorTemplate.cs index d32b16b..e7b1525 100644 --- a/Svelto.ECS/EntityDescriptorTemplate.cs +++ b/Svelto.ECS/Core/EntityDescriptorTemplate.cs @@ -2,15 +2,6 @@ using System; namespace Svelto.ECS { - public interface IEntityDescriptor - { - IComponentBuilder[] componentsToBuild { get; } - } - - public interface IDynamicEntityDescriptor: IEntityDescriptor - { - } - static class EntityDescriptorTemplate where TType : IEntityDescriptor, new() { static EntityDescriptorTemplate() diff --git a/Svelto.ECS/EntityFactory.cs b/Svelto.ECS/Core/EntityFactory.cs similarity index 100% rename from Svelto.ECS/EntityFactory.cs rename to Svelto.ECS/Core/EntityFactory.cs diff --git a/Svelto.ECS/EntityGroupNotFoundException.cs b/Svelto.ECS/Core/EntityGroupNotFoundException.cs similarity index 100% rename from Svelto.ECS/EntityGroupNotFoundException.cs rename to Svelto.ECS/Core/EntityGroupNotFoundException.cs diff --git a/Svelto.ECS/EntityInfoView.cs b/Svelto.ECS/Core/EntityInfoView.cs similarity index 100% rename from Svelto.ECS/EntityInfoView.cs rename to Svelto.ECS/Core/EntityInfoView.cs diff --git a/Svelto.ECS/EntityComponentInitializer.cs b/Svelto.ECS/Core/EntityInitializer.cs similarity index 90% rename from Svelto.ECS/EntityComponentInitializer.cs rename to Svelto.ECS/Core/EntityInitializer.cs index 72cbad2..dd2b2e3 100644 --- a/Svelto.ECS/EntityComponentInitializer.cs +++ b/Svelto.ECS/Core/EntityInitializer.cs @@ -1,12 +1,11 @@ -using System; -using Svelto.DataStructures; +using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { - public readonly ref struct EntityComponentInitializer + public readonly ref struct EntityInitializer { - public EntityComponentInitializer(EGID id, FasterDictionary group) + public EntityInitializer(EGID id, FasterDictionary group) { _group = group; _ID = id; diff --git a/Svelto.ECS/EntityNotFoundException.cs b/Svelto.ECS/Core/EntityNotFoundException.cs similarity index 100% rename from Svelto.ECS/EntityNotFoundException.cs rename to Svelto.ECS/Core/EntityNotFoundException.cs diff --git a/Svelto.ECS/Core/EntitySubmissionScheduler.cs b/Svelto.ECS/Core/EntitySubmissionScheduler.cs new file mode 100644 index 0000000..ac24d91 --- /dev/null +++ b/Svelto.ECS/Core/EntitySubmissionScheduler.cs @@ -0,0 +1,16 @@ +using System.Collections; + +namespace Svelto.ECS.Schedulers +{ + public abstract class EntitiesSubmissionScheduler + { + protected internal abstract EnginesRoot.EntitiesSubmitter onTick { set; } + + public abstract void Dispose(); + + public abstract bool paused { get; set; } + public uint iteration { get; protected internal set; } + + internal bool isRunning; + } +} \ No newline at end of file diff --git a/Svelto.ECS/EntitySubmitOperation.cs b/Svelto.ECS/Core/EntitySubmitOperation.cs similarity index 100% rename from Svelto.ECS/EntitySubmitOperation.cs rename to Svelto.ECS/Core/EntitySubmitOperation.cs diff --git a/Svelto.ECS/EntityViewUtility.cs b/Svelto.ECS/Core/EntityViewUtility.cs similarity index 100% rename from Svelto.ECS/EntityViewUtility.cs rename to Svelto.ECS/Core/EntityViewUtility.cs diff --git a/Svelto.ECS/Filters/EntitiesDB.GroupFilters.cs b/Svelto.ECS/Core/Filters/EntitiesDB.GroupFilters.cs similarity index 99% rename from Svelto.ECS/Filters/EntitiesDB.GroupFilters.cs rename to Svelto.ECS/Core/Filters/EntitiesDB.GroupFilters.cs index 77e5684..af599d9 100644 --- a/Svelto.ECS/Filters/EntitiesDB.GroupFilters.cs +++ b/Svelto.ECS/Core/Filters/EntitiesDB.GroupFilters.cs @@ -1,4 +1,3 @@ -using System; using Svelto.DataStructures; namespace Svelto.ECS @@ -99,7 +98,7 @@ namespace Svelto.ECS #endif return ref _filters[TypeRefWrapper.wrapper][groupID].GetFilter(filterId); } - + public bool TryGetFilterForGroup(int filterId, ExclusiveGroupStruct groupID, out FilterGroup groupFilter) where T : struct, IEntityComponent { diff --git a/Svelto.ECS/Filters/FilterGroup.cs b/Svelto.ECS/Core/Filters/FilterGroup.cs similarity index 100% rename from Svelto.ECS/Filters/FilterGroup.cs rename to Svelto.ECS/Core/Filters/FilterGroup.cs diff --git a/Svelto.ECS/Filters/FilteredIndices.cs b/Svelto.ECS/Core/Filters/FilteredIndices.cs similarity index 53% rename from Svelto.ECS/Filters/FilteredIndices.cs rename to Svelto.ECS/Core/Filters/FilteredIndices.cs index 47697cd..799a8f6 100644 --- a/Svelto.ECS/Filters/FilteredIndices.cs +++ b/Svelto.ECS/Core/Filters/FilteredIndices.cs @@ -8,14 +8,28 @@ namespace Svelto.ECS public FilteredIndices(NativeDynamicArrayCast denseListOfIndicesToEntityComponentArray) { _denseListOfIndicesToEntityComponentArray = denseListOfIndicesToEntityComponentArray; + _count = _denseListOfIndicesToEntityComponentArray.count; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Count() => _denseListOfIndicesToEntityComponentArray.Count(); + public int Count() => _count; [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint Get(uint index) => _denseListOfIndicesToEntityComponentArray[index]; + public uint this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _denseListOfIndicesToEntityComponentArray[index]; + } + + public uint this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _denseListOfIndicesToEntityComponentArray[index]; + } + readonly NativeDynamicArrayCast _denseListOfIndicesToEntityComponentArray; + readonly int _count; } } \ No newline at end of file diff --git a/Svelto.ECS/Filters/GroupFilters.cs b/Svelto.ECS/Core/Filters/GroupFilters.cs similarity index 98% rename from Svelto.ECS/Filters/GroupFilters.cs rename to Svelto.ECS/Core/Filters/GroupFilters.cs index 4226a23..99004d8 100644 --- a/Svelto.ECS/Filters/GroupFilters.cs +++ b/Svelto.ECS/Core/Filters/GroupFilters.cs @@ -40,7 +40,7 @@ namespace Svelto.ECS return filters.TryGetValue(filterIndex, out filter); } - public SveltoDictionary>, NativeStrategy + public SveltoDictionary>, NativeStrategy , NativeStrategy>.SveltoDictionaryKeyValueEnumerator GetEnumerator() { return filters.GetEnumerator(); diff --git a/Svelto.ECS/GlobalTypeID.cs b/Svelto.ECS/Core/GlobalTypeID.cs similarity index 90% rename from Svelto.ECS/GlobalTypeID.cs rename to Svelto.ECS/Core/GlobalTypeID.cs index 78a12c6..8e4cc18 100644 --- a/Svelto.ECS/GlobalTypeID.cs +++ b/Svelto.ECS/Core/GlobalTypeID.cs @@ -16,7 +16,7 @@ namespace Svelto.ECS interface IFiller { - void FillFromByteArray(EntityComponentInitializer init, NativeBag buffer); + void FillFromByteArray(EntityInitializer init, NativeBag buffer); } class Filler : IFiller where T : struct, IEntityComponent @@ -27,7 +27,7 @@ namespace Svelto.ECS } //it's an internal interface - public void FillFromByteArray(EntityComponentInitializer init, NativeBag buffer) + public void FillFromByteArray(EntityInitializer init, NativeBag buffer) { var component = buffer.Dequeue(); diff --git a/Svelto.ECS/Core/Groups/ExclusiveBuildGroup.cs b/Svelto.ECS/Core/Groups/ExclusiveBuildGroup.cs new file mode 100644 index 0000000..87aca8b --- /dev/null +++ b/Svelto.ECS/Core/Groups/ExclusiveBuildGroup.cs @@ -0,0 +1,27 @@ +namespace Svelto.ECS +{ + public readonly struct ExclusiveBuildGroup + { + internal ExclusiveBuildGroup(ExclusiveGroupStruct group) + { + this.group = group; + } + + public static implicit operator ExclusiveBuildGroup(ExclusiveGroupStruct group) + { + return new ExclusiveBuildGroup(group); + } + + public static implicit operator ExclusiveBuildGroup(ExclusiveGroup group) + { + return new ExclusiveBuildGroup(group); + } + + public static implicit operator uint(ExclusiveBuildGroup groupStruct) + { + return groupStruct.group; + } + + internal ExclusiveGroupStruct @group { get; } + } +} \ No newline at end of file diff --git a/Svelto.ECS/ExclusiveGroup.cs b/Svelto.ECS/Core/Groups/ExclusiveGroup.cs similarity index 99% rename from Svelto.ECS/ExclusiveGroup.cs rename to Svelto.ECS/Core/Groups/ExclusiveGroup.cs index b4fdac3..6f691fa 100644 --- a/Svelto.ECS/ExclusiveGroup.cs +++ b/Svelto.ECS/Core/Groups/ExclusiveGroup.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; #pragma warning disable 660,661 diff --git a/Svelto.ECS/ExclusiveGroupStruct.cs b/Svelto.ECS/Core/Groups/ExclusiveGroupStruct.cs similarity index 84% rename from Svelto.ECS/ExclusiveGroupStruct.cs rename to Svelto.ECS/Core/Groups/ExclusiveGroupStruct.cs index 8bb0a9c..30d25e5 100644 --- a/Svelto.ECS/ExclusiveGroupStruct.cs +++ b/Svelto.ECS/Core/Groups/ExclusiveGroupStruct.cs @@ -4,31 +4,6 @@ using System.Runtime.InteropServices; namespace Svelto.ECS { - public readonly struct BuildGroup - { - internal BuildGroup(ExclusiveGroupStruct group) - { - this.group = group; - } - - public static implicit operator BuildGroup(ExclusiveGroupStruct group) - { - return new BuildGroup(group); - } - - public static implicit operator BuildGroup(ExclusiveGroup group) - { - return new BuildGroup(group); - } - - public static implicit operator uint(BuildGroup groupStruct) - { - return groupStruct.group; - } - - internal ExclusiveGroupStruct @group { get; } - } - [StructLayout(LayoutKind.Explicit, Size = 4)] public struct ExclusiveGroupStruct : IEquatable, IComparable, IEqualityComparer diff --git a/Svelto.ECS/GroupCompound.cs b/Svelto.ECS/Core/Groups/GroupCompound.cs similarity index 96% rename from Svelto.ECS/GroupCompound.cs rename to Svelto.ECS/Core/Groups/GroupCompound.cs index 53badc1..25be5bd 100644 --- a/Svelto.ECS/GroupCompound.cs +++ b/Svelto.ECS/Core/Groups/GroupCompound.cs @@ -20,7 +20,7 @@ namespace Svelto.ECS static readonly FasterList _Groups; public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); - public static BuildGroup BuildGroup => new BuildGroup(_Groups[0]); + public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static GroupCompound() { @@ -100,7 +100,7 @@ namespace Svelto.ECS public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); - public static BuildGroup BuildGroup => new BuildGroup(_Groups[0]); + public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static void Add(ExclusiveGroupStruct group) { @@ -152,7 +152,7 @@ namespace Svelto.ECS public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); - public static BuildGroup BuildGroup => new BuildGroup(_Groups[0]); + public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); public static void Add(ExclusiveGroupStruct group) { @@ -200,7 +200,7 @@ namespace Svelto.ECS public static FasterReadOnlyList Groups => new FasterReadOnlyList(_Groups); - public static BuildGroup BuildGroup => new BuildGroup(_Groups[0]); + public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); static GroupTag() { diff --git a/Svelto.ECS/NamedExclusiveGroup.cs b/Svelto.ECS/Core/Groups/NamedExclusiveGroup.cs similarity index 100% rename from Svelto.ECS/NamedExclusiveGroup.cs rename to Svelto.ECS/Core/Groups/NamedExclusiveGroup.cs diff --git a/Svelto.ECS/IEntityDescriptorHolder.cs b/Svelto.ECS/Core/Hybrid/IEntityDescriptorHolder.cs similarity index 100% rename from Svelto.ECS/IEntityDescriptorHolder.cs rename to Svelto.ECS/Core/Hybrid/IEntityDescriptorHolder.cs diff --git a/Svelto.ECS/Hybrid/IEntityViewComponent.cs b/Svelto.ECS/Core/Hybrid/IEntityViewComponent.cs similarity index 100% rename from Svelto.ECS/Hybrid/IEntityViewComponent.cs rename to Svelto.ECS/Core/Hybrid/IEntityViewComponent.cs diff --git a/Svelto.ECS/Hybrid/IImplementor.cs b/Svelto.ECS/Core/Hybrid/IImplementor.cs similarity index 100% rename from Svelto.ECS/Hybrid/IImplementor.cs rename to Svelto.ECS/Core/Hybrid/IImplementor.cs diff --git a/Svelto.ECS/Core/Hybrid/ValueReference.cs b/Svelto.ECS/Core/Hybrid/ValueReference.cs new file mode 100644 index 0000000..0a4c802 --- /dev/null +++ b/Svelto.ECS/Core/Hybrid/ValueReference.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +namespace Svelto.ECS.Hybrid +{ + public struct ValueReference where T:class, IImplementor + { + public ValueReference(T obj) { _pointer = GCHandle.Alloc(obj, GCHandleType.Normal); } + + public static explicit operator T(ValueReference t) => (T) t._pointer.Target; + + GCHandle _pointer; + } +} \ No newline at end of file diff --git a/Svelto.ECS/IComponentBuilder.cs b/Svelto.ECS/Core/IComponentBuilder.cs similarity index 100% rename from Svelto.ECS/IComponentBuilder.cs rename to Svelto.ECS/Core/IComponentBuilder.cs diff --git a/Svelto.ECS/IDisposingEngine.cs b/Svelto.ECS/Core/IDisposingEngine.cs similarity index 100% rename from Svelto.ECS/IDisposingEngine.cs rename to Svelto.ECS/Core/IDisposingEngine.cs diff --git a/Svelto.ECS/IEngine.cs b/Svelto.ECS/Core/IEngine.cs similarity index 78% rename from Svelto.ECS/IEngine.cs rename to Svelto.ECS/Core/IEngine.cs index 5c5c8e9..ec87289 100644 --- a/Svelto.ECS/IEngine.cs +++ b/Svelto.ECS/Core/IEngine.cs @@ -7,6 +7,9 @@ namespace Svelto.ECS.Internal public interface IReactOnAddAndRemove : IReactEngine {} + + public interface IReactOnDispose : IReactEngine + {} public interface IReactOnSwap : IReactEngine {} @@ -23,6 +26,11 @@ namespace Svelto.ECS void Remove(ref T entityComponent, EGID egid); } + public interface IReactOnDispose : IReactOnDispose where T : IEntityComponent + { + void Remove(ref T entityComponent, EGID egid); + } + public interface IReactOnSwap : IReactOnSwap where T : IEntityComponent { void MovedTo(ref T entityComponent, ExclusiveGroupStruct previousGroup, EGID egid); diff --git a/Svelto.ECS/Core/IEntityComponent.cs b/Svelto.ECS/Core/IEntityComponent.cs new file mode 100644 index 0000000..cf4d06c --- /dev/null +++ b/Svelto.ECS/Core/IEntityComponent.cs @@ -0,0 +1,7 @@ +namespace Svelto.ECS +{ + ///Entity Components MUST implement IEntityComponent + public interface IEntityComponent + { + } +} \ No newline at end of file diff --git a/Svelto.ECS/IEntityFactory.cs b/Svelto.ECS/Core/IEntityFactory.cs similarity index 83% rename from Svelto.ECS/IEntityFactory.cs rename to Svelto.ECS/Core/IEntityFactory.cs index 6220c2b..0a7c180 100644 --- a/Svelto.ECS/IEntityFactory.cs +++ b/Svelto.ECS/Core/IEntityFactory.cs @@ -43,25 +43,25 @@ namespace Svelto.ECS /// /// /// - EntityComponentInitializer BuildEntity(uint entityID, BuildGroup groupStructId, + EntityInitializer BuildEntity(uint entityID, ExclusiveBuildGroup groupStructId, IEnumerable implementors = null) where T : IEntityDescriptor, new(); - EntityComponentInitializer BuildEntity(EGID egid, IEnumerable implementors = null) + EntityInitializer BuildEntity(EGID egid, IEnumerable implementors = null) where T : IEntityDescriptor, new(); - EntityComponentInitializer BuildEntity(uint entityID, BuildGroup groupStructId, + EntityInitializer BuildEntity(uint entityID, ExclusiveBuildGroup groupStructId, T descriptorEntity, IEnumerable implementors = null) where T : IEntityDescriptor; - EntityComponentInitializer BuildEntity(EGID egid, T entityDescriptor, IEnumerable implementors = null) + EntityInitializer BuildEntity(EGID egid, T entityDescriptor, IEnumerable implementors = null) where T : IEntityDescriptor; - EntityComponentInitializer BuildEntity + EntityInitializer BuildEntity (EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable implementors = null); #if UNITY_NATIVE - NativeEntityFactory ToNative(string memberName) where T : IEntityDescriptor, new(); + NativeEntityFactory ToNative(string callerName) where T : IEntityDescriptor, new(); #endif } } \ No newline at end of file diff --git a/Svelto.ECS/Core/IEntityFunctions.cs b/Svelto.ECS/Core/IEntityFunctions.cs new file mode 100644 index 0000000..1dd15bc --- /dev/null +++ b/Svelto.ECS/Core/IEntityFunctions.cs @@ -0,0 +1,34 @@ +using System.Runtime.CompilerServices; + +namespace Svelto.ECS +{ + public interface IEntityFunctions + { + //being entity ID globally not unique, the group must be specified when + //an entity is removed. Not specifying the group will attempt to remove + //the entity from the special standard group. + void RemoveEntity(uint entityID, ExclusiveBuildGroup groupID, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new(); + void RemoveEntity(EGID entityegid, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new(); + + void RemoveEntitiesFromGroup(ExclusiveBuildGroup groupID); + + void SwapEntitiesInGroup(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new(); + + void SwapEntityGroup(uint entityID, ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID) + where T : IEntityDescriptor, new(); + + void SwapEntityGroup(EGID fromID, ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new(); + + void SwapEntityGroup(EGID fromID, ExclusiveBuildGroup toGroupID, ExclusiveBuildGroup mustBeFromGroup) + where T : IEntityDescriptor, new(); + + void SwapEntityGroup(EGID fromID, EGID toId) where T : IEntityDescriptor, new(); + + void SwapEntityGroup(EGID fromID, EGID toId, ExclusiveBuildGroup mustBeFromGroup) + where T : IEntityDescriptor, new(); +#if UNITY_NATIVE + NativeEntityRemove ToNativeRemove(string memberName) where T : IEntityDescriptor, new(); + NativeEntitySwap ToNativeSwap(string memberName) where T : IEntityDescriptor, new(); +#endif + } +} \ No newline at end of file diff --git a/Svelto.ECS/IEntityComponent.cs b/Svelto.ECS/Core/INeedEGID.cs similarity index 71% rename from Svelto.ECS/IEntityComponent.cs rename to Svelto.ECS/Core/INeedEGID.cs index d5269f7..1812438 100644 --- a/Svelto.ECS/IEntityComponent.cs +++ b/Svelto.ECS/Core/INeedEGID.cs @@ -1,10 +1,5 @@ namespace Svelto.ECS { - ///Entity Components MUST implement IEntityComponent - public interface IEntityComponent - { - } - /// /// use INeedEGID on an IEntityComponent only if you need the EGID. consider using EGIDComponent instead /// diff --git a/Svelto.ECS/IQueryingEntitiesEngine.cs b/Svelto.ECS/Core/IQueryingEntitiesEngine.cs similarity index 100% rename from Svelto.ECS/IQueryingEntitiesEngine.cs rename to Svelto.ECS/Core/IQueryingEntitiesEngine.cs diff --git a/Svelto.ECS/QueryGroups.cs b/Svelto.ECS/Core/QueryGroups.cs similarity index 100% rename from Svelto.ECS/QueryGroups.cs rename to Svelto.ECS/Core/QueryGroups.cs diff --git a/Svelto.ECS/SetEGIDWithoutBoxing.cs b/Svelto.ECS/Core/SetEGIDWithoutBoxing.cs similarity index 96% rename from Svelto.ECS/SetEGIDWithoutBoxing.cs rename to Svelto.ECS/Core/SetEGIDWithoutBoxing.cs index bc81645..d5af6e1 100644 --- a/Svelto.ECS/SetEGIDWithoutBoxing.cs +++ b/Svelto.ECS/Core/SetEGIDWithoutBoxing.cs @@ -1,5 +1,3 @@ -using System.Runtime.CompilerServices; - namespace Svelto.ECS.Internal { delegate void SetEGIDWithoutBoxingActionCast(ref T target, EGID egid) where T : struct, IEntityComponent; diff --git a/Svelto.ECS/Core/SimpleEntitiesSubmissionScheduler.cs b/Svelto.ECS/Core/SimpleEntitiesSubmissionScheduler.cs new file mode 100644 index 0000000..d1c27bd --- /dev/null +++ b/Svelto.ECS/Core/SimpleEntitiesSubmissionScheduler.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections; + +namespace Svelto.ECS.Schedulers +{ + public sealed class SimpleEntitiesSubmissionScheduler : EntitiesSubmissionScheduler + { + public SimpleEntitiesSubmissionScheduler(uint maxNumberOfOperationsPerFrame = UInt32.MaxValue) + { + _maxNumberOfOperationsPerFrame = maxNumberOfOperationsPerFrame; + } + + public IEnumerator SubmitEntitiesAsync() + { + if (paused == false) + { + var submitEntities = _onTick.Invoke(_maxNumberOfOperationsPerFrame); + + while (submitEntities.MoveNext()) + yield return null; + } + } + + public void SubmitEntities() + { + var enumerator = SubmitEntitiesAsync(); + + while (enumerator.MoveNext()); + } + + public override bool paused { get; set; } + public override void Dispose() { } + + protected internal override EnginesRoot.EntitiesSubmitter onTick + { + set + { + DBC.ECS.Check.Require(_onTick.IsUnused, "a scheduler can be exclusively used by one enginesRoot only"); + + _onTick = value; + } + } + + EnginesRoot.EntitiesSubmitter _onTick; + readonly uint _maxNumberOfOperationsPerFrame; + } +} \ No newline at end of file diff --git a/Svelto.ECS/Core/SpecialEnumerators/DoubleIterationEnumerator.cs b/Svelto.ECS/Core/SpecialEnumerators/DoubleIterationEnumerator.cs new file mode 100644 index 0000000..18afdab --- /dev/null +++ b/Svelto.ECS/Core/SpecialEnumerators/DoubleIterationEnumerator.cs @@ -0,0 +1,546 @@ +using System; + +namespace Svelto.ECS +{ + public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, IEntityComponent + { + public DoubleEntitiesEnumerator(GroupsEnumerable groupsEnumerable) { _groupsEnumerable = groupsEnumerable; } + + public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } + + readonly GroupsEnumerable _groupsEnumerable; + + public ref struct EntityGroupsIterator + { + public EntityGroupsIterator(GroupsEnumerable groupsEnumerable) : this() + { + _groupsEnumerableA = groupsEnumerable.GetEnumerator(); + _groupsEnumerableA.MoveNext(); + _groupsEnumerableB = _groupsEnumerableA; + _indexA = 0; + _indexB = 0; + } + + public bool MoveNext() + { + //once GroupEnumerables complete, they reset. If they reset and moveNext doesn't happen, they are invalid + while (_groupsEnumerableA.isValid) + { + var (buffersA, _) = _groupsEnumerableA.Current; + var (buffersB, _) = _groupsEnumerableB.Current; + + //current index A must iterate as long as is less than the current A group count + while (_indexA < buffersA.count) + { + //current index B must iterate as long as is less than the current B group count + if (++_indexB < buffersB.count) + { + return true; + } + + //if B iteration is over, move to the next group + if (_groupsEnumerableB.MoveNext() == false) + { + //if there is no valid next groups, we reset B and we need to move to the next A element + _groupsEnumerableB = _groupsEnumerableA; + (buffersB, _) = _groupsEnumerableB.Current; + ++_indexA; //next A element + _indexB = _indexA; + } + else + //otherwise the current A will be checked against the new B group. IndexB must be reset + //to work on the new group + { + _indexB = -1; + } + } + + //the current group A iteration is done, so we move to the next A group + if (_groupsEnumerableA.MoveNext() == true) + { + //there is a new group, we reset the iteration + _indexA = 0; + _indexB = 0; + _groupsEnumerableB = _groupsEnumerableA; + } + else + return false; + } + + return false; + } + + public void Reset() { throw new Exception(); } + + public ValueRef Current + { + get + { + var valueRef = new ValueRef(_groupsEnumerableA.Current, _indexA, _groupsEnumerableB.Current + , _indexB); + return valueRef; + } + } + + public void Dispose() { } + + GroupsEnumerable.GroupsIterator _groupsEnumerableA; + GroupsEnumerable.GroupsIterator _groupsEnumerableB; + int _indexA; + int _indexB; + } + + public ref struct ValueRef + { + public readonly GroupsEnumerable.RefCurrent _current; + public readonly int _indexA; + public readonly GroupsEnumerable.RefCurrent _refCurrent; + public readonly int _indexB; + + public ValueRef + (GroupsEnumerable.RefCurrent current, int indexA, GroupsEnumerable.RefCurrent refCurrent + , int indexB) + { + _current = current; + _indexA = indexA; + _refCurrent = refCurrent; + _indexB = indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out EntityCollection refCurrent, out int indexB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out ExclusiveGroupStruct groupA + , out EntityCollection refCurrent, out int indexB, out ExclusiveGroupStruct groupB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + groupA = _current._group; + groupB = _refCurrent._group; + } + } + } + + public readonly ref struct DoubleIterationEnumerator where T1 : struct, IEntityComponent + where T2 : struct, IEntityComponent + { + public DoubleIterationEnumerator(GroupsEnumerable groupsEnumerable) + { + _groupsEnumerable = groupsEnumerable; + } + + public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } + + readonly GroupsEnumerable _groupsEnumerable; + + public ref struct EntityGroupsIterator + { + public EntityGroupsIterator(GroupsEnumerable groupsEnumerable) : this() + { + _groupsEnumerableA = groupsEnumerable.GetEnumerator(); + _groupsEnumerableA.MoveNext(); + _groupsEnumerableB = _groupsEnumerableA; + _indexA = 0; + _indexB = 0; + } + + public bool MoveNext() + { + //once GroupEnumerables complete, they reset. If they reset and moveNext doesn't happen, they are invalid + while (_groupsEnumerableA.isValid) + { + var (buffersA, _) = _groupsEnumerableA.Current; + var (buffersB, _) = _groupsEnumerableB.Current; + + //current index A must iterate as long as is less than the current A group count + while (_indexA < buffersA.count) + { + //current index B must iterate as long as is less than the current B group count + if (++_indexB < buffersB.count) + { + return true; + } + + //if B iteration is over, move to the next group + if (_groupsEnumerableB.MoveNext() == false) + { + //if there is no valid next groups, we reset B and we need to move to the next A element + _groupsEnumerableB = _groupsEnumerableA; + (buffersB, _) = _groupsEnumerableB.Current; + ++_indexA; //next A element + _indexB = _indexA; + } + else + //otherwise the current A will be checked against the new B group. IndexB must be reset + //to work on the new group + { + _indexB = -1; + } + } + + //the current group A iteration is done, so we move to the next A group + if (_groupsEnumerableA.MoveNext() == true) + { + //there is a new group, we reset the iteration + _indexA = 0; + _indexB = 0; + _groupsEnumerableB = _groupsEnumerableA; + } + else + return false; + } + + return false; + } + + public void Reset() { throw new Exception(); } + + public ValueRef Current + { + get + { + var valueRef = new ValueRef(_groupsEnumerableA.Current, _indexA, _groupsEnumerableB.Current + , _indexB); + return valueRef; + } + } + + public void Dispose() { } + + GroupsEnumerable.GroupsIterator _groupsEnumerableA; + GroupsEnumerable.GroupsIterator _groupsEnumerableB; + int _indexA; + int _indexB; + } + + public ref struct ValueRef + { + public readonly GroupsEnumerable.RefCurrent _current; + public readonly int _indexA; + public readonly GroupsEnumerable.RefCurrent _refCurrent; + public readonly int _indexB; + + public ValueRef + (GroupsEnumerable.RefCurrent current, int indexA, GroupsEnumerable.RefCurrent refCurrent + , int indexB) + { + _current = current; + _indexA = indexA; + _refCurrent = refCurrent; + _indexB = indexB; + } + + public void Deconstruct(out EntityCollection buffers, out int indexA, + out EntityCollection refCurrent, out int indexB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out ExclusiveGroupStruct groupA + , out EntityCollection refCurrent, out int indexB, out ExclusiveGroupStruct groupB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + groupA = _current._group; + groupB = _refCurrent._group; + } + } + } + + /// + /// Special Enumerator to iterate a group of entities against themselves with complexity n*(n+1)/2 (skips already tested couples) + /// + /// + /// + /// + public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, IEntityComponent + where T2 : struct, IEntityComponent + where T3 : struct, IEntityComponent + { + public DoubleEntitiesEnumerator(GroupsEnumerable groupsEnumerable) + { + _groupsEnumerable = groupsEnumerable; + } + + public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } + + readonly GroupsEnumerable _groupsEnumerable; + + public ref struct EntityGroupsIterator + { + public EntityGroupsIterator(GroupsEnumerable groupsEnumerable) : this() + { + _groupsEnumerableA = groupsEnumerable.GetEnumerator(); + _groupsEnumerableA.MoveNext(); + _groupsEnumerableB = _groupsEnumerableA; + _indexA = 0; + _indexB = 0; + } + + public bool MoveNext() + { + //once GroupEnumerables complete, they reset. If they reset and moveNext doesn't happen, they are invalid + while (_groupsEnumerableA.isValid) + { + var (buffersA, _) = _groupsEnumerableA.Current; + var (buffersB, _) = _groupsEnumerableB.Current; + + //current index A must iterate as long as is less than the current A group count + while (_indexA < buffersA.count) + { + //current index B must iterate as long as is less than the current B group count + if (++_indexB < buffersB.count) + { + return true; + } + + //if B iteration is over, move to the next group + if (_groupsEnumerableB.MoveNext() == false) + { + //if there is no valid next groups, we reset B and we need to move to the next A element + _groupsEnumerableB = _groupsEnumerableA; + (buffersB, _) = _groupsEnumerableB.Current; + ++_indexA; //next A element + _indexB = _indexA; + } + else + //otherwise the current A will be checked against the new B group. IndexB must be reset + //to work on the new group + { + _indexB = -1; + } + } + + //the current group A iteration is done, so we move to the next A group + if (_groupsEnumerableA.MoveNext() == true) + { + //there is a new group, we reset the iteration + _indexA = 0; + _indexB = 0; + _groupsEnumerableB = _groupsEnumerableA; + } + else + return false; + } + + return false; + } + + public void Reset() { throw new Exception(); } + + public ValueRef Current + { + get + { + var valueRef = new ValueRef(_groupsEnumerableA.Current, _indexA, _groupsEnumerableB.Current + , _indexB); + return valueRef; + } + } + + public void Dispose() { } + + GroupsEnumerable.GroupsIterator _groupsEnumerableA; + GroupsEnumerable.GroupsIterator _groupsEnumerableB; + int _indexA; + int _indexB; + } + + public ref struct ValueRef + { + public readonly GroupsEnumerable.RefCurrent _current; + public readonly int _indexA; + public readonly GroupsEnumerable.RefCurrent _refCurrent; + public readonly int _indexB; + + public ValueRef + (GroupsEnumerable.RefCurrent current, int indexA + , GroupsEnumerable.RefCurrent refCurrent, int indexB) + { + _current = current; + _indexA = indexA; + _refCurrent = refCurrent; + _indexB = indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out EntityCollection refCurrent + , out int indexB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out ExclusiveGroupStruct groupA + , out EntityCollection refCurrent, out int indexB, out ExclusiveGroupStruct groupB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + groupA = _current._group; + groupB = _refCurrent._group; + } + } + } + + /// + /// Special Enumerator to iterate a group of entities against themselves with complexity n*(n+1)/2 (skips already tested couples) + /// + /// + /// + /// + /// + public readonly ref struct DoubleEntitiesEnumerator where T1 : struct, IEntityComponent + where T2 : struct, IEntityComponent + where T3 : struct, IEntityComponent + where T4 : struct, IEntityComponent + { + public DoubleEntitiesEnumerator(GroupsEnumerable groupsEnumerable) + { + _groupsEnumerable = groupsEnumerable; + } + + public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } + + readonly GroupsEnumerable _groupsEnumerable; + + public ref struct EntityGroupsIterator + { + public EntityGroupsIterator(GroupsEnumerable groupsEnumerable) : this() + { + _groupsEnumerableA = groupsEnumerable.GetEnumerator(); + _groupsEnumerableA.MoveNext(); + _groupsEnumerableB = _groupsEnumerableA; + _indexA = 0; + _indexB = 0; + } + + public bool MoveNext() + { + //once GroupEnumerables complete, they reset. If they reset and moveNext doesn't happen, they are invalid + while (_groupsEnumerableA.isValid) + { + var (buffersA, _) = _groupsEnumerableA.Current; + var (buffersB, _) = _groupsEnumerableB.Current; + + //current index A must iterate as long as is less than the current A group count + while (_indexA < buffersA.count) + { + //current index B must iterate as long as is less than the current B group count + if (++_indexB < buffersB.count) + { + return true; + } + + //if B iteration is over, move to the next group + if (_groupsEnumerableB.MoveNext() == false) + { + //if there is no valid next groups, we reset B and we need to move to the next A element + _groupsEnumerableB = _groupsEnumerableA; + (buffersB, _) = _groupsEnumerableB.Current; + ++_indexA; //next A element + _indexB = _indexA; + } + else + //otherwise the current A will be checked against the new B group. IndexB must be reset + //to work on the new group + { + _indexB = -1; + } + } + + //the current group A iteration is done, so we move to the next A group + if (_groupsEnumerableA.MoveNext() == true) + { + //there is a new group, we reset the iteration + _indexA = 0; + _indexB = 0; + _groupsEnumerableB = _groupsEnumerableA; + } + else + return false; + } + + return false; + } + + public void Reset() { throw new Exception(); } + + public ValueRef Current + { + get + { + var valueRef = new ValueRef(_groupsEnumerableA.Current, _indexA, _groupsEnumerableB.Current + , _indexB); + return valueRef; + } + } + + public void Dispose() { } + + GroupsEnumerable.GroupsIterator _groupsEnumerableA; + GroupsEnumerable.GroupsIterator _groupsEnumerableB; + int _indexA; + int _indexB; + } + + public ref struct ValueRef + { + public readonly GroupsEnumerable.RefCurrent _current; + public readonly int _indexA; + public readonly GroupsEnumerable.RefCurrent _refCurrent; + public readonly int _indexB; + + public ValueRef + (GroupsEnumerable.RefCurrent current, int indexA + , GroupsEnumerable.RefCurrent refCurrent, int indexB) + { + _current = current; + _indexA = indexA; + _refCurrent = refCurrent; + _indexB = indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out EntityCollection refCurrent + , out int indexB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + } + + public void Deconstruct + (out EntityCollection buffers, out int indexA, out ExclusiveGroupStruct groupA + , out EntityCollection refCurrent, out int indexB, out ExclusiveGroupStruct groupB) + { + buffers = _current._buffers; + indexA = _indexA; + refCurrent = _refCurrent._buffers; + indexB = _indexB; + groupA = _current._group; + groupB = _refCurrent._group; + } + } + } +} \ No newline at end of file diff --git a/Svelto.ECS/Core/SpecialEnumerators/WaitForSubmissionEnumerator.cs b/Svelto.ECS/Core/SpecialEnumerators/WaitForSubmissionEnumerator.cs new file mode 100644 index 0000000..6222a78 --- /dev/null +++ b/Svelto.ECS/Core/SpecialEnumerators/WaitForSubmissionEnumerator.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections; +using Svelto.ECS.Schedulers; + +namespace Svelto.ECS +{ + /// + /// Enumerator that yields until the next Entities Submission + /// + public struct WaitForSubmissionEnumerator : IEnumerator + { + public WaitForSubmissionEnumerator(EntitiesSubmissionScheduler scheduler):this() + { + _scheduler = scheduler; + } + + public bool MoveNext() + { + switch (_state) + { + case 0: + _iteration = _scheduler.iteration; + _state = 1; + return true; + case 1: + if (_iteration != _scheduler.iteration) + { + _state = 0; + return false; + } + return true; + } + + throw new Exception("something is wrong"); + } + + void IEnumerator.Reset() + { + throw new NotImplementedException(); + } + + public object Current { get; } + + readonly EntitiesSubmissionScheduler _scheduler; + uint _state; + uint _iteration; + } +} \ No newline at end of file diff --git a/Svelto.ECS/Streams/Consumer.cs b/Svelto.ECS/Core/Streams/Consumer.cs similarity index 100% rename from Svelto.ECS/Streams/Consumer.cs rename to Svelto.ECS/Core/Streams/Consumer.cs diff --git a/Svelto.ECS/Streams/EnginesRoot.Streams.cs b/Svelto.ECS/Core/Streams/EnginesRoot.Streams.cs similarity index 100% rename from Svelto.ECS/Streams/EnginesRoot.Streams.cs rename to Svelto.ECS/Core/Streams/EnginesRoot.Streams.cs diff --git a/Svelto.ECS/Streams/EntitiesDB.Streams.cs b/Svelto.ECS/Core/Streams/EntitiesDB.Streams.cs similarity index 90% rename from Svelto.ECS/Streams/EntitiesDB.Streams.cs rename to Svelto.ECS/Core/Streams/EntitiesDB.Streams.cs index 6b2f4c1..d5d47f2 100644 --- a/Svelto.ECS/Streams/EntitiesDB.Streams.cs +++ b/Svelto.ECS/Core/Streams/EntitiesDB.Streams.cs @@ -1,5 +1,4 @@ -using System; -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; namespace Svelto.ECS { diff --git a/Svelto.ECS/Streams/EntitiesStreams.cs b/Svelto.ECS/Core/Streams/EntitiesStreams.cs similarity index 100% rename from Svelto.ECS/Streams/EntitiesStreams.cs rename to Svelto.ECS/Core/Streams/EntitiesStreams.cs diff --git a/Svelto.ECS/Streams/EntityStream.cs b/Svelto.ECS/Core/Streams/EntityStream.cs similarity index 100% rename from Svelto.ECS/Streams/EntityStream.cs rename to Svelto.ECS/Core/Streams/EntityStream.cs diff --git a/Svelto.ECS/Streams/GenericentityStreamConsumerFactory.cs b/Svelto.ECS/Core/Streams/GenericentityStreamConsumerFactory.cs similarity index 100% rename from Svelto.ECS/Streams/GenericentityStreamConsumerFactory.cs rename to Svelto.ECS/Core/Streams/GenericentityStreamConsumerFactory.cs diff --git a/Svelto.ECS/Streams/ThreadSafeNativeEntityStream.cs b/Svelto.ECS/Core/Streams/ThreadSafeNativeEntityStream.cs similarity index 100% rename from Svelto.ECS/Streams/ThreadSafeNativeEntityStream.cs rename to Svelto.ECS/Core/Streams/ThreadSafeNativeEntityStream.cs diff --git a/Svelto.ECS/TypeSafeDictionaryFactory.cs b/Svelto.ECS/Core/TypeSafeDictionaryFactory.cs similarity index 100% rename from Svelto.ECS/TypeSafeDictionaryFactory.cs rename to Svelto.ECS/Core/TypeSafeDictionaryFactory.cs diff --git a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs index c74f124..e3c3710 100644 --- a/Svelto.ECS/DataStructures/TypeSafeDictionary.cs +++ b/Svelto.ECS/DataStructures/TypeSafeDictionary.cs @@ -15,21 +15,21 @@ namespace Svelto.ECS.Internal internal static readonly bool IsUnmanaged = _type.IsUnmanagedEx() && (typeof(IEntityViewComponent).IsAssignableFrom(_type) == false); - SveltoDictionary>, ManagedStrategy, + SveltoDictionary>, ManagedStrategy, ManagedStrategy> implMgd; //used directly by native methods - internal SveltoDictionary>, NativeStrategy, + internal SveltoDictionary>, NativeStrategy, NativeStrategy> implUnmgd; public TypeSafeDictionary(uint size) { if (IsUnmanaged) - implUnmgd = new SveltoDictionary>, + implUnmgd = new SveltoDictionary>, NativeStrategy, NativeStrategy>(size); else { - implMgd = new SveltoDictionary>, + implMgd = new SveltoDictionary>, ManagedStrategy, ManagedStrategy>(size); } } @@ -106,8 +106,9 @@ namespace Svelto.ECS.Internal //this can be optimized, should pass all the entities and not restart the process for each one foreach (var value in implUnmgd) - ExecuteEnginesAddOrSwapCallbacksOnSingleEntity(entityComponentEnginesDB, ref typeSafeDictionary[value.Key] - , fromGroup, in profiler, new EGID(value.Key, toGroup)); + ExecuteEnginesAddOrSwapCallbacksOnSingleEntity(entityComponentEnginesDB + , ref typeSafeDictionary[value.Key], fromGroup + , in profiler, new EGID(value.Key, toGroup)); } else { @@ -115,8 +116,9 @@ namespace Svelto.ECS.Internal //this can be optimized, should pass all the entities and not restart the process for each one foreach (var value in implMgd) - ExecuteEnginesAddOrSwapCallbacksOnSingleEntity(entityComponentEnginesDB, ref typeSafeDictionary[value.Key] - , fromGroup, in profiler, new EGID(value.Key, toGroup)); + ExecuteEnginesAddOrSwapCallbacksOnSingleEntity(entityComponentEnginesDB + , ref typeSafeDictionary[value.Key], fromGroup + , in profiler, new EGID(value.Key, toGroup)); } } diff --git a/Svelto.ECS/DataStructures/Unmanaged/NativeBag.cs b/Svelto.ECS/DataStructures/Unmanaged/NativeBag.cs index 96e89c6..cb2ac97 100644 --- a/Svelto.ECS/DataStructures/Unmanaged/NativeBag.cs +++ b/Svelto.ECS/DataStructures/Unmanaged/NativeBag.cs @@ -9,7 +9,6 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Threading; using Svelto.Common; namespace Svelto.ECS.DataStructures diff --git a/Svelto.ECS/DataStructures/Unmanaged/NativeDynamicArrayCast.cs b/Svelto.ECS/DataStructures/Unmanaged/NativeDynamicArrayCast.cs index a34078b..3c45777 100644 --- a/Svelto.ECS/DataStructures/Unmanaged/NativeDynamicArrayCast.cs +++ b/Svelto.ECS/DataStructures/Unmanaged/NativeDynamicArrayCast.cs @@ -9,7 +9,11 @@ namespace Svelto.ECS.DataStructures [MethodImpl(MethodImplOptions.AggressiveInlining)] public int Count() => _array.Count(); - public int count => _array.Count(); + public int count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _array.Count(); + } public ref T this[int index] { diff --git a/Svelto.ECS/DataStructures/Unmanaged/SharedNativeInt.cs b/Svelto.ECS/DataStructures/Unmanaged/SharedNativeInt.cs index e180084..6810c79 100644 --- a/Svelto.ECS/DataStructures/Unmanaged/SharedNativeInt.cs +++ b/Svelto.ECS/DataStructures/Unmanaged/SharedNativeInt.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.InteropServices; using System.Threading; using Svelto.Common; diff --git a/Svelto.ECS/Dispatcher/DispatchOnChange.cs b/Svelto.ECS/Dispatcher/DispatchOnChange.cs index c2a40aa..b7ae294 100644 --- a/Svelto.ECS/Dispatcher/DispatchOnChange.cs +++ b/Svelto.ECS/Dispatcher/DispatchOnChange.cs @@ -8,7 +8,9 @@ namespace Svelto.ECS { _value = initialValue; } - + + public DispatchOnChange(EGID senderID, Action callback) : base(senderID, callback) {} + public new T value { set diff --git a/Svelto.ECS/Dispatcher/DispatchOnSet.cs b/Svelto.ECS/Dispatcher/DispatchOnSet.cs index 8334d2e..37c6e43 100644 --- a/Svelto.ECS/Dispatcher/DispatchOnSet.cs +++ b/Svelto.ECS/Dispatcher/DispatchOnSet.cs @@ -4,11 +4,12 @@ namespace Svelto.ECS { public class DispatchOnSet { - public DispatchOnSet(EGID senderID) - { - _senderID = senderID; + public DispatchOnSet(EGID senderID, Action callback):this(senderID) + { + NotifyOnValueSet(callback); } - + public DispatchOnSet(EGID senderID) { _senderID = senderID; } + public T value { set @@ -19,29 +20,29 @@ namespace Svelto.ECS _subscriber(_senderID, value); } } - + public void NotifyOnValueSet(Action action) { #if DEBUG && !PROFILE_SVELTO - DBC.ECS.Check.Require(_subscriber == null, $"{this.GetType().Name}: listener already registered"); + DBC.ECS.Check.Require(_subscriber == null, $"{this.GetType().Name}: listener already registered"); #endif _subscriber = action; - _paused = false; + _paused = false; } public void StopNotify() { _subscriber = null; - _paused = true; + _paused = true; } - public void PauseNotify() { _paused = true; } + public void PauseNotify() { _paused = true; } public void ResumeNotify() { _paused = false; } - protected T _value; - readonly EGID _senderID; + protected T _value; + readonly EGID _senderID; Action _subscriber; bool _paused; } -} +} \ No newline at end of file diff --git a/Svelto.ECS/EntitySubmissionScheduler.cs b/Svelto.ECS/EntitySubmissionScheduler.cs deleted file mode 100644 index d5af356..0000000 --- a/Svelto.ECS/EntitySubmissionScheduler.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace Svelto.ECS.Schedulers -{ - public interface IEntitiesSubmissionScheduler: IDisposable - { - bool paused { get; set; } - } - - public abstract class EntitiesSubmissionScheduler: IEntitiesSubmissionScheduler - { - protected internal abstract EnginesRoot.EntitiesSubmitter onTick { set; } - public abstract void Dispose(); - public abstract bool paused { get; set; } - } - - public abstract class ISimpleEntitiesSubmissionScheduler: EntitiesSubmissionScheduler - { - public abstract void SubmitEntities(); - } -} \ No newline at end of file diff --git a/Svelto.ECS/Extensions/Svelto/AllGroupsEnumerable.cs b/Svelto.ECS/Extensions/Svelto/AllGroupsEnumerable.cs index eb746df..54673e3 100644 --- a/Svelto.ECS/Extensions/Svelto/AllGroupsEnumerable.cs +++ b/Svelto.ECS/Extensions/Svelto/AllGroupsEnumerable.cs @@ -19,15 +19,12 @@ namespace Svelto.ECS public void Deconstruct(out EntityCollection collection, out ExclusiveGroupStruct group) { collection = this.collection; - group = this.@group; + group = this.@group; } } - - public AllGroupsEnumerable(EntitiesDB db) - { - _db = db; - } - + + public AllGroupsEnumerable(EntitiesDB db) { _db = db; } + public ref struct GroupsIterator { public GroupsIterator(EntitiesDB db) : this() @@ -40,13 +37,14 @@ namespace Svelto.ECS //attention, the while is necessary to skip empty groups while (_db.MoveNext() == true) { - FasterDictionary.KeyValuePairFast group = _db.Current; + var group = _db.Current; ITypeSafeDictionary typeSafeDictionary = @group.Value as ITypeSafeDictionary; - - if (typeSafeDictionary.count == 0) continue; + + if (typeSafeDictionary.count == 0) + continue; _array.collection = new EntityCollection(typeSafeDictionary.GetValues(out var count), count); - _array.@group = new ExclusiveGroupStruct(group.Key); + _array.@group = new ExclusiveGroupStruct(group.Key); return true; } @@ -56,15 +54,15 @@ namespace Svelto.ECS public GroupCollection Current => _array; - FasterDictionary.FasterDictionaryKeyValueEnumerator _db; + SveltoDictionary>, ManagedStrategy, + ManagedStrategy>.SveltoDictionaryKeyValueEnumerator _db; + GroupCollection _array; } - public GroupsIterator GetEnumerator() - { - return new GroupsIterator(_db); - } + public GroupsIterator GetEnumerator() { return new GroupsIterator(_db); } - readonly EntitiesDB _db; + readonly EntitiesDB _db; } -} +} \ No newline at end of file diff --git a/Svelto.ECS/Extensions/Svelto/EntityCollectionExtension.cs b/Svelto.ECS/Extensions/Svelto/EntityCollectionExtension.cs index b9b4153..a4d5029 100644 --- a/Svelto.ECS/Extensions/Svelto/EntityCollectionExtension.cs +++ b/Svelto.ECS/Extensions/Svelto/EntityCollectionExtension.cs @@ -1,4 +1,3 @@ -using System; using System.Runtime.CompilerServices; using Svelto.DataStructures; using Svelto.ECS.Hybrid; @@ -46,10 +45,10 @@ namespace Svelto.ECS where T3 : unmanaged, IEntityComponent where T4 : unmanaged, IEntityComponent { - buffer1 = ec.Item1._nativedBuffer; - buffer2 = ec.Item2._nativedBuffer; - buffer3 = ec.Item3._nativedBuffer; - buffer4 = ec.Item4._nativedBuffer; + buffer1 = ec.buffer1._nativedBuffer; + buffer2 = ec.buffer2._nativedBuffer; + buffer3 = ec.buffer3._nativedBuffer; + buffer4 = ec.buffer4._nativedBuffer; count = (int) ec.count; } @@ -188,10 +187,10 @@ namespace Svelto.ECS where T3 : unmanaged, IEntityComponent where T4 : struct, IEntityViewComponent { - buffer1 = ec.Item1._nativedBuffer; - buffer2 = ec.Item2._nativedBuffer; - buffer3 = ec.Item3._nativedBuffer; - buffer4 = ec.Item4._managedBuffer; + buffer1 = ec.buffer1._nativedBuffer; + buffer2 = ec.buffer2._nativedBuffer; + buffer3 = ec.buffer3._nativedBuffer; + buffer4 = ec.buffer4._managedBuffer; count = (int) ec.count; } } @@ -229,8 +228,8 @@ namespace Svelto.ECS where T3 : unmanaged, IEntityComponent where T4 : unmanaged, IEntityComponent { - return new BT, NB, NB, NB>(ec.Item1._nativedBuffer, ec.Item2._nativedBuffer - , ec.Item3._nativedBuffer, ec.Item4._nativedBuffer, ec.count); + return new BT, NB, NB, NB>(ec.buffer1._nativedBuffer, ec.buffer2._nativedBuffer + , ec.buffer3._nativedBuffer, ec.buffer4._nativedBuffer, ec.count); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -241,10 +240,10 @@ namespace Svelto.ECS where T3 : struct, IEntityViewComponent where T4 : struct, IEntityViewComponent { - buffer1 = ec.Item1._nativedBuffer; - buffer2 = ec.Item2._nativedBuffer; - buffer3 = ec.Item3._managedBuffer; - buffer4 = ec.Item4._managedBuffer; + buffer1 = ec.buffer1._nativedBuffer; + buffer2 = ec.buffer2._nativedBuffer; + buffer3 = ec.buffer3._managedBuffer; + buffer4 = ec.buffer4._managedBuffer; count = (int) ec.count; } } diff --git a/Svelto.ECS/Extensions/Svelto/GroupsEnumerable.cs b/Svelto.ECS/Extensions/Svelto/GroupsEnumerable.cs index 465ed8a..b1b9559 100644 --- a/Svelto.ECS/Extensions/Svelto/GroupsEnumerable.cs +++ b/Svelto.ECS/Extensions/Svelto/GroupsEnumerable.cs @@ -17,9 +17,6 @@ namespace Svelto.ECS where T3 : struct, IEntityComponent where T4 : struct, IEntityComponent { - readonly EntitiesDB _db; - readonly LocalFasterReadOnlyList _groups; - public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList groups) { _db = db; @@ -52,7 +49,8 @@ namespace Svelto.ECS var array = entityCollection1; var array2 = entityCollection2; - _buffers = new EntityCollection(array.buffer1, array.buffer2, array.buffer3, array2); + _buffers = new EntityCollection(array.buffer1, array.buffer2, array.buffer3 + , array2); break; } @@ -66,7 +64,8 @@ namespace Svelto.ECS public void Reset() { _indexGroup = -1; } - public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); + public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); + public bool isValid => _indexGroup != -1; readonly LocalFasterReadOnlyList _groups; @@ -76,44 +75,36 @@ namespace Svelto.ECS } public GroupsIterator GetEnumerator() { return new GroupsIterator(_db, _groups); } - } - public ref struct RefCurrent where T1 : struct, IEntityComponent - where T2 : struct, IEntityComponent - where T3 : struct, IEntityComponent - where T4 : struct, IEntityComponent - { - public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) - { - _buffers = buffers; - _group = group; - } + readonly EntitiesDB _db; + readonly LocalFasterReadOnlyList _groups; - public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) + public ref struct RefCurrent { - buffers = _buffers; - group = _group; - } + public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) + { + _buffers = buffers; + _group = group; + } - public readonly EntityCollection _buffers; - public readonly ExclusiveGroupStruct _group; + public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) + { + buffers = _buffers; + group = _group; + } + + public readonly EntityCollection _buffers; + public readonly ExclusiveGroupStruct _group; + } } - /// - /// ToDo source gen could return the implementation of IBuffer directly, but cannot be done manually - /// - /// - /// - /// public readonly ref struct GroupsEnumerable where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent where T3 : struct, IEntityComponent { - readonly EntitiesDB _db; - readonly LocalFasterReadOnlyList _groups; - public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList groups) { + DBC.ECS.Check.Require(groups.count > 0, "can't initialise a query without valid groups"); _db = db; _groups = groups; } @@ -150,7 +141,8 @@ namespace Svelto.ECS public void Reset() { _indexGroup = -1; } - public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); + public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); + public bool isValid => _indexGroup != -1; readonly LocalFasterReadOnlyList _groups; @@ -160,26 +152,27 @@ namespace Svelto.ECS } public GroupsIterator GetEnumerator() { return new GroupsIterator(_db, _groups); } - } - public ref struct RefCurrent where T1 : struct, IEntityComponent - where T2 : struct, IEntityComponent - where T3 : struct, IEntityComponent - { - public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) - { - _buffers = buffers; - _group = group; - } + readonly EntitiesDB _db; + readonly LocalFasterReadOnlyList _groups; - public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) + public ref struct RefCurrent { - buffers = _buffers; - group = _group; - } + public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) + { + _buffers = buffers; + _group = group; + } + + public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) + { + buffers = _buffers; + group = _group; + } - public readonly EntityCollection _buffers; - public readonly ExclusiveGroupStruct _group; + public readonly EntityCollection _buffers; + public readonly ExclusiveGroupStruct _group; + } } public readonly ref struct GroupsEnumerable @@ -223,7 +216,8 @@ namespace Svelto.ECS public void Reset() { _indexGroup = -1; } - public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); + public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); + public bool isValid => _indexGroup != -1; readonly EntitiesDB _db; readonly LocalFasterReadOnlyList _groups; @@ -236,24 +230,24 @@ namespace Svelto.ECS readonly EntitiesDB _db; readonly LocalFasterReadOnlyList _groups; - } - public ref struct RefCurrent where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent - { - public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) + public ref struct RefCurrent { - _buffers = buffers; - _group = group; - } + public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) + { + _buffers = buffers; + _group = group; + } - public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) - { - buffers = _buffers; - group = _group; - } + public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) + { + buffers = _buffers; + group = _group; + } - public readonly EntityCollection _buffers; - public readonly ExclusiveGroupStruct _group; + public readonly EntityCollection _buffers; + public readonly ExclusiveGroupStruct _group; + } } public readonly ref struct GroupsEnumerable where T1 : struct, IEntityComponent @@ -285,13 +279,19 @@ namespace Svelto.ECS _buffer = entityCollection; break; } + + var moveNext = _indexGroup < _groups.count; - return _indexGroup < _groups.count; + if (moveNext == false) + Reset(); + + return moveNext; } public void Reset() { _indexGroup = -1; } - public RefCurrent Current => new RefCurrent(_buffer, _groups[_indexGroup]); + public RefCurrent Current => new RefCurrent(_buffer, _groups[_indexGroup]); + public bool isValid => _indexGroup != -1; readonly EntitiesDB _db; readonly LocalFasterReadOnlyList _groups; @@ -304,23 +304,28 @@ namespace Svelto.ECS readonly EntitiesDB _db; readonly LocalFasterReadOnlyList _groups; - } - public ref struct RefCurrent where T1 : struct, IEntityComponent - { - public RefCurrent(in EntityCollection buffers, ExclusiveGroupStruct group) + public readonly ref struct RefCurrent { - _buffers = buffers; - _group = group; - } + public RefCurrent(in EntityCollection buffers, in ExclusiveGroupStruct group) + { + _buffers = buffers; + _group = group; + } - public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) - { - buffers = _buffers; - group = _group; - } + public void Deconstruct(out EntityCollection buffers, out ExclusiveGroupStruct group) + { + buffers = _buffers; + group = _group; + } + + public void Deconstruct(out EntityCollection buffers) + { + buffers = _buffers; + } - public readonly EntityCollection _buffers; - public readonly ExclusiveGroupStruct _group; + public readonly EntityCollection _buffers; + public readonly ExclusiveGroupStruct _group; + } } } \ No newline at end of file diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Jobs/IJobifiedEngine.cs b/Svelto.ECS/Extensions/Unity/DOTS/Jobs/IJobifiedEngine.cs new file mode 100644 index 0000000..80d35f9 --- /dev/null +++ b/Svelto.ECS/Extensions/Unity/DOTS/Jobs/IJobifiedEngine.cs @@ -0,0 +1,18 @@ +using Unity.Jobs; + +namespace Svelto.ECS.Extensions.Unity +{ + public interface IJobifiedEngine : IEngine + { + JobHandle Execute(JobHandle inputDeps, ref T _param); + + string name { get; } + } + + public interface IJobifiedEngine : IEngine + { + JobHandle Execute(JobHandle inputDeps); + + string name { get; } + } +} \ No newline at end of file diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Jobs/JobifiedEnginesGroup.cs b/Svelto.ECS/Extensions/Unity/DOTS/Jobs/JobifiedEnginesGroup.cs index 2a5eb10..7186710 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Jobs/JobifiedEnginesGroup.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Jobs/JobifiedEnginesGroup.cs @@ -5,20 +5,6 @@ using Unity.Jobs; namespace Svelto.ECS.Extensions.Unity { - public interface IJobifiedEngine : IEngine - { - JobHandle Execute(JobHandle inputDeps); - - string name { get; } - } - - public interface IJobifiedEngine : IEngine - { - JobHandle Execute(JobHandle inputDeps, ref T _param); - - string name { get; } - } - public interface IJobifiedGroupEngine : IJobifiedEngine { } /// @@ -58,7 +44,7 @@ namespace Svelto.ECS.Extensions.Unity return combinedHandles; } - protected internal void Add(Interface engine) + public void Add(Interface engine) { _engines.Add(engine); } @@ -66,7 +52,7 @@ namespace Svelto.ECS.Extensions.Unity public string name => _name; protected readonly FasterList _engines; - readonly string _name; + readonly string _name; } public abstract class JobifiedEnginesGroup: IJobifiedGroupEngine where Interface : class, IJobifiedEngine diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Native/EnginesRoot.NativeOperation.cs b/Svelto.ECS/Extensions/Unity/DOTS/Native/EnginesRoot.NativeOperation.cs index 0302254..136129c 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Native/EnginesRoot.NativeOperation.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Native/EnginesRoot.NativeOperation.cs @@ -9,30 +9,28 @@ namespace Svelto.ECS public partial class EnginesRoot { //todo: I very likely don't need to create one for each native entity factory, the same can be reused - readonly AtomicNativeBags _addOperationQueue = - new AtomicNativeBags(Common.Allocator.Persistent); + readonly AtomicNativeBags _addOperationQueue = new AtomicNativeBags(Common.Allocator.Persistent); - readonly AtomicNativeBags _removeOperationQueue = - new AtomicNativeBags(Common.Allocator.Persistent); + readonly AtomicNativeBags _removeOperationQueue = new AtomicNativeBags(Common.Allocator.Persistent); - readonly AtomicNativeBags _swapOperationQueue = - new AtomicNativeBags(Common.Allocator.Persistent); + readonly AtomicNativeBags _swapOperationQueue = new AtomicNativeBags(Common.Allocator.Persistent); NativeEntityRemove ProvideNativeEntityRemoveQueue(string memberName) where T : IEntityDescriptor, new() { //todo: remove operation array and store entity descriptor hash in the return value //todo I maybe able to provide a _nativeSwap.SwapEntity - _nativeRemoveOperations.Add( - new NativeOperationRemove(EntityDescriptorTemplate.descriptor.componentsToBuild, TypeCache.type, memberName)); + _nativeRemoveOperations.Add(new NativeOperationRemove( + EntityDescriptorTemplate.descriptor.componentsToBuild, TypeCache.type + , memberName)); return new NativeEntityRemove(_removeOperationQueue, _nativeRemoveOperations.count - 1); } - + NativeEntitySwap ProvideNativeEntitySwapQueue(string memberName) where T : IEntityDescriptor, new() { //todo: remove operation array and store entity descriptor hash in the return value - _nativeSwapOperations.Add( - new NativeOperationSwap(EntityDescriptorTemplate.descriptor.componentsToBuild, TypeCache.type, memberName)); + _nativeSwapOperations.Add(new NativeOperationSwap(EntityDescriptorTemplate.descriptor.componentsToBuild + , TypeCache.type, memberName)); return new NativeEntitySwap(_swapOperationQueue, _nativeSwapOperations.count - 1); } @@ -50,35 +48,41 @@ namespace Svelto.ECS { using (profiler.Sample("Native Remove/Swap Operations")) { - for (int i = 0; i < _removeOperationQueue.count; i++) + var removeBuffersCount = _removeOperationQueue.count; + for (int i = 0; i < removeBuffersCount; i++) { ref var buffer = ref _removeOperationQueue.GetBuffer(i); while (buffer.IsEmpty() == false) { - var componentsIndex = buffer.Dequeue(); - var entityEGID = buffer.Dequeue(); - var nativeRemoveOperation = _nativeRemoveOperations[componentsIndex]; - CheckRemoveEntityID(entityEGID, nativeRemoveOperation.entityDescriptorType); + var componentsIndex = buffer.Dequeue(); + var entityEGID = buffer.Dequeue(); + NativeOperationRemove nativeRemoveOperation = _nativeRemoveOperations[componentsIndex]; + CheckRemoveEntityID(entityEGID, nativeRemoveOperation.entityDescriptorType + , nativeRemoveOperation.caller); QueueEntitySubmitOperation(new EntitySubmitOperation( EntitySubmitOperationType.Remove, entityEGID, entityEGID , nativeRemoveOperation.components)); } } - for (int i = 0; i < _swapOperationQueue.count; i++) + var swapBuffersCount = _swapOperationQueue.count; + for (int i = 0; i < swapBuffersCount; i++) { ref var buffer = ref _swapOperationQueue.GetBuffer(i); while (buffer.IsEmpty() == false) { - var componentsIndex = buffer.Dequeue(); + var componentsIndex = buffer.Dequeue(); var entityEGID = buffer.Dequeue(); - + var componentBuilders = _nativeSwapOperations[componentsIndex].components; - CheckRemoveEntityID(entityEGID.@from, _nativeSwapOperations[componentsIndex].entityDescriptorType, _nativeSwapOperations[componentsIndex].caller ); - CheckAddEntityID(entityEGID.to, _nativeSwapOperations[componentsIndex].entityDescriptorType, _nativeSwapOperations[componentsIndex].caller); + CheckRemoveEntityID(entityEGID.@from + , _nativeSwapOperations[componentsIndex].entityDescriptorType + , _nativeSwapOperations[componentsIndex].caller); + CheckAddEntityID(entityEGID.to, _nativeSwapOperations[componentsIndex].entityDescriptorType + , _nativeSwapOperations[componentsIndex].caller); QueueEntitySubmitOperation(new EntitySubmitOperation( EntitySubmitOperationType.Swap, entityEGID.@from, entityEGID.to @@ -86,21 +90,22 @@ namespace Svelto.ECS } } } - + using (profiler.Sample("Native Add Operations")) { - for (int i = 0; i < _addOperationQueue.count; i++) + var addBuffersCount = _addOperationQueue.count; + for (int i = 0; i < addBuffersCount; i++) { ref var buffer = ref _addOperationQueue.GetBuffer(i); - + while (buffer.IsEmpty() == false) { var componentsIndex = buffer.Dequeue(); var egid = buffer.Dequeue(); var componentCounts = buffer.Dequeue(); - - EntityComponentInitializer init = - BuildEntity(egid, _nativeAddOperations[componentsIndex].components, _nativeAddOperations[componentsIndex].entityDescriptorType); + + var init = BuildEntity(egid, _nativeAddOperations[componentsIndex].components + , _nativeAddOperations[componentsIndex].entityDescriptorType); //only called if Init is called on the initialized (there is something to init) while (componentCounts > 0) @@ -146,22 +151,23 @@ namespace Svelto.ECS readonly struct NativeOperationBuild { internal readonly IComponentBuilder[] components; - internal readonly Type entityDescriptorType; + internal readonly Type entityDescriptorType; public NativeOperationBuild(IComponentBuilder[] descriptorComponentsToBuild, Type entityDescriptorType) { this.entityDescriptorType = entityDescriptorType; - components = descriptorComponentsToBuild; + components = descriptorComponentsToBuild; } } readonly struct NativeOperationRemove { internal readonly IComponentBuilder[] components; - internal readonly Type entityDescriptorType; - internal readonly string caller; - - public NativeOperationRemove(IComponentBuilder[] descriptorComponentsToRemove, Type entityDescriptorType, string caller) + internal readonly Type entityDescriptorType; + internal readonly string caller; + + public NativeOperationRemove + (IComponentBuilder[] descriptorComponentsToRemove, Type entityDescriptorType, string caller) { this.caller = caller; components = descriptorComponentsToRemove; @@ -172,10 +178,11 @@ namespace Svelto.ECS readonly struct NativeOperationSwap { internal readonly IComponentBuilder[] components; - internal readonly Type entityDescriptorType; - internal readonly string caller; + internal readonly Type entityDescriptorType; + internal readonly string caller; - public NativeOperationSwap(IComponentBuilder[] descriptorComponentsToSwap, Type entityDescriptorType, string caller) + public NativeOperationSwap + (IComponentBuilder[] descriptorComponentsToSwap, Type entityDescriptorType, string caller) { this.caller = caller; components = descriptorComponentsToSwap; diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEGIDMultiMapper.cs b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEGIDMultiMapper.cs index cac1afd..1a5af5e 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEGIDMultiMapper.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEGIDMultiMapper.cs @@ -7,24 +7,24 @@ namespace Svelto.ECS public struct NativeEGIDMultiMapper:IDisposable where T : unmanaged, IEntityComponent { SveltoDictionary>, + NativeStrategy>, NativeStrategy, NativeStrategy>, - NativeStrategy>, + NativeStrategy>, NativeStrategy>, + NativeStrategy>, NativeStrategy, NativeStrategy>>, NativeStrategy> _dic; public NativeEGIDMultiMapper (SveltoDictionary>, + NativeStrategy>, NativeStrategy, NativeStrategy>, - NativeStrategy>, + NativeStrategy>, NativeStrategy>, + NativeStrategy>, NativeStrategy, NativeStrategy>>, NativeStrategy> dictionary) diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityFactory.cs b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityFactory.cs index 7351b16..dc83142 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityFactory.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityFactory.cs @@ -14,19 +14,19 @@ namespace Svelto.ECS _addOperationQueue = addOperationQueue; } - public NativeEntityComponentInitializer BuildEntity - (uint eindex, BuildGroup BuildGroup, int threadIndex) + public NativeEntityInitializer BuildEntity + (uint eindex, ExclusiveBuildGroup exclusiveBuildGroup, int threadIndex) { NativeBag unsafeBuffer = _addOperationQueue.GetBuffer(threadIndex + 1); unsafeBuffer.Enqueue(_index); - unsafeBuffer.Enqueue(new EGID(eindex, BuildGroup)); + unsafeBuffer.Enqueue(new EGID(eindex, exclusiveBuildGroup)); unsafeBuffer.ReserveEnqueue(out var index) = 0; - return new NativeEntityComponentInitializer(unsafeBuffer, index); + return new NativeEntityInitializer(unsafeBuffer, index); } - public NativeEntityComponentInitializer BuildEntity(EGID egid, int threadIndex) + public NativeEntityInitializer BuildEntity(EGID egid, int threadIndex) { NativeBag unsafeBuffer = _addOperationQueue.GetBuffer(threadIndex + 1); @@ -34,7 +34,7 @@ namespace Svelto.ECS unsafeBuffer.Enqueue(new EGID(egid.entityID, egid.groupID)); unsafeBuffer.ReserveEnqueue(out var index) = 0; - return new NativeEntityComponentInitializer(unsafeBuffer, index); + return new NativeEntityInitializer(unsafeBuffer, index); } } } diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityComponentInitializer.cs b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityInitializer.cs similarity index 77% rename from Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityComponentInitializer.cs rename to Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityInitializer.cs index 1d988b6..dbd0225 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityComponentInitializer.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntityInitializer.cs @@ -2,12 +2,12 @@ using Svelto.ECS.DataStructures; namespace Svelto.ECS { - public readonly ref struct NativeEntityComponentInitializer + public readonly ref struct NativeEntityInitializer { readonly NativeBag _unsafeBuffer; readonly UnsafeArrayIndex _index; - public NativeEntityComponentInitializer(in NativeBag unsafeBuffer, UnsafeArrayIndex index) + public NativeEntityInitializer(in NativeBag unsafeBuffer, UnsafeArrayIndex index) { _unsafeBuffer = unsafeBuffer; _index = index; diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntitySwap.cs b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntitySwap.cs index 53de378..a60d1ac 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntitySwap.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Native/NativeEntitySwap.cs @@ -22,7 +22,7 @@ namespace Svelto.ECS } - public void SwapEntity(EGID from, BuildGroup to, int threadIndex) + public void SwapEntity(EGID from, ExclusiveBuildGroup to, int threadIndex) { var simpleNativeBag = _swapQueue.GetBuffer(threadIndex); simpleNativeBag.Enqueue(_indexSwap); diff --git a/Svelto.ECS/Extensions/Unity/DOTS/Native/UnityEntityDBExtensions.cs b/Svelto.ECS/Extensions/Unity/DOTS/Native/UnityEntityDBExtensions.cs index 4917887..41fefe7 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/Native/UnityEntityDBExtensions.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/Native/UnityEntityDBExtensions.cs @@ -48,12 +48,12 @@ namespace Svelto.ECS { var dictionary = new SveltoDictionary>, + NativeStrategy>, NativeStrategy, NativeStrategy>, - NativeStrategy>, + NativeStrategy>, NativeStrategy>, + NativeStrategy>, NativeStrategy, NativeStrategy>>, NativeStrategy> diff --git a/Svelto.ECS/Extensions/Unity/DOTS/UECS/IUECSSubmissionEngine.cs b/Svelto.ECS/Extensions/Unity/DOTS/UECS/IUECSSubmissionEngine.cs index b86f9db..9e7e4bb 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/UECS/IUECSSubmissionEngine.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/UECS/IUECSSubmissionEngine.cs @@ -1,12 +1,25 @@ #if UNITY_ECS +using Svelto.Common; using Unity.Entities; +using Unity.Jobs; namespace Svelto.ECS.Extensions.Unity { - public interface IUECSSubmissionEngine : IJobifiedEngine + public abstract class SubmissionEngine : SystemBase, IJobifiedEngine { - EntityCommandBuffer ECB { get; set;} - EntityManager EM { get; set;} + public JobHandle Execute(JobHandle inputDeps) + { + Dependency = JobHandle.CombineDependencies(Dependency, inputDeps); + + OnUpdate(); + + return Dependency; + } + + public EntityCommandBuffer ECB { get; internal set; } + protected EntityManager EM => this.EntityManager; + + public string name => TypeToString.Name(this); } } #endif \ No newline at end of file diff --git a/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoOverUECSEnginesGroup.cs b/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoOverUECSEnginesGroup.cs index 309fc74..f4e7013 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoOverUECSEnginesGroup.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoOverUECSEnginesGroup.cs @@ -6,19 +6,35 @@ using Unity.Jobs; namespace Svelto.ECS.Extensions.Unity { + /// + /// This is a high level class to abstract the complexity of creating a Svelto ECS application that interacts + /// with UECS. However this is designed to make it work almost out of the box, but it should be eventually + /// substituted by project customized code. + /// 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. The flow should be: + /// Svelto Engines Run + /// This Engine runs, which causeS: + /// Jobs to be completed (it's a sync point) + /// Synchronizations engines to be executed (Svelto to UECS) + /// Submission of Entities to be executed + /// Svelto Add/Remove callbacks to be called + /// ISubmissionEngines to be executed + /// UECS engines to executed + /// Synchronizations engines to be executed (UECS To Svelto) + /// [Sequenced(nameof(JobifiedSveltoEngines.SveltoOverUECS))] public class SveltoOverUECSEnginesGroup: IJobifiedEngine { public SveltoOverUECSEnginesGroup(EnginesRoot enginesRoot) { - DBC.ECS.Check.Require(enginesRoot.scheduler is ISimpleEntitiesSubmissionScheduler, "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 ISimpleEntitiesSubmissionScheduler, enginesRoot); + CreateUnityECSWorldForSvelto(enginesRoot.scheduler as SimpleEntitiesSubmissionScheduler, enginesRoot); } public World world { get; private set; } - void CreateUnityECSWorldForSvelto(ISimpleEntitiesSubmissionScheduler scheduler, EnginesRoot enginesRoot) + void CreateUnityECSWorldForSvelto(SimpleEntitiesSubmissionScheduler scheduler, EnginesRoot enginesRoot) { world = new World("Svelto<>UECS world"); @@ -29,7 +45,6 @@ namespace Svelto.ECS.Extensions.Unity //This is the UECS group that takes care of all the UECS systems that creates entities //it also submits Svelto entities _sveltoUecsEntitiesSubmissionGroup = new SveltoUECSEntitiesSubmissionGroup(scheduler, world); - enginesRoot.AddEngine(_sveltoUecsEntitiesSubmissionGroup); //This is the group that handles the UECS sync systems that copy the svelto entities values to UECS entities _syncSveltoToUecsGroup = new SyncSveltoToUECSGroup(); enginesRoot.AddEngine(_syncSveltoToUecsGroup); @@ -45,7 +60,7 @@ namespace Svelto.ECS.Extensions.Unity public JobHandle Execute(JobHandle inputDeps) { //this is a sync point, there won't be pending jobs after this - _sveltoUecsEntitiesSubmissionGroup.Execute(inputDeps); + _sveltoUecsEntitiesSubmissionGroup.SubmitEntities(inputDeps); //Mixed explicit job dependency and internal automatic ECS dependency system //Write in to UECS entities so the UECS dependencies react on the components touched @@ -59,7 +74,7 @@ namespace Svelto.ECS.Extensions.Unity return _syncUecsToSveltoGroup.Execute(handle); } - public void AddUECSSubmissionEngine(IUECSSubmissionEngine spawnUnityEntityOnSveltoEntityEngine) + public void AddUECSSubmissionEngine(SubmissionEngine spawnUnityEntityOnSveltoEntityEngine) { _sveltoUecsEntitiesSubmissionGroup.Add(spawnUnityEntityOnSveltoEntityEngine); _enginesRoot.AddEngine(spawnUnityEntityOnSveltoEntityEngine); @@ -94,7 +109,6 @@ namespace Svelto.ECS.Extensions.Unity SyncSveltoToUECSGroup _syncSveltoToUecsGroup; SyncUECSToSveltoGroup _syncUecsToSveltoGroup; EnginesRoot _enginesRoot; - } } #endif \ No newline at end of file diff --git a/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoUECSEntitiesSubmissionGroup.cs b/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoUECSEntitiesSubmissionGroup.cs index ca835d6..1f0a8d3 100644 --- a/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoUECSEntitiesSubmissionGroup.cs +++ b/Svelto.ECS/Extensions/Unity/DOTS/UECS/SveltoUECSEntitiesSubmissionGroup.cs @@ -1,4 +1,7 @@ #if UNITY_ECS +using System.Collections; +using Svelto.Common; +using Svelto.DataStructures; using Svelto.ECS.Schedulers; using Unity.Entities; using Unity.Jobs; @@ -15,22 +18,21 @@ namespace Svelto.ECS.Extensions.Unity /// solve external dependencies. External dependencies are tracked, but only linked to the UECS components operations /// With Dependency I cannot guarantee that an external container is used before previous jobs working on it are completed /// - public class SveltoUECSEntitiesSubmissionGroup : JobifiedEnginesGroup + public sealed class SveltoUECSEntitiesSubmissionGroup { - public SveltoUECSEntitiesSubmissionGroup - (ISimpleEntitiesSubmissionScheduler submissionScheduler, World UECSWorld) + public SveltoUECSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler, World UECSWorld) { _submissionScheduler = submissionScheduler; _ECBSystem = UECSWorld.CreateSystem(); + _engines = new FasterList(); } - public new void Execute(JobHandle jobHandle) + public void SubmitEntities(JobHandle jobHandle) { - //Sync Point as we must be sure that jobs that create/swap/remove entities are done - jobHandle.Complete(); - if (_submissionScheduler.paused) return; + + jobHandle.Complete(); //prepare the entity command buffer to be used by the registered engines var entityCommandBuffer = _ECBSystem.CreateCommandBuffer(); @@ -38,21 +40,40 @@ namespace Svelto.ECS.Extensions.Unity foreach (var system in _engines) { system.ECB = entityCommandBuffer; - system.EM = _ECBSystem.EntityManager; } //Submit Svelto Entities, calls Add/Remove/MoveTo that can be used by the IUECSSubmissionEngines _submissionScheduler.SubmitEntities(); - //execute submission engines and complete jobs - base.Execute(default).Complete(); + //execute submission engines and complete jobs because of this I don't need to do _ECBSystem.AddJobHandleForProducer(Dependency); + using (var profiler = new PlatformProfiler("SveltoUECSEntitiesSubmissionGroup")) + { + for (var index = 0; index < _engines.count; index++) + { + ref var engine = ref _engines[index]; + using (profiler.Sample(engine.name)) + { + jobHandle = engine.Execute(jobHandle); + } + } + } + + //Sync Point as we must be sure that jobs that create/swap/remove entities are done + jobHandle.Complete(); //flush command buffer _ECBSystem.Update(); } + + public void Add(SubmissionEngine engine) + { + _ECBSystem.World.AddSystem(engine); + _engines.Add(engine); + } - readonly ISimpleEntitiesSubmissionScheduler _submissionScheduler; + readonly SimpleEntitiesSubmissionScheduler _submissionScheduler; readonly SubmissionEntitiesCommandBufferSystem _ECBSystem; + readonly FasterList _engines; [DisableAutoCreation] class SubmissionEntitiesCommandBufferSystem : EntityCommandBufferSystem { } diff --git a/Svelto.ECS/Extensions/Unity/EntityDescriptorHolderHelper.cs b/Svelto.ECS/Extensions/Unity/EntityDescriptorHolderHelper.cs index 609c845..087d755 100644 --- a/Svelto.ECS/Extensions/Unity/EntityDescriptorHolderHelper.cs +++ b/Svelto.ECS/Extensions/Unity/EntityDescriptorHolderHelper.cs @@ -1,4 +1,4 @@ -#if UNITY_ECS +#if UNITY_5 || UNITY_5_3_OR_NEWER using Svelto.ECS.Hybrid; using UnityEngine; @@ -6,7 +6,7 @@ namespace Svelto.ECS.Extensions.Unity { public static class EntityDescriptorHolderHelper { - public static EntityComponentInitializer CreateEntity(this Transform contextHolder, EGID ID, + public static EntityInitializer CreateEntity(this Transform contextHolder, EGID ID, IEntityFactory factory, out T holder) where T : MonoBehaviour, IEntityDescriptorHolder { @@ -16,7 +16,7 @@ namespace Svelto.ECS.Extensions.Unity return factory.BuildEntity(ID, holder.GetDescriptor(), implementors); } - public static EntityComponentInitializer Create(this Transform contextHolder, EGID ID, + public static EntityInitializer Create(this Transform contextHolder, EGID ID, IEntityFactory factory) where T : MonoBehaviour, IEntityDescriptorHolder { diff --git a/Svelto.ECS/Extensions/Unity/SveltoGUIHelper.cs b/Svelto.ECS/Extensions/Unity/SveltoGUIHelper.cs index e24303b..b639404 100644 --- a/Svelto.ECS/Extensions/Unity/SveltoGUIHelper.cs +++ b/Svelto.ECS/Extensions/Unity/SveltoGUIHelper.cs @@ -86,7 +86,7 @@ namespace Svelto.ECS.Extensions.Unity return s; } - public static EntityComponentInitializer Create(EGID ID, Transform contextHolder, IEntityFactory factory, + public static EntityInitializer Create(EGID ID, Transform contextHolder, IEntityFactory factory, out T holder, bool searchImplementorsInChildren = false) where T : MonoBehaviour, IEntityDescriptorHolder { @@ -100,7 +100,7 @@ namespace Svelto.ECS.Extensions.Unity return factory.BuildEntity(ID, holder.GetDescriptor(), implementors); } - public static EntityComponentInitializer Create(EGID ID, Transform contextHolder, + public static EntityInitializer Create(EGID ID, Transform contextHolder, IEntityFactory factory, bool searchImplementorsInChildren = false) where T : MonoBehaviour, IEntityDescriptorHolder { diff --git a/Svelto.ECS/Extensions/Unity/UnityEntitiesSubmissionScheduler.cs b/Svelto.ECS/Extensions/Unity/UnityEntitiesSubmissionScheduler.cs index f58a5b3..d33078c 100644 --- a/Svelto.ECS/Extensions/Unity/UnityEntitiesSubmissionScheduler.cs +++ b/Svelto.ECS/Extensions/Unity/UnityEntitiesSubmissionScheduler.cs @@ -1,4 +1,5 @@ #if UNITY_5 || UNITY_5_3_OR_NEWER +using System; using Object = UnityEngine.Object; using System.Collections; using UnityEngine; @@ -57,7 +58,10 @@ namespace Svelto.ECS.Schedulers.Unity void SubmitEntities() { if (paused == false) - _onTick.Invoke(); + { + var enumerator = _onTick.Invoke(UInt32.MaxValue); + while (enumerator.MoveNext()) ; + } } protected internal override EnginesRoot.EntitiesSubmitter onTick diff --git a/Svelto.ECS/IEntityFunctions.cs b/Svelto.ECS/IEntityFunctions.cs deleted file mode 100644 index cee25a4..0000000 --- a/Svelto.ECS/IEntityFunctions.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Svelto.ECS -{ - public interface IEntityFunctions - { - //being entity ID globally not unique, the group must be specified when - //an entity is removed. Not specifying the group will attempt to remove - //the entity from the special standard group. - void RemoveEntity(uint entityID, BuildGroup groupID) where T : IEntityDescriptor, new(); - void RemoveEntity(EGID entityegid) where T : IEntityDescriptor, new(); - - void RemoveEntitiesFromGroup(BuildGroup groupID); - - void SwapEntitiesInGroup(BuildGroup fromGroupID, BuildGroup toGroupID) where T : IEntityDescriptor, new(); - - void SwapEntityGroup(uint entityID, BuildGroup fromGroupID, BuildGroup toGroupID) - where T : IEntityDescriptor, new(); - - void SwapEntityGroup(EGID fromID, BuildGroup toGroupID) where T : IEntityDescriptor, new(); - - void SwapEntityGroup(EGID fromID, BuildGroup toGroupID, BuildGroup mustBeFromGroup) - where T : IEntityDescriptor, new(); - - void SwapEntityGroup(EGID fromID, EGID toId) where T : IEntityDescriptor, new(); - - void SwapEntityGroup(EGID fromID, EGID toId, BuildGroup mustBeFromGroup) - where T : IEntityDescriptor, new(); -#if UNITY_NATIVE - NativeEntityRemove ToNativeRemove(string memberName) where T : IEntityDescriptor, new(); - NativeEntitySwap ToNativeSwap(string memberName) where T : IEntityDescriptor, new(); -#endif - } -} \ No newline at end of file diff --git a/Svelto.ECS/Serialization/DefaultVersioningFactory.cs b/Svelto.ECS/Serialization/DefaultVersioningFactory.cs index 2e3dfa4..917b52f 100644 --- a/Svelto.ECS/Serialization/DefaultVersioningFactory.cs +++ b/Svelto.ECS/Serialization/DefaultVersioningFactory.cs @@ -14,7 +14,7 @@ namespace Svelto.ECS.Serialization _implementors = implementors; } - public EntityComponentInitializer BuildDeserializedEntity + public EntityInitializer BuildDeserializedEntity (EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor , int serializationType, IEntitySerialization entitySerialization, IEntityFactory factory , bool enginesRootIsDeserializationOnly) diff --git a/Svelto.ECS/Serialization/EnginesRoot.GenericEntitySerialization.cs b/Svelto.ECS/Serialization/EnginesRoot.GenericEntitySerialization.cs index 98d856f..b2a873d 100644 --- a/Svelto.ECS/Serialization/EnginesRoot.GenericEntitySerialization.cs +++ b/Svelto.ECS/Serialization/EnginesRoot.GenericEntitySerialization.cs @@ -33,7 +33,7 @@ namespace Svelto.ECS } } - public EntityComponentInitializer DeserializeNewEntity + public EntityInitializer DeserializeNewEntity (EGID egid, ISerializationData serializationData, int serializationType) { //todo: SerializableEntityHeader may be needed to be customizable @@ -67,7 +67,7 @@ namespace Svelto.ECS public void DeserializeEntityComponents (ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor - , ref EntityComponentInitializer initializer, int serializationType) + , ref EntityInitializer initializer, int serializationType) { foreach (var serializableEntityBuilder in entityDescriptor.entitiesToSerialize) { diff --git a/Svelto.ECS/Serialization/EntitiesDB.SerializationDescriptorMap.cs b/Svelto.ECS/Serialization/EntitiesDB.SerializationDescriptorMap.cs index e301625..3e14cdb 100644 --- a/Svelto.ECS/Serialization/EntitiesDB.SerializationDescriptorMap.cs +++ b/Svelto.ECS/Serialization/EntitiesDB.SerializationDescriptorMap.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using Svelto.Common; using Svelto.ECS.Serialization; diff --git a/Svelto.ECS/Serialization/IDeserializationFactory.cs b/Svelto.ECS/Serialization/IDeserializationFactory.cs index b35226e..b741b24 100644 --- a/Svelto.ECS/Serialization/IDeserializationFactory.cs +++ b/Svelto.ECS/Serialization/IDeserializationFactory.cs @@ -2,7 +2,7 @@ namespace Svelto.ECS.Serialization { public interface IDeserializationFactory { - EntityComponentInitializer BuildDeserializedEntity + EntityInitializer BuildDeserializedEntity (EGID egid, ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor , int serializationType, IEntitySerialization entitySerialization, IEntityFactory factory , bool enginesRootIsDeserializationOnly); diff --git a/Svelto.ECS/Serialization/IEntitySerialization.cs b/Svelto.ECS/Serialization/IEntitySerialization.cs index 2ff055d..686a52c 100644 --- a/Svelto.ECS/Serialization/IEntitySerialization.cs +++ b/Svelto.ECS/Serialization/IEntitySerialization.cs @@ -29,7 +29,7 @@ namespace Svelto.ECS.Serialization void DeserializeEntity(EGID egid, ISerializationData serializationData, int serializationType); /// - /// Deserialize a serializationData and copy directly to an previously created EntityComponentInitializer + /// Deserialize a serializationData and copy directly to an previously created EntityInitializer /// /// /// @@ -37,7 +37,7 @@ namespace Svelto.ECS.Serialization /// void DeserializeEntityComponents(ISerializationData serializationData, ISerializableEntityDescriptor entityDescriptor, - ref EntityComponentInitializer initializer, int serializationType); + ref EntityInitializer initializer, int serializationType); /// /// Contrary to the other Deserialize methods that assume that the entity exists, this method is used to deserialise @@ -47,7 +47,7 @@ namespace Svelto.ECS.Serialization /// /// /// - EntityComponentInitializer DeserializeNewEntity(EGID egid, ISerializationData serializationData, + EntityInitializer DeserializeNewEntity(EGID egid, ISerializationData serializationData, int serializationType); /// diff --git a/Svelto.ECS/Serialization/ISerializableComponentBuilder.cs b/Svelto.ECS/Serialization/ISerializableComponentBuilder.cs index 2b1e906..a3729a0 100644 --- a/Svelto.ECS/Serialization/ISerializableComponentBuilder.cs +++ b/Svelto.ECS/Serialization/ISerializableComponentBuilder.cs @@ -10,7 +10,7 @@ namespace Svelto.ECS.Serialization void Deserialize(uint id, ITypeSafeDictionary dictionary, ISerializationData serializationData , int serializationType); - void Deserialize(ISerializationData serializationData, in EntityComponentInitializer initializer + void Deserialize(ISerializationData serializationData, in EntityInitializer initializer , int serializationType); } } \ No newline at end of file diff --git a/Svelto.ECS/Serialization/SerializableComponentBuilder.cs b/Svelto.ECS/Serialization/SerializableComponentBuilder.cs index d3ba176..6fbdecf 100644 --- a/Svelto.ECS/Serialization/SerializableComponentBuilder.cs +++ b/Svelto.ECS/Serialization/SerializableComponentBuilder.cs @@ -55,7 +55,7 @@ namespace Svelto.ECS.Serialization } public void Deserialize - (ISerializationData serializationData, in EntityComponentInitializer initializer + (ISerializationData serializationData, in EntityInitializer initializer , int serializationType) { IComponentSerializer componentSerializer = _serializers[(int) serializationType]; diff --git a/Svelto.ECS/SimpleEntitiesSubmissionScheduler.cs b/Svelto.ECS/SimpleEntitiesSubmissionScheduler.cs deleted file mode 100644 index 512a49f..0000000 --- a/Svelto.ECS/SimpleEntitiesSubmissionScheduler.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Svelto.ECS.Schedulers; - -namespace Svelto.ECS.Schedulers -{ - //This scheduler shouldn't be used in production and it's meant to be used for Unit Tests only - public sealed class SimpleEntitiesSubmissionScheduler : ISimpleEntitiesSubmissionScheduler - { - public override void SubmitEntities() - { - if (paused == false) - _onTick.Invoke(); - } - - protected internal override EnginesRoot.EntitiesSubmitter onTick - { - set - { - DBC.ECS.Check.Require(_onTick.IsUnused , "a scheduler can be exclusively used by one enginesRoot only"); - - _onTick = value; - } - } - - public override bool paused { get; set; } - - public override void Dispose() { } - - EnginesRoot.EntitiesSubmitter _onTick; - } -} \ No newline at end of file diff --git a/Svelto.ECS/Svelto.ECS.asmdef b/Svelto.ECS/Svelto.ECS.asmdef index 6ccb718..dc8a20f 100644 --- a/Svelto.ECS/Svelto.ECS.asmdef +++ b/Svelto.ECS/Svelto.ECS.asmdef @@ -1,5 +1,6 @@ { "name": "Svelto.ECS", + "rootNamespace": "", "references": [ "Unity.Entities", "Unity.Collections", @@ -51,6 +52,11 @@ "name": "com.unity.jobs", "expression": "", "define": "UNITY_JOBS" + }, + { + "name": "com.unity.jobs", + "expression": "", + "define": "UNITY_NATIVE" } ], "noEngineReferences": false diff --git a/Svelto.ECS/Svelto.ECS.csproj b/Svelto.ECS/Svelto.ECS.csproj index 1e77aca..d480b8a 100644 --- a/Svelto.ECS/Svelto.ECS.csproj +++ b/Svelto.ECS/Svelto.ECS.csproj @@ -15,8 +15,7 @@ true - - + diff --git a/Svelto.ECS/WaitForSubmissionEnumerator.cs b/Svelto.ECS/WaitForSubmissionEnumerator.cs deleted file mode 100644 index acf4816..0000000 --- a/Svelto.ECS/WaitForSubmissionEnumerator.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections; - -namespace Svelto.ECS -{ - public class WaitForSubmissionEnumerator : IEnumerator - { - class SubmissionEntityDescriptor : GenericEntityDescriptor - { - internal static readonly ExclusiveGroup SubmissionGroup = new ExclusiveGroup(); - } - - readonly IEntityFactory _entityFactory; - readonly EntitiesDB _entitiesDB; - readonly IEntityFunctions _entityFunctions; - - int _state; - - public WaitForSubmissionEnumerator(IEntityFunctions entityFunctions, IEntityFactory entityFactory, - EntitiesDB entitiesDb) - { - _entityFactory = entityFactory; - _entityFunctions = entityFunctions; - _entitiesDB = entitiesDb; - } - - public bool MoveNext() - { - switch (_state) - { - case 0: - _counter = _COUNTER++; - _entityFactory.BuildEntity(new EGID((uint) _counter, - SubmissionEntityDescriptor.SubmissionGroup)); - _state = 1; - return true; - case 1: - if (_entitiesDB.Exists(new EGID((uint) _counter, - SubmissionEntityDescriptor.SubmissionGroup)) == false) - return true; - - _entityFunctions.RemoveEntity(new EGID((uint) _counter, - SubmissionEntityDescriptor.SubmissionGroup)); - _state = 0; - return false; - } - - throw new Exception("something is wrong"); - } - - void IEnumerator.Reset() - { - throw new NotImplementedException(); - } - - public object Current { get; } - - struct SubmissionSignalStruct : IEntityComponent - {} - - int _counter; - static int _COUNTER; - } -} \ No newline at end of file diff --git a/Svelto.ECS/package.json b/Svelto.ECS/package.json index 7a7be4c..58d61f5 100644 --- a/Svelto.ECS/package.json +++ b/Svelto.ECS/package.json @@ -3,13 +3,13 @@ "category": "Svelto", "description": "Svelto ECS C# Lightweight Data Oriented Entity Component System Framework", "dependencies": { - "com.sebaslab.svelto.common": "3.0.0" + "com.sebaslab.svelto.common": "3.1.0" }, "keywords": [ "svelto" ], "name": "com.sebaslab.svelto.ecs", - "unity": "2019.2", - "version": "3.0.0", - "type": "framework" -} + "version": "3.1.0", + "type": "library", + "unity": "2019.3" +} \ No newline at end of file