@@ -1,4 +1 @@ | |||
/EntitySystem/note.txt | |||
/EntitySystem/note.txt.meta | |||
/*.meta | |||
*.meta |
@@ -1,183 +0,0 @@ | |||
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? | |||
public 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; | |||
} | |||
} |
@@ -1,807 +0,0 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
namespace Svelto.DataStructures | |||
{ | |||
public struct FasterListEnumerator<T> : IEnumerator<T> | |||
{ | |||
public T Current | |||
{ | |||
get { return _current; } | |||
} | |||
public FasterListEnumerator(T[] buffer, int size) | |||
{ | |||
_size = size; | |||
_counter = 0; | |||
_buffer = buffer; | |||
_current = default(T); | |||
} | |||
object IEnumerator.Current | |||
{ | |||
get { return _current; } | |||
} | |||
T IEnumerator<T>.Current | |||
{ | |||
get { return _current; } | |||
} | |||
public void Dispose() | |||
{ | |||
_buffer = null; | |||
} | |||
public bool MoveNext() | |||
{ | |||
if (_counter < _size) | |||
{ | |||
_current = _buffer[_counter++]; | |||
return true; | |||
} | |||
_current = default(T); | |||
return false; | |||
} | |||
public void Reset() | |||
{ | |||
_counter = 0; | |||
} | |||
bool IEnumerator.MoveNext() | |||
{ | |||
return MoveNext(); | |||
} | |||
void IEnumerator.Reset() | |||
{ | |||
Reset(); | |||
} | |||
T[] _buffer; | |||
int _counter; | |||
int _size; | |||
T _current; | |||
} | |||
public struct FasterListEnumeratorCast<T, U> : IEnumerator<T> where T:U | |||
{ | |||
public T Current | |||
{ | |||
get { return (T)_buffer.Current; } | |||
} | |||
public FasterListEnumeratorCast(FasterListEnumerator<U> buffer) | |||
{ | |||
_buffer = buffer; | |||
} | |||
object IEnumerator.Current | |||
{ | |||
get { return (T)_buffer.Current; } | |||
} | |||
T IEnumerator<T>.Current | |||
{ | |||
get { return (T)_buffer.Current; } | |||
} | |||
public void Dispose() | |||
{} | |||
public bool MoveNext() | |||
{ | |||
return _buffer.MoveNext(); | |||
} | |||
public void Reset() | |||
{ | |||
_buffer.Reset(); | |||
} | |||
bool IEnumerator.MoveNext() | |||
{ | |||
return MoveNext(); | |||
} | |||
void IEnumerator.Reset() | |||
{ | |||
Reset(); | |||
} | |||
FasterListEnumerator<U> _buffer; | |||
} | |||
public struct FasterReadOnlyList<T> : IList<T> | |||
{ | |||
public static FasterReadOnlyList<T> DefaultList = new FasterReadOnlyList<T>(new FasterList<T>()); | |||
public int Count { get { return _list.Count; } } | |||
public bool IsReadOnly { get { return true; } } | |||
public FasterReadOnlyList(FasterList<T> list) | |||
{ | |||
_list = list; | |||
} | |||
public T this[int index] { get { return _list[index]; } set { throw new NotImplementedException(); } } | |||
public FasterListEnumerator<T> GetEnumerator() | |||
{ | |||
return _list.GetEnumerator(); | |||
} | |||
public void Add(T item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public void Clear() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public bool Contains(T item) | |||
{ | |||
return _list.Contains(item); | |||
} | |||
public void CopyTo(T[] array, int arrayIndex) | |||
{ | |||
_list.CopyTo(array, arrayIndex); | |||
} | |||
public bool Remove(T item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public int IndexOf(T item) | |||
{ | |||
return _list.IndexOf(item); | |||
} | |||
public void Insert(int index, T item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public void RemoveAt(int index) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
IEnumerator<T> IEnumerable<T>.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
readonly FasterList<T> _list; | |||
} | |||
public struct FasterListThreadSafe<T> : IList<T> | |||
{ | |||
public FasterListThreadSafe(FasterList<T> list) | |||
{ | |||
if (list == null) throw new ArgumentException("invalid list"); | |||
_list = list; | |||
_lockQ = new ReaderWriterLockSlim(); | |||
} | |||
public int Count | |||
{ | |||
get | |||
{ | |||
_lockQ.EnterReadLock(); | |||
try | |||
{ | |||
return _list.Count; | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitReadLock(); | |||
} | |||
} | |||
} | |||
public bool IsReadOnly { get { return false; } } | |||
public T this[int index] | |||
{ | |||
get | |||
{ | |||
_lockQ.EnterReadLock(); | |||
try | |||
{ | |||
return _list[index]; | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitReadLock(); | |||
} | |||
} | |||
set | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list[index] = value; | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
} | |||
public FasterListEnumerator<T> GetEnumerator() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public void Add(T item) | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.Add(item); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void Clear() | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.Clear(); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void FastClear() | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.FastClear(); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
public bool Contains(T item) | |||
{ | |||
_lockQ.EnterReadLock(); | |||
try | |||
{ | |||
return _list.Contains(item); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitReadLock(); | |||
} | |||
} | |||
public void CopyTo(T[] array, int arrayIndex) | |||
{ | |||
_lockQ.EnterReadLock(); | |||
try | |||
{ | |||
_list.CopyTo(array, arrayIndex); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitReadLock(); | |||
} | |||
} | |||
public bool Remove(T item) | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
return _list.Remove(item); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
public int IndexOf(T item) | |||
{ | |||
_lockQ.EnterReadLock(); | |||
try | |||
{ | |||
return _list.IndexOf(item); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitReadLock(); | |||
} | |||
} | |||
public void Insert(int index, T item) | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.Insert(index, item); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void RemoveAt(int index) | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.RemoveAt(index); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void UnorderedRemoveAt(int index) | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.UnorderedRemoveAt(index); | |||
} | |||
finally | |||
{ | |||
_lockQ.ExitWriteLock(); | |||
} | |||
} | |||
IEnumerator<T> IEnumerable<T>.GetEnumerator() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
readonly FasterList<T> _list; | |||
readonly ReaderWriterLockSlim _lockQ; | |||
} | |||
public struct FasterReadOnlyListCast<T, U> : IList<U> where U:T | |||
{ | |||
public static FasterReadOnlyListCast<T, U> DefaultList = new FasterReadOnlyListCast<T, U>(new FasterList<T>()); | |||
public int Count { get { return _list.Count; } } | |||
public bool IsReadOnly { get { return true; } } | |||
public FasterReadOnlyListCast(FasterList<T> list) | |||
{ | |||
_list = list; | |||
} | |||
public U this[int index] { get { return (U)_list[index]; } set { throw new NotImplementedException(); } } | |||
public FasterListEnumeratorCast<U, T> GetEnumerator() | |||
{ | |||
return new FasterListEnumeratorCast<U, T>(_list.GetEnumerator()); | |||
} | |||
public void Add(U item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public void Clear() | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public bool Contains(U item) | |||
{ | |||
return _list.Contains(item); | |||
} | |||
public void CopyTo(U[] array, int arrayIndex) | |||
{ | |||
Array.Copy(_list.ToArrayFast(), 0, array, arrayIndex, _list.Count); | |||
} | |||
public bool Remove(U item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public int IndexOf(U item) | |||
{ | |||
return _list.IndexOf(item); | |||
} | |||
public void Insert(int index, U item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
public void RemoveAt(int index) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
IEnumerator<U> IEnumerable<U>.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
readonly FasterList<T> _list; | |||
} | |||
public interface IFasterList | |||
{} | |||
public class FasterList<T> : IList<T>, IFasterList | |||
{ | |||
const int MIN_SIZE = 4; | |||
public int Count | |||
{ | |||
get { return _count; } | |||
} | |||
public bool IsReadOnly | |||
{ | |||
get { return false; } | |||
} | |||
public FasterList() | |||
{ | |||
_count = 0; | |||
_buffer = new T[MIN_SIZE]; | |||
} | |||
public FasterList(int initialSize) | |||
{ | |||
_count = 0; | |||
_buffer = new T[initialSize]; | |||
} | |||
public FasterList(ICollection<T> collection) | |||
{ | |||
_buffer = new T[collection.Count]; | |||
collection.CopyTo(_buffer, 0); | |||
_count = _buffer.Length; | |||
} | |||
public FasterList(FasterList<T> listCopy) | |||
{ | |||
_buffer = new T[listCopy.Count]; | |||
listCopy.CopyTo(_buffer, 0); | |||
_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) | |||
AllocateMore(); | |||
_buffer[_count++] = item; | |||
} | |||
/// <summary> | |||
/// this is a dirtish trick to be able to use the index operastor | |||
/// before adding the elements through the Add functions | |||
/// </summary> | |||
/// <typeparam name="U"></typeparam> | |||
/// <param name="initialSize"></param> | |||
/// <returns></returns> | |||
public static FasterList<T> PreFill<U>(int initialSize) where U:T, new() | |||
{ | |||
var list = new FasterList<T>(initialSize); | |||
for (int i = 0; i < initialSize; i++) | |||
list.Add(new U()); | |||
list._count = 0; | |||
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); | |||
while (items.MoveNext()) | |||
_buffer[_count++] = items.Current; | |||
} | |||
public void AddRange(ICollection<T> items) | |||
{ | |||
AddRange(items.GetEnumerator(), items.Count); | |||
} | |||
public void AddRange(FasterList<T> items) | |||
{ | |||
AddRange(items.ToArrayFast(), items.Count); | |||
} | |||
public void AddRange(T[] items, int count) | |||
{ | |||
if (count == 0) return; | |||
if (_count + count >= _buffer.Length) | |||
AllocateMore(_count + count); | |||
Array.Copy(items, 0, _buffer, _count, count); | |||
_count += count; | |||
} | |||
public void AddRange(T[] items) | |||
{ | |||
AddRange(items, items.Length); | |||
} | |||
public FasterReadOnlyList<T> AsReadOnly() | |||
{ | |||
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 FastClear() | |||
{ | |||
_count = 0; | |||
} | |||
public void Clear() | |||
{ | |||
Array.Clear(_buffer, 0, _buffer.Length); | |||
_count = 0; | |||
} | |||
public bool Contains(T item) | |||
{ | |||
var index = IndexOf(item); | |||
return index != -1; | |||
} | |||
public void CopyTo(T[] array, int arrayIndex) | |||
{ | |||
Array.Copy(_buffer, 0, array, arrayIndex, Count); | |||
} | |||
public FasterListEnumerator<T> GetEnumerator() | |||
{ | |||
return new FasterListEnumerator<T>(_buffer, Count); | |||
} | |||
public int IndexOf(T item) | |||
{ | |||
var comp = EqualityComparer<T>.Default; | |||
for (var index = _count - 1; index >= 0; --index) | |||
if (comp.Equals(_buffer[index], item)) | |||
return index; | |||
return -1; | |||
} | |||
public void Insert(int index, T item) | |||
{ | |||
DesignByContract.Check.Require(index < _count, "out of bound index"); | |||
if (_count == _buffer.Length) AllocateMore(); | |||
Array.Copy(_buffer, index, _buffer, index + 1, _count - index); | |||
_buffer[index] = item; | |||
++_count; | |||
} | |||
public void Release() | |||
{ | |||
_count = 0; | |||
_buffer = null; | |||
} | |||
public bool Remove(T item) | |||
{ | |||
var index = IndexOf(item); | |||
if (index == -1) | |||
return false; | |||
RemoveAt(index); | |||
return true; | |||
} | |||
public void RemoveAt(int index) | |||
{ | |||
DesignByContract.Check.Require(index < _count, "out of bound index"); | |||
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; | |||
} | |||
public void SetAt(int index, T value) | |||
{ | |||
if (index >= _buffer.Length) | |||
AllocateMore(index + 1); | |||
if (_count <= index) | |||
_count = index + 1; | |||
this[index] = value; | |||
} | |||
public void Sort(IComparer<T> comparer) | |||
{ | |||
Array.Sort(_buffer, 0, _count, comparer); | |||
} | |||
public T[] ToArray() | |||
{ | |||
T[] destinationArray = new T[_count]; | |||
Array.Copy(_buffer, 0, destinationArray, 0, _count); | |||
return destinationArray; | |||
} | |||
/// <summary> | |||
/// This function exists to allow fast iterations. The size of the array returned cannot be | |||
/// used. The list count must be used instead. | |||
/// </summary> | |||
/// <returns></returns> | |||
public T[] ToArrayFast() | |||
{ | |||
return _buffer; | |||
} | |||
public bool UnorderedRemove(T item) | |||
{ | |||
var index = IndexOf(item); | |||
if (index == -1) | |||
return false; | |||
UnorderedRemoveAt(index); | |||
return true; | |||
} | |||
public bool UnorderedRemoveAt(int index) | |||
{ | |||
DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index"); | |||
if (index == --_count) | |||
{ | |||
_buffer[_count] = default(T); | |||
return false; | |||
} | |||
_buffer[index] = _buffer[_count]; | |||
_buffer[_count] = default(T); | |||
return true; | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
IEnumerator<T> IEnumerable<T>.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
void AllocateMore() | |||
{ | |||
var newList = new T[Math.Max(_buffer.Length << 1, MIN_SIZE)]; | |||
if (_count > 0) _buffer.CopyTo(newList, 0); | |||
_buffer = newList; | |||
} | |||
void AllocateMore(int newSize) | |||
{ | |||
var oldLength = Math.Max(_buffer.Length, MIN_SIZE); | |||
while (oldLength < newSize) | |||
oldLength <<= 1; | |||
var newList = new T[oldLength]; | |||
if (_count > 0) Array.Copy(_buffer, newList, _count); | |||
_buffer = newList; | |||
} | |||
public void Trim() | |||
{ | |||
if (_count < _buffer.Length) | |||
Resize(_count); | |||
} | |||
public bool Reuse<U>(int index, out U result) | |||
where U:class, T | |||
{ | |||
result = default(U); | |||
if (index >= _buffer.Length) | |||
return false; | |||
result = (U)_buffer[index]; | |||
return result != null; | |||
} | |||
T[] _buffer; | |||
int _count; | |||
} | |||
} |
@@ -1,56 +0,0 @@ | |||
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; | |||
} | |||
} |
@@ -1,142 +0,0 @@ | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
//from unify wiki | |||
namespace Svelto.DataStructures | |||
{ | |||
public class SingleLinkNode<T> | |||
{ | |||
// Note; the Next member cannot be a property since | |||
// it participates in many CAS operations | |||
public SingleLinkNode<T> Next; | |||
public T Item; | |||
} | |||
public static class SyncMethods | |||
{ | |||
public static bool CAS<T>(ref T location, T comparand, T newValue) where T : class | |||
{ | |||
return | |||
(object)comparand == | |||
(object)Interlocked.CompareExchange<T>(ref location, newValue, comparand); | |||
} | |||
} | |||
public class LockFreeLinkPool<T> | |||
{ | |||
private SingleLinkNode<T> head; | |||
public LockFreeLinkPool() | |||
{ | |||
head = new SingleLinkNode<T>(); | |||
} | |||
public void Push(SingleLinkNode<T> newNode) | |||
{ | |||
newNode.Item = default(T); | |||
do | |||
{ | |||
newNode.Next = head.Next; | |||
} while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, newNode.Next, newNode)); | |||
return; | |||
} | |||
public bool Pop(out SingleLinkNode<T> node) | |||
{ | |||
do | |||
{ | |||
node = head.Next; | |||
if (node == null) | |||
{ | |||
return false; | |||
} | |||
} while (!SyncMethods.CAS<SingleLinkNode<T>>(ref head.Next, node, node.Next)); | |||
return true; | |||
} | |||
} | |||
public class LockFreeQueue<T> | |||
{ | |||
SingleLinkNode<T> head; | |||
SingleLinkNode<T> tail; | |||
LockFreeLinkPool<T> trash; | |||
public LockFreeQueue() | |||
{ | |||
head = new SingleLinkNode<T>(); | |||
tail = head; | |||
trash = new LockFreeLinkPool<T>(); | |||
} | |||
public void Enqueue(T item) | |||
{ | |||
SingleLinkNode<T> oldTail = null; | |||
SingleLinkNode<T> oldTailNext; | |||
SingleLinkNode<T> newNode; | |||
if (!trash.Pop(out newNode)) | |||
{ | |||
newNode = new SingleLinkNode<T>(); | |||
} | |||
else | |||
{ | |||
newNode.Next = null; | |||
} | |||
newNode.Item = item; | |||
bool newNodeWasAdded = false; | |||
while (!newNodeWasAdded) | |||
{ | |||
oldTail = tail; | |||
oldTailNext = oldTail.Next; | |||
if (tail == oldTail) | |||
{ | |||
if (oldTailNext == null) | |||
newNodeWasAdded = SyncMethods.CAS<SingleLinkNode<T>>(ref tail.Next, null, newNode); | |||
else | |||
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, oldTailNext); | |||
} | |||
} | |||
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, newNode); | |||
} | |||
public bool Dequeue(out T item) | |||
{ | |||
item = default(T); | |||
SingleLinkNode<T> oldHead = null; | |||
bool haveAdvancedHead = false; | |||
while (!haveAdvancedHead) | |||
{ | |||
oldHead = head; | |||
SingleLinkNode<T> oldTail = tail; | |||
SingleLinkNode<T> oldHeadNext = oldHead.Next; | |||
if (oldHead == head) | |||
{ | |||
if (oldHead == oldTail) | |||
{ | |||
if (oldHeadNext == null) | |||
{ | |||
return false; | |||
} | |||
SyncMethods.CAS<SingleLinkNode<T>>(ref tail, oldTail, oldHeadNext); | |||
} | |||
else | |||
{ | |||
item = oldHeadNext.Item; | |||
haveAdvancedHead = SyncMethods.CAS<SingleLinkNode<T>>(ref head, oldHead, oldHeadNext); | |||
if (haveAdvancedHead) | |||
{ | |||
trash.Push(oldHead); | |||
} | |||
} | |||
} | |||
} | |||
return true; | |||
} | |||
} | |||
} |
@@ -1,327 +0,0 @@ | |||
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.FastClear(); | |||
_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; | |||
} | |||
} | |||
} |
@@ -1,23 +0,0 @@ | |||
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); | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
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; } | |||
} | |||
} |
@@ -1,544 +0,0 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
namespace Svelto.DataStructures | |||
{ | |||
public struct ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> | |||
{ | |||
public bool isInitialized { get { return _dictionary != null; } } | |||
/// <summary> | |||
/// Gets the element that has the specified key. | |||
/// </summary> | |||
/// <param name="key">The key of the element to get.</param> | |||
/// <returns>The element that has the specified key.</returns> | |||
/// <exception cref="ArgumentNullException">If <paramref name="key"/> is <see langword="null"/>.</exception> | |||
/// <exception cref="KeyNotFoundException">If property is retrieved and <paramref name="key"/> is not found.</exception> | |||
public TValue this[TKey key] | |||
{ | |||
get | |||
{ | |||
return _dictionary[key]; | |||
} | |||
} | |||
/// <summary> | |||
/// Gets the number of items in the dictionary. | |||
/// </summary> | |||
/// <value> | |||
/// The number of items in the dictionary. | |||
/// </value> | |||
public int Count | |||
{ | |||
get | |||
{ | |||
return _dictionary.Count; | |||
} | |||
} | |||
/// <summary> | |||
/// Gets a key collection that contains the keys of the dictionary. | |||
/// </summary> | |||
/// <value> | |||
/// A key collection that contains the keys of the dictionary. | |||
/// </value> | |||
public KeyCollection Keys | |||
{ | |||
get | |||
{ | |||
return new KeyCollection(_dictionary.Keys); | |||
} | |||
} | |||
/// <summary> | |||
/// Gets a collection that contains the values in the dictionary. | |||
/// </summary> | |||
/// <value> | |||
/// A collection that contains the values in the object that implements <see cref="ReadOnlyDictionary{TKey, TValue}"/>. | |||
/// </value> | |||
public ValueCollection Values | |||
{ | |||
get | |||
{ | |||
return new ValueCollection(_dictionary.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) | |||
{ | |||
if (dictionary == null) | |||
throw new ArgumentNullException("dictionary"); | |||
_dictionary = dictionary; | |||
} | |||
/// <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/> | |||
ICollection<TKey> IDictionary<TKey, TValue>.Keys | |||
{ | |||
get | |||
{ | |||
return Keys; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
ICollection<TValue> IDictionary<TKey, TValue>.Values | |||
{ | |||
get | |||
{ | |||
return Values; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly | |||
{ | |||
get | |||
{ | |||
return true; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
/// <inheritdoc/> | |||
void IDictionary<TKey, TValue>.Add(TKey key, TValue value) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
bool IDictionary<TKey, TValue>.Remove(TKey key) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<KeyValuePair<TKey, TValue>>.Clear() | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
bool IDictionary<TKey, TValue>.ContainsKey(TKey key) | |||
{ | |||
return _dictionary.ContainsKey(key); | |||
} | |||
bool IDictionary<TKey, TValue>.TryGetValue(TKey key, out TValue value) | |||
{ | |||
return _dictionary.TryGetValue(key, out value); | |||
} | |||
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> | |||
/// Initializes a new instance of the <see cref="KeyCollection"/> class | |||
/// as a wrapper around the specified collection of keys. | |||
/// </summary> | |||
/// <param name="keys">The collection of keys to wrap.</param> | |||
/// <exception cref="ArgumentNullException">If <paramref name="keys"/> is <see langword="null"/>.</exception> | |||
internal KeyCollection(ICollection<TKey> keys) | |||
{ | |||
if (keys == null) | |||
throw new ArgumentNullException("keys"); | |||
_keys = keys; | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection.IsSynchronized | |||
{ | |||
get | |||
{ | |||
return false; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
object ICollection.SyncRoot | |||
{ | |||
get | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
} | |||
/// <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 _keys.Count; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<TKey>.IsReadOnly | |||
{ | |||
get | |||
{ | |||
return true; | |||
} | |||
} | |||
/// <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> | |||
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param> | |||
/// <exception cref="ArgumentNullException">If <paramref name="array"/> is <see langword="null"/>.</exception> | |||
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="arrayIndex"/> is less than 0.</exception> | |||
/// <exception cref="ArgumentException"> | |||
/// If <paramref name="array"/> is multidimensional. | |||
/// <para>-or-</para> | |||
/// <para>If the number of elements in the source collection is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.</para> | |||
/// <para>-or-</para> | |||
/// <para>If the type <typeparamref name="TKey"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</para> | |||
/// </exception> | |||
public void CopyTo(TKey[] array, int arrayIndex) | |||
{ | |||
_keys.CopyTo(array, arrayIndex); | |||
} | |||
/// <summary> | |||
/// Returns an enumerator that iterates through the collection. | |||
/// </summary> | |||
/// <returns>An enumerator that can be used to iterate through the collection.</returns> | |||
public IEnumerator<TKey> GetEnumerator() | |||
{ | |||
return _keys.GetEnumerator(); | |||
} | |||
/// <inheritdoc/> | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<TKey>.Contains(TKey item) | |||
{ | |||
return _keys.Contains(item); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<TKey>.Add(TKey item) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<TKey>.Remove(TKey item) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<TKey>.Clear() | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <summary> | |||
/// The wrapped collection of keys. | |||
/// </summary> | |||
readonly ICollection<TKey> _keys; | |||
} | |||
/// <summary> | |||
/// Represents a read-only collection of the values of a <see cref="ReadOnlyDictionary{TKey, TValue}"/> object. | |||
/// </summary> | |||
public struct ValueCollection : ICollection<TValue>, ICollection | |||
{ | |||
/// <summary> | |||
/// Initializes a new instance of the <see cref="ValueCollection"/> class | |||
/// as a wrapper around the specified collection of values. | |||
/// </summary> | |||
/// <param name="values">The collection of values to wrap.</param> | |||
/// <exception cref="ArgumentNullException">If <paramref name="values"/> is <see langword="null"/>.</exception> | |||
internal ValueCollection(ICollection<TValue> values) | |||
{ | |||
if (values == null) | |||
throw new ArgumentNullException("values"); | |||
_values = values; | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection.IsSynchronized | |||
{ | |||
get | |||
{ | |||
return false; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
object ICollection.SyncRoot | |||
{ | |||
get | |||
{ | |||
throw new NotImplementedException(); | |||
} | |||
} | |||
/// <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 _values.Count; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<TValue>.IsReadOnly | |||
{ | |||
get | |||
{ | |||
return true; | |||
} | |||
} | |||
/// <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> | |||
/// <param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param> | |||
/// <exception cref="ArgumentNullException">If <paramref name="array"/> is <see langword="null"/>.</exception> | |||
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="arrayIndex"/> is less than 0.</exception> | |||
/// <exception cref="ArgumentException"> | |||
/// If <paramref name="array"/> is multidimensional. | |||
/// <para>-or-</para> | |||
/// <para>If the number of elements in the source collection is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.</para> | |||
/// <para>-or-</para> | |||
/// <para>If the type <typeparamref name="TValue"/> cannot be cast automatically to the type of the destination <paramref name="array"/>.</para> | |||
/// </exception> | |||
public void CopyTo(TValue[] array, int arrayIndex) | |||
{ | |||
_values.CopyTo(array, arrayIndex); | |||
} | |||
/// <summary> | |||
/// Returns an enumerator that iterates through the collection. | |||
/// </summary> | |||
/// <returns>An enumerator that can be used to iterate through the collection.</returns> | |||
public IEnumerator<TValue> GetEnumerator() | |||
{ | |||
return _values.GetEnumerator(); | |||
} | |||
/// <inheritdoc/> | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<TValue>.Contains(TValue item) | |||
{ | |||
return _values.Contains(item); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<TValue>.Add(TValue item) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
bool ICollection<TValue>.Remove(TValue item) | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <inheritdoc/> | |||
void ICollection<TValue>.Clear() | |||
{ | |||
throw new NotSupportedException(); | |||
} | |||
/// <summary> | |||
/// The wrapped collection of values. | |||
/// </summary> | |||
readonly ICollection<TValue> _values; | |||
} | |||
public struct DictionaryEnumerator:IEnumerator<KeyValuePair<TKey,TValue>> | |||
{ | |||
/// <inheritdoc/> | |||
public TKey Key | |||
{ | |||
get | |||
{ | |||
return _enumerator.Current.Key; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
public TValue Value | |||
{ | |||
get | |||
{ | |||
return _enumerator.Current.Value; | |||
} | |||
} | |||
public DictionaryEnumerator(IDictionary<TKey, TValue> dictionary) | |||
{ | |||
if (dictionary == null) | |||
throw new ArgumentNullException("dictionary"); | |||
_enumerator = dictionary.GetEnumerator(); | |||
} | |||
/// <inheritdoc/> | |||
public KeyValuePair<TKey, TValue> Current | |||
{ | |||
get | |||
{ | |||
return _enumerator.Current; | |||
} | |||
} | |||
/// <inheritdoc/> | |||
public bool MoveNext() | |||
{ | |||
return _enumerator.MoveNext(); | |||
} | |||
/// <inheritdoc/> | |||
public void Reset() | |||
{ | |||
_enumerator.Reset(); | |||
} | |||
object IEnumerator.Current | |||
{ | |||
get { return _enumerator.Current; } | |||
} | |||
public void Dispose() | |||
{ | |||
_enumerator.Dispose(); | |||
} | |||
readonly IEnumerator<KeyValuePair<TKey, TValue>> _enumerator; | |||
} | |||
} | |||
} |
@@ -1,290 +0,0 @@ | |||
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> | |||
public class ThreadSafeDictionary<TKey, TValue> | |||
{ | |||
public ThreadSafeDictionary(int v) | |||
{ | |||
dict = new Dictionary<TKey, TValue>(v); | |||
} | |||
public ThreadSafeDictionary() | |||
{ | |||
dict = new Dictionary<TKey, TValue>(); | |||
} | |||
// setup the lock; | |||
public virtual int Count | |||
{ | |||
get | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return dict.Count; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
} | |||
public virtual bool IsReadOnly | |||
{ | |||
get | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return dict.IsReadOnly; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
} | |||
public virtual FasterList<TKey> Keys | |||
{ | |||
get | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return new FasterList<TKey>(dict.Keys); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
} | |||
public virtual FasterList<TValue> Values | |||
{ | |||
get | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return new FasterList<TValue>(dict.Values); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
} | |||
public virtual TValue this[TKey key] | |||
{ | |||
get | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return dict[key]; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
set | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
dict[key] = value; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
} | |||
public virtual void Add(KeyValuePair<TKey, TValue> item) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
dict.Add(item); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public virtual void Clear() | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
dict.Clear(); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public virtual bool Contains(KeyValuePair<TKey, TValue> item) | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return dict.Contains(item); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
dict.CopyTo(array, arrayIndex); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
public virtual bool Remove(KeyValuePair<TKey, TValue> item) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
return dict.Remove(item); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public virtual void Add(TKey key, TValue value) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
dict.Add(key, value); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public virtual bool ContainsKey(TKey key) | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return dict.ContainsKey(key); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
public virtual bool Remove(TKey key) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
return dict.Remove(key); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public virtual bool TryGetValue(TKey key, out TValue value) | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
return dict.TryGetValue(key, out value); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
/// <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) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
// take a writelock immediately since we will always be writing | |||
if (dict.ContainsKey(key)) | |||
dict.Remove(key); | |||
dict.Add(key, newValue); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
/// <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) | |||
{ | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
if (dict.ContainsKey(key)) | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
dict.Remove(key); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
} | |||
// This is the internal dictionary that we are wrapping | |||
readonly IDictionary<TKey, TValue> dict; | |||
readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); | |||
} | |||
} |
@@ -1,233 +0,0 @@ | |||
using System.Collections.Generic; | |||
using System.Threading; | |||
namespace Svelto.DataStructures | |||
{ | |||
public class ThreadSafeQueue<T> | |||
{ | |||
readonly Queue<T> m_Queue; | |||
readonly ReaderWriterLockSlim LockQ = new ReaderWriterLockSlim(); | |||
public ThreadSafeQueue() | |||
{ | |||
m_Queue = new Queue<T>(); | |||
} | |||
public ThreadSafeQueue(int capacity) | |||
{ | |||
m_Queue = new Queue<T>(capacity); | |||
} | |||
public ThreadSafeQueue(IEnumerable<T> collection) | |||
{ | |||
m_Queue = new Queue<T>(collection); | |||
} | |||
public IEnumerator<T> GetEnumerator() | |||
{ | |||
Queue<T> localQ; | |||
LockQ.EnterReadLock(); | |||
try | |||
{ | |||
localQ = new Queue<T>(m_Queue); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitReadLock(); | |||
} | |||
foreach (T item in localQ) | |||
yield return item; | |||
} | |||
public void Enqueue(T item) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
m_Queue.Enqueue(item); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public T Dequeue() | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
return m_Queue.Dequeue(); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void EnqueueAll(IEnumerable<T> ItemsToQueue) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
foreach (T item in ItemsToQueue) | |||
m_Queue.Enqueue(item); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public FasterList<T> DequeueAll() | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
FasterList<T> returnList = new FasterList<T>(); | |||
while (m_Queue.Count > 0) | |||
returnList.Add(m_Queue.Dequeue()); | |||
return returnList; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void DequeueAllInto(FasterList<T> list) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
while (m_Queue.Count > 0) | |||
list.Add(m_Queue.Dequeue()); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void DequeueInto(FasterList<T> list, int count) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
int originalSize = m_Queue.Count; | |||
while (m_Queue.Count > 0 && originalSize - m_Queue.Count < count) | |||
list.Add(m_Queue.Dequeue()); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public FasterList<U> DequeueAllAs<U>() where U:class | |||
{ | |||
LockQ.EnterWriteLock(); | |||
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(); | |||
try | |||
{ | |||
T item = default(T); | |||
if (m_Queue.Count > 0) | |||
item = m_Queue.Peek(); | |||
return item; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public void Clear() | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
m_Queue.Clear(); | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public bool TryDequeue(out T item) | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
if (m_Queue.Count > 0) | |||
{ | |||
item = m_Queue.Dequeue(); | |||
return true; | |||
} | |||
else | |||
{ | |||
item = default(T); | |||
return false; | |||
} | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
public int Count | |||
{ | |||
get | |||
{ | |||
LockQ.EnterWriteLock(); | |||
try | |||
{ | |||
return m_Queue.Count; | |||
} | |||
finally | |||
{ | |||
LockQ.ExitWriteLock(); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,79 +0,0 @@ | |||
using System; | |||
/// <span class="code-SummaryComment"><summary></span> | |||
/// Represents a weak reference, which references an object while still allowing | |||
/// that object to be reclaimed by garbage collection. | |||
/// <span class="code-SummaryComment"></summary></span> | |||
/// <span class="code-SummaryComment"><typeparam name="T">The type of the object that is referenced.</typeparam></span> | |||
namespace Svelto.DataStructures | |||
{ | |||
#if !NETFX_CORE | |||
public class WeakReference<T> | |||
: WeakReference where T : class | |||
{ | |||
public bool IsValid { get { return Target != null && IsAlive == true; } } | |||
/// <span class="code-SummaryComment"><summary></span> | |||
/// Gets or sets the object (the target) referenced by the | |||
/// current WeakReference{T} object. | |||
/// <span class="code-SummaryComment"></summary></span> | |||
public new T Target | |||
{ | |||
get | |||
{ | |||
return (T)base.Target; | |||
} | |||
set | |||
{ | |||
base.Target = value; | |||
} | |||
} | |||
/// <span class="code-SummaryComment"><summary></span> | |||
/// Initializes a new instance of the WeakReference{T} class, referencing | |||
/// the specified object. | |||
/// <span class="code-SummaryComment"></summary></span> | |||
/// <span class="code-SummaryComment"><param name="target">The object to reference.</param></span> | |||
public WeakReference(T target) | |||
: base(target) | |||
{ } | |||
/// <span class="code-SummaryComment"><summary></span> | |||
/// Initializes a new instance of the WeakReference{T} class, referencing | |||
/// the specified object and using the specified resurrection tracking. | |||
/// <span class="code-SummaryComment"></summary></span> | |||
/// <span class="code-SummaryComment"><param name="target">An object to track.</param></span> | |||
/// <span class="code-SummaryComment"><param name="trackResurrection">Indicates when to stop tracking the object. </span> | |||
/// If true, the object is tracked | |||
/// after finalization; if false, the object is only tracked | |||
/// until finalization.<span class="code-SummaryComment"></param></span> | |||
public WeakReference(T target, bool trackResurrection) | |||
: base(target, trackResurrection) | |||
{ } | |||
} | |||
#else | |||
public class WeakReference<T> : System.WeakReference where T : class | |||
{ | |||
public bool IsValid { get { return Target != null && IsAlive == true; } } | |||
public new T Target | |||
{ | |||
get | |||
{ | |||
return (T)base.Target; | |||
} | |||
set | |||
{ | |||
base.Target = value; | |||
} | |||
} | |||
public WeakReference(T target) | |||
: base(target) | |||
{ } | |||
public WeakReference(T target, bool trackResurrection) | |||
: base(target, trackResurrection) | |||
{ } | |||
} | |||
#endif | |||
} |
@@ -1,109 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public class EngineNodeDB : IEngineNodeDB | |||
{ | |||
internal EngineNodeDB( Dictionary<Type, FasterList<INode>> nodesDB, | |||
Dictionary<Type, Dictionary<int, INode>> nodesDBdic, | |||
Dictionary<Type, FasterList<INode>> metaNodesDB) | |||
{ | |||
_nodesDB = nodesDB; | |||
_nodesDBdic = nodesDBdic; | |||
_metaNodesDB = metaNodesDB; | |||
} | |||
public FasterReadOnlyListCast<INode, T> QueryNodes<T>() where T:INode | |||
{ | |||
var type = typeof(T); | |||
FasterList<INode> nodes; | |||
if (_nodesDB.TryGetValue(type, out nodes) == false) | |||
return RetrieveEmptyNodeList<T>(); | |||
return new FasterReadOnlyListCast<INode, T>(nodes); | |||
} | |||
public ReadOnlyDictionary<int, INode> QueryIndexableNodes<T>() where T:INode | |||
{ | |||
var type = typeof(T); | |||
Dictionary<int, INode> nodes; | |||
if (_nodesDBdic.TryGetValue(type, out nodes) == false) | |||
return _defaultEmptyNodeDict; | |||
return new ReadOnlyDictionary<int, INode>(nodes); | |||
} | |||
public T QueryMetaNode<T>(int metaEntityID) where T : INode | |||
{ | |||
return QueryNode<T>(metaEntityID); | |||
} | |||
public bool TryQueryMetaNode<T>(int metaEntityID, out T node) where T : INode | |||
{ | |||
return TryQueryNode(metaEntityID, out node); | |||
} | |||
public FasterReadOnlyListCast<INode, T> QueryMetaNodes<T>() where T : INode | |||
{ | |||
var type = typeof(T); | |||
FasterList<INode> nodes; | |||
if (_metaNodesDB.TryGetValue(type, out nodes) == false) | |||
return RetrieveEmptyNodeList<T>(); | |||
return new FasterReadOnlyListCast<INode, T>(nodes); | |||
} | |||
public bool TryQueryNode<T>(int ID, out T node) where T:INode | |||
{ | |||
var type = typeof(T); | |||
INode internalNode; | |||
Dictionary<int, INode> nodes; | |||
if (_nodesDBdic.TryGetValue(type, out nodes) && | |||
nodes.TryGetValue(ID, out internalNode)) | |||
{ | |||
node = (T)internalNode; | |||
return true; | |||
} | |||
node = default(T); | |||
return false; | |||
} | |||
public T QueryNode<T>(int ID) where T:INode | |||
{ | |||
var type = typeof(T); | |||
INode internalNode; Dictionary<int, INode> nodes; | |||
if (_nodesDBdic.TryGetValue(type, out nodes) && | |||
nodes.TryGetValue(ID, out internalNode)) | |||
return (T)internalNode; | |||
throw new Exception("Node Not Found"); | |||
} | |||
static FasterReadOnlyListCast<INode, T> RetrieveEmptyNodeList<T>() where T : INode | |||
{ | |||
return FasterReadOnlyListCast<INode, T>.DefaultList; | |||
} | |||
readonly Dictionary<Type, FasterList<INode>> _nodesDB; | |||
readonly Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
readonly Dictionary<Type, FasterList<INode>> _metaNodesDB; | |||
readonly ReadOnlyDictionary<int, INode> _defaultEmptyNodeDict = new ReadOnlyDictionary<int, INode>(new Dictionary<int, INode>()); | |||
} | |||
} |
@@ -1,544 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.NodeSchedulers; | |||
using WeakReference = Svelto.DataStructures.WeakReference<Svelto.ECS.EnginesRoot>; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
#if NETFX_CORE | |||
using System.Reflection; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public sealed class EnginesRoot : IEnginesRoot, IEntityFactory | |||
{ | |||
public EnginesRoot(NodeSubmissionScheduler nodeScheduler) | |||
{ | |||
_nodeEngines = new Dictionary<Type, FasterList<IEngine>>(); | |||
_activableEngines = new Dictionary<Type, FasterList<IEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_engineRootWeakReference = new WeakReference(this); | |||
_nodesDB = new Dictionary<Type, FasterList<INode>>(); | |||
_nodesDBdic = new Dictionary<Type, Dictionary<int, INode>>(); | |||
_nodesToAdd = new FasterList<INode>(); | |||
_metaNodesToAdd = new FasterList<INode>(); | |||
_metaNodesDB = new Dictionary<Type, FasterList<INode>>(); | |||
_sharedStructNodeLists = new SharedStructNodeLists(); | |||
_sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); | |||
_internalRemove = InternalRemove; | |||
_internalDisable = InternalDisable; | |||
_internalEnable = InternalEnable; | |||
_internalMetaRemove = InternalMetaRemove; | |||
_scheduler = nodeScheduler; | |||
_scheduler.Schedule(SubmitNodes); | |||
_structNodeEngineType = typeof(IStructNodeEngine<>); | |||
_groupedStructNodesEngineType = typeof(IGroupedStructNodesEngine<>); | |||
_activableNodeEngineType = typeof(IActivableNodeEngine<>); | |||
_implementedInterfaceTypes = new Dictionary<Type, Type[]>(); | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
#endif | |||
} | |||
void SubmitNodes() | |||
{ | |||
int metaNodesCount = _metaNodesToAdd.Count; | |||
int nodesCount = _nodesToAdd.Count; | |||
if (metaNodesCount + nodesCount == 0) return; | |||
bool newNodesHaveBeenAddedWhileIterating; | |||
int startNodes = 0; | |||
int startMetaNodes = 0; | |||
int numberOfReenteringLoops = 0; | |||
do | |||
{ | |||
var nodesToAdd = _nodesToAdd.ToArrayFast(); | |||
for (int i = startNodes; i < nodesCount; i++) | |||
{ | |||
var node = nodesToAdd[i]; | |||
var nodeType = node.GetType(); | |||
AddNodeToTheDB(node, nodeType); | |||
var nodeWithId = node as INodeWithID; | |||
if (nodeWithId != null) | |||
AddNodeToNodesDictionary(nodeWithId, nodeType); | |||
} | |||
var metaNodesToAdd = _metaNodesToAdd.ToArrayFast(); | |||
for (int i = startMetaNodes; i < metaNodesCount; i++) | |||
{ | |||
var node = metaNodesToAdd[i]; | |||
var nodeType = node.GetType(); | |||
AddNodeToMetaDB(node, nodeType); | |||
var nodeWithId = node as INodeWithID; | |||
if (nodeWithId != null) | |||
AddNodeToNodesDictionary(nodeWithId, nodeType); | |||
} | |||
for (int i = startNodes; i < nodesCount; i++) | |||
{ | |||
var node = nodesToAdd[i]; | |||
AddNodeToTheSuitableEngines(node, node.GetType()); | |||
} | |||
for (int i = startMetaNodes; i < metaNodesCount; i++) | |||
{ | |||
var node = metaNodesToAdd[i]; | |||
AddNodeToTheSuitableEngines(node, node.GetType()); | |||
} | |||
newNodesHaveBeenAddedWhileIterating = | |||
_metaNodesToAdd.Count > metaNodesCount || | |||
_nodesToAdd.Count > nodesCount; | |||
startNodes = nodesCount; | |||
startMetaNodes = metaNodesCount; | |||
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++; | |||
metaNodesCount = _metaNodesToAdd.Count; | |||
nodesCount = _nodesToAdd.Count; | |||
} while (newNodesHaveBeenAddedWhileIterating); | |||
_nodesToAdd.Clear(); | |||
_metaNodesToAdd.Clear(); | |||
} | |||
public void AddEngine(IEngine engine) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.AddEngine(engine); | |||
#endif | |||
var queryableNodeEngine = engine as IQueryableNodeEngine; | |||
if (queryableNodeEngine != null) | |||
queryableNodeEngine.nodesDB = | |||
new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); | |||
var engineType = engine.GetType(); | |||
var implementedInterfaces = engineType.GetInterfaces(); | |||
CollectImplementedInterfaces(implementedInterfaces); | |||
var engineAdded = CheckGenericEngines(engine); | |||
if (CheckLegacyNodesEngine(engine, ref engineAdded) == false) | |||
CheckNodesEngine(engine, engineType, ref engineAdded); | |||
if (engineAdded == false) | |||
_otherEngines.Add(engine); | |||
var callBackOnAddEngine = engine as ICallBackOnAddEngine; | |||
if (callBackOnAddEngine != null) | |||
callBackOnAddEngine.Ready(); | |||
} | |||
void CollectImplementedInterfaces(Type[] implementedInterfaces) | |||
{ | |||
_implementedInterfaceTypes.Clear(); | |||
var type = typeof(IEngine); | |||
for (int index = 0; index < implementedInterfaces.Length; index++) | |||
{ | |||
var interfaceType = implementedInterfaces[index]; | |||
if (type.IsAssignableFrom(interfaceType) == false) | |||
continue; | |||
#if !NETFX_CORE | |||
if (false == interfaceType.IsGenericType) | |||
#else | |||
if (false == interfaceType.IsConstructedGenericType) | |||
#endif | |||
{ | |||
continue; | |||
} | |||
var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); | |||
_implementedInterfaceTypes.Add(genericTypeDefinition, interfaceType.GetGenericArguments()); | |||
} | |||
} | |||
bool CheckGenericEngines(IEngine engine) | |||
{ | |||
if (_implementedInterfaceTypes.Count == 0) return false; | |||
bool engineAdded = false; | |||
if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) | |||
{ | |||
((IStructNodeEngine)engine).CreateStructNodes | |||
(_sharedStructNodeLists); | |||
} | |||
if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) | |||
{ | |||
((IGroupedStructNodesEngine)engine).CreateStructNodes | |||
(_sharedGroupedStructNodeLists); | |||
} | |||
Type[] arguments; | |||
if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, | |||
out arguments)) | |||
{ | |||
AddEngine(engine, arguments, _activableEngines); | |||
engineAdded = true; | |||
} | |||
return engineAdded; | |||
} | |||
bool CheckLegacyNodesEngine(IEngine engine, ref bool engineAdded) | |||
{ | |||
var nodesEngine = engine as INodesEngine; | |||
if (nodesEngine != null) | |||
{ | |||
AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); | |||
engineAdded = true; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool CheckNodesEngine(IEngine engine, Type engineType, ref bool engineAdded) | |||
{ | |||
#if !NETFX_CORE | |||
var baseType = engineType.BaseType; | |||
if (baseType.IsGenericType | |||
#else | |||
var baseType = engineType.GetTypeInfo().BaseType; | |||
if (baseType.IsConstructedGenericType | |||
#endif | |||
&& engine is INodeEngine) | |||
{ | |||
AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); | |||
engineAdded = true; | |||
return true; | |||
} | |||
return false; | |||
} | |||
public void BuildEntity(int ID, EntityDescriptor ed) | |||
{ | |||
var entityNodes = ed.BuildNodes(ID, | |||
_internalRemove, | |||
_internalEnable, | |||
_internalDisable | |||
); | |||
_nodesToAdd.AddRange(entityNodes); | |||
} | |||
/// <summary> | |||
/// A meta entity is a way to manage a set of entitites that are not easily | |||
/// queriable otherwise. For example you may want to group existing entities | |||
/// by size and type and then use the meta entity node to manage the data | |||
/// shared among the single entities of the same type and size. This will | |||
/// prevent the scenario where the coder is forced to parse all the entities to | |||
/// find the ones of the same size and type. | |||
/// Since the entities are managed through the shared node, the same | |||
/// shared node must be found on the single entities of the same type and size. | |||
/// The shared node of the meta entity is then used by engines that are meant | |||
/// to manage a group of entities through a single node. | |||
/// The same engine can manage several meta entities nodes too. | |||
/// The Engine manages the logic of the Meta Node data and other engines | |||
/// can read back this data through the normal entity as the shared node | |||
/// will be present in their descriptor too. | |||
/// </summary> | |||
/// <param name="metaEntityID"></param> | |||
/// <param name="ed"></param> | |||
public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) | |||
{ | |||
var entityNodes = ed.BuildNodes(metaEntityID, | |||
_internalMetaRemove, | |||
_internalEnable, | |||
_internalDisable | |||
); | |||
_metaNodesToAdd.AddRange(entityNodes); | |||
} | |||
/// <summary> | |||
/// Using this function is like building a normal entity, but the nodes | |||
/// are grouped by groupID to be better processed inside engines and | |||
/// improve cache locality. Only IGroupStructNodeWithID nodes are grouped | |||
/// other nodes are managed as usual. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
public void BuildEntityInGroup(int entityID, int groupID, | |||
EntityDescriptor ed) | |||
{ | |||
var entityNodes = ed.BuildNodes(entityID, | |||
_internalRemove, | |||
_internalEnable, | |||
_internalDisable | |||
); | |||
_nodesToAdd.AddRange(entityNodes); | |||
for (int i = 0; i < entityNodes.Count; i++) | |||
{ | |||
var groupNode = entityNodes[i] as IGroupedStructNodeWithID; | |||
if (groupNode != null) | |||
groupNode.groupID = groupID; | |||
} | |||
} | |||
static void AddEngine(IEngine engine, Type[] types, | |||
Dictionary<Type, FasterList<IEngine>> engines) | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
FasterList<IEngine> list; | |||
var type = types[i]; | |||
if (engines.TryGetValue(type, out list) == false) | |||
{ | |||
list = new FasterList<IEngine>(); | |||
engines.Add(type, list); | |||
} | |||
list.Add(engine); | |||
} | |||
} | |||
void AddNodeToMetaDB(INode node, Type nodeType) | |||
{ | |||
FasterList<INode> nodes; | |||
if (_metaNodesDB.TryGetValue(nodeType, out nodes) == false) | |||
nodes = _metaNodesDB[nodeType] = new FasterList<INode>(); | |||
nodes.Add(node); | |||
} | |||
void AddNodeToTheDB<T>(T node, Type nodeType) where T : INode | |||
{ | |||
FasterList<INode> nodes; | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == false) | |||
nodes = _nodesDB[nodeType] = new FasterList<INode>(); | |||
nodes.Add(node); | |||
} | |||
void AddNodeToNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID | |||
{ | |||
Dictionary<int, INode> nodesDic; | |||
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) | |||
nodesDic = _nodesDBdic[nodeType] = new Dictionary<int, INode>(); | |||
nodesDic.Add(node.ID, node); | |||
} | |||
void AddNodeToTheSuitableEngines(INode node, Type nodeType) | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorAddDuration(enginesForNode[j] as INodeEngine, node); | |||
#else | |||
(enginesForNode[j] as INodeEngine).Add(node); | |||
#endif | |||
} | |||
} | |||
} | |||
void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode | |||
{ | |||
FasterList<INode> nodes; | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == true) | |||
nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? | |||
} | |||
void RemoveNodeFromMetaDB<T>(T node, Type nodeType) where T : INode | |||
{ | |||
FasterList<INode> nodes; | |||
if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true) | |||
nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? | |||
} | |||
void RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID | |||
{ | |||
Dictionary<int, INode> nodesDic; | |||
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) | |||
nodesDic.Remove(node.ID); | |||
} | |||
void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration((enginesForNode[j] as INodeEngine), node); | |||
#else | |||
(enginesForNode[j] as INodeEngine).Remove(node); | |||
#endif | |||
} | |||
} | |||
} | |||
void DisableNodeFromEngines(INode node, Type nodeType) | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
(enginesForNode[j] as IActivableNodeEngine).Disable(node); | |||
} | |||
} | |||
} | |||
void EnableNodeFromEngines(INode node, Type nodeType) | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
(enginesForNode[j] as IActivableNodeEngine).Enable(node); | |||
} | |||
} | |||
} | |||
void InternalDisable(FasterList<INode> nodes) | |||
{ | |||
if (_engineRootWeakReference.IsValid == false) | |||
return; | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
var node = nodes[i]; | |||
Type nodeType = node.GetType(); | |||
DisableNodeFromEngines(node, nodeType); | |||
} | |||
} | |||
void InternalEnable(FasterList<INode> nodes) | |||
{ | |||
if (_engineRootWeakReference.IsValid == false) | |||
return; | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
var node = nodes[i]; | |||
Type nodeType = node.GetType(); | |||
EnableNodeFromEngines(node, nodeType); | |||
} | |||
} | |||
void InternalRemove(FasterList<INode> nodes) | |||
{ | |||
if (_engineRootWeakReference.IsValid == false) | |||
return; | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
var node = nodes[i]; | |||
Type nodeType = node.GetType(); | |||
RemoveNodeFromEngines(node, nodeType); | |||
RemoveNodeFromTheDB(node, node.GetType()); | |||
var nodeWithId = node as INodeWithID; | |||
if (nodeWithId != null) | |||
RemoveNodeFromNodesDictionary(nodeWithId, nodeType); | |||
} | |||
} | |||
void InternalMetaRemove(FasterList<INode> nodes) | |||
{ | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
var node = nodes[i]; | |||
Type nodeType = node.GetType(); | |||
RemoveNodeFromEngines(node, nodeType); | |||
RemoveNodeFromMetaDB(node, nodeType); | |||
var nodeWithId = node as INodeWithID; | |||
if (nodeWithId != null) | |||
RemoveNodeFromNodesDictionary(nodeWithId, nodeType); | |||
} | |||
} | |||
readonly Dictionary<Type, FasterList<IEngine>> _nodeEngines; | |||
readonly Dictionary<Type, FasterList<IEngine>> _activableEngines; | |||
readonly FasterList<IEngine> _otherEngines; | |||
readonly Dictionary<Type, FasterList<INode>> _nodesDB; | |||
readonly Dictionary<Type, FasterList<INode>> _metaNodesDB; | |||
readonly Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
readonly FasterList<INode> _nodesToAdd; | |||
readonly FasterList<INode> _metaNodesToAdd; | |||
readonly WeakReference _engineRootWeakReference; | |||
readonly SharedStructNodeLists _sharedStructNodeLists; | |||
readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; | |||
readonly NodeSubmissionScheduler _scheduler; | |||
readonly Action<FasterList<INode>> _internalRemove; | |||
readonly Action<FasterList<INode>> _internalEnable; | |||
readonly Action<FasterList<INode>> _internalDisable; | |||
readonly Action<FasterList<INode>> _internalMetaRemove; | |||
readonly Type _structNodeEngineType; | |||
readonly Type _groupedStructNodesEngineType; | |||
readonly Type _activableNodeEngineType; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
} | |||
} | |||
@@ -1,196 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Svelto.DataStructures; | |||
#if NETFX_CORE | |||
using BindingFlags = System.Reflection.BindingFlags; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public class EntityDescriptor | |||
{ | |||
protected EntityDescriptor() | |||
{ | |||
} | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild) | |||
{ | |||
_nodesToBuild = new FasterList<INodeBuilder>(nodesToBuild); | |||
} | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor):this(nodesToBuild) | |||
{ | |||
ProcessImplementors(componentsImplementor); | |||
} | |||
public void AddImplementors(params object[] componentsImplementor) | |||
{ | |||
ProcessImplementors(componentsImplementor); | |||
} | |||
void ProcessImplementors(object[] implementors) | |||
{ | |||
for (int index = 0; index < implementors.Length; index++) | |||
{ | |||
var implementor = implementors[index]; | |||
if (implementor == null) | |||
{ | |||
Utility.Console.LogWarning( | |||
"Null implementor, are you using a wild GetComponents<Monobehaviour> to fetch it? " | |||
.FastConcat(ToString())); | |||
} | |||
else | |||
{ | |||
if (implementor is IRemoveEntityComponent) | |||
_removingImplementors.Add(implementor as IRemoveEntityComponent); | |||
if (implementor is IDisableEntityComponent) | |||
_disablingImplementors.Add(implementor as IDisableEntityComponent); | |||
if (implementor is IEnableEntityComponent) | |||
_enablingImplementors.Add(implementor as IEnableEntityComponent); | |||
var interfaces = implementor.GetType().GetInterfaces(); | |||
for (int iindex = 0; iindex < interfaces.Length; iindex++) | |||
{ | |||
_implementorsByType[interfaces[iindex]] = implementor; | |||
} | |||
} | |||
} | |||
} | |||
public void AddNodes(params INodeBuilder[] nodesWithID) | |||
{ | |||
_nodesToBuild.AddRange(nodesWithID); | |||
} | |||
public virtual FasterList<INode> BuildNodes(int ID) | |||
{ | |||
var nodes = new FasterList<INode>(); | |||
for (int index = 0; index < _nodesToBuild.Count; index++) | |||
{ | |||
var nodeBuilder = _nodesToBuild[index]; | |||
var node = nodeBuilder.Build(ID); | |||
if (nodeBuilder.reflects != FillNodeMode.None) | |||
node = FillNode(node, nodeBuilder.reflects); | |||
nodes.Add(node); | |||
} | |||
return nodes; | |||
} | |||
internal FasterList<INode> BuildNodes(int ID, | |||
Action<FasterList<INode>> removeEntity, | |||
Action<FasterList<INode>> enableEntity, | |||
Action<FasterList<INode>> disableEntity) | |||
{ | |||
var nodes = BuildNodes(ID); | |||
SetupImplementors(removeEntity, enableEntity, disableEntity, nodes); | |||
return nodes; | |||
} | |||
void SetupImplementors( | |||
Action<FasterList<INode>> removeEntity, | |||
Action<FasterList<INode>> enableEntity, | |||
Action<FasterList<INode>> disableEntity, | |||
FasterList<INode> nodes) | |||
{ | |||
Action removeEntityAction = () => { removeEntity(nodes); nodes.Clear(); }; | |||
Action disableEntityAction = () => disableEntity(nodes); | |||
Action enableEntityAction = () => enableEntity(nodes); | |||
for (int index = 0; index < _removingImplementors.Count; index++) | |||
_removingImplementors[index].removeEntity = removeEntityAction; | |||
for (int index = 0; index < _disablingImplementors.Count; index++) | |||
_disablingImplementors[index].disableEntity = disableEntityAction; | |||
for (int index = 0; index < _enablingImplementors.Count; index++) | |||
_enablingImplementors[index].enableEntity = enableEntityAction; | |||
} | |||
TNode FillNode<TNode>(TNode node, FillNodeMode mode) where TNode : INode | |||
{ | |||
var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
Type fieldType = field.FieldType; | |||
object component; | |||
if ((_implementorsByType.TryGetValue(fieldType, out component)) == false) | |||
{ | |||
if (mode == FillNodeMode.Strict) | |||
{ | |||
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; | |||
} | |||
} | |||
else | |||
field.SetValue(node, component); | |||
} | |||
return node; | |||
} | |||
readonly FasterList<IDisableEntityComponent> _disablingImplementors = new FasterList<IDisableEntityComponent>(); | |||
readonly FasterList<IRemoveEntityComponent> _removingImplementors = new FasterList<IRemoveEntityComponent>(); | |||
readonly FasterList<IEnableEntityComponent> _enablingImplementors = new FasterList<IEnableEntityComponent>(); | |||
readonly Dictionary<Type, object> _implementorsByType = new Dictionary<Type, object>(); | |||
readonly FasterList<INodeBuilder> _nodesToBuild; | |||
} | |||
public interface INodeBuilder | |||
{ | |||
INode Build(int ID); | |||
FillNodeMode reflects { get; } | |||
} | |||
public class NodeBuilder<NodeType> : INodeBuilder where NodeType : NodeWithID, new() | |||
{ | |||
public INode Build(int ID) | |||
{ | |||
NodeWithID node = NodeWithID.BuildNode<NodeType>(ID); | |||
return (NodeType)node; | |||
} | |||
public FillNodeMode reflects { get { return FillNodeMode.Strict; } } | |||
} | |||
public class StructNodeBuilder<NodeType> : INodeBuilder | |||
where NodeType : struct, IStructNodeWithID | |||
{ | |||
public INode Build(int ID) | |||
{ | |||
var shortID = (short)ID; | |||
IStructNodeWithID node = default(NodeType); | |||
node.ID = shortID; | |||
return node; | |||
} | |||
public virtual FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } | |||
} | |||
public class FastStructNodeBuilder<NodeType> : StructNodeBuilder<NodeType> | |||
where NodeType : struct, IStructNodeWithID | |||
{ | |||
public override FillNodeMode reflects { get { return FillNodeMode.None; } } | |||
} | |||
public enum FillNodeMode | |||
{ | |||
Strict, | |||
Relaxed, | |||
None | |||
} | |||
} |
@@ -1,41 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using System; | |||
using System.Collections; | |||
using UnityEngine; | |||
namespace Svelto.ECS.NodeSchedulers | |||
{ | |||
public class UnitySumbmissionNodeScheduler : NodeSubmissionScheduler | |||
{ | |||
public UnitySumbmissionNodeScheduler() | |||
{ | |||
GameObject go = new GameObject("ECSScheduler"); | |||
_scheduler = go.AddComponent<Scheduler>(); | |||
} | |||
public override void Schedule(Action submitNodes) | |||
{ | |||
_scheduler.OnTick += submitNodes; | |||
} | |||
class Scheduler : MonoBehaviour | |||
{ | |||
IEnumerator Start() | |||
{ | |||
while (true) | |||
{ | |||
yield return _wait; | |||
OnTick(); | |||
} | |||
} | |||
internal Action OnTick; | |||
WaitForEndOfFrame _wait = new WaitForEndOfFrame(); | |||
} | |||
Scheduler _scheduler; | |||
} | |||
} | |||
#endif |
@@ -1,239 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public 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 readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public 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 readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public 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 readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public 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 readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public 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 readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public 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 readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public class GenericMixedEntityDescriptor<T> : EntityDescriptor | |||
where T : INodeBuilder, new() | |||
{ | |||
static GenericMixedEntityDescriptor() | |||
{ | |||
_nodesToBuild = new INodeBuilder[] | |||
{ | |||
new T(), | |||
}; | |||
} | |||
public GenericMixedEntityDescriptor(params object[] componentsImplementor) : | |||
base(_nodesToBuild, componentsImplementor) | |||
{ } | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public class GenericMixedEntityDescriptor<T, U, V> : EntityDescriptor | |||
where T : INodeBuilder, new() | |||
where U : INodeBuilder, new() | |||
where V : INodeBuilder, new() | |||
{ | |||
static GenericMixedEntityDescriptor() | |||
{ | |||
_nodesToBuild = new INodeBuilder[] | |||
{ | |||
new T(), | |||
new U(), | |||
new V() | |||
}; | |||
} | |||
public GenericMixedEntityDescriptor(params object[] componentsImplementor) : | |||
base(_nodesToBuild, componentsImplementor) | |||
{ } | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public class GenericMixedEntityDescriptor<T, U, V, W> : EntityDescriptor | |||
where T : INodeBuilder, new() | |||
where U : INodeBuilder, new() | |||
where V : INodeBuilder, new() | |||
where W : INodeBuilder, new() | |||
{ | |||
static GenericMixedEntityDescriptor() | |||
{ | |||
_nodesToBuild = new INodeBuilder[] | |||
{ | |||
new T(), | |||
new U(), | |||
new V(), | |||
new W() | |||
}; | |||
} | |||
public GenericMixedEntityDescriptor(params object[] componentsImplementor) : | |||
base(_nodesToBuild, componentsImplementor) | |||
{ } | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public class GenericMixedEntityDescriptor<T, U, V, W, X> : EntityDescriptor | |||
where T : INodeBuilder, new() | |||
where U : INodeBuilder, new() | |||
where V : INodeBuilder, new() | |||
where W : INodeBuilder, new() | |||
where X : INodeBuilder, new() | |||
{ | |||
static GenericMixedEntityDescriptor() | |||
{ | |||
_nodesToBuild = new INodeBuilder[] | |||
{ | |||
new T(), | |||
new U(), | |||
new V(), | |||
new W(), | |||
new X() | |||
}; | |||
} | |||
public GenericMixedEntityDescriptor(params object[] componentsImplementor) : | |||
base(_nodesToBuild, componentsImplementor) | |||
{ } | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
public class GenericMixedEntityDescriptor<T, U, V, W, X, Y> : EntityDescriptor | |||
where T : INodeBuilder, new() | |||
where U : INodeBuilder, new() | |||
where V : INodeBuilder, new() | |||
where W : INodeBuilder, new() | |||
where X : INodeBuilder, new() | |||
where Y : INodeBuilder, new() | |||
{ | |||
static GenericMixedEntityDescriptor() | |||
{ | |||
_nodesToBuild = new INodeBuilder[] | |||
{ | |||
new T(), | |||
new U(), | |||
new V(), | |||
new W(), | |||
new X(), | |||
new Y() | |||
}; | |||
} | |||
public GenericMixedEntityDescriptor(params object[] componentsImplementor) : | |||
base(_nodesToBuild, componentsImplementor) | |||
{ } | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
} |
@@ -1,30 +0,0 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public class GenericEntityDescriptorHolder<T, I>: UnityEngine.MonoBehaviour, IEntityDescriptorHolder where T:EntityDescriptor | |||
{ | |||
public EntityDescriptor BuildDescriptorType(object[] externalImplentors) | |||
{ | |||
I[] implementors; | |||
if (externalImplentors != null) | |||
{ | |||
I[] baseImplentors = gameObject.GetComponents<I>(); | |||
implementors = new I[externalImplentors.Length + baseImplentors.Length]; | |||
Array.Copy(baseImplentors, implementors, baseImplentors.Length); | |||
Array.Copy(externalImplentors, 0, implementors, baseImplentors.Length, externalImplentors.Length); | |||
} | |||
else | |||
{ | |||
implementors = gameObject.GetComponents<I>(); | |||
} | |||
return (T)Activator.CreateInstance(typeof(T), implementors); | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,7 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface ICallBackOnAddEngine | |||
{ | |||
void Ready(); | |||
} | |||
} |
@@ -1,62 +0,0 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface IStructNodeEngine : IEngine | |||
{ | |||
void CreateStructNodes(SharedStructNodeLists sharedStructNodeLists); | |||
} | |||
public interface IGroupedStructNodesEngine : IEngine | |||
{ | |||
void CreateStructNodes(SharedGroupedStructNodesLists sharedStructNodeLists); | |||
} | |||
public interface IActivableNodeEngine : IEngine | |||
{ | |||
void Enable(INode obj); | |||
void Disable(INode obj); | |||
} | |||
public interface INodeEngine : IEngine | |||
{ | |||
void Add(INode obj); | |||
void Remove(INode obj); | |||
} | |||
public interface INodesEngine : INodeEngine | |||
{ | |||
System.Type[] AcceptedNodes(); | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngine | |||
{} | |||
public interface IActivableNodeEngine<in TNodeType> : IActivableNodeEngine where TNodeType : INode | |||
{ } | |||
public interface IQueryableNodeEngine:IEngine | |||
{ | |||
IEngineNodeDB nodesDB { set; } | |||
} | |||
/// <summary> | |||
/// The engines can receive and store INodes structs | |||
/// Unboxing will happen during the Add, but the | |||
/// data will then be stored and processed as stucts | |||
/// </summary> | |||
public interface IStructNodeEngine<T> : IStructNodeEngine where T:struct, IStructNodeWithID | |||
{ } | |||
/// <summary> | |||
/// same as above, but the nodes are grouped by ID | |||
/// usually the ID is the owner of the nodes of that | |||
/// group | |||
/// </summary> | |||
public interface IGroupedStructNodesEngine<T> : IGroupedStructNodesEngine where T:struct, IGroupedStructNodeWithID | |||
{ } | |||
} | |||
@@ -1,19 +0,0 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngineNodeDB | |||
{ | |||
ReadOnlyDictionary<int, INode> QueryIndexableNodes<T>() where T:INode; | |||
bool TryQueryNode<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 TryQueryMetaNode<T>(int metaEntityID, out T node) where T : INode; | |||
T QueryMetaNode<T>(int metaEntityID) where T : INode; | |||
FasterReadOnlyListCast<INode, T> QueryMetaNodes<T>() where T : INode; | |||
} | |||
} | |||
@@ -1,16 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEnginesRoot | |||
{ | |||
void AddEngine(IEngine engine); | |||
} | |||
public interface IEntityFactory | |||
{ | |||
void BuildEntity(int ID, EntityDescriptor ED); | |||
void BuildMetaEntity(int metaEntityID, EntityDescriptor ED); | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ED); | |||
} | |||
} |
@@ -1,11 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
/// <summary> | |||
/// please use [DisallowMultipleComponent] in your monobehaviours that implement IEntityDescriptorHolder | |||
/// </summary> | |||
public interface IEntityDescriptorHolder | |||
{ | |||
//I must find a nicer solution for the extraImplentors | |||
EntityDescriptor BuildDescriptorType(object[] extraImplentors = null); | |||
} | |||
} |
@@ -1,32 +0,0 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface INode | |||
{} | |||
public interface INodeWithID:INode | |||
{ | |||
int ID { get; } | |||
} | |||
public interface IStructNodeWithID : INode | |||
{ | |||
int ID { get; set; } | |||
} | |||
public interface IGroupedStructNodeWithID : IStructNodeWithID | |||
{ | |||
int groupID { get; set; } | |||
} | |||
public class NodeWithID: INodeWithID | |||
{ | |||
public static TNodeType BuildNode<TNodeType>(int ID) where TNodeType: NodeWithID, new() | |||
{ | |||
return new TNodeType { _ID = ID }; | |||
} | |||
public int ID { get { return _ID; } } | |||
protected int _ID; | |||
} | |||
} |
@@ -1,19 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IRemoveEntityComponent | |||
{ | |||
Action removeEntity { get; set; } | |||
} | |||
public interface IDisableEntityComponent | |||
{ | |||
Action disableEntity { get; set; } | |||
} | |||
public interface IEnableEntityComponent | |||
{ | |||
Action enableEntity { get; set; } | |||
} | |||
} |
@@ -1,47 +0,0 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public abstract class MultiNodesEngine<T> | |||
where T : INode | |||
{ | |||
protected abstract void AddNode(T node); | |||
protected abstract void RemoveNode(T node); | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class MultiNodesEngine : INodesEngine | |||
{ | |||
public abstract System.Type[] AcceptedNodes(); | |||
public abstract void Add(INode node); | |||
public abstract void Remove(INode node); | |||
} | |||
public abstract class MultiNodesEngine<T, U> : MultiNodesEngine<T>, | |||
INodeEngine | |||
where T : INode | |||
where U : INode | |||
{ | |||
protected abstract void AddNode(U node); | |||
protected abstract void RemoveNode(U node); | |||
public void Add(INode node) | |||
{ | |||
if (node is T) | |||
AddNode((T)node); | |||
else | |||
AddNode((U)node); | |||
} | |||
public void Remove(INode node) | |||
{ | |||
if (node is T) | |||
RemoveNode((T)node); | |||
else | |||
RemoveNode((U)node); | |||
} | |||
} | |||
} |
@@ -1,9 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS.NodeSchedulers | |||
{ | |||
public abstract class NodeSubmissionScheduler | |||
{ | |||
abstract public void Schedule(Action submitNodes); | |||
} | |||
} |
@@ -1,21 +0,0 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class SingleNodeEngine<TNodeType> : INodeEngine | |||
where TNodeType : INode | |||
{ | |||
public void Add(INode obj) | |||
{ | |||
Add((TNodeType) obj); | |||
} | |||
public void Remove(INode obj) | |||
{ | |||
Remove((TNodeType) obj); | |||
} | |||
protected abstract void Add(TNodeType node); | |||
protected abstract void Remove(TNodeType node); | |||
} | |||
} |
@@ -1,134 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public class StructNodes<T> where T:struct, IStructNodeWithID | |||
{ | |||
public T[] GetList(out int numberOfItems) | |||
{ | |||
numberOfItems = _internalList.Count; | |||
return _internalList.ToArrayFast(); | |||
} | |||
public StructNodes(SharedStructNodeLists container) | |||
{ | |||
_internalList = container.GetList<T>(); | |||
} | |||
public void Add(T node) | |||
{ | |||
T convert = (T)node; | |||
_internalList.Add(convert); | |||
} | |||
readonly FasterList<T> _internalList; | |||
} | |||
public class StructGroupNodes<T> | |||
where T : struct, IGroupedStructNodeWithID | |||
{ | |||
public StructGroupNodes(SharedGroupedStructNodesLists container) | |||
{ | |||
_container = container; | |||
} | |||
public void Add(int groupID, T node) | |||
{ | |||
T convert = (T)node; | |||
var fasterList = (_container.GetList<T>(groupID) as FasterList<T>); | |||
indices[node.ID] = fasterList.Count; | |||
fasterList.Add(convert); | |||
} | |||
public void Remove(int groupID, T node) | |||
{ | |||
var fasterList = (_container.GetList<T>(groupID) as FasterList<T>); | |||
var index = indices[node.ID]; | |||
indices.Remove(node.ID); | |||
if (fasterList.UnorderedRemoveAt(index)) | |||
indices[fasterList[index].ID] = index; | |||
} | |||
public T[] GetList(int groupID, out int numberOfItems) | |||
{ | |||
var fasterList = (_container.GetList<T>(groupID) as FasterList<T>); | |||
numberOfItems = fasterList.Count; | |||
return fasterList.ToArrayFast(); | |||
} | |||
readonly SharedGroupedStructNodesLists _container; | |||
readonly Dictionary<int, int> indices = new Dictionary<int, int>(); | |||
} | |||
public class SharedStructNodeLists | |||
{ | |||
readonly Dictionary<Type, IFasterList> _collection; | |||
internal SharedStructNodeLists() | |||
{ | |||
_collection = new Dictionary<Type, IFasterList>(); | |||
} | |||
internal FasterList<T> GetList<T>() where T:struct | |||
{ | |||
IFasterList list; | |||
if (_collection.TryGetValue(typeof (T), out list)) | |||
{ | |||
return list as FasterList<T>; | |||
} | |||
list = new FasterList<T>(); | |||
_collection.Add(typeof (T), list); | |||
return (FasterList<T>) list; | |||
} | |||
} | |||
public class SharedGroupedStructNodesLists | |||
{ | |||
internal SharedGroupedStructNodesLists() | |||
{ | |||
_collection = new Dictionary<Type, Dictionary<int, IFasterList>>(); | |||
} | |||
internal IFasterList GetList<T>(int groupID) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic = GetGroup<T>(); | |||
IFasterList localList; | |||
if (dic.TryGetValue(groupID, out localList)) | |||
return localList; | |||
localList = new FasterList<T>(); | |||
dic.Add(groupID, localList); | |||
return localList; | |||
} | |||
internal Dictionary<int, IFasterList> GetGroup<T>() where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic; | |||
if (_collection.TryGetValue(typeof(T), out dic)) | |||
{ | |||
return dic; | |||
} | |||
dic = new Dictionary<int, IFasterList>(); | |||
_collection.Add(typeof(T), dic); | |||
return dic; | |||
} | |||
readonly Dictionary<Type, Dictionary<int, IFasterList>> _collection; | |||
} | |||
} |
@@ -1,111 +0,0 @@ | |||
systems do not hold component data, but only system states | |||
systems cannot be injected | |||
systems are SRP and OCP | |||
systems communicates between component, mediators, producer/consumer, observers. producer/consumer and observers must be defined in the layer of the engine. | |||
systems can have injected dependencies | |||
components don't have logic | |||
components can have only getter and setter | |||
components cannot define patterns that requires logic. | |||
components cannot issues commands | |||
High Cohesion[edit] | |||
Main article: Cohesion (computer science) | |||
High Cohesion is an evaluative pattern that attempts to keep objects appropriately focused, manageable and understandable. High cohesion is generally used in support of Low Coupling. High cohesion means that the responsibilities of a given element are strongly related and highly focused. Breaking programs into classes and subsystems is an example of activities that increase the cohesive properties of a system. Alternatively, low cohesion is a situation in which a given element has too many unrelated responsibilities. Elements with low cohesion often suffer from being hard to comprehend, hard to reuse, hard to maintain and averse to change.[3] | |||
Low Coupling[edit] | |||
Main article: Loose coupling | |||
Low Coupling is an evaluative pattern, which dictates how to assign responsibilities to support: | |||
lower dependency between the classes, | |||
change in one class having lower impact on other classes, | |||
higher reuse potential. | |||
events, observers and mediators have the inconvience to hold the reference to the engine, which forces to use cleanup if the engine must be removed. | |||
Observers are easy to clean up from the engine. Mediators needs to be integrated to the framework to be simple to clean up. Component events need the clean up function. | |||
producer/consumer has the inconvienent to force check the number of jobs available everyframe | |||
Engine can't be removed, they can only be disabled, but the logic of disabling must be handled by the engine itself | |||
Should components have just one element? Should engines use just nodes? Components are ditacted by the entities and Nodes by the engines | |||
http://thelinuxlich.github.io/artemis_CSharp/ | |||
differences: components no events, everthing must be update | |||
give more responsabiltiy to the user, semplicity | |||
https://github.com/sschmid/Entitas-CSharp/wiki/Overview | |||
no groups, no queries | |||
http://entity-systems.wikidot.com/es-articles | |||
http://www.ashframework.org/ | |||
it's very important to give a namespace to the engines. In this way it's impossible to create semantically wrong nodes (PlayerNode Vs TargetNode) | |||
ToDo: | |||
it's not safe to remove an engine without having called being denitialised internal states. A special ClearOnRemove function must be added for each engine | |||
namespace GameFramework.RayCast | |||
{ | |||
public class RayCastEngineEngine | |||
{ | |||
public RayCastEngine(RayCastEmployer jobList) | |||
{ | |||
jobList.onJobassigned += OnRaycastRequested; | |||
} | |||
public void Add(IComponent obj) | |||
{} | |||
public void Remove(IComponent obj) | |||
{} | |||
void OnRaycastRequested(RayCastJob job) | |||
{ | |||
RaycastHit shootHit; | |||
Physics.Raycast(job.rayVector, out shootHit, job.range, _enemyMask); | |||
job.Done(shootHit); | |||
} | |||
RayCastEmployer _employer; | |||
int _enemyMask; | |||
} | |||
public struct RayCastJob | |||
{ | |||
readonly public Ray rayVector; | |||
readonly public float range; | |||
readonly public Action<RaycastHit> Done; | |||
public RayCastJob(Ray direction, float distance, Action<RaycastHit> OnDone) | |||
{ | |||
rayVector = direction; | |||
range = distance; | |||
Done = OnDone; | |||
} | |||
} | |||
public class RayCastEmployer | |||
{ | |||
public event Action<RayCastJob> onJobassigned; | |||
public void AssignJob(RayCastJob data, Action<RaycastHit> onJobdone) | |||
{ | |||
onJobassigned(data); | |||
} | |||
} | |||
} | |||
if your code can be read as | |||
A tells B to do something is direct | |||
A register B event is indirect | |||
althoggh if B tells A something through event is direct again. B must say something like I don't know who you are, but this just happened. you say B.SomethingHappenedToMe() not B.YouMustDoThis(); | |||
un engine non deve mai avere concetti di un altro engine. dire all'engine sonoro suona morte � sbagliato. � l'engine death che triggera l'evento e l'engine sound ad ascoltarlo. |
@@ -0,0 +1 @@ | |||
Subproject commit 9fd29eaa5a2dd50a248112c045ae7691cab20a44 |
@@ -0,0 +1,4 @@ | |||
/EntitySystem/note.txt | |||
/EntitySystem/note.txt.meta | |||
/*.meta | |||
*.meta |
@@ -2,7 +2,6 @@ | |||
#region | |||
using System; | |||
using Svelto.DataStructures; | |||
using UnityEngine; | |||
#endregion |
@@ -0,0 +1,11 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
namespace Svelto.Context | |||
{ | |||
public interface IUnityCompositionRoot | |||
{ | |||
void OnContextCreated(UnityContext contextHolder); | |||
void OnContextInitialized(); | |||
void OnContextDestroyed(); | |||
} | |||
} | |||
#endif |
@@ -1,5 +1,3 @@ | |||
using System; | |||
namespace Svelto.Context | |||
{ | |||
public interface IWaitForFrameworkDestruction |
@@ -1,5 +1,3 @@ | |||
using System; | |||
namespace Svelto.Context | |||
{ | |||
public interface IWaitForFrameworkInitialization |
@@ -13,6 +13,11 @@ public abstract class UnityContext:MonoBehaviour | |||
} | |||
} | |||
//a Unity context is a platform specific context wrapper. | |||
//Unity will drive the ICompositionRoot interface. | |||
//OnContextCreated is called during the Awake of this MB | |||
//OnContextInitialized is called one frame after the MB started | |||
//OnContextDestroyed is called when the MB is destroyed | |||
public class UnityContext<T>: UnityContext where T:class, ICompositionRoot, new() | |||
{ | |||
protected override void OnAwake() |
@@ -0,0 +1,51 @@ | |||
using Svelto.DataStructures; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
/// <summary> | |||
/// This is just a place holder at the moment | |||
/// I always wanted to create my own Dictionary | |||
/// data structure as excercise, but never had the | |||
/// time to. At the moment I need the custom interface | |||
/// wrapped though. | |||
/// </summary> | |||
public interface ITypeSafeDictionary | |||
{ | |||
void FillWithIndexedEntityViews(ITypeSafeList entityViews); | |||
bool Remove(int entityId); | |||
IEntityView GetIndexedEntityView(int entityID); | |||
} | |||
class TypeSafeDictionary<TValue> : Dictionary<int, TValue>, ITypeSafeDictionary where TValue:IEntityView | |||
{ | |||
internal static readonly ReadOnlyDictionary<int, TValue> Default = | |||
new ReadOnlyDictionary<int, TValue>(new Dictionary<int, TValue>()); | |||
public void FillWithIndexedEntityViews(ITypeSafeList entityViews) | |||
{ | |||
int count; | |||
var buffer = FasterList<TValue>.NoVirt.ToArrayFast((FasterList<TValue>) entityViews, out count); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var entityView = buffer[i]; | |||
Add(entityView.ID, entityView); | |||
} | |||
} | |||
new public bool Remove(int entityId) | |||
{ | |||
base.Remove(entityId); | |||
return this.Count > 0; | |||
} | |||
public IEntityView GetIndexedEntityView(int entityID) | |||
{ | |||
return this[entityID]; | |||
} | |||
} | |||
} |
@@ -0,0 +1,148 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface ITypeSafeList: IEnumerable | |||
{ | |||
void AddRange(ITypeSafeList entityViewListValue); | |||
ITypeSafeList Create(); | |||
bool isQueryiableEntityView { get; } | |||
bool UnorderedRemove(int entityID); | |||
ITypeSafeDictionary CreateIndexedDictionary(); | |||
IEntityView[] ToArrayFast(out int count); | |||
void ReserveCapacity(int capacity); | |||
} | |||
class TypeSafeFasterListForECS<T>: FasterList<T> where T:IEntityView | |||
{ | |||
protected TypeSafeFasterListForECS() | |||
{ | |||
_mappedIndices = new Dictionary<int, int>(); | |||
} | |||
protected TypeSafeFasterListForECS(int size):base(size) | |||
{ | |||
_mappedIndices = new Dictionary<int, int>(); | |||
} | |||
public bool UnorderedRemove(int entityID) | |||
{ | |||
var index = _mappedIndices[entityID]; | |||
DesignByContract.Check.Assert(entityID == this[index].ID, "Something went wrong with the Svelto.ECS code, please contact the author"); | |||
_mappedIndices.Remove(entityID); | |||
if (UnorderedRemoveAt(index)) | |||
_mappedIndices[this[index].ID] = index; | |||
return this.Count > 0; | |||
} | |||
public void AddRange(ITypeSafeList entityViewListValue) | |||
{ | |||
var index = this.Count; | |||
base.AddRange(entityViewListValue as FasterList<T>); | |||
for (int i = index; i < Count; ++i) | |||
_mappedIndices[this[i].ID] = i; | |||
} | |||
new public void Add(T entityView) | |||
{ | |||
var index = this.Count; | |||
base.Add(entityView); | |||
_mappedIndices[entityView.ID] = index; | |||
} | |||
public void ReserveCapacity(int capacity) | |||
{ | |||
if (this.ToArrayFast().Length < capacity) | |||
Resize(capacity); | |||
} | |||
public int GetIndexFromID(int entityID) | |||
{ | |||
return _mappedIndices[entityID]; | |||
} | |||
readonly Dictionary<int, int> _mappedIndices; | |||
} | |||
class TypeSafeFasterListForECSForStructs<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T:struct, IEntityStruct | |||
{ | |||
public TypeSafeFasterListForECSForStructs(int size):base(size) | |||
{} | |||
public TypeSafeFasterListForECSForStructs() | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterListForECSForStructs<T>(); | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return false; } | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
throw new Exception("Not Allowed"); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
{ | |||
throw new Exception("Not Allowed"); | |||
} | |||
public ITypeSafeList Create(int size) | |||
{ | |||
return new TypeSafeFasterListForECSForStructs<T>(size); | |||
} | |||
} | |||
class TypeSafeFasterListForECSForClasses<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T:EntityView, new() | |||
{ | |||
public TypeSafeFasterListForECSForClasses(int size):base(size) | |||
{} | |||
public TypeSafeFasterListForECSForClasses() | |||
{} | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterListForECSForClasses<T>(); | |||
} | |||
public bool isQueryiableEntityView | |||
{ | |||
get { return true; } | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
return new TypeSafeDictionary<T>(); | |||
} | |||
public IEntityView[] ToArrayFast(out int count) | |||
{ | |||
count = this.Count; | |||
return this.ToArrayFast(); | |||
} | |||
public ITypeSafeList Create(int size) | |||
{ | |||
return new TypeSafeFasterListForECSForClasses<T>(size); | |||
} | |||
} | |||
} |
@@ -0,0 +1,143 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Schedulers; | |||
using Svelto.WeakEvents; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <summary> | |||
/// Engines root contextualize your engines and entities. You don't need to limit yourself to one EngineRoot | |||
/// as multiple engines root could promote separation of scopes. The EntitySubmissionScheduler checks | |||
/// periodically if new entity must be submited to the database and the engines. It's an external | |||
/// dependencies to be indipendent by the running platform as the user can define it. | |||
/// The EntitySubmissionScheduler cannot hold an EnginesRoot reference, that's why | |||
/// it must receive a weak reference of the EnginesRoot callback. | |||
/// </summary> | |||
public EnginesRoot(EntitySubmissionScheduler entityViewScheduler) | |||
{ | |||
_entityViewEngines = new Dictionary<Type, FasterList<IHandleEntityViewEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_entityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_metaEntityViewsDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_entityViewsDBDic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_entityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_metaEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedEntityViewsToAdd = new DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_DB = new EntityViewsDB(_entityViewsDB, _entityViewsDBDic, _metaEntityViewsDB, _groupEntityViewsDB); | |||
_scheduler = entityViewScheduler; | |||
_scheduler.Schedule(new WeakAction(SubmitEntityViews)); | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
#endif | |||
} | |||
public void AddEngine(IEngine engine) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
Profiler.EngineProfiler.AddEngine(engine); | |||
#endif | |||
var viewEngine = engine as IHandleEntityViewEngine; | |||
if (viewEngine != null) | |||
CheckEntityViewsEngine(viewEngine); | |||
else | |||
_otherEngines.Add(engine); | |||
var queryableEntityViewEngine = engine as IQueryingEntityViewEngine; | |||
if (queryableEntityViewEngine != null) | |||
{ | |||
queryableEntityViewEngine.entityViewsDB = _DB; | |||
queryableEntityViewEngine.Ready(); | |||
} | |||
} | |||
void CheckEntityViewsEngine(IEngine engine) | |||
{ | |||
var baseType = engine.GetType().GetBaseType(); | |||
while (baseType != _object) | |||
{ | |||
if (baseType.IsGenericTypeEx()) | |||
{ | |||
var genericArguments = baseType.GetGenericArgumentsEx(); | |||
AddEngine(engine as IHandleEntityViewEngine, genericArguments, _entityViewEngines); | |||
return; | |||
} | |||
baseType = baseType.GetBaseType(); | |||
} | |||
throw new ArgumentException("Not Supported Engine " + engine.ToString()); | |||
} | |||
//The T parameter allows to pass datastructure sthat not necessarly are | |||
//defined with IEngine, but must be defined with IEngine implementations | |||
static void AddEngine<T>(T engine, Type[] entityViewTypes, | |||
Dictionary<Type, FasterList<T>> engines) where T:IEngine | |||
{ | |||
for (int i = 0; i < entityViewTypes.Length; i++) | |||
{ | |||
var type = entityViewTypes[i]; | |||
AddEngine(engine, engines, type); | |||
} | |||
} | |||
static void AddEngine<T>(T engine, Dictionary<Type, FasterList<T>> engines, Type type) where T : IEngine | |||
{ | |||
FasterList<T> list; | |||
if (engines.TryGetValue(type, out list) == false) | |||
{ | |||
list = new FasterList<T>(); | |||
engines.Add(type, list); | |||
} | |||
list.Add(engine); | |||
} | |||
readonly Dictionary<Type, FasterList<IHandleEntityViewEngine>> _entityViewEngines; | |||
readonly FasterList<IEngine> _otherEngines; | |||
static readonly Type _entityViewType= typeof(EntityView); | |||
static readonly Type _object = typeof(object); | |||
class DoubleBufferedEntityViews<T> where T : class, IDictionary, new() | |||
{ | |||
readonly T _entityViewsToAddBufferA = new T(); | |||
readonly T _entityViewsToAddBufferB = new T(); | |||
internal DoubleBufferedEntityViews() | |||
{ | |||
this.other = _entityViewsToAddBufferA; | |||
this.current = _entityViewsToAddBufferB; | |||
} | |||
internal T other; | |||
internal T current; | |||
internal void Swap() | |||
{ | |||
var toSwap = other; | |||
other = current; | |||
current = toSwap; | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,411 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
/// <summary> | |||
/// an EnginesRoot reference cannot be held by anything else than the Composition Root | |||
/// where it has been created. IEntityFactory and IEntityFunctions allow a weakreference | |||
/// of the EnginesRoot to be passed around. | |||
/// </summary> | |||
/// <returns></returns> | |||
public IEntityFactory GenerateEntityFactory() | |||
{ | |||
return new GenericEntityFactory(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
public IEntityFunctions GenerateEntityFunctions() | |||
{ | |||
return new GenericEntityFunctions(new DataStructures.WeakReference<EnginesRoot>(this)); | |||
} | |||
/// <summary> | |||
/// The EntityDescriptor doesn't need to be ever instantiated. It just describes the Entity | |||
/// itself in terms of EntityViews to build. The Implementors are passed to fill the | |||
/// references of the EntityViews components. Please read the articles on my blog | |||
/// to understand better the terminologies | |||
/// </summary> | |||
/// <typeparam name="T"></typeparam> | |||
/// <param name="entityID"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
/// <summary> | |||
/// When the type of the entity is not known (this is a special case!) an EntityDescriptorInfo | |||
/// can be built in place of the generic parameter T. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="entityDescriptor"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors) | |||
{ | |||
EntityFactory.BuildEntityViews | |||
(entityID, _entityViewsToAdd.current, entityDescriptor, implementors); | |||
} | |||
/// <summary> | |||
/// A meta entity is a way to manage a set of entitites that are not easily | |||
/// queriable otherwise. For example you may want to group existing entities | |||
/// by size and type and then use the meta entity entityView to manage the data | |||
/// shared among the single entities of the same type and size. This will | |||
/// prevent the scenario where the coder is forced to parse all the entities to | |||
/// find the ones of the same size and type. | |||
/// Since the entities are managed through the shared entityView, the same | |||
/// shared entityView must be found on the single entities of the same type and size. | |||
/// The shared entityView of the meta entity is then used by engines that are meant | |||
/// to manage a group of entities through a single entityView. | |||
/// The same engine can manage several meta entities entityViews too. | |||
/// The Engine manages the logic of the Meta EntityView data and other engines | |||
/// can read back this data through the normal entity as the shared entityView | |||
/// will be present in their descriptor too. | |||
/// It's a way to control a group of Entities through a entityView only. | |||
/// This set of entities can share exactly the same entityView reference if | |||
/// built through this function. In this way, if you need to set a variable | |||
/// on a group of entities, instead to inject N entityViews and iterate over | |||
/// them to set the same value, you can inject just one entityView, set the value | |||
/// and be sure that the value is shared between entities. | |||
/// </summary> | |||
/// <param name="metaEntityID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildMetaEntity<T>(int metaEntityID, object[] implementors) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildEntityViews(metaEntityID, _metaEntityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, implementors); | |||
} | |||
/// <summary> | |||
/// Using this function is like building a normal entity, but the entityViews | |||
/// are grouped by groupID to be more efficently processed inside engines and | |||
/// improve cache locality. Either class entityViews and struct entityViews can be | |||
/// grouped. | |||
/// </summary> | |||
/// <param name="entityID"></param> | |||
/// <param name="groupID"></param> | |||
/// <param name="ed"></param> | |||
/// <param name="implementors"></param> | |||
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
EntityDescriptorTemplate<T>.Default, | |||
implementors); | |||
} | |||
void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
EntityFactory.BuildGroupedEntityViews(entityID, groupID, | |||
_groupedEntityViewsToAdd.current, | |||
entityDescriptor, implementors); | |||
} | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
var entityViewsToBuild = ((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
ITypeSafeList dbList; | |||
if (_entityViewsDB.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsDB[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.ReserveCapacity(size); | |||
if (_entityViewsToAdd.current.TryGetValue(entityViewType, out dbList) == false) | |||
_entityViewsToAdd.current[entityViewType] = entityViewBuilder.Preallocate(ref dbList, size); | |||
else | |||
dbList.ReserveCapacity(size); | |||
} | |||
} | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
var removeEntityImplementor = removeInfo as RemoveEntityImplementor; | |||
if (removeEntityImplementor.isInAGroup) | |||
InternalRemove(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, removeEntityImplementor.groupID, _entityViewsDB); | |||
else | |||
InternalRemoveFromDBAndEngines(removeEntityImplementor.removeEntityInfo.entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemoveFromDBAndEngines( ((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild, entityID, _entityViewsDB); | |||
} | |||
void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild, metaEntityID, _metaEntityViewsDB); | |||
} | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
InternalRemoveFromDBAndEngines(((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild, entityID, _groupEntityViewsDB[groupID]); | |||
} | |||
void RemoveEntitiesGroup(int groupID) | |||
{ | |||
foreach (var group in _groupEntityViewsDB[groupID]) | |||
{ | |||
var entityViewType = group.Key; | |||
int count; | |||
var entities = group.Value.ToArrayFast(out count); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var entityID = entities[i].ID; | |||
InternalRemoveEntityViewFromDBAndEngines(_entityViewsDB, entityViewType, entityID); | |||
} | |||
} | |||
_groupEntityViewsDB.Remove(groupID); | |||
} | |||
void InternalRemoveEntityViewFromDBAndEngines(Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Type entityViewType, int entityID) | |||
{ | |||
var entityViews = entityViewsDB[entityViewType]; | |||
if (entityViews.UnorderedRemove(entityID) == false) | |||
entityViewsDB.Remove(entityViewType); | |||
if (entityViews.isQueryiableEntityView) | |||
{ | |||
var typeSafeDictionary = _entityViewsDBDic[entityViewType]; | |||
var entityView = typeSafeDictionary.GetIndexedEntityView(entityID); | |||
if (typeSafeDictionary.Remove(entityID) == false) | |||
_entityViewsDBDic.Remove(entityViewType); | |||
for (var current = entityViewType; current != _entityViewType; current = current.BaseType) | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView, current); | |||
} | |||
} | |||
void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() | |||
{ | |||
DesignByContract.Check.Require(fromGroupID != toGroupID, "can't move an entity to the same group where it already belongs to"); | |||
var entityViewBuilders = ((EntityDescriptorInfo) EntityDescriptorTemplate<T>.Default).entityViewsToBuild; | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
var dictionary = _groupEntityViewsDB[fromGroupID]; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (_groupEntityViewsDB.TryGetValue(toGroupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
_groupEntityViewsDB.Add(toGroupID, groupedEntityViewsTyped); | |||
} | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
IEntityViewBuilder entityViewBuilder = entityViewBuilders[i]; | |||
Type entityViewType = entityViewBuilder.GetEntityViewType(); | |||
ITypeSafeList fromSafeList = dictionary[entityViewType]; | |||
ITypeSafeList toSafeList; | |||
if (groupedEntityViewsTyped.TryGetValue(entityViewType, out toSafeList) == false) | |||
{ | |||
toSafeList = fromSafeList.Create(); | |||
} | |||
entityViewBuilder.MoveEntityView(entityID, fromSafeList, toSafeList); | |||
if (fromSafeList.UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
} | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(fromGroupID); | |||
} | |||
void InternalRemoveFromDBAndEngines(IEntityViewBuilder[] entityViewBuilders, int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
InternalRemoveEntityViewFromDBAndEngines(entityViewsDB, entityViewType, entityID); | |||
} | |||
} | |||
void InternalRemove(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
InternalRemoveFromGroupDB(entityViewBuilders, entityID, groupID); | |||
InternalRemoveFromDBAndEngines(entityViewBuilders, entityID, entityViewsDB); | |||
} | |||
void InternalRemoveFromGroupDB(IEntityViewBuilder[] entityViewBuilders, int entityID, int groupID) | |||
{ | |||
int entityViewBuildersCount = entityViewBuilders.Length; | |||
Dictionary<Type, ITypeSafeList> dictionary = _groupEntityViewsDB[groupID]; | |||
for (int i = 0; i < entityViewBuildersCount; i++) | |||
{ | |||
Type entityViewType = entityViewBuilders[i].GetEntityViewType(); | |||
if (dictionary[entityViewType].UnorderedRemove(entityID) == false) | |||
dictionary.Remove(entityViewType); | |||
} | |||
if (dictionary.Count == 0) _groupEntityViewsDB.Remove(groupID); | |||
} | |||
static void RemoveEntityViewFromEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, | |||
IEntityView entityView, Type entityViewType) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
for (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(fastList[j], entityView); | |||
#else | |||
fastList[j].Remove(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
class GenericEntityFactory : IEntityFactory | |||
{ | |||
DataStructures.WeakReference<EnginesRoot> _weakEngine; | |||
public GenericEntityFactory(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakEngine = weakReference; | |||
} | |||
public void BuildEntity<T>(int entityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntity<T>(entityID, implementors); | |||
} | |||
public void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntity(entityID, entityDescriptor, implementors); | |||
} | |||
public void BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildMetaEntity<T>(metaEntityID, implementors); | |||
} | |||
public void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup<T>(entityID, groupID, implementors); | |||
} | |||
public void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors = null) | |||
{ | |||
_weakEngine.Target.BuildEntityInGroup(entityID, groupID, entityDescriptor, implementors); | |||
} | |||
public void Preallocate<T>(int size) where T : IEntityDescriptor, new() | |||
{ | |||
_weakEngine.Target.Preallocate<T>(size); | |||
} | |||
} | |||
class GenericEntityFunctions : IEntityFunctions | |||
{ | |||
public GenericEntityFunctions(DataStructures.WeakReference<EnginesRoot> weakReference) | |||
{ | |||
_weakReference = weakReference; | |||
} | |||
public void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo) | |||
{ | |||
_weakReference.Target.RemoveEntity(entityID, removeInfo); | |||
} | |||
public void RemoveEntity<T>(int entityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
public void RemoveMetaEntity<T>(int metaEntityID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(metaEntityID); | |||
} | |||
public void RemoveEntityFromGroup<T>(int entityID, int groupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.RemoveEntity<T>(entityID); | |||
} | |||
public void RemoveGroupedEntities(int groupID) | |||
{ | |||
_weakReference.Target.RemoveEntitiesGroup(groupID); | |||
} | |||
public void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new() | |||
{ | |||
_weakReference.Target.SwapEntityGroup<T>(entityID, fromGroupID, toGroupID); | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _weakReference; | |||
} | |||
public void Dispose() | |||
{ | |||
foreach (var entity in _entityViewsDB) | |||
{ | |||
if (entity.Value.isQueryiableEntityView == true) | |||
{ | |||
foreach (var entityView in entity.Value) | |||
{ | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); | |||
} | |||
} | |||
} | |||
foreach (var entity in _metaEntityViewsDB) | |||
{ | |||
foreach (var entityView in entity.Value) | |||
{ | |||
RemoveEntityViewFromEngines(_entityViewEngines, entityView as EntityView, entity.Key); | |||
} | |||
} | |||
} | |||
readonly EntityViewsDB _DB; | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBDic; | |||
} | |||
} |
@@ -0,0 +1,165 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Schedulers; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
namespace Svelto.ECS | |||
{ | |||
public partial class EnginesRoot : IDisposable | |||
{ | |||
void SubmitEntityViews() | |||
{ | |||
bool newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
int numberOfReenteringLoops = 0; | |||
while (newEntityViewsHaveBeenAddedWhileIterating) | |||
{ | |||
//use other as source from now on | |||
//current will be use to write new entityViews | |||
_entityViewsToAdd.Swap(); | |||
_metaEntityViewsToAdd.Swap(); | |||
_groupedEntityViewsToAdd.Swap(); | |||
if (_entityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_entityViewsToAdd.other, _entityViewsDB); | |||
if (_metaEntityViewsToAdd.other.Count > 0) | |||
AddEntityViewsToTheDBAndSuitableEngines(_metaEntityViewsToAdd.other, _metaEntityViewsDB); | |||
if (_groupedEntityViewsToAdd.other.Count > 0) | |||
AddGroupEntityViewsToTheDBAndSuitableEngines(_groupedEntityViewsToAdd.other, _groupEntityViewsDB, _entityViewsDB); | |||
//other can be cleared now | |||
_entityViewsToAdd.other.Clear(); | |||
_metaEntityViewsToAdd.other.Clear(); | |||
_groupedEntityViewsToAdd.other.Clear(); | |||
//has current new entityViews? | |||
newEntityViewsHaveBeenAddedWhileIterating = | |||
_metaEntityViewsToAdd.current.Count > 0 | |||
|| _entityViewsToAdd.current.Count > 0 | |||
|| _groupedEntityViewsToAdd.current.Count > 0; | |||
if (numberOfReenteringLoops > 5) | |||
throw new Exception("possible infinite loop found creating Entities inside IEntityViewsEngine Add method, please consider building entities outside IEntityViewsEngine Add method"); | |||
numberOfReenteringLoops++; | |||
} | |||
} | |||
void AddEntityViewsToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> entityViewsToAdd, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
AddEntityViewToDB(entityViewsDB, entityViewList); | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
AddEntityViewToEntityViewsDictionary(_entityViewsDBDic, entityViewList.Value, entityViewList.Key); | |||
} | |||
} | |||
foreach (var entityViewList in entityViewsToAdd) | |||
{ | |||
if (entityViewList.Value.isQueryiableEntityView) | |||
{ | |||
var type = entityViewList.Key; | |||
for (var current = type; current != _entityViewType; current = current.BaseType) | |||
AddEntityViewToTheSuitableEngines(_entityViewEngines, entityViewList.Value, | |||
current); | |||
} | |||
} | |||
} | |||
void AddGroupEntityViewsToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedEntityViewsToAdd, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
Dictionary<Type, ITypeSafeList> entityViewsDB) | |||
{ | |||
foreach (var group in groupedEntityViewsToAdd) | |||
{ | |||
AddEntityViewsToGroupDB(groupEntityViewsDB, @group); | |||
AddEntityViewsToTheDBAndSuitableEngines(group.Value, entityViewsDB); | |||
} | |||
} | |||
static void AddEntityViewsToGroupDB(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB, | |||
KeyValuePair<int, Dictionary<Type, ITypeSafeList>> @group) | |||
{ | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsByType; | |||
if (groupEntityViewsDB.TryGetValue(@group.Key, out groupedEntityViewsByType) == false) | |||
groupedEntityViewsByType = groupEntityViewsDB[@group.Key] = new Dictionary<Type, ITypeSafeList>(); | |||
foreach (var entityView in @group.Value) | |||
{ | |||
groupedEntityViewsByType.Add(entityView.Key, entityView.Value); | |||
} | |||
} | |||
static void AddEntityViewToDB(Dictionary<Type, ITypeSafeList> entityViewsDB, KeyValuePair<Type, ITypeSafeList> entityViewList) | |||
{ | |||
ITypeSafeList dbList; | |||
if (entityViewsDB.TryGetValue(entityViewList.Key, out dbList) == false) | |||
dbList = entityViewsDB[entityViewList.Key] = entityViewList.Value.Create(); | |||
dbList.AddRange(entityViewList.Value); | |||
} | |||
static void AddEntityViewToEntityViewsDictionary(Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
ITypeSafeList entityViews, Type entityViewType) | |||
{ | |||
ITypeSafeDictionary entityViewsDic; | |||
if (entityViewsDBdic.TryGetValue(entityViewType, out entityViewsDic) == false) | |||
entityViewsDic = entityViewsDBdic[entityViewType] = entityViews.CreateIndexedDictionary(); | |||
entityViewsDic.FillWithIndexedEntityViews(entityViews); | |||
} | |||
static void AddEntityViewToTheSuitableEngines(Dictionary<Type, FasterList<IHandleEntityViewEngine>> entityViewEngines, ITypeSafeList entityViewsList, Type entityViewType) | |||
{ | |||
FasterList<IHandleEntityViewEngine> enginesForEntityView; | |||
if (entityViewEngines.TryGetValue(entityViewType, out enginesForEntityView)) | |||
{ | |||
int viewsCount; | |||
var entityViews = entityViewsList.ToArrayFast(out viewsCount); | |||
for (int i = 0; i < viewsCount; i++) | |||
{ | |||
int count; | |||
var fastList = FasterList<IHandleEntityViewEngine>.NoVirt.ToArrayFast(enginesForEntityView, out count); | |||
IEntityView entityView = entityViews[i]; | |||
for (int j = 0; j < count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorAddDuration(fastList[j], entityView); | |||
#else | |||
fastList[j].Add(entityView); | |||
#endif | |||
} | |||
} | |||
} | |||
} | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _entityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<Type, ITypeSafeList>> _metaEntityViewsToAdd; | |||
readonly DoubleBufferedEntityViews<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedEntityViewsToAdd; | |||
readonly EntitySubmissionScheduler _scheduler; | |||
} | |||
} |
@@ -0,0 +1,272 @@ | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.Utilities; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityDescriptor | |||
{ | |||
IEntityViewBuilder[] entityViewsToBuild { get; } | |||
} | |||
public class EntityDescriptor:IEntityDescriptor | |||
{ | |||
protected EntityDescriptor(IEntityViewBuilder[] entityViewsToBuild) | |||
{ | |||
this.entityViewsToBuild = entityViewsToBuild; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild { get; private set; } | |||
} | |||
public interface IEntityDescriptorInfo | |||
{} | |||
public static class EntityDescriptorTemplate<TType> where TType : IEntityDescriptor, new() | |||
{ | |||
public static readonly IEntityDescriptorInfo Default = new EntityDescriptorInfo(new TType()); | |||
} | |||
public class DynamicEntityDescriptorInfo<TType> : EntityDescriptorInfo where TType : IEntityDescriptor, new() | |||
{ | |||
public DynamicEntityDescriptorInfo(FasterList<IEntityViewBuilder> extraEntityViews) | |||
{ | |||
DesignByContract.Check.Require(extraEntityViews.Count > 0, "don't use a DynamicEntityDescriptorInfo if you don't need to use extra EntityViews"); | |||
var descriptor = new TType(); | |||
int length = descriptor.entityViewsToBuild.Length; | |||
entityViewsToBuild = new IEntityViewBuilder[length + extraEntityViews.Count]; | |||
Array.Copy(descriptor.entityViewsToBuild, 0, entityViewsToBuild, 0, length); | |||
Array.Copy(extraEntityViews.ToArrayFast(), 0, entityViewsToBuild, length, extraEntityViews.Count); | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); | |||
name = descriptor.ToString(); | |||
} | |||
} | |||
} | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public class EntityDescriptorInfo:IEntityDescriptorInfo | |||
{ | |||
internal IEntityViewBuilder[] entityViewsToBuild; | |||
internal RemoveEntityImplementor removeEntityImplementor; | |||
internal string name; | |||
internal EntityDescriptorInfo(IEntityDescriptor descriptor) | |||
{ | |||
name = descriptor.ToString(); | |||
entityViewsToBuild = descriptor.entityViewsToBuild; | |||
removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuild); | |||
} | |||
protected EntityDescriptorInfo() | |||
{} | |||
} | |||
static class EntityFactory | |||
{ | |||
internal static void BuildGroupedEntityViews(int entityID, int groupID, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
Dictionary<Type, ITypeSafeList> groupedEntityViewsTyped; | |||
if (groupEntityViewsByType.TryGetValue(groupID, out groupedEntityViewsTyped) == false) | |||
{ | |||
groupedEntityViewsTyped = new Dictionary<Type, ITypeSafeList>(); | |||
groupEntityViewsByType.Add(groupID, groupedEntityViewsTyped); | |||
} | |||
//I would like to find a better solution for this | |||
var removeEntityImplementor = new RemoveEntityImplementor(entityViewsToBuildDescriptor.entityViewsToBuild, groupID); | |||
InternalBuildEntityViews(entityID, groupedEntityViewsTyped, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); | |||
} | |||
internal static void BuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
var removeEntityImplementor = entityViewsToBuildDescriptor.removeEntityImplementor; | |||
InternalBuildEntityViews(entityID, entityViewsByType, entityViewsToBuildDescriptor, implementors, removeEntityImplementor); | |||
} | |||
static void InternalBuildEntityViews(int entityID, | |||
Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
IEntityDescriptorInfo eentityViewsToBuildDescriptor, | |||
object[] implementors, RemoveEntityImplementor removeEntityImplementor) | |||
{ | |||
var entityViewsToBuildDescriptor = eentityViewsToBuildDescriptor as EntityDescriptorInfo; | |||
var entityViewsToBuild = entityViewsToBuildDescriptor.entityViewsToBuild; | |||
int count = entityViewsToBuild.Length; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var entityViewBuilder = entityViewsToBuild[index]; | |||
var entityViewType = entityViewBuilder.GetEntityViewType(); | |||
//only class EntityView will be returned | |||
//struct EntityView cannot be filled so it will be null. | |||
var entityViewObjectToFill = | |||
BuildEntityView(entityID, entityViewsByType, entityViewType, entityViewBuilder); | |||
//the semantic of this code must still be improved | |||
//but only classes can be filled, so I am aware | |||
//it's a EntityView | |||
if (entityViewObjectToFill != null) | |||
{ | |||
FillEntityView(entityViewObjectToFill as EntityView, implementors, removeEntityImplementor, | |||
entityViewsToBuildDescriptor.name); | |||
} | |||
} | |||
} | |||
static IEntityView BuildEntityView(int entityID, Dictionary<Type, ITypeSafeList> entityViewsByType, | |||
Type entityViewType, IEntityViewBuilder entityViewBuilder) | |||
{ | |||
ITypeSafeList entityViewsList; | |||
var entityViewsPoolWillBeCreated = | |||
entityViewsByType.TryGetValue(entityViewType, out entityViewsList) == false; | |||
IEntityView entityViewObjectToFill; | |||
//passing the undefined entityViewsByType inside the entityViewBuilder will allow | |||
//it to be created with the correct type and casted back to the undefined list. | |||
//that's how the list will be eventually of the target type. | |||
entityViewBuilder.BuildEntityViewAndAddToList(ref entityViewsList, entityID, out entityViewObjectToFill); | |||
if (entityViewsPoolWillBeCreated) | |||
entityViewsByType.Add(entityViewType, entityViewsList); | |||
return entityViewObjectToFill as IEntityView; | |||
} | |||
//this is used to avoid newing a dictionary every time, but it's used locally only and it's clearead for each use | |||
#if DEBUG && !PROFILER | |||
static readonly Dictionary<Type, Tuple<object, int>> implementorsByType = new Dictionary<Type, Tuple<object, int>>(); | |||
#else | |||
static readonly Dictionary<Type, object> implementorsByType = new Dictionary<Type, object>(); | |||
#endif | |||
static void FillEntityView(EntityView entityView, object[] implementors, RemoveEntityImplementor removeEntity, | |||
string entityDescriptorName) | |||
{ | |||
for (int index = 0; index < implementors.Length; index++) | |||
{ | |||
var implementor = implementors[index]; | |||
if (implementor != null) | |||
{ | |||
var type = implementor.GetType(); | |||
Type[] interfaces; | |||
if (_cachedTypes.TryGetValue(type, out interfaces) == false) | |||
interfaces = _cachedTypes[type] = type.GetInterfacesEx(); | |||
for (int iindex = 0; iindex < interfaces.Length; iindex++) | |||
{ | |||
var componentType = interfaces[iindex]; | |||
#if DEBUG && !PROFILER | |||
Tuple<object, int> implementorHolder; | |||
if (implementorsByType.TryGetValue(componentType, out implementorHolder) == true) | |||
implementorHolder.item2++; | |||
else | |||
implementorsByType[componentType] = new Tuple<object, int>(implementor, 1); | |||
#else | |||
implementorsByType[componentType] = implementor; | |||
#endif | |||
} | |||
} | |||
#if DEBUG && !PROFILER | |||
else | |||
Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(entityView.ToString())); | |||
#endif | |||
} | |||
int count; | |||
//Very efficent way to collect the fields of every EntityViewType | |||
KeyValuePair<Type, CastedAction<EntityView>>[] setters = | |||
FasterList<KeyValuePair<Type, CastedAction<EntityView>>>.NoVirt.ToArrayFast(entityView.entityViewBlazingFastReflection, out count); | |||
var removeEntityComponentType = typeof(IRemoveEntityComponent); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var keyValuePair = setters[i]; | |||
Type fieldType = keyValuePair.Key; | |||
if (fieldType != removeEntityComponentType) | |||
{ | |||
#if DEBUG && !PROFILER | |||
Tuple<object, int> component; | |||
#else | |||
object component; | |||
#endif | |||
if (implementorsByType.TryGetValue(fieldType, out component) == false) | |||
{ | |||
Exception e = new Exception(NOT_FOUND_EXCEPTION + " Component Type: " + fieldType.Name + " - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
throw e; | |||
} | |||
#if DEBUG && !PROFILER | |||
if (component.item2 > 1) | |||
Utility.Console.LogError(DUPLICATE_IMPLEMENTOR_ERROR.FastConcat( | |||
"Component Type: ", fieldType.Name, " implementor: ", | |||
component.item1.ToString()) + " - EntityView: " + | |||
entityView.GetType().Name + " - EntityDescriptor " + entityDescriptorName); | |||
#endif | |||
#if DEBUG && !PROFILER | |||
keyValuePair.Value.Call(entityView, component.item1); | |||
#else | |||
keyValuePair.Value.Call(entityView, component); | |||
#endif | |||
} | |||
else | |||
{ | |||
keyValuePair.Value.Call(entityView, removeEntity); | |||
} | |||
} | |||
implementorsByType.Clear(); | |||
} | |||
#if DEBUG && !PROFILER | |||
struct Tuple<T1, T2> | |||
{ | |||
public T1 item1; | |||
public T2 item2; | |||
public Tuple(T1 implementor, T2 v) | |||
{ | |||
item1 = implementor; | |||
item2 = v; | |||
} | |||
} | |||
#endif | |||
static Dictionary<Type, Type[]> _cachedTypes = new Dictionary<Type, Type[]>(); | |||
const string DUPLICATE_IMPLEMENTOR_ERROR = | |||
"<color=orange>Svelto.ECS</color> the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; | |||
const string NULL_IMPLEMENTOR_ERROR = | |||
"<color=orange>Svelto.ECS</color> Null implementor, please be careful about the implementors passed to avoid performance loss "; | |||
const string NOT_FOUND_EXCEPTION = "<color=orange>Svelto.ECS</color> Implementor not found for an EntityView. "; | |||
} | |||
} | |||
@@ -0,0 +1,9 @@ | |||
using Svelto.WeakEvents; | |||
namespace Svelto.ECS.Schedulers | |||
{ | |||
public abstract class EntitySubmissionScheduler | |||
{ | |||
abstract public void Schedule(WeakAction submitEntityViews); | |||
} | |||
} |
@@ -0,0 +1,59 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Svelto.DataStructures; | |||
using Svelto.Utilities; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityView | |||
{ | |||
int ID { get; } | |||
} | |||
public interface IEntityStruct:IEntityView | |||
{ | |||
new int ID { set; } | |||
} | |||
public class EntityView : IEntityView | |||
{ | |||
public int ID { get { return _ID; } } | |||
internal FasterList<KeyValuePair<Type, CastedAction<EntityView>>> entityViewBlazingFastReflection; | |||
internal int _ID; | |||
} | |||
static class EntityView<T> where T: EntityView, new() | |||
{ | |||
internal static T BuildEntityView(int ID) | |||
{ | |||
if (FieldCache<T>.list.Count == 0) | |||
{ | |||
var type = typeof(T); | |||
var fields = type.GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
for (int i = fields.Length - 1; i >= 0; --i) | |||
{ | |||
var field = fields[i]; | |||
CastedAction<EntityView> setter = FastInvoke<T>.MakeSetter<EntityView>(field); | |||
FieldCache<T>.list.Add(new KeyValuePair<Type, CastedAction<EntityView>>(field.FieldType, setter)); | |||
} | |||
} | |||
return new T { _ID = ID, entityViewBlazingFastReflection = FieldCache<T>.list }; | |||
} | |||
//check if I can remove W | |||
static class FieldCache<W> where W:T | |||
{ | |||
internal static readonly FasterList<KeyValuePair<Type, CastedAction<EntityView>>> list | |||
= new FasterList<KeyValuePair<Type, CastedAction<EntityView>>>(); | |||
} | |||
} | |||
} | |||
@@ -0,0 +1,99 @@ | |||
using System; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewBuilder | |||
{ | |||
void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView); | |||
ITypeSafeList Preallocate(ref ITypeSafeList list, int size); | |||
Type GetEntityViewType(); | |||
void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList); | |||
} | |||
public class EntityViewBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : EntityView, new() | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
var lentityView = EntityView<EntityViewType>.BuildEntityView(entityID); | |||
castedList.Add(lentityView); | |||
entityView = lentityView; | |||
} | |||
public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForClasses<EntityViewType>(size); | |||
else | |||
list.ReserveCapacity(size); | |||
return list; | |||
} | |||
public Type GetEntityViewType() | |||
{ | |||
return _entityViewType; | |||
} | |||
public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
{ | |||
var fromCastedList = fromSafeList as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
var toCastedList = toSafeList as TypeSafeFasterListForECSForClasses<EntityViewType>; | |||
toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
public class EntityStructBuilder<EntityViewType> : IEntityViewBuilder where EntityViewType : struct, IEntityStruct | |||
{ | |||
public void BuildEntityViewAndAddToList(ref ITypeSafeList list, int entityID, out IEntityView entityView) | |||
{ | |||
var lentityView = default(EntityViewType); | |||
lentityView.ID = entityID; | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(); | |||
var castedList = list as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
castedList.Add(lentityView); | |||
entityView = null; | |||
} | |||
public ITypeSafeList Preallocate(ref ITypeSafeList list, int size) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterListForECSForStructs<EntityViewType>(size); | |||
else | |||
list.ReserveCapacity(size); | |||
return list; | |||
} | |||
public Type GetEntityViewType() | |||
{ | |||
return _entityViewType; | |||
} | |||
public void MoveEntityView(int entityID, ITypeSafeList fromSafeList, ITypeSafeList toSafeList) | |||
{ | |||
var fromCastedList = fromSafeList as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
var toCastedList = toSafeList as TypeSafeFasterListForECSForStructs<EntityViewType>; | |||
toCastedList.Add(fromCastedList[fromCastedList.GetIndexFromID(entityID)]); | |||
} | |||
readonly Type _entityViewType = typeof(EntityViewType); | |||
} | |||
} |
@@ -0,0 +1,165 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
class EntityViewsDB : IEntityViewsDB | |||
{ | |||
internal EntityViewsDB( Dictionary<Type, ITypeSafeList> entityViewsDB, | |||
Dictionary<Type, ITypeSafeDictionary> entityViewsDBdic, | |||
Dictionary<Type, ITypeSafeList> metaEntityViewsDB, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupEntityViewsDB) | |||
{ | |||
_entityViewsDB = entityViewsDB; | |||
_entityViewsDBdic = entityViewsDBdic; | |||
_metaEntityViewsDB = metaEntityViewsDB; | |||
_groupEntityViewsDB = groupEntityViewsDB; | |||
} | |||
public FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new() | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeList entityViews; | |||
if (_entityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
} | |||
public FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int @group) where T:EntityView, new() | |||
{ | |||
Dictionary<Type, ITypeSafeList> entityViews; | |||
if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>(entityViews as FasterList<T>); | |||
} | |||
public T[] QueryEntityViewsAsArray<T>(out int count) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
count = 0; | |||
ITypeSafeList entityViews; | |||
if (_entityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewArray<T>(); | |||
var castedEntityViews = (FasterList<T>)entityViews; | |||
return FasterList < T > .NoVirt.ToArrayFast(castedEntityViews, out count); | |||
} | |||
public T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
count = 0; | |||
Dictionary<Type, ITypeSafeList> entityViews; | |||
if (_groupEntityViewsDB.TryGetValue(group, out entityViews) == false) | |||
return RetrieveEmptyEntityViewArray<T>(); | |||
var castedEntityViews = (FasterList<T>)entityViews[type]; | |||
count = castedEntityViews.Count; | |||
return FasterList<T>.NoVirt.ToArrayFast(castedEntityViews, out count); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T:IEntityView | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary entityViews; | |||
if (_entityViewsDBdic.TryGetValue(type, out entityViews) == false) | |||
return TypeSafeDictionary<T>.Default; | |||
return new ReadOnlyDictionary<int, T>(entityViews as Dictionary<int, T>); | |||
} | |||
public bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; | |||
ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
_entityViewsDBdic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
{ | |||
entityView = internalEntityView; | |||
return true; | |||
} | |||
entityView = default(T); | |||
return false; | |||
} | |||
public T QueryEntityView<T>(int ID) where T : IEntityView | |||
{ | |||
var type = typeof(T); | |||
T internalEntityView; ITypeSafeDictionary entityViews; | |||
TypeSafeDictionary<T> casted; | |||
_entityViewsDBdic.TryGetValue(type, out entityViews); | |||
casted = entityViews as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalEntityView)) | |||
return (T)internalEntityView; | |||
throw new Exception("EntityView Not Found"); | |||
} | |||
public T QueryMetaEntityView<T>(int metaEntityID) where T:EntityView, new() | |||
{ | |||
return QueryEntityView<T>(metaEntityID); | |||
} | |||
public bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T:EntityView, new() | |||
{ | |||
return TryQueryEntityView(metaEntityID, out entityView); | |||
} | |||
public FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T:EntityView, new() | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeList entityViews; | |||
if (_metaEntityViewsDB.TryGetValue(type, out entityViews) == false) | |||
return RetrieveEmptyEntityViewList<T>(); | |||
return new FasterReadOnlyList<T>((FasterList<T>)entityViews); | |||
} | |||
static FasterReadOnlyList<T> RetrieveEmptyEntityViewList<T>() | |||
{ | |||
return FasterReadOnlyList<T>.DefaultList; | |||
} | |||
static T[] RetrieveEmptyEntityViewArray<T>() | |||
{ | |||
return FasterList<T>.DefaultList.ToArrayFast(); | |||
} | |||
readonly Dictionary<Type, ITypeSafeList> _entityViewsDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _entityViewsDBdic; | |||
readonly Dictionary<Type, ITypeSafeList> _metaEntityViewsDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupEntityViewsDB; | |||
} | |||
} |
@@ -0,0 +1,180 @@ | |||
#if EXPERIMENTAL | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Experimental.Internal; | |||
namespace Svelto.ECS.Experimental.Internal | |||
{ | |||
public interface IStructEntityViewEngine : IEngine | |||
{ | |||
void CreateStructEntityViews(SharedStructEntityViewLists sharedStructEntityViewLists); | |||
} | |||
public interface IGroupedStructEntityViewsEngine : IEngine | |||
{ | |||
void CreateStructEntityViews(SharedGroupedStructEntityViewsLists sharedStructEntityViewLists); | |||
} | |||
} | |||
namespace Svelto.ECS.Experimental | |||
{ | |||
public interface IGroupedEntityView | |||
{ | |||
int groupID { get; set; } | |||
} | |||
/// <summary> | |||
/// The engines can receive and store IEntityViews structs | |||
/// Unboxing will happen during the Add, but the | |||
/// data will then be stored and processed as stucts | |||
/// </summary> | |||
public interface IStructEntityViewEngine<T> : IStructEntityViewEngine where T:struct, IEntityStruct | |||
{ } | |||
/// <summary> | |||
/// same as above, but the entityViews are grouped by ID | |||
/// usually the ID is the owner of the entityViews of that | |||
/// group | |||
/// </summary> | |||
public interface IGroupedStructEntityViewsEngine<T> : IGroupedStructEntityViewsEngine where T : struct, IGroupedEntityView | |||
{ | |||
void Add(ref T entityView); | |||
void Remove(ref T entityView); | |||
} | |||
public sealed class StructEntityViews<T> where T:struct, IEntityStruct | |||
{ | |||
public T[] GetList(out int numberOfItems) | |||
{ | |||
numberOfItems = _internalList.Count; | |||
return _internalList.ToArrayFast(); | |||
} | |||
public StructEntityViews(SharedStructEntityViewLists container) | |||
{ | |||
_internalList = SharedStructEntityViewLists.NoVirt.GetList<T>(container); | |||
} | |||
public void Add(T entityView) | |||
{ | |||
T convert = (T)entityView; | |||
_internalList.Add(convert); | |||
} | |||
readonly FasterList<T> _internalList; | |||
} | |||
public struct StructGroupEntityViews<T> | |||
where T : struct, IEntityView | |||
{ | |||
public StructGroupEntityViews(SharedGroupedStructEntityViewsLists container) | |||
{ | |||
_container = container; | |||
indices = new Dictionary<int, int>(); | |||
} | |||
public void Add(int groupID, T entityView) | |||
{ | |||
T convert = (T)entityView; | |||
var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
indices[entityView.ID] = fasterList.Count; | |||
fasterList.Add(convert); | |||
} | |||
public void Remove(int groupID, T entityView) | |||
{ | |||
var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
var index = indices[entityView.ID]; | |||
indices.Remove(entityView.ID); | |||
if (fasterList.UnorderedRemoveAt(index)) | |||
indices[fasterList[index].ID] = index; | |||
} | |||
public T[] GetList(int groupID, out int numberOfItems) | |||
{ | |||
var fasterList = (SharedGroupedStructEntityViewsLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
return FasterList<T>.NoVirt.ToArrayFast(fasterList, out numberOfItems); | |||
} | |||
readonly SharedGroupedStructEntityViewsLists _container; | |||
readonly Dictionary<int, int> indices; | |||
} | |||
public class SharedStructEntityViewLists | |||
{ | |||
internal SharedStructEntityViewLists() | |||
{ | |||
_collection = new Dictionary<Type, IFasterList>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static FasterList<T> GetList<T>(SharedStructEntityViewLists obj) where T : struct | |||
{ | |||
IFasterList list; | |||
if (obj._collection.TryGetValue(typeof(T), out list)) | |||
{ | |||
return list as FasterList<T>; | |||
} | |||
list = new FasterList<T>(); | |||
obj._collection.Add(typeof(T), list); | |||
return (FasterList<T>)list; | |||
} | |||
} | |||
readonly Dictionary<Type, IFasterList> _collection; | |||
} | |||
public class SharedGroupedStructEntityViewsLists | |||
{ | |||
internal SharedGroupedStructEntityViewsLists() | |||
{ | |||
_collection = new Dictionary<Type, Dictionary<int, IFasterList>>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static IFasterList GetList<T>(SharedGroupedStructEntityViewsLists list, int groupID) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic = GetGroup<T>(list); | |||
IFasterList localList; | |||
if (dic.TryGetValue(groupID, out localList)) | |||
return localList; | |||
localList = new FasterList<T>(); | |||
dic.Add(groupID, localList); | |||
return localList; | |||
} | |||
internal static Dictionary<int, IFasterList> GetGroup<T>(SharedGroupedStructEntityViewsLists list) where T : struct | |||
{ | |||
Dictionary<int, IFasterList> dic; | |||
if (list._collection.TryGetValue(typeof(T), out dic)) | |||
{ | |||
return dic; | |||
} | |||
dic = new Dictionary<int, IFasterList>(); | |||
list._collection.Add(typeof(T), dic); | |||
return dic; | |||
} | |||
} | |||
readonly Dictionary<Type, Dictionary<int, IFasterList>> _collection; | |||
} | |||
} | |||
#endif |
@@ -0,0 +1,14 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
namespace Svelto.ECS | |||
{ | |||
public class GenericEntityDescriptorHolder<T>: | |||
UnityEngine.MonoBehaviour , IEntityDescriptorHolder | |||
where T: class, IEntityDescriptor, new() | |||
{ | |||
public IEntityDescriptorInfo RetrieveDescriptor() | |||
{ | |||
return EntityDescriptorTemplate<T>.Default; | |||
} | |||
} | |||
} | |||
#endif |
@@ -0,0 +1,53 @@ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using System.Collections; | |||
using Svelto.WeakEvents; | |||
using UnityEngine; | |||
namespace Svelto.ECS.Schedulers.Unity | |||
{ | |||
//The EntityViewSubmissionScheduler has been introduced to make | |||
//the entityView submission logic platform indipendent. | |||
//Please don't be tempted to create your own submission to | |||
//adapt to your game level code design. For example, | |||
//you may be tempted to write a submission logic to submit | |||
//the entityViews immediatly just because convenient for your game | |||
//logic. This is not how it works. | |||
public class UnitySumbmissionEntityViewScheduler : EntitySubmissionScheduler | |||
{ | |||
public UnitySumbmissionEntityViewScheduler() | |||
{ | |||
GameObject go = new GameObject("ECSScheduler"); | |||
_scheduler = go.AddComponent<Scheduler>(); | |||
} | |||
public override void Schedule(WeakAction submitEntityViews) | |||
{ | |||
_scheduler.OnTick = submitEntityViews; | |||
} | |||
class Scheduler : MonoBehaviour | |||
{ | |||
IEnumerator Start() | |||
{ | |||
while (true) | |||
{ | |||
yield return _wait; | |||
if (OnTick.IsValid) | |||
OnTick.Invoke(); | |||
else | |||
yield break; | |||
} | |||
} | |||
internal WeakAction OnTick; | |||
WaitForEndOfFrame _wait = new WaitForEndOfFrame(); | |||
} | |||
Scheduler _scheduler; | |||
} | |||
} | |||
#endif |
@@ -0,0 +1,110 @@ | |||
using System.Runtime.InteropServices; | |||
namespace Svelto.ECS | |||
{ | |||
public class GenericEntityDescriptor<T>:IEntityDescriptor where T : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
entityViewBuilders = new IEntityViewBuilder[] { new EntityViewBuilder<T>() }; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return entityViewBuilders; } | |||
} | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder<T>(), new EntityViewBuilder<U>()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return entityViewBuilders; } | |||
} | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder<T>(), new EntityViewBuilder<U>(), new EntityViewBuilder<V>()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return entityViewBuilders; } | |||
} | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V, W> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
where W : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder<T>(), new EntityViewBuilder<U>(), new EntityViewBuilder<V>(), new EntityViewBuilder<W>()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return entityViewBuilders; } | |||
} | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V, W, X> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
where W : EntityView, new() | |||
where X : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder<T>(), new EntityViewBuilder<U>(), new EntityViewBuilder<V>(), new EntityViewBuilder<W>(), new EntityViewBuilder<X>()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return entityViewBuilders; } | |||
} | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
public class GenericEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor where T : EntityView, new() | |||
where U : EntityView, new() | |||
where V : EntityView, new() | |||
where W : EntityView, new() | |||
where X : EntityView, new() | |||
where Y : EntityView, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
{ | |||
entityViewBuilders = new IEntityViewBuilder[] {new EntityViewBuilder<T>(), new EntityViewBuilder<U>(), new EntityViewBuilder<V>(), new EntityViewBuilder<W>(), new EntityViewBuilder<X>(), new EntityViewBuilder<Y>()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return entityViewBuilders; } | |||
} | |||
public static readonly IEntityViewBuilder[] entityViewBuilders; | |||
} | |||
} |
@@ -0,0 +1,21 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface IHandleEntityViewEngine : IEngine | |||
{ | |||
void Add(IEntityView entityView); | |||
void Remove(IEntityView entityView); | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngine | |||
{} | |||
public interface IQueryingEntityViewEngine : IEngine | |||
{ | |||
IEntityViewsDB entityViewsDB { set; } | |||
void Ready(); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngineEntityViewDB | |||
{ | |||
FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new(); | |||
FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T: EntityView, new(); | |||
FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int group) where T: EntityView, new(); | |||
T[] QueryEntityViewsAsArray<T>(out int count) where T: IEntityView; | |||
T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T: IEntityView; | |||
ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T: IEntityView; | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView; | |||
T QueryEntityView<T>(int ID) where T: IEntityView; | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T: EntityView, new(); | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView, new(); | |||
} | |||
} | |||
@@ -0,0 +1,29 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityFactory | |||
{ | |||
void Preallocate<T>(int size) where T : IEntityDescriptor, new(); | |||
void BuildEntity<T>(int entityID, object[] implementors = null) where T:IEntityDescriptor, new(); | |||
void BuildEntity(int entityID, IEntityDescriptorInfo entityDescriptorInfo, object[] implementors); | |||
void BuildMetaEntity<T>(int metaEntityID, object[] implementors = null) where T:IEntityDescriptor, new(); | |||
void BuildEntityInGroup<T>(int entityID, int groupID, object[] implementors = null) where T:IEntityDescriptor, new(); | |||
void BuildEntityInGroup(int entityID, int groupID, IEntityDescriptorInfo entityDescriptor, object[] implementors); | |||
} | |||
public interface IEntityFunctions | |||
{ | |||
void RemoveEntity(int entityID, IRemoveEntityComponent removeInfo); | |||
void RemoveEntity<T>(int entityID) where T:IEntityDescriptor, new(); | |||
void RemoveMetaEntity<T>(int metaEntityID) where T:IEntityDescriptor, new(); | |||
void RemoveEntityFromGroup<T>(int entityID, int groupID) where T:IEntityDescriptor, new(); | |||
void RemoveGroupedEntities(int groupID); | |||
void SwapEntityGroup<T>(int entityID, int fromGroupID, int toGroupID) where T : IEntityDescriptor, new(); | |||
} | |||
} |
@@ -0,0 +1,7 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityDescriptorHolder | |||
{ | |||
IEntityDescriptorInfo RetrieveDescriptor(); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEntityViewsDB | |||
{ | |||
FasterReadOnlyList<T> QueryEntityViews<T>() where T:EntityView, new(); | |||
FasterReadOnlyList<T> QueryMetaEntityViews<T>() where T: EntityView, new(); | |||
FasterReadOnlyList<T> QueryGroupedEntityViews<T>(int group) where T: EntityView, new(); | |||
T[] QueryEntityViewsAsArray<T>(out int count) where T: IEntityView; | |||
T[] QueryGroupedEntityViewsAsArray<T>(int @group, out int count) where T: IEntityView; | |||
ReadOnlyDictionary<int, T> QueryIndexableEntityViews<T>() where T: IEntityView; | |||
bool TryQueryEntityView<T>(int ID, out T entityView) where T : IEntityView; | |||
T QueryEntityView<T>(int ID) where T: IEntityView; | |||
bool TryQueryMetaEntityView<T>(int metaEntityID, out T entityView) where T: EntityView, new(); | |||
T QueryMetaEntityView<T>(int metaEntityID) where T: EntityView, new(); | |||
} | |||
} | |||
@@ -0,0 +1,107 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public class MixedEntityDescriptor<T>:IEntityDescriptor where T : class, IEntityViewBuilder, new() | |||
{ | |||
static MixedEntityDescriptor() | |||
{ | |||
_entityViewsToBuild = new IEntityViewBuilder[] {new T()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return _entityViewsToBuild; } | |||
} | |||
static readonly IEntityViewBuilder[] _entityViewsToBuild; | |||
} | |||
public class MixedEntityDescriptor<T, U> : IEntityDescriptor where T : class, IEntityViewBuilder, new() | |||
where U : class, IEntityViewBuilder, new() | |||
{ | |||
static MixedEntityDescriptor() | |||
{ | |||
_entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return _entityViewsToBuild; } | |||
} | |||
static readonly IEntityViewBuilder[] _entityViewsToBuild; | |||
} | |||
public class MixedEntityDescriptor<T, U, V> : IEntityDescriptor where T : class, IEntityViewBuilder, new() | |||
where U : class, IEntityViewBuilder, new() | |||
where V : class, IEntityViewBuilder, new() | |||
{ | |||
static MixedEntityDescriptor() | |||
{ | |||
_entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return _entityViewsToBuild; } | |||
} | |||
static readonly IEntityViewBuilder[] _entityViewsToBuild; | |||
} | |||
public class MixedEntityDescriptor<T, U, V, W> : IEntityDescriptor where T : class, IEntityViewBuilder, new() | |||
where U : class, IEntityViewBuilder, new() | |||
where V : class, IEntityViewBuilder, new() | |||
where W : class, IEntityViewBuilder, new() | |||
{ | |||
static MixedEntityDescriptor() | |||
{ | |||
_entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return _entityViewsToBuild; } | |||
} | |||
static readonly IEntityViewBuilder[] _entityViewsToBuild; | |||
} | |||
public class MixedEntityDescriptor<T, U, V, W, X> : IEntityDescriptor where T : class, IEntityViewBuilder, new() | |||
where U : class, IEntityViewBuilder, new() | |||
where V : class, IEntityViewBuilder, new() | |||
where W : class, IEntityViewBuilder, new() | |||
where X : class, IEntityViewBuilder, new() | |||
{ | |||
static MixedEntityDescriptor() | |||
{ | |||
_entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return _entityViewsToBuild; } | |||
} | |||
static readonly IEntityViewBuilder[] _entityViewsToBuild; | |||
} | |||
public class MixedEntityDescriptor<T, U, V, W, X, Y> : IEntityDescriptor where T : class, IEntityViewBuilder, new() | |||
where U : class, IEntityViewBuilder, new() | |||
where V : class, IEntityViewBuilder, new() | |||
where W : class, IEntityViewBuilder, new() | |||
where X : class, IEntityViewBuilder, new() | |||
where Y : class, IEntityViewBuilder, new() | |||
{ | |||
static MixedEntityDescriptor() | |||
{ | |||
_entityViewsToBuild = new IEntityViewBuilder[] {new T(), new U(), new V(), new W(), new X(), new Y()}; | |||
} | |||
public IEntityViewBuilder[] entityViewsToBuild | |||
{ | |||
get { return _entityViewsToBuild; } | |||
} | |||
static readonly IEntityViewBuilder[] _entityViewsToBuild; | |||
} | |||
} |
@@ -0,0 +1,118 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public abstract class MultiEntityViewsEngine<T>:IHandleEntityViewEngine where T:EntityView, new() | |||
{ | |||
protected abstract void Add(T entityView); | |||
protected abstract void Remove(T entityView); | |||
public virtual void Add(IEntityView entityView) | |||
{ | |||
Add((T) entityView); | |||
} | |||
public virtual void Remove(IEntityView entityView) | |||
{ | |||
Remove((T) entityView); | |||
} | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class MultiEntityViewsEngine<T, U> : MultiEntityViewsEngine<T> | |||
where U:EntityView, new() where T : EntityView, new() | |||
{ | |||
protected abstract void Add(U entityView); | |||
protected abstract void Remove(U entityView); | |||
public override void Add(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as U; | |||
if (castedEntityView != null) | |||
{ | |||
Add(castedEntityView); | |||
} | |||
else | |||
{ | |||
base.Add(entityView); | |||
} | |||
} | |||
public override void Remove(IEntityView entityView) | |||
{ | |||
if (entityView is U) | |||
{ | |||
Remove((U) entityView); | |||
} | |||
else | |||
{ | |||
base.Remove(entityView); | |||
} | |||
} | |||
} | |||
public abstract class MultiEntityViewsEngine<T, U, V> : MultiEntityViewsEngine<T, U> | |||
where V : EntityView, new() where U : EntityView, new() where T : EntityView, new() | |||
{ | |||
protected abstract void Add(V entityView); | |||
protected abstract void Remove(V entityView); | |||
public override void Add(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as V; | |||
if (castedEntityView != null) | |||
{ | |||
Add(castedEntityView); | |||
} | |||
else | |||
base.Add(entityView); | |||
} | |||
public override void Remove(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as V; | |||
if (castedEntityView != null) | |||
{ | |||
Remove(castedEntityView); | |||
} | |||
else | |||
base.Remove(entityView); | |||
} | |||
} | |||
/// <summary> | |||
/// Please do not add more MultiEntityViewsEngine | |||
/// if you use more than 4 nodes, your engine has | |||
/// already too many responsabilities. | |||
/// </summary> | |||
public abstract class MultiEntityViewsEngine<T, U, V, W> : MultiEntityViewsEngine<T, U, V> | |||
where W : EntityView, new() where V : EntityView, new() where U : EntityView, new() where T : EntityView, new() | |||
{ | |||
protected abstract void Add(W entityView); | |||
protected abstract void Remove(W entityView); | |||
public override void Add(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as W; | |||
if (castedEntityView != null) | |||
{ | |||
Add(castedEntityView); | |||
} | |||
else | |||
base.Add(entityView); | |||
} | |||
public override void Remove(IEntityView entityView) | |||
{ | |||
var castedEntityView = entityView as W; | |||
if (castedEntityView != null) | |||
{ | |||
Remove(castedEntityView); | |||
} | |||
else | |||
base.Remove(entityView); | |||
} | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
#if UNITY_EDITOR | |||
using System; | |||
using System.Collections.Generic; | |||
using UnityEditor; | |||
using UnityEngine; | |||
@@ -33,12 +33,12 @@ namespace Svelto.ECS.Profiler | |||
double _accumulatedAddDuration; | |||
double _minAddDuration; | |||
double _maxAddDuration; | |||
int _nodesAddedCount; | |||
int _entityViewsAddedCount; | |||
double _accumulatedRemoveDuration; | |||
double _minRemoveDuration; | |||
double _maxRemoveDuration; | |||
int _nodesRemovedCount; | |||
int _entityViewsRemovedCount; | |||
public IEngine engine { get { return _engine; } } | |||
public string engineName { get { return _engineName; } } | |||
@@ -56,8 +56,8 @@ namespace Svelto.ECS.Profiler | |||
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 averageAddDuration { get { return _entityViewsAddedCount == 0 ? 0 : _accumulatedAddDuration / _entityViewsAddedCount; } } | |||
public double averageRemoveDuration { get { return _entityViewsRemovedCount == 0 ? 0 : _accumulatedRemoveDuration / _entityViewsRemovedCount; } } | |||
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; } } | |||
@@ -126,7 +126,7 @@ namespace Svelto.ECS.Profiler | |||
_maxAddDuration = duration; | |||
} | |||
_accumulatedAddDuration += duration; | |||
_nodesAddedCount += 1; | |||
_entityViewsAddedCount += 1; | |||
} | |||
public void AddRemoveDuration(double duration) | |||
@@ -140,7 +140,7 @@ namespace Svelto.ECS.Profiler | |||
_maxRemoveDuration = duration; | |||
} | |||
_accumulatedRemoveDuration += duration; | |||
_nodesRemovedCount += 1; | |||
_entityViewsRemovedCount += 1; | |||
} | |||
public void ResetDurations() | |||
@@ -156,12 +156,12 @@ namespace Svelto.ECS.Profiler | |||
_accumulatedAddDuration = 0; | |||
_minAddDuration = 0; | |||
_maxAddDuration = 0; | |||
_nodesAddedCount = 0; | |||
_entityViewsAddedCount = 0; | |||
_accumulatedRemoveDuration = 0; | |||
_minRemoveDuration = 0; | |||
_maxRemoveDuration = 0; | |||
_nodesRemovedCount = 0; | |||
_entityViewsRemovedCount = 0; | |||
} | |||
} | |||
} |
@@ -12,30 +12,28 @@ namespace Svelto.ECS.Profiler | |||
{ | |||
static readonly Stopwatch _stopwatch = new Stopwatch(); | |||
public static void MonitorAddDuration(INodeEngine engine, INode node) | |||
public static void MonitorAddDuration(IHandleEntityViewEngine engine, IEntityView entityView) | |||
{ | |||
EngineInfo info; | |||
if (engineInfos.TryGetValue(engine.GetType(), out info)) | |||
{ | |||
_stopwatch.Reset(); | |||
_stopwatch.Start(); | |||
engine.Add(node); | |||
_stopwatch.Stop(); | |||
engine.Add(entityView); | |||
_stopwatch.Reset(); | |||
info.AddAddDuration(_stopwatch.Elapsed.TotalMilliseconds); | |||
} | |||
} | |||
public static void MonitorRemoveDuration(INodeEngine engine, INode node) | |||
public static void MonitorRemoveDuration(IHandleEntityViewEngine engine, IEntityView entityView) | |||
{ | |||
EngineInfo info; | |||
if (engineInfos.TryGetValue(engine.GetType(), out info)) | |||
{ | |||
_stopwatch.Reset(); | |||
_stopwatch.Start(); | |||
engine.Remove(node); | |||
_stopwatch.Stop(); | |||
engine.Remove(entityView); | |||
_stopwatch.Reset(); | |||
info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
namespace Svelto.ECS.Internal | |||
{ | |||
sealed class RemoveEntityImplementor : IRemoveEntityComponent | |||
{ | |||
public RemoveEntityImplementor(IEntityViewBuilder[] entityViews, int groupID):this(entityViews) | |||
{ | |||
this.groupID = groupID; | |||
isInAGroup = true; | |||
} | |||
internal RemoveEntityImplementor(IEntityViewBuilder[] entityViews) | |||
{ | |||
removeEntityInfo = new RemoveEntityInfo(entityViews); | |||
} | |||
internal readonly RemoveEntityInfo removeEntityInfo; | |||
internal readonly int groupID; | |||
internal readonly bool isInAGroup; | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public interface IRemoveEntityComponent | |||
{} | |||
public struct RemoveEntityInfo | |||
{ | |||
internal readonly IEntityViewBuilder[] entityViewsToBuild; | |||
public RemoveEntityInfo(IEntityViewBuilder[] entityViews) : this() | |||
{ | |||
this.entityViewsToBuild = entityViews; | |||
} | |||
} | |||
} |
@@ -0,0 +1,20 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class SingleEntityViewEngine<T> : IHandleEntityViewEngine where T:EntityView, new() | |||
{ | |||
public void Add(IEntityView entityView) | |||
{ | |||
Add((T)entityView); //when byref returns will be vailable, this should be passed by reference, not copy! | |||
} | |||
public void Remove(IEntityView entityView) | |||
{ | |||
Remove((T)entityView); | |||
} | |||
protected abstract void Add(T entityView); | |||
protected abstract void Remove(T entityView); | |||
} | |||
} |
@@ -1,3 +1,4 @@ | |||
#if UNITY_5_3_OR_NEWER || UNITY_5 | |||
using UnityEngine; | |||
namespace Svelto.Factories | |||
@@ -10,3 +11,4 @@ namespace Svelto.Factories | |||
GameObject Build(GameObject prefab); | |||
} | |||
} | |||
#endif |
@@ -1,3 +1,5 @@ | |||
#if UNITY_5_3_OR_NEWER || UNITY_5 | |||
using System; | |||
using UnityEngine; | |||
@@ -9,3 +11,4 @@ namespace Svelto.Factories | |||
} | |||
} | |||
#endif |
@@ -1,152 +0,0 @@ | |||
using System; | |||
#if NETFX_CORE | |||
using Windows.System.Diagnostics; | |||
#else | |||
using System.Diagnostics; | |||
#endif | |||
using System.Text; | |||
namespace Utility | |||
{ | |||
public static class Console | |||
{ | |||
static StringBuilder _stringBuilder = new StringBuilder(256); | |||
#if UNITY_5_3_OR_NEWER || UNITY_5 | |||
public static ILogger logger = new SlowLoggerUnity(); | |||
#else | |||
public static ILogger logger = new SimpleLogger(); | |||
#endif | |||
public static volatile bool BatchLog = false; | |||
//Hack, have to find the right solution | |||
public static Action<Exception, object, string, string> onException; | |||
static Console() | |||
{ | |||
onException = (e, obj, message, stack) => | |||
{ | |||
UnityEngine.Debug.LogException(e, (UnityEngine.Object)obj); | |||
}; | |||
} | |||
public static void Log(string txt) | |||
{ | |||
logger.Log(txt); | |||
} | |||
public static void LogError(string txt) | |||
{ | |||
string toPrint; | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append("-!!!!!!-> "); | |||
_stringBuilder.Append(txt); | |||
toPrint = _stringBuilder.ToString(); | |||
} | |||
logger.Log(toPrint, null, LogType.Error); | |||
} | |||
public static void LogError(string txt, string stack) | |||
{ | |||
string toPrint; | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append("-!!!!!!-> "); | |||
_stringBuilder.Append(txt); | |||
toPrint = _stringBuilder.ToString(); | |||
} | |||
logger.Log(toPrint, stack, LogType.Error); | |||
} | |||
public static void LogException(Exception e) | |||
{ | |||
LogException(e, null); | |||
} | |||
public static void LogException(Exception e, UnityEngine.Object obj) | |||
{ | |||
string toPrint; | |||
string stackTrace; | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append("-!!!!!!-> ").Append(e.Message); | |||
stackTrace = e.StackTrace; | |||
if (e.InnerException != null) | |||
{ | |||
e = e.InnerException; | |||
_stringBuilder.Append(" Inner Message: ").Append(e.Message).Append(" Inner Stacktrace:") | |||
.Append(e.StackTrace); | |||
stackTrace = e.StackTrace; | |||
} | |||
toPrint = _stringBuilder.ToString(); | |||
} | |||
onException(e, obj, toPrint, stackTrace); | |||
} | |||
public static void LogWarning(string txt) | |||
{ | |||
string toPrint; | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append("------> "); | |||
_stringBuilder.Append(txt); | |||
toPrint = _stringBuilder.ToString(); | |||
} | |||
logger.Log(toPrint, null, LogType.Warning); | |||
} | |||
/// <summary> | |||
/// Use this function if you don't want the message to be batched | |||
/// </summary> | |||
/// <param name="txt"></param> | |||
public static void SystemLog(string txt) | |||
{ | |||
string toPrint; | |||
lock (_stringBuilder) | |||
{ | |||
#if NETFX_CORE | |||
string currentTimeString = DateTime.UtcNow.ToString("dd/mm/yy hh:ii:ss"); | |||
string processTimeString = (DateTime.UtcNow - ProcessDiagnosticInfo.GetForCurrentProcess().ProcessStartTime.DateTime).ToString(); | |||
#else | |||
string currentTimeString = DateTime.UtcNow.ToLongTimeString(); //ensure includes seconds | |||
string processTimeString = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString(); | |||
#endif | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append("[").Append(currentTimeString); | |||
_stringBuilder.Append("][").Append(processTimeString); | |||
_stringBuilder.Length = _stringBuilder.Length - 3; //remove some precision that we don't need | |||
_stringBuilder.Append("] ").AppendLine(txt); | |||
toPrint = _stringBuilder.ToString(); | |||
} | |||
#if !UNITY_EDITOR && !NETFX_CORE | |||
System.Console.WriteLine(toPrint); | |||
#else | |||
UnityEngine.Debug.Log(toPrint); | |||
#endif | |||
} | |||
} | |||
} |
@@ -1,459 +0,0 @@ | |||
// from: http://www.codeproject.com/Articles/1863/Design-by-Contract-Framework | |||
// Provides support for Design By Contract | |||
// as described by Bertrand Meyer in his seminal book, | |||
// Object-Oriented Software Construction (2nd Ed) Prentice Hall 1997 | |||
// (See chapters 11 and 12). | |||
// | |||
// See also Building Bug-free O-O Software: An Introduction to Design by Contract | |||
// http://www.eiffel.com/doc/manuals/technology/contract/ | |||
// | |||
// The following conditional compilation symbols are supported: | |||
// | |||
// These suggestions are based on Bertrand Meyer's Object-Oriented Software Construction (2nd Ed) p393 | |||
// | |||
// DBC_CHECK_ALL - Check assertions - implies checking preconditions, postconditions and invariants | |||
// DBC_CHECK_INVARIANT - Check invariants - implies checking preconditions and postconditions | |||
// DBC_CHECK_POSTCONDITION - Check postconditions - implies checking preconditions | |||
// DBC_CHECK_PRECONDITION - Check preconditions only, e.g., in Release build | |||
// | |||
// A suggested default usage scenario is the following: | |||
// | |||
// #if DEBUG | |||
// #define DBC_CHECK_ALL | |||
// #else | |||
// #define DBC_CHECK_PRECONDITION | |||
// #endif | |||
// | |||
// Alternatively, you can define these in the project properties dialog. | |||
#if DEBUG && !PROFILER | |||
#define DBC_CHECK_ALL | |||
#endif | |||
using System; | |||
using System.Diagnostics; | |||
namespace DesignByContract | |||
{ | |||
/// <summary> | |||
/// Design By Contract Checks. | |||
/// | |||
/// Each method generates an exception or | |||
/// a trace assertion statement if the contract is broken. | |||
/// </summary> | |||
/// <remarks> | |||
/// This example shows how to call the Require method. | |||
/// Assume DBC_CHECK_PRECONDITION is defined. | |||
/// <code> | |||
/// public void Test(int x) | |||
/// { | |||
/// try | |||
/// { | |||
/// Check.Require(x > 1, "x must be > 1"); | |||
/// } | |||
/// catch (System.Exception ex) | |||
/// { | |||
/// Console.WriteLine(ex.ToString()); | |||
/// } | |||
/// } | |||
/// </code> | |||
/// If you wish to use trace assertion statements, intended for Debug scenarios, | |||
/// rather than exception handling then set | |||
/// | |||
/// <code>Check.UseAssertions = true</code> | |||
/// | |||
/// You can specify this in your application entry point and maybe make it | |||
/// dependent on conditional compilation flags or configuration file settings, e.g., | |||
/// <code> | |||
/// #if DBC_USE_ASSERTIONS | |||
/// Check.UseAssertions = true; | |||
/// #endif | |||
/// </code> | |||
/// You can direct output to a Trace listener. For example, you could insert | |||
/// <code> | |||
/// Trace.Listeners.Clear(); | |||
/// Trace.Listeners.Add(new TextWriterTraceListener(Console.Out)); | |||
/// </code> | |||
/// | |||
/// or direct output to a file or the Event Log. | |||
/// | |||
/// (Note: For ASP.NET clients use the Listeners collection | |||
/// of the Debug, not the Trace, object and, for a Release build, only exception-handling | |||
/// is possible.) | |||
/// </remarks> | |||
/// | |||
public sealed class Check | |||
{ | |||
#region Interface | |||
/// <summary> | |||
/// Precondition check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT"), | |||
Conditional("DBC_CHECK_POSTCONDITION"), | |||
Conditional("DBC_CHECK_PRECONDITION")] | |||
public static void Require(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PreconditionException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Precondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Precondition check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT"), | |||
Conditional("DBC_CHECK_POSTCONDITION"), | |||
Conditional("DBC_CHECK_PRECONDITION")] | |||
public static void Require(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PreconditionException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Precondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Precondition check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT"), | |||
Conditional("DBC_CHECK_POSTCONDITION"), | |||
Conditional("DBC_CHECK_PRECONDITION")] | |||
public static void Require(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PreconditionException("Precondition failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Precondition failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Postcondition check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT"), | |||
Conditional("DBC_CHECK_POSTCONDITION")] | |||
public static void Ensure(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PostconditionException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Postcondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Postcondition check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT"), | |||
Conditional("DBC_CHECK_POSTCONDITION")] | |||
public static void Ensure(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PostconditionException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Postcondition: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Postcondition check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT"), | |||
Conditional("DBC_CHECK_POSTCONDITION")] | |||
public static void Ensure(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new PostconditionException("Postcondition failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Postcondition failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Invariant check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT")] | |||
public static void Invariant(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new InvariantException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Invariant: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Invariant check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT")] | |||
public static void Invariant(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new InvariantException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Invariant: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Invariant check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL"), | |||
Conditional("DBC_CHECK_INVARIANT")] | |||
public static void Invariant(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new InvariantException("Invariant failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Invariant failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Assertion check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL")] | |||
public static void Assert(bool assertion, string message) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new AssertionException(message); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Assertion: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Assertion check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL")] | |||
public static void Assert(bool assertion, string message, Exception inner) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new AssertionException(message, inner); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Assertion: " + message); | |||
} | |||
} | |||
/// <summary> | |||
/// Assertion check. | |||
/// </summary> | |||
[Conditional("DBC_CHECK_ALL")] | |||
public static void Assert(bool assertion) | |||
{ | |||
if (UseExceptions) | |||
{ | |||
if (!assertion) | |||
throw new AssertionException("Assertion failed."); | |||
} | |||
else | |||
{ | |||
Trace.Assert(assertion, "Assertion failed."); | |||
} | |||
} | |||
/// <summary> | |||
/// Set this if you wish to use Trace Assert statements | |||
/// instead of exception handling. | |||
/// (The Check class uses exception handling by default.) | |||
/// </summary> | |||
public static bool UseAssertions | |||
{ | |||
get | |||
{ | |||
return useAssertions; | |||
} | |||
set | |||
{ | |||
useAssertions = value; | |||
} | |||
} | |||
#endregion // Interface | |||
#region Implementation | |||
// No creation | |||
private Check() {} | |||
/// <summary> | |||
/// Is exception handling being used? | |||
/// </summary> | |||
private static bool UseExceptions | |||
{ | |||
get | |||
{ | |||
return !useAssertions; | |||
} | |||
} | |||
// Are trace assertion statements being used? | |||
// Default is to use exception handling. | |||
private static bool useAssertions = false; | |||
#endregion // Implementation | |||
} // End Check | |||
internal class Trace | |||
{ | |||
internal static void Assert(bool assertion, string v) | |||
{ | |||
#if NETFX_CORE | |||
System.Diagnostics.Contracts.Contract.Assert(assertion, v); | |||
#else | |||
System.Diagnostics.Trace.Assert(assertion, v); | |||
#endif | |||
} | |||
} | |||
#region Exceptions | |||
/// <summary> | |||
/// Exception raised when a contract is broken. | |||
/// Catch this exception type if you wish to differentiate between | |||
/// any DesignByContract exception and other runtime exceptions. | |||
/// | |||
/// </summary> | |||
public class DesignByContractException : Exception | |||
{ | |||
protected DesignByContractException() {} | |||
protected DesignByContractException(string message) : base(message) {} | |||
protected DesignByContractException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when a precondition fails. | |||
/// </summary> | |||
public class PreconditionException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Precondition Exception. | |||
/// </summary> | |||
public PreconditionException() {} | |||
/// <summary> | |||
/// Precondition Exception. | |||
/// </summary> | |||
public PreconditionException(string message) : base(message) {} | |||
/// <summary> | |||
/// Precondition Exception. | |||
/// </summary> | |||
public PreconditionException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when a postcondition fails. | |||
/// </summary> | |||
public class PostconditionException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Postcondition Exception. | |||
/// </summary> | |||
public PostconditionException() {} | |||
/// <summary> | |||
/// Postcondition Exception. | |||
/// </summary> | |||
public PostconditionException(string message) : base(message) {} | |||
/// <summary> | |||
/// Postcondition Exception. | |||
/// </summary> | |||
public PostconditionException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when an invariant fails. | |||
/// </summary> | |||
public class InvariantException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Invariant Exception. | |||
/// </summary> | |||
public InvariantException() {} | |||
/// <summary> | |||
/// Invariant Exception. | |||
/// </summary> | |||
public InvariantException(string message) : base(message) {} | |||
/// <summary> | |||
/// Invariant Exception. | |||
/// </summary> | |||
public InvariantException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
/// <summary> | |||
/// Exception raised when an assertion fails. | |||
/// </summary> | |||
public class AssertionException : DesignByContractException | |||
{ | |||
/// <summary> | |||
/// Assertion Exception. | |||
/// </summary> | |||
public AssertionException() {} | |||
/// <summary> | |||
/// Assertion Exception. | |||
/// </summary> | |||
public AssertionException(string message) : base(message) {} | |||
/// <summary> | |||
/// Assertion Exception. | |||
/// </summary> | |||
public AssertionException(string message, Exception inner) : base(message, inner) {} | |||
} | |||
#endregion // Exception classes | |||
} // End Design By Contract |
@@ -1,99 +0,0 @@ | |||
using System.Text; | |||
public static class FastConcatUtility | |||
{ | |||
static readonly StringBuilder _stringBuilder = new StringBuilder(256); | |||
public static string FastConcat<T>(this string str1, T str2) | |||
{ | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append(str1); | |||
_stringBuilder.Append(str2); | |||
return _stringBuilder.ToString(); | |||
} | |||
} | |||
public static string FastConcat(this string str1, string str2, string str3) | |||
{ | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append(str1); | |||
_stringBuilder.Append(str2); | |||
_stringBuilder.Append(str3); | |||
return _stringBuilder.ToString(); | |||
} | |||
} | |||
public static string FastConcat(this string str1, string str2, string str3, string str4) | |||
{ | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append(str1); | |||
_stringBuilder.Append(str2); | |||
_stringBuilder.Append(str3); | |||
_stringBuilder.Append(str4); | |||
return _stringBuilder.ToString(); | |||
} | |||
} | |||
public static string FastConcat(this string str1, string str2, string str3, string str4, string str5) | |||
{ | |||
lock (_stringBuilder) | |||
{ | |||
_stringBuilder.Length = 0; | |||
_stringBuilder.Append(str1); | |||
_stringBuilder.Append(str2); | |||
_stringBuilder.Append(str3); | |||
_stringBuilder.Append(str4); | |||
_stringBuilder.Append(str5); | |||
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 | |||
{ | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
#endif | |||
} |
@@ -1,14 +0,0 @@ | |||
namespace Utility | |||
{ | |||
public enum LogType | |||
{ | |||
Log, | |||
Exception, | |||
Warning, | |||
Error | |||
} | |||
public interface ILogger | |||
{ | |||
void Log (string txt, string stack = null, LogType type = LogType.Log); | |||
} | |||
} |
@@ -1,120 +0,0 @@ | |||
using System; | |||
using System.IO; | |||
/// <summary> | |||
/// Murmur hash. | |||
/// | |||
/// Creates an evenly destributed uint hash from a string. | |||
/// Very fast and fairly unique | |||
/// </summary> | |||
public class Murmur3 | |||
{ | |||
static public uint MurmurHash3_x86_32(byte[] data, uint length, uint seed) | |||
{ | |||
uint nblocks = length >> 2; | |||
uint h1 = seed; | |||
const uint c1 = 0xcc9e2d51; | |||
const uint c2 = 0x1b873593; | |||
//---------- | |||
// body | |||
int i = 0 ; | |||
for (uint j = nblocks; j > 0 ; --j) | |||
{ | |||
uint k1l = BitConverter.ToUInt32(data, i); | |||
k1l *= c1; | |||
k1l = rotl32(k1l, 15); | |||
k1l *= c2; | |||
h1 ^= k1l; | |||
h1 = rotl32(h1, 13); | |||
h1 = h1 * 5 + 0xe6546b64; | |||
i+=4; | |||
} | |||
//---------- | |||
// tail | |||
nblocks <<= 2; | |||
uint k1 = 0; | |||
uint tailLength = length & 3; | |||
if (tailLength == 3) | |||
k1 ^= (uint)data[2 + nblocks] << 16; | |||
if (tailLength >= 2) | |||
k1 ^= (uint)data[1 + nblocks] << 8; | |||
if (tailLength >= 1) | |||
{ | |||
k1 ^= data[nblocks]; | |||
k1 *= c1; k1 = rotl32(k1, 15); k1 *= c2; h1 ^= k1; | |||
} | |||
//---------- | |||
// finalization | |||
h1 ^= length; | |||
h1 = fmix32(h1); | |||
return h1; | |||
} | |||
static uint fmix32(uint h) | |||
{ | |||
h ^= h >> 16; | |||
h *= 0x85ebca6b; | |||
h ^= h >> 13; | |||
h *= 0xc2b2ae35; | |||
h ^= h >> 16; | |||
return h; | |||
} | |||
static uint rotl32(uint x, byte r) | |||
{ | |||
return (x << r) | (x >> (32 - r)); | |||
} | |||
static public bool VerificationTest() | |||
{ | |||
byte[] key = new byte[256]; | |||
byte[] hashes = new byte[1024]; | |||
for (uint i = 0; i < 256; i++) | |||
{ | |||
key[i] = (byte)i; | |||
uint result = MurmurHash3_x86_32(key, i, 256 - i); | |||
Buffer.BlockCopy(BitConverter.GetBytes(result), 0, hashes, (int)i * 4, 4); | |||
} | |||
// Then hash the result array | |||
uint finalr = MurmurHash3_x86_32(hashes, 1024, 0); | |||
uint verification = 0xB0F57EE3; | |||
//---------- | |||
if (verification != finalr) | |||
{ | |||
return false; | |||
} | |||
else | |||
{ | |||
System.Diagnostics.Debug.WriteLine("works"); | |||
return true; | |||
} | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
public static class NetFXCoreWrappers | |||
{ | |||
public static MethodInfo GetMethodInfoEx(this Delegate delegateEx) | |||
{ | |||
#if NETFX_CORE | |||
var method = delegateEx.GetMethodInfo(); | |||
#else | |||
var method = delegateEx.Method; | |||
#endif | |||
return method; | |||
} | |||
public static Type GetDeclaringType(this MethodInfo methodInfo) | |||
{ | |||
#if NETFX_CORE | |||
return methodInfo.DeclaringType; | |||
#else | |||
return methodInfo.ReflectedType; | |||
#endif | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
namespace Utility | |||
{ | |||
public class SimpleLogger : ILogger | |||
{ | |||
public void Log(string txt, string stack = null, LogType type = LogType.Log) | |||
{ | |||
switch (type) | |||
{ | |||
case LogType.Log: | |||
Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); | |||
break; | |||
case LogType.Exception: | |||
Console.SystemLog("Log of exceptions not supported"); | |||
break; | |||
case LogType.Warning: | |||
Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); | |||
break; | |||
case LogType.Error: | |||
Console.SystemLog(stack != null ? txt.FastConcat(stack) : txt); | |||
break; | |||
} | |||
} | |||
} | |||
} |
@@ -1,26 +0,0 @@ | |||
#if UNITY_5_3_OR_NEWER || UNITY_5 | |||
namespace Utility | |||
{ | |||
public class SlowLoggerUnity : 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; | |||
} | |||
} | |||
} | |||
} | |||
#endif |
@@ -1,47 +0,0 @@ | |||
using System; | |||
public static class SafeEvent | |||
{ | |||
public static void SafeRaise<T>(this Action<T> onEvent, T val) | |||
{ | |||
if (onEvent != null) | |||
{ | |||
var length = onEvent.GetInvocationList().Length; | |||
for (int index = 0; index < length; index++) | |||
{ | |||
Action<T> handler = (Action<T>) onEvent.GetInvocationList()[index]; | |||
try | |||
{ | |||
if (handler != null) handler.Invoke(val); | |||
} | |||
catch (Exception e) | |||
{ | |||
Utility.Console.LogException(e); | |||
} | |||
} | |||
} | |||
} | |||
public static void SafeRaise(this Action onEvent) | |||
{ | |||
if (onEvent != null) | |||
{ | |||
var length = onEvent.GetInvocationList().Length; | |||
for (int index = 0; index < length; index++) | |||
{ | |||
Action handler = (Action)onEvent.GetInvocationList()[index]; | |||
try | |||
{ | |||
if (handler != null) handler.Invoke(); | |||
} | |||
catch (Exception e) | |||
{ | |||
Utility.Console.LogException(e); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
@@ -1,92 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
namespace Svelto.WeakEvents | |||
{ | |||
public class WeakAction<T1, T2> : WeakAction | |||
{ | |||
public WeakAction(Action<T1, T2> listener) | |||
: base(listener.Target, listener.GetMethodInfoEx()) | |||
{} | |||
public void Invoke(T1 data1, T2 data2) | |||
{ | |||
_data[0] = data1; | |||
_data[1] = data2; | |||
Invoke_Internal(_data); | |||
} | |||
readonly object[] _data = new object[2]; | |||
} | |||
public class WeakAction<T> : WeakActionBase | |||
{ | |||
public WeakAction(Action<T> listener) | |||
: base(listener.Target, listener.GetMethodInfoEx()) | |||
{} | |||
public void Invoke(T data) | |||
{ | |||
_data[0] = data; | |||
Invoke_Internal(_data); | |||
} | |||
readonly object[] _data = new object[1]; | |||
} | |||
public class WeakAction : WeakActionBase | |||
{ | |||
public WeakAction(Action listener) : base(listener) | |||
{} | |||
public WeakAction(object listener, MethodInfo method) : base(listener, method) | |||
{} | |||
public void Invoke() | |||
{ | |||
Invoke_Internal(null); | |||
} | |||
} | |||
public abstract class WeakActionBase | |||
{ | |||
protected readonly DataStructures.WeakReference<object> ObjectRef; | |||
protected readonly MethodInfo Method; | |||
public bool IsValid | |||
{ | |||
get { return ObjectRef.IsValid; } | |||
} | |||
protected WeakActionBase(Action listener) | |||
: this(listener.Target, listener.GetMethodInfoEx()) | |||
{} | |||
protected WeakActionBase(object listener, MethodInfo method) | |||
{ | |||
ObjectRef = new DataStructures.WeakReference<object>(listener); | |||
Method = method; | |||
#if NETFX_CORE | |||
var attributes = (CompilerGeneratedAttribute[])method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); | |||
if (attributes.Length != 0) | |||
throw new ArgumentException("Cannot create weak event to anonymous method with closure."); | |||
#else | |||
if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) | |||
throw new ArgumentException("Cannot create weak event to anonymous method with closure."); | |||
#endif | |||
} | |||
protected void Invoke_Internal(object[] data) | |||
{ | |||
if (ObjectRef.IsValid) | |||
Method.Invoke(ObjectRef.Target, data); | |||
else | |||
Utility.Console.LogWarning("Target of weak action has been garbage collected"); | |||
} | |||
} | |||
} |
@@ -1,154 +0,0 @@ | |||
using System; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
//careful, you must handle the destruction of the GCHandles! | |||
namespace Svelto.WeakEvents | |||
{ | |||
public struct WeakActionStruct<T1, T2> : IEquatable<WeakActionStruct<T1, T2>>, IDisposable | |||
{ | |||
public WeakActionStruct(Action<T1, T2> listener) | |||
{ | |||
WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), out _objectRef, out _method); | |||
} | |||
public bool Invoke(object[] args) | |||
{ | |||
return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); | |||
} | |||
public bool Equals(WeakActionStruct<T1, T2> other) | |||
{ | |||
return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, | |||
other._objectRef.Target, other._method); | |||
} | |||
public void Dispose() | |||
{ | |||
_objectRef.Free(); | |||
} | |||
public bool IsMatch(object otherObject, MethodInfo otherMethod) | |||
{ | |||
return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, | |||
otherObject, otherMethod); | |||
} | |||
GCHandle _objectRef; | |||
readonly MethodInfo _method; | |||
} | |||
public struct WeakActionStruct<T> : IEquatable<WeakActionStruct<T>>, IDisposable | |||
{ | |||
public WeakActionStruct(Action<T> listener) | |||
{ | |||
WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), | |||
out _objectRef, out _method); | |||
} | |||
public bool Invoke(object[] args) | |||
{ | |||
return WeakActionStructUtility.Invoke(ref _objectRef, _method, args); | |||
} | |||
public bool Equals(WeakActionStruct<T> other) | |||
{ | |||
return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, | |||
other._objectRef.Target, other._method); | |||
} | |||
public void Dispose() | |||
{ | |||
_objectRef.Free(); | |||
} | |||
public bool IsMatch(object otherObject, MethodInfo otherMethod) | |||
{ | |||
return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, | |||
otherObject, otherMethod); | |||
} | |||
GCHandle _objectRef; | |||
readonly MethodInfo _method; | |||
} | |||
public struct WeakActionStruct : IEquatable<WeakActionStruct>, IDisposable | |||
{ | |||
public WeakActionStruct(Action listener) | |||
{ | |||
WeakActionStructUtility.Init(listener.Target, listener.GetMethodInfoEx(), | |||
out _objectRef, out _method); | |||
} | |||
public bool Invoke() | |||
{ | |||
return WeakActionStructUtility.Invoke(ref _objectRef, _method, null); | |||
} | |||
public bool Equals(WeakActionStruct other) | |||
{ | |||
return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, | |||
other._objectRef.Target, other._method); | |||
} | |||
public void Dispose() | |||
{ | |||
_objectRef.Free(); | |||
} | |||
public bool IsMatch(object otherObject, MethodInfo otherMethod) | |||
{ | |||
return WeakActionStructUtility.IsMatch(_objectRef.Target, _method, | |||
otherObject, otherMethod); | |||
} | |||
GCHandle _objectRef; | |||
readonly MethodInfo _method; | |||
} | |||
static class WeakActionStructUtility | |||
{ | |||
internal static void Init(object target, MethodInfo method, | |||
out GCHandle objectRef, out MethodInfo methodOut) | |||
{ | |||
objectRef = GCHandle.Alloc(target, GCHandleType.Weak); | |||
methodOut = method; | |||
#if DEBUG && !PROFILER | |||
#if NETFX_CORE | |||
Method = listener.GetMethodInfo(); | |||
var attributes = (CompilerGeneratedAttribute[])Method.GetType().GetTypeInfo().GetCustomAttributes(typeof(CompilerGeneratedAttribute), false); | |||
if(attributes.Length != 0) | |||
throw new ArgumentException("Cannot create weak event to anonymous method with closure."); | |||
#else | |||
if (method.DeclaringType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Length != 0) | |||
throw new ArgumentException("Cannot create weak event to anonymous method with closure."); | |||
#endif | |||
#endif | |||
} | |||
public static bool Invoke(ref GCHandle objectRef, MethodInfo method, object[] args) | |||
{ | |||
if (objectRef.IsAllocated && objectRef.Target != null) | |||
{ | |||
method.Invoke(objectRef.Target, args); | |||
return true; | |||
} | |||
Dispose(ref objectRef); | |||
return false; | |||
} | |||
public static void Dispose(ref GCHandle objectRef) | |||
{ | |||
objectRef.Free(); | |||
} | |||
public static bool IsMatch(object objectRef, MethodInfo method, | |||
object _objectRef, MethodInfo _method) | |||
{ | |||
return _method.Equals(method) && objectRef.Equals(_objectRef); | |||
} | |||
} | |||
} |
@@ -1,163 +0,0 @@ | |||
using Svelto.DataStructures; | |||
using System; | |||
using System.Reflection; | |||
namespace Svelto.WeakEvents | |||
{ | |||
public class WeakEvent | |||
{ | |||
public static WeakEvent operator+(WeakEvent c1, Action x) | |||
{ | |||
if (c1 == null) c1 = new WeakEvent(); | |||
c1._subscribers.Add(new WeakActionStruct(x)); | |||
return c1; | |||
} | |||
public static WeakEvent operator-(WeakEvent c1, Action x) | |||
{ | |||
DesignByContract.Check.Require(x != null); | |||
c1.Remove(x.Target, x.GetMethodInfoEx()); | |||
return c1; | |||
} | |||
public void Invoke() | |||
{ | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
if (_subscribers[i].Invoke() == false) | |||
_subscribers.UnorderedRemoveAt(i--); | |||
} | |||
void Remove(object thisObject, MethodInfo thisMethod) | |||
{ | |||
for (int i = 0; i < _subscribers.Count; ++i) | |||
{ | |||
var otherObject = _subscribers[i]; | |||
if (otherObject.IsMatch(thisObject, thisMethod)) | |||
{ | |||
_subscribers.UnorderedRemoveAt(i); | |||
break; | |||
} | |||
} | |||
} | |||
~WeakEvent() | |||
{ | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
_subscribers[i].Dispose(); | |||
} | |||
readonly FasterList<WeakActionStruct> | |||
_subscribers = new FasterList<WeakActionStruct>(); | |||
} | |||
public class WeakEvent<T1> | |||
{ | |||
public static WeakEvent<T1> operator+(WeakEvent<T1> c1, Action<T1> x) | |||
{ | |||
if (c1 == null) c1 = new WeakEvent<T1>(); | |||
c1._subscribers.Add(new WeakActionStruct<T1>(x)); | |||
return c1; | |||
} | |||
public static WeakEvent<T1> operator-(WeakEvent<T1> c1, Action<T1> x) | |||
{ | |||
DesignByContract.Check.Require(x != null); | |||
c1.Remove(x.Target, x.GetMethodInfoEx()); | |||
return c1; | |||
} | |||
public void Invoke(T1 arg1) | |||
{ | |||
args[0] = arg1; | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
if (_subscribers[i].Invoke(args) == false) | |||
_subscribers.UnorderedRemoveAt(i--); | |||
} | |||
void Remove(object thisObject, MethodInfo thisMethod) | |||
{ | |||
for (int i = 0; i < _subscribers.Count; ++i) | |||
{ | |||
var otherObject = _subscribers[i]; | |||
if (otherObject.IsMatch(thisObject, thisMethod)) | |||
{ | |||
_subscribers.UnorderedRemoveAt(i); | |||
break; | |||
} | |||
} | |||
} | |||
~WeakEvent() | |||
{ | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
_subscribers[i].Dispose(); | |||
} | |||
readonly object[] args = new object[1]; | |||
readonly FasterList<WeakActionStruct<T1>> | |||
_subscribers = new FasterList<WeakActionStruct<T1>>(); | |||
} | |||
public class WeakEvent<T1, T2> | |||
{ | |||
public static WeakEvent<T1, T2> operator+(WeakEvent<T1, T2> c1, Action<T1, T2> x) | |||
{ | |||
if (c1 == null) c1 = new WeakEvent<T1, T2>(); | |||
c1._subscribers.Add(new WeakActionStruct<T1, T2>(x)); | |||
return c1; | |||
} | |||
public static WeakEvent<T1, T2> operator-(WeakEvent<T1, T2> c1, Action<T1, T2> x) | |||
{ | |||
DesignByContract.Check.Require(x != null); | |||
c1.Remove(x.Target, x.GetMethodInfoEx()); | |||
return c1; | |||
} | |||
public void Invoke(T1 arg1, T2 arg2) | |||
{ | |||
args[0] = arg1; | |||
args[1] = arg2; | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
if (_subscribers[i].Invoke(args) == false) | |||
_subscribers.UnorderedRemoveAt(i--); | |||
} | |||
void Remove(object thisObject, MethodInfo thisMethod) | |||
{ | |||
for (int i = 0; i < _subscribers.Count; ++i) | |||
{ | |||
var otherObject = _subscribers[i]; | |||
if (otherObject.IsMatch(thisObject, thisMethod)) | |||
{ | |||
_subscribers.UnorderedRemoveAt(i); | |||
break; | |||
} | |||
} | |||
} | |||
~WeakEvent() | |||
{ | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
_subscribers[i].Dispose(); | |||
} | |||
readonly object[] args = new object[2]; | |||
readonly FasterList<WeakActionStruct<T1, T2>> | |||
_subscribers = new FasterList<WeakActionStruct<T1, T2>>(); | |||
} | |||
} |