using System; using System.Collections.Generic; using System.Reflection; using Svelto.DataStructures; using Svelto.ECS.Internal; namespace Svelto.ECS { public class EntityDescriptor { protected EntityDescriptor() {} /// /// if you want to avoid allocation in run-time, you can prebuild /// EntityDescriptors and use them to build entities at different /// times /// protected EntityDescriptor(INodeBuilder[] nodesToBuild) { _nodesToBuild = new FasterList(nodesToBuild); } protected EntityDescriptor(INodeBuilder[] nodesToBuild, params object[] componentsImplementor):this(nodesToBuild) { ProcessImplementors(componentsImplementor); } public void AddImplementors(params object[] componentsImplementor) { ProcessImplementors(componentsImplementor); } public void AddNodes(params INodeBuilder[] nodesWithID) { _nodesToBuild.AddRange(nodesWithID); } internal void BuildGroupedNodes (int entityID, int groupID, Dictionary> groupNodes, ref BuildNodeCallbackStruct callBackstruct) { for (int index = 0; index < _nodesToBuild.Count; index++) { var nodeBuilder = _nodesToBuild[index]; var nodeType = nodeBuilder.GetNodeType(); Dictionary groupedNodesTyped; if (groupNodes.TryGetValue(nodeType, out groupedNodesTyped) == false) { groupedNodesTyped = new Dictionary(); groupNodes.Add(nodeType, 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;*/ } } internal void BuildNodes(int entityID, Dictionary nodesToAdd, ref BuildNodeCallbackStruct callBackstruct) { for (int index = 0; index < _nodesToBuild.Count; index++) { var nodeBuilder = _nodesToBuild[index]; var nodeType = nodeBuilder.GetNodeType(); ITypeSafeList nodes; var mustAdd = nodesToAdd.TryGetValue(nodeType, out nodes) == false; var node = nodeBuilder.BuildAndAddToList(ref nodes, entityID); if (mustAdd) nodesToAdd[nodeType] = nodes; if (node != null && nodeBuilder.reflects != FillNodeMode.None) { FillNode(node, nodeBuilder.reflects); SetupImplementors(ref callBackstruct, nodes); } } } void ProcessImplementors(object[] implementors) { for (int index = 0; index < implementors.Length; index++) { var implementor = implementors[index]; if (implementor != null) { if (implementor is IRemoveEntityComponent) _removingImplementors.Add(new DataStructures.WeakReference(implementor as IRemoveEntityComponent)); if (implementor is IDisableEntityComponent) _disablingImplementors.Add(new DataStructures.WeakReference(implementor as IDisableEntityComponent)); if (implementor is IEnableEntityComponent) _enablingImplementors.Add(new DataStructures.WeakReference(implementor as IEnableEntityComponent)); var interfaces = implementor.GetType().GetInterfaces(); var weakReference = new DataStructures.WeakReference(implementor); for (int iindex = 0; iindex < interfaces.Length; iindex++) { var componentType = interfaces[iindex]; _implementorsByType[componentType] = weakReference; #if DEBUG && !PROFILER if (_implementorCounterByType.ContainsKey(componentType) == false) _implementorCounterByType[componentType] = 1; else _implementorCounterByType[componentType]++; #endif } } #if DEBUG && !PROFILER else Utility.Console.LogError(NULL_IMPLEMENTOR_ERROR.FastConcat(ToString())); #endif } } void SetupImplementors( ref BuildNodeCallbackStruct callBackstruct, ITypeSafeList nodes) { 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; int disablingImplementorsCount = _disablingImplementors.Count; 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; } TNode FillNode(TNode node, FillNodeMode mode) where TNode : INode { 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; DataStructures.WeakReference component; 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); #if DEBUG && !PROFILER { if (_implementorCounterByType[fieldType] != 1) { Utility.Console.LogError( DUPLICATE_IMPLEMENTOR_ERROR.FastConcat("component: ", fieldType.ToString(), " implementor: ", component.Target.ToString())); } } #endif } return node; } readonly FasterList> _disablingImplementors = new FasterList>(); readonly FasterList> _removingImplementors = new FasterList>(); readonly FasterList> _enablingImplementors = new FasterList>(); readonly Dictionary> _implementorsByType = new Dictionary>(); #if DEBUG && !PROFILER readonly Dictionary _implementorCounterByType = new Dictionary(); #endif readonly FasterList _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 to fetch it? "; const string NOT_FOUND_EXCEPTION = "Svelto.ECS: Implementor not found for a Node. Implementor Type: "; } }