- Support for grouped nodes (adding and querying them) is almost complete - EngineRoot and EngineNodeDB can now support nodes as struct and class - INodeEngine Add and Remove functions accept only NodeWithID (classes only) -tags/Rel2b
@@ -1,7 +1,8 @@ | |||
using Svelto.DataStructures; | |||
using System.Collections.Generic; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
namespace Svelto.ECS.Internal | |||
{ | |||
/// <summary> | |||
/// This is just a place holder at the moment | |||
@@ -13,11 +14,37 @@ namespace Svelto.ECS | |||
public interface ITypeSafeDictionary | |||
{ | |||
void FillWithIndexedNodes(ITypeSafeList nodes); | |||
void Remove(int entityId); | |||
NodeWithID GetIndexedNode(int entityID); | |||
} | |||
public class TypeSafeDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ITypeSafeDictionary | |||
class TypeSafeDictionary<TValue> : Dictionary<int, TValue>, ITypeSafeDictionary where TValue:NodeWithID | |||
{ | |||
internal static readonly ReadOnlyDictionary<TKey, TValue> Default = new ReadOnlyDictionary<TKey, TValue>(new TypeSafeDictionary<TKey, TValue>()); | |||
internal static readonly ReadOnlyDictionary<int, TValue> Default = | |||
new ReadOnlyDictionary<int, TValue>(new Dictionary<int, TValue>()); | |||
public void FillWithIndexedNodes(ITypeSafeList nodes) | |||
{ | |||
int count; | |||
var buffer = FasterList<TValue>.NoVirt.ToArrayFast((FasterList<TValue>) nodes, out count); | |||
for (int i = 0; i < count; i++) | |||
{ | |||
var node = buffer[i]; | |||
Add(node.ID, node); | |||
} | |||
} | |||
public void Remove(int entityId) | |||
{ | |||
throw new System.NotImplementedException(); | |||
} | |||
public NodeWithID GetIndexedNode(int entityID) | |||
{ | |||
return this[entityID]; | |||
} | |||
} | |||
} |
@@ -0,0 +1,82 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public interface ITypeSafeList: IEnumerable | |||
{ | |||
void AddRange(ITypeSafeList nodeListValue); | |||
ITypeSafeList Create(); | |||
bool isQueryiableNode { get; } | |||
void UnorderedRemove(int index); | |||
ITypeSafeDictionary CreateIndexedDictionary(); | |||
} | |||
class TypeSafeFasterListForECS<T>: FasterList<T> where T:INode | |||
{ | |||
protected TypeSafeFasterListForECS() | |||
{ | |||
_mappedIndices = new Dictionary<int, int>(); | |||
} | |||
public void UnorderedRemove(int mappedIndex) | |||
{ | |||
var index = _mappedIndices[mappedIndex]; | |||
_mappedIndices.Remove(mappedIndex); | |||
if (UnorderedRemoveAt(index)) | |||
_mappedIndices[this[index].ID] = index; | |||
} | |||
public void AddRange(ITypeSafeList nodeListValue) | |||
{ | |||
var index = this.Count; | |||
AddRange(nodeListValue as FasterList<T>); | |||
for (int i = index; i < Count; ++i) | |||
_mappedIndices[this[i].ID] = this.Count; | |||
} | |||
readonly Dictionary<int, int> _mappedIndices; | |||
} | |||
class TypeSafeFasterListForECSForStructs<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T:struct, INode | |||
{ | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterListForECSForStructs<T>(); | |||
} | |||
public bool isQueryiableNode | |||
{ | |||
get { return false; } | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
throw new Exception("Not Allowed"); | |||
} | |||
} | |||
class TypeSafeFasterListForECSForClasses<T> : TypeSafeFasterListForECS<T>, ITypeSafeList where T:NodeWithID | |||
{ | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterListForECSForClasses<T>(); | |||
} | |||
public bool isQueryiableNode | |||
{ | |||
get { return true; } | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
return new TypeSafeDictionary<T>(); | |||
} | |||
} | |||
} |
@@ -1,51 +0,0 @@ | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public interface ITypeSafeList | |||
{ | |||
void Clear(); | |||
void AddRange(ITypeSafeList nodeListValue); | |||
ITypeSafeList Create(); | |||
ITypeSafeDictionary CreateIndexedDictionary(); | |||
void AddToIndexedDictionary(ITypeSafeDictionary nodesDic); | |||
} | |||
public class TypeSafeFasterList<T> : FasterList<T>, ITypeSafeList | |||
{ | |||
public TypeSafeFasterList() | |||
{ | |||
} | |||
public void AddRange(ITypeSafeList nodeListValue) | |||
{ | |||
AddRange(nodeListValue as FasterList<T>); | |||
} | |||
public ITypeSafeList Create() | |||
{ | |||
return new TypeSafeFasterList<T>(); | |||
} | |||
public ITypeSafeDictionary CreateIndexedDictionary() | |||
{ | |||
return new TypeSafeDictionary<int, T>(); | |||
} | |||
public void AddToIndexedDictionary(ITypeSafeDictionary nodesDic) | |||
{ | |||
var dic = nodesDic as TypeSafeDictionary<int, T>; | |||
var buffer = NoVirt.ToArrayFast(this); | |||
for (int i = 0; i < Count; i++) | |||
{ | |||
T node = buffer[i]; | |||
dic[(node as NodeWithID).ID] = node; | |||
} | |||
} | |||
} | |||
} |
@@ -1,6 +1,7 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
@@ -8,11 +9,13 @@ namespace Svelto.ECS | |||
{ | |||
internal EngineNodeDB( Dictionary<Type, ITypeSafeList> nodesDB, | |||
Dictionary<Type, ITypeSafeDictionary> nodesDBdic, | |||
Dictionary<Type, ITypeSafeList> metaNodesDB) | |||
Dictionary<Type, ITypeSafeList> metaNodesDB, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupNodesDB) | |||
{ | |||
_nodesDB = nodesDB; | |||
_nodesDBdic = nodesDBdic; | |||
_metaNodesDB = metaNodesDB; | |||
_groupNodesDB = groupNodesDB; | |||
} | |||
public FasterReadOnlyList<T> QueryNodes<T>() | |||
@@ -27,24 +30,46 @@ namespace Svelto.ECS | |||
return new FasterReadOnlyList<T>((FasterList<T>)nodes); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableNodes<T>() | |||
public FasterReadOnlyList<T> QueryGroupedNodes<T>(int @group) | |||
{ | |||
return new FasterReadOnlyList<T>(_groupNodesDB[group] as FasterList<T>); | |||
} | |||
public T[] QueryNodesAsArray<T>(out int count) where T : struct | |||
{ | |||
var type = typeof(T); | |||
count = 0; | |||
ITypeSafeList nodes; | |||
if (_nodesDB.TryGetValue(type, out nodes) == false) | |||
return null; | |||
var castedNodes = (FasterList<T>)nodes; | |||
count = castedNodes.Count; | |||
return castedNodes.ToArrayFast(); | |||
} | |||
public ReadOnlyDictionary<int, T> QueryIndexableNodes<T>() where T:NodeWithID | |||
{ | |||
var type = typeof(T); | |||
ITypeSafeDictionary nodes; | |||
if (_nodesDBdic.TryGetValue(type, out nodes) == false) | |||
return TypeSafeDictionary<int, T>.Default; | |||
return TypeSafeDictionary<T>.Default; | |||
return new ReadOnlyDictionary<int, T>(nodes as Dictionary<int, T>); | |||
} | |||
public T QueryMetaNode<T>(int metaEntityID) | |||
public T QueryMetaNode<T>(int metaEntityID) where T:NodeWithID | |||
{ | |||
return QueryNode<T>(metaEntityID); | |||
} | |||
public bool TryQueryMetaNode<T>(int metaEntityID, out T node) | |||
public bool TryQueryMetaNode<T>(int metaEntityID, out T node) where T:NodeWithID | |||
{ | |||
return TryQueryNode(metaEntityID, out node); | |||
} | |||
@@ -61,18 +86,22 @@ namespace Svelto.ECS | |||
return new FasterReadOnlyList<T>((FasterList<T>)nodes); | |||
} | |||
public bool TryQueryNode<T>(int ID, out T node) | |||
public bool TryQueryNode<T>(int ID, out T node) where T:NodeWithID | |||
{ | |||
var type = typeof(T); | |||
T internalNode; | |||
ITypeSafeDictionary nodes; | |||
TypeSafeDictionary<T> casted; | |||
if (_nodesDBdic.TryGetValue(type, out nodes) && | |||
(nodes as Dictionary<int, T>).TryGetValue(ID, out internalNode)) | |||
_nodesDBdic.TryGetValue(type, out nodes); | |||
casted = nodes as TypeSafeDictionary<T>; | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalNode)) | |||
{ | |||
node = internalNode; | |||
node = (T) internalNode; | |||
return true; | |||
} | |||
@@ -82,14 +111,18 @@ namespace Svelto.ECS | |||
return false; | |||
} | |||
public T QueryNode<T>(int ID) | |||
public T QueryNode<T>(int ID) where T:NodeWithID | |||
{ | |||
var type = typeof(T); | |||
T internalNode; ITypeSafeDictionary nodes; | |||
TypeSafeDictionary<T> casted; | |||
_nodesDBdic.TryGetValue(type, out nodes); | |||
casted = nodes as TypeSafeDictionary<T>; | |||
if (_nodesDBdic.TryGetValue(type, out nodes) && | |||
(nodes as Dictionary<int, T>).TryGetValue(ID, out internalNode)) | |||
if (casted != null && | |||
casted.TryGetValue(ID, out internalNode)) | |||
return (T)internalNode; | |||
throw new Exception("Node Not Found"); | |||
@@ -103,5 +136,6 @@ namespace Svelto.ECS | |||
readonly Dictionary<Type, ITypeSafeList> _nodesDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _nodesDBdic; | |||
readonly Dictionary<Type, ITypeSafeList> _metaNodesDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupNodesDB; | |||
} | |||
} |
@@ -1,12 +1,13 @@ | |||
using System; | |||
using System.Collections; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
using Svelto.ECS.Legacy; | |||
using Svelto.ECS.NodeSchedulers; | |||
using System.Reflection; | |||
using Svelto.ECS.Profiler; | |||
using Svelto.Utilities; | |||
using UnityEngine.UI; | |||
using UnityEngine.XR.WSA.Persistence; | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
using Svelto.ECS.Profiler; | |||
@@ -16,9 +17,9 @@ namespace Svelto.ECS.Internal | |||
{ | |||
struct BuildNodeCallbackStruct | |||
{ | |||
public Action<ITypeSafeList> _internalRemove; | |||
public Action<ITypeSafeList> _internalEnable; | |||
public Action<ITypeSafeList> _internalDisable; | |||
public Action<FasterList<INodeBuilder>, int> internalRemove; | |||
public Action<FasterList<INodeBuilder>, int> internalEnable; | |||
public Action<FasterList<INodeBuilder>, int> internalDisable; | |||
} | |||
} | |||
@@ -32,22 +33,37 @@ namespace Svelto.ECS | |||
_activableEngines = new Dictionary<Type, FasterList<IEngine>>(); | |||
_otherEngines = new FasterList<IEngine>(); | |||
//_engineRootWeakReference = new DataStructures.WeakReference<EnginesRoot>(this); | |||
_engineRootWeakReference = new DataStructures.WeakReference<EnginesRoot>(this); | |||
_nodesDB = new Dictionary<Type, ITypeSafeList>(); | |||
_metaNodesDB = new Dictionary<Type, ITypeSafeList>(); | |||
_groupNodesDB = new Dictionary<int, Dictionary<Type, ITypeSafeList>>(); | |||
_nodesDBdic = new Dictionary<Type, ITypeSafeDictionary>(); | |||
_sharedStructNodeLists = new SharedStructNodeLists(); | |||
_sharedGroupedStructNodeLists = new SharedGroupedStructNodesLists(); | |||
_nodesToAdd = new DoubleBufferedNodes<Dictionary<Type, ITypeSafeList>>(); | |||
_metaNodesToAdd = new DoubleBufferedNodes<Dictionary<Type, ITypeSafeList>>(); | |||
_groupedNodesToAdd = new DoubleBufferedNodes<Dictionary<int, Dictionary<Type, ITypeSafeList>>>(); | |||
_callBackStructForBuiltGroupedNodes = new BuildNodeCallbackStruct(); | |||
_nodesToAdd = new Dictionary<Type, ITypeSafeList>(); | |||
_metaNodesToAdd = new Dictionary<Type, ITypeSafeList>(); | |||
_groupedNodesToAdd = new Dictionary<Type, Dictionary<int, ITypeSafeList>>(); | |||
_callBackStructForBuiltGroupedNodes.internalRemove = InternalRemove; | |||
_callBackStructForBuiltGroupedNodes.internalDisable = InternalDisable; | |||
_callBackStructForBuiltGroupedNodes.internalEnable = InternalEnable; | |||
_callBackStruct = new BuildNodeCallbackStruct(); | |||
_callBackStructForBuiltNodes = new BuildNodeCallbackStruct(); | |||
/* _callBackStruct._internalRemove = InternalRemove; | |||
_callBackStruct._internalDisable = InternalDisable; | |||
_callBackStruct._internalEnable = InternalEnable; | |||
_callBackStruct._internalMetaRemove = InternalMetaRemove;*/ | |||
_callBackStructForBuiltNodes.internalRemove = InternalGroupedRemove; | |||
_callBackStructForBuiltNodes.internalDisable = InternalDisable; | |||
_callBackStructForBuiltNodes.internalEnable = InternalEnable; | |||
_callBackStructForBuiltMetaNodes = new BuildNodeCallbackStruct(); | |||
_callBackStructForBuiltMetaNodes.internalRemove = InternalMetaRemove; | |||
_callBackStructForBuiltMetaNodes.internalDisable = InternalDisable; | |||
_callBackStructForBuiltMetaNodes.internalEnable = InternalEnable; | |||
_scheduler = nodeScheduler; | |||
_scheduler.Schedule(SubmitNodes); | |||
@@ -58,15 +74,15 @@ namespace Svelto.ECS | |||
_implementedInterfaceTypes = new Dictionary<Type, Type[]>(); | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
GameObject debugEngineObject = new GameObject("Engine Debugger"); | |||
#if UNITY_EDITOR | |||
UnityEngine.GameObject debugEngineObject = new UnityEngine.GameObject("Engine Debugger"); | |||
debugEngineObject.gameObject.AddComponent<EngineProfilerBehaviour>(); | |||
#endif | |||
} | |||
public void BuildEntity(int ID, EntityDescriptor ed) | |||
{ | |||
ed.BuildNodes(ID, _nodesToAdd, ref _callBackStruct); | |||
ed.BuildNodes(ID, _nodesToAdd.other, ref _callBackStructForBuiltNodes); | |||
} | |||
/// <summary> | |||
@@ -95,7 +111,7 @@ namespace Svelto.ECS | |||
/// <param name="ed"></param> | |||
public void BuildMetaEntity(int metaEntityID, EntityDescriptor ed) | |||
{ | |||
ed.BuildNodes(metaEntityID, _metaNodesToAdd, ref _callBackStruct); | |||
ed.BuildNodes(metaEntityID, _metaNodesToAdd.other, ref _callBackStructForBuiltMetaNodes); | |||
} | |||
/// <summary> | |||
@@ -110,18 +126,18 @@ namespace Svelto.ECS | |||
public void BuildEntityInGroup(int entityID, int groupID, | |||
EntityDescriptor ed) | |||
{ | |||
ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd, ref _callBackStruct); | |||
ed.BuildGroupedNodes(entityID, groupID, _groupedNodesToAdd.other, ref _callBackStructForBuiltGroupedNodes); | |||
} | |||
public void AddEngine(IEngine engine) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
#if UNITY_EDITOR | |||
EngineProfiler.AddEngine(engine); | |||
#endif | |||
var queryableNodeEngine = engine as IQueryableNodeEngine; | |||
if (queryableNodeEngine != null) | |||
queryableNodeEngine.nodesDB = | |||
new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB); | |||
new EngineNodeDB(_nodesDB, _nodesDBdic, _metaNodesDB, _groupNodesDB); | |||
var engineType = engine.GetType(); | |||
var implementedInterfaces = engineType.GetInterfaces(); | |||
@@ -171,6 +187,18 @@ namespace Svelto.ECS | |||
bool engineAdded = false; | |||
if (_implementedInterfaceTypes.ContainsKey(_structNodeEngineType)) | |||
{ | |||
((IStructNodeEngine)engine).CreateStructNodes | |||
(_sharedStructNodeLists); | |||
} | |||
if (_implementedInterfaceTypes.ContainsKey(_groupedStructNodesEngineType)) | |||
{ | |||
((IGroupedStructNodesEngine)engine).CreateStructNodes | |||
(_sharedGroupedStructNodeLists); | |||
} | |||
Type[] arguments; | |||
if (_implementedInterfaceTypes.TryGetValue(_activableNodeEngineType, | |||
out arguments)) | |||
@@ -235,36 +263,75 @@ namespace Svelto.ECS | |||
} | |||
} | |||
static void AddNodesToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> nodesToAdd, | |||
static void AddNodesToTheDBAndSuitableEngines(Dictionary<Type, ITypeSafeList> nodesToAdd, | |||
Dictionary<Type, FasterList<IEngine>> nodeEngines, | |||
Dictionary<Type, ITypeSafeDictionary> nodesDBdic, | |||
Dictionary<Type, ITypeSafeList> nodesDB) | |||
{ | |||
foreach (var nodeList in nodesToAdd) | |||
{ | |||
ITypeSafeList dbList; | |||
AddNodeToDB(nodesDB, nodeList); | |||
if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) | |||
dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); | |||
if (nodeList.Value.isQueryiableNode) | |||
{ | |||
AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); | |||
foreach (var node in nodeList.Value) | |||
AddNodeToTheSuitableEngines(nodeEngines, node as NodeWithID, nodeList.Key); | |||
} | |||
} | |||
} | |||
dbList.AddRange(nodeList.Value); | |||
static void AddGroupNodesToTheDBAndSuitableEngines(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupedNodesToAdd, | |||
Dictionary<Type, FasterList<IEngine>> nodeEngines, | |||
Dictionary<Type, ITypeSafeDictionary> nodesDBdic, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupNodesDB, | |||
Dictionary<Type, ITypeSafeList> nodesDB) | |||
{ | |||
foreach (var group in groupedNodesToAdd) | |||
{ | |||
AddNodesToTheDBAndSuitableEngines(group.Value, nodeEngines, nodesDBdic, nodesDB); | |||
AddNodeToNodesDictionary(nodesDBdic, nodeList.Value, nodeList.Key); | |||
AddNodesToTheSuitableEngines(nodeEngines, nodeList.Value, nodeList.Key); | |||
AddNodesToGroupDB(groupNodesDB, @group); | |||
} | |||
} | |||
static void AddNodesToGroupDB(Dictionary<int, Dictionary<Type, ITypeSafeList>> groupNodesDB, | |||
KeyValuePair<int, Dictionary<Type, ITypeSafeList>> @group) | |||
{ | |||
Dictionary<Type, ITypeSafeList> groupedNodesByType; | |||
if (groupNodesDB.TryGetValue(@group.Key, out groupedNodesByType) == false) | |||
groupedNodesByType = groupNodesDB[@group.Key] = new Dictionary<Type, ITypeSafeList>(); | |||
foreach (var node in @group.Value) | |||
{ | |||
groupedNodesByType.Add(node.Key, node.Value); | |||
} | |||
} | |||
static void AddNodeToDB(Dictionary<Type, ITypeSafeList> nodesDB, KeyValuePair<Type, ITypeSafeList> nodeList) | |||
{ | |||
ITypeSafeList dbList; | |||
if (nodesDB.TryGetValue(nodeList.Key, out dbList) == false) | |||
dbList = nodesDB[nodeList.Key] = nodeList.Value.Create(); | |||
dbList.AddRange(nodeList.Value); | |||
} | |||
static void AddNodeToNodesDictionary(Dictionary<Type, ITypeSafeDictionary> nodesDBdic, ITypeSafeList nodes, Type nodeType) | |||
static void AddNodeToNodesDictionary(Dictionary<Type, ITypeSafeDictionary> nodesDBdic, | |||
ITypeSafeList nodes, Type nodeType) | |||
{ | |||
ITypeSafeDictionary nodesDic; | |||
if (nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) | |||
nodesDic = nodesDBdic[nodeType] = nodes.CreateIndexedDictionary(); | |||
nodes.AddToIndexedDictionary(nodesDic); | |||
nodesDic.FillWithIndexedNodes(nodes); | |||
} | |||
static void AddNodesToTheSuitableEngines(Dictionary<Type, FasterList<IEngine>> nodeEngines, ITypeSafeList nodes, Type nodeType) | |||
static void AddNodeToTheSuitableEngines(Dictionary<Type, FasterList<IEngine>> nodeEngines, NodeWithID node, Type nodeType) | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
@@ -273,191 +340,170 @@ namespace Svelto.ECS | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorAddDuration(AddNodeToEngine, enginesForNode[j] as INodeEngine, node); | |||
EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); | |||
#else | |||
(enginesForNode[j] as INodeEngine).Add(nodes); | |||
(enginesForNode[j] as INodeEngine).Add(node); | |||
#endif | |||
} | |||
} | |||
} | |||
/* | |||
void RemoveNodeFromTheDB<T>(T node, Type nodeType) where T : INode | |||
{ | |||
FasterList<INode> nodes; | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == true) | |||
nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? | |||
} | |||
/* | |||
void DisableNodeFromEngines(INode node, Type nodeType) | |||
{ | |||
ITypeSafeList enginesForNode; | |||
void RemoveNodeFromMetaDB<T>(T node, Type nodeType) where T : INode | |||
if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
FasterList<INode> nodes; | |||
if (_metaNodesDB.TryGetValue(nodeType, out nodes) == true) | |||
nodes.UnorderedRemove(node); //should I remove it from the dictionary if length is zero? | |||
(enginesForNode[j] as IActivableNodeEngine).Disable(node); | |||
} | |||
} | |||
} | |||
void RemoveNodeFromNodesDictionary<T>(T node, Type nodeType) where T : INodeWithID | |||
{ | |||
Dictionary<int, INode> nodesDic; | |||
if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) | |||
nodesDic.Remove(node.ID); | |||
} | |||
void EnableNodeFromEngines(INode node, Type nodeType) | |||
{ | |||
ITypeSafeList enginesForNode; | |||
void RemoveNodeFromEngines<T>(T node, Type nodeType) where T : INode | |||
if (_activableEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); | |||
#else | |||
(enginesForNode[j] as INodeEngine).Remove(node); | |||
#endif | |||
} | |||
} | |||
(enginesForNode[j] as IActivableNodeEngine).Enable(node); | |||
} | |||
} | |||
}*/ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
void AddNodeToEngine(IEngine engine, INode node) | |||
{ | |||
(engine as INodeEngine).Add(node); | |||
} | |||
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 RemoveNodeFromEngine(IEngine engine, INode node) | |||
{ | |||
(engine as INodeEngine).Remove(node); | |||
} | |||
#endif | |||
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 | |||
void AddNodeToEngine(IEngine engine, INode node) | |||
{ | |||
(engine as INodeEngine).Add(node); | |||
} | |||
void InternalDisable(FasterList<INodeBuilder> nodeBuilders, int entityID) | |||
{ | |||
/* if (_engineRootWeakReference.IsValid == false) | |||
return; | |||
void RemoveNodeFromEngine(IEngine engine, INode node) | |||
{ | |||
(engine as INodeEngine).Remove(node); | |||
} | |||
#endif | |||
/* | |||
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); | |||
} | |||
} | |||
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 InternalEnable(FasterList<INodeBuilder> nodeBuilders, int entityID) | |||
{/* | |||
if (_engineRootWeakReference.IsValid == false) | |||
return; | |||
void InternalRemove(IFasterList 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); | |||
}*/ | |||
} | |||
for (int i = 0; i < nodes.Count; i++) | |||
{ | |||
var node = nodes[i]; | |||
Type nodeType = node.GetType(); | |||
void InternalRemove(FasterList<INodeBuilder> nodeBuilders, int entityID) | |||
{ | |||
if (_engineRootWeakReference.IsValid == false) | |||
return; | |||
RemoveNodeFromEngines(node, nodeType); | |||
RemoveNodeFromTheDB(node, node.GetType()); | |||
int nodeBuildersCount = nodeBuilders.Count; | |||
for (int i = 0; i < nodeBuildersCount; i++) | |||
{ | |||
Type nodeType = nodeBuilders[i].GetType(); | |||
var nodeWithId = node as INodeWithID; | |||
if (nodeWithId != null) | |||
RemoveNodeFromNodesDictionary(nodeWithId, nodeType); | |||
} | |||
} | |||
ITypeSafeList nodes; | |||
if (_nodesDB.TryGetValue(nodeType, out nodes) == true) | |||
nodes.UnorderedRemove(entityID); | |||
void InternalMetaRemove(FasterList<INode> nodes) | |||
if (nodes.isQueryiableNode) | |||
{ | |||
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); | |||
} | |||
var node = _nodesDBdic[nodeType].GetIndexedNode(entityID); | |||
_nodesDBdic[nodeType].Remove(entityID); | |||
RemoveNodeFromEngines(_nodeEngines, node, nodeType); | |||
} | |||
} | |||
} | |||
void InternalGroupedRemove(FasterList<INodeBuilder> nodeBuilders, int entityID) | |||
{ | |||
} | |||
readonly DataStructures.WeakReference<EnginesRoot> _engineRootWeakReference; | |||
void InternalMetaRemove(FasterList<INodeBuilder> nodeBuilders, int entityID) | |||
{ | |||
} | |||
static void RemoveNodeFromEngines(Dictionary<Type, FasterList<IEngine>> nodeEngines, NodeWithID node, Type nodeType) | |||
{ | |||
FasterList<IEngine> enginesForNode; | |||
*/ | |||
if (nodeEngines.TryGetValue(nodeType, out enginesForNode)) | |||
{ | |||
for (int j = 0; j < enginesForNode.Count; j++) | |||
{ | |||
#if ENGINE_PROFILER_ENABLED && UNITY_EDITOR | |||
EngineProfiler.MonitorRemoveDuration(RemoveNodeFromEngine, (enginesForNode[j] as INodeEngine), node); | |||
#else | |||
(enginesForNode[j] as INodeEngine).Remove(node); | |||
#endif | |||
} | |||
} | |||
} | |||
void SubmitNodes() | |||
{ | |||
int metaNodesCount = _metaNodesToAdd.Count; | |||
int nodesCount = _nodesToAdd.Count; | |||
if (metaNodesCount + nodesCount == 0) return; | |||
_nodesToAdd.Swap(); | |||
_metaNodesToAdd.Swap(); | |||
_groupedNodesToAdd.Swap(); | |||
bool newNodesHaveBeenAddedWhileIterating = | |||
_metaNodesToAdd.Count > 0 | |||
|| _nodesToAdd.Count > 0 | |||
|| _groupedNodesToAdd.Count > 0; | |||
bool newNodesHaveBeenAddedWhileIterating; | |||
int startNodes = 0; | |||
int startMetaNodes = 0; | |||
int numberOfReenteringLoops = 0; | |||
do | |||
while (newNodesHaveBeenAddedWhileIterating) | |||
{ | |||
AddNodesToTheDBAndSuitableEngines(_nodesToAdd, _nodeEngines, _nodesDBdic, _nodesDB); | |||
AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd, _nodeEngines, _nodesDBdic, _metaNodesDB); | |||
if ( _nodesToAdd.Count > 0) | |||
AddNodesToTheDBAndSuitableEngines(_nodesToAdd.current, _nodeEngines, _nodesDBdic, _nodesDB); | |||
if ( _metaNodesToAdd.Count > 0) | |||
AddNodesToTheDBAndSuitableEngines(_metaNodesToAdd.current, _nodeEngines, _nodesDBdic, _metaNodesDB); | |||
if (_groupedNodesToAdd.Count > 0) | |||
AddGroupNodesToTheDBAndSuitableEngines(_groupedNodesToAdd.current, _nodeEngines, _nodesDBdic, _groupNodesDB, _nodesDB); | |||
_nodesToAdd.Clear(); | |||
_metaNodesToAdd.Clear(); | |||
_groupedNodesToAdd.Clear(); | |||
_nodesToAdd.Swap(); | |||
_metaNodesToAdd.Swap(); | |||
_groupedNodesToAdd.Swap(); | |||
newNodesHaveBeenAddedWhileIterating = | |||
_metaNodesToAdd.Count > metaNodesCount || | |||
_nodesToAdd.Count > nodesCount; | |||
startNodes = nodesCount; | |||
startMetaNodes = metaNodesCount; | |||
_metaNodesToAdd.Count > 0 | |||
|| _nodesToAdd.Count > 0 | |||
|| _groupedNodesToAdd.Count > 0; | |||
if (numberOfReenteringLoops > 5) | |||
throw new Exception("possible infinite loop found creating Entities inside INodesEngine Add method, please consider building entities outside INodesEngine Add method"); | |||
numberOfReenteringLoops++; | |||
metaNodesCount = _metaNodesToAdd.Count; | |||
nodesCount = _nodesToAdd.Count; | |||
} while (newNodesHaveBeenAddedWhileIterating); | |||
_nodesToAdd.Clear(); | |||
_metaNodesToAdd.Clear(); | |||
} | |||
} | |||
readonly Dictionary<Type, FasterList<IEngine>> _nodeEngines; | |||
@@ -467,25 +513,60 @@ namespace Svelto.ECS | |||
readonly Dictionary<Type, ITypeSafeList> _nodesDB; | |||
readonly Dictionary<Type, ITypeSafeList> _metaNodesDB; | |||
readonly Dictionary<Type, Dictionary<int, ITypeSafeList>> _groupNodesDB; | |||
readonly Dictionary<int, Dictionary<Type, ITypeSafeList>> _groupNodesDB; | |||
readonly Dictionary<Type, ITypeSafeDictionary> _nodesDBdic; | |||
/// <summary> | |||
/// Need to think about how to make BuildEntity thread safe as well | |||
/// </summary> | |||
readonly Dictionary<Type, ITypeSafeList> _nodesToAdd; | |||
readonly Dictionary<Type, ITypeSafeList> _metaNodesToAdd; | |||
readonly Dictionary<Type, Dictionary<int, ITypeSafeList>> _groupedNodesToAdd; | |||
readonly DoubleBufferedNodes<Dictionary<Type, ITypeSafeList>> _nodesToAdd; | |||
readonly DoubleBufferedNodes<Dictionary<Type, ITypeSafeList>> _metaNodesToAdd; | |||
readonly DoubleBufferedNodes<Dictionary<int, Dictionary<Type, ITypeSafeList>>> _groupedNodesToAdd; | |||
readonly NodeSubmissionScheduler _scheduler; | |||
readonly Type _structNodeEngineType; | |||
readonly Type _groupedStructNodesEngineType; | |||
readonly Type _activableNodeEngineType; | |||
readonly SharedStructNodeLists _sharedStructNodeLists; | |||
readonly SharedGroupedStructNodesLists _sharedGroupedStructNodeLists; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
readonly Dictionary<Type, Type[]> _implementedInterfaceTypes; | |||
readonly DataStructures.WeakReference<EnginesRoot> _engineRootWeakReference; | |||
BuildNodeCallbackStruct _callBackStruct; | |||
BuildNodeCallbackStruct _callBackStructForBuiltNodes; | |||
BuildNodeCallbackStruct _callBackStructForBuiltGroupedNodes; | |||
BuildNodeCallbackStruct _callBackStructForBuiltMetaNodes; | |||
class DoubleBufferedNodes<T> where T : class, IDictionary, new() | |||
{ | |||
readonly T _nodesToAddBufferA = new T(); | |||
readonly T _nodesToAddBufferB = new T(); | |||
public DoubleBufferedNodes() | |||
{ | |||
this.other = _nodesToAddBufferA; | |||
this.current = _nodesToAddBufferB; | |||
} | |||
public T other { get; private set; } | |||
public T current { get; private set; } | |||
public int Count | |||
{ | |||
get { return current.Count; } | |||
} | |||
public void Clear() | |||
{ | |||
current.Clear(); | |||
} | |||
public void Swap() | |||
{ | |||
var toSwap = other; | |||
other = current; | |||
current = toSwap; | |||
} | |||
} | |||
} | |||
} |
@@ -8,24 +8,6 @@ namespace Svelto.ECS | |||
{ | |||
public class EntityDescriptor | |||
{ | |||
protected EntityDescriptor() | |||
{} | |||
/// <summary> | |||
/// if you want to avoid allocation in run-time, you can prebuild | |||
/// EntityDescriptors and use them to build entities at different | |||
/// times | |||
/// </summary> | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild) | |||
{ | |||
_nodesToBuild = new FasterList<INodeBuilder>(nodesToBuild); | |||
} | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild, | |||
params object[] componentsImplementor):this(nodesToBuild) | |||
{ | |||
ProcessImplementors(componentsImplementor); | |||
} | |||
public void AddImplementors(params object[] componentsImplementor) | |||
{ | |||
ProcessImplementors(componentsImplementor); | |||
@@ -38,7 +20,7 @@ namespace Svelto.ECS | |||
internal void BuildGroupedNodes | |||
(int entityID, int groupID, | |||
Dictionary<Type, Dictionary<int, ITypeSafeList>> groupNodes, | |||
Dictionary<int, Dictionary<Type, ITypeSafeList>> groupNodesByType, | |||
ref BuildNodeCallbackStruct callBackstruct) | |||
{ | |||
for (int index = 0; index < _nodesToBuild.Count; index++) | |||
@@ -46,62 +28,68 @@ namespace Svelto.ECS | |||
var nodeBuilder = _nodesToBuild[index]; | |||
var nodeType = nodeBuilder.GetNodeType(); | |||
Dictionary<int, ITypeSafeList> groupedNodesTyped; | |||
Dictionary<Type, ITypeSafeList> groupedNodesTyped; | |||
if (groupNodes.TryGetValue(nodeType, out groupedNodesTyped) == false) | |||
if (groupNodesByType.TryGetValue(groupID, out groupedNodesTyped) == false) | |||
{ | |||
groupedNodesTyped = new Dictionary<int, ITypeSafeList>(); | |||
groupedNodesTyped = new Dictionary<Type, ITypeSafeList>(); | |||
groupNodes.Add(nodeType, groupedNodesTyped); | |||
groupNodesByType.Add(groupID, groupedNodesTyped); | |||
}; | |||
ITypeSafeList nodes; | |||
var mustAdd = groupedNodesTyped.TryGetValue(groupID, out nodes) == false; | |||
var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); | |||
if (mustAdd) | |||
groupedNodesTyped[groupID] = nodes; | |||
if (node != null && nodeBuilder.reflects != FillNodeMode.None) | |||
{ | |||
node = FillNode(node, nodeBuilder.reflects); | |||
SetupImplementors(ref callBackstruct, nodes); | |||
} | |||
/* var groupNode = node as IGroupedNode; | |||
if (groupNode != null) | |||
groupNode.groupID = groupID;*/ | |||
BuildAndFillNode(entityID, groupedNodesTyped, nodeType, nodeBuilder); | |||
} | |||
SetupImplementors(ref callBackstruct, entityID); | |||
} | |||
internal void BuildNodes(int entityID, | |||
Dictionary<Type, ITypeSafeList> nodesToAdd, | |||
Dictionary<Type, ITypeSafeList> nodesByType, | |||
ref BuildNodeCallbackStruct callBackstruct) | |||
{ | |||
for (int index = 0; index < _nodesToBuild.Count; index++) | |||
int count = _nodesToBuild.Count; | |||
for (int index = 0; index < count; index++) | |||
{ | |||
var nodeBuilder = _nodesToBuild[index]; | |||
var nodeType = nodeBuilder.GetNodeType(); | |||
BuildAndFillNode(entityID, nodesByType, nodeType, nodeBuilder); | |||
} | |||
SetupImplementors(ref callBackstruct, entityID); | |||
} | |||
void BuildAndFillNode(int entityID, Dictionary<Type, ITypeSafeList> groupedNodesTyped, Type nodeType, INodeBuilder nodeBuilder) | |||
{ | |||
ITypeSafeList nodes; | |||
ITypeSafeList nodes; | |||
var mustAdd = nodesToAdd.TryGetValue(nodeType, out nodes) == false; | |||
var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); | |||
var nodesPoolWillBeCreated = groupedNodesTyped.TryGetValue(nodeType, out nodes) == false; | |||
var nodeObjectToFill = nodeBuilder.BuildNodeAndAddToList(ref nodes, entityID); | |||
if (mustAdd) | |||
nodesToAdd[nodeType] = nodes; | |||
if (nodesPoolWillBeCreated) | |||
groupedNodesTyped.Add(nodeType, nodes); | |||
if (node != null && nodeBuilder.reflects != FillNodeMode.None) | |||
{ | |||
FillNode(node, nodeBuilder.reflects); | |||
SetupImplementors(ref callBackstruct, nodes); | |||
} | |||
} | |||
//the semantic of this code must still be improved | |||
//but only classes can be filled, so I am aware | |||
//it's a NodeWithID | |||
if (nodeObjectToFill != null) | |||
FillNode(nodeObjectToFill as NodeWithID); | |||
} | |||
/// <summary> | |||
/// if you want to avoid allocation in run-time, you can prebuild | |||
/// EntityDescriptors and use them to build entities at different | |||
/// times | |||
/// </summary> | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild) | |||
{ | |||
_nodesToBuild = new FasterList<INodeBuilder>(nodesToBuild); | |||
} | |||
protected EntityDescriptor(INodeBuilder[] nodesToBuild, | |||
params object[] componentsImplementor):this(nodesToBuild) | |||
{ | |||
ProcessImplementors(componentsImplementor); | |||
} | |||
void ProcessImplementors(object[] implementors) | |||
@@ -144,30 +132,41 @@ namespace Svelto.ECS | |||
void SetupImplementors( | |||
ref BuildNodeCallbackStruct callBackstruct, | |||
ITypeSafeList nodes) | |||
int entityID) | |||
{ | |||
var RemoveEntity = callBackstruct._internalRemove; | |||
var DisableEntity = callBackstruct._internalDisable; | |||
var EnableEntity = callBackstruct._internalEnable; | |||
var RemoveEntity = callBackstruct.internalRemove; | |||
var DisableEntity = callBackstruct.internalDisable; | |||
var EnableEntity = callBackstruct.internalEnable; | |||
Action removeEntityAction = () => { RemoveEntity(nodes); nodes.Clear(); }; | |||
Action disableEntityAction = () => DisableEntity(nodes); | |||
Action enableEntityAction = () => EnableEntity(nodes); | |||
int removingImplementorsCount = _removingImplementors.Count; | |||
for (int index = 0; index < removingImplementorsCount; index++) | |||
_removingImplementors[index].Target.removeEntity = removeEntityAction; | |||
if (removingImplementorsCount > 0) | |||
{ | |||
Action removeEntityAction = () => RemoveEntity(_nodesToBuild, entityID); | |||
for (int index = 0; index < removingImplementorsCount; index++) | |||
_removingImplementors[index].Target.removeEntity = removeEntityAction; | |||
} | |||
int disablingImplementorsCount = _disablingImplementors.Count; | |||
for (int index = 0; index < disablingImplementorsCount; index++) | |||
_disablingImplementors[index].Target.disableEntity = disableEntityAction; | |||
if (disablingImplementorsCount > 0) | |||
{ | |||
Action disableEntityAction = () => DisableEntity(_nodesToBuild, entityID); | |||
for (int index = 0; index < disablingImplementorsCount; index++) | |||
_disablingImplementors[index].Target.disableEntity = disableEntityAction; | |||
} | |||
int enablingImplementorsCount = _enablingImplementors.Count; | |||
for (int index = 0; index < enablingImplementorsCount; index++) | |||
_enablingImplementors[index].Target.enableEntity = enableEntityAction; | |||
if (enablingImplementorsCount > 0) | |||
{ | |||
Action enableEntityAction = () => EnableEntity(_nodesToBuild, entityID); | |||
for (int index = 0; index < enablingImplementorsCount; index++) | |||
_enablingImplementors[index].Target.enableEntity = enableEntityAction; | |||
} | |||
} | |||
TNode FillNode<TNode>(TNode node, FillNodeMode mode) where TNode : INode | |||
void FillNode<TNode>(TNode node) where TNode : NodeWithID | |||
{ | |||
var fields = node.GetType().GetFields(BindingFlags.Public | | |||
BindingFlags.Instance); | |||
@@ -180,15 +179,12 @@ namespace Svelto.ECS | |||
if (_implementorsByType.TryGetValue(fieldType, out component) == false) | |||
{ | |||
if (mode == FillNodeMode.Strict) | |||
{ | |||
Exception e = | |||
new Exception(NOT_FOUND_EXCEPTION + | |||
field.FieldType.Name + " - Node: " + node.GetType().Name + | |||
" - EntityDescriptor " + this); | |||
throw e; | |||
} | |||
} | |||
else | |||
field.SetValue(node, component.Target); | |||
@@ -205,10 +201,8 @@ namespace Svelto.ECS | |||
#endif | |||
} | |||
return node; | |||
} | |||
readonly FasterList<DataStructures.WeakReference<IDisableEntityComponent>> _disablingImplementors = new FasterList<DataStructures.WeakReference<IDisableEntityComponent>>(); | |||
readonly FasterList<DataStructures.WeakReference<IRemoveEntityComponent>> _removingImplementors = new FasterList<DataStructures.WeakReference<IRemoveEntityComponent>>(); | |||
readonly FasterList<DataStructures.WeakReference<IEnableEntityComponent>> _enablingImplementors = new FasterList<DataStructures.WeakReference<IEnableEntityComponent>>(); | |||
@@ -217,8 +211,8 @@ namespace Svelto.ECS | |||
#if DEBUG && !PROFILER | |||
readonly Dictionary<Type, int> _implementorCounterByType = new Dictionary<Type, int>(); | |||
#endif | |||
readonly FasterList<INodeBuilder> _nodesToBuild; | |||
readonly FasterList<INodeBuilder> _nodesToBuild; | |||
const string DUPLICATE_IMPLEMENTOR_ERROR = "the same component is implemented with more than one implementor. This is considered an error and MUST be fixed. "; | |||
const string NULL_IMPLEMENTOR_ERROR = "Null implementor, are you using a wild GetComponents<Monobehaviour> to fetch it? "; | |||
const string NOT_FOUND_EXCEPTION = "Svelto.ECS: Implementor not found for a Node. Implementor Type: "; | |||
@@ -1,4 +1,4 @@ | |||
using Svelto.DataStructures; | |||
using Rewired.Utils; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
@@ -15,16 +15,19 @@ namespace Svelto.ECS.Internal | |||
public interface IActivableNodeEngine : IEngine | |||
{ | |||
void Enable(ITypeSafeList nodes); | |||
void Disable(ITypeSafeList nodes); | |||
void Enable(NodeWithID node); | |||
void Disable(NodeWithID node); | |||
} | |||
public interface INodeEngine : IEngine | |||
{ | |||
void Add(ITypeSafeList nodes); | |||
void Remove(ITypeSafeList nodes); | |||
void Add(NodeWithID node); | |||
void Remove(NodeWithID node); | |||
} | |||
} | |||
namespace Svelto.ECS.Legacy | |||
{ | |||
public interface INodesEngine : INodeEngine | |||
{ | |||
System.Type[] AcceptedNodes(); | |||
@@ -57,7 +60,10 @@ namespace Svelto.ECS | |||
/// usually the ID is the owner of the nodes of that | |||
/// group | |||
/// </summary> | |||
public interface IGroupedStructNodesEngine<T> : IGroupedStructNodesEngine where T:struct, IGroupedNode | |||
{ } | |||
public interface IGroupedStructNodesEngine<T> : IGroupedStructNodesEngine where T : struct, IGroupedNode | |||
{ | |||
void Add(ref T node); | |||
void Remove(ref T node); | |||
} | |||
} | |||
@@ -4,15 +4,19 @@ namespace Svelto.ECS | |||
{ | |||
public interface IEngineNodeDB | |||
{ | |||
ReadOnlyDictionary<int, T> QueryIndexableNodes<T>(); | |||
bool TryQueryNode<T>(int ID, out T node); | |||
T QueryNode<T>(int ID); | |||
FasterReadOnlyList<T> QueryNodes<T>(); | |||
bool TryQueryMetaNode<T>(int metaEntityID, out T node); | |||
T QueryMetaNode<T>(int metaEntityID); | |||
FasterReadOnlyList<T> QueryMetaNodes<T>(); | |||
FasterReadOnlyList<T> QueryGroupedNodes<T>(int group); | |||
T[] QueryNodesAsArray<T>(out int count) where T:struct; | |||
ReadOnlyDictionary<int, T> QueryIndexableNodes<T>() where T:NodeWithID; | |||
bool TryQueryNode<T>(int ID, out T node) where T:NodeWithID; | |||
T QueryNode<T>(int ID) where T:NodeWithID; | |||
bool TryQueryMetaNode<T>(int metaEntityID, out T node) where T:NodeWithID; | |||
T QueryMetaNode<T>(int metaEntityID) where T:NodeWithID; | |||
} | |||
} | |||
@@ -1,17 +1,19 @@ | |||
namespace Svelto.ECS | |||
{ | |||
public interface INode | |||
{} | |||
public interface IStructNodeWithID : INode | |||
{ | |||
int ID { get; set; } | |||
int ID { get; } | |||
} | |||
public interface IGroupedNode | |||
{ | |||
int groupID { get; set; } | |||
} | |||
public interface IStructNodeWithID : INode | |||
{ | |||
new int ID { get; set; } | |||
} | |||
public class NodeWithID: INode | |||
{ | |||
@@ -3,102 +3,83 @@ using Svelto.ECS.Internal; | |||
namespace Svelto.ECS.Internal | |||
{ | |||
public abstract class MultiNodesEngine<T> where T:class | |||
public abstract class MultiNodesEngine<T>:INodeEngine where T:NodeWithID | |||
{ | |||
protected abstract void AddNode(T node); | |||
protected abstract void RemoveNode(T node); | |||
protected abstract void Add(T node); | |||
protected abstract void Remove(T node); | |||
public virtual void Add(NodeWithID node) | |||
{ | |||
Add((T) node); | |||
} | |||
public virtual void Remove(NodeWithID node) | |||
{ | |||
Remove((T) node); | |||
} | |||
} | |||
} | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class MultiNodesEngine : INodesEngine | |||
{ | |||
public abstract System.Type[] AcceptedNodes(); | |||
public abstract void Add(ITypeSafeList nodeWrapper); | |||
public abstract void Remove(ITypeSafeList nodeWrapper); | |||
} | |||
public abstract class MultiNodesEngine<T, U> : MultiNodesEngine<T>, | |||
INodeEngine where T:class where U:class | |||
public abstract class MultiNodesEngine<T, U> : MultiNodesEngine<T> | |||
where T:NodeWithID where U:NodeWithID | |||
{ | |||
protected abstract void AddNode(U node); | |||
protected abstract void RemoveNode(U node); | |||
protected abstract void Add(U node); | |||
protected abstract void Remove(U node); | |||
public virtual void Add(ITypeSafeList nodes) | |||
public override void Add(NodeWithID node) | |||
{ | |||
if (nodes is FasterList<U>) | |||
var castedNode = node as U; | |||
if (castedNode != null) | |||
{ | |||
var strongTypeNodes = (FasterList<U>)nodes; | |||
for (int i = 0; i < strongTypeNodes.Count; i++) | |||
{ | |||
AddNode(strongTypeNodes[i]); | |||
} | |||
Add(castedNode); | |||
} | |||
else | |||
if (nodes is FasterList<T>) | |||
{ | |||
var strongTypeNodes = (FasterList<T>)nodes; | |||
for (int i = 0; i < strongTypeNodes.Count; i++) | |||
{ | |||
AddNode(strongTypeNodes[i]); | |||
} | |||
base.Add(node); | |||
} | |||
} | |||
public virtual void Remove(ITypeSafeList nodeWrapper) | |||
public override void Remove(NodeWithID node) | |||
{ | |||
/* if (nodeWrapper is NodeWrapper<T>) | |||
if (node is U) | |||
{ | |||
T node; | |||
nodeWrapper.GetNode<T>(out node); | |||
RemoveNode(ref node); | |||
Remove((U) node); | |||
} | |||
else | |||
{ | |||
U node; | |||
nodeWrapper.GetNode<U>(out node); | |||
RemoveNode(ref node); | |||
}*/ | |||
base.Remove(node); | |||
} | |||
} | |||
} | |||
public abstract class MultiNodesEngine<T, U, V> : MultiNodesEngine<T, U> where T: class where U : class | |||
public abstract class MultiNodesEngine<T, U, V> : MultiNodesEngine<T, U> | |||
where T: NodeWithID where U : NodeWithID where V:NodeWithID | |||
{ | |||
protected abstract void AddNode(V node); | |||
protected abstract void RemoveNode(V node); | |||
protected abstract void Add(V node); | |||
protected abstract void Remove(V node); | |||
public override void Add(ITypeSafeList nodes) | |||
public override void Add(NodeWithID node) | |||
{ | |||
if (nodes is FasterList<V>) | |||
var castedNode = node as V; | |||
if (castedNode != null) | |||
{ | |||
var strongTypeNodes = (FasterList<V>)nodes; | |||
for (int i = 0; i < strongTypeNodes.Count; i++) | |||
{ | |||
AddNode(strongTypeNodes[i]); | |||
} | |||
Add(castedNode); | |||
} | |||
else | |||
base.Add(nodes); | |||
base.Add(node); | |||
} | |||
public override void Remove(ITypeSafeList nodeWrapper) | |||
public override void Remove(NodeWithID node) | |||
{ | |||
/* if (nodeWrapper is V) | |||
var castedNode = node as V; | |||
if (castedNode != null) | |||
{ | |||
V node; | |||
nodeWrapper.GetNode<V>(out node); | |||
RemoveNode(ref node); | |||
Remove(castedNode); | |||
} | |||
else | |||
base.Remove(nodeWrapper);*/ | |||
base.Remove(node); | |||
} | |||
} | |||
} |
@@ -6,21 +6,19 @@ namespace Svelto.ECS | |||
{ | |||
public interface INodeBuilder | |||
{ | |||
INode BuildAndAddToList(ref ITypeSafeList list, int entityID); | |||
INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID); | |||
Type GetNodeType(); | |||
FillNodeMode reflects { get; } | |||
} | |||
public class NodeBuilder<NodeType> : INodeBuilder where NodeType : NodeWithID, new() | |||
{ | |||
public INode BuildAndAddToList(ref ITypeSafeList list, int entityID) | |||
public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) | |||
{ | |||
if (list == null) | |||
list = new TypeSafeFasterList<NodeType>(); | |||
list = new TypeSafeFasterListForECSForClasses<NodeType>(); | |||
var castedList = list as FasterList<NodeType>; | |||
var castedList = list as TypeSafeFasterListForECSForClasses<NodeType>; | |||
var node = NodeWithID.BuildNode<NodeType>(entityID); | |||
@@ -29,11 +27,6 @@ namespace Svelto.ECS | |||
return node; | |||
} | |||
public FillNodeMode reflects | |||
{ | |||
get { return FillNodeMode.Strict; } | |||
} | |||
public Type GetNodeType() | |||
{ | |||
return typeof(NodeType); | |||
@@ -42,15 +35,15 @@ namespace Svelto.ECS | |||
public class StructNodeBuilder<NodeType> : INodeBuilder where NodeType : struct, IStructNodeWithID | |||
{ | |||
public INode BuildAndAddToList(ref ITypeSafeList list, int entityID) | |||
public INode BuildNodeAndAddToList(ref ITypeSafeList list, int entityID) | |||
{ | |||
var node = default(NodeType); | |||
node.ID = entityID; | |||
if (list == null) | |||
list = new TypeSafeFasterList<NodeType>(); | |||
list = new TypeSafeFasterListForECSForStructs<NodeType>(); | |||
var castedList = list as FasterList<NodeType>; | |||
var castedList = list as TypeSafeFasterListForECSForStructs<NodeType>; | |||
castedList.Add(node); | |||
@@ -61,17 +54,5 @@ namespace Svelto.ECS | |||
{ | |||
return typeof(NodeType); | |||
} | |||
public virtual FillNodeMode reflects | |||
{ | |||
get { return FillNodeMode.None; } | |||
} | |||
} | |||
public enum FillNodeMode | |||
{ | |||
Strict, | |||
None | |||
} | |||
} |
@@ -1,6 +1,6 @@ | |||
#if asdUNITY_EDITOR | |||
#if UNITY_EDITOR | |||
using System; | |||
using System.Collections.Generic; | |||
using UnityEditor; | |||
using UnityEngine; | |||
@@ -1,4 +1,3 @@ | |||
#if asdDEBUG | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics; | |||
@@ -13,10 +12,9 @@ namespace Svelto.ECS.Profiler | |||
{ | |||
static readonly Stopwatch _stopwatch = new Stopwatch(); | |||
public static void MonitorAddDuration(Action<INodeEngine, INodeWrapper> addingFunc, INodeEngine engine, INodeWrapper node) | |||
public static void MonitorAddDuration(Action<INodeEngine, INode> addingFunc, INodeEngine engine, INode node) | |||
{ | |||
EngineInfo info; | |||
if (engineInfos.TryGetValue(engine.GetType(), out info)) | |||
{ | |||
_stopwatch.Start(); | |||
@@ -27,15 +25,14 @@ namespace Svelto.ECS.Profiler | |||
} | |||
} | |||
public static void MonitorRemoveDuration(Action<INodeEngine, INodeWrapper> removeFunc, INodeEngine engine, INodeWrapper node) | |||
public static void MonitorRemoveDuration(Action<INodeEngine, INode> removeFunc, INodeEngine engine, NodeWithID node) | |||
{ | |||
EngineInfo info; | |||
if (engineInfos.TryGetValue(engine.GetType(), out info)) | |||
{ | |||
_stopwatch.Start(); | |||
removeFunc(engine, node); | |||
// engine.Remove(node); | |||
engine.Remove(node); | |||
_stopwatch.Reset(); | |||
info.AddRemoveDuration(_stopwatch.Elapsed.TotalMilliseconds); | |||
@@ -61,4 +58,3 @@ namespace Svelto.ECS.Profiler | |||
public static readonly Dictionary<Type, EngineInfo> engineInfos = new Dictionary<Type, EngineInfo>(); | |||
} | |||
} | |||
#endif |
@@ -1,4 +1,4 @@ | |||
#if asdUNITY_EDITOR | |||
#if UNITY_EDITOR | |||
using System; | |||
using System.Collections.Generic; | |||
using UnityEngine; | |||
@@ -1,28 +1,17 @@ | |||
using Svelto.DataStructures; | |||
using Svelto.ECS.Internal; | |||
namespace Svelto.ECS | |||
{ | |||
public abstract class SingleNodeEngine<T> : INodeEngine where T:class | |||
public abstract class SingleNodeEngine<T> : INodeEngine where T:NodeWithID | |||
{ | |||
public void Add(ITypeSafeList nodes) | |||
public void Add(NodeWithID node) | |||
{ | |||
var strongTypeNodes = (FasterList<T>)nodes; | |||
for (int i = 0; i < strongTypeNodes.Count; i++) | |||
{ | |||
Add(strongTypeNodes[i]); //when byref returns will be vailable, this should be passed by reference, not copy! | |||
} | |||
Add((T)node); //when byref returns will be vailable, this should be passed by reference, not copy! | |||
} | |||
public void Remove(ITypeSafeList nodes) | |||
public void Remove(NodeWithID node) | |||
{ | |||
/* | |||
T node; | |||
nodeWrapper.GetNode(out node); | |||
Remove(node);*/ | |||
Remove((T)node); | |||
} | |||
protected abstract void Add(T node); | |||
@@ -60,8 +60,8 @@ namespace Svelto.ECS | |||
public T[] GetList(int groupID, out int numberOfItems) | |||
{ | |||
var fasterList = (SharedGroupedStructNodesLists.NoVirt.GetList<T>(_container, groupID) as FasterList<T>); | |||
numberOfItems = FasterList<T>.NoVirt.Count(fasterList); | |||
return FasterList<T>.NoVirt.ToArrayFast(fasterList); | |||
return FasterList<T>.NoVirt.ToArrayFast(fasterList, out numberOfItems); | |||
} | |||
readonly SharedGroupedStructNodesLists _container; | |||
@@ -72,20 +72,20 @@ namespace Svelto.ECS | |||
{ | |||
internal SharedStructNodeLists() | |||
{ | |||
_collection = new Dictionary<Type, ITypeSafeList>(); | |||
_collection = new Dictionary<Type, IFasterList>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static FasterList<T> GetList<T>(SharedStructNodeLists obj) where T : struct | |||
{ | |||
ITypeSafeList list; | |||
IFasterList list; | |||
if (obj._collection.TryGetValue(typeof(T), out list)) | |||
{ | |||
return list as FasterList<T>; | |||
} | |||
list = new TypeSafeFasterList<T>(); | |||
list = new FasterList<T>(); | |||
obj._collection.Add(typeof(T), list); | |||
@@ -93,42 +93,42 @@ namespace Svelto.ECS | |||
} | |||
} | |||
readonly Dictionary<Type, ITypeSafeList> _collection; | |||
readonly Dictionary<Type, IFasterList> _collection; | |||
} | |||
public class SharedGroupedStructNodesLists | |||
{ | |||
internal SharedGroupedStructNodesLists() | |||
{ | |||
_collection = new Dictionary<Type, Dictionary<int, ITypeSafeList>>(); | |||
_collection = new Dictionary<Type, Dictionary<int, IFasterList>>(); | |||
} | |||
internal static class NoVirt | |||
{ | |||
internal static ITypeSafeList GetList<T>(SharedGroupedStructNodesLists list, int groupID) where T : struct | |||
internal static IFasterList GetList<T>(SharedGroupedStructNodesLists list, int groupID) where T : struct | |||
{ | |||
Dictionary<int, ITypeSafeList> dic = GetGroup<T>(list); | |||
ITypeSafeList localList; | |||
Dictionary<int, IFasterList> dic = GetGroup<T>(list); | |||
IFasterList localList; | |||
if (dic.TryGetValue(groupID, out localList)) | |||
return localList; | |||
localList = new TypeSafeFasterList<T>(); | |||
localList = new FasterList<T>(); | |||
dic.Add(groupID, localList); | |||
return localList; | |||
} | |||
internal static Dictionary<int, ITypeSafeList> GetGroup<T>(SharedGroupedStructNodesLists list) where T : struct | |||
internal static Dictionary<int, IFasterList> GetGroup<T>(SharedGroupedStructNodesLists list) where T : struct | |||
{ | |||
Dictionary<int, ITypeSafeList> dic; | |||
Dictionary<int, IFasterList> dic; | |||
if (list._collection.TryGetValue(typeof(T), out dic)) | |||
{ | |||
return dic; | |||
} | |||
dic = new Dictionary<int, ITypeSafeList>(); | |||
dic = new Dictionary<int, IFasterList>(); | |||
list._collection.Add(typeof(T), dic); | |||
@@ -136,6 +136,6 @@ namespace Svelto.ECS | |||
} | |||
} | |||
readonly Dictionary<Type, Dictionary<int, ITypeSafeList>> _collection; | |||
readonly Dictionary<Type, Dictionary<int, IFasterList>> _collection; | |||
} | |||
} |