///// <summary>
        ///// Fetches every node connection declaration for each node type for later use
        ///// </summary>
        //public static void FetchNodeConnectionDeclarations()
        //{
        //          nodePortDeclarations = NodeSystemSetting.Inst.NodePortDec;
        //}

        /// <summary>
        /// Updates all node connection ports in the given node and creates or adjusts them according to the declaration
        /// </summary>
        public static void UpdateConnectionPorts(Node node)
        {
            foreach (ConnectionPortDeclaration portDecl in GetPortDeclarationEnumerator(node, true))
            {
                ConnectionPort port = (ConnectionPort)portDecl.portField.GetValue(node);
                if (port == null)
                {                 // Create new port from declaration
                    port = portDecl.portInfo.CreateNew(node);
                    portDecl.portField.SetValue(node, port);
                }
                else
                {                 // Check port values against port declaration
                    portDecl.portInfo.UpdateProperties(port);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Removes the connection of this port to the specified port if existant
        /// </summary>
        public void RemoveConnection(ConnectionPort port, bool silent = false)
        {
            Undo.RecordObjects(new [] { this, port }, "NodeEditor_连接移除保存");
            if (port == null)
            {
                connections.RemoveAll(p => p != null);
                return;
            }

            if (!silent)
            {
                NodeEditorCallbacks.IssueOnRemoveConnection(this, port);
            }
            port.connections.Remove(this);
            connections.Remove(port);
        }
Beispiel #3
0
        /// <summary>
        /// Returns whether every direct ancestor has been calculated
        /// </summary>
        public bool ancestorsCalculated()
        {
            for (int i = 0; i < inputPorts.Count; i++)
            {
                ConnectionPort port = inputPorts[i];
                for (int t = 0; t < port.connections.Count; t++)
                {
                    if (!port.connections[t].body.calculated)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Beispiel #4
0
 public virtual bool IsCompatibleWith(ConnectionPort port)
 {
     if (port.GetType() != ConnectionType)
     {
         return(false);
     }
     if (port.styleID != StyleID)
     {
         return(false);
     }
     if (!(Direction == Direction.None && port.direction == Direction.None) &&
         !(Direction == Direction.In && port.direction == Direction.Out) &&
         !(Direction == Direction.Out && port.direction == Direction.In))
     {
         return(false);
     }
     return(true);
 }
 public static void IssueOnRemoveConnection(ConnectionPort port1, ConnectionPort port2)
 {
     if (OnRemoveConnection != null)
     {
         OnRemoveConnection.Invoke(port1, port2);
     }
     for (int cnt = 0; cnt < receiverCount; cnt++)
     {
         if (callbackReceiver [cnt] == null)
         {
             callbackReceiver.RemoveAt(cnt--);
         }
         else
         {
             callbackReceiver [cnt].OnRemoveConnection(port1, port2);
         }
     }
 }
 public static void IssueOnAddConnectionPort(ConnectionPort connectionPort)
 {
     if (OnAddConnectionPort != null)
     {
         OnAddConnectionPort.Invoke(connectionPort);
     }
     for (int cnt = 0; cnt < receiverCount; cnt++)
     {
         if (callbackReceiver [cnt] == null)
         {
             callbackReceiver.RemoveAt(cnt--);
         }
         else
         {
             callbackReceiver [cnt].OnAddConnectionPort(connectionPort);
         }
     }
 }
Beispiel #7
0
        /// <summary>
        /// Returns all node IDs that can automatically connect to the specified port.
        /// If port is null, all node IDs are returned.
        /// </summary>
        public static List <string> getCompatibleNodes(ConnectionPort port)
        {
            if (port == null)
            {
                return(NodeTypes.nodes.Keys.ToList());
            }
            List <string> compatibleNodes = new List <string> ();

            foreach (NodeTypeData nodeData in NodeTypes.nodes.Values)
            {             // Iterate over all nodes to check compability of any of their connection ports
                if (ConnectionPortManager.GetPortDeclarations(nodeData.typeID).Any(
                        (ConnectionPortDeclaration portDecl) => portDecl.portInfo.IsCompatibleWith(port)))
                {
                    compatibleNodes.Add(nodeData.typeID);
                }
            }
            return(compatibleNodes);
        }
        public override bool IsCompatibleWith(ConnectionPort port)
        {
            if (!(Direction == Direction.None && port.direction == Direction.None) &&
                !(Direction == Direction.In && port.direction == Direction.Out) &&
                !(Direction == Direction.Out && port.direction == Direction.In))
            {
                return(false);
            }
            ValueConnectionKnob valueKnob = port as ValueConnectionKnob;

            if (valueKnob == null)
            {
                return(false);
            }
            Type knobType = ConnectionPortStyles.GetValueType(StyleID);

            return(knobType.IsAssignableFrom(valueKnob.valueType));
        }
        public static void ReinstateNode(Node node, List <ConnectionPort> connectedPorts)
        {
            if (node == null)
            {             // Not critical. Happens when undo records are triggered, but it's canvas has been unloaded
                // Debug.LogWarning("Lost reference to Undo SO 'node'!");
                return;
            }
            if (connectedPorts == null)             // Should not happen if node has not been lost
            {
                Debug.LogWarning("Lost reference to Undo SO 'connectedPorts'!");
            }
            node.canvas.nodes.Remove(node);
            node.canvas.nodes.Add(node);
            ConnectionPortManager.UpdateConnectionPorts(node);
            if (connectedPorts != null)
            {
                int portIndex = 0;
                for (int i = 0; i < connectedPorts.Count; i++)
                {
                    if (connectedPorts[i] == null)
                    {                     // 'Decode' null-seperated list
                        portIndex++;
                        continue;
                    }
                    if (node.connectionPorts.Count <= portIndex)
                    {
                        Debug.LogWarning("Misaligned port count in reinstated node!");
                        break;
                    }
                    ConnectionPort port1 = node.connectionPorts[portIndex], port2 = connectedPorts[i];
                    // Workaround for undo records created in playmode that have being deleted (by Unity) after exiting
                    if (port1.body.canvas.nodes.Contains(port1.body) && port2.body.canvas.nodes.Contains(port2.body))
                    {
                        port1.TryApplyConnection(port2, true);
                    }
                }

                if (node.connectionPorts.Count > portIndex)
                {
                    Debug.LogWarning("Misaligned port count in reinstated node!");
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Removes the connection of this port to the specified port if existant
        /// </summary>
        public void RemoveConnection(ConnectionPort port, bool silent = false)
        {
            if (port == null)
            {
                connections.RemoveAll(p => p != null);
                return;
            }

            if (!silent)
            {
                NodeEditorCallbacks.IssueOnRemoveConnection(this, port);
            }
            port.connections.Remove(this);
            connections.Remove(port);

            if (!silent)
            {
                body.canvas.OnNodeChange(body);
            }
        }
Beispiel #11
0
        /// <summary>
        /// Determines whether a connection can be applied between this port and the specified port
        /// </summary>
        public virtual bool CanApplyConnection(ConnectionPort port)
        {
            if (port == null || body == port.body || connections.Contains(port))
            {
                return(false);
            }

            if (direction == Direction.None && port.direction == Direction.None)
            {
                return(true); // None-Directive connections can always connect
            }
            if (direction == Direction.In && port.direction != Direction.Out)
            {
                return(false); // Cannot connect inputs with anything other than outputs
            }
            if (direction == Direction.Out && port.direction != Direction.In)
            {
                return(false); // Cannot connect outputs with anything other than inputs
            }
            if (!body.canvas.allowRecursion)
            {
                // Assure no loop would be created
                bool loop;
                if (direction == Direction.Out)
                {
                    loop = body.isChildOf(port.body);
                }
                else
                {
                    loop = port.body.isChildOf(body);
                }
                if (loop)
                {
                    // Loop would be created, not allowed
                    Debug.LogWarning("Cannot apply connection: Recursion detected!");
                    return(false);
                }
            }

            return(true);
        }
Beispiel #12
0
        /// <summary>
        /// Applies a connection between between this port and the specified port.
        /// 'CanApplyConnection' has to be checked before to avoid interferences!
        /// </summary>
        public void ApplyConnection(ConnectionPort port, bool silent = false)
        {
            if (port == null)
            {
                return;
            }

            if (maxConnectionCount == ConnectionCount.Single && connections.Count > 0)
            {             // Respect maximum connection count on this port
                RemoveConnection(connections[0], silent);
                connections.Clear();
            }
            connections.Add(port);

            if (port.maxConnectionCount == ConnectionCount.Single && port.connections.Count > 0)
            {             // Respect maximum connection count on the other port
                port.RemoveConnection(port.connections[0], silent);
                port.connections.Clear();
            }
            port.connections.Add(this);

#if UNITY_EDITOR
            if (!silent)
            {             // Create Undo record
                          // Important: Copy variables used within anonymous functions within same level (this if block) for correct serialization!
                ConnectionPort port1 = this, port2 = port;
                UndoPro.UndoProManager.RecordOperation(
                    () => NodeEditorUndoActions.CreateConnection(port1, port2),
                    () => NodeEditorUndoActions.DeleteConnection(port1, port2),
                    "Create Connection");
            }
#endif

            if (!silent)
            {             // Callbacks
                port.body.OnAddConnection(port, this);
                body.OnAddConnection(this, port);
                NodeEditorCallbacks.IssueOnAddConnection(this, port);
                body.canvas.OnNodeChange(direction == Direction.In? port.body : body);
            }
        }
Beispiel #13
0
 /// <summary>
 /// Recursively checks whether this node is in a loop
 /// </summary>
 internal bool isInLoop()
 {
     if (BeginRecursiveSearchLoop())
     {
         return(this == startRecursiveSearchNode);
     }
     for (int i = 0; i < inputPorts.Count; i++)
     {
         ConnectionPort port = inputPorts[i];
         for (int t = 0; t < port.connections.Count; t++)
         {
             if (port.connections[t].body.isInLoop())
             {
                 StopRecursiveSearchLoop();
                 return(true);
             }
         }
     }
     EndRecursiveSearchLoop();
     return(false);
 }
Beispiel #14
0
        /// <summary>
        /// Determines whether a connection can be applied between this port and the specified port
        /// </summary>
        public virtual bool CanApplyConnection(ConnectionPort port)
        {
            if (port == null || body == port.body || connections.Contains(port))
            {
                return(false);
            }

            if (direction == Direction.None && port.direction == Direction.None)
            {
                return(true);                // None-Directive connections can always connect
            }
            if (direction == Direction.In && port.direction != Direction.Out)
            {
                return(false);                // Cannot connect inputs with anything other than outputs
            }
            if (direction == Direction.Out && port.direction != Direction.In)
            {
                return(false);                // Cannot connect outputs with anything other than inputs
            }
            if (styleID != port.styleID)
            {
                return(false);              // Cannot connect two different styles
            }
            if (direction == Direction.Out) // Let inputs handle checks for recursion
            {
                return(port.CanApplyConnection(this));
            }

            if (port.body.isChildOf(body))
            {             // Recursive
                if (!port.body.allowsLoopRecursion(body))
                {
                    // TODO: Generic Notification
                    Debug.LogWarning("Cannot apply connection: Recursion detected!");
                    return(false);
                }
            }
            return(true);
        }
        /// <summary>
        /// Removes the connection of this port to the specified port if existant
        /// </summary>
        public void RemoveConnection(ConnectionPort port, bool silent = false)
        {
#if UNITY_EDITOR
            if (silent == false && port != null)
            {             // Undo record
                // Important: Copy variables used within anonymous functions within same level (this if block) for correct serialization!
                ConnectionPort port1 = this, port2 = port;
                UndoPro.UndoProManager.RecordOperation(
                    () => NodeEditorUndoActions.DeleteConnection(port1, port2),
                    () => NodeEditorUndoActions.CreateConnection(port1, port2),
                    "Delete Connection");
            }
#endif

            if (port == null)
            {
                Debug.LogWarning("Cannot delete null port!");
                //connections.RemoveAll (p => p != null);
                return;
            }

            if (!silent)
            {
                port.body.OnRemoveConnection(port, this);
                this.body.OnRemoveConnection(this, port);
                NodeEditorCallbacks.IssueOnRemoveConnection(this, port);
            }

            port.connections.Remove(this);
            connections.Remove(port);

            if (!silent)
            {
                body.canvas.OnNodeChange(body);
            }
        }
        /// <summary>
        /// Returns an enumerator of type ConnectionPortDeclaration over all port declarations of the given node
        /// </summary>
        public static IEnumerable GetPortDeclarationEnumerator(Node node, bool triggerUpdate = false)
        {
            List <ConnectionPort> declaredConnectionPorts = new List <ConnectionPort> ();

            ConnectionPortDeclaration[] portDecls;
            if (nodePortDeclarations.TryGetValue(node.GetID, out portDecls))
            {
                foreach (ConnectionPortDeclaration portDecl in portDecls)
                {                 // Iterate over each connection port and yield it's declaration
                    yield return(portDecl);

                    ConnectionPort port = (ConnectionPort)portDecl.portField.GetValue(node);
                    if (port != null)
                    {
                        declaredConnectionPorts.Add(port);
                    }
                }
            }
            if (triggerUpdate)
            {             // Update lists as values might have changes when calling this function
                node.staticConnectionPorts = declaredConnectionPorts;
                UpdateRepresentativePortLists(node);
            }
        }
Beispiel #17
0
 /// <summary>
 /// Creates a node of the specified ID at pos on the current canvas, optionally auto-connecting the specified output to a matching input
 /// </summary>
 public static Node Create(string nodeID, Vector2 pos, ConnectionPort connectingPort = null, bool silent = false, bool init = true)
 {
     return(Create(nodeID, pos, NodeEditor.curNodeCanvas, connectingPort, silent, init));
 }
Beispiel #18
0
 /// <summary>
 /// Callback when the given port on this node was assigned a new connection
 /// </summary>
 protected internal virtual void OnAddConnection(ConnectionPort port, ConnectionPort connection)
 {
 }
Beispiel #19
0
        /// <summary>
        /// Creates a working copy of the specified nodeCanvas, and optionally also of it's associated editorStates.
        /// This breaks the link of this object to any stored assets and references. That means, that all changes to this object will have to be explicitly saved.
        /// </summary>
        public static NodeCanvas CreateWorkingCopy(NodeCanvas nodeCanvas, bool editorStates = true)
        {
            if (nodeCanvas == null)
            {
                return(null);
            }

            // Lists holding initial and cloned version of each ScriptableObject for later replacement of references
            List <ScriptableObject> allSOs    = new List <ScriptableObject> ();
            List <ScriptableObject> clonedSOs = new List <ScriptableObject> ();

            System.Func <ScriptableObject, ScriptableObject> copySOs = (ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so);

            // Clone and enter the canvas object and it's referenced SOs
            nodeCanvas = AddClonedSO(allSOs, clonedSOs, nodeCanvas);
            AddClonedSOs(allSOs, clonedSOs, nodeCanvas.GetScriptableObjects());

            // Iterate over the core ScriptableObjects in the canvas and clone them
            for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++)
            {
                Node node = nodeCanvas.nodes[nodeCnt];

                // Clone Node and additional scriptableObjects
                Node clonedNode = AddClonedSO(allSOs, clonedSOs, node);
                AddClonedSOs(allSOs, clonedSOs, clonedNode.GetScriptableObjects());

                // Update representative port list connectionPorts with all ports and clone them
                ConnectionPortManager.UpdatePortLists(clonedNode);
                AddClonedSOs(allSOs, clonedSOs, clonedNode.connectionPorts);
            }

            // Replace every reference to any of the initial SOs of the first list with the respective clones of the second list
            nodeCanvas.CopyScriptableObjects(copySOs);

            for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++)
            {             // Replace SOs in all Nodes
                Node node = nodeCanvas.nodes[nodeCnt];

                // Replace node and additional ScriptableObjects with their copies
                Node clonedNode = nodeCanvas.nodes[nodeCnt] = ReplaceSO(allSOs, clonedSOs, node);
                clonedNode.CopyScriptableObjects(copySOs);

                // Replace ConnectionPorts
                foreach (ConnectionPortDeclaration portDecl in ConnectionPortManager.GetPortDeclarationEnumerator(clonedNode, true))
                {                 // Iterate over each static port declaration and replace it with it's connections
                    ConnectionPort port = (ConnectionPort)portDecl.portField.GetValue(clonedNode);
                    port = ReplaceSO(allSOs, clonedSOs, port);
                    for (int c = 0; c < port.connections.Count; c++)
                    {
                        port.connections[c] = ReplaceSO(allSOs, clonedSOs, port.connections[c]);
                    }
                    port.body = clonedNode;
                    portDecl.portField.SetValue(clonedNode, port);
                }
                for (int i = 0; i < clonedNode.dynamicConnectionPorts.Count; i++)
                {                 // Iterate over all dynamic connection ports
                    ConnectionPort port = clonedNode.dynamicConnectionPorts[i];
                    port = ReplaceSO(allSOs, clonedSOs, port);
                    for (int c = 0; c < port.connections.Count; c++)
                    {
                        port.connections[c] = ReplaceSO(allSOs, clonedSOs, port.connections[c]);
                    }
                    port.body = clonedNode;
                    clonedNode.dynamicConnectionPorts[i] = port;
                }
            }

            if (editorStates)             // Clone the editorStates
            {
                nodeCanvas.editorStates = CreateWorkingCopy(nodeCanvas.editorStates, nodeCanvas);
            }
            // Fix references in editorStates to Nodes in the canvas
            foreach (NodeEditorState state in nodeCanvas.editorStates)
            {
                state.selectedNode = ReplaceSO(allSOs, clonedSOs, state.selectedNode);
            }

            return(nodeCanvas);
        }
Beispiel #20
0
        /// <summary>
        /// Creates a node of the specified ID at pos on the specified canvas, optionally auto-connecting the specified output to a matching input
        /// silent disables any events, init specifies whether OnCreate should be called
        /// </summary>
        public static Node Create(string nodeID, Vector2 pos, NodeCanvas hostCanvas,
                                  ConnectionPort connectingPort = null, bool silent = false, bool init = true)
        {
            if (string.IsNullOrEmpty(nodeID) || hostCanvas == null)
            {
                throw new ArgumentException();
            }
            if (!NodeCanvasManager.CheckCanvasCompability(nodeID, hostCanvas.GetType()))
            {
                throw new UnityException("Cannot create Node with ID '" + nodeID +
                                         "' as it is not compatible with the current canavs type (" +
                                         hostCanvas.GetType().ToString() + ")!");
            }
            if (!hostCanvas.CanAddNode(nodeID))
            {
                throw new UnityException("Cannot create Node with ID '" + nodeID + "' on the current canvas of type (" +
                                         hostCanvas.GetType().ToString() + ")!");
            }

            // Create node from data
            NodeTypeData data = NodeTypes.getNodeData(nodeID);
            Node         node = (Node)CreateInstance(data.type);

            if (node == null)
            {
                return(null);
            }

            // Init node state
            node.name     = node.Title;
            node.autoSize = node.DefaultSize;
            node.position = pos;
            ConnectionPortManager.UpdateConnectionPorts(node);
            if (init)
            {
                node.OnCreate();
            }

            if (connectingPort != null)
            {
                // Handle auto-connection and link the output to the first compatible input
                foreach (ConnectionPort port in node.connectionPorts)
                {
                    if (port.TryApplyConnection(connectingPort, silent))
                    {
                        break;
                    }
                }
            }

            // Add node to host canvas
            hostCanvas.nodes.Add(node);
            if (!silent)
            {
                // Callbacks
                hostCanvas.OnNodeChange(connectingPort != null ? connectingPort.body : node);
                NodeEditorCallbacks.IssueOnAddNode(node);
                hostCanvas.Validate();
                NodeEditor.RepaintClients();
            }

            return(node);
        }
 public virtual void OnAddConnectionPort(ConnectionPort knob)
 {
 }
Beispiel #22
0
        /// <summary>
        /// Creates a copy of the specified node at pos on the specified canvas, optionally auto-connecting the specified output to a matching input
        /// silent disables any events
        /// </summary>
        public static Node CreateCopy(Node toCopy, Vector2 pos, NodeCanvas hostCanvas, ConnectionPort connectingPort = null, bool silent = false)
        {
            if (toCopy == null || hostCanvas == null)
            {
                throw new ArgumentException();
            }
            if (!NodeCanvasManager.CheckCanvasCompability(toCopy.GetID, hostCanvas.GetType()))
            {
                throw new UnityException("Cannot create Node with ID '" + toCopy.GetID + "' as it is not compatible with the current canvas type (" + hostCanvas.GetType().ToString() + ")!");
            }
            if (!hostCanvas.CanAddNode(toCopy.GetID))
            {
                throw new UnityException("Cannot create Node with ID '" + toCopy.GetID + "' on the current canvas of type (" + hostCanvas.GetType().ToString() + ")!");
            }
            Node node = ScriptableObject.Instantiate(toCopy);

            //Clone static connection ports
            foreach (ConnectionPortDeclaration portDecl in ConnectionPortManager.GetPortDeclarationEnumerator(node, true))
            {
                ConnectionPort port = (ConnectionPort)portDecl.portField.GetValue(node);
                port = portDecl.portInfo.CreateNew(node);
                portDecl.portField.SetValue(node, port);
            }
            //Clone dynamic connection ports
            for (int i = 0; i < node.dynamicConnectionPorts.Count; ++i)
            {
                node.dynamicConnectionPorts[i]      = ScriptableObject.Instantiate(node.dynamicConnectionPorts[i]);
                node.dynamicConnectionPorts[i].body = node;
                node.dynamicConnectionPorts[i].ClearConnections();
            }
            ConnectionPortManager.UpdateRepresentativePortLists(node);
            //Clone child SOs
            System.Func <ScriptableObject, ScriptableObject> copySOs = (ScriptableObject so) => ScriptableObject.Instantiate(so);;
            node.CopyScriptableObjects(copySOs);
            if (node == null)
            {
                return(null);
            }

            // Init node state
            node.name     = node.Title;
            node.autoSize = node.DefaultSize;
            node.position = pos;
            ConnectionPortManager.UpdateConnectionPorts(node);

            if (connectingPort != null)
            { // Handle auto-connection and link the output to the first compatible input
                for (int i = 0; i < node.connectionPorts.Count; i++)
                {
                    if (node.connectionPorts[i].TryApplyConnection(connectingPort, silent))
                    {
                        break;
                    }
                }
            }

            // Add node to host canvas
            hostCanvas.nodes.Add(node);
            if (!silent)
            { // Callbacks
                hostCanvas.OnNodeChange(connectingPort != null ? connectingPort.body : node);
                NodeEditorCallbacks.IssueOnAddNode(node);
                hostCanvas.Validate();
                NodeEditor.RepaintClients();
            }

            return(node);
        }
Beispiel #23
0
 /// <summary>
 /// Creates a copy of the specified at pos on the current canvas, optionally auto-connecting the specified output to a matching input
 /// </summary>
 public static Node CreateCopy(Node toCopy, Vector2 pos, ConnectionPort connectingPort = null, bool silent = false)
 {
     return(CreateCopy(toCopy, pos, NodeEditor.curNodeCanvas, connectingPort, silent));
 }
 // Connection
 public virtual void OnAddConnection(ConnectionPort port1, ConnectionPort port2)
 {
 }
Beispiel #25
0
        /// <summary>
        /// Creates a node of the specified ID at pos on the specified canvas, optionally auto-connecting the specified output to a matching input
        /// silent disables any events, init specifies whether OnCreate should be called
        /// </summary>
        public static Node Create(string nodeID, Vector2 pos, NodeCanvas hostCanvas, ConnectionPort connectingPort = null, bool silent = false, bool init = true)
        {
            if (string.IsNullOrEmpty(nodeID) || hostCanvas == null)
            {
                throw new ArgumentException();
            }
            if (!NodeCanvasManager.CheckCanvasCompability(nodeID, hostCanvas.GetType()))
            {
                throw new UnityException("Cannot create Node with ID '" + nodeID + "' as it is not compatible with the current canavs type (" + hostCanvas.GetType().ToString() + ")!");
            }
            if (!hostCanvas.CanAddNode(nodeID))
            {
                throw new UnityException("Cannot create Node with ID '" + nodeID + "' on the current canvas of type (" + hostCanvas.GetType().ToString() + ")!");
            }

            // Create node from data
            NodeTypeData data = NodeTypes.getNodeData(nodeID);
            Node         node = (Node)CreateInstance(data.type);

            if (node == null)
            {
                return(null);
            }

            // Init node state
            node.canvas   = hostCanvas;
            node.name     = node.Title;
            node.autoSize = node.DefaultSize;
            node.position = pos;
            ConnectionPortManager.UpdateConnectionPorts(node);
            if (init)
            {
                node.OnCreate();
            }

            if (connectingPort != null)
            {             // Handle auto-connection and link the output to the first compatible input
                for (int i = 0; i < node.connectionPorts.Count; i++)
                {
                    if (node.connectionPorts[i].TryApplyConnection(connectingPort, true))
                    {
                        break;
                    }
                }
            }

            // Add node to host canvas
            hostCanvas.nodes.Add(node);
            if (!silent)
            {             // Callbacks
                hostCanvas.OnNodeChange(connectingPort != null ? connectingPort.body : node);
                NodeEditorCallbacks.IssueOnAddNode(node);
                hostCanvas.Validate();
                NodeEditor.RepaintClients();
            }

#if UNITY_EDITOR
            if (!silent)
            {
                List <ConnectionPort> connectedPorts = new List <ConnectionPort>();
                foreach (ConnectionPort port in node.connectionPorts)
                {                 // 'Encode' connected ports in one list (double level cannot be serialized)
                    foreach (ConnectionPort conn in port.connections)
                    {
                        connectedPorts.Add(conn);
                    }
                    connectedPorts.Add(null);
                }
                Node createdNode = node;
                UndoPro.UndoProManager.RecordOperation(
                    () => NodeEditorUndoActions.ReinstateNode(createdNode, connectedPorts),
                    () => NodeEditorUndoActions.RemoveNode(createdNode),
                    "Create Node");
                // Make sure the new node is in the memory dump
                NodeEditorUndoActions.CompleteSOMemoryDump(hostCanvas);
            }
#endif

            return(node);
        }
 public virtual void OnRemoveConnection(ConnectionPort port1, ConnectionPort port2)
 {
 }