- improve NETFX_CORE compatibility - implementors can now be added after the descriptor is created - SingleNodeEngine is now abstracttags/Rel1
@@ -42,7 +42,7 @@ namespace Svelto.Context | |||
/// Register a prefab to be built later using a string ID. | |||
/// </summary> | |||
/// <param name="prefab">original prefab</param> | |||
public GameObject Build(GameObject prefab) | |||
virtual public GameObject Build(GameObject prefab) | |||
{ | |||
var copy = Object.Instantiate(prefab) as GameObject; | |||
@@ -10,11 +10,7 @@ namespace Svelto.Context | |||
{ | |||
public class MonoBehaviourFactory : Factories.IMonoBehaviourFactory | |||
{ | |||
public MonoBehaviourFactory() | |||
{ | |||
} | |||
public M Build<M>(Func<M> constructor) where M : MonoBehaviour | |||
virtual public M Build<M>(Func<M> constructor) where M : MonoBehaviour | |||
{ | |||
var mb = constructor(); | |||
@@ -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<T> _list; | |||
} | |||
public struct FasterListThreadSafe<T> : IList<T> | |||
{ | |||
public FasterListThreadSafe(FasterList<T> 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<T> 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<T> IEnumerable<T>.GetEnumerator() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
readonly FasterList<T> _list; | |||
readonly ReaderWriterLockSlim _lockQ; | |||
} | |||
public struct FasterReadOnlyListCast<T, U> : IList<U> where U:T | |||
{ | |||
public static FasterList<T> DefaultList = new FasterList<T>(); | |||
@@ -320,6 +498,14 @@ namespace Svelto.DataStructures | |||
_buffer[_count++] = item; | |||
} | |||
/// <summary> | |||
/// this is a dirtish trick to be able to use the index operastor | |||
/// before adding the elements through the Add functions | |||
/// </summary> | |||
/// <typeparam name="U"></typeparam> | |||
/// <param name="initialSize"></param> | |||
/// <returns></returns> | |||
public static FasterList<T> PreFill<U>(int initialSize) where U:T, new() | |||
{ | |||
var list = new FasterList<T>(initialSize); | |||
@@ -1,7 +1,10 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
//note, rewrite like ThreadSafeQueue | |||
namespace Svelto.DataStructures | |||
{ | |||
/// <summary> | |||
@@ -13,6 +16,16 @@ namespace Svelto.DataStructures | |||
[Serializable] | |||
public class ThreadSafeDictionary<TKey, TValue> | |||
{ | |||
public ThreadSafeDictionary(int v) | |||
{ | |||
dict = new Dictionary<TKey, TValue>(v); | |||
} | |||
public ThreadSafeDictionary() | |||
{ | |||
dict = new Dictionary<TKey, TValue>(); | |||
} | |||
// 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<TKey, TValue> dict = new Dictionary<TKey, TValue>(); | |||
readonly IDictionary<TKey, TValue> dict; | |||
[NonSerialized] readonly ReaderWriterLockSlim dictionaryLock = Locks.GetLockInstance(LockRecursionPolicy.NoRecursion); | |||
} | |||
@@ -1,4 +1,3 @@ | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
@@ -6,9 +5,9 @@ namespace Svelto.DataStructures | |||
{ | |||
public class ThreadSafeQueue<T> | |||
{ | |||
private readonly Queue<T> m_Queue; | |||
readonly Queue<T> 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<T> 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<U> DequeueAllAs<U>() where U:class | |||
{ | |||
LockQ.EnterWriteLock(); | |||
@@ -94,6 +94,10 @@ namespace Svelto.ECS | |||
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
Dictionary<Type, FasterList<INode>> _nodesDBgroups; | |||
//Dictionary<Type, ThreadSafeFasterList<INode>> _nodesDB; | |||
//Dictionary<Type, ThreadsSafeDictionary<int, INode>> _nodesDBdic; | |||
// Dictionary<Type, ThreadSafeFasterList<INode>> _nodesDBgroups; | |||
ReadOnlyDictionary<int, INode> _defaultEmptyNodeDict = new ReadOnlyDictionary<int, INode>(new Dictionary<int, INode>()); | |||
} | |||
} |
@@ -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<INode>, 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); | |||
} | |||
/// <summary> | |||
/// 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. | |||
/// </summary> | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
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<Type, FasterList<INodeEngine<INode>>> _nodeEngines; | |||
FasterList<IEngine> _otherEnginesReferences; | |||
Dictionary<Type, FasterList<INode>> _nodesDB; | |||
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
Dictionary<Type, FasterList<INode>> _nodesDBgroups; | |||
FasterList<INode> _nodesToAdd; | |||
FasterList<INode> _groupNodesToAdd; | |||
Dictionary<Type, FasterList<INode>> _nodesDB; | |||
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
WeakReference _engineRootWeakReference; | |||
Dictionary<Type, FasterList<INode>> _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<INode> _nodesToAdd; | |||
FasterList<INode> _groupNodesToAdd; | |||
//future enhancements: | |||
WeakReference _engineRootWeakReference; | |||
} | |||
} | |||
@@ -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<INode> BuildNodes(int ID, Action<INode> removeAction) | |||
{ | |||
var nodes = new FasterList<INode>(); | |||
@@ -73,8 +86,9 @@ namespace Svelto.ECS | |||
return node; | |||
} | |||
readonly object[] _implementors; | |||
INodeBuilder[] _nodesToBuild; | |||
object[] _implementors; | |||
readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public interface INodeBuilder | |||
@@ -5,14 +5,11 @@ | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
_nodesToBuild = new INodeBuilder[] | |||
{ | |||
new NodeBuilder<T>() | |||
}; | |||
_nodesToBuild = new INodeBuilder[] { new NodeBuilder<T>() }; | |||
} | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{ | |||
} | |||
{} | |||
static INodeBuilder[] _nodesToBuild; | |||
} | |||
@@ -28,9 +25,10 @@ | |||
new NodeBuilder<U>() | |||
}; | |||
} | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{ | |||
} | |||
{} | |||
static INodeBuilder[] _nodesToBuild; | |||
} | |||
@@ -0,0 +1,28 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class GenericEntityDescriptorHolder<T, I>: UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor | |||
{ | |||
public EntityDescriptor BuildDescriptorType(object[] externalImplentors) | |||
{ | |||
I[] implementors; | |||
if (externalImplentors != null) | |||
{ | |||
I[] baseImplentors = gameObject.GetComponents<I>(); | |||
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<I>(); | |||
} | |||
return (T)Activator.CreateInstance(typeof(T), implementors); | |||
} | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
fileFormatVersion: 2 | |||
guid: f2bc0783e8d4a7b49a84705c55d8b255 | |||
timeCreated: 1498225965 | |||
licenseType: Pro | |||
MonoImporter: | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -0,0 +1,7 @@ | |||
namespace Svelto.ECS | |||
{ | |||
interface ICallBackOnAddEngine | |||
{ | |||
void Ready(); | |||
} | |||
} |
@@ -0,0 +1,12 @@ | |||
fileFormatVersion: 2 | |||
guid: 3928de9a08e5b534ab857ea8b5bebdaf | |||
timeCreated: 1497524074 | |||
licenseType: Pro | |||
MonoImporter: | |||
serializedVersion: 2 | |||
defaultReferences: [] | |||
executionOrder: 0 | |||
icon: {instanceID: 0} | |||
userData: | |||
assetBundleName: | |||
assetBundleVariant: |
@@ -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<float> _engineMonitorData; | |||
const int SYSTEM_MONITOR_DATA_LENGTH = 300; | |||
SORTING_OPTIONS _sortingOption = SORTING_OPTIONS.AVERAGE; | |||
public override void OnInspectorGUI() | |||
@@ -1,5 +1,5 @@ | |||
fileFormatVersion: 2 | |||
guid: 3e961e5c8cc40064fa25092d835d1a80 | |||
guid: de0de03babf2e9d4db95c2be94eb8c95 | |||
timeCreated: 1462527509 | |||
licenseType: Pro | |||
MonoImporter: | |||
@@ -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); | |||
} | |||
} |
@@ -12,11 +12,16 @@ namespace BetterWeakEvents | |||
public WeakAction(Action<T1, T2> 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<T> 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 | |||
} | |||