@@ -9,7 +9,7 @@ namespace Svelto.DataStructures | |||
// isn't taken into account (we would have to do a shift in both arrays) | |||
// Could be added as an option? | |||
class CircularBufferIndexer<TKey, TVal> : IDictionary<TKey, TVal> | |||
public class CircularBufferIndexer<TKey, TVal> : IDictionary<TKey, TVal> | |||
{ | |||
public ICollection<TKey> Keys | |||
{ | |||
@@ -352,12 +352,12 @@ namespace Svelto.DataStructures | |||
} | |||
} | |||
public void UnorderredRemoveAt(int index) | |||
public void UnorderedRemoveAt(int index) | |||
{ | |||
_lockQ.EnterWriteLock(); | |||
try | |||
{ | |||
_list.UnorderredRemoveAt(index); | |||
_list.UnorderedRemoveAt(index); | |||
} | |||
finally | |||
{ | |||
@@ -450,10 +450,12 @@ namespace Svelto.DataStructures | |||
readonly FasterList<T> _list; | |||
} | |||
public class FasterList<T> : IList<T> | |||
public interface IFasterList | |||
{} | |||
public class FasterList<T> : IList<T>, IFasterList | |||
{ | |||
public static FasterList<T> DefaultList = new FasterList<T>(); | |||
const int MIN_SIZE = 4; | |||
public int Count | |||
@@ -567,6 +569,11 @@ namespace Svelto.DataStructures | |||
_count += count; | |||
} | |||
public void AddRange(T[] items) | |||
{ | |||
AddRange(items, items.Length); | |||
} | |||
public FasterReadOnlyList<T> AsReadOnly() | |||
{ | |||
return new FasterReadOnlyList<T>(this); | |||
@@ -703,32 +710,30 @@ namespace Svelto.DataStructures | |||
return _buffer; | |||
} | |||
public bool UnorderredRemove(T item) | |||
public bool UnorderedRemove(T item) | |||
{ | |||
var index = IndexOf(item); | |||
if (index == -1) | |||
return false; | |||
UnorderredRemoveAt(index); | |||
UnorderedRemoveAt(index); | |||
return true; | |||
} | |||
public T UnorderredRemoveAt(int index) | |||
public bool UnorderedRemoveAt(int index) | |||
{ | |||
DesignByContract.Check.Require(index < _count && _count > 0, "out of bound index"); | |||
T item = _buffer[index]; | |||
if (index == --_count) | |||
return item; | |||
return false; | |||
T swap = _buffer[index]; | |||
_buffer[index] = _buffer[_count]; | |||
_buffer[_count] = swap; | |||
return item; | |||
return true; | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
@@ -13,9 +13,9 @@ namespace Svelto.DataStructures | |||
public sealed class HeapPriorityQueue<T> : IPriorityQueue<T> | |||
where T : PriorityQueueNode | |||
{ | |||
int _numNodes; | |||
private readonly FasterList<T> _nodes; | |||
long _numNodesEverEnqueued; | |||
private int _numNodes; | |||
private readonly FasterList<T> _nodes; | |||
private long _numNodesEverEnqueued; | |||
/// <summary> | |||
/// Instantiate a new Priority Queue | |||
@@ -101,10 +101,10 @@ namespace Svelto.DataStructures | |||
CascadeUp(_nodes[_numNodes]); | |||
} | |||
#if NET_VERSION_4_5 | |||
#if NET_VERSION_4_5 | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
#endif | |||
void Swap(T node1, T node2) | |||
#endif | |||
private void Swap(T node1, T node2) | |||
{ | |||
//Swap the nodes | |||
_nodes[node1.QueueIndex] = node2; | |||
@@ -117,14 +117,14 @@ namespace Svelto.DataStructures | |||
} | |||
//Performance appears to be slightly better when this is NOT inlined o_O | |||
void CascadeUp(T node) | |||
private void CascadeUp(T node) | |||
{ | |||
//aka Heapify-up | |||
int parent = node.QueueIndex / 2; | |||
while (parent >= 1) | |||
while(parent >= 1) | |||
{ | |||
T parentNode = _nodes[parent]; | |||
if (HasHigherPriority(parentNode, node)) | |||
if(HasHigherPriority(parentNode, node)) | |||
break; | |||
//Node has lower priority value, so move it up the heap | |||
@@ -134,9 +134,9 @@ namespace Svelto.DataStructures | |||
} | |||
} | |||
#if NET_VERSION_4_5 | |||
#if NET_VERSION_4_5 | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
#endif | |||
#endif | |||
private void CascadeDown(T node) | |||
{ | |||
//aka Heapify-down | |||
@@ -198,10 +198,10 @@ namespace Svelto.DataStructures | |||
/// 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 | |||
#if NET_VERSION_4_5 | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
#endif | |||
bool HasHigherPriority(T higher, T lower) | |||
#endif | |||
private bool HasHigherPriority(T higher, T lower) | |||
{ | |||
return (higher.Priority < lower.Priority || | |||
(higher.Priority == lower.Priority && higher.InsertionIndex < lower.InsertionIndex)); | |||
@@ -242,13 +242,13 @@ namespace Svelto.DataStructures | |||
OnNodeUpdated(node); | |||
} | |||
void OnNodeUpdated(T 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)) | |||
if(parentIndex > 0 && HasHigherPriority(node, parentNode)) | |||
{ | |||
CascadeUp(node); | |||
} | |||
@@ -1,77 +1,71 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
class EngineNodeDB : IEngineNodeDB | |||
public class EngineNodeDB : IEngineNodeDB | |||
{ | |||
internal EngineNodeDB( Dictionary<Type, FasterList<INode>> nodesDB, | |||
Dictionary<Type, Dictionary<int, INode>> nodesDBdic, | |||
Dictionary<Type, FasterList<INode>> nodesDBgroups) | |||
Dictionary<Type, FasterList<INode>> metaNodesDB, | |||
Dictionary<Type, IStructGroupNodes> structNodesDB) | |||
{ | |||
_nodesDB = new DataStructures.WeakReference<Dictionary<Type, FasterList<INode>>>(nodesDB); | |||
_nodesDBdic = new DataStructures.WeakReference<Dictionary<Type, Dictionary<int, INode>>>(nodesDBdic); | |||
_nodesDBgroups = new DataStructures.WeakReference<Dictionary<Type, FasterList<INode>>>(nodesDBgroups); | |||
_nodesDB = nodesDB; | |||
_nodesDBdic = nodesDBdic; | |||
_metaNodesDB = metaNodesDB; | |||
_structNodesDB = structNodesDB; | |||
} | |||
public FasterReadOnlyListCast<INode, T> QueryNodes<T>() where T:INode | |||
{ | |||
var type = typeof(T); | |||
if (_nodesDB.IsValid == false || _nodesDB.Target.ContainsKey(type) == false) | |||
if (_nodesDB.ContainsKey(type) == false) | |||
return RetrieveEmptyNodeList<T>(); | |||
return new FasterReadOnlyListCast<INode, T>(_nodesDB.Target[type]); | |||
return new FasterReadOnlyListCast<INode, T>(_nodesDB[type]); | |||
} | |||
/* public FasterReadOnlyList<T> QueryStructNodes<T>() where T:struct | |||
{ | |||
var type = typeof(T); | |||
if (_nodesDBStructs.ContainsKey(type) == false) | |||
return RetrieveEmptyStructNodeList<T>(); | |||
return new FasterReadOnlyList<T>(((StructNodeList<T>)(_nodesDBStructs[type])).list); | |||
}*/ | |||
public ReadOnlyDictionary<int, INode> QueryIndexableNodes<T>() where T:INode | |||
{ | |||
var type = typeof(T); | |||
if (_nodesDB.IsValid == false || _nodesDBdic.Target.ContainsKey(type) == false) | |||
if (_nodesDBdic.ContainsKey(type) == false) | |||
return _defaultEmptyNodeDict; | |||
return new ReadOnlyDictionary<int, INode>(_nodesDBdic.Target[type]); | |||
return new ReadOnlyDictionary<int, INode>(_nodesDBdic[type]); | |||
} | |||
public T QueryNodeFromGroup<T>(int groupID) where T : INode | |||
public T QueryMetaNode<T>(int metaEntityID) where T : INode | |||
{ | |||
return QueryNode<T>(groupID); | |||
return QueryNode<T>(metaEntityID); | |||
} | |||
public bool QueryNodeFromGroup<T>(int groupID, out T node) where T : INode | |||
public bool TryQueryMetaNode<T>(int metaEntityID, out T node) where T : INode | |||
{ | |||
return QueryNode<T>(groupID, out node); | |||
return TryQueryNode(metaEntityID, out node); | |||
} | |||
public FasterReadOnlyListCast<INode, T> QueryNodesFromGroups<T>() where T : INode | |||
public FasterReadOnlyListCast<INode, T> QueryMetaNodes<T>() where T : INode | |||
{ | |||
var type = typeof(T); | |||
if (_nodesDBgroups.IsValid == false || _nodesDBgroups.Target.ContainsKey(type) == false) | |||
if (_metaNodesDB.ContainsKey(type) == false) | |||
return RetrieveEmptyNodeList<T>(); | |||
return new FasterReadOnlyListCast<INode, T>(_nodesDBgroups.Target[type]); | |||
return new FasterReadOnlyListCast<INode, T>(_metaNodesDB[type]); | |||
} | |||
public bool QueryNode<T>(int ID, out T node) where T:INode | |||
public bool TryQueryNode<T>(int ID, out T node) where T:INode | |||
{ | |||
var type = typeof(T); | |||
INode internalNode; | |||
if (_nodesDBdic.IsValid && _nodesDBdic.Target.ContainsKey(type) && _nodesDBdic.Target[type].TryGetValue(ID, out internalNode)) | |||
if (_nodesDBdic.ContainsKey(type) && | |||
_nodesDBdic[type].TryGetValue(ID, out internalNode)) | |||
{ | |||
node = (T)internalNode; | |||
@@ -89,39 +83,33 @@ namespace Svelto.ECS | |||
INode internalNode; | |||
if (_nodesDBdic.IsValid && _nodesDBdic.Target.ContainsKey(type) && _nodesDBdic.Target[type].TryGetValue(ID, out internalNode)) | |||
if (_nodesDBdic.ContainsKey(type) && | |||
_nodesDBdic[type].TryGetValue(ID, out internalNode)) | |||
return (T)internalNode; | |||
throw new Exception("Node Not Found"); | |||
} | |||
static FasterReadOnlyListCast<INode, T> RetrieveEmptyNodeList<T>() where T : INode | |||
public FasterReadOnlyListCast<INode, T> QueryGroupNodes<T>(int groupID) where T : INode | |||
{ | |||
return new FasterReadOnlyListCast<INode, T>(FasterList<INode>.DefaultList); | |||
var type = typeof(T); | |||
if (_nodesDB.ContainsKey(type) == false) | |||
return RetrieveEmptyNodeList<T>(); | |||
return new FasterReadOnlyListCast<INode, T>(_nodesDB[type]); | |||
} | |||
static FasterReadOnlyList<T> RetrieveEmptyStructNodeList<T>() where T : struct | |||
static FasterReadOnlyListCast<INode, T> RetrieveEmptyNodeList<T>() where T : INode | |||
{ | |||
return new FasterReadOnlyList<T>(FasterList<T>.DefaultList); | |||
return new FasterReadOnlyListCast<INode, T>(FasterList<INode>.DefaultList); | |||
} | |||
Svelto.DataStructures.WeakReference<Dictionary<Type, FasterList<INode>>> _nodesDB; | |||
Svelto.DataStructures.WeakReference<Dictionary<Type, Dictionary<int, INode>>> _nodesDBdic; | |||
Svelto.DataStructures.WeakReference<Dictionary<Type, FasterList<INode>>> _nodesDBgroups; | |||
// Dictionary<Type, StructNodeList> _nodesDBStructs; | |||
//Dictionary<Type, ThreadSafeFasterList<INode>> _nodesDB; | |||
//Dictionary<Type, ThreadsSafeDictionary<int, INode>> _nodesDBdic; | |||
// Dictionary<Type, ThreadSafeFasterList<INode>> _nodesDBgroups; | |||
readonly Dictionary<Type, FasterList<INode>> _nodesDB; | |||
readonly Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
readonly Dictionary<Type, FasterList<INode>> _metaNodesDB; | |||
readonly Dictionary<Type, IStructGroupNodes> _structNodesDB; | |||
ReadOnlyDictionary<int, INode> _defaultEmptyNodeDict = new ReadOnlyDictionary<int, INode>(new Dictionary<int, INode>()); | |||
class StructNodeList | |||
{ } | |||
class StructNodeList<T> : StructNodeList where T : struct | |||
{ | |||
public FasterList<T> list = new FasterList<T>(); | |||
} | |||
readonly ReadOnlyDictionary<int, INode> _defaultEmptyNodeDict = new ReadOnlyDictionary<int, INode>(new Dictionary<int, INode>()); | |||
} | |||
} |
@@ -2,10 +2,11 @@ using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.NodeSchedulers; | |||
using UnityEngine; | |||
using WeakReference = Svelto.DataStructures.WeakReference<Svelto.ECS.EnginesRoot>; | |||
using Svelto.ECS.NodeSchedulers; | |||
using Svelto.ECS.Internal; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
#endif | |||
@@ -15,25 +16,54 @@ using System.Reflection; | |||
namespace Svelto.ECS | |||
{ | |||
class Scheduler : MonoBehaviour | |||
{ | |||
IEnumerator Start() | |||
{ | |||
while (true) | |||
{ | |||
yield return _waitForEndOfFrame; | |||
OnTick(); | |||
} | |||
} | |||
internal Action OnTick; | |||
readonly WaitForEndOfFrame _waitForEndOfFrame = new WaitForEndOfFrame(); | |||
} | |||
public sealed class EnginesRoot : IEnginesRoot, IEntityFactory | |||
{ | |||
public EnginesRoot(NodeSubmissionScheduler nodeScheduler) | |||
{ | |||
_nodeEngines = new Dictionary<Type, FasterList<INodeEngine>>(); | |||
_nodeEngines = new Dictionary<Type, FasterList<IEngine>>(); | |||
_activableEngines = new Dictionary<Type, FasterList<IEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
_engineRootWeakReference = new WeakReference(this); | |||
_otherEnginesReferences = new FasterList<IEngine>(); | |||
_nodesDB = new Dictionary<Type, FasterList<INode>>(); | |||
_nodesDBdic = new Dictionary<Type, Dictionary<int, INode>>(); | |||
_nodesToAdd = new FasterList<INode>(); | |||
_groupNodesToAdd = new FasterList<INode>(); | |||
_metaNodesToAdd = new FasterList<INode>(); | |||
_metaNodesDB = new Dictionary<Type, FasterList<INode>>(); | |||
_structNodesDB = new Dictionary<Type, IStructGroupNodes>(); | |||
_nodesDBgroups = new Dictionary<Type, FasterList<INode>>(); | |||
_internalRemove = InternalRemove; | |||
_internalDisable = InternalDisable; | |||
_internalEnable = InternalEnable; | |||
_internalMetaRemove = InternalMetaRemove; | |||
_scheduler = nodeScheduler; | |||
_scheduler.Schedule(SubmitNodes); | |||
_activableNodeEngineType = typeof(IActivableNodeEngine<>); | |||
_implementedInterfaceTypes = new Dictionary<Type, Type[]>(); | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
GameObject debugEngineObject = new GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
@@ -42,28 +72,38 @@ namespace Svelto.ECS | |||
void SubmitNodes() | |||
{ | |||
int groupNodesCount; | |||
int nodesCount; | |||
int metaNodesCount = _metaNodesToAdd.Count; | |||
int nodesCount = _nodesToAdd.Count; | |||
if (metaNodesCount + nodesCount == 0) return; | |||
bool newNodesHaveBeenAddedWhileIterating; | |||
int startNodes = 0; | |||
int startGroupNodes = 0; | |||
int startMetaNodes = 0; | |||
int numberOfReenteringLoops = 0; | |||
do | |||
{ | |||
groupNodesCount = _groupNodesToAdd.Count; | |||
nodesCount = _nodesToAdd.Count; | |||
for (int i = startNodes; i < nodesCount; i++) | |||
{ | |||
var node = _nodesToAdd[i]; | |||
AddNodeToTheDB(node, node.GetType()); | |||
var nodeType = node.GetType(); | |||
AddNodeToTheDB(node, nodeType); | |||
var nodeWithId = node as INodeWithID; | |||
if (nodeWithId != null) | |||
AddNodeToNodesDictionary(nodeWithId, nodeType); | |||
} | |||
for (int i = startGroupNodes; i < groupNodesCount; i++) | |||
for (int i = startMetaNodes; i < metaNodesCount; i++) | |||
{ | |||
var node = _groupNodesToAdd[i]; | |||
AddNodeToGroupDB(node, node.GetType()); | |||
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++) | |||
@@ -72,151 +112,223 @@ namespace Svelto.ECS | |||
AddNodeToTheSuitableEngines(node, node.GetType()); | |||
} | |||
for (int i = startGroupNodes; i < groupNodesCount; i++) | |||
for (int i = startMetaNodes; i < metaNodesCount; i++) | |||
{ | |||
var node = _groupNodesToAdd[i]; | |||
var node = _metaNodesToAdd[i]; | |||
AddNodeToTheSuitableEngines(node, node.GetType()); | |||
} | |||
newNodesHaveBeenAddedWhileIterating = _groupNodesToAdd.Count > groupNodesCount || _nodesToAdd.Count > nodesCount; | |||
newNodesHaveBeenAddedWhileIterating = | |||
_metaNodesToAdd.Count > metaNodesCount || | |||
_nodesToAdd.Count > nodesCount; | |||
startNodes = nodesCount; | |||
startGroupNodes = groupNodesCount; | |||
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++; | |||
numberOfReenteringLoops++; | |||
metaNodesCount = _metaNodesToAdd.Count; | |||
nodesCount = _nodesToAdd.Count; | |||
} while (newNodesHaveBeenAddedWhileIterating); | |||
_nodesToAdd.Clear(); | |||
_groupNodesToAdd.Clear(); | |||
_metaNodesToAdd.Clear(); | |||
} | |||
public void AddEngine<T>(INodeEngine<T> engine) where T:class, INode | |||
public void AddEngine(IEngine engine) | |||
{ | |||
AddEngine(new NodeEngineWrapper<T>(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, _structNodesDB); | |||
if (engine is IQueryableNodeEngine) | |||
(engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic, _nodesDBgroups); | |||
} | |||
var engineType = engine.GetType(); | |||
var implementedInterfaces = engineType.GetInterfaces(); | |||
public void AddEngine<T, U>(INodeEngine<T, U> engine) where T:class, INode where U:class, INode | |||
{ | |||
AddEngine(new NodeEngineWrapper<T, U>(engine)); | |||
AddEngine((INodeEngine<U>)(engine)); | |||
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(); | |||
} | |||
public void AddEngine<T, U, V>(INodeEngine<T, U, V> engine) where T:class, INode | |||
where U:class, INode | |||
where V:class, INode | |||
void CollectImplementedInterfaces(Type[] implementedInterfaces) | |||
{ | |||
AddEngine(new NodeEngineWrapper<T, U, V>(engine)); | |||
AddEngine((INodeEngine<U, V>)(engine)); | |||
_implementedInterfaceTypes.Clear(); | |||
for (int index = 0; index < implementedInterfaces.Length; index++) | |||
{ | |||
var interfaceType = implementedInterfaces[index]; | |||
#if !NETFX_CORE | |||
if (false == interfaceType.IsGenericType) | |||
#else | |||
if (false == interfaceType.IsConstructedGenericType) | |||
#endif | |||
{ | |||
continue; | |||
} | |||
var genericTypeDefinition = interfaceType.GetGenericTypeDefinition(); | |||
var a = interfaceType.GetGenericArguments(); | |||
var b = genericTypeDefinition.GetGenericArguments(); | |||
_implementedInterfaceTypes.Add(genericTypeDefinition, | |||
interfaceType.GetGenericArguments()); | |||
} | |||
} | |||
public void AddEngine(IEngine engine) | |||
bool CheckGenericEngines(IEngine engine) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.AddEngine(engine); | |||
#endif | |||
if (engine is IQueryableNodeEngine) | |||
(engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic, _nodesDBgroups); | |||
if (_implementedInterfaceTypes.Count == 0) return false; | |||
if (engine is INodesEngine) | |||
bool engineAdded = false; | |||
Type[] arguments; | |||
if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, | |||
out arguments)) | |||
{ | |||
var nodesEngine = engine as INodesEngine; | |||
AddEngine(engine, arguments, _activableEngines); | |||
AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); | |||
engineAdded = true; | |||
} | |||
else | |||
return engineAdded; | |||
} | |||
bool CheckLegacyNodesEngine(IEngine engine, ref bool engineAdded) | |||
{ | |||
var nodesEngine = engine as INodesEngine; | |||
if (nodesEngine != null) | |||
{ | |||
var engineType = engine.GetType(); | |||
AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); | |||
#if !NETFX_CORE | |||
var baseType = engineType.BaseType; | |||
engineAdded = true; | |||
return true; | |||
} | |||
return false; | |||
} | |||
if (baseType.IsGenericType | |||
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 | |||
&& baseType.GetGenericTypeDefinition() == typeof(SingleNodeEngine<>)) | |||
{ | |||
AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); | |||
} | |||
else | |||
{ | |||
bool found = false; | |||
for (int i = 0, maxLength = engineType.GetInterfaces().Length; i < maxLength; i++) | |||
{ | |||
var type = engineType.GetInterfaces()[i]; | |||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(INodeEngine<>)) | |||
{ | |||
AddEngine(engine as INodeEngine, type.GetGenericArguments(), _nodeEngines); | |||
&& engine is INodeEngine) | |||
{ | |||
AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); | |||
found = true; | |||
} | |||
} | |||
engineAdded = true; | |||
if (found == false) | |||
_otherEnginesReferences.Add(engine); | |||
} | |||
return true; | |||
} | |||
if (engine is ICallBackOnAddEngine) | |||
(engine as ICallBackOnAddEngine).Ready(); | |||
return false; | |||
} | |||
public void BuildEntity(int ID, EntityDescriptor ed) | |||
{ | |||
var entityNodes = ed.BuildNodes(ID, (nodes) => | |||
{ | |||
if (_engineRootWeakReference.IsValid == true) | |||
InternalRemove(nodes); | |||
}); | |||
var entityNodes = ed.BuildNodes(ID, | |||
_internalRemove, | |||
_internalEnable, | |||
_internalDisable | |||
); | |||
_nodesToAdd.AddRange(entityNodes); | |||
} | |||
/// <summary> | |||
/// An entity group is a meta entity. It's a way to create a set of entitites that | |||
/// are not easily queriable otherwise. For example you may group existing entities | |||
/// by size and type and then use the groupID to retrieve a single node that is shared | |||
/// among the single entities of the same type and size. This willwd prevent the scenario | |||
/// where the coder is forced to parse all the entities to find the ones of the same | |||
/// size and type. Since the entity group is managed through the shared node, the same | |||
/// 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 is then used by engines that are meant to manage a group of entities | |||
/// through a single node. The same engine can manage several groups of entitites. | |||
/// 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 BuildEntityGroup(int groupID, EntityDescriptor ed) | |||
public void BuildEntityInGroup(int entityID, int groupID, | |||
EntityDescriptor ed) | |||
{ | |||
var entityNodes = ed.BuildNodes(groupID, (nodes) => | |||
{ | |||
if (_engineRootWeakReference.IsValid == true) | |||
InternalGroupRemove(nodes); | |||
}); | |||
var entityNodes = ed.BuildNodes(entityID, | |||
_internalRemove, | |||
_internalEnable, | |||
_internalDisable | |||
); | |||
_nodesToAdd.AddRange(entityNodes); | |||
_groupNodesToAdd.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(INodeEngine engine, Type[] types, Dictionary<Type, FasterList<INodeEngine>> engines) | |||
static void AddEngine(IEngine engine, Type[] types, | |||
Dictionary<Type, FasterList<IEngine>> engines) | |||
{ | |||
for (int i = 0; i < types.Length; i++) | |||
{ | |||
FasterList<INodeEngine> list; | |||
FasterList<IEngine> list; | |||
var type = types[i]; | |||
if (engines.TryGetValue(type, out list) == false) | |||
{ | |||
list = new FasterList<INodeEngine>(); | |||
list = new FasterList<IEngine>(); | |||
engines.Add(type, list); | |||
} | |||
@@ -225,136 +337,223 @@ namespace Svelto.ECS | |||
} | |||
} | |||
void AddNodeToGroupDB(INode node, Type nodeType) | |||
void AddNodeToMetaDB(INode node, Type nodeType) | |||
{ | |||
FasterList<INode> nodes; | |||
if (_nodesDBgroups.TryGetValue(nodeType, out nodes) == false) | |||
nodes = _nodesDBgroups[nodeType] = new FasterList<INode>(); | |||
if (_metaNodesDB.TryGetValue(nodeType, out nodes) == false) | |||
nodes = _metaNodesDB[nodeType] = new FasterList<INode>(); | |||
nodes.Add(node); | |||
AddNodeToNodesDictionary(node, nodeType); | |||
} | |||
void AddNodeToTheDB(INode node, Type nodeType) | |||
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); | |||
if (node is IStructNodeWithID == false) | |||
{ | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == false) | |||
nodes = _nodesDB[nodeType] = new FasterList<INode>(); | |||
AddNodeToNodesDictionary(node, nodeType); | |||
nodes.Add(node); | |||
} | |||
else | |||
{ | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == false) | |||
nodes = _nodesDB[nodeType] = new FasterList<INode>(); | |||
} | |||
} | |||
void AddNodeToNodesDictionary(INode node, Type nodeType) | |||
void AddNodeToNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID | |||
{ | |||
if (node is NodeWithID) | |||
{ | |||
Dictionary<int, INode> nodesDic; | |||
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) | |||
nodesDic = _nodesDBdic[nodeType] = new Dictionary<int, INode>(); | |||
Dictionary<int, INode> nodesDic; | |||
nodesDic[(node as NodeWithID).ID] = node; | |||
} | |||
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<INodeEngine> enginesForNode; | |||
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(AddNodeToEngine, enginesForNode[j], node); | |||
EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j] as INodeEngine, node); | |||
#else | |||
enginesForNode[j].Add(node); | |||
(enginesForNode[j] as INodeEngine).Add(node); | |||
#endif | |||
} | |||
} | |||
} | |||
void RemoveNodesFromDB(Dictionary<Type, FasterList<INode>> DB, FasterReadOnlyList<INode> nodes) | |||
void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode | |||
{ | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
FasterList<INode> nodesInDB; | |||
FasterList<INode> nodes; | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == true) | |||
nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? | |||
} | |||
var node = nodes[i]; | |||
var nodeType = node.GetType(); | |||
if (DB.TryGetValue(nodeType, out nodesInDB) == true) | |||
nodesInDB.UnorderredRemove(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? | |||
} | |||
if (node is NodeWithID) | |||
{ | |||
Dictionary<int, INode> nodesDic; | |||
void RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID | |||
{ | |||
Dictionary<int, INode> nodesDic; | |||
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) | |||
nodesDic.Remove((node as NodeWithID).ID); | |||
} | |||
} | |||
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) | |||
nodesDic.Remove(node.ID); | |||
} | |||
void RemoveNodesFromEngines(FasterReadOnlyList<INode> nodes) | |||
void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode | |||
{ | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
FasterList<INodeEngine> enginesForNode; | |||
var node = nodes[i]; | |||
FasterList<IEngine> enginesForNode; | |||
if (_nodeEngines.TryGetValue(node.GetType(), out enginesForNode)) | |||
if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, enginesForNode[j], node); | |||
EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); | |||
#else | |||
enginesForNode[j].Remove(node); | |||
(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); | |||
} | |||
} | |||
} | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
static void AddNodeToEngine(INodeEngine engine, INode node) | |||
void AddNodeToEngine(IEngine engine, INode node) | |||
{ | |||
engine.Add(node); | |||
(engine as INodeEngine).Add(node); | |||
} | |||
static void RemoveNodeFromEngine(INodeEngine engine, INode node) | |||
void RemoveNodeFromEngine(IEngine engine, INode node) | |||
{ | |||
engine.Remove(node); | |||
(engine as INodeEngine).Remove(node); | |||
} | |||
#endif | |||
void InternalRemove(FasterReadOnlyList<INode> nodes) | |||
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) | |||
{ | |||
RemoveNodesFromEngines(nodes); | |||
RemoveNodesFromDB(_nodesDB, 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 InternalGroupRemove(FasterReadOnlyList<INode> nodes) | |||
void InternalMetaRemove(FasterList<INode> nodes) | |||
{ | |||
RemoveNodesFromEngines(nodes); | |||
RemoveNodesFromDB(_nodesDBgroups, 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); | |||
} | |||
} | |||
Dictionary<Type, FasterList<INodeEngine>> _nodeEngines; | |||
FasterList<IEngine> _otherEnginesReferences; | |||
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, IStructGroupNodes> _structNodesDB; | |||
readonly Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
readonly FasterList<INode> _nodesToAdd; | |||
readonly FasterList<INode> _metaNodesToAdd; | |||
readonly WeakReference _engineRootWeakReference; | |||
Dictionary<Type, FasterList<INode>> _nodesDB; | |||
Dictionary<Type, FasterList<INode>> _nodesDBgroups; | |||
readonly NodeSubmissionScheduler _scheduler; | |||
Dictionary<Type, Dictionary<int, INode>> _nodesDBdic; | |||
readonly Action<FasterList<INode>> _internalRemove; | |||
readonly Action<FasterList<INode>> _internalEnable; | |||
readonly Action<FasterList<INode>> _internalDisable; | |||
readonly Action<FasterList<INode>> _internalMetaRemove; | |||
FasterList<INode> _nodesToAdd; | |||
FasterList<INode> _groupNodesToAdd; | |||
readonly Type _activableNodeEngineType; | |||
WeakReference _engineRootWeakReference; | |||
NodeSubmissionScheduler _scheduler; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
} | |||
} | |||
@@ -1,4 +1,5 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Reflection; | |||
using Svelto.DataStructures; | |||
#if NETFX_CORE | |||
@@ -11,39 +12,53 @@ namespace Svelto.ECS | |||
{ | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor) | |||
{ | |||
_implementors = componentsImplementor; | |||
_nodesToBuild = nodesToBuild; | |||
_nodesToBuild = new FasterList<INodeBuilder>(nodesToBuild); | |||
ProcessImplementors(componentsImplementor); | |||
} | |||
/* protected EntityDescriptor(IStructNodeBuilder[] structNodesToBuild) | |||
public void AddImplementors(params object[] componentsImplementor) | |||
{ | |||
_structNodesToBuild = structNodesToBuild; | |||
}*/ | |||
ProcessImplementors(componentsImplementor); | |||
} | |||
public void AddImplementors(params object[] componentsImplementor) | |||
void ProcessImplementors(object[] implementors) | |||
{ | |||
var implementors = new object[componentsImplementor.Length + _implementors.Length]; | |||
for (int index = 0; index < implementors.Length; index++) | |||
{ | |||
var implementor = implementors[index]; | |||
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); | |||
Array.Copy(_implementors, implementors, _implementors.Length); | |||
Array.Copy(componentsImplementor, 0, implementors, _implementors.Length, componentsImplementor.Length); | |||
var interfaces = implementor.GetType().GetInterfaces(); | |||
_implementors = implementors; | |||
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, Action<FasterReadOnlyList<INode>> removeAction) | |||
public virtual FasterList<INode> BuildNodes(int ID) | |||
{ | |||
var nodes = new FasterList<INode>(); | |||
for (int index = _nodesToBuild.Length - 1; index >= 0; index--) | |||
for (int index = 0; index < _nodesToBuild.Count; index++) | |||
{ | |||
var nodeBuilder = _nodesToBuild[index]; | |||
var node = FillNode(nodeBuilder.Build(ID), () => | |||
{ | |||
removeAction(new FasterReadOnlyList<INode>()); | |||
var node = nodeBuilder.Build(ID); | |||
nodes.Clear(); | |||
} | |||
); | |||
if (nodeBuilder.reflects != FillNodeMode.None) | |||
node = FillNode(node, nodeBuilder.reflects); | |||
nodes.Add(node); | |||
} | |||
@@ -51,74 +66,116 @@ namespace Svelto.ECS | |||
return nodes; | |||
} | |||
TNode FillNode<TNode>(TNode node, Action removeAction) where TNode: INode | |||
internal FasterList<INode> BuildNodes(int ID, | |||
Action<FasterList<INode>> removeEntity, | |||
Action<FasterList<INode>> enableEntity, | |||
Action<FasterList<INode>> disableEntity) | |||
{ | |||
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 = null; | |||
var nodes = BuildNodes(ID); | |||
for (int j = 0; j < _implementors.Length; j++) | |||
{ | |||
var implementor = _implementors[j]; | |||
SetupImplementors(removeEntity, enableEntity, disableEntity, nodes); | |||
if (implementor != null && fieldType.IsAssignableFrom(implementor.GetType())) | |||
{ | |||
component = implementor; | |||
return nodes; | |||
} | |||
if (fieldType.IsAssignableFrom(typeof(IRemoveEntityComponent))) | |||
(component as IRemoveEntityComponent).removeEntity = removeAction; | |||
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; | |||
} | |||
break; | |||
} | |||
} | |||
INode FillNode(INode node, FillNodeMode mode) | |||
{ | |||
var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); | |||
if (component == null) | |||
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) | |||
{ | |||
Exception e = new Exception("Svelto.ECS: Implementor not found for a Node. " + | |||
"Implementor Type: " + field.FieldType.Name + " - Node: " + node.GetType().Name + " - EntityDescriptor " + this); | |||
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; | |||
throw e; | |||
} | |||
} | |||
field.SetValue(node, component); | |||
else | |||
field.SetValue(node, component); | |||
} | |||
return node; | |||
} | |||
object[] _implementors; | |||
readonly INodeBuilder[] _nodesToBuild; | |||
// readonly IStructNodeBuilder[] _structNodesToBuild; | |||
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 | |||
{ | |||
NodeWithID Build(int ID); | |||
INodeWithID Build(int ID); | |||
FillNodeMode reflects { get; } | |||
} | |||
public class NodeBuilder<NodeType> : INodeBuilder where NodeType:NodeWithID, new() | |||
public class NodeBuilder<NodeType> : INodeBuilder where NodeType : NodeWithID, new() | |||
{ | |||
public NodeWithID Build(int ID) | |||
public INodeWithID Build(int ID) | |||
{ | |||
NodeWithID node = NodeWithID.BuildNode<NodeType>(ID); | |||
return (NodeType)node; | |||
} | |||
public FillNodeMode reflects { get { return FillNodeMode.Strict; } } | |||
} | |||
/* | |||
public interface IStructNodeBuilder | |||
{} | |||
public class StructNodeBuilder<NodeType> : IStructNodeBuilder where NodeType : struct | |||
//To Do: Probably I will need to add an | |||
//FastStructNodeBuilder where reflects is false | |||
public class StructNodeBuilder<NodeType> : INodeBuilder | |||
where NodeType : struct, IStructNodeWithID | |||
{ | |||
public NodeType Build() | |||
public INodeWithID Build(int ID) | |||
{ | |||
return new NodeType(); | |||
IStructNodeWithID node = default(NodeType); | |||
node.ID = ID; | |||
return node; | |||
} | |||
}*/ | |||
public FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } | |||
} | |||
public enum FillNodeMode | |||
{ | |||
Strict, | |||
Relaxed, | |||
None | |||
} | |||
} |
@@ -1,4 +1,5 @@ | |||
using System; | |||
#if UNITY_5 || UNITY_5_3_OR_NEWER | |||
using System; | |||
using System.Collections; | |||
using UnityEngine; | |||
@@ -24,15 +25,17 @@ namespace Svelto.ECS.NodeSchedulers | |||
{ | |||
while (true) | |||
{ | |||
yield return new WaitForEndOfFrame(); | |||
yield return _wait; | |||
OnTick(); | |||
} | |||
} | |||
internal Action OnTick; | |||
WaitForEndOfFrame _wait = new WaitForEndOfFrame(); | |||
} | |||
Scheduler _scheduler; | |||
} | |||
} | |||
#endif |
@@ -1,6 +1,6 @@ | |||
namespace Svelto.ECS | |||
{ | |||
class GenericEntityDescriptor<T> : EntityDescriptor | |||
public class GenericEntityDescriptor<T> : EntityDescriptor | |||
where T : NodeWithID, new() | |||
{ | |||
static GenericEntityDescriptor() | |||
@@ -10,10 +10,10 @@ | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{} | |||
static INodeBuilder[] _nodesToBuild; | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
class GenericEntityDescriptor<T, U> : EntityDescriptor | |||
public class GenericEntityDescriptor<T, U> : EntityDescriptor | |||
where T : NodeWithID, new() | |||
where U : NodeWithID, new() | |||
{ | |||
@@ -29,10 +29,10 @@ | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{} | |||
static INodeBuilder[] _nodesToBuild; | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
class GenericEntityDescriptor<T, U, V> : EntityDescriptor | |||
public class GenericEntityDescriptor<T, U, V> : EntityDescriptor | |||
where T : NodeWithID, new() | |||
where U : NodeWithID, new() | |||
where V : NodeWithID, new() | |||
@@ -47,12 +47,12 @@ | |||
}; | |||
} | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{ | |||
} | |||
static INodeBuilder[] _nodesToBuild; | |||
{} | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
class GenericEntityDescriptor<T, U, V, W> : EntityDescriptor | |||
public class GenericEntityDescriptor<T, U, V, W> : EntityDescriptor | |||
where T : NodeWithID, new() | |||
where U : NodeWithID, new() | |||
where V : NodeWithID, new() | |||
@@ -69,12 +69,12 @@ | |||
}; | |||
} | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{ | |||
} | |||
static INodeBuilder[] _nodesToBuild; | |||
{} | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
class GenericEntityDescriptor<T, U, V, W, X> : EntityDescriptor | |||
public class GenericEntityDescriptor<T, U, V, W, X> : EntityDescriptor | |||
where T : NodeWithID, new() | |||
where U : NodeWithID, new() | |||
where V : NodeWithID, new() | |||
@@ -93,11 +93,12 @@ | |||
}; | |||
} | |||
public GenericEntityDescriptor(params object[] componentsImplementor) : base(_nodesToBuild, componentsImplementor) | |||
{ | |||
} | |||
static INodeBuilder[] _nodesToBuild; | |||
{} | |||
static readonly INodeBuilder[] _nodesToBuild; | |||
} | |||
class GenericEntityDescriptor<T, U, V, W, X, Y> : EntityDescriptor | |||
public class GenericEntityDescriptor<T, U, V, W, X, Y> : EntityDescriptor | |||
where T : NodeWithID, new() | |||
where U : NodeWithID, new() | |||
where V : NodeWithID, new() | |||
@@ -118,8 +119,121 @@ | |||
}; | |||
} | |||
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() | |||
}; | |||
} | |||
static INodeBuilder[] _nodesToBuild; | |||
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,7 +1,7 @@ | |||
namespace Svelto.ECS | |||
{ | |||
interface ICallBackOnAddEngine | |||
public interface ICallBackOnAddEngine | |||
{ | |||
void Ready(); | |||
} | |||
} | |||
} |
@@ -1,27 +1,14 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEngine | |||
{} | |||
public interface INodeEngine<in TNodeType>:IEngine where TNodeType:INode | |||
{ | |||
void Add(TNodeType obj); | |||
void Remove(TNodeType obj); | |||
} | |||
public interface INodeEngine<in T, in U>:INodeEngine<U> where T:INode where U:INode | |||
{ | |||
void Add(T obj); | |||
void Remove(T obj); | |||
} | |||
using Svelto.ECS.Internal; | |||
public interface INodeEngine<in T, in U, in V>:INodeEngine<U, V> where T:INode where U:INode where V:INode | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface IActivableNodeEngine : IEngine | |||
{ | |||
void Add(T obj); | |||
void Remove(T obj); | |||
void Enable(INode obj); | |||
void Disable(INode obj); | |||
} | |||
public interface INodeEngine:IEngine | |||
public interface INodeEngine : IEngine | |||
{ | |||
void Add(INode obj); | |||
void Remove(INode obj); | |||
@@ -31,9 +18,19 @@ namespace Svelto.ECS | |||
{ | |||
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; } | |||
} | |||
} | |||
@@ -6,16 +6,14 @@ namespace Svelto.ECS | |||
{ | |||
ReadOnlyDictionary<int, INode> QueryIndexableNodes<T>() where T:INode; | |||
bool QueryNode<T>(int ID, out T node) 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; | |||
// FasterReadOnlyList<T> QueryStructNodes<T>() where T : struct; | |||
bool QueryNodeFromGroup<T>(int ID, out T node) where T : INode; | |||
T QueryNodeFromGroup<T>(int ID) where T : INode; | |||
FasterReadOnlyListCast<INode, T> QueryNodesFromGroups<T>() where T : INode; | |||
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,3 +1,5 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public interface IEnginesRoot | |||
@@ -9,6 +11,8 @@ namespace Svelto.ECS | |||
{ | |||
void BuildEntity(int ID, EntityDescriptor ED); | |||
void BuildEntityGroup(int ID, EntityDescriptor ED); | |||
void BuildMetaEntity(int metaEntityID, EntityDescriptor ED); | |||
void BuildEntityInGroup(int entityID, int groupID, EntityDescriptor ED); | |||
} | |||
} |
@@ -3,7 +3,22 @@ namespace Svelto.ECS | |||
public interface INode | |||
{} | |||
public class NodeWithID: INode | |||
public interface INodeWithID:INode | |||
{ | |||
int ID { get; } | |||
} | |||
public interface IStructNodeWithID : INodeWithID | |||
{ | |||
new 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() | |||
{ | |||
@@ -6,4 +6,14 @@ namespace Svelto.ECS | |||
{ | |||
Action removeEntity { get; set; } | |||
} | |||
public interface IDisableEntityComponent | |||
{ | |||
Action disableEntity { get; set; } | |||
} | |||
public interface IEnableEntityComponent | |||
{ | |||
Action enableEntity { get; set; } | |||
} | |||
} |
@@ -0,0 +1,47 @@ | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public abstract class MultiNodesEngine<T> | |||
where T : INode | |||
{ | |||
protected internal abstract void Add(T node); | |||
protected internal abstract void Remove(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<U>, | |||
INodeEngine | |||
where T : INode | |||
where U : INode | |||
{ | |||
protected abstract void Add(T node); | |||
protected abstract void Remove(T node); | |||
public void Add(INode node) | |||
{ | |||
if (node is T) | |||
Add((T) node); | |||
else | |||
((MultiNodesEngine<U>)(this)).Add((U)node); | |||
} | |||
public void Remove(INode node) | |||
{ | |||
if (node is T) | |||
Remove((T)node); | |||
else | |||
((MultiNodesEngine<U>)(this)).Remove((U)node); | |||
} | |||
} | |||
} |
@@ -1,66 +0,0 @@ | |||
using System; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
class NodeEngineWrapper<T> : SingleNodeEngine<T> where T : class, INode | |||
{ | |||
INodeEngine<T> engine; | |||
public NodeEngineWrapper(INodeEngine<T> engine) | |||
{ | |||
this.engine = engine; | |||
} | |||
protected override void Add(T node) | |||
{ | |||
engine.Add((T)node); | |||
} | |||
protected override void Remove(T node) | |||
{ | |||
engine.Remove((T)node); | |||
} | |||
} | |||
class NodeEngineWrapper<T, U>: SingleNodeEngine<T> where T : class, INode where U : class, INode | |||
{ | |||
INodeEngine<T, U> engine; | |||
public NodeEngineWrapper(INodeEngine<T, U> engine) | |||
{ | |||
this.engine = engine; | |||
} | |||
protected override void Add(T node) | |||
{ | |||
engine.Add((T)node); | |||
} | |||
protected override void Remove(T node) | |||
{ | |||
engine.Remove((T)node); | |||
} | |||
} | |||
class NodeEngineWrapper<T, U, V>: SingleNodeEngine<T> where T : class, INode | |||
where U : class, INode | |||
where V : class, INode | |||
{ | |||
INodeEngine<T, U, V> engine; | |||
public NodeEngineWrapper(INodeEngine<T, U, V> engine) | |||
{ | |||
this.engine = engine; | |||
} | |||
protected override void Add(T node) | |||
{ | |||
engine.Add((T)node); | |||
} | |||
protected override void Remove(T node) | |||
{ | |||
engine.Remove((T)node); | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
using Svelto.ECS.Internal; | |||
//This profiler is based on the Entitas Visual Debugging tool | |||
//https://github.com/sschmid/Entitas-CSharp | |||
@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using System.Collections.Generic; | |||
using UnityEngine; | |||
@@ -1,15 +1,18 @@ | |||
namespace Svelto.ECS | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class SingleNodeEngine<TNodeType> : INodeEngine where TNodeType : class, INode | |||
public abstract class SingleNodeEngine<TNodeType> : INodeEngine | |||
where TNodeType : class, INode | |||
{ | |||
void INodeEngine.Add(INode obj) | |||
public void Add(INode obj) | |||
{ | |||
Add(obj as TNodeType); | |||
Add((TNodeType) obj); | |||
} | |||
void INodeEngine.Remove(INode obj) | |||
public void Remove(INode obj) | |||
{ | |||
Remove(obj as TNodeType); | |||
Remove((TNodeType) obj); | |||
} | |||
protected abstract void Add(TNodeType node); | |||
@@ -0,0 +1,74 @@ | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public class StructNodes<T>: IStructNodes where T:struct, IStructNodeWithID | |||
{ | |||
public FasterList<T> list | |||
{ | |||
get | |||
{ | |||
return _internalList; | |||
} | |||
} | |||
public StructNodes() | |||
{ | |||
_internalList = new FasterList<T>(); | |||
} | |||
public void Add(T node) | |||
{ | |||
T convert = (T)node; | |||
_internalList.Add(convert); | |||
} | |||
readonly FasterList<T> _internalList; | |||
} | |||
public class StructGroupNodes<T>: IStructGroupNodes | |||
where T : struct, IGroupedStructNodeWithID | |||
{ | |||
public void Add(int groupID, T node) | |||
{ | |||
T convert = (T)node; | |||
var fasterList = GetList(groupID); | |||
_indices[node.ID] = fasterList.Count; | |||
fasterList.Add(convert); | |||
} | |||
public void Remove(int groupID, T node) | |||
{ | |||
var fasterList = GetList(groupID); | |||
var index = _indices[node.ID]; | |||
_indices.Remove(node.ID); | |||
if (fasterList.UnorderedRemoveAt(index)) | |||
_indices[fasterList[index].ID] = index; | |||
} | |||
public FasterList<T> GetList(int groupID) | |||
{ | |||
return _nodes[groupID]; | |||
} | |||
readonly Dictionary<int, int> _indices = new Dictionary<int, int>(); | |||
Dictionary<int, FasterList<T>> _nodes = new Dictionary<int, FasterList<T>>(); | |||
} | |||
} | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface IStructGroupNodes | |||
{ | |||
} | |||
public interface IStructNodes | |||
{ | |||
} | |||
} |
@@ -0,0 +1,111 @@ | |||
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. |
@@ -324,18 +324,18 @@ namespace DesignByContract | |||
useAssertions = value; | |||
} | |||
} | |||
#endregion // Interface | |||
#endregion // Interface | |||
#region Implementation | |||
#region Implementation | |||
// No creation | |||
Check() { } | |||
// No creation | |||
private Check() {} | |||
/// <summary> | |||
/// Is exception handling being used? | |||
/// </summary> | |||
private static bool UseExceptions | |||
/// <summary> | |||
/// Is exception handling being used? | |||
/// </summary> | |||
private static bool UseExceptions | |||
{ | |||
get | |||
{ | |||
@@ -343,15 +343,15 @@ namespace DesignByContract | |||
} | |||
} | |||
// Are trace assertion statements being used? | |||
// Default is to use exception handling. | |||
static bool useAssertions = false; | |||
// Are trace assertion statements being used? | |||
// Default is to use exception handling. | |||
private static bool useAssertions = false; | |||
#endregion // Implementation | |||
#endregion // Implementation | |||
} // End Check | |||
} // End Check | |||
class Trace | |||
internal class Trace | |||
{ | |||
internal static void Assert(bool assertion, string v) | |||
{ | |||
@@ -136,7 +136,7 @@ namespace Utility | |||
logger.Log(txt); | |||
} | |||
public static void LogError(string txt, bool showCurrentStack = true) | |||
public static void LogError(string txt) | |||
{ | |||
string toPrint; | |||
@@ -148,11 +148,8 @@ namespace Utility | |||
toPrint = _stringBuilder.ToString(); | |||
} | |||
#if !NETFX_CORE | |||
logger.Log(toPrint, showCurrentStack == true ? new StackTrace().ToString() : null, LogType.Error); | |||
#else | |||
logger.Log(toPrint, null, LogType.Error); | |||
#endif | |||
} | |||
public static void LogError(string txt, string stack) | |||
@@ -1,4 +1,4 @@ | |||
using System; | |||
using System; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using System.Runtime.InteropServices; | |||
@@ -1,5 +1,6 @@ | |||
using Svelto.DataStructures; | |||
using System; | |||
using System.Collections.Generic; | |||
namespace BetterWeakEvents | |||
{ | |||
@@ -13,7 +14,7 @@ namespace BetterWeakEvents | |||
public static WeakEvent<T1, T2> operator-(WeakEvent<T1, T2> c1, Action<T1, T2> x) | |||
{ | |||
c1._subscribers.UnorderredRemove(new WeakAction<T1, T2>(x)); | |||
c1._subscribers.UnorderedRemove(new WeakAction<T1, T2>(x)); | |||
return c1; | |||
} | |||
@@ -21,7 +22,7 @@ namespace BetterWeakEvents | |||
{ | |||
for (int i = 0; i < _subscribers.Count; i++) | |||
if (_subscribers[i].Invoke(arg1, arg2) == false) | |||
_subscribers.UnorderredRemoveAt(i--); | |||
_subscribers.UnorderedRemoveAt(i--); | |||
} | |||
~WeakEvent() | |||
@@ -32,4 +33,4 @@ namespace BetterWeakEvents | |||
protected FasterList<WeakAction<T1, T2>> _subscribers = new FasterList<WeakAction<T1, T2>>(); | |||
} | |||
} | |||
} |