Browse Source

- added a new Engine callback function called when the engine has been added to be sure that the nodeDB reference has been filled

- improve NETFX_CORE compatibility
- implementors can now be added after the descriptor is created
- SingleNodeEngine is now abstract
tags/Rel1
sebas77 7 years ago
parent
commit
b29472eafc
19 changed files with 372 additions and 69 deletions
  1. +1
    -1
      Context/Factories/GameObjectFactory.cs
  2. +1
    -5
      Context/Factories/MonoBehaviourFactory.cs
  3. +186
    -0
      DataStructures/FasterList.cs
  4. +14
    -1
      DataStructures/ThreadSafeDictionary.cs
  5. +18
    -3
      DataStructures/ThreadSafeQueue.cs
  6. +0
    -0
      ECS/Dispatcher/DispatchOnChange.cs
  7. +0
    -0
      ECS/Dispatcher/DispatchOnChange.cs.meta
  8. +4
    -0
      ECS/EngineNodeDB.cs
  9. +37
    -30
      ECS/EnginesRoot.cs
  10. +16
    -2
      ECS/EntityDescriptor.cs
  11. +6
    -8
      ECS/GenericEntityDescriptor.cs
  12. +28
    -0
      ECS/GenericEntityDescriptorHolder.cs
  13. +12
    -0
      ECS/GenericEntityDescriptorHolder.cs.meta
  14. +7
    -0
      ECS/ICallBackOnAddEngine.cs
  15. +12
    -0
      ECS/ICallBackOnAddEngine.cs.meta
  16. +0
    -4
      ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs
  17. +1
    -1
      ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta
  18. +2
    -4
      ECS/SingleNodeEngine.cs
  19. +27
    -10
      Utilities/WeakActionStruct.cs

+ 1
- 1
Context/Factories/GameObjectFactory.cs View File

@@ -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;



+ 1
- 5
Context/Factories/MonoBehaviourFactory.cs View File

@@ -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();



+ 186
- 0
DataStructures/FasterList.cs View File

@@ -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);


+ 14
- 1
DataStructures/ThreadSafeDictionary.cs View File

@@ -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);
}


+ 18
- 3
DataStructures/ThreadSafeQueue.cs View File

@@ -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();


ECS/Dispatcher/DispatcherOnChange.cs → ECS/Dispatcher/DispatchOnChange.cs View File


ECS/Dispatcher/DispatcherOnChange.cs.meta → ECS/Dispatcher/DispatchOnChange.cs.meta View File


+ 4
- 0
ECS/EngineNodeDB.cs View File

@@ -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>());
}
}

+ 37
- 30
ECS/EnginesRoot.cs View File

@@ -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;
}
}


+ 16
- 2
ECS/EntityDescriptor.cs View File

@@ -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


+ 6
- 8
ECS/GenericEntityDescriptor.cs View File

@@ -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;
}



+ 28
- 0
ECS/GenericEntityDescriptorHolder.cs View File

@@ -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);
}
}
}

+ 12
- 0
ECS/GenericEntityDescriptorHolder.cs.meta View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f2bc0783e8d4a7b49a84705c55d8b255
timeCreated: 1498225965
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 7
- 0
ECS/ICallBackOnAddEngine.cs View File

@@ -0,0 +1,7 @@
namespace Svelto.ECS
{
interface ICallBackOnAddEngine
{
void Ready();
}
}

+ 12
- 0
ECS/ICallBackOnAddEngine.cs.meta View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3928de9a08e5b534ab857ea8b5bebdaf
timeCreated: 1497524074
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 0
- 4
ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs View File

@@ -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
- 1
ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3e961e5c8cc40064fa25092d835d1a80
guid: de0de03babf2e9d4db95c2be94eb8c95
timeCreated: 1462527509
licenseType: Pro
MonoImporter:


+ 2
- 4
ECS/SingleNodeEngine.cs View File

@@ -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);
}
}

+ 27
- 10
Utilities/WeakActionStruct.cs View File

@@ -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
}



Loading…
Cancel
Save