Browse Source

local commit

tags/Rel1
sebas77 7 years ago
parent
commit
b24be7d266
25 changed files with 1004 additions and 446 deletions
  1. +1
    -1
      DataStructures/CircularBufferIndexer.cs
  2. +16
    -11
      DataStructures/FasterList.cs
  3. +16
    -16
      DataStructures/Priority Queue/HeapPriorityQueue.cs
  4. +38
    -50
      ECS/EngineNodeDB.cs
  5. +363
    -164
      ECS/EnginesRoot.cs
  6. +114
    -57
      ECS/EntityDescriptor.cs
  7. +5
    -2
      ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs
  8. +132
    -18
      ECS/GenericEntityDescriptor.cs
  9. +2
    -2
      ECS/ICallBackOnAddEngine.cs
  10. +17
    -20
      ECS/IEngine.cs
  11. +4
    -6
      ECS/IEngineNodeDB.cs
  12. +5
    -1
      ECS/IEnginesRoot.cs
  13. +16
    -1
      ECS/INode.cs
  14. +10
    -0
      ECS/IRemoveEntityComponent.cs
  15. +47
    -0
      ECS/MultipleNodesEngine.cs
  16. +0
    -66
      ECS/NodeEngineWrapper.cs
  17. +1
    -0
      ECS/Profiler/EngineProfiler.cs
  18. +1
    -1
      ECS/Profiler/EngineProfilerBehaviour.cs
  19. +9
    -6
      ECS/SingleNodeEngine.cs
  20. +74
    -0
      ECS/StructNodes.cs
  21. +111
    -0
      ECS/note.txt
  22. +15
    -15
      Utilities/DesignByContract.cs
  23. +2
    -5
      Utilities/Print.cs
  24. +1
    -1
      Utilities/WeakActionStruct.cs
  25. +4
    -3
      Utilities/WeakEvent.cs

+ 1
- 1
DataStructures/CircularBufferIndexer.cs View File

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


+ 16
- 11
DataStructures/FasterList.cs View File

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


+ 16
- 16
DataStructures/Priority Queue/HeapPriorityQueue.cs View File

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


+ 38
- 50
ECS/EngineNodeDB.cs View File

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

+ 363
- 164
ECS/EnginesRoot.cs View File

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


+ 114
- 57
ECS/EntityDescriptor.cs View File

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

Extensions/Unity/UnitySumbmissionNodeScheduler.cs → ECS/Extensions/Unity/UnitySumbmissionNodeScheduler.cs View File

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

+ 132
- 18
ECS/GenericEntityDescriptor.cs View File

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

+ 2
- 2
ECS/ICallBackOnAddEngine.cs View File

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

+ 17
- 20
ECS/IEngine.cs View File

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


+ 4
- 6
ECS/IEngineNodeDB.cs View File

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


+ 5
- 1
ECS/IEnginesRoot.cs View File

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

+ 16
- 1
ECS/INode.cs View File

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


+ 10
- 0
ECS/IRemoveEntityComponent.cs View File

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

+ 47
- 0
ECS/MultipleNodesEngine.cs View File

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

+ 0
- 66
ECS/NodeEngineWrapper.cs View File

@@ -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
- 0
ECS/Profiler/EngineProfiler.cs View File

@@ -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
- 1
ECS/Profiler/EngineProfilerBehaviour.cs View File

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



+ 9
- 6
ECS/SingleNodeEngine.cs View File

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


+ 74
- 0
ECS/StructNodes.cs View File

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

+ 111
- 0
ECS/note.txt View File

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

+ 15
- 15
Utilities/DesignByContract.cs View File

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


+ 2
- 5
Utilities/Print.cs View File

@@ -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
- 1
Utilities/WeakActionStruct.cs View File

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


+ 4
- 3
Utilities/WeakEvent.cs View File

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

Loading…
Cancel
Save