private void SaveNewNode(Node node) { if (!useCache) { return; } CheckCurrentCache(); if (nodeCanvas.livesInScene) { return; } if (!nodeCanvas.nodes.Contains(node)) { return; } NodeEditorSaveManager.AddSubAsset(node, lastSessionPath); foreach (ScriptableObject so in node.GetScriptableObjects()) { NodeEditorSaveManager.AddSubAsset(so, node); } foreach (NodeKnob knob in node.nodeKnobs) { NodeEditorSaveManager.AddSubAsset(knob, node); foreach (ScriptableObject so in knob.GetScriptableObjects()) { NodeEditorSaveManager.AddSubAsset(so, knob); } } UpdateCacheFile(); }
/// <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(); nodeCanvas = Clone(nodeCanvas); // Take each SO, make a clone of it and store both versions in the respective list // This will only iterate over the 'source instances' List <ScriptableObject> allSOs = new List <ScriptableObject> (); List <ScriptableObject> clonedSOs = new List <ScriptableObject> (); 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()); foreach (NodeKnob knob in clonedNode.nodeKnobs) { // Clone NodeKnobs and additional scriptableObjects AddClonedSO(allSOs, clonedSOs, knob); AddClonedSOs(allSOs, clonedSOs, knob.GetScriptableObjects()); } } // Replace every reference to any of the initial SOs of the first list with the respective clones of the second list for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { // Clone Nodes, structural content and additional scriptableObjects Node node = nodeCanvas.nodes[nodeCnt]; // Replace node and additional ScriptableObjects Node clonedNode = nodeCanvas.nodes[nodeCnt] = ReplaceSO(allSOs, clonedSOs, node); clonedNode.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); // We're going to restore these from NodeKnobs if desired (!compressed) //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; // Replace additional scriptableObjects in the NodeKnob knob.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } for (int knobCnt = 0; knobCnt < clonedNode.Inputs.Count; knobCnt++) { // Clone generic NodeKnobs NodeInput knob = clonedNode.Inputs[knobCnt] = ReplaceSO(allSOs, clonedSOs, clonedNode.Inputs[knobCnt]); knob.body = clonedNode; } for (int knobCnt = 0; knobCnt < clonedNode.Outputs.Count; knobCnt++) { // Clone generic NodeKnobs NodeOutput knob = clonedNode.Outputs[knobCnt] = ReplaceSO(allSOs, clonedSOs, clonedNode.Outputs[knobCnt]); knob.body = clonedNode; } } if (editorStates) { nodeCanvas.editorStates = CreateWorkingCopy(nodeCanvas.editorStates, nodeCanvas); foreach (NodeEditorState state in nodeCanvas.editorStates) { state.selectedNode = ReplaceSO(allSOs, clonedSOs, state.selectedNode); } } else { foreach (NodeEditorState state in nodeCanvas.editorStates) { state.selectedNode = null; } } 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 = 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); }
public static NodeCanvas CreateWorkingCopy(NodeCanvas nodeCanvas, bool editorStates) { nodeCanvas.Validate(); nodeCanvas = Clone(nodeCanvas); List <ScriptableObject> allSOs = new List <ScriptableObject>(); List <ScriptableObject> clonedSOs = new List <ScriptableObject>(); for (int i = 0; i < nodeCanvas.nodes.Count; i++) { Node node = nodeCanvas.nodes[i]; node.CheckNodeKnobMigration(); Node node2 = AddClonedSO(allSOs, clonedSOs, node); AddClonedSOs(allSOs, clonedSOs, node2.GetScriptableObjects()); foreach (NodeKnob nodeKnob3 in node2.nodeKnobs) { AddClonedSO(allSOs, clonedSOs, nodeKnob3); AddClonedSOs(allSOs, clonedSOs, nodeKnob3.GetScriptableObjects()); } } for (int j = 0; j < nodeCanvas.nodes.Count; j++) { Node initialSO = nodeCanvas.nodes[j]; Node node3 = ReplaceSO(allSOs, clonedSOs, initialSO); nodeCanvas.nodes[j] = node3; Node node4 = node3; node4.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); for (int k = 0; k < node4.nodeKnobs.Count; k++) { NodeKnob nodeKnob = ReplaceSO(allSOs, clonedSOs, node4.nodeKnobs[k]); node4.nodeKnobs[k] = nodeKnob; NodeKnob nodeKnob2 = nodeKnob; nodeKnob2.body = node4; nodeKnob2.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } for (int l = 0; l < node4.Inputs.Count; l++) { NodeInput nodeInput = ReplaceSO(allSOs, clonedSOs, node4.Inputs[l]); node4.Inputs[l] = nodeInput; NodeInput nodeInput2 = nodeInput; nodeInput2.body = node4; } for (int m = 0; m < node4.Outputs.Count; m++) { NodeOutput nodeOutput = ReplaceSO(allSOs, clonedSOs, node4.Outputs[m]); node4.Outputs[m] = nodeOutput; NodeOutput nodeOutput2 = nodeOutput; nodeOutput2.body = node4; } } if (editorStates) { nodeCanvas.editorStates = CreateWorkingCopy(nodeCanvas.editorStates, nodeCanvas); NodeEditorState[] editorStates2 = nodeCanvas.editorStates; foreach (NodeEditorState nodeEditorState in editorStates2) { nodeEditorState.selectedNode = ReplaceSO(allSOs, clonedSOs, nodeEditorState.selectedNode); } } else { NodeEditorState[] editorStates3 = nodeCanvas.editorStates; foreach (NodeEditorState nodeEditorState2 in editorStates3) { nodeEditorState2.selectedNode = null; } } 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); }
/// <summary> /// CreateWorkingCopy a working copy of the canvas and each editorState. This will break the link to the canvas asset and thus all changes made to the working copy have to be explicitly saved. /// Check compressed if the copy is not intended for useage but for storage, this will leave the Inputs and Outputs list of Node empty /// </summary> public static void CreateWorkingCopy(ref NodeCanvas nodeCanvas, NodeEditorState[] editorStates, bool compressed) { nodeCanvas = Clone(nodeCanvas); // Take each SO, make a clone of it and store both versions in the respective list // This will only iterate over the 'source instances' List <ScriptableObject> allSOs = new List <ScriptableObject> (); List <ScriptableObject> clonedSOs = new List <ScriptableObject> (); for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { Node node = nodeCanvas.nodes[nodeCnt]; node.CheckNodeKnobMigration(); Node clonedNode = (Node)AddClonedSO(allSOs, clonedSOs, node); for (int knobCnt = 0; knobCnt < clonedNode.nodeKnobs.Count; knobCnt++) { // Clone NodeKnobs // Debug.Log ("Cloned " + knobCnt + " " + (clonedNode.nodeKnobs[knobCnt] == null? "null" : clonedNode.nodeKnobs[knobCnt].name) + " on node " + node.name); AddClonedSO(allSOs, clonedSOs, clonedNode.nodeKnobs[knobCnt]); // Clone additional scriptableObjects ScriptableObject[] additionalKnobSOs = clonedNode.nodeKnobs[knobCnt].GetScriptableObjects(); foreach (ScriptableObject so in additionalKnobSOs) { AddClonedSO(allSOs, clonedSOs, so); } } for (int transCnt = 0; transCnt < clonedNode.transitions.Count; transCnt++) { // Clone Transitions Transition trans = clonedNode.transitions[transCnt]; if (trans.startNode == node) { AddClonedSO(allSOs, clonedSOs, trans); // Debug.Log ("Did copy Transition " + trans.name + " because its Node " + clonedNode.name + " is the start node!"); } else { // Debug.Log ("Did NOT copy Transition " + trans.name + " because its Node " + clonedNode.name + " is NOT the start node (" + trans.startNode.name + ")!"); clonedNode.transitions.RemoveAt(transCnt); transCnt--; } } // Clone additional scriptableObjects ScriptableObject[] additionalNodeSOs = clonedNode.GetScriptableObjects(); foreach (ScriptableObject so in additionalNodeSOs) { AddClonedSO(allSOs, clonedSOs, so); } } // Replace every reference to any of the initial SOs of the first list with the respective clones of the second list nodeCanvas.currentNode = ReplaceSO(allSOs, clonedSOs, nodeCanvas.currentNode); nodeCanvas.currentTransition = ReplaceSO(allSOs, clonedSOs, nodeCanvas.currentTransition); for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { // Clone Nodes, structural content and additional scriptableObjects Node node = nodeCanvas.nodes[nodeCnt]; Node clonedNode = nodeCanvas.nodes[nodeCnt] = ReplaceSO(allSOs, clonedSOs, node); // We're going to restore these from NodeKnobs if desired (!compressed) 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; // Replace additional scriptableObjects in the NodeKnob knob.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); if (!compressed) { // Add NodeInputs and NodeOutputs to the apropriate lists in Node if desired (!compressed) if (knob is NodeInput) { clonedNode.Inputs.Add(knob as NodeInput); } else if (knob is NodeOutput) { clonedNode.Outputs.Add(knob as NodeOutput); } } } for (int transCnt = 0; transCnt < clonedNode.transitions.Count; transCnt++) { // Clone transitions Transition trans = clonedNode.transitions[transCnt]; if (trans.startNode != node) { continue; } trans = clonedNode.transitions[transCnt] = ReplaceSO(allSOs, clonedSOs, trans); if (trans == null) { Debug.LogError("Could not copy transition number " + transCnt + " of Node " + clonedNode.name + "!"); continue; } // Debug.Log ("Did replace contents of Transition " + trans.name + " because its Node " + clonedNode.name + " is the start node!"); trans.startNode = ReplaceSO(allSOs, clonedSOs, trans.startNode); trans.endNode = ReplaceSO(allSOs, clonedSOs, trans.endNode); if (!compressed) { trans.endNode.transitions.Add(trans); } } // Replace additional scriptableObjects in the Node node.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } // Also create working copies for specified editorStates, if any // Needs to be in the same function as the EditorState references nodes from the NodeCanvas if (editorStates != null) { for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++) { if (editorStates[stateCnt] == null) { continue; } NodeEditorState state = editorStates[stateCnt] = Clone(editorStates[stateCnt]); state.canvas = nodeCanvas; state.focusedNode = null; state.selectedNode = state.selectedNode != null?ReplaceSO(allSOs, clonedSOs, state.selectedNode) : null; state.makeTransition = null; state.connectOutput = null; } } }
/// <summary> /// CreateWorkingCopy a working copy of the canvas and each editorState. This will break the link to the canvas asset and thus all changes made to the working copy have to be explicitly saved. /// Check compressed if the copy is not intended for useage but for storage, this will leave the Inputs and Outputs list of Node empty /// </summary> public static void CreateWorkingCopy(ref NodeCanvas nodeCanvas, NodeEditorState[] editorStates, bool compressed) { nodeCanvas = Clone(nodeCanvas); // Take each SO, make a clone of it and store both versions in the respective list // This will only iterate over the 'source instances' List <ScriptableObject> allSOs = new List <ScriptableObject> (); List <ScriptableObject> clonedSOs = new List <ScriptableObject> (); foreach (Node node in nodeCanvas.nodes) { node.CheckNodeKnobMigration(); Node clonedNode = AddClonedSO(allSOs, clonedSOs, node); foreach (NodeKnob knob in clonedNode.nodeKnobs) { // Clone NodeKnobs NodeKnob clonedKnob = AddClonedSO(allSOs, clonedSOs, knob); // Clone additional scriptableObjects ScriptableObject[] additionalKnobSOs = clonedKnob.GetScriptableObjects(); foreach (ScriptableObject so in additionalKnobSOs) { AddClonedSO(allSOs, clonedSOs, so); } } // Clone additional scriptableObjects ScriptableObject[] additionalNodeSOs = clonedNode.GetScriptableObjects(); foreach (ScriptableObject so in additionalNodeSOs) { AddClonedSO(allSOs, clonedSOs, so); } } // Replace every reference to any of the initial SOs of the first list with the respective clones of the second list for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++) { // Clone Nodes, structural content and additional scriptableObjects Node clonedNode = nodeCanvas.nodes[nodeCnt] = ReplaceSO(allSOs, clonedSOs, nodeCanvas.nodes[nodeCnt]); // We're going to restore these from NodeKnobs if desired (!compressed) clonedNode.Inputs = new List <NodeInput> (); clonedNode.Outputs = new List <NodeOutput> (); for (int knobCnt = 0; knobCnt < clonedNode.nodeKnobs.Count; knobCnt++) { // Clone generic NodeKnobs NodeKnob clonedKnob = clonedNode.nodeKnobs[knobCnt] = ReplaceSO(allSOs, clonedSOs, clonedNode.nodeKnobs[knobCnt]); clonedKnob.body = clonedNode; if (!compressed) { // Add NodeInputs and NodeOutputs to the apropriate lists in Node if desired (!compressed) if (clonedKnob is NodeInput) { clonedNode.Inputs.Add(clonedKnob as NodeInput); } else if (clonedKnob is NodeOutput) { clonedNode.Outputs.Add(clonedKnob as NodeOutput); } } // Replace additional scriptableObjects in the NodeKnob clonedKnob.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } // Replace additional scriptableObjects in the Node clonedNode.CopyScriptableObjects((ScriptableObject so) => ReplaceSO(allSOs, clonedSOs, so)); } // Also create working copies for specified editorStates, if any // Needs to be in the same function as the EditorState references nodes from the NodeCanvas if (editorStates != null) { for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++) { if (editorStates[stateCnt] == null) { continue; } NodeEditorState clonedState = editorStates[stateCnt] = Clone(editorStates[stateCnt]); clonedState.canvas = nodeCanvas; clonedState.focusedNode = null; clonedState.selectedNode = clonedState.selectedNode != null?ReplaceSO(allSOs, clonedSOs, clonedState.selectedNode) : null; clonedState.makeTransition = null; clonedState.connectOutput = null; } } }