diff --git a/Context/Factories/GameObjectFactory.cs b/Context/Factories/GameObjectFactory.cs index 551c88f..a8cde2b 100644 --- a/Context/Factories/GameObjectFactory.cs +++ b/Context/Factories/GameObjectFactory.cs @@ -42,7 +42,7 @@ namespace Svelto.Context /// Register a prefab to be built later using a string ID. /// /// original prefab - public GameObject Build(GameObject prefab) + virtual public GameObject Build(GameObject prefab) { var copy = Object.Instantiate(prefab) as GameObject; diff --git a/Context/Factories/MonoBehaviourFactory.cs b/Context/Factories/MonoBehaviourFactory.cs index 62502f6..94786dd 100644 --- a/Context/Factories/MonoBehaviourFactory.cs +++ b/Context/Factories/MonoBehaviourFactory.cs @@ -10,11 +10,7 @@ namespace Svelto.Context { public class MonoBehaviourFactory : Factories.IMonoBehaviourFactory { - public MonoBehaviourFactory() - { - } - - public M Build(Func constructor) where M : MonoBehaviour + virtual public M Build(Func constructor) where M : MonoBehaviour { var mb = constructor(); diff --git a/DataStructures/FasterList.cs b/DataStructures/FasterList.cs index 78cbaa2..ae44d60 100644 --- a/DataStructures/FasterList.cs +++ b/DataStructures/FasterList.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Threading; using UnityEngine; namespace Svelto.DataStructures @@ -188,6 +189,183 @@ namespace Svelto.DataStructures readonly FasterList _list; } + public struct FasterListThreadSafe : IList + { + public FasterListThreadSafe(FasterList list) + { + _list = list; + _lockQ = new ReaderWriterLockSlim(); + } + + public int Count + { + get + { + _lockQ.EnterReadLock(); + try + { + return _list.Count; + } + finally + { + _lockQ.ExitReadLock(); + } + } + } + public bool IsReadOnly { get { return false; } } + + public T this[int index] + { + get + { + _lockQ.EnterReadLock(); + try + { + return _list[index]; + } + finally + { + _lockQ.ExitReadLock(); + } + } + set + { + _lockQ.EnterWriteLock(); + try + { + _list[index] = value; + } + finally + { + _lockQ.ExitWriteLock(); + } + } + } + + public FasterListEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + public void Add(T item) + { + _lockQ.EnterWriteLock(); + try + { + _list.Add(item); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + + public void Clear() + { + _lockQ.EnterWriteLock(); + try + { + _list.Clear(); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + + public bool Contains(T item) + { + _lockQ.EnterReadLock(); + try + { + return _list.Contains(item); + } + finally + { + _lockQ.ExitReadLock(); + } + } + + public void CopyTo(T[] array, int arrayIndex) + { + _lockQ.EnterWriteLock(); + try + { + _list.CopyTo(array, arrayIndex); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + + public bool Remove(T item) + { + _lockQ.EnterWriteLock(); + try + { + return _list.Remove(item); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + + public int IndexOf(T item) + { + _lockQ.EnterReadLock(); + try + { + return _list.IndexOf(item); + } + finally + { + _lockQ.ExitReadLock(); + } + } + + public void Insert(int index, T item) + { + _lockQ.EnterWriteLock(); + try + { + _list.Insert(index, item); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + + public void RemoveAt(int index) + { + _lockQ.EnterWriteLock(); + try + { + _list.RemoveAt(index); + } + finally + { + _lockQ.ExitWriteLock(); + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + + readonly FasterList _list; + + readonly ReaderWriterLockSlim _lockQ; + } + public struct FasterReadOnlyListCast : IList where U:T { public static FasterList DefaultList = new FasterList(); @@ -320,6 +498,14 @@ namespace Svelto.DataStructures _buffer[_count++] = item; } + + /// + /// this is a dirtish trick to be able to use the index operastor + /// before adding the elements through the Add functions + /// + /// + /// + /// public static FasterList PreFill(int initialSize) where U:T, new() { var list = new FasterList(initialSize); diff --git a/DataStructures/ThreadSafeDictionary.cs b/DataStructures/ThreadSafeDictionary.cs index 94a3646..1505547 100644 --- a/DataStructures/ThreadSafeDictionary.cs +++ b/DataStructures/ThreadSafeDictionary.cs @@ -1,7 +1,10 @@ + using System; using System.Collections.Generic; using System.Threading; +//note, rewrite like ThreadSafeQueue + namespace Svelto.DataStructures { /// @@ -13,6 +16,16 @@ namespace Svelto.DataStructures [Serializable] public class ThreadSafeDictionary { + public ThreadSafeDictionary(int v) + { + dict = new Dictionary(v); + } + + public ThreadSafeDictionary() + { + dict = new Dictionary(); + } + // setup the lock; public virtual int Count { @@ -183,7 +196,7 @@ namespace Svelto.DataStructures } // This is the internal dictionary that we are wrapping - readonly IDictionary dict = new Dictionary(); + readonly IDictionary dict; [NonSerialized] readonly ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); } diff --git a/DataStructures/ThreadSafeQueue.cs b/DataStructures/ThreadSafeQueue.cs index 4505dd8..d9197f0 100644 --- a/DataStructures/ThreadSafeQueue.cs +++ b/DataStructures/ThreadSafeQueue.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using System.Threading; @@ -6,9 +5,9 @@ namespace Svelto.DataStructures { public class ThreadSafeQueue { - private readonly Queue m_Queue; + readonly Queue m_Queue; - private readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); + readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); public ThreadSafeQueue() { @@ -121,6 +120,22 @@ namespace Svelto.DataStructures } } + public void DequeueInto(FasterList list, int count) + { + LockQ.EnterWriteLock(); + try + { + int originalSize = m_Queue.Count; + while (m_Queue.Count > 0 && originalSize - m_Queue.Count < count) + list.Add(m_Queue.Dequeue()); + } + + finally + { + LockQ.ExitWriteLock(); + } + } + public FasterList DequeueAllAs() where U:class { LockQ.EnterWriteLock(); diff --git a/ECS/Dispatcher/DispatcherOnChange.cs b/ECS/Dispatcher/DispatchOnChange.cs similarity index 100% rename from ECS/Dispatcher/DispatcherOnChange.cs rename to ECS/Dispatcher/DispatchOnChange.cs diff --git a/ECS/Dispatcher/DispatcherOnChange.cs.meta b/ECS/Dispatcher/DispatchOnChange.cs.meta similarity index 100% rename from ECS/Dispatcher/DispatcherOnChange.cs.meta rename to ECS/Dispatcher/DispatchOnChange.cs.meta diff --git a/ECS/EngineNodeDB.cs b/ECS/EngineNodeDB.cs index 1ed8944..8c73fa2 100644 --- a/ECS/EngineNodeDB.cs +++ b/ECS/EngineNodeDB.cs @@ -94,6 +94,10 @@ namespace Svelto.ECS Dictionary> _nodesDBdic; Dictionary> _nodesDBgroups; + //Dictionary> _nodesDB; + //Dictionary> _nodesDBdic; +// Dictionary> _nodesDBgroups; + ReadOnlyDictionary _defaultEmptyNodeDict = new ReadOnlyDictionary(new Dictionary()); } } diff --git a/ECS/EnginesRoot.cs b/ECS/EnginesRoot.cs index 0f1867a..d3af55c 100644 --- a/ECS/EnginesRoot.cs +++ b/ECS/EnginesRoot.cs @@ -122,31 +122,32 @@ namespace Svelto.ECS var nodesEngine = engine as INodesEngine; AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); - - return; } + else + { + + var engineType = engine.GetType(); +// Type baseInterface = null; + #if !NETFX_CORE - var baseType = engine.GetType().BaseType; + var baseType = engineType.BaseType; - if (baseType.IsGenericType) + if (baseType.IsGenericType #else - var baseType = engine.GetType().GetTypeInfo().BaseType; + var baseType = engineType.GetTypeInfo().BaseType; - if (baseType.IsConstructedGenericType) + if (baseType.IsConstructedGenericType #endif - - { - var genericType = baseType.GetGenericTypeDefinition(); - - if (genericType == typeof(SingleNodeEngine<>)) + && baseType.GetGenericTypeDefinition() == typeof (SingleNodeEngine<>)) { AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); - - return; } + else + _otherEnginesReferences.Add(engine); } - - _otherEnginesReferences.Add(engine); + + if (engine is ICallBackOnAddEngine) + (engine as ICallBackOnAddEngine).Ready(); } public void BuildEntity(int ID, EntityDescriptor ed) @@ -160,6 +161,19 @@ namespace Svelto.ECS _nodesToAdd.AddRange(entityNodes); } + /// + /// An entity group is a meta entity. It's a way to create a set of entitites that + /// are not easily queriable otherwise. For example you may group existing entities + /// by size and type and then use the groupID to retrieve a single node that is shared + /// among the single entities of the same type and size. This willwd prevent the scenario + /// where the coder is forced to parse all the entities to find the ones of the same + /// size and type. Since the entity group is managed through the shared node, the same + /// shared node must be found on the single entities of the same type and size. + /// The shared node is then used by engines that are meant to manage a group of entities + /// through a single node. The same engine can manage several groups of entitites. + /// + /// + /// public void BuildEntityGroup(int groupID, EntityDescriptor ed) { var entityNodes = ed.BuildNodes(groupID, (node) => @@ -234,7 +248,7 @@ namespace Svelto.ECS { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j], node); -#else +#else enginesForNode[j].Add(node); #endif } @@ -280,7 +294,7 @@ namespace Svelto.ECS { #if ENGINE_PROFILER_ENABLED && UNITY_EDITOR EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node); -#else +#else enginesForNode[j].Remove(node); #endif } @@ -317,22 +331,15 @@ namespace Svelto.ECS Dictionary>> _nodeEngines; FasterList _otherEnginesReferences; - Dictionary> _nodesDB; - Dictionary> _nodesDBdic; - - Dictionary> _nodesDBgroups; - - FasterList _nodesToAdd; - FasterList _groupNodesToAdd; + Dictionary> _nodesDB; + Dictionary> _nodesDBdic; - WeakReference _engineRootWeakReference; + Dictionary> _nodesDBgroups; - //integrated pooling system - //add debug panel like Entitas has - //GCHandle should be used to reduce the number of strong references - //datastructure could be thread safe + FasterList _nodesToAdd; + FasterList _groupNodesToAdd; - //future enhancements: + WeakReference _engineRootWeakReference; } } diff --git a/ECS/EntityDescriptor.cs b/ECS/EntityDescriptor.cs index 6183fd5..7dab7ee 100644 --- a/ECS/EntityDescriptor.cs +++ b/ECS/EntityDescriptor.cs @@ -1,6 +1,9 @@ using System; using System.Reflection; using Svelto.DataStructures; +#if NETFX_CORE +using BindingFlags = System.Reflection.BindingFlags; +#endif namespace Svelto.ECS { @@ -12,6 +15,16 @@ namespace Svelto.ECS _nodesToBuild = nodesToBuild; } + public void AddImplementors(params object[] componentsImplementor) + { + var implementors = new object[componentsImplementor.Length + _implementors.Length]; + + Array.Copy(_implementors, implementors, _implementors.Length); + Array.Copy(componentsImplementor, 0, implementors, _implementors.Length, componentsImplementor.Length); + + _implementors = implementors; + } + public virtual FasterList BuildNodes(int ID, Action removeAction) { var nodes = new FasterList(); @@ -73,8 +86,9 @@ namespace Svelto.ECS return node; } - readonly object[] _implementors; - INodeBuilder[] _nodesToBuild; + object[] _implementors; + + readonly INodeBuilder[] _nodesToBuild; } public interface INodeBuilder diff --git a/ECS/GenericEntityDescriptor.cs b/ECS/GenericEntityDescriptor.cs index 16c2687..62ddd73 100644 --- a/ECS/GenericEntityDescriptor.cs +++ b/ECS/GenericEntityDescriptor.cs @@ -5,14 +5,11 @@ { static GenericEntityDescriptor() { - _nodesToBuild = new INodeBuilder[] - { - new NodeBuilder() - }; + _nodesToBuild = new INodeBuilder[] { new NodeBuilder() }; } public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - { - } + {} + static INodeBuilder[] _nodesToBuild; } @@ -28,9 +25,10 @@ new NodeBuilder() }; } + public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) - { - } + {} + static INodeBuilder[] _nodesToBuild; } diff --git a/ECS/GenericEntityDescriptorHolder.cs b/ECS/GenericEntityDescriptorHolder.cs new file mode 100644 index 0000000..4758fa2 --- /dev/null +++ b/ECS/GenericEntityDescriptorHolder.cs @@ -0,0 +1,28 @@ +using System; + +namespace Svelto.ECS +{ + public class GenericEntityDescriptorHolder: UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor + { + public EntityDescriptor BuildDescriptorType(object[] externalImplentors) + { + I[] implementors; + + if (externalImplentors != null) + { + I[] baseImplentors = gameObject.GetComponents(); + + implementors = new I[externalImplentors.Length + baseImplentors.Length]; + + Array.Copy(baseImplentors, implementors, baseImplentors.Length); + Array.Copy(externalImplentors, 0, implementors, baseImplentors.Length, externalImplentors.Length); + } + else + { + implementors = gameObject.GetComponents(); + } + + return (T)Activator.CreateInstance(typeof(T), implementors); + } + } +} \ No newline at end of file diff --git a/ECS/GenericEntityDescriptorHolder.cs.meta b/ECS/GenericEntityDescriptorHolder.cs.meta new file mode 100644 index 0000000..fc5bfc6 --- /dev/null +++ b/ECS/GenericEntityDescriptorHolder.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f2bc0783e8d4a7b49a84705c55d8b255 +timeCreated: 1498225965 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/ICallBackOnAddEngine.cs b/ECS/ICallBackOnAddEngine.cs new file mode 100644 index 0000000..30ac6de --- /dev/null +++ b/ECS/ICallBackOnAddEngine.cs @@ -0,0 +1,7 @@ +namespace Svelto.ECS +{ + interface ICallBackOnAddEngine + { + void Ready(); + } +} \ No newline at end of file diff --git a/ECS/ICallBackOnAddEngine.cs.meta b/ECS/ICallBackOnAddEngine.cs.meta new file mode 100644 index 0000000..80e5f96 --- /dev/null +++ b/ECS/ICallBackOnAddEngine.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3928de9a08e5b534ab857ea8b5bebdaf +timeCreated: 1497524074 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs index 1ac387a..a691298 100644 --- a/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs +++ b/ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs @@ -21,7 +21,6 @@ namespace Svelto.ECS.Profiler } static bool _hideEmptyEngines = true; - static bool _showTickEngines; static bool _showAddEngines; static bool _showRemoveEngines; @@ -31,9 +30,6 @@ namespace Svelto.ECS.Profiler string maxTitle = "Max".PadRight(15, ' '); string avgTitle = "Avg".PadRight(15, ' '); - EnginesMonitor _enginesMonitor; - Queue _engineMonitorData; - const int SYSTEM_MONITOR_DATA_LENGTH = 300; SORTING_OPTIONS _sortingOption = SORTING_OPTIONS.AVERAGE; public override void OnInspectorGUI() diff --git a/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta b/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta index 489305b..11f6ff4 100644 --- a/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta +++ b/ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 3e961e5c8cc40064fa25092d835d1a80 +guid: de0de03babf2e9d4db95c2be94eb8c95 timeCreated: 1462527509 licenseType: Pro MonoImporter: diff --git a/ECS/SingleNodeEngine.cs b/ECS/SingleNodeEngine.cs index f888ee2..6b43243 100644 --- a/ECS/SingleNodeEngine.cs +++ b/ECS/SingleNodeEngine.cs @@ -12,9 +12,7 @@ Remove(obj as TNodeType); } - protected virtual void Add(TNodeType node) - {} - protected virtual void Remove(TNodeType node) - {} + protected abstract void Add(TNodeType node); + protected abstract void Remove(TNodeType node); } } diff --git a/Utilities/WeakActionStruct.cs b/Utilities/WeakActionStruct.cs index 8bb39b4..dff59f6 100644 --- a/Utilities/WeakActionStruct.cs +++ b/Utilities/WeakActionStruct.cs @@ -12,11 +12,16 @@ namespace BetterWeakEvents public WeakAction(Action listener) { ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak); - -#if !NETFX_CORE - Method = listener.Method; -#else +#if NETFX_CORE Method = listener.GetMethodInfo(); + var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); + if(attributes.Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#else + Method = listener.Method; + + if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); #endif } @@ -51,10 +56,16 @@ namespace BetterWeakEvents public WeakAction(Action listener) { ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak); -#if !NETFX_CORE - Method = listener.Method; -#else +#if NETFX_CORE Method = listener.GetMethodInfo(); + var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); + if(attributes.Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#else + Method = listener.Method; + + if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); #endif } @@ -89,10 +100,16 @@ namespace BetterWeakEvents public WeakAction(Action listener) { ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak); -#if !NETFX_CORE - Method = listener.Method; -#else +#if NETFX_CORE Method = listener.GetMethodInfo(); + var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); + if(attributes.Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); +#else + Method = listener.Method; + + if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) + throw new ArgumentException("Cannot create weak event to anonymous method with closure."); #endif }