Browse Source

Merge pull request #4 from sebas77/alpha

Alpha
tags/Rel1
Sebastiano Mandalà GitHub 7 years ago
parent
commit
4180eef16b
93 changed files with 3592 additions and 1065 deletions
  1. +8
    -12
      Context/ContextNotifier.cs
  2. +2
    -2
      Context/Factories/GameObjectFactory.cs
  3. +9
    -0
      Context/Factories/Legacy.meta
  4. +98
    -0
      Context/Factories/Legacy/GameObjectFactory.cs
  5. +3
    -1
      Context/Factories/Legacy/GameObjectFactory.cs.meta
  6. +36
    -0
      Context/Factories/Legacy/MonoBehaviourFactory.cs
  7. +3
    -1
      Context/Factories/Legacy/MonoBehaviourFactory.cs.meta
  8. +1
    -1
      Context/IContextNotifer.cs
  9. +11
    -0
      Context/IUnityContextHierarchyChangedListener.cs
  10. +8
    -0
      Context/IUnityContextHierarchyChangedListener.cs.meta
  11. +9
    -0
      Context/Unity.meta
  12. +30
    -0
      Context/Unity/NotifyComponentsRemoved.cs
  13. +8
    -0
      Context/Unity/NotifyComponentsRemoved.cs.meta
  14. +183
    -0
      DataStructures/CircularBufferIndexer.cs
  15. +8
    -0
      DataStructures/CircularBufferIndexer.cs.meta
  16. +146
    -112
      DataStructures/FasterList.cs
  17. +3
    -1
      DataStructures/FasterList.cs.meta
  18. +56
    -0
      DataStructures/HashableWeakReference.cs
  19. +3
    -1
      DataStructures/HashableWeakReference.cs.meta
  20. +1
    -1
      DataStructures/Priority Queue.meta
  21. +327
    -0
      DataStructures/Priority Queue/HeapPriorityQueue.cs
  22. +8
    -0
      DataStructures/Priority Queue/HeapPriorityQueue.cs.meta
  23. +23
    -0
      DataStructures/Priority Queue/IPriorityQueue.cs
  24. +8
    -0
      DataStructures/Priority Queue/IPriorityQueue.cs.meta
  25. +24
    -0
      DataStructures/Priority Queue/PriorityQueueNode.cs
  26. +8
    -0
      DataStructures/Priority Queue/PriorityQueueNode.cs.meta
  27. +154
    -265
      DataStructures/ReadOnlyDictionary.cs
  28. +183
    -0
      DataStructures/SerializableDictionary.cs
  29. +7
    -0
      DataStructures/SerializableDictionary.cs.meta
  30. +303
    -0
      DataStructures/ThreadSafeDictionary.cs
  31. +3
    -1
      DataStructures/ThreadSafeDictionary.cs.meta
  32. +50
    -3
      DataStructures/ThreadSafeQueue.cs
  33. +5
    -0
      DataStructures/WeakReference.cs
  34. +2
    -0
      ECS.meta
  35. +0
    -39
      ECS/Dispatcher/Dispatcher.cs
  36. +0
    -12
      ECS/Dispatcher/Dispatcher.cs.meta
  37. +13
    -23
      ECS/Dispatcher/DispatcherOnChange.cs
  38. +43
    -0
      ECS/Dispatcher/DispatcherOnSet.cs
  39. +12
    -0
      ECS/Dispatcher/DispatcherOnSet.cs.meta
  40. +36
    -7
      ECS/EngineNodeDB.cs
  41. +183
    -34
      ECS/EnginesRoot.cs
  42. +30
    -33
      ECS/EntityDescriptor.cs
  43. +127
    -0
      ECS/GenericEntityDescriptor.cs
  44. +12
    -0
      ECS/GenericEntityDescriptor.cs.meta
  45. +0
    -6
      ECS/IComponent.cs
  46. +1
    -17
      ECS/IEngine.cs
  47. +8
    -1
      ECS/IEngineNodeDB.cs
  48. +3
    -1
      ECS/IEnginesRoot.cs
  49. +6
    -5
      ECS/IEntityDescriptorHolder.cs
  50. +1
    -1
      ECS/IEntityDescriptorHolder.cs.meta
  51. +6
    -0
      ECS/IImplementor.cs
  52. +0
    -0
      ECS/IImplementor.cs.meta
  53. +2
    -2
      ECS/INode.cs
  54. +1
    -1
      ECS/IRemoveEntityComponent.cs
  55. +9
    -0
      ECS/Profiler.meta
  56. +9
    -0
      ECS/Profiler/Editor.meta
  57. +9
    -0
      ECS/Profiler/Editor/EngineProfiler.meta
  58. +373
    -0
      ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs
  59. +12
    -0
      ECS/Profiler/Editor/EngineProfiler/EngineProfilerInspector.cs.meta
  60. +22
    -0
      ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs
  61. +12
    -0
      ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs.meta
  62. +132
    -0
      ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs
  63. +12
    -0
      ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs.meta
  64. +65
    -0
      ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs
  65. +12
    -0
      ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta
  66. +167
    -0
      ECS/Profiler/EngineInfo.cs
  67. +12
    -0
      ECS/Profiler/EngineInfo.cs.meta
  68. +126
    -0
      ECS/Profiler/EngineProfiler.cs
  69. +12
    -0
      ECS/Profiler/EngineProfiler.cs.meta
  70. +19
    -0
      ECS/Profiler/EngineProfilerBehaviour.cs
  71. +12
    -0
      ECS/Profiler/EngineProfilerBehaviour.cs.meta
  72. +52
    -0
      ECS/Sequencer.cs
  73. +12
    -0
      ECS/Sequencer.cs.meta
  74. +20
    -0
      ECS/SingleNodeEngine.cs
  75. +12
    -0
      ECS/SingleNodeEngine.cs.meta
  76. +3
    -3
      Factories.meta
  77. +0
    -42
      Observer/Observable.cs
  78. +0
    -12
      Observer/Observable.cs.meta
  79. +0
    -111
      Observer/Observer.cs
  80. +0
    -12
      Observer/Observer.cs.meta
  81. +0
    -5
      Ticker.meta
  82. +0
    -31
      Ticker/ITickable.cs
  83. +0
    -8
      Ticker/ITicker.cs
  84. +0
    -15
      Ticker/IntervaledTickAttribute.cs
  85. +0
    -12
      Ticker/IntervaledTickAttribute.cs.meta
  86. +0
    -153
      Ticker/TickBehaviour.cs
  87. +0
    -57
      Ticker/UnityTicker.cs
  88. +3
    -3
      Utilities.meta
  89. +79
    -18
      Utilities/Print.cs
  90. +122
    -0
      Utilities/WeakActionStruct.cs
  91. +12
    -0
      Utilities/WeakActionStruct.cs.meta
  92. +35
    -0
      Utilities/WeakEvent.cs
  93. +12
    -0
      Utilities/WeakEvent.cs.meta

+ 8
- 12
Context/ContextNotifier.cs View File

@@ -1,6 +1,6 @@
using Svelto.DataStructures;
using System;
using System.Collections.Generic;
using Svelto.DataStructures;

namespace Svelto.Context
{
@@ -33,19 +33,17 @@ namespace Svelto.Context
/// </summary>
public void NotifyFrameworkDeinitialized()
{
for (int i = _toDeinitialize.Count - 1; i >= 0; --i)
{
for (var i = _toDeinitialize.Count - 1; i >= 0; --i)
try
{
var obj = _toDeinitialize[i];
if (obj.IsAlive == true)
(obj.Target as IWaitForFrameworkDestruction).OnFrameworkDestroyed();
if (obj.IsAlive)
obj.Target.OnFrameworkDestroyed();
}
catch (Exception e)
{
Utility.Console.LogException(e);
}
}

_toDeinitialize = null;
}
@@ -55,24 +53,22 @@ namespace Svelto.Context
/// </summary>
public void NotifyFrameworkInitialized()
{
for (int i = _toInitialize.Count - 1; i >= 0; --i)
{
for (var i = _toInitialize.Count - 1; i >= 0; --i)
try
{
var obj = _toInitialize[i];
if (obj.IsAlive == true)
(obj.Target as IWaitForFrameworkInitialization).OnFrameworkInitialized();
if (obj.IsAlive)
obj.Target.OnFrameworkInitialized();
}
catch (Exception e)
{
Utility.Console.LogException(e);
}
}

_toInitialize = null;
}

List<WeakReference<IWaitForFrameworkDestruction>> _toDeinitialize;
List<WeakReference<IWaitForFrameworkDestruction>> _toDeinitialize;
List<WeakReference<IWaitForFrameworkInitialization>> _toInitialize;
}
}

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

@@ -16,7 +16,7 @@ namespace Svelto.Context

public GameObject Build(string prefabName)
{
DesignByContract.Check.Require(_prefabs.ContainsKey(prefabName), "Svelto.Factories.IGameObjectFactory - Invalid Prefab Type");
DesignByContract.Check.Require(_prefabs.ContainsKey(prefabName), "Svelto.Factories.IGameObjectFactory -prefab was not found:" + prefabName);

var go = Build(_prefabs[prefabName][0]);

@@ -48,7 +48,7 @@ namespace Svelto.Context
/// <param name="prefab">original prefab</param>
public GameObject Build(GameObject prefab)
{
Profiler.BeginSample("GameObject Factory Build");
UnityEngine.Profiling.Profiler.BeginSample("GameObject Factory Build");

var copy = Object.Instantiate(prefab) as GameObject;



+ 9
- 0
Context/Factories/Legacy.meta View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8d34411ef4f6005489ca3bb91987c84a
folderAsset: yes
timeCreated: 1466179612
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 98
- 0
Context/Factories/Legacy/GameObjectFactory.cs View File

@@ -0,0 +1,98 @@
#region

using System.Collections.Generic;
using Svelto.Context.Legacy;
using Svelto.DataStructures;
using UnityEngine;

#endregion

namespace Svelto.Context.Legacy
{
public class GameObjectFactory : Factories.IGameObjectFactory
{
public GameObjectFactory(IUnityContextHierarchyChangedListener root)
{
_unityContext = new WeakReference<IUnityContextHierarchyChangedListener>(root);

_prefabs = new Dictionary<string, GameObject[]>();
}

public GameObject Build(string prefabName)
{
DesignByContract.Check.Require(_prefabs.ContainsKey(prefabName), "Svelto.Factories.IGameObjectFactory - Invalid Prefab Type");

var go = Build(_prefabs[prefabName][0]);

GameObject parent = _prefabs[prefabName][1];

if (parent != null)
{
Transform transform = go.transform;

var scale = transform.localScale;
var rotation = transform.localRotation;
var position = transform.localPosition;

parent.SetActive(true);

transform.parent = parent.transform;

transform.localPosition = position;
transform.localRotation = rotation;
transform.localScale = scale;
}

return go;
}

/// <summary>
/// Register a prefab to be built later using a string ID.
/// </summary>
/// <param name="prefab">original prefab</param>
public GameObject Build(GameObject prefab)
{
DesignByContract.Check.Require(_unityContext.IsAlive == true, "Context is used, but not alive");

UnityEngine.Profiling.Profiler.BeginSample("GameObject Factory Build");

var copy = Object.Instantiate(prefab) as GameObject;
var components = copy.GetComponentsInChildren<MonoBehaviour>(true);

for (var i = 0; i < components.Length; ++i)
{
var monoBehaviour = components[i];
if (monoBehaviour != null)
{
var currentGo = monoBehaviour.gameObject;

_unityContext.Target.OnMonobehaviourAdded(monoBehaviour);
if (currentGo.GetComponent<NotifyComponentsRemoved>() == null)
currentGo.AddComponent<NotifyComponentsRemoved>().unityContext = _unityContext;
}
else
{
//Utility.Console.Log("delete me");
}
}

UnityEngine.Profiling.Profiler.EndSample();

return copy;
}

public void RegisterPrefab(GameObject prefab, string prefabName, GameObject parent = null)
{
var objects = new GameObject[2];

objects[0] = prefab; objects[1] = parent;

_prefabs.Add(prefabName, objects);
}

Dictionary<string, GameObject[]> _prefabs;
WeakReference<IUnityContextHierarchyChangedListener> _unityContext;
}
}

Ticker/ITickable.cs.meta → Context/Factories/Legacy/GameObjectFactory.cs.meta View File

@@ -1,5 +1,7 @@
fileFormatVersion: 2
guid: 8830537b810b3fa489b14e66327f0af2
guid: 110a36d7de251bc41a444815f58a61c5
timeCreated: 1466179612
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []

+ 36
- 0
Context/Factories/Legacy/MonoBehaviourFactory.cs View File

@@ -0,0 +1,36 @@
#region

using System;
using Svelto.DataStructures;
using UnityEngine;

#endregion

namespace Svelto.Context.Legacy
{
public class MonoBehaviourFactory : Factories.IMonoBehaviourFactory
{
public MonoBehaviourFactory(IUnityContextHierarchyChangedListener unityContext)
{
_unityContext = new WeakReference<IUnityContextHierarchyChangedListener>(unityContext);
}

public M Build<M>(Func<M> constructor) where M : MonoBehaviour
{
DesignByContract.Check.Require(_unityContext.IsAlive == true, "Context is used, but not alive");

var mb = constructor();

_unityContext.Target.OnMonobehaviourAdded(mb);

GameObject go = mb.gameObject;

if (go.GetComponent<NotifyComponentsRemoved>() == null)
go.AddComponent<NotifyComponentsRemoved>().unityContext = _unityContext;

return mb;
}

WeakReference<IUnityContextHierarchyChangedListener> _unityContext;
}
}

Ticker/ITicker.cs.meta → Context/Factories/Legacy/MonoBehaviourFactory.cs.meta View File

@@ -1,5 +1,7 @@
fileFormatVersion: 2
guid: 0bf92a08bb722064ab845dea9463933e
guid: 86181a20ee37df64c9332a1c32369d72
timeCreated: 1466179768
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []

+ 1
- 1
Context/IContextNotifer.cs View File

@@ -5,7 +5,7 @@ namespace Svelto.Context
void NotifyFrameworkInitialized();
void NotifyFrameworkDeinitialized();

void AddFrameworkInitializationListener(IWaitForFrameworkInitialization obj);
void AddFrameworkInitializationListener(IWaitForFrameworkInitialization obj);
void AddFrameworkDestructionListener(IWaitForFrameworkDestruction obj);
}
}

+ 11
- 0
Context/IUnityContextHierarchyChangedListener.cs View File

@@ -0,0 +1,11 @@
using UnityEngine;

namespace Svelto.Context.Legacy
{
public interface IUnityContextHierarchyChangedListener
{
void OnMonobehaviourAdded(MonoBehaviour component);

void OnMonobehaviourRemoved(MonoBehaviour component);
}
}

+ 8
- 0
Context/IUnityContextHierarchyChangedListener.cs.meta View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 905bfd795bede6d448694b23dd88e0be
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

+ 9
- 0
Context/Unity.meta View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 14144568b327bbe40876c12a777e5f05
folderAsset: yes
timeCreated: 1434752394
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 30
- 0
Context/Unity/NotifyComponentsRemoved.cs View File

@@ -0,0 +1,30 @@
using Svelto.DataStructures;
using UnityEngine;

namespace Svelto.Context.Legacy
{
public class NotifyComponentsRemoved : MonoBehaviour
{
public WeakReference<IUnityContextHierarchyChangedListener> unityContext { private get; set; }

void Start()
{
if (unityContext == null)
{
Destroy(this);
}
}

void OnDestroy()
{
if (unityContext == null || unityContext.IsAlive == false)
return;

MonoBehaviour[] components = gameObject.GetComponents<MonoBehaviour>();

for (int i = 0; i < components.Length; ++i)
if (components[i] != null)
unityContext.Target.OnMonobehaviourRemoved(components[i]);
}
}
}

+ 8
- 0
Context/Unity/NotifyComponentsRemoved.cs.meta View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 13278f0cd187d8d43acc6a02479e459b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

+ 183
- 0
DataStructures/CircularBufferIndexer.cs View File

@@ -0,0 +1,183 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace Svelto.DataStructures
{
// Serves as simple circular buffer dictionary, first in, first out
// Main drawback: it is the oldest in the list that is removed and the fact that we might re access a key
// isn't taken into account (we would have to do a shift in both arrays)
// Could be added as an option?

class CircularBufferIndexer<TKey, TVal> : IDictionary<TKey, TVal>
{
public ICollection<TKey> Keys
{
get { return _keys; }
}

public ICollection<TVal> Values
{
get { return _values; }
}

public int Count
{
get { throw new NotImplementedException(); }
}

public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}

public CircularBufferIndexer(int size)
{
_keys = new TKey[size];
_values = new TVal[size];
_length = _startIndex = _nextIndex = 0;
}

public TVal this[TKey key]
{
get
{
int index = _startIndex;
for (int i = 0; i < _length; ++i)
{
if (_keys[index].Equals(key))
{
return _values[index];
}

index = NextPosition(index);
}
throw new KeyNotFoundException();
}
set
{
int index = _startIndex;
for (int i = 0; i < _length; ++i)
{
if (_keys[index].Equals(key))
{
_values[index] = value;
return;
}

index = NextPosition(index);
}
throw new KeyNotFoundException();
}
}

public void Add(TKey key, TVal value)
{
if (ContainsKey(key))
{
this[key] = value;
return;
}

_keys[_nextIndex] = key;
_values[_nextIndex] = value;
_nextIndex = NextPosition(_nextIndex);
if (IsFull())
{
_startIndex = NextPosition(_startIndex);
}
else
{
++_length;
}
}

public bool ContainsKey(TKey key)
{
int index = _startIndex;
for (int i = 0; i < _length; ++i)
{
if (_keys[index].Equals(key))
{
return true;
}

index = NextPosition(index);
}
return false;
}

public bool Remove(TKey key)
{
throw new NotImplementedException();
}

public bool TryGetValue(TKey key, out TVal value)
{
value = default(TVal);
int index = _startIndex;
for (int i = 0; i < _length; ++i)
{
if (_keys[index].Equals(key))
{
value = _values[index];
return true;
}

index = NextPosition(index);
}
return false;
}

public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}

public void Add(KeyValuePair<TKey, TVal> item)
{
Add(item.Key, item.Value);
}

public void Clear()
{
throw new NotImplementedException();
}

public bool Contains(KeyValuePair<TKey, TVal> item)
{
throw new NotImplementedException();
}

public void CopyTo(KeyValuePair<TKey, TVal>[] array, int arrayIndex)
{
throw new NotImplementedException();
}

public bool Remove(KeyValuePair<TKey, TVal> item)
{
throw new NotImplementedException();
}

IEnumerator<KeyValuePair<TKey, TVal>> IEnumerable<KeyValuePair<TKey, TVal>>.GetEnumerator()
{
throw new NotImplementedException();
}

int NextPosition(int position)
{
return (position + 1) % _keys.Length;
}

bool IsFull()
{
return _length == _values.Length;
}

TKey[] _keys;
TVal[] _values;
int _startIndex;
int _nextIndex;
int _length;
}
}

+ 8
- 0
DataStructures/CircularBufferIndexer.cs.meta View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0d87fb4479e8365499c162fe0fc94acc
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

+ 146
- 112
DataStructures/FasterList.cs View File

@@ -1,7 +1,3 @@
/**
* Custom modified version of Michael Lyashenko's BetterList
**/

using System;
using System.Collections;
using System.Collections.Generic;
@@ -16,16 +12,6 @@ namespace Svelto.DataStructures
get { return _current; }
}

object IEnumerator.Current
{
get { return _current; }
}

T IEnumerator<T>.Current
{
get { return _current; }
}

public FasterListEnumerator(T[] buffer, int size)
{
_size = size;
@@ -34,19 +20,19 @@ namespace Svelto.DataStructures
_current = default(T);
}

public void Dispose()
object IEnumerator.Current
{
_buffer = null;
get { return _current; }
}

bool IEnumerator.MoveNext()
T IEnumerator<T>.Current
{
return MoveNext();
get { return _current; }
}

void IEnumerator.Reset()
public void Dispose()
{
Reset();
_buffer = null;
}

public bool MoveNext()
@@ -68,6 +54,16 @@ namespace Svelto.DataStructures
_counter = 0;
}

bool IEnumerator.MoveNext()
{
return MoveNext();
}

void IEnumerator.Reset()
{
Reset();
}

T[] _buffer;
int _counter;
int _size;
@@ -81,42 +77,42 @@ namespace Svelto.DataStructures
get { return (T)_buffer.Current; }
}

object IEnumerator.Current
public FasterListEnumeratorCast(FasterListEnumerator<U> buffer)
{
get { return (T)_buffer.Current; }
_buffer = buffer;
}

T IEnumerator<T>.Current
object IEnumerator.Current
{
get { return (T)_buffer.Current; }
}

public FasterListEnumeratorCast(FasterListEnumerator<U> buffer)
T IEnumerator<T>.Current
{
_buffer = buffer;
get { return (T)_buffer.Current; }
}

public void Dispose()
{}

bool IEnumerator.MoveNext()
public bool MoveNext()
{
return MoveNext();
return _buffer.MoveNext();
}

void IEnumerator.Reset()
public void Reset()
{
Reset();
_buffer.Reset();
}

public bool MoveNext()
bool IEnumerator.MoveNext()
{
return _buffer.MoveNext();
return MoveNext();
}

public void Reset()
void IEnumerator.Reset()
{
_buffer.Reset();
Reset();
}

FasterListEnumerator<U> _buffer;
@@ -124,20 +120,15 @@ namespace Svelto.DataStructures

public struct FasterReadOnlyList<T> : IList<T>
{
public int Count { get { return _list.Count; } }
public bool IsReadOnly { get { return true; } }

public FasterReadOnlyList(FasterList<T> list)
{
_list = list;
}

IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } }

public FasterListEnumerator<T> GetEnumerator()
{
@@ -169,9 +160,6 @@ namespace Svelto.DataStructures
throw new NotImplementedException();
}

public int Count { get { return _list.Count; } }
public bool IsReadOnly { get { return true; } }

public int IndexOf(T item)
{
return _list.IndexOf(item);
@@ -187,27 +175,32 @@ namespace Svelto.DataStructures
throw new NotImplementedException();
}

public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } }
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

readonly FasterList<T> _list;
}

public struct FasterReadOnlyListCast<T, U> : IList<U> where U:T
{
public static FasterList<T> DefaultList = new FasterList<T>();

public int Count { get { return _list.Count; } }
public bool IsReadOnly { get { return true; } }

public FasterReadOnlyListCast(FasterList<T> list)
{
_list = list;
}

IEnumerator<U> IEnumerable<U>.GetEnumerator()
{
return GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public U this[int index] { get { return (U)_list[index]; } set { throw new NotImplementedException(); } }

public FasterListEnumeratorCast<U, T> GetEnumerator()
{
@@ -239,9 +232,6 @@ namespace Svelto.DataStructures
throw new NotImplementedException();
}

public int Count { get { return _list.Count; } }
public bool IsReadOnly { get { return true; } }

public int IndexOf(U item)
{
return _list.IndexOf(item);
@@ -257,14 +247,23 @@ namespace Svelto.DataStructures
throw new NotImplementedException();
}

public U this[int index] { get { return (U)_list[index]; } set { throw new NotImplementedException(); } }
IEnumerator<U> IEnumerable<U>.GetEnumerator()
{
return GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

readonly FasterList<T> _list;
static public FasterList<T> DefaultList = new FasterList<T>();
}

public class FasterList<T> : IList<T>
{
const int MIN_SIZE = 4;

public int Count
{
get { return _count; }
@@ -307,6 +306,12 @@ namespace Svelto.DataStructures
_count = listCopy.Count;
}

public T this[int i]
{
get { DesignByContract.Check.Require(i < _count, "out of bound index"); return _buffer[i]; }
set { DesignByContract.Check.Require(i < _count, "out of bound index"); _buffer[i] = value; }
}

public void Add(T item)
{
if (_count == _buffer.Length)
@@ -315,44 +320,46 @@ namespace Svelto.DataStructures
_buffer[_count++] = item;
}

public static FasterList<T> PreFill<U>(int initialSize) where U:T, new()
{
var list = new FasterList<T>(initialSize);

for (int i = 0; i < initialSize; i++)
list.Add(new U());

list.Clear();

return list;
}

public void AddRange(IEnumerable<T> items, int count)
{
AddRange(items.GetEnumerator(), count);
}

public void AddRange(IEnumerator<T> items, int count)
{
if (_count + count >= _buffer.Length)
AllocateMore(_count + count);

for (var i = items.GetEnumerator(); i.MoveNext();)
{
var item = i.Current;
_buffer[_count++] = item;
}
while (items.MoveNext())
_buffer[_count++] = items.Current;
}

public void AddRange(ICollection<T> items)
{
var count = items.Count;
if (_count + count >= _buffer.Length)
AllocateMore(_count + count);

for (var i = items.GetEnumerator(); i.MoveNext();)
{
var item = i.Current;
_buffer[_count++] = item;
}
AddRange(items.GetEnumerator(), items.Count);
}

public void AddRange(FasterList<T> items)
{
var count = items.Count;
if (_count + count >= _buffer.Length)
AllocateMore(_count + count);

Array.Copy(items._buffer, 0, _buffer, _count, count);
_count += count;
AddRange(items.ToArrayFast(), items.Count);
}

public void AddRange(T[] items)
public void AddRange(T[] items, int count)
{
var count = items.Length;
if (count == 0) return;

if (_count + count >= _buffer.Length)
AllocateMore(_count + count);

@@ -365,11 +372,22 @@ namespace Svelto.DataStructures
return new FasterReadOnlyList<T>(this);
}

/// <summary>
/// Careful, you could keep on holding references you don't want to hold to anymore
/// Use DeepClear in case.
/// </summary>
public void Clear()
{
_count = 0;
}

public void DeepClear()
{
Array.Clear(_buffer, 0, _buffer.Length);

_count = 0;
}

public bool Contains(T item)
{
var index = IndexOf(item);
@@ -387,16 +405,6 @@ namespace Svelto.DataStructures
return new FasterListEnumerator<T>(_buffer, Count);
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}

public int IndexOf(T item)
{
var comp = EqualityComparer<T>.Default;
@@ -442,16 +450,19 @@ namespace Svelto.DataStructures
{
DesignByContract.Check.Require(index < _count, "out of bound index");

--_count;

if (index == _count)
if (index == --_count)
return;

Array.Copy(_buffer, index + 1, _buffer, index, _count - index);

_buffer[_count] = default(T);
}

public void Resize(int newSize)
{
if (newSize < MIN_SIZE)
newSize = MIN_SIZE;

Array.Resize(ref _buffer, newSize);

_count = newSize;
@@ -468,10 +479,9 @@ namespace Svelto.DataStructures
this[index] = value;
}

public void Sort(Comparison<T> comparer)
public void Sort(IComparer<T> comparer)
{
Trim();
Array.Sort(_buffer, comparer);
Array.Sort(_buffer, 0, _count, comparer);
}

public T[] ToArray()
@@ -505,46 +515,70 @@ namespace Svelto.DataStructures
return true;
}

public void UnorderredRemoveAt(int index)
public T UnorderredRemoveAt(int index)
{
DesignByContract.Check.Require(index < _count, "out of bound index");
DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index");

_buffer[index] = _buffer[--_count];
T item = _buffer[index];

if (index == --_count)
return item;

T swap = _buffer[index];
_buffer[index] = _buffer[_count];
_buffer[_count] = swap;

return item;
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

private void AllocateMore()
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}

void AllocateMore()
{
var newList = new T[Mathf.Max(_buffer.Length << 1, MIN_SIZE)];
if (_count > 0) _buffer.CopyTo(newList, 0);
_buffer = newList;
}

private void AllocateMore(int newSize)
void AllocateMore(int newSize)
{
var oldLength = _buffer.Length;
var oldLength = Mathf.Max(_buffer.Length, MIN_SIZE);

while (oldLength < newSize)
oldLength <<= 1;

var newList = new T[oldLength];
if (_count > 0) _buffer.CopyTo(newList, 0);
if (_count > 0) Array.Copy(_buffer, newList, _count);
_buffer = newList;
}

private void Trim()
public void Trim()
{
if (_count < _buffer.Length)
Resize(_count);
}

public T this[int i]
public bool Reuse(int index, out T result)
{
get { DesignByContract.Check.Require(i < _count, "out of bound index"); return _buffer[i]; }
set { DesignByContract.Check.Require(i < _count, "out of bound index"); _buffer[i] = value; }
result = default(T);

if (index >= _buffer.Length)
return false;

result = _buffer[index];

return result != null;
}

private const int MIN_SIZE = 32;
private T[] _buffer;
private int _count;
T[] _buffer;
int _count;
}
}

+ 3
- 1
DataStructures/FasterList.cs.meta View File

@@ -1,5 +1,7 @@
fileFormatVersion: 2
guid: 0859454e6e6d968498cea54757578eda
guid: d19e59cbec974dd4d821a7dd21f87a88
timeCreated: 1472488070
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []


+ 56
- 0
DataStructures/HashableWeakReference.cs View File

@@ -0,0 +1,56 @@
using System;

namespace Svelto.DataStructures
{
class HashableWeakRef<T> : IEquatable<HashableWeakRef<T>> where T : class
{
public bool isAlive { get { return _weakRef.IsAlive; } }
public T Target { get { return (T)_weakRef.Target; } }

public HashableWeakRef(T target)
{
_weakRef = new WeakReference(target);
_hash = target.GetHashCode();
}

public static bool operator !=(HashableWeakRef<T> a, HashableWeakRef<T> b)
{
return !(a == b);
}

public static bool operator ==(HashableWeakRef<T> a, HashableWeakRef<T> b)
{
if (a._hash != b._hash)
return false;

var tmpTargetA = (T) a._weakRef.Target;
var tmpTargetB = (T) b._weakRef.Target;

if (tmpTargetA == null || tmpTargetB == null)
return false;

return tmpTargetA == tmpTargetB;
}

public override bool Equals(object other)
{
if (other is HashableWeakRef<T>)
return this.Equals((HashableWeakRef<T>)other);

return false;
}

public bool Equals(HashableWeakRef<T> other)
{
return (this == other);
}

public override int GetHashCode()
{
return _hash;
}

int _hash;
WeakReference _weakRef;
}
}

Ticker/TickBehaviour.cs.meta → DataStructures/HashableWeakReference.cs.meta View File

@@ -1,5 +1,7 @@
fileFormatVersion: 2
guid: 82d08d9d100803c47b036667fdc671cf
guid: 0cfa789b3147c2e4e80d067693a58103
timeCreated: 1455809369
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []

Observer.meta → DataStructures/Priority Queue.meta View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 48e872bc336b396409c9316cdbfc045a
guid: 8fffa27a4e8919a4db6fe1369e22e1b5
folderAsset: yes
DefaultImporter:
userData:

+ 327
- 0
DataStructures/Priority Queue/HeapPriorityQueue.cs View File

@@ -0,0 +1,327 @@
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Svelto.DataStructures;

namespace Svelto.DataStructures
{
/// <summary>
/// An implementation of a min-Priority Queue using a heap. Has O(1) .Contains()!
/// See https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Getting%20Started for more information
/// </summary>
/// <typeparam name="T">The values in the queue. Must implement the PriorityQueueNode interface</typeparam>
public sealed class HeapPriorityQueue<T> : IPriorityQueue<T>
where T : PriorityQueueNode
{
private int _numNodes;
private readonly FasterList<T> _nodes;
private long _numNodesEverEnqueued;

/// <summary>
/// Instantiate a new Priority Queue
/// </summary>
/// <param name="maxNodes">The max nodes ever allowed to be enqueued (going over this will cause an exception)</param>
public HeapPriorityQueue()
{
_numNodes = 0;
_nodes = new FasterList<T>();
_numNodesEverEnqueued = 0;
}

public HeapPriorityQueue(int initialSize)
{
_numNodes = 0;
_nodes = new FasterList<T>(initialSize);
_numNodesEverEnqueued = 0;
}
/// <summary>
/// Returns the number of nodes in the queue. O(1)
/// </summary>
public int Count
{
get
{
return _numNodes;
}
}

/// <summary>
/// Returns the maximum number of items that can be enqueued at once in this queue. Once you hit this number (ie. once Count == MaxSize),
/// attempting to enqueue another item will throw an exception. O(1)
/// </summary>
public int MaxSize
{
get
{
return _nodes.Count - 1;
}
}

/// <summary>
/// Removes every node from the queue. O(n) (So, don't do this often!)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void Clear()
{
_nodes.Clear();

_numNodes = 0;
}

/// <summary>
/// Returns (in O(1)!) whether the given node is in the queue. O(1)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public bool Contains(T node)
{
return (_nodes[node.QueueIndex] == node);
}

/// <summary>
/// Enqueue a node - .Priority must be set beforehand! O(log n)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void Enqueue(T node, double priority)
{
node.Priority = priority;
_numNodes++;
if (_nodes.Count < _numNodes)
_nodes.Resize(_numNodes + 1);

_nodes[_numNodes] = node;
node.QueueIndex = _numNodes;
node.InsertionIndex = _numNodesEverEnqueued++;
CascadeUp(_nodes[_numNodes]);
}

#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private void Swap(T node1, T node2)
{
//Swap the nodes
_nodes[node1.QueueIndex] = node2;
_nodes[node2.QueueIndex] = node1;

//Swap their indicies
int temp = node1.QueueIndex;
node1.QueueIndex = node2.QueueIndex;
node2.QueueIndex = temp;
}

//Performance appears to be slightly better when this is NOT inlined o_O
private void CascadeUp(T node)
{
//aka Heapify-up
int parent = node.QueueIndex / 2;
while(parent >= 1)
{
T parentNode = _nodes[parent];
if(HasHigherPriority(parentNode, node))
break;

//Node has lower priority value, so move it up the heap
Swap(node, parentNode); //For some reason, this is faster with Swap() rather than (less..?) individual operations, like in CascadeDown()

parent = node.QueueIndex / 2;
}
}

#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private void CascadeDown(T node)
{
//aka Heapify-down
T newParent;
int finalQueueIndex = node.QueueIndex;
while(true)
{
newParent = node;
int childLeftIndex = 2 * finalQueueIndex;

//Check if the left-child is higher-priority than the current node
if(childLeftIndex > _numNodes)
{
//This could be placed outside the loop, but then we'd have to check newParent != node twice
node.QueueIndex = finalQueueIndex;
_nodes[finalQueueIndex] = node;
break;
}

T childLeft = _nodes[childLeftIndex];
if(HasHigherPriority(childLeft, newParent))
{
newParent = childLeft;
}

//Check if the right-child is higher-priority than either the current node or the left child
int childRightIndex = childLeftIndex + 1;
if(childRightIndex <= _numNodes)
{
T childRight = _nodes[childRightIndex];
if(HasHigherPriority(childRight, newParent))
{
newParent = childRight;
}
}

//If either of the children has higher (smaller) priority, swap and continue cascading
if(newParent != node)
{
//Move new parent to its new index. node will be moved once, at the end
//Doing it this way is one less assignment operation than calling Swap()
_nodes[finalQueueIndex] = newParent;

int temp = newParent.QueueIndex;
newParent.QueueIndex = finalQueueIndex;
finalQueueIndex = temp;
}
else
{
//See note above
node.QueueIndex = finalQueueIndex;
_nodes[finalQueueIndex] = node;
break;
}
}
}

/// <summary>
/// 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
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
private bool HasHigherPriority(T higher, T lower)
{
return (higher.Priority < lower.Priority ||
(higher.Priority == lower.Priority && higher.InsertionIndex < lower.InsertionIndex));
}

/// <summary>
/// Removes the head of the queue (node with highest priority; ties are broken by order of insertion), and returns it. O(log n)
/// </summary>
public T Dequeue()
{
T returnMe = _nodes[1];
Remove(returnMe);
return returnMe;
}

/// <summary>
/// Returns the head of the queue, without removing it (use Dequeue() for that). O(1)
/// </summary>
public T First
{
get
{
return _nodes[1];
}
}

/// <summary>
/// This method must be called on a node every time its priority changes while it is in the queue.
/// <b>Forgetting to call this method will result in a corrupted queue!</b>
/// O(log n)
/// </summary>
#if NET_VERSION_4_5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#endif
public void UpdatePriority(T node, double priority)
{
node.Priority = priority;
OnNodeUpdated(node);
}

private 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))
{
CascadeUp(node);
}
else
{
//Note that CascadeDown will be called if parentNode == node (that is, node is the root)
CascadeDown(node);
}
}

/// <summary>
/// Removes a node from the queue. Note that the node does not need to be the head of the queue. O(log n)
/// </summary>
public void Remove(T node)
{
if(_numNodes <= 1)
{
_nodes[1] = null;
_numNodes = 0;
return;
}

//Make sure the node is the last node in the queue
bool wasSwapped = false;
T formerLastNode = _nodes[_numNodes];
if(node.QueueIndex != _numNodes)
{
//Swap the node with the last node
Swap(node, formerLastNode);
wasSwapped = true;
}

_numNodes--;
_nodes[node.QueueIndex] = null;

if(wasSwapped)
{
//Now bubble formerLastNode (which is no longer the last node) up or down as appropriate
OnNodeUpdated(formerLastNode);
}
}

public IEnumerator<T> GetEnumerator()
{
for(int i = 1; i <= _numNodes; i++)
yield return _nodes[i];
}

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// <b>Should not be called in production code.</b>
/// Checks to make sure the queue is still in a valid state. Used for testing/debugging the queue.
/// </summary>
public bool IsValidQueue()
{
for(int i = 1; i < _nodes.Count; i++)
{
if(_nodes[i] != null)
{
int childLeftIndex = 2 * i;
if(childLeftIndex < _nodes.Count && _nodes[childLeftIndex] != null && HasHigherPriority(_nodes[childLeftIndex], _nodes[i]))
return false;

int childRightIndex = childLeftIndex + 1;
if(childRightIndex < _nodes.Count && _nodes[childRightIndex] != null && HasHigherPriority(_nodes[childRightIndex], _nodes[i]))
return false;
}
}
return true;
}
}
}

+ 8
- 0
DataStructures/Priority Queue/HeapPriorityQueue.cs.meta View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ac754b29409379046935c0890bab6dc5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

+ 23
- 0
DataStructures/Priority Queue/IPriorityQueue.cs View File

@@ -0,0 +1,23 @@
using System.Collections.Generic;

namespace Svelto.DataStructures
{
/// <summary>
/// The IPriorityQueue interface. This is mainly here for purists, and in case I decide to add more implementations later.
/// For speed purposes, it is actually recommended that you *don't* access the priority queue through this interface, since the JIT can
/// (theoretically?) optimize method calls from concrete-types slightly better.
/// </summary>
public interface IPriorityQueue<T> : IEnumerable<T>
where T : PriorityQueueNode
{
void Remove(T node);
void UpdatePriority(T node, double priority);
void Enqueue(T node, double priority);
T Dequeue();
T First { get; }
int Count { get; }
int MaxSize { get; }
void Clear();
bool Contains(T node);
}
}

+ 8
- 0
DataStructures/Priority Queue/IPriorityQueue.cs.meta View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5d399e4c2c1fe1f47833d6b70bf16184
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

+ 24
- 0
DataStructures/Priority Queue/PriorityQueueNode.cs View File

@@ -0,0 +1,24 @@
namespace Svelto.DataStructures
{
public class PriorityQueueNode
{
/// <summary>
/// The Priority to insert this node at. Must be set BEFORE adding a node to the queue
/// </summary>
public double Priority { get;
set;
}

/// <summary>
/// <b>Used by the priority queue - do not edit this value.</b>
/// Represents the order the node was inserted in
/// </summary>
public long InsertionIndex { get; set; }

/// <summary>
/// <b>Used by the priority queue - do not edit this value.</b>
/// Represents the current position in the queue
/// </summary>
public int QueueIndex { get; set; }
}
}

+ 8
- 0
DataStructures/Priority Queue/PriorityQueueNode.cs.meta View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2a6cc02a61a6ff549b1dcac74c71681f
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

+ 154
- 265
DataStructures/ReadOnlyDictionary.cs View File

@@ -1,28 +1,11 @@
//note: ripped from openstacknetsdk

using System;
using System.Collections;
using System.Collections.Generic;

namespace Svelto.DataStructures
{
public struct ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary
public struct ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> _dictionary;

/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyDictionary{TKey, TValue}"/> class
/// that is a wrapper around the specified dictionary.
/// </summary>
/// <param name="dictionary">The dictionary to wrap.</param>
public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");

_dictionary = dictionary;
}

public bool isInitialized { get { return _dictionary != null; } }

/// <summary>
@@ -40,45 +23,6 @@ namespace Svelto.DataStructures
}
}

/// <inheritdoc/>
/// <summary>
/// Gets the element that has the specified key.
/// </summary>
/// <exception cref="NotSupportedException">If the property is set.</exception>
TValue IDictionary<TKey, TValue>.this[TKey key]
{
get
{
return this[key];
}

set
{
throw new NotSupportedException();
}
}

/// <inheritdoc/>
/// <summary>
/// Gets the element that has the specified key.
/// </summary>
/// <exception cref="NotSupportedException">If the property is set.</exception>
object IDictionary.this[object key]
{
get
{
if (!(key is TKey))
return null;

return this[(TKey)key];
}

set
{
throw new NotSupportedException();
}
}

/// <summary>
/// Gets the number of items in the dictionary.
/// </summary>
@@ -88,8 +32,8 @@ namespace Svelto.DataStructures
public int Count
{
get
{
return _dictionary.Count;
{
return _dictionary.Count;
}
}

@@ -107,24 +51,6 @@ namespace Svelto.DataStructures
}
}

/// <inheritdoc/>
ICollection<TKey> IDictionary<TKey, TValue>.Keys
{
get
{
return Keys;
}
}

/// <inheritdoc/>
ICollection IDictionary.Keys
{
get
{
return Keys;
}
}

/// <summary>
/// Gets a collection that contains the values in the dictionary.
/// </summary>
@@ -139,155 +65,82 @@ namespace Svelto.DataStructures
}
}

/// <inheritdoc/>
ICollection<TValue> IDictionary<TKey, TValue>.Values
/// <summary>
/// Initializes a new instance of the <see cref="ReadOnlyDictionary{TKey, TValue}"/> class
/// that is a wrapper around the specified dictionary.
/// </summary>
/// <param name="dictionary">The dictionary to wrap.</param>
public ReadOnlyDictionary(Dictionary<TKey, TValue> dictionary)
{
get
{
return Values;
}
}
if (dictionary == null)
throw new ArgumentNullException("dictionary");

/// <inheritdoc/>
ICollection IDictionary.Values
{
get
{
return Values;
}
_dictionary = dictionary;
}

/// <inheritdoc/>
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
/// <summary>
/// Gets the element that has the specified key.
/// </summary>
/// <exception cref="NotSupportedException">If the property is set.</exception>
TValue IDictionary<TKey, TValue>.this[TKey key]
{
get
{
return true;
return this[key];
}
}

/// <inheritdoc/>
bool IDictionary.IsFixedSize
{
get
set
{
return true;
throw new NotSupportedException();
}
}

/// <inheritdoc/>
bool IDictionary.IsReadOnly
ICollection<TKey> IDictionary<TKey, TValue>.Keys
{
get
{
return true;
return Keys;
}
}

/// <inheritdoc/>
bool ICollection.IsSynchronized
ICollection<TValue> IDictionary<TKey, TValue>.Values
{
get
{
return false;
return Values;
}
}

/// <inheritdoc/>
object ICollection.SyncRoot
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
{
get
{
ICollection collection = this as ICollection;
if (collection == null)
return collection.SyncRoot;

throw new NotSupportedException("The current object does not support the SyncRoot property.");
return true;
}
}

/// <summary>
/// Determines whether the dictionary contains an element that has the specified key.
/// </summary>
/// <param name="key">The key to locate in the dictionary.</param>
/// <returns><see langword="true"/> if the dictionary contains an element that has the specified key; otherwise, <see langword="false"/>.</returns>
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}

/// <inheritdoc/>
bool IDictionary.Contains(object key)
{
if (key == null)
throw new ArgumentNullException("key");

if (key is TKey)
return ContainsKey((TKey)key);

return false;
}

/// <summary>
/// Returns an enumerator that iterates through the <see cref="ReadOnlyDictionary{TKey, TValue}"/>.
/// </summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dictionary.GetEnumerator();
}

/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <inheritdoc/>
IDictionaryEnumerator IDictionary.GetEnumerator()
{
IDictionary dictionary = _dictionary as IDictionary;
if (dictionary != null)
return dictionary.GetEnumerator();

return new DictionaryEnumerator(_dictionary);
}

/// <summary>
/// Retrieves the value that is associated with the specified key.
/// </summary>
/// <param name="key">The key whose value will be retrieved.</param>
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param>
/// <returns><see langword="true"/> if the object that implements <see cref="ReadOnlyDictionary{TKey, TValue}"/> contains an element with the specified key; otherwise, <see langword="false"/>.</returns>
public bool TryGetValue(TKey key, out TValue value)
{
return _dictionary.TryGetValue(key, out value);
}

/// <inheritdoc/>
void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
{
throw new NotSupportedException();
}

/// <inheritdoc/>
void IDictionary.Add(object key, object value)
{
throw new NotSupportedException();
}

/// <inheritdoc/>
bool IDictionary<TKey, TValue>.Remove(TKey key)
{
throw new NotSupportedException();
}

/// <inheritdoc/>
void IDictionary.Remove(object key)
{
throw new NotSupportedException();
}

/// <inheritdoc/>
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
@@ -318,29 +171,60 @@ namespace Svelto.DataStructures
throw new NotSupportedException();
}

/// <inheritdoc/>
void IDictionary.Clear()
bool IDictionary<TKey, TValue>.ContainsKey(TKey key)
{
throw new NotSupportedException();
return _dictionary.ContainsKey(key);
}

/// <inheritdoc/>
void ICollection.CopyTo(Array array, int index)
bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value)
{
throw new NotImplementedException();
return _dictionary.TryGetValue(key, out value);
}

/// <summary>
int ICollection<KeyValuePair<TKey, TValue>>.Count
{
get { return _dictionary.Count; }
}

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
return _dictionary.GetEnumerator();
}

/// <summary>
/// Determines whether the dictionary contains an element that has the specified key.
/// </summary>
/// <param name="key">The key to locate in the dictionary.</param>
/// <returns><see langword="true"/> if the dictionary contains an element that has the specified key; otherwise, <see langword="false"/>.</returns>
public bool ContainsKey(TKey key)
{
return _dictionary.ContainsKey(key);
}

public DictionaryEnumerator GetEnumerator()
{
return new DictionaryEnumerator(_dictionary);
}

/// <summary>
/// Retrieves the value that is associated with the specified key.
/// </summary>
/// <param name="key">The key whose value will be retrieved.</param>
/// <param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param>
/// <returns><see langword="true"/> if the object that implements <see cref="ReadOnlyDictionary{TKey, TValue}"/> contains an element with the specified key; otherwise, <see langword="false"/>.</returns>
public bool TryGetValue(TKey key, out TValue value)
{
return _dictionary.TryGetValue(key, out value);
}

readonly Dictionary<TKey, TValue> _dictionary;

/// <summary>
/// Represents a read-only collection of the keys of a <see cref="ReadOnlyDictionary{TKey, TValue}"/> object.
/// </summary>
public struct KeyCollection : ICollection<TKey>, ICollection
{
/// <summary>
/// The wrapped collection of keys.
/// </summary>
private readonly ICollection<TKey> _keys;

/// <summary>
/// <summary>
/// Initializes a new instance of the <see cref="KeyCollection"/> class
/// as a wrapper around the specified collection of keys.
/// </summary>
@@ -354,48 +238,54 @@ namespace Svelto.DataStructures
_keys = keys;
}

/// <summary>
/// Gets the number of elements in the collection.
/// </summary>
/// <value>
/// The number of elements in the collection.
/// </value>
public int Count
/// <inheritdoc/>
bool ICollection.IsSynchronized
{
get
{
return _keys.Count;
return false;
}
}

/// <inheritdoc/>
bool ICollection<TKey>.IsReadOnly
/// <inheritdoc/>
object ICollection.SyncRoot
{
get
{
return true;
throw new NotImplementedException();
}
}

/// <inheritdoc/>
bool ICollection.IsSynchronized
/// <inheritdoc/>
void ICollection.CopyTo(Array array, int index)
{
throw new NotImplementedException();
}

/// <summary>
/// Gets the number of elements in the collection.
/// </summary>
/// <value>
/// The number of elements in the collection.
/// </value>
public int Count
{
get
{
return false;
return _keys.Count;
}
}

/// <inheritdoc/>
object ICollection.SyncRoot
/// <inheritdoc/>
bool ICollection<TKey>.IsReadOnly
{
get
{
throw new NotImplementedException();
return true;
}
}

/// <summary>
/// <summary>
/// Copies the elements of the collection to an array, starting at a specific array index.
/// </summary>
/// <param name="array">The one-dimensional array that is the destination of the elements copied from the collection. The array must have zero-based indexing.</param>
@@ -414,13 +304,7 @@ namespace Svelto.DataStructures
_keys.CopyTo(array, arrayIndex);
}

/// <inheritdoc/>
void ICollection.CopyTo(Array array, int index)
{
throw new NotImplementedException();
}

/// <summary>
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
@@ -429,35 +313,40 @@ namespace Svelto.DataStructures
return _keys.GetEnumerator();
}

/// <inheritdoc/>
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <inheritdoc/>
/// <inheritdoc/>
bool ICollection<TKey>.Contains(TKey item)
{
return _keys.Contains(item);
}

/// <inheritdoc/>
/// <inheritdoc/>
void ICollection<TKey>.Add(TKey item)
{
throw new NotSupportedException();
}

/// <inheritdoc/>
/// <inheritdoc/>
bool ICollection<TKey>.Remove(TKey item)
{
throw new NotSupportedException();
}

/// <inheritdoc/>
/// <inheritdoc/>
void ICollection<TKey>.Clear()
{
throw new NotSupportedException();
}

/// <summary>
/// The wrapped collection of keys.
/// </summary>
readonly ICollection<TKey> _keys;
}

/// <summary>
@@ -465,11 +354,6 @@ namespace Svelto.DataStructures
/// </summary>
public struct ValueCollection : ICollection<TValue>, ICollection
{
/// <summary>
/// The wrapped collection of values.
/// </summary>
private readonly ICollection<TValue> _values;

/// <summary>
/// Initializes a new instance of the <see cref="ValueCollection"/> class
/// as a wrapper around the specified collection of values.
@@ -484,44 +368,50 @@ namespace Svelto.DataStructures
_values = values;
}

/// <summary>
/// Gets the number of elements in the collection.
/// </summary>
/// <value>
/// The number of elements in the collection.
/// </value>
public int Count
/// <inheritdoc/>
bool ICollection.IsSynchronized
{
get
{
return _values.Count;
return false;
}
}

/// <inheritdoc/>
bool ICollection<TValue>.IsReadOnly
object ICollection.SyncRoot
{
get
{
return true;
throw new NotImplementedException();
}
}

/// <inheritdoc/>
bool ICollection.IsSynchronized
void ICollection.CopyTo(Array array, int index)
{
throw new NotImplementedException();
}

/// <summary>
/// Gets the number of elements in the collection.
/// </summary>
/// <value>
/// The number of elements in the collection.
/// </value>
public int Count
{
get
{
return false;
return _values.Count;
}
}

/// <inheritdoc/>
object ICollection.SyncRoot
bool ICollection<TValue>.IsReadOnly
{
get
{
throw new NotImplementedException();
return true;
}
}

@@ -544,12 +434,6 @@ namespace Svelto.DataStructures
_values.CopyTo(array, arrayIndex);
}

/// <inheritdoc/>
void ICollection.CopyTo(Array array, int index)
{
throw new NotImplementedException();
}

/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
@@ -588,54 +472,47 @@ namespace Svelto.DataStructures
{
throw new NotSupportedException();
}

/// <summary>
/// The wrapped collection of values.
/// </summary>
readonly ICollection<TValue> _values;
}

struct DictionaryEnumerator : IDictionaryEnumerator
public struct DictionaryEnumerator:IEnumerator<KeyValuePair<TKey,TValue>>
{
private readonly IEnumerator<KeyValuePair<TKey, TValue>> _enumerator;

public DictionaryEnumerator(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null)
throw new ArgumentNullException("dictionary");

_enumerator = dictionary.GetEnumerator();
}

/// <inheritdoc/>
public DictionaryEntry Entry
public TKey Key
{
get
{
KeyValuePair<TKey, TValue> current = _enumerator.Current;
return new DictionaryEntry(current.Key, current.Value);
return _enumerator.Current.Key;
}
}

/// <inheritdoc/>
public object Key
public TValue Value
{
get
{
return _enumerator.Current.Key;
return _enumerator.Current.Value;
}
}

/// <inheritdoc/>
public object Value
public DictionaryEnumerator(IDictionary<TKey, TValue> dictionary)
{
get
{
return _enumerator.Current.Value;
}
if (dictionary == null)
throw new ArgumentNullException("dictionary");
_enumerator = dictionary.GetEnumerator();
}

/// <inheritdoc/>
public object Current
public KeyValuePair<TKey, TValue> Current
{
get
{
return Entry;
return _enumerator.Current;
}
}

@@ -650,6 +527,18 @@ namespace Svelto.DataStructures
{
_enumerator.Reset();
}

object IEnumerator.Current
{
get { return _enumerator.Current; }
}

public void Dispose()
{
_enumerator.Dispose();
}

readonly IEnumerator<KeyValuePair<TKey, TValue>> _enumerator;
}
}
}

+ 183
- 0
DataStructures/SerializableDictionary.cs View File

@@ -0,0 +1,183 @@
#define XML_ENABLED

using System;
using System.Runtime.Serialization;
#if XML_ENABLED
using System.Xml;
using System.Xml.Serialization;
#endif
using System.Collections.Generic;

[Serializable()]
public struct KeyValueSerialization<TKey, TVal>
{
public TKey Key;
public TVal Value;
}

[Serializable()]
public class SerializableDictionary<TKey, TVal> : Dictionary<TKey, TVal>,
#if XML_ENABLED
IXmlSerializable,
#endif
ISerializable
{
#region Constants
private const string DictionaryNodeName = "Dictionary";
private const string ItemNodeName = "Item";
private const string KeyNodeName = "Key";
private const string ValueNodeName = "Value";
#endregion
#region Constructors
public SerializableDictionary()
{
}
public SerializableDictionary(IDictionary<TKey, TVal> dictionary)
: base(dictionary)
{
}
public SerializableDictionary(IEqualityComparer<TKey> comparer)
: base(comparer)
{
}
public SerializableDictionary(int capacity)
: base(capacity)
{
}
public SerializableDictionary(IDictionary<TKey, TVal> dictionary, IEqualityComparer<TKey> comparer)
: base(dictionary, comparer)
{
}
public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer)
: base(capacity, comparer)
{
}
#endregion
#region ISerializable Members
public SerializableDictionary(SerializationInfo info, StreamingContext context)
{
int itemCount = info.GetInt32("count");
for (int i = 0; i < itemCount; i++)
{
KeyValueSerialization<TKey, TVal> kvp = (KeyValueSerialization<TKey, TVal>)info.GetValue(String.Format("Im{0}", i), typeof(KeyValueSerialization<TKey, TVal>));
this.Add(kvp.Key, kvp.Value);
}
}
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("count", this.Count);
int itemIdx = 0;
foreach (KeyValuePair<TKey, TVal> kvp in this)
{
KeyValueSerialization<TKey, TVal> kvs = new KeyValueSerialization<TKey, TVal>();
kvs.Key = kvp.Key;
kvs.Value = kvp.Value;
info.AddValue(String.Format("Im{0}", itemIdx), kvs, typeof(KeyValueSerialization<TKey, TVal>));
itemIdx++;
}
}
#endregion
#if XML_ENABLED
#region IXmlSerializable Members
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer)
{
//writer.WriteStartElement(DictionaryNodeName);
foreach (KeyValuePair<TKey, TVal> kvp in this)
{
writer.WriteStartElement(ItemNodeName);
writer.WriteStartElement(KeyNodeName);
KeySerializer.Serialize(writer, kvp.Key);
writer.WriteEndElement();
writer.WriteStartElement(ValueNodeName);
ValueSerializer.Serialize(writer, kvp.Value);
writer.WriteEndElement();
writer.WriteEndElement();
}
//writer.WriteEndElement();
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader)
{
if (reader.IsEmptyElement)
{
return;
}
// Move past container
if (!reader.Read())
{
throw new XmlException("Error in Deserialization of Dictionary");
}
//reader.ReadStartElement(DictionaryNodeName);
while (reader.NodeType != XmlNodeType.EndElement)
{
reader.ReadStartElement(ItemNodeName);
reader.ReadStartElement(KeyNodeName);
TKey key = (TKey)KeySerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadStartElement(ValueNodeName);
TVal value = (TVal)ValueSerializer.Deserialize(reader);
reader.ReadEndElement();
reader.ReadEndElement();
this.Add(key, value);
reader.MoveToContent();
}
//reader.ReadEndElement();
reader.ReadEndElement(); // Read End Element to close Read of containing node
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema()
{
return null;
}

#endregion
#region Private Properties

protected XmlSerializer ValueSerializer
{
get
{
if (valueSerializer == null)
{
valueSerializer = new XmlSerializer(typeof(TVal));
}
return valueSerializer;
}
}

private XmlSerializer KeySerializer
{
get
{
if (keySerializer == null)
{
keySerializer = new XmlSerializer(typeof(TKey));
}
return keySerializer;
}
}

#endregion
#region Private Members
private XmlSerializer keySerializer = null;
private XmlSerializer valueSerializer = null;
#endregion
#endif
}


+ 7
- 0
DataStructures/SerializableDictionary.cs.meta View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b4a9cb2903cd07946a8650aeefb8d853
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}

+ 303
- 0
DataStructures/ThreadSafeDictionary.cs View File

@@ -0,0 +1,303 @@
using System;
using System.Collections.Generic;
using System.Threading;

namespace Svelto.DataStructures
{
/// <summary>
/// original code: http://devplanet.com/blogs/brianr/archive/2008/09/29/thread-safe-dictionary-update.aspx
/// simplified (not an IDictionary) and apdated (uses FasterList)
/// </summary>
/// <typeparam name = "TKey"></typeparam>
/// <typeparam name = "TValue"></typeparam>
[Serializable]
public class ThreadSafeDictionary<TKey, TValue>
{
// setup the lock;
public virtual int Count
{
get
{
using (new ReadOnlyLock(dictionaryLock))
{
return dict.Count;
}
}
}

public virtual bool IsReadOnly
{
get
{
using (new ReadOnlyLock(dictionaryLock))
{
return dict.IsReadOnly;
}
}
}

public virtual FasterList<TKey> Keys
{
get
{
using (new ReadOnlyLock(dictionaryLock))
{
return new FasterList<TKey>(dict.Keys);
}
}
}

public virtual FasterList<TValue> Values
{
get
{
using (new ReadOnlyLock(dictionaryLock))
{
return new FasterList<TValue>(dict.Values);
}
}
}

public virtual TValue this[TKey key]
{
get
{
using (new ReadOnlyLock(dictionaryLock))
{
return dict[key];
}
}

set
{
using (new WriteLock(dictionaryLock))
{
dict[key] = value;
}
}
}

public virtual void Add(KeyValuePair<TKey, TValue> item)
{
using (new WriteLock(dictionaryLock))
{
dict.Add(item);
}
}

public virtual void Clear()
{
using (new WriteLock(dictionaryLock))
{
dict.Clear();
}
}

public virtual bool Contains(KeyValuePair<TKey, TValue> item)
{
using (new ReadOnlyLock(dictionaryLock))
{
return dict.Contains(item);
}
}

public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
using (new ReadOnlyLock(dictionaryLock))
{
dict.CopyTo(array, arrayIndex);
}
}

public virtual bool Remove(KeyValuePair<TKey, TValue> item)
{
using (new WriteLock(dictionaryLock))
{
return dict.Remove(item);
}
}

public virtual void Add(TKey key, TValue value)
{
using (new WriteLock(dictionaryLock))
{
dict.Add(key, value);
}
}

public virtual bool ContainsKey(TKey key)
{
using (new ReadOnlyLock(dictionaryLock))
{
return dict.ContainsKey(key);
}
}

public virtual bool Remove(TKey key)
{
using (new WriteLock(dictionaryLock))
{
return dict.Remove(key);
}
}

public virtual bool TryGetValue(TKey key, out TValue value)
{
using (new ReadOnlyLock(dictionaryLock))
{
return dict.TryGetValue(key, out value);
}
}

/// <summary>
/// Merge does a blind remove, and then add. Basically a blind Upsert.
/// </summary>
/// <param name = "key">Key to lookup</param>
/// <param name = "newValue">New Value</param>
public void MergeSafe(TKey key, TValue newValue)
{
using (new WriteLock(dictionaryLock))
{
// take a writelock immediately since we will always be writing
if (dict.ContainsKey(key))
dict.Remove(key);

dict.Add(key, newValue);
}
}

/// <summary>
/// This is a blind remove. Prevents the need to check for existence first.
/// </summary>
/// <param name = "key">Key to remove</param>
public void RemoveSafe(TKey key)
{
using (new ReadLock(dictionaryLock))
{
if (dict.ContainsKey(key))
using (new WriteLock(dictionaryLock))
{
dict.Remove(key);
}
}
}

// This is the internal dictionary that we are wrapping
readonly IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();

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

Ticker/UnityTicker.cs.meta → DataStructures/ThreadSafeDictionary.cs.meta View File

@@ -1,5 +1,7 @@
fileFormatVersion: 2
guid: b62a08472017f914d9fc399eeb95108e
guid: db7c720ce4e437f48b1380223ba08192
timeCreated: 1470829214
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []

+ 50
- 3
DataStructures/ThreadSafeQueue.cs View File

@@ -1,4 +1,3 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
@@ -88,12 +87,12 @@ namespace Svelto.DataStructures
}
}

public List<T> DequeueAll()
public FasterList<T> DequeueAll()
{
LockQ.EnterWriteLock();
try
{
List<T> returnList = new List<T>();
FasterList<T> returnList = new FasterList<T>();

while (m_Queue.Count > 0)
returnList.Add(m_Queue.Dequeue());
@@ -107,6 +106,40 @@ namespace Svelto.DataStructures
}
}

public void DequeueAllInto(FasterList<T> list)
{
LockQ.EnterWriteLock();
try
{
while (m_Queue.Count > 0)
list.Add(m_Queue.Dequeue());
}

finally
{
LockQ.ExitWriteLock();
}
}

public FasterList<U> DequeueAllAs<U>() where U:class
{
LockQ.EnterWriteLock();
try
{
FasterList<U> returnList = new FasterList<U>();

while (m_Queue.Count > 0)
returnList.Add(m_Queue.Dequeue() as U);

return returnList;
}

finally
{
LockQ.ExitWriteLock();
}
}

public T Peek()
{
LockQ.EnterWriteLock();
@@ -126,6 +159,20 @@ namespace Svelto.DataStructures
}
}

public void Clear()
{
LockQ.EnterWriteLock();
try
{
m_Queue.Clear();
}

finally
{
LockQ.ExitWriteLock();
}
}

public bool TryDequeue(out T item)
{
LockQ.EnterWriteLock();


+ 5
- 0
DataStructures/WeakReference.cs View File

@@ -55,4 +55,9 @@ namespace Svelto.DataStructures
: base(info, context)
{ }
}

public static class WeakReferenceUtility
{
public static bool IsValid(this WeakReference obj) { return obj != null && obj.IsAlive == true && obj.Target != null; }
}
}

+ 2
- 0
ECS.meta View File

@@ -3,3 +3,5 @@ guid: 5015ea56c030d6542bd4daa46f59e549
folderAsset: yes
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 0
- 39
ECS/Dispatcher/Dispatcher.cs View File

@@ -1,39 +0,0 @@
public class Dispatcher<S, T>
{
public event System.Action<S, T> subscribers;

private Dispatcher() { }

public Dispatcher(S sender)
{
_sender = sender;
}

public void Dispatch(ref T value)
{
if (subscribers != null)
subscribers(_sender, value);
}

readonly S _sender;
}

public class Dispatcher<S>
{
public event System.Action<S> subscribers;

private Dispatcher() { }

public Dispatcher(S sender)
{
_sender = sender;
}

public void Dispatch()
{
if (subscribers != null)
subscribers(_sender);
}

readonly S _sender;
}

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

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

+ 13
- 23
ECS/Dispatcher/DispatcherOnChange.cs View File

@@ -1,34 +1,24 @@
using System.Collections.Generic;

public class DispatcherOnChange<S, T>: Dispatcher<S, T>
namespace Svelto.ECS
{
public DispatcherOnChange(S sender) : base(sender) { }

public T value
public class DispatchOnChange<T> : DispatchOnSet<T>
{
set
public DispatchOnChange(int senderID) : base(senderID)
{ }

public new T value
{
if (EqualityComparer<T>.Default.Equals(value, _value) == false)
set
{
_value = value;
if (EqualityComparer<T>.Default.Equals(value, _value) == false)
base.value = value;
}

Dispatch(ref value);
get
{
return _value;
}
}
}

T _value;
}

public class DispatcherOnSet<S, T>: Dispatcher<S, T>
{
public DispatcherOnSet(S sender) : base(sender) { }

public T value
{
set
{
Dispatch(ref value);
}
}
}

+ 43
- 0
ECS/Dispatcher/DispatcherOnSet.cs View File

@@ -0,0 +1,43 @@
using BetterWeakEvents;

namespace Svelto.ECS
{
public class DispatchOnSet<T>
{
public DispatchOnSet(int senderID)
{
_senderID = senderID;
_subscribers = new WeakEvent<int, T>();
}

public T value
{
set
{
_value = value;

_subscribers.Invoke(_senderID, value);
}

get
{
return _value;
}
}

public void NotifyOnValueSet(System.Action<int, T> action)
{
_subscribers += action;
}

public void StopNotify(System.Action<int, T> action)
{
_subscribers -= action;
}

protected T _value;
protected int _senderID;

protected WeakEvent<int, T> _subscribers;
}
}

+ 12
- 0
ECS/Dispatcher/DispatcherOnSet.cs.meta View File

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

+ 36
- 7
ECS/EngineNodeDB.cs View File

@@ -2,14 +2,17 @@ using System;
using System.Collections.Generic;
using Svelto.DataStructures;

namespace Svelto.ES
namespace Svelto.ECS
{
class EngineNodeDB : IEngineNodeDB
{
internal EngineNodeDB(Dictionary<Type, FasterList<INode>> nodesDB, Dictionary<Type, Dictionary<int, INode>> nodesDBdic)
internal EngineNodeDB( Dictionary<Type, FasterList<INode>> nodesDB,
Dictionary<Type, Dictionary<int, INode>> nodesDBdic,
Dictionary<Type, FasterList<INode>> nodesDBgroups)
{
this._nodesDB = nodesDB;
this._nodesDBdic = nodesDBdic;
_nodesDB = nodesDB;
_nodesDBdic = nodesDBdic;
_nodesDBgroups = nodesDBgroups;
}

public FasterReadOnlyListCast<INode, T> QueryNodes<T>() where T:INode
@@ -17,7 +20,7 @@ namespace Svelto.ES
var type = typeof(T);

if (_nodesDB.ContainsKey(type) == false)
return new FasterReadOnlyListCast<INode, T>(FasterReadOnlyListCast<INode, T>.DefaultList);
return RetrieveEmptyNodeList<T>();

return new FasterReadOnlyListCast<INode, T>(_nodesDB[type]);
}
@@ -32,6 +35,26 @@ namespace Svelto.ES
return new ReadOnlyDictionary<int, INode>(_nodesDBdic[type]);
}

public T QueryNodeFromGroup<T>(int groupID) where T : INode
{
return QueryNode<T>(groupID);
}

public bool QueryNodeFromGroup<T>(int groupID, out T node) where T : INode
{
return QueryNode<T>(groupID, out node);
}

public FasterReadOnlyListCast<INode, T> QueryNodesFromGroups<T>() where T : INode
{
var type = typeof(T);

if (_nodesDBgroups.ContainsKey(type) == false)
return RetrieveEmptyNodeList<T>();

return new FasterReadOnlyListCast<INode, T>(_nodesDBgroups[type]);
}

public bool QueryNode<T>(int ID, out T node) where T:INode
{
var type = typeof(T);
@@ -62,9 +85,15 @@ namespace Svelto.ES
throw new Exception("Node Not Found");
}

static FasterReadOnlyListCast<INode, T> RetrieveEmptyNodeList<T>() where T : INode
{
return new FasterReadOnlyListCast<INode, T>(FasterReadOnlyListCast<INode, T>.DefaultList);
}

Dictionary<Type, FasterList<INode>> _nodesDB;
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic;
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic;
Dictionary<Type, FasterList<INode>> _nodesDBgroups;

ReadOnlyDictionary<int, INode> _defaultEmptyNodeDict = new ReadOnlyDictionary<int, INode>(new Dictionary<int, INode>());
ReadOnlyDictionary<int, INode> _defaultEmptyNodeDict = new ReadOnlyDictionary<int, INode>(new Dictionary<int, INode>());
}
}

+ 183
- 34
ECS/EnginesRoot.cs View File

@@ -1,37 +1,117 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Svelto.DataStructures;
using Svelto.Ticker;
using UnityEngine;

namespace Svelto.ES
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
using Svelto.ECS.Profiler;
#endif

namespace Svelto.ECS
{
public sealed class EnginesRoot: IEnginesRoot, IEndOfFrameTickable, IEntityFactory
class Scheduler : MonoBehaviour
{
public EnginesRoot(ITicker ticker)
IEnumerator Start()
{
ticker.Add(this);
while (true)
{
yield return new WaitForEndOfFrame();

OnTick();
}
}

internal Action OnTick;
}

public sealed class EnginesRoot : IEnginesRoot, IEntityFactory
{
public EnginesRoot()
{
_nodeEngines = new Dictionary<Type, FasterList<INodeEngine<INode>>>();
_engineRootWeakReference = new WeakReference<EnginesRoot>(this);
_otherEnginesReferences = new FasterList<IEngine>();
_nodesDB = new Dictionary<Type, FasterList<INode>>();
_nodesDBdic = new Dictionary<Type, Dictionary<int, INode>>();

_nodesToAdd = new Queue<INode>();
_nodesToRemove = new Queue<INode>();
_nodesToAdd = new FasterList<INode>();
_groupNodesToAdd = new FasterList<INode>();

_nodesDBgroups = new Dictionary<Type, FasterList<INode>>();

GameObject go = new GameObject("ECSScheduler");

go.AddComponent<Scheduler>().OnTick += SubmitNodes;

#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
GameObject debugEngineObject = new GameObject("Engine Debugger");
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>();
#endif
}

public void EndOfFrameTick(float deltaSec)
void SubmitNodes()
{
while (_nodesToAdd.Count > 0) InternalAdd(_nodesToAdd.Dequeue());
while (_nodesToRemove.Count > 0) InternalRemove(_nodesToRemove.Dequeue());
int groupNodesCount;
int nodesCount;
bool newNodesHaveBeenAddedWhileIterating;
int startNodes = 0;
int startGroupNodes = 0;
int numberOfReenteringLoops = 0;

do
{
groupNodesCount = _groupNodesToAdd.Count;
nodesCount = _nodesToAdd.Count;

for (int i = startNodes; i < nodesCount; i++)
{
var node = _nodesToAdd[i];
AddNodeToTheDB(node, node.GetType());
}

for (int i = startGroupNodes; i < groupNodesCount; i++)
{
var node = _groupNodesToAdd[i];
AddNodeToGroupDB(node, node.GetType());
}

for (int i = startNodes; i < nodesCount; i++)
{
var node = _nodesToAdd[i];
AddNodeToTheSuitableEngines(node, node.GetType());
}

for (int i = startGroupNodes; i < groupNodesCount; i++)
{
var node = _groupNodesToAdd[i];
AddNodeToTheSuitableEngines(node, node.GetType());
}

newNodesHaveBeenAddedWhileIterating = _groupNodesToAdd.Count > groupNodesCount || _nodesToAdd.Count > nodesCount;

startNodes = nodesCount;
startGroupNodes = groupNodesCount;

if (numberOfReenteringLoops > 5)
throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method");

numberOfReenteringLoops++;

} while (newNodesHaveBeenAddedWhileIterating);

_nodesToAdd.Clear();
_groupNodesToAdd.Clear();
}

public void AddEngine(IEngine engine)
{
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
EngineProfiler.AddEngine(engine);
#endif
if (engine is IQueryableNodeEngine)
(engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic);
(engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic, _nodesDBgroups);

if (engine is INodesEngine)
{
@@ -46,7 +126,7 @@ namespace Svelto.ES
if (baseType.IsGenericType)
{
var genericType = baseType.GetGenericTypeDefinition();
if (genericType == typeof(SingleNodeEngine<>))
{
AddEngine(engine as INodeEngine<INode>, baseType.GetGenericArguments(), _nodeEngines);
@@ -55,7 +135,7 @@ namespace Svelto.ES
}
}

_otherEnginesReferences.Add(engine);
_otherEnginesReferences.Add(engine);
}

public void BuildEntity(int ID, EntityDescriptor ed)
@@ -63,14 +143,24 @@ namespace Svelto.ES
var entityNodes = ed.BuildNodes(ID, (node) =>
{
if (_engineRootWeakReference.IsValid == true)
_engineRootWeakReference.Target._nodesToRemove.Enqueue(node);
InternalRemove(node);
});
for (int i = 0; i < entityNodes.Count; i++)
_nodesToAdd.Enqueue(entityNodes[i]);
_nodesToAdd.AddRange(entityNodes);
}

static void AddEngine<T>(T engine, Type[] types, Dictionary<Type, FasterList<INodeEngine<INode>>> engines) where T:INodeEngine<INode>
public void BuildEntityGroup(int groupID, EntityDescriptor ed)
{
var entityNodes = ed.BuildNodes(groupID, (node) =>
{
if (_engineRootWeakReference.IsValid == true)
InternalGroupRemove(node);
});

_groupNodesToAdd.AddRange(entityNodes);
}

static void AddEngine<T>(T engine, Type[] types, Dictionary<Type, FasterList<INodeEngine<INode>>> engines) where T : INodeEngine<INode>
{
for (int i = 0; i < types.Length; i++)
{
@@ -89,20 +179,15 @@ namespace Svelto.ES
}
}

void InternalAdd<T>(T node) where T:INode
void AddNodeToGroupDB(INode node, Type nodeType)
{
Type nodeType = node.GetType();

AddNodeToTheSuitableEngines(node, nodeType);
AddNodeToTheDB(node, nodeType);
}
FasterList<INode> nodes;
if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == false)
nodes = _nodesDBgroups[nodeType] = new FasterList<INode>();

void InternalRemove<T>(T node) where T:INode
{
Type nodeType = node.GetType();
nodes.Add(node);

RemoveNodeFromEngines(node, nodeType);
RemoveNodeFromTheDB(node, nodeType);
AddNodeToNodesDictionary(node, nodeType);
}

void AddNodeToTheDB<T>(T node, Type nodeType) where T : INode
@@ -113,12 +198,17 @@ namespace Svelto.ES

nodes.Add(node);

AddNodeToNodesDictionary(node, nodeType);
}

void AddNodeToNodesDictionary<T>(T node, Type nodeType) where T : INode
{
if (node is NodeWithID)
{
Dictionary<int, INode> nodesDic;
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false)
nodesDic = _nodesDBdic[nodeType] = new Dictionary<int, INode>();
nodesDic[(node as NodeWithID).ID] = node;
}
}
@@ -128,16 +218,29 @@ namespace Svelto.ES
FasterList<INodeEngine<INode>> enginesForNode;

if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
{
for (int j = 0; j < enginesForNode.Count; j++)
{
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j], node);
#else
enginesForNode[j].Add(node);
#endif
}
}
}

void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode
{
FasterList<INode> nodes;
if (_nodesDB.TryGetValue(nodeType, out nodes) == true)
nodes.Remove(node); //should I remove it from the dictionary if length is zero?
nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero?

RemoveNodeFromNodesDictionary(node, nodeType);
}

void RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INode
{
if (node is NodeWithID)
{
Dictionary<int, INode> nodesDic;
@@ -147,13 +250,57 @@ namespace Svelto.ES
}
}

void RemoveNodeFromGroupDB<T>(T node, Type nodeType) where T : INode
{
FasterList<INode> nodes;
if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == true)
nodes.UnorderredRemove(node); //should I remove it from the dictionary if length is zero?

RemoveNodeFromNodesDictionary(node, nodeType);
}

void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode
{
FasterList<INodeEngine<INode>> enginesForNode;

if (_nodeEngines.TryGetValue(nodeType, out enginesForNode))
{
for (int j = 0; j < enginesForNode.Count; j++)
{
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node);
#else
enginesForNode[j].Remove(node);
#endif
}
}
}
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR
void AddNodeToEngine(INodeEngine<INode> engine, INode node)
{
engine.Add(node);
}

void RemoveNodeFromEngine(INodeEngine<INode> engine, INode node)
{
engine.Remove(node);
}
#endif
void InternalRemove<T>(T node) where T : INode
{
Type nodeType = node.GetType();

RemoveNodeFromEngines(node, nodeType);
RemoveNodeFromTheDB(node, node.GetType());
}

void InternalGroupRemove<T>(T node) where T : INode
{
Type nodeType = node.GetType();

RemoveNodeFromEngines(node, nodeType);
RemoveNodeFromGroupDB(node, node.GetType());
}

Dictionary<Type, FasterList<INodeEngine<INode>>> _nodeEngines;
@@ -162,11 +309,13 @@ namespace Svelto.ES
Dictionary<Type, FasterList<INode>> _nodesDB;
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic;

Queue<INode> _nodesToAdd;
Queue<INode> _nodesToRemove;
Dictionary<Type, FasterList<INode>> _nodesDBgroups;

FasterList<INode> _nodesToAdd;
FasterList<INode> _groupNodesToAdd;

WeakReference<EnginesRoot> _engineRootWeakReference;
//integrated pooling system
//add debug panel like Entitas has
//GCHandle should be used to reduce the number of strong references


+ 30
- 33
ECS/EntityDescriptor.cs View File

@@ -2,37 +2,37 @@
using System.Reflection;
using Svelto.DataStructures;

namespace Svelto.ES
namespace Svelto.ECS
{
public class EntityDescriptor
{
EntityDescriptor()
{}

protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor)
protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor)
{
_implementors = componentsImplementor; _nodesToBuild = nodesToBuild;
_implementors = componentsImplementor;
_nodesToBuild = nodesToBuild;
}

virtual public FasterList<INode> BuildNodes(int ID, Action<INode> removeAction)
{
var nodes = new FasterList<INode>();
public virtual FasterList<INode> BuildNodes(int ID, Action<INode> removeAction)
{
var nodes = new FasterList<INode>();

for (int index = 0; index < _nodesToBuild.Length; index++)
{
var nodeBuilder = _nodesToBuild[index];
var node = FillNode(nodeBuilder.Build(ID), () =>
{
for (int i = 0; i < nodes.Count; i++)
removeAction(nodes[i]);

for (int index = 0; index < _nodesToBuild.Length; index++)
{
var nodeBuilder = _nodesToBuild[index];
var node = FillNode(nodeBuilder.Build(ID), () =>
{
for (int i = 0; i < nodes.Count; i++)
removeAction(nodes[i]);
}
);
nodes.Clear();
}
);

nodes.Add (node);
}
nodes.Add (node);
}

return nodes;
}
return nodes;
}

TNode FillNode<TNode>(TNode node, Action removeAction) where TNode: INode
{
@@ -40,15 +40,15 @@ namespace Svelto.ES

for (int i = fields.Length - 1; i >=0 ; --i)
{
var field = fields[i];
Type fieldType = field.FieldType;
object component = null;
var field = fields[i];
Type fieldType = field.FieldType;
object component = null;

for (int j = 0; j < _implementors.Length; j++)
{
var implementor = _implementors[j];

if (fieldType.IsAssignableFrom(implementor.GetType()))
if (implementor != null && fieldType.IsAssignableFrom(implementor.GetType()))
{
component = implementor;

@@ -61,10 +61,8 @@ namespace Svelto.ES

if (component == null)
{
Exception e = new Exception("Svelto.ES: An Entity must hold all the components needed for a Node. " +
"Type: " + field.FieldType.Name + " Node: " + node.GetType().Name);

Utility.Console.LogException(e);
Exception e = new Exception("Svelto.ECS: Implementor not found for a Node. " +
"Implementor Type: " + field.FieldType.Name + " - Node: " + node.GetType().Name + " - EntityDescriptor " + this);

throw e;
}
@@ -75,9 +73,8 @@ namespace Svelto.ES
return node;
}

readonly object[] _implementors;

INodeBuilder[] _nodesToBuild;
readonly object[] _implementors;
INodeBuilder[] _nodesToBuild;
}

public interface INodeBuilder


+ 127
- 0
ECS/GenericEntityDescriptor.cs View File

@@ -0,0 +1,127 @@
namespace Svelto.ECS
{
class GenericEntityDescriptor<T> : EntityDescriptor
where T : NodeWithID, new()
{
static GenericEntityDescriptor()
{
_nodesToBuild = new INodeBuilder[]
{
new NodeBuilder<T>()
};
}
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor)
{
}
static INodeBuilder[] _nodesToBuild;
}

class GenericEntityDescriptor<T, U> : EntityDescriptor
where T : NodeWithID, new()
where U : NodeWithID, new()
{
static GenericEntityDescriptor()
{
_nodesToBuild = new INodeBuilder[]
{
new NodeBuilder<T>(),
new NodeBuilder<U>()
};
}
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor)
{
}
static INodeBuilder[] _nodesToBuild;
}

class GenericEntityDescriptor<T, U, V> : EntityDescriptor
where T : NodeWithID, new()
where U : NodeWithID, new()
where V : NodeWithID, new()
{
static GenericEntityDescriptor()
{
_nodesToBuild = new INodeBuilder[]
{
new NodeBuilder<T>(),
new NodeBuilder<U>(),
new NodeBuilder<V>()
};
}
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor)
{
}
static INodeBuilder[] _nodesToBuild;
}

class GenericEntityDescriptor<T, U, V, W> : EntityDescriptor
where T : NodeWithID, new()
where U : NodeWithID, new()
where V : NodeWithID, new()
where W : NodeWithID, new()
{
static GenericEntityDescriptor()
{
_nodesToBuild = new INodeBuilder[]
{
new NodeBuilder<T>(),
new NodeBuilder<U>(),
new NodeBuilder<V>(),
new NodeBuilder<W>()
};
}
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor)
{
}
static INodeBuilder[] _nodesToBuild;
}

class GenericEntityDescriptor<T, U, V, W, X> : EntityDescriptor
where T : NodeWithID, new()
where U : NodeWithID, new()
where V : NodeWithID, new()
where W : NodeWithID, new()
where X : NodeWithID, new()
{
static GenericEntityDescriptor()
{
_nodesToBuild = new INodeBuilder[]
{
new NodeBuilder<T>(),
new NodeBuilder<U>(),
new NodeBuilder<V>(),
new NodeBuilder<W>(),
new NodeBuilder<X>()
};
}
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor)
{
}
static INodeBuilder[] _nodesToBuild;
}
class GenericEntityDescriptor<T, U, V, W, X, Y> : EntityDescriptor
where T : NodeWithID, new()
where U : NodeWithID, new()
where V : NodeWithID, new()
where W : NodeWithID, new()
where X : NodeWithID, new()
where Y : NodeWithID, new()
{
static GenericEntityDescriptor()
{
_nodesToBuild = new INodeBuilder[]
{
new NodeBuilder<T>(),
new NodeBuilder<U>(),
new NodeBuilder<V>(),
new NodeBuilder<W>(),
new NodeBuilder<X>(),
new NodeBuilder<Y>()
};
}
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor)
{
}
static INodeBuilder[] _nodesToBuild;
}
}

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

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

+ 0
- 6
ECS/IComponent.cs View File

@@ -1,6 +0,0 @@
namespace Svelto.ES
{
public interface IComponent
{
}
}

+ 1
- 17
ECS/IEngine.cs View File

@@ -1,4 +1,4 @@
namespace Svelto.ES
namespace Svelto.ECS
{
public interface IEngine
{}
@@ -18,20 +18,4 @@ namespace Svelto.ES
{
IEngineNodeDB nodesDB { set; }
}

public abstract class SingleNodeEngine<TNodeType> : INodeEngine<INode> where TNodeType:class, INode
{
void INodeEngine<INode>.Add(INode obj)
{
Add(obj as TNodeType);
}

void INodeEngine<INode>.Remove(INode obj)
{
Remove(obj as TNodeType);
}

protected abstract void Add(TNodeType node);
protected abstract void Remove(TNodeType node);
}
}

+ 8
- 1
ECS/IEngineNodeDB.cs View File

@@ -1,12 +1,19 @@
using Svelto.DataStructures;

namespace Svelto.ES
namespace Svelto.ECS
{
public interface IEngineNodeDB
{
ReadOnlyDictionary<int, INode> QueryIndexableNodes<T>() where T:INode;
bool QueryNode<T>(int ID, out T node) where T:INode;
T QueryNode<T>(int ID) where T:INode;
FasterReadOnlyListCast<INode, T> QueryNodes<T>() where T:INode;

bool QueryNodeFromGroup<T>(int ID, out T node) where T : INode;
T QueryNodeFromGroup<T>(int ID) where T : INode;
FasterReadOnlyListCast<INode, T> QueryNodesFromGroups<T>() where T : INode;
}
}


+ 3
- 1
ECS/IEnginesRoot.cs View File

@@ -1,4 +1,4 @@
namespace Svelto.ES
namespace Svelto.ECS
{
public interface IEnginesRoot
{
@@ -8,5 +8,7 @@ namespace Svelto.ES
public interface IEntityFactory
{
void BuildEntity(int ID, EntityDescriptor ED);

void BuildEntityGroup(int ID, EntityDescriptor ED);
}
}

+ 6
- 5
ECS/IEntityDescriptorHolder.cs View File

@@ -1,10 +1,11 @@
namespace Svelto.ES
namespace Svelto.ECS
{
/// <summary>
/// please use [DisallowMultipleComponent] in your monobehaviours that implement IEntityDescriptorHolder
/// </summary>
/// <summary>
/// please use [DisallowMultipleComponent] in your monobehaviours that implement IEntityDescriptorHolder
/// </summary>
public interface IEntityDescriptorHolder
{
EntityDescriptor BuildDescriptorType();
//I must find a nicer solution for the extraImplentors
EntityDescriptor BuildDescriptorType(object[] extraImplentors = null);
}
}

+ 1
- 1
ECS/IEntityDescriptorHolder.cs.meta View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 5a8db83410a8aaa40b824fdc3d968f67
guid: 0badb413a22f42a4b9f68e356e88b07f
timeCreated: 1463438461
licenseType: Free
MonoImporter:


+ 6
- 0
ECS/IImplementor.cs View File

@@ -0,0 +1,6 @@
namespace Svelto.ECS
{
public interface IImplementor
{
}
}

ECS/IComponent.cs.meta → ECS/IImplementor.cs.meta View File


+ 2
- 2
ECS/INode.cs View File

@@ -1,11 +1,11 @@
namespace Svelto.ES
namespace Svelto.ECS
{
public interface INode
{}

public class NodeWithID: INode
{
public static TNodeType BuildNode<TNodeType>(int ID) where TNodeType: NodeWithID, new()
public static TNodeType BuildNode<TNodeType>(int ID) where TNodeType: NodeWithID, new()
{
return new TNodeType { _ID = ID };
}


+ 1
- 1
ECS/IRemoveEntityComponent.cs View File

@@ -1,6 +1,6 @@
using System;

namespace Svelto.ES
namespace Svelto.ECS
{
public interface IRemoveEntityComponent
{


+ 9
- 0
ECS/Profiler.meta View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8d07544bb8b417f4a9eaefe0d4771d89
folderAsset: yes
timeCreated: 1462355668
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
ECS/Profiler/Editor.meta View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 71a4fc836cd9bde4bbb936a073804ec5
folderAsset: yes
timeCreated: 1480683133
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

+ 9
- 0
ECS/Profiler/Editor/EngineProfiler.meta View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 777a9420fd80746428f9d2c5b718fd2f
folderAsset: yes
timeCreated: 1462351213
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

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

@@ -0,0 +1,373 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
[CustomEditor(typeof (EngineProfilerBehaviour))]
public class EngineProfilerInspector : Editor
{
enum SORTING_OPTIONS
{
AVERAGE,
MIN,
MAX,
NAME,
NONE
}

static bool _hideEmptyEngines = true;
static bool _showTickEngines;
static bool _showAddEngines;
static bool _showRemoveEngines;

static string _systemNameSearchTerm = string.Empty;

float _axisUpperBounds = 2f;

string updateTitle = "Update".PadRight(15, ' ');
string lateUpdateTitle = "Late".PadRight(13, ' ');
string fixedupdateTitle = "Fixed".PadRight(15, ' ');
string minTitle = "Min".PadRight(15, ' ');
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()
{
var engineProfilerBehaviour = (EngineProfilerBehaviour) target;
EngineInfo[] engines = new EngineInfo[engineProfilerBehaviour.engines.Count];
engineProfilerBehaviour.engines.CopyTo(engines, 0);

DrawEnginesMonitor(engines);
DrawEngineList(engineProfilerBehaviour, engines);
EditorUtility.SetDirty(target);
}

void DrawEngineList(EngineProfilerBehaviour engineProfilerBehaviour, EngineInfo[] engines)
{
ProfilerEditorLayout.BeginVerticalBox();
{
ProfilerEditorLayout.BeginHorizontal();
{
if (GUILayout.Button("Reset Durations", GUILayout.Width(120), GUILayout.Height(14)))
{
engineProfilerBehaviour.ResetDurations();
}
}
ProfilerEditorLayout.EndHorizontal();

_sortingOption = (SORTING_OPTIONS) EditorGUILayout.EnumPopup("Sort By:", _sortingOption);

_hideEmptyEngines = EditorGUILayout.Toggle("Hide empty systems", _hideEmptyEngines);
EditorGUILayout.Space();

ProfilerEditorLayout.BeginHorizontal();
{
_systemNameSearchTerm = EditorGUILayout.TextField("Search", _systemNameSearchTerm);

const string clearButtonControlName = "Clear Button";
GUI.SetNextControlName(clearButtonControlName);
if (GUILayout.Button("x", GUILayout.Width(19), GUILayout.Height(14)))
{
_systemNameSearchTerm = string.Empty;
GUI.FocusControl(clearButtonControlName);
}
}
ProfilerEditorLayout.EndHorizontal();

_showTickEngines = EditorGUILayout.Foldout(_showTickEngines, "Engines Ticks");
if (_showTickEngines && ShouldShowSystems(engines))
{
ProfilerEditorLayout.BeginVerticalBox();
{
var systemsDrawn = DrawUpdateEngineInfos(engines);
if (systemsDrawn == 0)
{
EditorGUILayout.LabelField(string.Empty);
}
}
ProfilerEditorLayout.EndVertical();
}

_showAddEngines = EditorGUILayout.Foldout(_showAddEngines, "Engines Add");
if (_showAddEngines && ShouldShowSystems(engines))
{
ProfilerEditorLayout.BeginVerticalBox();
{
var systemsDrawn = DrawAddEngineInfos(engines);
if (systemsDrawn == 0)
{
EditorGUILayout.LabelField(string.Empty);
}
}
ProfilerEditorLayout.EndVertical();
}

_showRemoveEngines = EditorGUILayout.Foldout(_showRemoveEngines, "Engines Remove");
if (_showRemoveEngines && ShouldShowSystems(engines))
{
ProfilerEditorLayout.BeginVerticalBox();
{
var systemsDrawn = DrawRemoveEngineInfos(engines);
if (systemsDrawn == 0)
{
EditorGUILayout.LabelField(string.Empty);
}
}
ProfilerEditorLayout.EndVertical();
}
}
ProfilerEditorLayout.EndVertical();
}

void DrawEnginesMonitor(EngineInfo[] engines)
{
if (_enginesMonitor == null)
{
_enginesMonitor = new EnginesMonitor(SYSTEM_MONITOR_DATA_LENGTH);
_engineMonitorData = new Queue<float>(new float[SYSTEM_MONITOR_DATA_LENGTH]);
if (EditorApplication.update != Repaint)
{
EditorApplication.update += Repaint;
}
}
double totalDuration = 0;
for (int i = 0; i < engines.Length; i++)
{
totalDuration += engines[i].lastUpdateDuration;
}

ProfilerEditorLayout.BeginVerticalBox();
{
EditorGUILayout.LabelField("Execution duration", EditorStyles.boldLabel);

ProfilerEditorLayout.BeginHorizontal();
{
EditorGUILayout.LabelField("Total", totalDuration.ToString());
}
ProfilerEditorLayout.EndHorizontal();

ProfilerEditorLayout.BeginHorizontal();
{
_axisUpperBounds = EditorGUILayout.FloatField("Axis Upper Bounds", _axisUpperBounds);
}
ProfilerEditorLayout.EndHorizontal();

if (!EditorApplication.isPaused)
{
if (_engineMonitorData.Count >= SYSTEM_MONITOR_DATA_LENGTH)
{
_engineMonitorData.Dequeue();
}

_engineMonitorData.Enqueue((float) totalDuration);
}
_enginesMonitor.Draw(_engineMonitorData.ToArray(), 80f, _axisUpperBounds);
}
ProfilerEditorLayout.EndVertical();
}

int DrawUpdateEngineInfos(EngineInfo[] engines)
{
if (_sortingOption != SORTING_OPTIONS.NONE)
{
SortUpdateEngines(engines);
}

string title =
updateTitle.FastConcat(lateUpdateTitle)
.FastConcat(fixedupdateTitle)
.FastConcat(minTitle)
.FastConcat(maxTitle);
EditorGUILayout.LabelField("Engine Name", title, EditorStyles.boldLabel);

int enginesDrawn = 0;
for (int i = 0; i < engines.Length; i++)
{
EngineInfo engineInfo = engines[i];

if (engineInfo.engineName.ToLower().Contains(_systemNameSearchTerm.ToLower()))
{
ProfilerEditorLayout.BeginHorizontal();
{
var avg = string.Format("{0:0.000}", engineInfo.averageUpdateDuration).PadRight(15);
var avgLate = string.Format("{0:0.000}", engineInfo.averageLateUpdateDuration).PadRight(15);
var avgFixed = string.Format("{0:0.000}", engineInfo.averageFixedUpdateDuration).PadRight(15);
var min = string.Format("{0:0.000}", engineInfo.minUpdateDuration).PadRight(15);
var max = string.Format("{0:0.000}", engineInfo.maxUpdateDuration);

string output = avg.FastConcat(avgLate).FastConcat(avgFixed).FastConcat(min).FastConcat(max);

EditorGUILayout.LabelField(engineInfo.engineName, output, GetEngineStyle());
}
ProfilerEditorLayout.EndHorizontal();

enginesDrawn += 1;
}
}
return enginesDrawn;
}

int DrawAddEngineInfos(EngineInfo[] engines)
{
if (_sortingOption != SORTING_OPTIONS.NONE)
{
SortAddEngines(engines);
}

string title = avgTitle.FastConcat(minTitle).FastConcat(maxTitle);
EditorGUILayout.LabelField("Engine Name", title, EditorStyles.boldLabel);

int enginesDrawn = 0;
for (int i = 0; i < engines.Length; i++)
{
EngineInfo engineInfo = engines[i];
if (engineInfo.engineName.ToLower().Contains(_systemNameSearchTerm.ToLower()) &&
!engineInfo.minAddDuration.Equals(0) && !engineInfo.maxAddDuration.Equals(0))
{
ProfilerEditorLayout.BeginHorizontal();
{
var avg = string.Format("{0:0.000}", engineInfo.averageAddDuration).PadRight(15);
var min = string.Format("{0:0.000}", engineInfo.minAddDuration).PadRight(15);
var max = string.Format("{0:0.000}", engineInfo.maxAddDuration);

string output = avg.FastConcat(min).FastConcat(max);

EditorGUILayout.LabelField(engineInfo.engineName, output, GetEngineStyle());
}
ProfilerEditorLayout.EndHorizontal();

enginesDrawn += 1;
}
}
return enginesDrawn;
}

int DrawRemoveEngineInfos(EngineInfo[] engines)
{
if (_sortingOption != SORTING_OPTIONS.NONE)
{
SortRemoveEngines(engines);
}

string title = avgTitle.FastConcat(minTitle).FastConcat(maxTitle);
EditorGUILayout.LabelField("Engine Name", title, EditorStyles.boldLabel);

int enginesDrawn = 0;
for (int i = 0; i < engines.Length; i++)
{
EngineInfo engineInfo = engines[i];
if (engineInfo.engineName.ToLower().Contains(_systemNameSearchTerm.ToLower()) &&
!engineInfo.minRemoveDuration.Equals(0) && !engineInfo.maxRemoveDuration.Equals(0))
{
ProfilerEditorLayout.BeginHorizontal();
{
var avg = string.Format("{0:0.000}", engineInfo.averageRemoveDuration).PadRight(15);
var min = string.Format("{0:0.000}", engineInfo.minRemoveDuration).PadRight(15);
var max = string.Format("{0:0.000}", engineInfo.maxRemoveDuration);

string output = avg.FastConcat(min).FastConcat(max);

EditorGUILayout.LabelField(engineInfo.engineName, output, GetEngineStyle());
}
ProfilerEditorLayout.EndHorizontal();

enginesDrawn += 1;
}
}
return enginesDrawn;
}

static GUIStyle GetEngineStyle()
{
var style = new GUIStyle(GUI.skin.label);
var color = EditorGUIUtility.isProSkin ? Color.white : style.normal.textColor;

style.normal.textColor = color;

return style;
}

static bool ShouldShowSystems(EngineInfo[] engines)
{
return engines.Length > 0;
}

#region Sorting Engines
void SortUpdateEngines(EngineInfo[] engines)
{
switch (_sortingOption)
{
case SORTING_OPTIONS.AVERAGE:
Array.Sort(engines,
(engine1, engine2) => engine2.averageUpdateDuration.CompareTo(engine1.averageUpdateDuration));
break;
case SORTING_OPTIONS.MIN:
Array.Sort(engines,
(engine1, engine2) => engine2.minUpdateDuration.CompareTo(engine1.minUpdateDuration));
break;
case SORTING_OPTIONS.MAX:
Array.Sort(engines,
(engine1, engine2) => engine2.maxUpdateDuration.CompareTo(engine1.maxUpdateDuration));
break;
case SORTING_OPTIONS.NAME:
Array.Sort(engines, StringComparer.InvariantCulture);
break;
}
}

void SortAddEngines(EngineInfo[] engines)
{
switch (_sortingOption)
{
case SORTING_OPTIONS.AVERAGE:
Array.Sort(engines,
(engine1, engine2) => engine2.averageAddDuration.CompareTo(engine1.averageAddDuration));
break;
case SORTING_OPTIONS.MIN:
Array.Sort(engines,
(engine1, engine2) => engine2.minAddDuration.CompareTo(engine1.minAddDuration));
break;
case SORTING_OPTIONS.MAX:
Array.Sort(engines,
(engine1, engine2) => engine2.maxAddDuration.CompareTo(engine1.maxAddDuration));
break;
case SORTING_OPTIONS.NAME:
Array.Sort(engines, StringComparer.InvariantCulture);
break;
}
}

void SortRemoveEngines(EngineInfo[] engines)
{
switch (_sortingOption)
{
case SORTING_OPTIONS.AVERAGE:
Array.Sort(engines,
(engine1, engine2) => engine2.averageRemoveDuration.CompareTo(engine1.averageRemoveDuration));
break;
case SORTING_OPTIONS.MIN:
Array.Sort(engines,
(engine1, engine2) => engine2.minRemoveDuration.CompareTo(engine1.minRemoveDuration));
break;
case SORTING_OPTIONS.MAX:
Array.Sort(engines,
(engine1, engine2) => engine2.maxRemoveDuration.CompareTo(engine1.maxRemoveDuration));
break;
case SORTING_OPTIONS.NAME:
Array.Sort(engines, StringComparer.InvariantCulture);
break;
}
}
}
#endregion
}

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

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

+ 22
- 0
ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs View File

@@ -0,0 +1,22 @@
using UnityEditor;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
internal class EngineProfilerMenuItem
{
[MenuItem("Engines/Enable Profiler")]
public static void EnableProfiler()
{
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "ENGINE_PROFILER_ENABLED");
}

[MenuItem("Engines/Disable Profiler")]
public static void DisableProfiler()
{
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, "");
}
}
}

+ 12
- 0
ECS/Profiler/Editor/EngineProfiler/EngineProfilerMenuItem.cs.meta View File

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

+ 132
- 0
ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs View File

@@ -0,0 +1,132 @@
using System.Linq;
using UnityEditor;
using UnityEngine;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
public class EnginesMonitor
{
public float xBorder = 48;
public float yBorder = 20;
public int rightLinePadding = -15;
public string labelFormat = "{0:0.0}";
public string axisFormat = "{0:0.0}";
public int gridLines = 1;
public float axisRounding = 5f;
public float anchorRadius = 1f;
public Color lineColor = Color.magenta;

readonly GUIStyle _labelTextStyle;
readonly GUIStyle _centeredStyle;
readonly Vector3[] _cachedLinePointVerticies;
readonly Vector3[] _linePoints;

public EnginesMonitor(int dataLength)
{
_labelTextStyle = new GUIStyle(GUI.skin.label);
_labelTextStyle.alignment = TextAnchor.UpperRight;
_centeredStyle = new GUIStyle();
_centeredStyle.alignment = TextAnchor.UpperCenter;
_centeredStyle.normal.textColor = Color.white;
_linePoints = new Vector3[dataLength];
_cachedLinePointVerticies = new[]
{
new Vector3(-1, 1, 0)*anchorRadius,
new Vector3(1, 1, 0)*anchorRadius,
new Vector3(1, -1, 0)*anchorRadius,
new Vector3(-1, -1, 0)*anchorRadius,
};
}

public void Draw(float[] data, float height, float axisUpperBounds)
{
axisRounding = axisUpperBounds;
var rect = GUILayoutUtility.GetRect(EditorGUILayout.GetControlRect().width, height);
var top = rect.y + yBorder;
var floor = rect.y + rect.height - yBorder;
var availableHeight = floor - top;
var max = data.Length != 0 ? data.Max() : 0f;
if (max%axisRounding != 0)
{
max = max + axisRounding - (max%axisRounding);
}

drawGridLines(top, rect.width, availableHeight, max);
drawLine(data, floor, rect.width, availableHeight, max);
}

void drawGridLines(float top, float width, float availableHeight, float max)
{
var handleColor = Handles.color;
Handles.color = Color.grey;
var n = gridLines + 1;
var lineSpacing = availableHeight/n;
for (int i = 0; i <= n; i++)
{
var lineY = top + (lineSpacing*i);
Handles.DrawLine(
new Vector2(xBorder, lineY),
new Vector2(width - rightLinePadding, lineY)
);
GUI.Label(
new Rect(0, lineY - 8, xBorder - 2, 50),
string.Format(axisFormat, max*(1f - ((float) i/(float) n))),
_labelTextStyle
);
}
Handles.color = handleColor;
}

void drawLine(float[] data, float floor, float width, float availableHeight, float max)
{
var lineWidth = (float) (width - xBorder - rightLinePadding)/data.Length;
var handleColor = Handles.color;
var labelRect = new Rect();
Vector2 newLine;
bool mousePositionDiscovered = false;
float mouseHoverDataValue = 0;
float linePointScale;
Handles.color = lineColor;
Handles.matrix = Matrix4x4.identity;
HandleUtility.handleMaterial.SetPass(0);
for (int i = 0; i < data.Length; i++)
{
var value = data[i];
var lineTop = floor - (availableHeight*(value/max));
newLine = new Vector2(xBorder + (lineWidth*i), lineTop);
_linePoints[i] = new Vector3(newLine.x, newLine.y, 0);
linePointScale = 1f;
if (!mousePositionDiscovered)
{
var anchorPosRadius3 = anchorRadius*3;
var anchorPosRadius6 = anchorRadius*6;
var anchorPos = newLine - (Vector2.up*0.5f);
labelRect = new Rect(anchorPos.x - anchorPosRadius3, anchorPos.y - anchorPosRadius3,
anchorPosRadius6, anchorPosRadius6);
if (labelRect.Contains(Event.current.mousePosition))
{
mousePositionDiscovered = true;
mouseHoverDataValue = value;
linePointScale = 3f;
}
}
Handles.matrix = Matrix4x4.TRS(_linePoints[i], Quaternion.identity, Vector3.one*linePointScale);
Handles.DrawAAConvexPolygon(_cachedLinePointVerticies);
}
Handles.matrix = Matrix4x4.identity;
Handles.DrawAAPolyLine(2f, data.Length, _linePoints);

if (mousePositionDiscovered)
{
labelRect.y -= 16;
labelRect.width += 50;
labelRect.x -= 25;
GUI.Label(labelRect, string.Format(labelFormat, mouseHoverDataValue), _centeredStyle);
}
Handles.color = handleColor;
}
}
}

+ 12
- 0
ECS/Profiler/Editor/EngineProfiler/EnginesMonitor.cs.meta View File

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

+ 65
- 0
ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs View File

@@ -0,0 +1,65 @@
using UnityEditor;
using UnityEngine;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
public static class ProfilerEditorLayout
{
public static void ShowWindow<T>(string title) where T : EditorWindow
{
var window = EditorWindow.GetWindow<T>(true, title);
window.minSize = window.maxSize = new Vector2(415f, 520f);
window.Show();
}

public static Texture2D LoadTexture(string label)
{
var guid = AssetDatabase.FindAssets(label)[0];
if (guid != null)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
return AssetDatabase.LoadAssetAtPath<Texture2D>(path);
}
return null;
}

public static float DrawHeaderTexture(EditorWindow window, Texture2D texture)
{
const int scollBarWidth = 15;
var ratio = texture.width/texture.height;
var width = window.position.width - 8 - scollBarWidth;
var height = width/ratio;
GUI.DrawTexture(new Rect(4, 2, width, height), texture, ScaleMode.ScaleToFit);

return height;
}

public static Rect BeginVertical()
{
return EditorGUILayout.BeginVertical();
}

public static Rect BeginVerticalBox(GUIStyle style = null)
{
return EditorGUILayout.BeginVertical(style ?? GUI.skin.box);
}

public static void EndVertical()
{
EditorGUILayout.EndVertical();
}

public static Rect BeginHorizontal()
{
return EditorGUILayout.BeginHorizontal();
}

public static void EndHorizontal()
{
EditorGUILayout.EndHorizontal();
}
}
}

+ 12
- 0
ECS/Profiler/Editor/EngineProfiler/ProfilerEditorLayout.cs.meta View File

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

+ 167
- 0
ECS/Profiler/EngineInfo.cs View File

@@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
public sealed class EngineInfo
{
enum UpdateType
{
Update = 0,
LateUpdate = 1,
FixedUpdate = 2,
}

readonly IEngine _engine;
readonly string _engineName;
readonly Type _engineType;

const int NUM_UPDATE_TYPES = 3;
const int NUM_FRAMES_TO_AVERAGE = 10;

//use a queue to averave out the last 30 frames
Queue<double>[] _updateFrameTimes = new Queue<double>[NUM_UPDATE_TYPES];
readonly double[] _accumulatedUpdateDuration = new double[NUM_UPDATE_TYPES];
readonly double[] _lastUpdateDuration = new double[NUM_UPDATE_TYPES];

readonly double[] _minUpdateDuration = new double[NUM_UPDATE_TYPES];
readonly double[] _maxUpdateDuration = new double[NUM_UPDATE_TYPES];

double _accumulatedAddDuration;
double _minAddDuration;
double _maxAddDuration;
int _nodesAddedCount;

double _accumulatedRemoveDuration;
double _minRemoveDuration;
double _maxRemoveDuration;
int _nodesRemovedCount;

public IEngine engine { get { return _engine; } }
public string engineName { get { return _engineName; } }
public Type engineType { get { return _engineType; } }

public double lastUpdateDuration { get { return _lastUpdateDuration[(int) UpdateType.Update]; } }
public double lastFixedUpdateDuration { get { return _lastUpdateDuration[(int)UpdateType.LateUpdate]; } }
public double lastLateUpdateDuration { get { return _lastUpdateDuration[(int)UpdateType.FixedUpdate]; } }

public double minAddDuration { get { return _minAddDuration; } }
public double minRemoveDuration { get { return _minRemoveDuration; } }
public double minUpdateDuration { get { return _minUpdateDuration[(int)UpdateType.Update]; } }

public double maxAddDuration { get { return _maxAddDuration; } }
public double maxRemoveDuration { get { return _maxRemoveDuration; } }
public double maxUpdateDuration { get { return _maxUpdateDuration[(int)UpdateType.Update]; } }

public double averageAddDuration { get { return _nodesAddedCount == 0 ? 0 : _accumulatedAddDuration / _nodesAddedCount; } }
public double averageRemoveDuration { get { return _nodesRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _nodesRemovedCount; } }
public double averageUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.Update].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.Update] / _updateFrameTimes[(int)UpdateType.Update].Count; } }
public double averageLateUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.LateUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.LateUpdate] / _updateFrameTimes[(int)UpdateType.LateUpdate].Count; } }
public double averageFixedUpdateDuration { get { return _updateFrameTimes[(int)UpdateType.FixedUpdate].Count == 0 ? 0 : _accumulatedUpdateDuration[(int)UpdateType.FixedUpdate] / _updateFrameTimes[(int)UpdateType.FixedUpdate].Count; } }

public EngineInfo(IEngine engine)
{
_engine = engine;
_engineName = _engine.ToString();

int foundNamespace = _engineName.LastIndexOf(".");
_engineName = _engineName.Remove(0, foundNamespace + 1);

_engineType = engine.GetType();

for (int i = 0; i < NUM_UPDATE_TYPES; i++)
{
_updateFrameTimes[i] = new Queue<double>();
}
ResetDurations();
}

public void AddUpdateDuration(double updateDuration)
{
AddUpdateDurationForType(updateDuration, (int)UpdateType.Update);
}

public void AddLateUpdateDuration(double updateDuration)
{
AddUpdateDurationForType(updateDuration, (int)UpdateType.LateUpdate);
}

public void AddFixedUpdateDuration(double updateDuration)
{
AddUpdateDurationForType(updateDuration, (int)UpdateType.FixedUpdate);
}

void AddUpdateDurationForType(double updateDuration, int updateType)
{
if (updateDuration < _minUpdateDuration[updateType] || _minUpdateDuration[updateType] == 0)
{
_minUpdateDuration[updateType] = updateDuration;
}
if (updateDuration > _maxUpdateDuration[updateType])
{
_maxUpdateDuration[updateType] = updateDuration;
}

if (_updateFrameTimes[updateType].Count == NUM_FRAMES_TO_AVERAGE)
{
_accumulatedUpdateDuration[updateType] -= _updateFrameTimes[updateType].Dequeue();
}

_accumulatedUpdateDuration[updateType] += updateDuration;
_updateFrameTimes[updateType].Enqueue(updateDuration);
_lastUpdateDuration[updateType] = updateDuration;
}

public void AddAddDuration(double duration)
{
if (duration < _minAddDuration || _minAddDuration == 0)
{
_minAddDuration = duration;
}
if (duration > _maxAddDuration)
{
_maxAddDuration = duration;
}
_accumulatedAddDuration += duration;
_nodesAddedCount += 1;
}

public void AddRemoveDuration(double duration)
{
if (duration < _minRemoveDuration || _minRemoveDuration == 0)
{
_minRemoveDuration = duration;
}
if (duration > _maxRemoveDuration)
{
_maxRemoveDuration = duration;
}
_accumulatedRemoveDuration += duration;
_nodesRemovedCount += 1;
}

public void ResetDurations()
{
for (int i = 0; i < NUM_UPDATE_TYPES; i++)
{
_accumulatedUpdateDuration[i] = 0;
_minUpdateDuration[i] = 0;
_maxUpdateDuration[i] = 0;
_updateFrameTimes[i].Clear();
}

_accumulatedAddDuration = 0;
_minAddDuration = 0;
_maxAddDuration = 0;
_nodesAddedCount = 0;

_accumulatedRemoveDuration = 0;
_minRemoveDuration = 0;
_maxRemoveDuration = 0;
_nodesRemovedCount = 0;
}
}
}

+ 12
- 0
ECS/Profiler/EngineInfo.cs.meta View File

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

+ 126
- 0
ECS/Profiler/EngineProfiler.cs View File

@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using Svelto.Ticker.Legacy;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
public sealed class EngineProfiler
{
static readonly Stopwatch _stopwatch = new Stopwatch();

public static void MonitorAddDuration(Action<INodeEngine<INode>, INode> addingFunc, INodeEngine<INode> engine, INode node)
{
EngineInfo info;
if (engineInfos.TryGetValue(engine.GetType(), out info))
{
_stopwatch.Reset();
_stopwatch.Start();
addingFunc(engine, node);
_stopwatch.Stop();

info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds);
}
}

public static void MonitorRemoveDuration(Action<INodeEngine<INode>, INode> removeFunc, INodeEngine<INode> engine, INode node)
{
EngineInfo info;
if (engineInfos.TryGetValue(engine.GetType(), out info))
{
_stopwatch.Reset();
_stopwatch.Start();
removeFunc(engine, node);
engine.Remove(node);
_stopwatch.Stop();
info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds);
}
}

public static void MonitorUpdateDuration(ITickable tickable)
{
if (tickable is INodeEngine<INode>)
{
EngineInfo info;
if (engineInfos.TryGetValue((tickable as INodeEngine<INode>).GetType(), out info))
{
_stopwatch.Reset();
_stopwatch.Start();
tickable.Tick(Time.deltaTime);
_stopwatch.Stop();

info.AddUpdateDuration(_stopwatch.Elapsed.TotalMilliseconds);
}
}
else
{
tickable.Tick(Time.deltaTime);
}
}

public static void MonitorUpdateDuration(IPhysicallyTickable tickable)
{
if (tickable is INodeEngine<INode>)
{
EngineInfo info;
if (engineInfos.TryGetValue((tickable as INodeEngine<INode>).GetType(), out info))
{
_stopwatch.Reset();
_stopwatch.Start();
tickable.PhysicsTick(Time.fixedDeltaTime);
_stopwatch.Stop();

info.AddFixedUpdateDuration(_stopwatch.Elapsed.TotalMilliseconds);
}
}
else
{
tickable.PhysicsTick(Time.fixedDeltaTime);
}
}

public static void MonitorUpdateDuration(ILateTickable tickable)
{
if (tickable is INodeEngine<INode>)
{
EngineInfo info;
if (engineInfos.TryGetValue((tickable as INodeEngine<INode>).GetType(), out info))
{
_stopwatch.Reset();
_stopwatch.Start();
tickable.LateTick(Time.deltaTime);
_stopwatch.Stop();

info.AddLateUpdateDuration(_stopwatch.Elapsed.TotalMilliseconds);
}
}
else
{
tickable.LateTick(Time.deltaTime);
}
}

public static void AddEngine(IEngine engine)
{
if (engineInfos.ContainsKey(engine.GetType()) == false)
{
engineInfos.Add(engine.GetType(), new EngineInfo(engine));
}
}

public static void ResetDurations()
{
foreach (var engine in engineInfos)
{
engine.Value.ResetDurations();
}
}

public static readonly Dictionary<Type, EngineInfo> engineInfos = new Dictionary<Type, EngineInfo>();
}
}

+ 12
- 0
ECS/Profiler/EngineProfiler.cs.meta View File

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

+ 19
- 0
ECS/Profiler/EngineProfilerBehaviour.cs View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using UnityEngine;

//This profiler is based on the Entitas Visual Debugging tool
//https://github.com/sschmid/Entitas-CSharp

namespace Svelto.ECS.Profiler
{
public class EngineProfilerBehaviour : MonoBehaviour
{
public Dictionary<Type, EngineInfo>.ValueCollection engines { get { return EngineProfiler.engineInfos.Values; } }

public void ResetDurations()
{
EngineProfiler.ResetDurations();
}
}
}

+ 12
- 0
ECS/Profiler/EngineProfilerBehaviour.cs.meta View File

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

+ 52
- 0
ECS/Sequencer.cs View File

@@ -0,0 +1,52 @@
using System;
using Steps = System.Collections.Generic.Dictionary<Svelto.ECS.IEngine, System.Collections.Generic.Dictionary<System.Enum, Svelto.ECS.IStep[]>>;

namespace Svelto.ECS
{
public interface IStep
{ }

public interface IStep<T>:IStep
{
void Step(ref T token, Enum condition);
}

public class Sequencer
{
public Sequencer()
{}

public void SetSequence(Steps steps)
{
_steps = steps;
}

public void Next<T>(IEngine engine, ref T param)
{
Next(engine, ref param, Condition.always);
}

public void Next<T>(IEngine engine, ref T param, Enum condition)
{
var tos = _steps[engine];
var steps = tos[condition];

if (steps != null)
for (int i = 0; i < steps.Length; i++)
((IStep<T>)steps[i]).Step(ref param, condition);
}

Steps _steps;
}

public enum Condition
{
always
}

public enum DamageCondition
{
damage,
dead
}
}

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

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

+ 20
- 0
ECS/SingleNodeEngine.cs View File

@@ -0,0 +1,20 @@
namespace Svelto.ECS
{
public abstract class SingleNodeEngine<TNodeType> : INodeEngine<INode> where TNodeType : class, INode
{
void INodeEngine<INode>.Add(INode obj)
{
Add(obj as TNodeType);
}

void INodeEngine<INode>.Remove(INode obj)
{
Remove(obj as TNodeType);
}

protected virtual void Add(TNodeType node)
{}
protected virtual void Remove(TNodeType node)
{}
}
}

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

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

+ 3
- 3
Factories.meta View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 354b7801c1d782b47b5d9ff9aba85e83
guid: 7f7896118ef3c4949898b5c30aea0c47
folderAsset: yes
timeCreated: 1434752394
licenseType: Free
timeCreated: 1484044925
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:


+ 0
- 42
Observer/Observable.cs View File

@@ -1,42 +0,0 @@
using System;

namespace Svelto.Observer
{
public delegate void ObserverAction<DispatchType>(ref DispatchType parameter);

public interface IObservable
{
event Action Notify;

void Dispatch();
}

public interface IObservable<DispatchType>
{
event ObserverAction<DispatchType> Notify;

void Dispatch(ref DispatchType parameter);
}

public class Observable<DispatchType>:IObservable<DispatchType>
{
public event ObserverAction<DispatchType> Notify;

public void Dispatch(ref DispatchType parameter)
{
if (Notify != null)
Notify(ref parameter);
}
}

public class Observable:IObservable
{
public event Action Notify;

public void Dispatch()
{
if (Notify != null)
Notify();
}
}
}

+ 0
- 12
Observer/Observable.cs.meta View File

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

+ 0
- 111
Observer/Observer.cs View File

@@ -1,111 +0,0 @@
using System;

namespace Svelto.Observer.InterNamespace
{
public abstract class Observer<DispatchType, ActionType> : IObserver<ActionType>
{
protected Observer(Observable<DispatchType> observable)
{
observable.Notify += OnObservableDispatched;

_unsubscribe = () => observable.Notify -= OnObservableDispatched;
}

public void AddAction(ObserverAction<ActionType> action)
{
_actions += action;
}

public void RemoveAction(ObserverAction<ActionType> action)
{
_actions -= action;
}

public void Unsubscribe()
{
_unsubscribe();
}

void OnObservableDispatched(ref DispatchType dispatchNotification)
{
if (_actions != null)
{
var actionType = TypeMap(ref dispatchNotification);

_actions(ref actionType);
}
}

protected abstract ActionType TypeMap(ref DispatchType dispatchNotification);

ObserverAction<ActionType> _actions;
Action _unsubscribe;
}
}

namespace Svelto.Observer.IntraNamespace
{
public class Observer<DispatchType> : InterNamespace.Observer<DispatchType, DispatchType>
{
public Observer(Observable<DispatchType> observable) : base(observable)
{ }

protected override DispatchType TypeMap(ref DispatchType dispatchNotification)
{
return dispatchNotification;
}
}
}

namespace Svelto.Observer
{
public class Observer: IObserver
{
public Observer(Observable observable)
{
observable.Notify += OnObservableDispatched;

_unsubscribe = () => observable.Notify -= OnObservableDispatched;
}

public void AddAction(Action action)
{
_actions += action;
}

public void RemoveAction(Action action)
{
_actions -= action;
}

public void Unsubscribe()
{
_unsubscribe();
}

void OnObservableDispatched()
{
if (_actions != null)
_actions();
}

Action _actions;
readonly Action _unsubscribe;
}

public interface IObserver<WatchingType>
{
void AddAction(ObserverAction<WatchingType> action);
void RemoveAction(ObserverAction<WatchingType> action);

void Unsubscribe();
}

public interface IObserver
{
void AddAction(Action action);
void RemoveAction(Action action);

void Unsubscribe();
}
}

+ 0
- 12
Observer/Observer.cs.meta View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 7b4eff431179a5047a4b9110fe27ecf6
timeCreated: 1440352946
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

+ 0
- 5
Ticker.meta View File

@@ -1,5 +0,0 @@
fileFormatVersion: 2
guid: 86d00787627f3e643bfb37812067fbc5
folderAsset: yes
DefaultImporter:
userData:

+ 0
- 31
Ticker/ITickable.cs View File

@@ -1,31 +0,0 @@
namespace Svelto.Ticker
{
public interface ILateTickable : ITickableBase
{
void LateTick(float deltaSec);
}

public interface IPhysicallyTickable : ITickableBase
{
void PhysicsTick(float deltaSec);
}

public interface ITickable : ITickableBase
{
void Tick(float deltaSec);
}

public interface IEndOfFrameTickable : ITickableBase
{
void EndOfFrameTick(float deltaSec);
}

public interface IIntervaledTickable : ITickableBase
{
void IntervaledTick();
}

public interface ITickableBase
{
}
}

+ 0
- 8
Ticker/ITicker.cs View File

@@ -1,8 +0,0 @@
namespace Svelto.Ticker
{
public interface ITicker
{
void Add(ITickableBase tickable);
void Remove(ITickableBase tickable);
}
}

+ 0
- 15
Ticker/IntervaledTickAttribute.cs View File

@@ -1,15 +0,0 @@
using System;

namespace Svelto.Ticker
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
internal class IntervaledTickAttribute : Attribute
{
public float interval;

public IntervaledTickAttribute(float intervalTime)
{
interval = intervalTime;
}
}
}

+ 0
- 12
Ticker/IntervaledTickAttribute.cs.meta View File

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

+ 0
- 153
Ticker/TickBehaviour.cs View File

@@ -1,153 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Svelto.Ticker
{
public class TickBehaviour : MonoBehaviour
{
IEnumerator Start ()
{
var waitForEndFrame = new WaitForEndOfFrame();

while (true)
{
yield return waitForEndFrame;

for (int i = _endOfFrameTicked.Count - 1; i >= 0; --i)
{
try
{
_endOfFrameTicked[i].EndOfFrameTick(Time.deltaTime);
}
catch (Exception e)
{
Utility.Console.LogException(e);
}
}
}
}
internal void Add(ITickable tickable)
{
_ticked.Add(tickable);
}

internal void AddLate(ILateTickable tickable)
{
_lateTicked.Add(tickable);
}

internal void AddPhysic(IPhysicallyTickable tickable)
{
_physicallyTicked.Add(tickable);
}

internal void AddEndOfFrame(IEndOfFrameTickable tickable)
{
_endOfFrameTicked.Add(tickable);
}

internal void Remove(ITickable tickable)
{
_ticked.Remove(tickable);
}

internal void RemoveLate(ILateTickable tickable)
{
_lateTicked.Remove(tickable);
}

internal void RemovePhysic(IPhysicallyTickable tickable)
{
_physicallyTicked.Remove(tickable);
}

internal void RemoveEndOfFrame(IEndOfFrameTickable tickable)
{
_endOfFrameTicked.Remove(tickable);
}

void FixedUpdate()
{
for (int i = _physicallyTicked.Count - 1; i >= 0; --i)
{
try
{
_physicallyTicked[i].PhysicsTick(Time.fixedDeltaTime);
}
catch (Exception e)
{
Utility.Console.LogException(e);
}
}
}

void LateUpdate()
{
for (int i = _lateTicked.Count - 1; i >= 0; --i)
{
try
{
_lateTicked[i].LateTick(Time.deltaTime);
}
catch (Exception e)
{
Utility.Console.LogException(e);
}
}
}

void Update()
{
for (int i = _ticked.Count - 1; i >= 0; --i)
{
try
{
_ticked[i].Tick(Time.deltaTime);
}
catch (Exception e)
{
Utility.Console.LogException(e);
}
}
}

internal void AddIntervaled(IIntervaledTickable tickable)
{
var methodInfo = ((Action)tickable.IntervaledTick).Method;
object[] attrs = methodInfo.GetCustomAttributes(typeof(IntervaledTickAttribute), true);

IEnumerator intervaledTick = IntervaledUpdate(tickable, (attrs[0] as IntervaledTickAttribute).interval);

_intervalledTicked[tickable] = intervaledTick;

StartCoroutine(intervaledTick);
}

internal void RemoveIntervaled(IIntervaledTickable tickable)
{
IEnumerator enumerator;

if (_intervalledTicked.TryGetValue(tickable, out enumerator))
{
StopCoroutine(enumerator);

_intervalledTicked.Remove(tickable);
}
}

IEnumerator IntervaledUpdate(IIntervaledTickable tickable, float seconds)
{
while (true) { DateTime next = DateTime.UtcNow.AddSeconds(seconds); while (DateTime.UtcNow < next) yield return null; tickable.IntervaledTick(); }
}

List<ILateTickable> _lateTicked = new List<ILateTickable>();
List<IPhysicallyTickable> _physicallyTicked = new List<IPhysicallyTickable>();
List<ITickable> _ticked = new List<ITickable>();
List<IEndOfFrameTickable> _endOfFrameTicked = new List<IEndOfFrameTickable>();

Dictionary<IIntervaledTickable, IEnumerator> _intervalledTicked = new Dictionary<IIntervaledTickable, IEnumerator>();
}
}

+ 0
- 57
Ticker/UnityTicker.cs View File

@@ -1,57 +0,0 @@
using UnityEngine;

namespace Svelto.Ticker
{
class UnityTicker : ITicker
{
public UnityTicker()
{
_ticker = Object.FindObjectOfType<TickBehaviour>();

if (_ticker == null)
{
var go = new GameObject("SveltoTicker");

_ticker = go.AddComponent<TickBehaviour>();
}
}

public void Add(ITickableBase tickable)
{
if (tickable is ITickable)
_ticker.Add(tickable as ITickable);

if (tickable is IPhysicallyTickable)
_ticker.AddPhysic(tickable as IPhysicallyTickable);

if (tickable is ILateTickable)
_ticker.AddLate(tickable as ILateTickable);

if (tickable is IEndOfFrameTickable)
_ticker.AddEndOfFrame(tickable as IEndOfFrameTickable);

if (tickable is IIntervaledTickable)
_ticker.AddIntervaled(tickable as IIntervaledTickable);
}

public void Remove(ITickableBase tickable)
{
if (tickable is ITickable)
_ticker.Remove(tickable as ITickable);

if (tickable is IPhysicallyTickable)
_ticker.RemovePhysic(tickable as IPhysicallyTickable);

if (tickable is ILateTickable)
_ticker.RemoveLate(tickable as ILateTickable);

if (tickable is IEndOfFrameTickable)
_ticker.RemoveEndOfFrame(tickable as IEndOfFrameTickable);

if (tickable is IIntervaledTickable)
_ticker.RemoveIntervaled(tickable as IIntervaledTickable);
}

readonly TickBehaviour _ticker;
}
}

+ 3
- 3
Utilities.meta View File

@@ -1,8 +1,8 @@
fileFormatVersion: 2
guid: 9581aacbfc73076489f471e3e83ba71d
guid: b7374ca2eb247d44c8783d7d23f9b89e
folderAsset: yes
timeCreated: 1440947158
licenseType: Free
timeCreated: 1484394896
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:


+ 79
- 18
Utilities/Print.cs View File

@@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
using System.Text;
using Debug = UnityEngine.Debug;
using UnityEngine;

public static class FastConcatUtility
{
@@ -65,20 +65,78 @@ public static class FastConcatUtility
return _stringBuilder.ToString();
}
}

public static string FastJoin(this string[] str)
{
lock (_stringBuilder)
{
_stringBuilder.Length = 0;

for (int i = 0; i < str.Length; i++)
_stringBuilder.Append(str[i]);

return _stringBuilder.ToString();
}
}

public static string FastJoin(this string[] str, string str1)
{
lock (_stringBuilder)
{
_stringBuilder.Length = 0;

for (int i = 0; i < str.Length; i++)
_stringBuilder.Append(str[i]);

_stringBuilder.Append(str1);

return _stringBuilder.ToString();
}
}
}

namespace Utility
{
public interface ILogger
{
void Log (string txt, string stack = null, LogType type = LogType.Log);
}

public class SlowLogger : ILogger
{
public void Log(string txt, string stack = null, LogType type = LogType.Log)
{
switch (type)
{
case LogType.Log:
UnityEngine.Debug.Log(stack != null ? txt.FastConcat(stack) : txt);
break;
case LogType.Exception:
UnityEngine.Debug.LogError("Log of exceptions not supported");
break;
case LogType.Warning:
UnityEngine.Debug.LogWarning(stack != null ? txt.FastConcat(stack) : txt);
break;
case LogType.Error:
UnityEngine.Debug.LogError(stack != null ? txt.FastConcat(stack) : txt);
break;
}
}
}

public static class Console
{
static StringBuilder _stringBuilder = new StringBuilder(256);

public static ILogger logger = new SlowLogger();
public static volatile bool BatchLog = false;

public static void Log(string txt)
{
Debug.Log(txt);
logger.Log(txt);
}

public static void LogError(string txt)
public static void LogError(string txt, bool showCurrentStack = true)
{
string toPrint;
@@ -90,31 +148,34 @@ namespace Utility

toPrint = _stringBuilder.ToString();
}
Debug.LogError(toPrint);
}

public static void LogException(Exception e)
{
LogException(e, null);
logger.Log(toPrint, showCurrentStack == true ? new StackTrace().ToString() : null, LogType.Error);
}

public static void LogException(Exception e, UnityEngine.Object obj)
public static void LogError(string txt, string stack)
{
string toPrint;

lock (_stringBuilder)
{
_stringBuilder.Length = 0;
_stringBuilder.Append("-!!!!!!-> ").Append(e);
_stringBuilder.Append("-!!!!!!-> ");
_stringBuilder.Append(txt);

toPrint = _stringBuilder.ToString();
}

Exception ex = new Exception(e.ToString());
logger.Log(toPrint, stack, LogType.Error);
}

public static void LogException(Exception e)
{
LogException(e, null);
}

Debug.Log(toPrint);
Debug.LogException(ex, obj);
public static void LogException(Exception e, UnityEngine.Object obj)
{
UnityEngine.Debug.LogException(e, obj);
}

public static void LogWarning(string txt)
@@ -130,11 +191,11 @@ namespace Utility
toPrint = _stringBuilder.ToString();
}

Debug.LogWarning(toPrint);
logger.Log(toPrint, null, LogType.Warning);
}

/// <summary>
/// This function should never be used explicitly
/// Use this function if you don't want the message to be batched
/// </summary>
/// <param name="txt"></param>
public static void SystemLog(string txt)
@@ -144,7 +205,7 @@ namespace Utility
lock (_stringBuilder)
{
string currentTimeString = DateTime.UtcNow.ToLongTimeString(); //ensure includes seconds
string processTimeString = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString();
string processTimeString = (DateTime.UtcNow - Process.GetCurrentProcess().StartTime).ToString();

_stringBuilder.Length = 0;
_stringBuilder.Append("[").Append(currentTimeString);
@@ -158,7 +219,7 @@ namespace Utility
#if !UNITY_EDITOR
System.Console.WriteLine(toPrint);
#else
Debug.Log(toPrint);
UnityEngine.Debug.Log(toPrint);
#endif
}
}


+ 122
- 0
Utilities/WeakActionStruct.cs View File

@@ -0,0 +1,122 @@
using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

//careful, you must handle the destruction of the GCHandles!

namespace BetterWeakEvents
{
public struct WeakAction<T1, T2> : IEquatable<WeakAction<T1, T2>>
{
public WeakAction(Action<T1, T2> listener)
{
ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak);
Method = listener.Method;

if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0)
throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
}

public bool Invoke(T1 data1, T2 data2)
{
if (ObjectRef.IsAllocated && ObjectRef.Target != null)
{
Method.Invoke(ObjectRef.Target, new object[] { data1, data2 });
return true;
}

Release();
return false;
}

public bool Equals(WeakAction<T1, T2> other)
{
return (Method.Equals(other.Method));
}

public void Release()
{
ObjectRef.Free();
}

readonly GCHandle ObjectRef;
readonly MethodInfo Method;
}

public struct WeakAction<T> : IEquatable<WeakAction<T>>
{
public WeakAction(Action<T> listener)
{
ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak);
Method = listener.Method;

if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0)
throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
}

public bool Invoke(T data)
{
if (ObjectRef.IsAllocated && ObjectRef.Target != null)
{
Method.Invoke(ObjectRef.Target, new object[] { data });
return true;
}

Release();
return false;
}

public bool Equals(WeakAction<T> other)
{
return (Method.Equals(other.Method));
}

public void Release()
{
ObjectRef.Free();
}

readonly GCHandle ObjectRef;
readonly MethodInfo Method;
}

public struct WeakAction : IEquatable<WeakAction>
{
public WeakAction(Action listener)
{
ObjectRef = GCHandle.Alloc(listener.Target, GCHandleType.Weak);
Method = listener.Method;

if (Method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0)
throw new ArgumentException("Cannot create weak event to anonymous method with closure.");
}

public bool Invoke()
{
if (ObjectRef.IsAllocated && ObjectRef.Target != null)
{
Method.Invoke(ObjectRef.Target, null);
return true;
}

Release();
return false;
}

public bool Equals(WeakAction other)
{
return (Method.Equals(other.Method));
}

public void Release()
{
ObjectRef.Free();
}

readonly GCHandle ObjectRef;
readonly MethodInfo Method;
}


}

+ 12
- 0
Utilities/WeakActionStruct.cs.meta View File

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

+ 35
- 0
Utilities/WeakEvent.cs View File

@@ -0,0 +1,35 @@
using Svelto.DataStructures;
using System;

namespace BetterWeakEvents
{
public class WeakEvent<T1, T2>
{
public static WeakEvent<T1, T2> operator+(WeakEvent<T1, T2> c1, Action<T1, T2> x)
{
c1._subscribers.Add(new WeakAction<T1, T2>(x));
return c1;
}

public static WeakEvent<T1, T2> operator-(WeakEvent<T1, T2> c1, Action<T1, T2> x)
{
c1._subscribers.UnorderredRemove(new WeakAction<T1, T2>(x));
return c1;
}

public void Invoke(T1 arg1, T2 arg2)
{
for (int i = 0; i < _subscribers.Count; i++)
if (_subscribers[i].Invoke(arg1, arg2) == false)
_subscribers.UnorderredRemoveAt(i--);
}

~WeakEvent()
{
for (int i = 0; i < _subscribers.Count; i++)
_subscribers[i].Release();
}

protected FasterList<WeakAction<T1, T2>> _subscribers = new FasterList<WeakAction<T1, T2>>();
}
}

+ 12
- 0
Utilities/WeakEvent.cs.meta View File

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

Loading…
Cancel
Save