/// <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); }
/// <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) { nodeCanvas.Validate(true); // 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]; node.CheckNodeKnobMigration(); // Clone Node and additional scriptableObjects Node clonedNode = AddClonedSO(allSOs, clonedSOs, node); AddClonedSOs(allSOs, clonedSOs, clonedNode.GetScriptableObjects()); // Clone NodeKnobs foreach (NodeKnob knob in clonedNode.nodeKnobs) { AddClonedSO(allSOs, clonedSOs, knob); } } // 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 NodeKnobs and restore Inputs/Outputs by NodeKnob type clonedNode.Inputs = new List <NodeInput> (); clonedNode.Outputs = new List <NodeOutput> (); for (int knobCnt = 0; knobCnt < clonedNode.nodeKnobs.Count; knobCnt++) { // Clone generic NodeKnobs NodeKnob knob = clonedNode.nodeKnobs[knobCnt] = ReplaceSO(allSOs, clonedSOs, clonedNode.nodeKnobs[knobCnt]); knob.body = clonedNode; knob.CopyScriptableObjects(copySOs); // Add inputs/outputs to their lists again if (knob is NodeInput) { clonedNode.Inputs.Add(knob as NodeInput); } else if (knob is NodeOutput) { clonedNode.Outputs.Add(knob as NodeOutput); } } } 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); }