using System; using System.Collections.Generic; using System.Reflection; using Svelto.DataStructures; #if NETFX_CORE using BindingFlags = System.Reflection.BindingFlags; #endif namespace Svelto.ECS { public class EntityDescriptor { protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor) { _nodesToBuild = new FasterList(nodesToBuild); ProcessImplementors(componentsImplementor); } public void AddImplementors(params object[] componentsImplementor) { ProcessImplementors(componentsImplementor); } void ProcessImplementors(object[] implementors) { for (int index = 0; index < implementors.Length; index++) { var implementor = implementors[index]; if (implementor is IRemoveEntityComponent) _removingImplementors.Add(implementor as IRemoveEntityComponent); if (implementor is IDisableEntityComponent) _disablingImplementors.Add(implementor as IDisableEntityComponent); if (implementor is IEnableEntityComponent) _enablingImplementors.Add(implementor as IEnableEntityComponent); var interfaces = implementor.GetType().GetInterfaces(); for (int iindex = 0; iindex < interfaces.Length; iindex++) { _implementorsByType[interfaces[iindex]] = implementor; } } } public void AddNodes(params INodeBuilder[] nodesWithID) { _nodesToBuild.AddRange(nodesWithID); } public virtual FasterList BuildNodes(int ID) { var nodes = new FasterList(); for (int index = 0; index < _nodesToBuild.Count; index++) { var nodeBuilder = _nodesToBuild[index]; var node = nodeBuilder.Build(ID); if (nodeBuilder.reflects != FillNodeMode.None) node = FillNode(node, nodeBuilder.reflects); nodes.Add(node); } return nodes; } internal FasterList BuildNodes(int ID, Action> removeEntity, Action> enableEntity, Action> disableEntity) { var nodes = BuildNodes(ID); SetupImplementors(removeEntity, enableEntity, disableEntity, nodes); return nodes; } void SetupImplementors( Action> removeEntity, Action> enableEntity, Action> disableEntity, FasterList 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; } INode FillNode(INode node, FillNodeMode mode) { var fields = node.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance); for (int i = fields.Length - 1; i >= 0; --i) { var field = fields[i]; Type fieldType = field.FieldType; object component; if ((_implementorsByType.TryGetValue(fieldType, out component)) == false) { if (mode == FillNodeMode.Strict) { Exception e = new Exception("Svelto.ECS: Implementor not found for a Node. " + "Implementor Type: " + field.FieldType.Name + " - Node: " + node.GetType().Name + " - EntityDescriptor " + this); throw e; } } else field.SetValue(node, component); } return node; } readonly FasterList _disablingImplementors = new FasterList(); readonly FasterList _removingImplementors = new FasterList(); readonly FasterList _enablingImplementors = new FasterList(); readonly Dictionary _implementorsByType = new Dictionary(); readonly FasterList _nodesToBuild; } public interface INodeBuilder { INodeWithID Build(int ID); FillNodeMode reflects { get; } } public class NodeBuilder : INodeBuilder where NodeType : NodeWithID, new() { public INodeWithID Build(int ID) { NodeWithID node = NodeWithID.BuildNode(ID); return (NodeType)node; } public FillNodeMode reflects { get { return FillNodeMode.Strict; } } } //To Do: Probably I will need to add an //FastStructNodeBuilder where reflects is false public class StructNodeBuilder : INodeBuilder where NodeType : struct, IStructNodeWithID { public INodeWithID Build(int ID) { IStructNodeWithID node = default(NodeType); node.ID = ID; return node; } public FillNodeMode reflects { get { return FillNodeMode.Relaxed; } } } public enum FillNodeMode { Strict, Relaxed, None } }