diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index ae44d60..bc96c16 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -193,7 +193,8 @@ namespace Svelto.DataStructures { public FasterListThreadSafe(FasterList list) { - _list = list; + if (list == null) throw new ArgumentException("invalid list"); + _list = list; _lockQ = new ReaderWriterLockSlim(); } @@ -288,14 +289,14 @@ namespace Svelto.DataStructures public void CopyTo(T[] array, int arrayIndex) { - _lockQ.EnterWriteLock(); + _lockQ.EnterReadLock(); try { _list.CopyTo(array, arrayIndex); } finally { - _lockQ.ExitWriteLock(); + _lockQ.ExitReadLock(); } } @@ -351,6 +352,19 @@ namespace Svelto.DataStructures } } + public void UnorderredRemoveAt(int index) + { + _lockQ.EnterWriteLock(); + try + { + _list.UnorderredRemoveAt(index); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); @@ -368,8 +382,6 @@ namespace Svelto.DataStructures public struct FasterReadOnlyListCast : IList where U:T { - public static FasterList DefaultList = new FasterList(); - public int Count { get { return _list.Count; } } public bool IsReadOnly { get { return true; } } @@ -402,7 +414,7 @@ namespace Svelto.DataStructures public void CopyTo(U[] array, int arrayIndex) { - throw new NotImplementedException(); + Array.Copy(_list.ToArrayFast(), 0, array, arrayIndex, _list.Count); } public bool Remove(U item) @@ -440,6 +452,8 @@ namespace Svelto.DataStructures public class FasterList : IList { + public static FasterList DefaultList = new FasterList(); + const int MIN_SIZE = 4; public int Count @@ -752,14 +766,15 @@ namespace Svelto.DataStructures Resize(_count); } - public bool Reuse(int index, out T result) + public bool Reuse(int index, out U result) + where U:class, T { - result = default(T); + result = default(U); if (index >= _buffer.Length) return false; - result = _buffer[index]; + result = (U)_buffer[index]; return result != null; } diff --git a/DataStructures/Priority Queue/HeapPriorityQueue.cs b/DataStructures/Priority Queue/HeapPriorityQueue.cs index c30e06d..2774d57 100644 --- a/DataStructures/Priority Queue/HeapPriorityQueue.cs +++ b/DataStructures/Priority Queue/HeapPriorityQueue.cs @@ -13,9 +13,9 @@ namespace Svelto.DataStructures public sealed class HeapPriorityQueue : IPriorityQueue where T : PriorityQueueNode { - private int _numNodes; - private readonly FasterList _nodes; - private long _numNodesEverEnqueued; + int _numNodes; + private readonly FasterList _nodes; + long _numNodesEverEnqueued; /// /// Instantiate a new Priority Queue @@ -101,10 +101,10 @@ namespace Svelto.DataStructures CascadeUp(_nodes[_numNodes]); } - #if NET_VERSION_4_5 +#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private void Swap(T node1, T node2) +#endif + void Swap(T node1, T node2) { //Swap the nodes _nodes[node1.QueueIndex] = node2; @@ -117,14 +117,14 @@ namespace Svelto.DataStructures } //Performance appears to be slightly better when this is NOT inlined o_O - private void CascadeUp(T node) + void CascadeUp(T node) { //aka Heapify-up int parent = node.QueueIndex / 2; - while(parent >= 1) + while (parent >= 1) { T parentNode = _nodes[parent]; - if(HasHigherPriority(parentNode, node)) + if (HasHigherPriority(parentNode, node)) break; //Node has lower priority value, so move it up the heap @@ -134,9 +134,9 @@ namespace Svelto.DataStructures } } - #if NET_VERSION_4_5 +#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif +#endif private void CascadeDown(T node) { //aka Heapify-down @@ -198,10 +198,10 @@ namespace Svelto.DataStructures /// Returns true if 'higher' has higher priority than 'lower', false otherwise. /// Note that calling HasHigherPriority(node, node) (ie. both arguments the same node) will return false /// - #if NET_VERSION_4_5 +#if NET_VERSION_4_5 [MethodImpl(MethodImplOptions.AggressiveInlining)] - #endif - private bool HasHigherPriority(T higher, T lower) +#endif + bool HasHigherPriority(T higher, T lower) { return (higher.Priority < lower.Priority || (higher.Priority == lower.Priority && higher.InsertionIndex < lower.InsertionIndex)); @@ -242,13 +242,13 @@ namespace Svelto.DataStructures OnNodeUpdated(node); } - private void OnNodeUpdated(T node) + void OnNodeUpdated(T node) { //Bubble the updated node up or down as appropriate int parentIndex = node.QueueIndex / 2; T parentNode = _nodes[parentIndex]; - if(parentIndex > 0 && HasHigherPriority(node, parentNode)) + if (parentIndex > 0 && HasHigherPriority(node, parentNode)) { CascadeUp(node); } diff --git a/DataStructures/ThreadSafeDictionary.cs b/DataStructures/ThreadSafeDictionary.cs index 1505547..0bfb662 100644 --- a/DataStructures/ThreadSafeDictionary.cs +++ b/DataStructures/ThreadSafeDictionary.cs @@ -31,10 +31,15 @@ namespace Svelto.DataStructures { get { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return dict.Count; } + finally + { + LockQ.ExitReadLock(); + } } } @@ -42,10 +47,15 @@ namespace Svelto.DataStructures { get { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return dict.IsReadOnly; } + finally + { + LockQ.ExitReadLock(); + } } } @@ -53,10 +63,15 @@ namespace Svelto.DataStructures { get { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return new FasterList(dict.Keys); } + finally + { + LockQ.ExitReadLock(); + } } } @@ -64,10 +79,15 @@ namespace Svelto.DataStructures { get { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return new FasterList(dict.Values); } + finally + { + LockQ.ExitReadLock(); + } } } @@ -75,91 +95,146 @@ namespace Svelto.DataStructures { get { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return dict[key]; } + finally + { + LockQ.ExitReadLock(); + } } set { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { dict[key] = value; } + finally + { + LockQ.ExitWriteLock(); + } } } public virtual void Add(KeyValuePair item) { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { dict.Add(item); } + finally + { + LockQ.ExitWriteLock(); + } } public virtual void Clear() { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { dict.Clear(); } + finally + { + LockQ.ExitWriteLock(); + } } public virtual bool Contains(KeyValuePair item) { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return dict.Contains(item); } + finally + { + LockQ.ExitReadLock(); + } } public virtual void CopyTo(KeyValuePair[] array, int arrayIndex) { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { dict.CopyTo(array, arrayIndex); } + finally + { + LockQ.ExitReadLock(); + } } public virtual bool Remove(KeyValuePair item) { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { return dict.Remove(item); } + finally + { + LockQ.ExitWriteLock(); + } } public virtual void Add(TKey key, TValue value) { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { dict.Add(key, value); } + finally + { + LockQ.ExitWriteLock(); + } } public virtual bool ContainsKey(TKey key) { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return dict.ContainsKey(key); } + finally + { + LockQ.ExitReadLock(); + } } public virtual bool Remove(TKey key) { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { return dict.Remove(key); } + finally + { + LockQ.ExitWriteLock(); + } } public virtual bool TryGetValue(TKey key, out TValue value) { - using (new ReadOnlyLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { return dict.TryGetValue(key, out value); } + finally + { + LockQ.ExitReadLock(); + } } /// @@ -169,7 +244,8 @@ namespace Svelto.DataStructures /// New Value public void MergeSafe(TKey key, TValue newValue) { - using (new WriteLock(dictionaryLock)) + LockQ.EnterWriteLock(); + try { // take a writelock immediately since we will always be writing if (dict.ContainsKey(key)) @@ -177,6 +253,10 @@ namespace Svelto.DataStructures dict.Add(key, newValue); } + finally + { + LockQ.ExitWriteLock(); + } } /// @@ -185,132 +265,29 @@ namespace Svelto.DataStructures /// Key to remove public void RemoveSafe(TKey key) { - using (new ReadLock(dictionaryLock)) + LockQ.EnterReadLock(); + try { if (dict.ContainsKey(key)) - using (new WriteLock(dictionaryLock)) - { - dict.Remove(key); - } + LockQ.EnterWriteLock(); + try + { + dict.Remove(key); + } + finally + { + LockQ.ExitWriteLock(); + } + } + finally + { + LockQ.ExitReadLock(); } } // This is the internal dictionary that we are wrapping readonly IDictionary dict; - [NonSerialized] readonly ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); - } - - public static class Locks - { - public static ReaderWriterLockSlim GetLockInstance() - { - return GetLockInstance(LockRecursionPolicy.SupportsRecursion); - } - - public static ReaderWriterLockSlim GetLockInstance(LockRecursionPolicy recursionPolicy) - { - return new ReaderWriterLockSlim(recursionPolicy); - } - - public static void GetReadLock(ReaderWriterLockSlim locks) - { - var lockAcquired = false; - while (!lockAcquired) - lockAcquired = locks.TryEnterUpgradeableReadLock(1); - } - - public static void GetReadOnlyLock(ReaderWriterLockSlim locks) - { - var lockAcquired = false; - while (!lockAcquired) - lockAcquired = locks.TryEnterReadLock(1); - } - - public static void GetWriteLock(ReaderWriterLockSlim locks) - { - var lockAcquired = false; - while (!lockAcquired) - lockAcquired = locks.TryEnterWriteLock(1); - } - - public static void ReleaseLock(ReaderWriterLockSlim locks) - { - ReleaseWriteLock(locks); - ReleaseReadLock(locks); - ReleaseReadOnlyLock(locks); - } - - public static void ReleaseReadLock(ReaderWriterLockSlim locks) - { - if (locks.IsUpgradeableReadLockHeld) - locks.ExitUpgradeableReadLock(); - } - - public static void ReleaseReadOnlyLock(ReaderWriterLockSlim locks) - { - if (locks.IsReadLockHeld) - locks.ExitReadLock(); - } - - public static void ReleaseWriteLock(ReaderWriterLockSlim locks) - { - if (locks.IsWriteLockHeld) - locks.ExitWriteLock(); - } - } - - public abstract class BaseLock : IDisposable - { - protected ReaderWriterLockSlim _Locks; - - public BaseLock(ReaderWriterLockSlim locks) - { - _Locks = locks; - } - - public abstract void Dispose(); - } - - public class ReadLock : BaseLock - { - public ReadLock(ReaderWriterLockSlim locks) - : base(locks) - { - Locks.GetReadLock(_Locks); - } - - public override void Dispose() - { - Locks.ReleaseReadLock(_Locks); - } - } - - public class ReadOnlyLock : BaseLock - { - public ReadOnlyLock(ReaderWriterLockSlim locks) - : base(locks) - { - Locks.GetReadOnlyLock(_Locks); - } - - public override void Dispose() - { - Locks.ReleaseReadOnlyLock(_Locks); - } - } - - public class WriteLock : BaseLock - { - public WriteLock(ReaderWriterLockSlim locks) - : base(locks) - { - Locks.GetWriteLock(_Locks); - } - - public override void Dispose() - { - Locks.ReleaseWriteLock(_Locks); - } + readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); } } diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 8c73fa2..4a31542 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -10,29 +10,39 @@ namespace Svelto.ECS Dictionary> nodesDBdic, Dictionary> nodesDBgroups) { - _nodesDB = nodesDB; - _nodesDBdic = nodesDBdic; - _nodesDBgroups = nodesDBgroups; + _nodesDB = new DataStructures.WeakReference>>(nodesDB); + _nodesDBdic = new DataStructures.WeakReference>>(nodesDBdic); + _nodesDBgroups = new DataStructures.WeakReference>>(nodesDBgroups); } public FasterReadOnlyListCast QueryNodes() where T:INode { var type = typeof(T); - if (_nodesDB.ContainsKey(type) == false) + if (_nodesDB.IsValid == false || _nodesDB.Target.ContainsKey(type) == false) return RetrieveEmptyNodeList(); - return new FasterReadOnlyListCast(_nodesDB[type]); + return new FasterReadOnlyListCast(_nodesDB.Target[type]); } + /* public FasterReadOnlyList QueryStructNodes() where T:struct + { + var type = typeof(T); + + if (_nodesDBStructs.ContainsKey(type) == false) + return RetrieveEmptyStructNodeList(); + + return new FasterReadOnlyList(((StructNodeList)(_nodesDBStructs[type])).list); + }*/ + public ReadOnlyDictionary QueryIndexableNodes() where T:INode { var type = typeof(T); - if (_nodesDBdic.ContainsKey(type) == false) + if (_nodesDB.IsValid == false || _nodesDBdic.Target.ContainsKey(type) == false) return _defaultEmptyNodeDict; - return new ReadOnlyDictionary(_nodesDBdic[type]); + return new ReadOnlyDictionary(_nodesDBdic.Target[type]); } public T QueryNodeFromGroup(int groupID) where T : INode @@ -49,10 +59,10 @@ namespace Svelto.ECS { var type = typeof(T); - if (_nodesDBgroups.ContainsKey(type) == false) + if (_nodesDBgroups.IsValid == false || _nodesDBgroups.Target.ContainsKey(type) == false) return RetrieveEmptyNodeList(); - return new FasterReadOnlyListCast(_nodesDBgroups[type]); + return new FasterReadOnlyListCast(_nodesDBgroups.Target[type]); } public bool QueryNode(int ID, out T node) where T:INode @@ -61,7 +71,7 @@ namespace Svelto.ECS INode internalNode; - if (_nodesDBdic.ContainsKey(type) && _nodesDBdic[type].TryGetValue(ID, out internalNode)) + if (_nodesDBdic.IsValid && _nodesDBdic.Target.ContainsKey(type) && _nodesDBdic.Target[type].TryGetValue(ID, out internalNode)) { node = (T)internalNode; @@ -79,7 +89,7 @@ namespace Svelto.ECS INode internalNode; - if (_nodesDBdic.ContainsKey(type) && _nodesDBdic[type].TryGetValue(ID, out internalNode)) + if (_nodesDBdic.IsValid && _nodesDBdic.Target.ContainsKey(type) && _nodesDBdic.Target[type].TryGetValue(ID, out internalNode)) return (T)internalNode; throw new Exception("Node Not Found"); @@ -87,17 +97,31 @@ namespace Svelto.ECS static FasterReadOnlyListCast RetrieveEmptyNodeList() where T : INode { - return new FasterReadOnlyListCast(FasterReadOnlyListCast.DefaultList); + return new FasterReadOnlyListCast(FasterList.DefaultList); + } + + static FasterReadOnlyList RetrieveEmptyStructNodeList() where T : struct + { + return new FasterReadOnlyList(FasterList.DefaultList); } - Dictionary> _nodesDB; - Dictionary> _nodesDBdic; - Dictionary> _nodesDBgroups; + Svelto.DataStructures.WeakReference>> _nodesDB; + Svelto.DataStructures.WeakReference>> _nodesDBdic; + Svelto.DataStructures.WeakReference>> _nodesDBgroups; +// Dictionary _nodesDBStructs; //Dictionary> _nodesDB; //Dictionary> _nodesDBdic; // Dictionary> _nodesDBgroups; ReadOnlyDictionary _defaultEmptyNodeDict = new ReadOnlyDictionary(new Dictionary()); + + class StructNodeList + { } + + class StructNodeList : StructNodeList where T : struct + { + public FasterList list = new FasterList(); + } } } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index d3af55c..0807d13 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -4,7 +4,8 @@ using System.Collections.Generic; using Svelto.DataStructures; using UnityEngine; using WeakReference = Svelto.DataStructures.WeakReference; - +using Svelto.ECS.NodeSchedulers; +using Svelto.ECS.Internal; #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR using Svelto.ECS.Profiler; #endif @@ -14,26 +15,11 @@ using System.Reflection; namespace Svelto.ECS { - class Scheduler : MonoBehaviour - { - IEnumerator Start() - { - while (true) - { - yield return new WaitForEndOfFrame(); - - OnTick(); - } - } - - internal Action OnTick; - } - public sealed class EnginesRoot : IEnginesRoot, IEntityFactory { - public EnginesRoot() + public EnginesRoot(NodeSubmissionScheduler nodeScheduler) { - _nodeEngines = new Dictionary>>(); + _nodeEngines = new Dictionary>(); _engineRootWeakReference = new WeakReference(this); _otherEnginesReferences = new FasterList(); @@ -45,9 +31,8 @@ namespace Svelto.ECS _nodesDBgroups = new Dictionary>(); - GameObject go = new GameObject("ECSScheduler"); - - go.AddComponent().OnTick += SubmitNodes; + _scheduler = nodeScheduler; + _scheduler.Schedule(SubmitNodes); #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR GameObject debugEngineObject = new GameObject("Engine Debugger"); @@ -109,6 +94,28 @@ namespace Svelto.ECS _groupNodesToAdd.Clear(); } + public void AddEngine(INodeEngine engine) where T:class, INode + { + AddEngine(new NodeEngineWrapper(engine)); + + if (engine is IQueryableNodeEngine) + (engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic, _nodesDBgroups); + } + + public void AddEngine(INodeEngine engine) where T:class, INode where U:class, INode + { + AddEngine(new NodeEngineWrapper(engine)); + AddEngine((INodeEngine)(engine)); + } + + public void AddEngine(INodeEngine engine) where T:class, INode + where U:class, INode + where V:class, INode + { + AddEngine(new NodeEngineWrapper(engine)); + AddEngine((INodeEngine)(engine)); + } + public void AddEngine(IEngine engine) { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR @@ -125,9 +132,7 @@ namespace Svelto.ECS } else { - var engineType = engine.GetType(); -// Type baseInterface = null; #if !NETFX_CORE var baseType = engineType.BaseType; @@ -138,12 +143,28 @@ namespace Svelto.ECS if (baseType.IsConstructedGenericType #endif - && baseType.GetGenericTypeDefinition() == typeof (SingleNodeEngine<>)) + && baseType.GetGenericTypeDefinition() == typeof(SingleNodeEngine<>)) { - AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); + AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); } else - _otherEnginesReferences.Add(engine); + { + bool found = false; + + for (int i = 0, maxLength = engineType.GetInterfaces().Length; i < maxLength; i++) + { + var type = engineType.GetInterfaces()[i]; + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(INodeEngine<>)) + { + AddEngine(engine as INodeEngine, type.GetGenericArguments(), _nodeEngines); + + found = true; + } + } + + if (found == false) + _otherEnginesReferences.Add(engine); + } } if (engine is ICallBackOnAddEngine) @@ -152,10 +173,10 @@ namespace Svelto.ECS public void BuildEntity(int ID, EntityDescriptor ed) { - var entityNodes = ed.BuildNodes(ID, (node) => + var entityNodes = ed.BuildNodes(ID, (nodes) => { if (_engineRootWeakReference.IsValid == true) - InternalRemove(node); + InternalRemove(nodes); }); _nodesToAdd.AddRange(entityNodes); @@ -176,26 +197,26 @@ namespace Svelto.ECS /// public void BuildEntityGroup(int groupID, EntityDescriptor ed) { - var entityNodes = ed.BuildNodes(groupID, (node) => + var entityNodes = ed.BuildNodes(groupID, (nodes) => { if (_engineRootWeakReference.IsValid == true) - InternalGroupRemove(node); + InternalGroupRemove(nodes); }); _groupNodesToAdd.AddRange(entityNodes); } - static void AddEngine(T engine, Type[] types, Dictionary>> engines) where T : INodeEngine + static void AddEngine(INodeEngine engine, Type[] types, Dictionary> engines) { for (int i = 0; i < types.Length; i++) { - FasterList> list; + FasterList list; var type = types[i]; if (engines.TryGetValue(type, out list) == false) { - list = new FasterList>(); + list = new FasterList(); engines.Add(type, list); } @@ -215,7 +236,7 @@ namespace Svelto.ECS AddNodeToNodesDictionary(node, nodeType); } - void AddNodeToTheDB(T node, Type nodeType) where T : INode + void AddNodeToTheDB(INode node, Type nodeType) { FasterList nodes; if (_nodesDB.TryGetValue(nodeType, out nodes) == false) @@ -226,7 +247,7 @@ namespace Svelto.ECS AddNodeToNodesDictionary(node, nodeType); } - void AddNodeToNodesDictionary(T node, Type nodeType) where T : INode + void AddNodeToNodesDictionary(INode node, Type nodeType) { if (node is NodeWithID) { @@ -238,9 +259,9 @@ namespace Svelto.ECS } } - void AddNodeToTheSuitableEngines(T node, Type nodeType) where T : INode + void AddNodeToTheSuitableEngines(INode node, Type nodeType) { - FasterList> enginesForNode; + FasterList enginesForNode; if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) { @@ -255,91 +276,85 @@ namespace Svelto.ECS } } - void RemoveNodeFromTheDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDB.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero? - - RemoveNodeFromNodesDictionary(node, nodeType); - } - - void RemoveNodeFromNodesDictionary(T node, Type nodeType) where T : INode + void RemoveNodesFromDB(Dictionary> DB, FasterReadOnlyList nodes) { - if (node is NodeWithID) + for (int i = 0; i < nodes.Count; i++) { - Dictionary nodesDic; + FasterList nodesInDB; - if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) - nodesDic.Remove((node as NodeWithID).ID); - } - } + var node = nodes[i]; + var nodeType = node.GetType(); + + if (DB.TryGetValue(nodeType, out nodesInDB) == true) + nodesInDB.UnorderredRemove(node); //should I remove it from the dictionary if length is zero? - void RemoveNodeFromGroupDB(T node, Type nodeType) where T : INode - { - FasterList nodes; - if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == true) - nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero? + if (node is NodeWithID) + { + Dictionary nodesDic; - RemoveNodeFromNodesDictionary(node, nodeType); + if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) + nodesDic.Remove((node as NodeWithID).ID); + } + } } - void RemoveNodeFromEngines(T node, Type nodeType) where T : INode + void RemoveNodesFromEngines(FasterReadOnlyList nodes) { - FasterList> enginesForNode; - - if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) + for (int i = 0; i < nodes.Count; i++) { - for (int j = 0; j < enginesForNode.Count; j++) + FasterList enginesForNode; + var node = nodes[i]; + + if (_nodeEngines.TryGetValue(node.GetType(), out enginesForNode)) { + for (int j = 0; j < enginesForNode.Count; j++) + { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node); + EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node); #else - enginesForNode[j].Remove(node); + enginesForNode[j].Remove(node); #endif + } } } } #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR - void AddNodeToEngine(INodeEngine engine, INode node) + static void AddNodeToEngine(INodeEngine engine, INode node) { engine.Add(node); } - void RemoveNodeFromEngine(INodeEngine engine, INode node) + static void RemoveNodeFromEngine(INodeEngine engine, INode node) { engine.Remove(node); } #endif - - void InternalRemove(T node) where T : INode - { - Type nodeType = node.GetType(); - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromTheDB(node, node.GetType()); + void InternalRemove(FasterReadOnlyList nodes) + { + RemoveNodesFromEngines(nodes); + RemoveNodesFromDB(_nodesDB, nodes); } - void InternalGroupRemove(T node) where T : INode + void InternalGroupRemove(FasterReadOnlyList nodes) { - Type nodeType = node.GetType(); - - RemoveNodeFromEngines(node, nodeType); - RemoveNodeFromGroupDB(node, node.GetType()); + RemoveNodesFromEngines(nodes); + RemoveNodesFromDB(_nodesDBgroups, nodes); } - Dictionary>> _nodeEngines; + Dictionary> _nodeEngines; FasterList _otherEnginesReferences; Dictionary> _nodesDB; - Dictionary> _nodesDBdic; - Dictionary> _nodesDBgroups; + Dictionary> _nodesDBdic; + FasterList _nodesToAdd; FasterList _groupNodesToAdd; WeakReference _engineRootWeakReference; + NodeSubmissionScheduler _scheduler; } } diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 7dab7ee..d818dce 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -15,6 +15,11 @@ namespace Svelto.ECS _nodesToBuild = nodesToBuild; } + /* protected EntityDescriptor(IStructNodeBuilder[] structNodesToBuild) + { + _structNodesToBuild = structNodesToBuild; + }*/ + public void AddImplementors(params object[] componentsImplementor) { var implementors = new object[componentsImplementor.Length + _implementors.Length]; @@ -25,23 +30,22 @@ namespace Svelto.ECS _implementors = implementors; } - public virtual FasterList BuildNodes(int ID, Action removeAction) + public virtual FasterList BuildNodes(int ID, Action> removeAction) { var nodes = new FasterList(); - for (int index = 0; index < _nodesToBuild.Length; index++) + for (int index = _nodesToBuild.Length - 1; index >= 0; index--) { var nodeBuilder = _nodesToBuild[index]; var node = FillNode(nodeBuilder.Build(ID), () => { - for (int i = 0; i < nodes.Count; i++) - removeAction(nodes[i]); + removeAction(new FasterReadOnlyList()); nodes.Clear(); } ); - nodes.Add (node); + nodes.Add(node); } return nodes; @@ -88,7 +92,8 @@ namespace Svelto.ECS object[] _implementors; - readonly INodeBuilder[] _nodesToBuild; + readonly INodeBuilder[] _nodesToBuild; + // readonly IStructNodeBuilder[] _structNodesToBuild; } public interface INodeBuilder @@ -105,4 +110,15 @@ namespace Svelto.ECS return (NodeType)node; } } +/* + public interface IStructNodeBuilder + {} + + public class StructNodeBuilder : IStructNodeBuilder where NodeType : struct + { + public NodeType Build() + { + return new NodeType(); + } + }*/ } diff --git a/ECS/IEngine.cs b/ECS/IEngine.cs index 5bddc66..3d67fcd 100644 --- a/ECS/IEngine.cs +++ b/ECS/IEngine.cs @@ -9,7 +9,25 @@ namespace Svelto.ECS void Remove(TNodeType obj); } - public interface INodesEngine : INodeEngine + public interface INodeEngine:INodeEngine where T:INode where U:INode + { + void Add(T obj); + void Remove(T obj); + } + + public interface INodeEngine:INodeEngine where T:INode where U:INode where V:INode + { + void Add(T obj); + void Remove(T obj); + } + + public interface INodeEngine:IEngine + { + void Add(INode obj); + void Remove(INode obj); + } + + public interface INodesEngine : INodeEngine { System.Type[] AcceptedNodes(); } diff --git a/ECS/IEngineNodeDB.cs b/ECS/IEngineNodeDB.cs index 069d532..6103ad0 100644 --- a/ECS/IEngineNodeDB.cs +++ b/ECS/IEngineNodeDB.cs @@ -11,6 +11,8 @@ namespace Svelto.ECS FasterReadOnlyListCast QueryNodes() where T:INode; +// FasterReadOnlyList QueryStructNodes() where T : struct; + bool QueryNodeFromGroup(int ID, out T node) where T : INode; T QueryNodeFromGroup(int ID) where T : INode; FasterReadOnlyListCast QueryNodesFromGroups() where T : INode; diff --git a/ECS/NodeEngineWrapper.cs b/ECS/NodeEngineWrapper.cs new file mode 100644 index 0000000..49ec673 --- /dev/null +++ b/ECS/NodeEngineWrapper.cs @@ -0,0 +1,66 @@ +using System; + +namespace Svelto.ECS.Internal +{ + class NodeEngineWrapper : SingleNodeEngine where T : class, INode + { + INodeEngine engine; + + public NodeEngineWrapper(INodeEngine engine) + { + this.engine = engine; + } + + protected override void Add(T node) + { + engine.Add((T)node); + } + + protected override void Remove(T node) + { + engine.Remove((T)node); + } + } + + class NodeEngineWrapper: SingleNodeEngine where T : class, INode where U : class, INode + { + INodeEngine engine; + + public NodeEngineWrapper(INodeEngine engine) + { + this.engine = engine; + } + + protected override void Add(T node) + { + engine.Add((T)node); + } + + protected override void Remove(T node) + { + engine.Remove((T)node); + } + } + + class NodeEngineWrapper: SingleNodeEngine where T : class, INode + where U : class, INode + where V : class, INode + { + INodeEngine engine; + + public NodeEngineWrapper(INodeEngine engine) + { + this.engine = engine; + } + + protected override void Add(T node) + { + engine.Add((T)node); + } + + protected override void Remove(T node) + { + engine.Remove((T)node); + } + } +} \ No newline at end of file diff --git a/ECS/NodeSubmissionScheduler.cs b/ECS/NodeSubmissionScheduler.cs new file mode 100644 index 0000000..7f04648 --- /dev/null +++ b/ECS/NodeSubmissionScheduler.cs @@ -0,0 +1,9 @@ +using System; + +namespace Svelto.ECS.NodeSchedulers +{ + public abstract class NodeSubmissionScheduler + { + abstract public void Schedule(Action submitNodes); + } +} \ No newline at end of file diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs index 2c20e59..d7c6b93 100644 --- a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs @@ -5,7 +5,7 @@ using UnityEditor; namespace Svelto.ECS.Profiler { - internal class EngineProfilerMenuItem + class EngineProfilerMenuItem { [MenuItem("Engines/Enable Profiler")] public static void EnableProfiler() diff --git a/ECS/Profiler/EngineProfiler.cs b/ECS/Profiler/EngineProfiler.cs index f055f3d..53e7296 100644 --- a/ECS/Profiler/EngineProfiler.cs +++ b/ECS/Profiler/EngineProfiler.cs @@ -11,7 +11,7 @@ namespace Svelto.ECS.Profiler { static readonly Stopwatch _stopwatch = new Stopwatch(); - public static void MonitorAddDuration(Action, INode> addingFunc, INodeEngine engine, INode node) + public static void MonitorAddDuration(Action addingFunc, INodeEngine engine, INode node) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) @@ -25,7 +25,7 @@ namespace Svelto.ECS.Profiler } } - public static void MonitorRemoveDuration(Action, INode> removeFunc, INodeEngine engine, INode node) + public static void MonitorRemoveDuration(Action removeFunc, INodeEngine engine, INode node) { EngineInfo info; if (engineInfos.TryGetValue(engine.GetType(), out info)) diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index 6b43243..d92b840 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -1,13 +1,13 @@ namespace Svelto.ECS { - public abstract class SingleNodeEngine : INodeEngine where TNodeType : class, INode + public abstract class SingleNodeEngine : INodeEngine where TNodeType : class, INode { - void INodeEngine.Add(INode obj) + void INodeEngine.Add(INode obj) { Add(obj as TNodeType); } - void INodeEngine.Remove(INode obj) + void INodeEngine.Remove(INode obj) { Remove(obj as TNodeType); } diff --git a/Extensions/Unity/UnitySumbmissionNodeScheduler.cs b/Extensions/Unity/UnitySumbmissionNodeScheduler.cs new file mode 100644 index 0000000..e79a425 --- /dev/null +++ b/Extensions/Unity/UnitySumbmissionNodeScheduler.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections; +using UnityEngine; + +namespace Svelto.ECS.NodeSchedulers +{ + public class UnitySumbmissionNodeScheduler : NodeSubmissionScheduler + { + public UnitySumbmissionNodeScheduler() + { + GameObject go = new GameObject("ECSScheduler"); + + _scheduler = go.AddComponent(); + } + + public override void Schedule(Action submitNodes) + { + _scheduler.OnTick += submitNodes; + } + + class Scheduler : MonoBehaviour + { + IEnumerator Start() + { + while (true) + { + yield return new WaitForEndOfFrame(); + + OnTick(); + } + } + + internal Action OnTick; + } + + Scheduler _scheduler; + } +} diff --git a/Utilities/DesignByContract.cs b/Utilities/DesignByContract.cs index d34861e..9a76411 100644 --- a/Utilities/DesignByContract.cs +++ b/Utilities/DesignByContract.cs @@ -324,18 +324,18 @@ namespace DesignByContract useAssertions = value; } } - - #endregion // Interface - #region Implementation + #endregion // Interface - // No creation - private Check() {} + #region Implementation - /// - /// Is exception handling being used? - /// - private static bool UseExceptions + // No creation + Check() { } + + /// + /// Is exception handling being used? + /// + private static bool UseExceptions { get { @@ -343,15 +343,15 @@ namespace DesignByContract } } - // Are trace assertion statements being used? - // Default is to use exception handling. - private static bool useAssertions = false; + // Are trace assertion statements being used? + // Default is to use exception handling. + static bool useAssertions = false; - #endregion // Implementation + #endregion // Implementation - } // End Check + } // End Check - internal class Trace + class Trace { internal static void Assert(bool assertion, string v) {