using System; using System.Collections.Generic; using Svelto.DataStructures; using Svelto.Ticker; using Nodes.Player; namespace Svelto.ES { public sealed class EnginesRoot: IEnginesRoot, IEndOfFrameTickable, IEntityFactory { public EnginesRoot(ITicker ticker) { ticker.Add(this); _nodeEngines = new Dictionary>>(); _engineRootWeakReference = new WeakReference(this); _otherEnginesReferences = new FasterList(); _nodesDB = new Dictionary>(); _nodesDBdic = new Dictionary>(); _nodesToAdd = new Queue(); _nodesToRemove = new Queue(); } public void EndOfFrameTick(float deltaSec) { while (_nodesToAdd.Count > 0) InternalAdd(_nodesToAdd.Dequeue()); while (_nodesToRemove.Count > 0) InternalRemove(_nodesToRemove.Dequeue()); } public void AddEngine(IEngine engine) { if (engine is IQueryableNodeEngine) (engine as IQueryableNodeEngine).nodesDB = new EngineNodeDB(_nodesDB, _nodesDBdic); if (engine is INodesEngine) { var nodesEngine = engine as INodesEngine; AddEngine(nodesEngine, nodesEngine.AcceptedNodes(), _nodeEngines); return; } var baseType = engine.GetType().BaseType; if (baseType.IsGenericType) { var genericType = baseType.GetGenericTypeDefinition(); if (genericType == typeof(SingleNodeEngine<>)) { AddEngine(engine as INodeEngine, baseType.GetGenericArguments(), _nodeEngines); return; } } _otherEnginesReferences.Add(engine); } public void BuildEntity(int ID, EntityDescriptor ed) { var entityNodes = ed.BuildNodes(ID, (node) => { if (_engineRootWeakReference.isValid == true) _engineRootWeakReference.Target._nodesToRemove.Enqueue(node); }); for (int i = 0; i < entityNodes.Count; i++) _nodesToAdd.Enqueue(entityNodes[i]); } static void AddEngine(T engine, Type[] types, Dictionary>> engines) where T:INodeEngine { for (int i = 0; i < types.Length; i++) { FasterList> list; var type = types[i]; if (engines.TryGetValue(type, out list) == false) { list = new FasterList>(); engines.Add(type, list); } list.Add(engine); } } void InternalAdd(T node) where T:INode { Type nodeType = node.GetType(); AddNodeToTheSuitableEngines(node, nodeType); AddNodeToTheDB(node, nodeType); } void InternalRemove(T node) where T:INode { Type nodeType = node.GetType(); RemoveNodeFromEngines(node, nodeType); RemoveNodeFromTheDB(node, nodeType); } void AddNodeToTheDB(T node, Type nodeType) where T : INode { FasterList nodes; if (_nodesDB.TryGetValue(nodeType, out nodes) == false) nodes = _nodesDB[nodeType] = new FasterList(); nodes.Add(node); if (node is NodeWithID) { Dictionary nodesDic; if (_nodesDBdic.TryGetValue(nodeType, out nodesDic) == false) nodesDic = _nodesDBdic[nodeType] = new Dictionary(); nodesDic[(node as NodeWithID).ID] = node; } } void AddNodeToTheSuitableEngines(T node, Type nodeType) where T : INode { FasterList> enginesForNode; if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) for (int j = 0; j < enginesForNode.Count; j++) enginesForNode[j].Add(node); } void RemoveNodeFromTheDB(T node, Type nodeType) where T : INode { FasterList nodes; if (_nodesDB.TryGetValue(nodeType, out nodes) == true) nodes.Remove(node); //should I remove it from the dictionary if length is zero? if (node is NodeWithID) { Dictionary nodesDic; if (_nodesDBdic.TryGetValue(nodeType, out nodesDic)) nodesDic.Remove((node as NodeWithID).ID); } } void RemoveNodeFromEngines(T node, Type nodeType) where T : INode { FasterList> enginesForNode; if (_nodeEngines.TryGetValue(nodeType, out enginesForNode)) for (int j = 0; j < enginesForNode.Count; j++) enginesForNode[j].Remove(node); } Dictionary>> _nodeEngines; FasterList _otherEnginesReferences; Dictionary> _nodesDB; Dictionary> _nodesDBdic; Queue _nodesToAdd; Queue _nodesToRemove; WeakReference _engineRootWeakReference; //integrated pooling system //add debug panel like Entitas has //GCHandle should be used to reduce the number of strong references //datastructure could be thread safe //future enhancements: } }