@@ -1 +1 @@ | |||
Subproject commit ee4913b173b844afcce2ec017abcb0845764db40 | |||
Subproject commit d0e08231b4464226b04c81b6a9aaaf5250200e36 |
@@ -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 | |||
@@ -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")] |
@@ -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); | |||
} |
@@ -1,7 +1,6 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using Svelto.Common; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS |
@@ -0,0 +1,25 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IStepEngine : IEngine | |||
{ | |||
void Step(); | |||
string name { get; } | |||
} | |||
public interface IStepEngine<T> : 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<T> : IStepEngine<T> | |||
{ | |||
} | |||
} |
@@ -3,28 +3,6 @@ using Svelto.Common; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IStepEngine : IEngine | |||
{ | |||
void Step(); | |||
string name { get; } | |||
} | |||
public interface IStepEngine<T> : IEngine | |||
{ | |||
void Step(ref T _param); | |||
string name { get; } | |||
} | |||
public interface IStepGroupEngine : IStepEngine | |||
{ | |||
} | |||
public interface IStepGroupEngine<T> : IStepEngine<T> | |||
{ | |||
} | |||
public abstract class SortedEnginesGroup<Interface, SequenceOrder> : 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<Interface, SequenceOrder> _instancedSequence; | |||
@@ -62,7 +40,7 @@ namespace Svelto.ECS | |||
_instancedSequence = new Sequence<Interface, SequenceOrder>(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); | |||
} | |||
} | |||
} |
@@ -30,4 +30,32 @@ namespace Svelto.ECS | |||
readonly string _name; | |||
readonly FasterList<Interface> _instancedSequence; | |||
} | |||
public abstract class UnsortedEnginesGroup<Interface, Parameter> : IStepGroupEngine<Parameter> | |||
where Interface : IStepEngine<Parameter> | |||
{ | |||
protected UnsortedEnginesGroup(FasterList<Interface> 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<Interface> _instancedSequence; | |||
} | |||
} |
@@ -1,5 +1,4 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS |
@@ -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>(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<EnginesRoot> _weakReference; | |||
} | |||
readonly EntitiesSubmissionScheduler _scheduler; | |||
public IEntitiesSubmissionScheduler scheduler => _scheduler; | |||
readonly EntitiesSubmissionScheduler _scheduler; | |||
public EntitiesSubmissionScheduler scheduler => _scheduler; | |||
/// <summary> | |||
/// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot | |||
@@ -40,15 +53,16 @@ namespace Svelto.ECS | |||
/// </summary> | |||
public EnginesRoot(EntitiesSubmissionScheduler entitiesComponentScheduler) | |||
{ | |||
_entitiesOperations = new ThreadSafeDictionary<ulong, EntitySubmitOperation>(); | |||
serializationDescriptorMap = new SerializationDescriptorMap(); | |||
_reactiveEnginesAddRemove = new FasterDictionary<RefWrapperType, FasterList<IReactEngine>>(); | |||
_reactiveEnginesSwap = new FasterDictionary<RefWrapperType, FasterList<IReactEngine>>(); | |||
_reactiveEnginesSubmission = new FasterList<IReactOnSubmission>(); | |||
_enginesSet = new FasterList<IEngine>(); | |||
_enginesTypeSet = new HashSet<Type>(); | |||
_disposableEngines = new FasterList<IDisposable>(); | |||
_transientEntitiesOperations = new FasterList<EntitySubmitOperation>(); | |||
_entitiesOperations = new FasterDictionary<ulong, EntitySubmitOperation>(); | |||
serializationDescriptorMap = new SerializationDescriptorMap(); | |||
_reactiveEnginesAddRemove = new FasterDictionary<RefWrapperType, FasterList<IReactEngine>>(); | |||
_reactiveEnginesAddRemoveOnDispose = new FasterDictionary<RefWrapperType, FasterList<IReactEngine>>(); | |||
_reactiveEnginesSwap = new FasterDictionary<RefWrapperType, FasterList<IReactEngine>>(); | |||
_reactiveEnginesSubmission = new FasterList<IReactOnSubmission>(); | |||
_enginesSet = new FasterList<IEngine>(); | |||
_enginesTypeSet = new HashSet<Type>(); | |||
_disposableEngines = new FasterList<IDisposable>(); | |||
_transientEntitiesOperations = new FasterList<EntitySubmitOperation>(); | |||
_groupEntityComponentsDB = | |||
new FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>(); | |||
@@ -104,15 +118,13 @@ namespace Svelto.ECS | |||
} | |||
} | |||
foreach (FasterDictionary<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>. | |||
KeyValuePairFast groups in _groupEntityComponentsDB) | |||
foreach (var groups in _groupEntityComponentsDB) | |||
{ | |||
foreach (FasterDictionary<RefWrapperType, ITypeSafeDictionary>.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<ExclusiveGroupStruct, FasterDictionary<RefWrapperType, ITypeSafeDictionary>>. | |||
KeyValuePairFast groups in _groupEntityComponentsDB) | |||
foreach (var groups in _groupEntityComponentsDB) | |||
{ | |||
foreach (FasterDictionary<RefWrapperType, ITypeSafeDictionary>.KeyValuePairFast entityList in groups | |||
.Value) | |||
foreach (var entityList in groups.Value) | |||
entityList.Value.Dispose(); | |||
} | |||
foreach (FasterDictionary<RefWrapperType, FasterDictionary<ExclusiveGroupStruct, GroupFilters>>. | |||
KeyValuePairFast type in _groupFilters) | |||
foreach (FasterDictionary<ExclusiveGroupStruct, GroupFilters>.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<T> | |||
static void AddEngineToList<T> | |||
(T engine, Type[] entityComponentTypes, FasterDictionary<RefWrapperType, FasterList<IReactEngine>> 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<IReactEngine>(); | |||
static void AddEngine<T>(T engine, FasterDictionary<RefWrapperType, FasterList<IReactEngine>> engines, Type type) | |||
where T : class, IReactEngine | |||
{ | |||
if (engines.TryGetValue(new RefWrapperType(type), out var list) == false) | |||
{ | |||
list = new FasterList<IReactEngine>(); | |||
engines.Add(new RefWrapperType(type), list); | |||
} | |||
engines.Add(new RefWrapperType(type), list); | |||
list.Add(engine); | |||
} | |||
list.Add(engine); | |||
} | |||
readonly FasterDictionary<RefWrapperType, FasterList<IReactEngine>> _reactiveEnginesAddRemove; | |||
readonly FasterDictionary<RefWrapperType, FasterList<IReactEngine>> _reactiveEnginesAddRemoveOnDispose; | |||
readonly FasterDictionary<RefWrapperType, FasterList<IReactEngine>> _reactiveEnginesSwap; | |||
readonly FasterList<IReactOnSubmission> _reactiveEnginesSubmission; | |||
readonly FasterList<IDisposable> _disposableEngines; | |||
readonly FasterList<IEngine> _enginesSet; | |||
readonly HashSet<Type> _enginesTypeSet; | |||
internal bool _isDisposing; | |||
readonly FasterList<IReactOnSubmission> _reactiveEnginesSubmission; | |||
readonly FasterList<IDisposable> _disposableEngines; | |||
readonly FasterList<IEngine> _enginesSet; | |||
readonly HashSet<Type> _enginesTypeSet; | |||
internal bool _isDisposing; | |||
} | |||
} |
@@ -29,7 +29,7 @@ namespace Svelto.ECS | |||
///-------------------------------------------- | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
EntityComponentInitializer BuildEntity | |||
EntityInitializer BuildEntity | |||
(EGID entityID, IComponentBuilder[] componentsToBuild, Type descriptorType, | |||
IEnumerable<object> 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<RefWrapperType, ITypeSafeDictionary>.KeyValuePairFast dictionaryOfEntities | |||
in dictionariesOfEntities) | |||
foreach (var dictionaryOfEntities in dictionariesOfEntities) | |||
{ | |||
dictionaryOfEntities.Value.ExecuteEnginesRemoveCallbacks(_reactiveEnginesAddRemove, profiler | |||
, new ExclusiveGroupStruct(groupID)); |
@@ -13,8 +13,8 @@ namespace Svelto.ECS | |||
_enginesRoot = new Svelto.DataStructures.WeakReference<EnginesRoot>(weakReference); | |||
} | |||
public EntityComponentInitializer BuildEntity<T> | |||
(uint entityID, BuildGroup groupStructId, IEnumerable<object> implementors = null) | |||
public EntityInitializer BuildEntity<T> | |||
(uint entityID, ExclusiveBuildGroup groupStructId, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId) | |||
@@ -22,26 +22,26 @@ namespace Svelto.ECS | |||
, TypeCache<T>.type, implementors); | |||
} | |||
public EntityComponentInitializer BuildEntity<T>(EGID egid, IEnumerable<object> implementors = null) | |||
public EntityInitializer BuildEntity<T>(EGID egid, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
return _enginesRoot.Target.BuildEntity( | |||
egid, EntityDescriptorTemplate<T>.descriptor.componentsToBuild, TypeCache<T>.type, implementors); | |||
} | |||
public EntityComponentInitializer BuildEntity<T> | |||
public EntityInitializer BuildEntity<T> | |||
(EGID egid, T entityDescriptor, IEnumerable<object> implementors) where T : IEntityDescriptor | |||
{ | |||
return _enginesRoot.Target.BuildEntity(egid, entityDescriptor.componentsToBuild, TypeCache<T>.type, implementors); | |||
} | |||
#if UNITY_NATIVE | |||
public NativeEntityFactory ToNative<T>(string memberName) where T : IEntityDescriptor, new() | |||
public NativeEntityFactory ToNative<T>(string callerName) where T : IEntityDescriptor, new() | |||
{ | |||
return _enginesRoot.Target.ProvideNativeEntityFactoryQueue<T>(memberName); | |||
return _enginesRoot.Target.ProvideNativeEntityFactoryQueue<T>(callerName); | |||
} | |||
#endif | |||
public EntityComponentInitializer BuildEntity<T> | |||
(uint entityID, BuildGroup groupStructId, T descriptorEntity, IEnumerable<object> implementors) | |||
public EntityInitializer BuildEntity<T> | |||
(uint entityID, ExclusiveBuildGroup groupStructId, T descriptorEntity, IEnumerable<object> implementors) | |||
where T : IEntityDescriptor | |||
{ | |||
return _enginesRoot.Target.BuildEntity(new EGID(entityID, groupStructId) | |||
@@ -54,7 +54,7 @@ namespace Svelto.ECS | |||
_enginesRoot.Target.Preallocate<T>(groupStructId, size); | |||
} | |||
public EntityComponentInitializer BuildEntity(EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable<object> implementors = null) | |||
public EntityInitializer BuildEntity(EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable<object> implementors = null) | |||
{ | |||
return _enginesRoot.Target.BuildEntity(egid, componentsToBuild, type, implementors); | |||
} |
@@ -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<T>(uint entityID, BuildGroup groupID) where T : | |||
public void RemoveEntity<T>(uint entityID, ExclusiveBuildGroup groupID, [CallerMemberName] string memberName = "") where T : | |||
IEntityDescriptor, new() | |||
{ | |||
RemoveEntity<T>(new EGID(entityID, groupID)); | |||
RemoveEntity<T>(new EGID(entityID, groupID), memberName); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void RemoveEntity<T>(EGID entityEGID) where T : IEntityDescriptor, new() | |||
public void RemoveEntity<T>(EGID entityEGID, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new() | |||
{ | |||
DBC.ECS.Check.Require(entityEGID.groupID != 0, "invalid group detected"); | |||
var descriptorComponentsToBuild = EntityDescriptorTemplate<T>.descriptor.componentsToBuild; | |||
_enginesRoot.Target.CheckRemoveEntityID(entityEGID, TypeCache<T>.type); | |||
_enginesRoot.Target.CheckRemoveEntityID(entityEGID, TypeCache<T>.type, memberName); | |||
_enginesRoot.Target.QueueEntitySubmitOperation<T>( | |||
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<T>(BuildGroup fromGroupID, BuildGroup toGroupID) | |||
public void SwapEntitiesInGroup<T>(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<T>(uint entityID, BuildGroup fromGroupID, | |||
BuildGroup toGroupID) | |||
public void SwapEntityGroup<T>(uint entityID, ExclusiveBuildGroup fromGroupID, | |||
ExclusiveBuildGroup toGroupID) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
SwapEntityGroup<T>(new EGID(entityID, fromGroupID), toGroupID); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(EGID fromID, BuildGroup toGroupID) | |||
public void SwapEntityGroup<T>(EGID fromID, ExclusiveBuildGroup toGroupID) | |||
where T : IEntityDescriptor, new() | |||
{ | |||
SwapEntityGroup<T>(fromID, new EGID(fromID.entityID, (uint) toGroupID)); | |||
} | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public void SwapEntityGroup<T>(EGID fromID, BuildGroup toGroupID | |||
, BuildGroup mustBeFromGroup) | |||
public void SwapEntityGroup<T>(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<T>(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; | |||
} | |||
} | |||
} |
@@ -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<EntitySubmitOperation> _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 | |||
/// </summary> | |||
/// <param name="profiler"></param> | |||
void SingleSubmission(in PlatformProfiler profiler) | |||
/// <param name="maxNumberOfOperations"></param> | |||
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<ulong, EntitySubmitOperation> _entitiesOperations; | |||
readonly FasterDictionary<ulong, EntitySubmitOperation> _entitiesOperations; | |||
} | |||
} |
@@ -6,16 +6,17 @@ namespace Svelto.ECS | |||
{ | |||
public readonly ref struct EntityCollection<T> where T : struct, IEntityComponent | |||
{ | |||
static readonly bool IsUnmanaged = TypeSafeDictionary<T>.IsUnmanaged; | |||
public EntityCollection(IBuffer<T> buffer, uint count):this() | |||
static readonly bool IsUnmanaged = TypeSafeDictionary<T>.IsUnmanaged; | |||
public EntityCollection(IBuffer<T> buffer, uint count) : this() | |||
{ | |||
DBC.ECS.Check.Require(count == 0 || buffer.isValid, "Buffer is found in impossible state"); | |||
if (IsUnmanaged) | |||
_nativedBuffer = (NB<T>) buffer; | |||
else | |||
_managedBuffer = (MB<T>) buffer; | |||
_count = count; | |||
_count = count; | |||
} | |||
public uint count => _count; | |||
@@ -26,7 +27,8 @@ namespace Svelto.ECS | |||
readonly uint _count; | |||
} | |||
public readonly ref struct EntityCollection<T1, T2> where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent | |||
public readonly ref struct EntityCollection<T1, T2> | |||
where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent | |||
{ | |||
internal EntityCollection(in EntityCollection<T1> array1, in EntityCollection<T2> array2) | |||
{ | |||
@@ -89,14 +91,14 @@ namespace Svelto.ECS | |||
readonly EntityCollection<T3> _array3; | |||
} | |||
public readonly ref struct EntityCollection<T1, T2, T3, T4> | |||
where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
public readonly ref struct EntityCollection<T1, T2, T3, T4> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
{ | |||
internal EntityCollection | |||
(in EntityCollection<T1> array1, in EntityCollection<T2> array2, in EntityCollection<T3> array3, in EntityCollection<T4> array4) | |||
(in EntityCollection<T1> array1, in EntityCollection<T2> array2, in EntityCollection<T3> array3 | |||
, in EntityCollection<T4> array4) | |||
{ | |||
_array1 = array1; | |||
_array2 = array2; | |||
@@ -104,25 +106,25 @@ namespace Svelto.ECS | |||
_array4 = array4; | |||
} | |||
internal EntityCollection<T1> Item1 | |||
internal EntityCollection<T1> buffer1 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _array1; | |||
} | |||
internal EntityCollection<T2> Item2 | |||
internal EntityCollection<T2> buffer2 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _array2; | |||
} | |||
internal EntityCollection<T3> Item3 | |||
internal EntityCollection<T3> buffer3 | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _array3; | |||
} | |||
internal EntityCollection<T4> Item4 | |||
internal EntityCollection<T4> 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<BufferT1> | |||
{ | |||
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<BufferT1> 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; | |||
} | |||
} | |||
} | |||
} |
@@ -6,6 +6,19 @@ namespace Svelto.ECS | |||
/// <summary> | |||
/// 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<BaseDescriptor> | |||
/// { | |||
/// public SpecialisedDescriptor() : base (new IComponentBuilder[] | |||
/// { | |||
/// new ComponentBuilder<ObjectParentComponent>() //add more components to the base descriptor | |||
/// }) | |||
/// { | |||
/// ExtendWith<ContractDescriptor>(); //add extra components from descriptors that act as contract | |||
/// } | |||
/// } | |||
/// </summary> | |||
/// <typeparam name="TType"></typeparam> | |||
public class ExtendibleEntityDescriptor<TType> : IDynamicEntityDescriptor where TType : IEntityDescriptor, new() |
@@ -0,0 +1,6 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IDynamicEntityDescriptor: IEntityDescriptor | |||
{ | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityDescriptor | |||
{ | |||
IComponentBuilder[] componentsToBuild { get; } | |||
} | |||
} |
@@ -2,15 +2,6 @@ using System; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityDescriptor | |||
{ | |||
IComponentBuilder[] componentsToBuild { get; } | |||
} | |||
public interface IDynamicEntityDescriptor: IEntityDescriptor | |||
{ | |||
} | |||
static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
{ | |||
static EntityDescriptorTemplate() |
@@ -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<RefWrapperType, ITypeSafeDictionary> group) | |||
public EntityInitializer(EGID id, FasterDictionary<RefWrapperType, ITypeSafeDictionary> group) | |||
{ | |||
_group = group; | |||
_ID = id; |
@@ -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; | |||
} | |||
} |
@@ -1,4 +1,3 @@ | |||
using System; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
@@ -99,7 +98,7 @@ namespace Svelto.ECS | |||
#endif | |||
return ref _filters[TypeRefWrapper<T>.wrapper][groupID].GetFilter(filterId); | |||
} | |||
public bool TryGetFilterForGroup<T>(int filterId, ExclusiveGroupStruct groupID, out FilterGroup groupFilter) | |||
where T : struct, IEntityComponent | |||
{ |
@@ -8,14 +8,28 @@ namespace Svelto.ECS | |||
public FilteredIndices(NativeDynamicArrayCast<uint> 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<uint> _denseListOfIndicesToEntityComponentArray; | |||
readonly int _count; | |||
} | |||
} |
@@ -40,7 +40,7 @@ namespace Svelto.ECS | |||
return filters.TryGetValue(filterIndex, out filter); | |||
} | |||
public SveltoDictionary<int, FilterGroup, NativeStrategy<FasterDictionaryNode<int>>, NativeStrategy<FilterGroup> | |||
public SveltoDictionary<int, FilterGroup, NativeStrategy<SveltoDictionaryNode<int>>, NativeStrategy<FilterGroup> | |||
, NativeStrategy<int>>.SveltoDictionaryKeyValueEnumerator GetEnumerator() | |||
{ | |||
return filters.GetEnumerator(); |
@@ -16,7 +16,7 @@ namespace Svelto.ECS | |||
interface IFiller | |||
{ | |||
void FillFromByteArray(EntityComponentInitializer init, NativeBag buffer); | |||
void FillFromByteArray(EntityInitializer init, NativeBag buffer); | |||
} | |||
class Filler<T> : 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<T>(); | |||
@@ -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; } | |||
} | |||
} |
@@ -1,6 +1,5 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Runtime.CompilerServices; | |||
#pragma warning disable 660,661 | |||
@@ -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<ExclusiveGroupStruct>, IComparable<ExclusiveGroupStruct>, | |||
IEqualityComparer<ExclusiveGroupStruct> |
@@ -20,7 +20,7 @@ namespace Svelto.ECS | |||
static readonly FasterList<ExclusiveGroupStruct> _Groups; | |||
public static FasterReadOnlyList<ExclusiveGroupStruct> Groups => new FasterReadOnlyList<ExclusiveGroupStruct>(_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<ExclusiveGroupStruct> Groups => | |||
new FasterReadOnlyList<ExclusiveGroupStruct>(_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<ExclusiveGroupStruct> Groups => | |||
new FasterReadOnlyList<ExclusiveGroupStruct>(_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<ExclusiveGroupStruct> Groups => | |||
new FasterReadOnlyList<ExclusiveGroupStruct>(_Groups); | |||
public static BuildGroup BuildGroup => new BuildGroup(_Groups[0]); | |||
public static ExclusiveBuildGroup BuildGroup => new ExclusiveBuildGroup(_Groups[0]); | |||
static GroupTag() | |||
{ |
@@ -0,0 +1,13 @@ | |||
using System.Runtime.InteropServices; | |||
namespace Svelto.ECS.Hybrid | |||
{ | |||
public struct ValueReference<T> where T:class, IImplementor | |||
{ | |||
public ValueReference(T obj) { _pointer = GCHandle.Alloc(obj, GCHandleType.Normal); } | |||
public static explicit operator T(ValueReference<T> t) => (T) t._pointer.Target; | |||
GCHandle _pointer; | |||
} | |||
} |
@@ -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<T> : IReactOnDispose where T : IEntityComponent | |||
{ | |||
void Remove(ref T entityComponent, EGID egid); | |||
} | |||
public interface IReactOnSwap<T> : IReactOnSwap where T : IEntityComponent | |||
{ | |||
void MovedTo(ref T entityComponent, ExclusiveGroupStruct previousGroup, EGID egid); |
@@ -0,0 +1,7 @@ | |||
namespace Svelto.ECS | |||
{ | |||
///<summary>Entity Components MUST implement IEntityComponent</summary> | |||
public interface IEntityComponent | |||
{ | |||
} | |||
} |
@@ -43,25 +43,25 @@ namespace Svelto.ECS | |||
/// <param name="groupStructId"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
EntityComponentInitializer BuildEntity<T>(uint entityID, BuildGroup groupStructId, | |||
EntityInitializer BuildEntity<T>(uint entityID, ExclusiveBuildGroup groupStructId, | |||
IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor, new(); | |||
EntityComponentInitializer BuildEntity<T>(EGID egid, IEnumerable<object> implementors = null) | |||
EntityInitializer BuildEntity<T>(EGID egid, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor, new(); | |||
EntityComponentInitializer BuildEntity<T>(uint entityID, BuildGroup groupStructId, | |||
EntityInitializer BuildEntity<T>(uint entityID, ExclusiveBuildGroup groupStructId, | |||
T descriptorEntity, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor; | |||
EntityComponentInitializer BuildEntity<T>(EGID egid, T entityDescriptor, IEnumerable<object> implementors = null) | |||
EntityInitializer BuildEntity<T>(EGID egid, T entityDescriptor, IEnumerable<object> implementors = null) | |||
where T : IEntityDescriptor; | |||
EntityComponentInitializer BuildEntity | |||
EntityInitializer BuildEntity | |||
(EGID egid, IComponentBuilder[] componentsToBuild, Type type, IEnumerable<object> implementors = null); | |||
#if UNITY_NATIVE | |||
NativeEntityFactory ToNative<T>(string memberName) where T : IEntityDescriptor, new(); | |||
NativeEntityFactory ToNative<T>(string callerName) where T : IEntityDescriptor, new(); | |||
#endif | |||
} | |||
} |
@@ -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<T>(uint entityID, ExclusiveBuildGroup groupID, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new(); | |||
void RemoveEntity<T>(EGID entityegid, [CallerMemberName] string memberName = "") where T : IEntityDescriptor, new(); | |||
void RemoveEntitiesFromGroup(ExclusiveBuildGroup groupID); | |||
void SwapEntitiesInGroup<T>(ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(uint entityID, ExclusiveBuildGroup fromGroupID, ExclusiveBuildGroup toGroupID) | |||
where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, ExclusiveBuildGroup toGroupID) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, ExclusiveBuildGroup toGroupID, ExclusiveBuildGroup mustBeFromGroup) | |||
where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, EGID toId) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, EGID toId, ExclusiveBuildGroup mustBeFromGroup) | |||
where T : IEntityDescriptor, new(); | |||
#if UNITY_NATIVE | |||
NativeEntityRemove ToNativeRemove<T>(string memberName) where T : IEntityDescriptor, new(); | |||
NativeEntitySwap ToNativeSwap<T>(string memberName) where T : IEntityDescriptor, new(); | |||
#endif | |||
} | |||
} |
@@ -1,10 +1,5 @@ | |||
namespace Svelto.ECS | |||
{ | |||
///<summary>Entity Components MUST implement IEntityComponent</summary> | |||
public interface IEntityComponent | |||
{ | |||
} | |||
/// <summary> | |||
/// use INeedEGID on an IEntityComponent only if you need the EGID. consider using EGIDComponent instead | |||
/// </summary> |
@@ -1,5 +1,3 @@ | |||
using System.Runtime.CompilerServices; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
delegate void SetEGIDWithoutBoxingActionCast<T>(ref T target, EGID egid) where T : struct, IEntityComponent; |
@@ -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; | |||
} | |||
} |
@@ -0,0 +1,546 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public readonly ref struct DoubleEntitiesEnumerator<T1> where T1 : struct, IEntityComponent | |||
{ | |||
public DoubleEntitiesEnumerator(GroupsEnumerable<T1> groupsEnumerable) { _groupsEnumerable = groupsEnumerable; } | |||
public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } | |||
readonly GroupsEnumerable<T1> _groupsEnumerable; | |||
public ref struct EntityGroupsIterator | |||
{ | |||
public EntityGroupsIterator(GroupsEnumerable<T1> 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<T1>.GroupsIterator _groupsEnumerableA; | |||
GroupsEnumerable<T1>.GroupsIterator _groupsEnumerableB; | |||
int _indexA; | |||
int _indexB; | |||
} | |||
public ref struct ValueRef | |||
{ | |||
public readonly GroupsEnumerable<T1>.RefCurrent _current; | |||
public readonly int _indexA; | |||
public readonly GroupsEnumerable<T1>.RefCurrent _refCurrent; | |||
public readonly int _indexB; | |||
public ValueRef | |||
(GroupsEnumerable<T1>.RefCurrent current, int indexA, GroupsEnumerable<T1>.RefCurrent refCurrent | |||
, int indexB) | |||
{ | |||
_current = current; | |||
_indexA = indexA; | |||
_refCurrent = refCurrent; | |||
_indexB = indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1> buffers, out int indexA, out EntityCollection<T1> refCurrent, out int indexB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1> buffers, out int indexA, out ExclusiveGroupStruct groupA | |||
, out EntityCollection<T1> 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<T1, T2> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
{ | |||
public DoubleIterationEnumerator(GroupsEnumerable<T1, T2> groupsEnumerable) | |||
{ | |||
_groupsEnumerable = groupsEnumerable; | |||
} | |||
public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } | |||
readonly GroupsEnumerable<T1, T2> _groupsEnumerable; | |||
public ref struct EntityGroupsIterator | |||
{ | |||
public EntityGroupsIterator(GroupsEnumerable<T1, T2> 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<T1, T2>.GroupsIterator _groupsEnumerableA; | |||
GroupsEnumerable<T1, T2>.GroupsIterator _groupsEnumerableB; | |||
int _indexA; | |||
int _indexB; | |||
} | |||
public ref struct ValueRef | |||
{ | |||
public readonly GroupsEnumerable<T1, T2>.RefCurrent _current; | |||
public readonly int _indexA; | |||
public readonly GroupsEnumerable<T1, T2>.RefCurrent _refCurrent; | |||
public readonly int _indexB; | |||
public ValueRef | |||
(GroupsEnumerable<T1, T2>.RefCurrent current, int indexA, GroupsEnumerable<T1, T2>.RefCurrent refCurrent | |||
, int indexB) | |||
{ | |||
_current = current; | |||
_indexA = indexA; | |||
_refCurrent = refCurrent; | |||
_indexB = indexB; | |||
} | |||
public void Deconstruct(out EntityCollection<T1, T2> buffers, out int indexA, | |||
out EntityCollection<T1, T2> refCurrent, out int indexB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1, T2> buffers, out int indexA, out ExclusiveGroupStruct groupA | |||
, out EntityCollection<T1, T2> refCurrent, out int indexB, out ExclusiveGroupStruct groupB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
groupA = _current._group; | |||
groupB = _refCurrent._group; | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Special Enumerator to iterate a group of entities against themselves with complexity n*(n+1)/2 (skips already tested couples) | |||
/// </summary> | |||
/// <typeparam name="T1"></typeparam> | |||
/// <typeparam name="T2"></typeparam> | |||
/// <typeparam name="T3"></typeparam> | |||
public readonly ref struct DoubleEntitiesEnumerator<T1, T2, T3> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
{ | |||
public DoubleEntitiesEnumerator(GroupsEnumerable<T1, T2, T3> groupsEnumerable) | |||
{ | |||
_groupsEnumerable = groupsEnumerable; | |||
} | |||
public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } | |||
readonly GroupsEnumerable<T1, T2, T3> _groupsEnumerable; | |||
public ref struct EntityGroupsIterator | |||
{ | |||
public EntityGroupsIterator(GroupsEnumerable<T1, T2, T3> 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<T1, T2, T3>.GroupsIterator _groupsEnumerableA; | |||
GroupsEnumerable<T1, T2, T3>.GroupsIterator _groupsEnumerableB; | |||
int _indexA; | |||
int _indexB; | |||
} | |||
public ref struct ValueRef | |||
{ | |||
public readonly GroupsEnumerable<T1, T2, T3>.RefCurrent _current; | |||
public readonly int _indexA; | |||
public readonly GroupsEnumerable<T1, T2, T3>.RefCurrent _refCurrent; | |||
public readonly int _indexB; | |||
public ValueRef | |||
(GroupsEnumerable<T1, T2, T3>.RefCurrent current, int indexA | |||
, GroupsEnumerable<T1, T2, T3>.RefCurrent refCurrent, int indexB) | |||
{ | |||
_current = current; | |||
_indexA = indexA; | |||
_refCurrent = refCurrent; | |||
_indexB = indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1, T2, T3> buffers, out int indexA, out EntityCollection<T1, T2, T3> refCurrent | |||
, out int indexB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1, T2, T3> buffers, out int indexA, out ExclusiveGroupStruct groupA | |||
, out EntityCollection<T1, T2, T3> refCurrent, out int indexB, out ExclusiveGroupStruct groupB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
groupA = _current._group; | |||
groupB = _refCurrent._group; | |||
} | |||
} | |||
} | |||
/// <summary> | |||
/// Special Enumerator to iterate a group of entities against themselves with complexity n*(n+1)/2 (skips already tested couples) | |||
/// </summary> | |||
/// <typeparam name="T1"></typeparam> | |||
/// <typeparam name="T2"></typeparam> | |||
/// <typeparam name="T3"></typeparam> | |||
/// <typeparam name="T4"></typeparam> | |||
public readonly ref struct DoubleEntitiesEnumerator<T1, T2, T3, T4> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
{ | |||
public DoubleEntitiesEnumerator(GroupsEnumerable<T1, T2, T3, T4> groupsEnumerable) | |||
{ | |||
_groupsEnumerable = groupsEnumerable; | |||
} | |||
public EntityGroupsIterator GetEnumerator() { return new EntityGroupsIterator(_groupsEnumerable); } | |||
readonly GroupsEnumerable<T1, T2, T3, T4> _groupsEnumerable; | |||
public ref struct EntityGroupsIterator | |||
{ | |||
public EntityGroupsIterator(GroupsEnumerable<T1, T2, T3, T4> 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<T1, T2, T3, T4>.GroupsIterator _groupsEnumerableA; | |||
GroupsEnumerable<T1, T2, T3, T4>.GroupsIterator _groupsEnumerableB; | |||
int _indexA; | |||
int _indexB; | |||
} | |||
public ref struct ValueRef | |||
{ | |||
public readonly GroupsEnumerable<T1, T2, T3, T4>.RefCurrent _current; | |||
public readonly int _indexA; | |||
public readonly GroupsEnumerable<T1, T2, T3, T4>.RefCurrent _refCurrent; | |||
public readonly int _indexB; | |||
public ValueRef | |||
(GroupsEnumerable<T1, T2, T3, T4>.RefCurrent current, int indexA | |||
, GroupsEnumerable<T1, T2, T3, T4>.RefCurrent refCurrent, int indexB) | |||
{ | |||
_current = current; | |||
_indexA = indexA; | |||
_refCurrent = refCurrent; | |||
_indexB = indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1, T2, T3, T4> buffers, out int indexA, out EntityCollection<T1, T2, T3, T4> refCurrent | |||
, out int indexB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
} | |||
public void Deconstruct | |||
(out EntityCollection<T1, T2, T3, T4> buffers, out int indexA, out ExclusiveGroupStruct groupA | |||
, out EntityCollection<T1, T2, T3, T4> refCurrent, out int indexB, out ExclusiveGroupStruct groupB) | |||
{ | |||
buffers = _current._buffers; | |||
indexA = _indexA; | |||
refCurrent = _refCurrent._buffers; | |||
indexB = _indexB; | |||
groupA = _current._group; | |||
groupB = _refCurrent._group; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,48 @@ | |||
using System; | |||
using System.Collections; | |||
using Svelto.ECS.Schedulers; | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// Enumerator that yields until the next Entities Submission | |||
/// </summary> | |||
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; | |||
} | |||
} |
@@ -1,5 +1,4 @@ | |||
using System; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.CompilerServices; | |||
namespace Svelto.ECS | |||
{ |
@@ -15,21 +15,21 @@ namespace Svelto.ECS.Internal | |||
internal static readonly bool IsUnmanaged = | |||
_type.IsUnmanagedEx() && (typeof(IEntityViewComponent).IsAssignableFrom(_type) == false); | |||
SveltoDictionary<uint, TValue, NativeStrategy<FasterDictionaryNode<uint>>, ManagedStrategy<TValue>, | |||
SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, ManagedStrategy<TValue>, | |||
ManagedStrategy<int>> implMgd; | |||
//used directly by native methods | |||
internal SveltoDictionary<uint, TValue, NativeStrategy<FasterDictionaryNode<uint>>, NativeStrategy<TValue>, | |||
internal SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, NativeStrategy<TValue>, | |||
NativeStrategy<int>> implUnmgd; | |||
public TypeSafeDictionary(uint size) | |||
{ | |||
if (IsUnmanaged) | |||
implUnmgd = new SveltoDictionary<uint, TValue, NativeStrategy<FasterDictionaryNode<uint>>, | |||
implUnmgd = new SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<TValue>, NativeStrategy<int>>(size); | |||
else | |||
{ | |||
implMgd = new SveltoDictionary<uint, TValue, NativeStrategy<FasterDictionaryNode<uint>>, | |||
implMgd = new SveltoDictionary<uint, TValue, NativeStrategy<SveltoDictionaryNode<uint>>, | |||
ManagedStrategy<TValue>, ManagedStrategy<int>>(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)); | |||
} | |||
} | |||
@@ -9,7 +9,6 @@ | |||
using System; | |||
using System.Diagnostics; | |||
using System.Runtime.CompilerServices; | |||
using System.Threading; | |||
using Svelto.Common; | |||
namespace Svelto.ECS.DataStructures | |||
@@ -9,7 +9,11 @@ namespace Svelto.ECS.DataStructures | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public int Count() => _array.Count<T>(); | |||
public int count => _array.Count<T>(); | |||
public int count | |||
{ | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
get => _array.Count<T>(); | |||
} | |||
public ref T this[int index] | |||
{ | |||
@@ -1,5 +1,4 @@ | |||
using System; | |||
using System.Runtime.InteropServices; | |||
using System.Threading; | |||
using Svelto.Common; | |||
@@ -8,7 +8,9 @@ namespace Svelto.ECS | |||
{ | |||
_value = initialValue; | |||
} | |||
public DispatchOnChange(EGID senderID, Action<EGID, T> callback) : base(senderID, callback) {} | |||
public new T value | |||
{ | |||
set | |||
@@ -4,11 +4,12 @@ namespace Svelto.ECS | |||
{ | |||
public class DispatchOnSet<T> | |||
{ | |||
public DispatchOnSet(EGID senderID) | |||
{ | |||
_senderID = senderID; | |||
public DispatchOnSet(EGID senderID, Action<EGID, T> 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<EGID, T> 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<EGID, T> _subscriber; | |||
bool _paused; | |||
} | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -19,15 +19,12 @@ namespace Svelto.ECS | |||
public void Deconstruct(out EntityCollection<T1> 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<ExclusiveGroupStruct, ITypeSafeDictionary>.KeyValuePairFast group = _db.Current; | |||
var group = _db.Current; | |||
ITypeSafeDictionary<T1> typeSafeDictionary = @group.Value as ITypeSafeDictionary<T1>; | |||
if (typeSafeDictionary.count == 0) continue; | |||
if (typeSafeDictionary.count == 0) | |||
continue; | |||
_array.collection = new EntityCollection<T1>(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<ExclusiveGroupStruct, ITypeSafeDictionary>.FasterDictionaryKeyValueEnumerator _db; | |||
SveltoDictionary<ExclusiveGroupStruct, ITypeSafeDictionary, | |||
ManagedStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, ManagedStrategy<ITypeSafeDictionary>, | |||
ManagedStrategy<int>>.SveltoDictionaryKeyValueEnumerator _db; | |||
GroupCollection _array; | |||
} | |||
public GroupsIterator GetEnumerator() | |||
{ | |||
return new GroupsIterator(_db); | |||
} | |||
public GroupsIterator GetEnumerator() { return new GroupsIterator(_db); } | |||
readonly EntitiesDB _db; | |||
readonly EntitiesDB _db; | |||
} | |||
} | |||
} |
@@ -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<T1>, NB<T2>, NB<T3>, NB<T4>>(ec.Item1._nativedBuffer, ec.Item2._nativedBuffer | |||
, ec.Item3._nativedBuffer, ec.Item4._nativedBuffer, ec.count); | |||
return new BT<NB<T1>, NB<T2>, NB<T3>, NB<T4>>(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; | |||
} | |||
} |
@@ -17,9 +17,6 @@ namespace Svelto.ECS | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
{ | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList<ExclusiveGroupStruct> groups) | |||
{ | |||
_db = db; | |||
@@ -52,7 +49,8 @@ namespace Svelto.ECS | |||
var array = entityCollection1; | |||
var array2 = entityCollection2; | |||
_buffers = new EntityCollection<T1, T2, T3, T4>(array.buffer1, array.buffer2, array.buffer3, array2); | |||
_buffers = new EntityCollection<T1, T2, T3, T4>(array.buffer1, array.buffer2, array.buffer3 | |||
, array2); | |||
break; | |||
} | |||
@@ -66,7 +64,8 @@ namespace Svelto.ECS | |||
public void Reset() { _indexGroup = -1; } | |||
public RefCurrent<T1, T2, T3, T4> Current => new RefCurrent<T1, T2, T3, T4>(_buffers, _groups[_indexGroup]); | |||
public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); | |||
public bool isValid => _indexGroup != -1; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
@@ -76,44 +75,36 @@ namespace Svelto.ECS | |||
} | |||
public GroupsIterator GetEnumerator() { return new GroupsIterator(_db, _groups); } | |||
} | |||
public ref struct RefCurrent<T1, T2, T3, T4> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
where T4 : struct, IEntityComponent | |||
{ | |||
public RefCurrent(in EntityCollection<T1, T2, T3, T4> buffers, ExclusiveGroupStruct group) | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
public void Deconstruct(out EntityCollection<T1, T2, T3, T4> buffers, out ExclusiveGroupStruct group) | |||
public ref struct RefCurrent | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public RefCurrent(in EntityCollection<T1, T2, T3, T4> buffers, ExclusiveGroupStruct group) | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
public readonly EntityCollection<T1, T2, T3, T4> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
public void Deconstruct(out EntityCollection<T1, T2, T3, T4> buffers, out ExclusiveGroupStruct group) | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public readonly EntityCollection<T1, T2, T3, T4> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
} | |||
} | |||
/// <summary> | |||
/// ToDo source gen could return the implementation of IBuffer directly, but cannot be done manually | |||
/// </summary> | |||
/// <typeparam name="T1"></typeparam> | |||
/// <typeparam name="T2"></typeparam> | |||
/// <typeparam name="T3"></typeparam> | |||
public readonly ref struct GroupsEnumerable<T1, T2, T3> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
{ | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
public GroupsEnumerable(EntitiesDB db, in LocalFasterReadOnlyList<ExclusiveGroupStruct> 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<T1, T2, T3> Current => new RefCurrent<T1, T2, T3>(_buffers, _groups[_indexGroup]); | |||
public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); | |||
public bool isValid => _indexGroup != -1; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
@@ -160,26 +152,27 @@ namespace Svelto.ECS | |||
} | |||
public GroupsIterator GetEnumerator() { return new GroupsIterator(_db, _groups); } | |||
} | |||
public ref struct RefCurrent<T1, T2, T3> where T1 : struct, IEntityComponent | |||
where T2 : struct, IEntityComponent | |||
where T3 : struct, IEntityComponent | |||
{ | |||
public RefCurrent(in EntityCollection<T1, T2, T3> buffers, ExclusiveGroupStruct group) | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
public void Deconstruct(out EntityCollection<T1, T2, T3> buffers, out ExclusiveGroupStruct group) | |||
public ref struct RefCurrent | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public RefCurrent(in EntityCollection<T1, T2, T3> buffers, ExclusiveGroupStruct group) | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
public void Deconstruct(out EntityCollection<T1, T2, T3> buffers, out ExclusiveGroupStruct group) | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public readonly EntityCollection<T1, T2, T3> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
public readonly EntityCollection<T1, T2, T3> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
} | |||
} | |||
public readonly ref struct GroupsEnumerable<T1, T2> | |||
@@ -223,7 +216,8 @@ namespace Svelto.ECS | |||
public void Reset() { _indexGroup = -1; } | |||
public RefCurrent<T1, T2> Current => new RefCurrent<T1, T2>(_buffers, _groups[_indexGroup]); | |||
public RefCurrent Current => new RefCurrent(_buffers, _groups[_indexGroup]); | |||
public bool isValid => _indexGroup != -1; | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
@@ -236,24 +230,24 @@ namespace Svelto.ECS | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
} | |||
public ref struct RefCurrent<T1, T2> where T1 : struct, IEntityComponent where T2 : struct, IEntityComponent | |||
{ | |||
public RefCurrent(in EntityCollection<T1, T2> buffers, ExclusiveGroupStruct group) | |||
public ref struct RefCurrent | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
public RefCurrent(in EntityCollection<T1, T2> buffers, ExclusiveGroupStruct group) | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
public void Deconstruct(out EntityCollection<T1, T2> buffers, out ExclusiveGroupStruct group) | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public void Deconstruct(out EntityCollection<T1, T2> buffers, out ExclusiveGroupStruct group) | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public readonly EntityCollection<T1, T2> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
public readonly EntityCollection<T1, T2> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
} | |||
} | |||
public readonly ref struct GroupsEnumerable<T1> 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<T1> Current => new RefCurrent<T1>(_buffer, _groups[_indexGroup]); | |||
public RefCurrent Current => new RefCurrent(_buffer, _groups[_indexGroup]); | |||
public bool isValid => _indexGroup != -1; | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
@@ -304,23 +304,28 @@ namespace Svelto.ECS | |||
readonly EntitiesDB _db; | |||
readonly LocalFasterReadOnlyList<ExclusiveGroupStruct> _groups; | |||
} | |||
public ref struct RefCurrent<T1> where T1 : struct, IEntityComponent | |||
{ | |||
public RefCurrent(in EntityCollection<T1> buffers, ExclusiveGroupStruct group) | |||
public readonly ref struct RefCurrent | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
public RefCurrent(in EntityCollection<T1> buffers, in ExclusiveGroupStruct group) | |||
{ | |||
_buffers = buffers; | |||
_group = group; | |||
} | |||
public void Deconstruct(out EntityCollection<T1> buffers, out ExclusiveGroupStruct group) | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public void Deconstruct(out EntityCollection<T1> buffers, out ExclusiveGroupStruct group) | |||
{ | |||
buffers = _buffers; | |||
group = _group; | |||
} | |||
public void Deconstruct(out EntityCollection<T1> buffers) | |||
{ | |||
buffers = _buffers; | |||
} | |||
public readonly EntityCollection<T1> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
public readonly EntityCollection<T1> _buffers; | |||
public readonly ExclusiveGroupStruct _group; | |||
} | |||
} | |||
} |
@@ -0,0 +1,18 @@ | |||
using Unity.Jobs; | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
public interface IJobifiedEngine<T> : IEngine | |||
{ | |||
JobHandle Execute(JobHandle inputDeps, ref T _param); | |||
string name { get; } | |||
} | |||
public interface IJobifiedEngine : IEngine | |||
{ | |||
JobHandle Execute(JobHandle inputDeps); | |||
string name { get; } | |||
} | |||
} |
@@ -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<T> : IEngine | |||
{ | |||
JobHandle Execute(JobHandle inputDeps, ref T _param); | |||
string name { get; } | |||
} | |||
public interface IJobifiedGroupEngine<T> : IJobifiedEngine<T> | |||
{ } | |||
/// <summary> | |||
@@ -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<Interface> _engines; | |||
readonly string _name; | |||
readonly string _name; | |||
} | |||
public abstract class JobifiedEnginesGroup<Interface, Param>: IJobifiedGroupEngine<Param> where Interface : class, IJobifiedEngine<Param> | |||
@@ -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<T>(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<entityDescriptor> | |||
_nativeRemoveOperations.Add( | |||
new NativeOperationRemove(EntityDescriptorTemplate<T>.descriptor.componentsToBuild, TypeCache<T>.type, memberName)); | |||
_nativeRemoveOperations.Add(new NativeOperationRemove( | |||
EntityDescriptorTemplate<T>.descriptor.componentsToBuild, TypeCache<T>.type | |||
, memberName)); | |||
return new NativeEntityRemove(_removeOperationQueue, _nativeRemoveOperations.count - 1); | |||
} | |||
NativeEntitySwap ProvideNativeEntitySwapQueue<T>(string memberName) where T : IEntityDescriptor, new() | |||
{ | |||
//todo: remove operation array and store entity descriptor hash in the return value | |||
_nativeSwapOperations.Add( | |||
new NativeOperationSwap(EntityDescriptorTemplate<T>.descriptor.componentsToBuild, TypeCache<T>.type, memberName)); | |||
_nativeSwapOperations.Add(new NativeOperationSwap(EntityDescriptorTemplate<T>.descriptor.componentsToBuild | |||
, TypeCache<T>.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<uint>(); | |||
var entityEGID = buffer.Dequeue<EGID>(); | |||
var nativeRemoveOperation = _nativeRemoveOperations[componentsIndex]; | |||
CheckRemoveEntityID(entityEGID, nativeRemoveOperation.entityDescriptorType); | |||
var componentsIndex = buffer.Dequeue<uint>(); | |||
var entityEGID = buffer.Dequeue<EGID>(); | |||
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<uint>(); | |||
var componentsIndex = buffer.Dequeue<uint>(); | |||
var entityEGID = buffer.Dequeue<DoubleEGID>(); | |||
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<uint>(); | |||
var egid = buffer.Dequeue<EGID>(); | |||
var componentCounts = buffer.Dequeue<uint>(); | |||
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; | |||
@@ -7,24 +7,24 @@ namespace Svelto.ECS | |||
public struct NativeEGIDMultiMapper<T>:IDisposable where T : unmanaged, IEntityComponent | |||
{ | |||
SveltoDictionary<ExclusiveGroupStruct, SveltoDictionary<uint, T, | |||
NativeStrategy<FasterDictionaryNode<uint>>, | |||
NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, | |||
NativeStrategy<int>>, | |||
NativeStrategy<FasterDictionaryNode<ExclusiveGroupStruct>>, | |||
NativeStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, | |||
NativeStrategy<SveltoDictionary<uint, T, | |||
NativeStrategy<FasterDictionaryNode<uint>>, | |||
NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, | |||
NativeStrategy<int>>>, | |||
NativeStrategy<int>> _dic; | |||
public NativeEGIDMultiMapper | |||
(SveltoDictionary<ExclusiveGroupStruct, SveltoDictionary<uint, T, | |||
NativeStrategy<FasterDictionaryNode<uint>>, | |||
NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, | |||
NativeStrategy<int>>, | |||
NativeStrategy<FasterDictionaryNode<ExclusiveGroupStruct>>, | |||
NativeStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, | |||
NativeStrategy<SveltoDictionary<uint, T, | |||
NativeStrategy<FasterDictionaryNode<uint>>, | |||
NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, | |||
NativeStrategy<int>>>, | |||
NativeStrategy<int>> dictionary) | |||
@@ -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<uint>(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<uint>(out var index) = 0; | |||
return new NativeEntityComponentInitializer(unsafeBuffer, index); | |||
return new NativeEntityInitializer(unsafeBuffer, index); | |||
} | |||
} | |||
} |
@@ -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; |
@@ -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); | |||
@@ -48,12 +48,12 @@ namespace Svelto.ECS | |||
{ | |||
var dictionary = | |||
new SveltoDictionary<ExclusiveGroupStruct, SveltoDictionary<uint, T, | |||
NativeStrategy<FasterDictionaryNode<uint>>, | |||
NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, | |||
NativeStrategy<int>>, | |||
NativeStrategy<FasterDictionaryNode<ExclusiveGroupStruct>>, | |||
NativeStrategy<SveltoDictionaryNode<ExclusiveGroupStruct>>, | |||
NativeStrategy<SveltoDictionary<uint, T, | |||
NativeStrategy<FasterDictionaryNode<uint>>, | |||
NativeStrategy<SveltoDictionaryNode<uint>>, | |||
NativeStrategy<T>, | |||
NativeStrategy<int>>>, | |||
NativeStrategy<int>> | |||
@@ -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 |
@@ -6,19 +6,35 @@ using Unity.Jobs; | |||
namespace Svelto.ECS.Extensions.Unity | |||
{ | |||
/// <summary> | |||
/// 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) | |||
/// </summary> | |||
[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 |
@@ -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 | |||
/// </summary> | |||
public class SveltoUECSEntitiesSubmissionGroup : JobifiedEnginesGroup<IUECSSubmissionEngine> | |||
public sealed class SveltoUECSEntitiesSubmissionGroup | |||
{ | |||
public SveltoUECSEntitiesSubmissionGroup | |||
(ISimpleEntitiesSubmissionScheduler submissionScheduler, World UECSWorld) | |||
public SveltoUECSEntitiesSubmissionGroup(SimpleEntitiesSubmissionScheduler submissionScheduler, World UECSWorld) | |||
{ | |||
_submissionScheduler = submissionScheduler; | |||
_ECBSystem = UECSWorld.CreateSystem<SubmissionEntitiesCommandBufferSystem>(); | |||
_engines = new FasterList<SubmissionEngine>(); | |||
} | |||
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<SubmissionEngine> _engines; | |||
[DisableAutoCreation] | |||
class SubmissionEntitiesCommandBufferSystem : EntityCommandBufferSystem { } | |||
@@ -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<T>(this Transform contextHolder, EGID ID, | |||
public static EntityInitializer CreateEntity<T>(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<T>(this Transform contextHolder, EGID ID, | |||
public static EntityInitializer Create<T>(this Transform contextHolder, EGID ID, | |||
IEntityFactory factory) | |||
where T : MonoBehaviour, IEntityDescriptorHolder | |||
{ | |||
@@ -86,7 +86,7 @@ namespace Svelto.ECS.Extensions.Unity | |||
return s; | |||
} | |||
public static EntityComponentInitializer Create<T>(EGID ID, Transform contextHolder, IEntityFactory factory, | |||
public static EntityInitializer Create<T>(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<T>(EGID ID, Transform contextHolder, | |||
public static EntityInitializer Create<T>(EGID ID, Transform contextHolder, | |||
IEntityFactory factory, bool searchImplementorsInChildren = false) | |||
where T : MonoBehaviour, IEntityDescriptorHolder | |||
{ | |||
@@ -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 | |||
@@ -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<T>(uint entityID, BuildGroup groupID) where T : IEntityDescriptor, new(); | |||
void RemoveEntity<T>(EGID entityegid) where T : IEntityDescriptor, new(); | |||
void RemoveEntitiesFromGroup(BuildGroup groupID); | |||
void SwapEntitiesInGroup<T>(BuildGroup fromGroupID, BuildGroup toGroupID) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(uint entityID, BuildGroup fromGroupID, BuildGroup toGroupID) | |||
where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, BuildGroup toGroupID) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, BuildGroup toGroupID, BuildGroup mustBeFromGroup) | |||
where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, EGID toId) where T : IEntityDescriptor, new(); | |||
void SwapEntityGroup<T>(EGID fromID, EGID toId, BuildGroup mustBeFromGroup) | |||
where T : IEntityDescriptor, new(); | |||
#if UNITY_NATIVE | |||
NativeEntityRemove ToNativeRemove<T>(string memberName) where T : IEntityDescriptor, new(); | |||
NativeEntitySwap ToNativeSwap<T>(string memberName) where T : IEntityDescriptor, new(); | |||
#endif | |||
} | |||
} |
@@ -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) | |||
@@ -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) | |||
{ | |||
@@ -1,6 +1,5 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Reflection; | |||
using Svelto.Common; | |||
using Svelto.ECS.Serialization; | |||
@@ -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); | |||