예제 #1
0
        /// <summary>
        /// Saves the the given NodeCanvas along with the given NodeEditorStates if specified as a new asset, optionally as working copies
        /// </summary>
        public static void SaveNodeCanvas(string path, NodeCanvas nodeCanvas, bool createWorkingCopy)
        {
                #if !UNITY_EDITOR
            throw new System.NotImplementedException();
                #endif

            if (string.IsNullOrEmpty(path))
            {
                throw new UnityException("Cannot save NodeCanvas: No spath specified to save the NodeCanvas " + (nodeCanvas != null? nodeCanvas.name : "") + " to!");
            }
            if (nodeCanvas == null)
            {
                throw new UnityException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path " + path + " is null!");
            }
            if (nodeCanvas.livesInScene)
            {
                Debug.LogWarning("Attempting to save scene canvas " + nodeCanvas.name + " to an asset, scene object references will be broken!" + (!createWorkingCopy? " No workingCopy is going to be created, so your scene save is broken, too!" : ""));
            }
                #if UNITY_EDITOR
            if (!createWorkingCopy && UnityEditor.AssetDatabase.Contains(nodeCanvas) && UnityEditor.AssetDatabase.GetAssetPath(nodeCanvas) != path)
            {
                Debug.LogError("Trying to create a duplicate save file for '" + nodeCanvas.name + "'! Forcing to create a working copy!"); createWorkingCopy = true;
            }
                #endif

            nodeCanvas.livesInScene = false;
            nodeCanvas.Validate();

                #if UNITY_EDITOR
            // Preprocess the canvas
            if (createWorkingCopy)
            {
                nodeCanvas = CreateWorkingCopy(nodeCanvas, true);
                Compress(ref nodeCanvas);
            }

            // Write canvas and editorStates
            UnityEditor.AssetDatabase.CreateAsset(nodeCanvas, path);
            AddSubAssets(nodeCanvas.editorStates, nodeCanvas);

            // Write nodes + contents
            foreach (Node node in nodeCanvas.nodes)
            {             // Write node and additional scriptable objects
                AddSubAsset(node, nodeCanvas);
                AddSubAssets(node.GetScriptableObjects(), node);
                foreach (NodeKnob knob in node.nodeKnobs)
                {                 // Write knobs and their additional scriptable objects
                    AddSubAsset(knob, node);
                    AddSubAssets(knob.GetScriptableObjects(), knob);
                }
            }

            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();
                #else
            // TODO: Node Editor: Need to implement ingame-saving (Resources, AsssetBundles, ... won't work)
                #endif

            NodeEditorCallbacks.IssueOnSaveCanvas(nodeCanvas);
        }
        /// <summary>
        /// Saves the the specified NodeCanvas as a new asset at path, optionally as a working copy and overwriting any existing save at path
        /// </summary>
        public static void SaveNodeCanvas(string path, ref NodeCanvas nodeCanvas)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: No path specified!");
            }
            if (nodeCanvas == null)
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path '" + path +
                                                       "' is null!");
            }
            if (nodeCanvas.GetType() == typeof(NodeCanvas))
            {
                throw new System.ArgumentException(
                          "Cannot save NodeCanvas: The NodeCanvas has no explicit type! Please convert it to a valid sub-type of NodeCanvas!");
            }

            nodeCanvas.Validate();

            if (!UnityEditor.AssetDatabase.Contains(nodeCanvas))
            {
                UnityEditor.AssetDatabase.CreateAsset(nodeCanvas, path);
            }

            PurifyCanvas(path);
            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();

            NodeEditorCallbacks.IssueOnSaveCanvas(nodeCanvas);
        }
예제 #3
0
        /// <summary>
        /// Saves the current node canvas as a new asset and links optional editorStates with it
        /// </summary>
        public static void SaveNodeCanvas(NodeCanvas nodeCanvas, string path, params NodeEditorState[] editorStates)
        {
            if (String.IsNullOrEmpty(path))
            {
                return;
            }

            nodeCanvas = GetWorkingCopy(nodeCanvas);
            for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++)
            {
                editorStates[stateCnt] = GetWorkingCopy(editorStates[stateCnt], nodeCanvas);
            }

        #if UNITY_EDITOR
            UnityEditor.AssetDatabase.CreateAsset(nodeCanvas, path);
            foreach (NodeEditorState editorState in editorStates)
            {
                UnityEditor.AssetDatabase.AddObjectToAsset(editorState, nodeCanvas);
                editorState.hideFlags = HideFlags.HideInHierarchy;
            }
            for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++)
            {             // Add every node and every of it's inputs/outputs into the file.
                // Results in a big mess but there's no other way (like a hierarchy)
                Node node = nodeCanvas.nodes [nodeCnt];
                UnityEditor.AssetDatabase.AddObjectToAsset(node, nodeCanvas);
                node.hideFlags = HideFlags.HideInHierarchy;
                for (int inCnt = 0; inCnt < node.Inputs.Count; inCnt++)
                {
                    UnityEditor.AssetDatabase.AddObjectToAsset(node.Inputs [inCnt], node);
                    node.Inputs [inCnt].hideFlags = HideFlags.HideInHierarchy;
                }
                for (int outCnt = 0; outCnt < node.Outputs.Count; outCnt++)
                {
                    UnityEditor.AssetDatabase.AddObjectToAsset(node.Outputs [outCnt], node);
                    node.Outputs [outCnt].hideFlags = HideFlags.HideInHierarchy;
                }
                for (int transCnt = 0; transCnt < node.transitions.Count; transCnt++)
                {
                    UnityEditor.AssetDatabase.AddObjectToAsset(node.transitions [transCnt], node);
                    node.transitions [transCnt].hideFlags = HideFlags.HideInHierarchy;
                }
            }
            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();
        #else
            // TODO: Node Editor: Need to implement ingame-saving (Resources, AsssetBundles, ... won't work)
        #endif
            NodeEditorCallbacks.IssueOnSaveCanvas(nodeCanvas);
        }
 private static void SaveCanvas(NodeEditorInputInfo info)
 {
     if (info.inputEvent.type == EventType.Layout)
     {
         return;
     }
     #if UNITY_EDITOR
     NodeEditorState state = info.editorState;
     if (!string.IsNullOrEmpty(state.canvas.savePath))
     {
         NodeEditorSaveManager.SaveNodeCanvas(state.canvas.savePath, ref state.canvas, true);
         EditorWindow.focusedWindow.ShowNotification(new GUIContent("Canvas Saved!"));
         NodeEditorCallbacks.IssueOnSaveCanvas(state.canvas);
     }
     else
     {
         EditorWindow.focusedWindow.ShowNotification(new GUIContent("No save location found. Use 'Save As' [Ctrl+Alt+S]"));
     }
     #endif
     info.inputEvent.Use();
 }
예제 #5
0
        /// <summary>
        /// Saves the the specified NodeCanvas as a new asset at path, optionally as a working copy and overwriting any existing save at path
        /// </summary>
        public static void SaveNodeCanvas(string path, ref NodeCanvas nodeCanvas, bool createWorkingCopy = false, bool safeOverwrite = true)
        {
#if !UNITY_EDITOR
            throw new System.NotImplementedException();
#else
            if (string.IsNullOrEmpty(path))
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: No path specified!");
            }
            if (nodeCanvas == null)
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path '" + path + "' is null!");
            }
            if (nodeCanvas.GetType() == typeof(NodeCanvas))
            {
                throw new System.ArgumentException("Cannot save NodeCanvas: The NodeCanvas has no explicit type! Please convert it to a valid sub-type of NodeCanvas!");
            }
            if (nodeCanvas.allowSceneSaveOnly)
            {
                throw new System.InvalidOperationException("Cannot save NodeCanvas: NodeCanvas is marked to contain scene data and cannot be saved as an asset!");
            }

            nodeCanvas.Validate();

            if (nodeCanvas.livesInScene)
            {
                Debug.LogWarning("Attempting to save scene canvas '" + nodeCanvas.name + "' to an asset, references to scene object may be broken!" + (!createWorkingCopy? " Forcing creation of working copy!" : ""));
                createWorkingCopy = true;
            }
            if (UnityEditor.AssetDatabase.Contains(nodeCanvas) && UnityEditor.AssetDatabase.GetAssetPath(nodeCanvas) != path)
            {
                Debug.LogWarning("Trying to create a duplicate save file for '" + nodeCanvas.name + "'! Forcing creation of working copy!");
                nodeCanvas = CreateWorkingCopy(nodeCanvas);
            }

            // Prepare and update source path of the canvas
            path = ResourceManager.PreparePath(path);
            nodeCanvas.UpdateSource(path);

            // Preprocess the canvas
            NodeCanvas processedCanvas = nodeCanvas;
            processedCanvas.OnBeforeSavingCanvas();
            if (createWorkingCopy)
            {
                processedCanvas = CreateWorkingCopy(processedCanvas);
            }

            // Differenciate canvasSave as the canvas asset and nodeCanvas as the source incase an existing save has been overwritten
            NodeCanvas canvasSave = processedCanvas;
            NodeCanvas prevSave;
            if (safeOverwrite && (prevSave = ResourceManager.LoadResource <NodeCanvas> (path)) != null && prevSave.GetType() == canvasSave.GetType())
            {             // OVERWRITE: Delete contents of old save
                Object[] subAssets = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(path);
                for (int i = 0; i < subAssets.Length; i++)
                {                 // Delete all subassets except the main canvas to preserve references
                    if (subAssets[i] != prevSave)
                    {
                        Object.DestroyImmediate(subAssets[i], true);
                    }
                }
                // Overwrite main canvas
                OverwriteCanvas(ref prevSave, processedCanvas);
                canvasSave = prevSave;
            }
            else
            {             // Write main canvas
                UnityEditor.AssetDatabase.DeleteAsset(path);
                UnityEditor.AssetDatabase.CreateAsset(processedCanvas, path);
            }

            // Write editorStates
            AddSubAssets(processedCanvas.editorStates, canvasSave);
            // Write nodes + contents
            foreach (Node node in processedCanvas.nodes)
            { // Write node and additional scriptable objects
                AddSubAsset(node, canvasSave);
                AddSubAssets(node.GetScriptableObjects(), node);
                // Make sure all node ports are included in the representative connectionPorts list
                ConnectionPortManager.UpdatePortLists(node);
                foreach (ConnectionPort port in node.connectionPorts)
                {
                    AddSubAsset(port, node);
                }
            }

            XProfile.Begin("-");
            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();
            XProfile.End(true);

            NodeEditorCallbacks.IssueOnSaveCanvas(canvasSave);
        #endif
        }
예제 #6
0
        /// <summary>
        /// Saves the nodeCanvas in the current scene under the specified name, optionally as a working copy and overwriting any existing save at path
        /// If the specified canvas is stored as an asset, the saved canvas will loose the reference to the asset
        /// </summary>
        public static void SaveSceneNodeCanvas(string saveName, ref NodeCanvas nodeCanvas, bool createWorkingCopy, bool safeOverwrite = true)
        {
            if (string.IsNullOrEmpty(saveName))
            {
                throw new System.ArgumentNullException("Cannot save Canvas to scene: No save name specified!");
            }
            if (nodeCanvas == null)
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved as '" + saveName + "' is null!");
            }
            if (nodeCanvas.GetType() == typeof(NodeCanvas))
            {
                throw new System.ArgumentException("Cannot save NodeCanvas: The NodeCanvas has no explicit type! Please convert it to a valid sub-type of NodeCanvas!");
            }

            if (saveName.StartsWith("SCENE/"))
            {
                saveName = saveName.Substring(6);
            }

            nodeCanvas.Validate();

            if (!nodeCanvas.livesInScene
                #if UNITY_EDITOR // Make sure the canvas has no reference to an asset
                || UnityEditor.AssetDatabase.Contains(nodeCanvas)
                #endif
                )
            {
                Debug.LogWarning("Creating scene save '" + nodeCanvas.name + "' for canvas saved as an asset! Forcing creation of working copy!");
                nodeCanvas = CreateWorkingCopy(nodeCanvas);
            }

            // Update the source of the canvas
            nodeCanvas.UpdateSource("SCENE/" + saveName);

            // Preprocess the canvas
            NodeCanvas processedCanvas = nodeCanvas;
            processedCanvas.OnBeforeSavingCanvas();
            if (createWorkingCopy)
            {
                processedCanvas = CreateWorkingCopy(processedCanvas);
            }

            // Get the saveHolder and store the canvas
            NodeCanvas          savedCanvas = processedCanvas;
            NodeCanvasSceneSave sceneSave   = FindSceneSave(saveName, true);

#if UNITY_EDITOR
            if (sceneSave.savedNodeCanvas != null && safeOverwrite && sceneSave.savedNodeCanvas.GetType() == savedCanvas.GetType())             // OVERWRITE
            {
                OverwriteCanvas(ref sceneSave.savedNodeCanvas, savedCanvas);
            }

            if (!Application.isPlaying)
            {             // Set Dirty
                UnityEditor.EditorUtility.SetDirty(sceneSave.gameObject);
#if UNITY_5_3_OR_NEWER || UNITY_5_3
                UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(sceneSave.gameObject.scene);
#else
                UnityEditor.EditorApplication.MarkSceneDirty();
                        #endif
            }
#endif
            sceneSave.savedNodeCanvas = savedCanvas;

            NodeEditorCallbacks.IssueOnSaveCanvas(savedCanvas);
        }
        /// <summary>
        /// Saves the the specified NodeCanvas as a new asset at path, optionally as a working copy and overwriting any existing save at path
        /// </summary>
        public static void SaveNodeCanvas(string path, ref NodeCanvas nodeCanvas, bool createWorkingCopy, bool safeOverwrite = true)
        {
                #if !UNITY_EDITOR
            throw new System.NotImplementedException();

            // TODO: Node Editor: Need to implement ingame-saving (Resources, AsssetBundles, ... won't work)
                #endif

            if (string.IsNullOrEmpty(path))
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: No path specified!");
            }
            if (nodeCanvas == null)
            {
                throw new System.ArgumentNullException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path '" + path + "' is null!");
            }
            if (nodeCanvas.GetType() == typeof(NodeCanvas))
            {
                throw new System.ArgumentException("Cannot save NodeCanvas: The NodeCanvas has no explicit type! Please convert it to a valid sub-type of NodeCanvas!");
            }

            if (nodeCanvas.livesInScene)
            {
                Debug.LogWarning("Attempting to save scene canvas '" + nodeCanvas.name + "' to an asset, references to scene object may be broken!" + (!createWorkingCopy? " Forcing creation of working copy!" : ""));
                createWorkingCopy = true;
            }
                #if UNITY_EDITOR
            if (UnityEditor.AssetDatabase.Contains(nodeCanvas) && UnityEditor.AssetDatabase.GetAssetPath(nodeCanvas) != path)
            {
                Debug.LogWarning("Trying to create a duplicate save file for '" + nodeCanvas.name + "'! Forcing creation of working copy!");
                ProcessCanvas(ref nodeCanvas, true);
            }
                #endif

                #if UNITY_EDITOR
            // Prepare and update source path of the canvas
            path = ResourceManager.PreparePath(path);
            nodeCanvas.UpdateSource(path);

            // Preprocess the canvas
            NodeCanvas processedCanvas = nodeCanvas;
            processedCanvas.OnBeforeSavingCanvas();
            ProcessCanvas(ref processedCanvas, createWorkingCopy);

            // Differenciate canvasSave as the canvas asset and nodeCanvas as the source incase an existing save has been overwritten
            NodeCanvas canvasSave = processedCanvas;
            NodeCanvas prevSave;
            if (safeOverwrite && (prevSave = ResourceManager.LoadResource <NodeCanvas> (path)) != null && prevSave.GetType() == canvasSave.GetType())
            {             // OVERWRITE: Delete contents of old save
                for (int nodeCnt = 0; nodeCnt < prevSave.nodes.Count; nodeCnt++)
                {
                    Node node = prevSave.nodes[nodeCnt];
                    for (int knobCnt = 0; knobCnt < node.nodeKnobs.Count; knobCnt++)
                    {
                        if (node.nodeKnobs[knobCnt] != null)
                        {
                            Object.DestroyImmediate(node.nodeKnobs[knobCnt], true);
                        }
                    }
                    Object.DestroyImmediate(node, true);
                }
                for (int i = 0; i < prevSave.editorStates.Length; i++)
                {
                    if (prevSave.editorStates[i] != null)
                    {
                        Object.DestroyImmediate(prevSave.editorStates[i], true);
                    }
                }
                // Overwrite main canvas
                OverwriteCanvas(ref prevSave, processedCanvas);
                canvasSave = prevSave;
            }
            else
            {             // Write main canvas
                UnityEditor.AssetDatabase.CreateAsset(processedCanvas, path);
            }

            // Write editorStates
            AddSubAssets(processedCanvas.editorStates, canvasSave);
            // Write nodes + contents
            foreach (Node node in processedCanvas.nodes)
            {             // Write node and additional scriptable objects
                AddSubAsset(node, canvasSave);
                AddSubAssets(node.GetScriptableObjects(), node);
                foreach (NodeKnob knob in node.nodeKnobs)
                {
                    AddSubAsset(knob, node);
                }
            }

            //UnityEditor.AssetDatabase.SaveAssets ();
            //UnityEditor.AssetDatabase.Refresh ();

            NodeEditorCallbacks.IssueOnSaveCanvas(canvasSave);
                #endif
        }
예제 #8
0
        /// <summary>
        /// Saves the the given NodeCanvas or, if specified, a working copy of it, as a new asset along with working copies, if specified, of the given NodeEditorStates
        /// </summary>
        public static void SaveNodeCanvas(string path, bool createWorkingCopy, NodeCanvas nodeCanvas, params NodeEditorState[] editorStates)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new UnityException("Cannot save NodeCanvas: No spath specified to save the NodeCanvas " + (nodeCanvas != null? nodeCanvas.name : "") + " to!");
            }
            if (nodeCanvas == null)
            {
                throw new UnityException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path " + path + " is null!");
            }

            for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++)
            {
                if (editorStates[stateCnt] == null)
                {
                    Debug.LogError("A NodeEditorState that should be saved to path " + path + " is null!");
                }
            }

            path = path.Replace(Application.dataPath, "Assets");

        #if UNITY_EDITOR
            if (createWorkingCopy)
            {             // Copy canvas and editorStates
                CreateWorkingCopy(ref nodeCanvas, editorStates, true);
            }

            // Write canvas and editorStates
            UnityEditor.AssetDatabase.CreateAsset(nodeCanvas, path);
            for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++)
            {
                if (editorStates[stateCnt] != null)
                {
                    AddSubAsset(editorStates[stateCnt], nodeCanvas);
                }
            }

            // Write nodes + contents
            for (int nodeCnt = 0; nodeCnt < nodeCanvas.nodes.Count; nodeCnt++)
            {             // Every node and each ScriptableObject in it
                Node node = nodeCanvas.nodes [nodeCnt];
                AddSubAsset(node, nodeCanvas);
                for (int knobCnt = 0; knobCnt < node.nodeKnobs.Count; knobCnt++)
                {
                    AddSubAsset(node.nodeKnobs [knobCnt], node);
                }
                for (int transCnt = 0; transCnt < node.transitions.Count; transCnt++)
                {
                    if (node.transitions[transCnt].startNode == node)
                    {
                        AddSubAsset(node.transitions [transCnt], node);
//						Debug.Log ("Did save Transition " + node.transitions [transCnt].name + " because its Node " + node.name + " is the start node!");
                    }
//					else
//						Debug.Log ("Did NOT save Transition " + node.transitions [transCnt].name + " because its Node " + node.name + " is NOT the start node (" + (node.transitions[transCnt].startNode != null? node.transitions[transCnt].startNode.name : "Null") + ")!");
                }
            }

            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();
        #else
            // TODO: Node Editor: Need to implement ingame-saving (Resources, AsssetBundles, ... won't work)
        #endif

            NodeEditorCallbacks.IssueOnSaveCanvas(nodeCanvas);
        }
예제 #9
0
        /// <summary>
        /// Saves the the given NodeCanvas or, if specified, a working copy of it, as a new asset along with working copies, if specified, of the given NodeEditorStates
        /// </summary>
        public static void SaveNodeCanvas(string path, bool createWorkingCopy, NodeCanvas nodeCanvas, params NodeEditorState[] editorStates)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new UnityException("Cannot save NodeCanvas: No spath specified to save the NodeCanvas " + (nodeCanvas != null? nodeCanvas.name : "") + " to!");
            }
            if (nodeCanvas == null)
            {
                throw new UnityException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path " + path + " is null!");
            }

            foreach (NodeEditorState state in editorStates)
            {
                if (state == null)
                {
                    Debug.LogError("A NodeEditorState that should be saved to path " + path + " is null!");
                }
            }

            path = path.Replace(Application.dataPath, "Assets");

        #if UNITY_EDITOR
            if (createWorkingCopy)
            {             // Copy canvas and editorStates
                CreateWorkingCopy(ref nodeCanvas, editorStates, true);
            }

            // Write canvas and editorStates
            UnityEditor.AssetDatabase.CreateAsset(nodeCanvas, path);
            foreach (NodeEditorState state in editorStates)
            {
                if (state != null)
                {
                    AddSubAsset(state, nodeCanvas);
                }
            }

            // Write nodes + contents
            foreach (Node node in nodeCanvas.nodes)
            {             // Every node and each ScriptableObject in it
                AddSubAsset(node, nodeCanvas);
                foreach (NodeKnob knob in node.nodeKnobs)
                {
                    AddSubAsset(knob, node);
                    // Add additional scriptableObjects
                    ScriptableObject[] additionalKnobSOs = knob.GetScriptableObjects();
                    foreach (ScriptableObject so in additionalKnobSOs)
                    {
                        AddSubAsset(so, knob);
                    }
                }
                // Add additional scriptableObjects
                ScriptableObject[] additionalNodeSOs = node.GetScriptableObjects();
                foreach (ScriptableObject so in additionalNodeSOs)
                {
                    AddSubAsset(so, node);
                }
            }

            UnityEditor.AssetDatabase.SaveAssets();
            UnityEditor.AssetDatabase.Refresh();
        #else
            // TODO: Node Editor: Need to implement ingame-saving (Resources, AsssetBundles, ... won't work)
        #endif

            NodeEditorCallbacks.IssueOnSaveCanvas(nodeCanvas);
        }
예제 #10
0
        /// <summary>
        /// Saves the the given NodeCanvas along with the given NodeEditorStates if specified as a new asset, optionally as working copies
        /// </summary>
        public static void SaveNodeCanvas(string path, NodeCanvas nodeCanvas, bool createWorkingCopy, bool safeOverwrite = true)
        {
                #if !UNITY_EDITOR
            throw new System.NotImplementedException();
                #endif

            if (string.IsNullOrEmpty(path) || !path.StartsWith("Assets"))
            {
                throw new UnityException("Cannot save NodeCanvas: Invalid path specified: '" + path + "'!");
            }
            if (nodeCanvas == null)
            {
                throw new UnityException("Cannot save NodeCanvas: The specified NodeCanvas that should be saved to path " + path + " is null!");
            }
            if (nodeCanvas.GetType() == typeof(NodeCanvas))
            {
                throw new UnityException("Cannot save NodeCanvas: The NodeCanvas has no explicit type: '" + nodeCanvas.GetType().ToString() + "'. Please convert it to a valid type!");
            }
            if (nodeCanvas.livesInScene)
            {
                Debug.LogWarning("Attempting to save scene canvas " + nodeCanvas.name + " to an asset, scene object references may be broken!" + (!createWorkingCopy? " No workingCopy is going to be created, so your scene save is broken, too!" : ""));
            }
                #if UNITY_EDITOR
            if (!createWorkingCopy && UnityEditor.AssetDatabase.Contains(nodeCanvas) && UnityEditor.AssetDatabase.GetAssetPath(nodeCanvas) != path)
            {
                Debug.LogError("Trying to create a duplicate save file for '" + nodeCanvas.name + "'! Forcing to create a working copy!"); createWorkingCopy = true;
            }
                #endif

            path = ResourceManager.PreparePath(path);

            nodeCanvas.OnBeforeSavingCanvas();

            NodeCanvas canvasSave = nodeCanvas;

                #if UNITY_EDITOR
            nodeCanvas.UpdateSource(path);

            // Preprocess the canvas
            ProcessCanvas(ref nodeCanvas, createWorkingCopy);
            nodeCanvas.livesInScene = false;

            canvasSave = nodeCanvas;
            NodeCanvas prevSave;
            if (safeOverwrite && (prevSave = ResourceManager.LoadResource <NodeCanvas> (path)) != null && prevSave.GetType() == canvasSave.GetType()) // OVERWRITE
            {                                                                                                                                         // Delete contents of old save
                for (int nodeCnt = 0; nodeCnt < prevSave.nodes.Count; nodeCnt++)
                {
                    Node node = prevSave.nodes[nodeCnt];
                    for (int knobCnt = 0; knobCnt < node.nodeKnobs.Count; knobCnt++)
                    {
                        if (node.nodeKnobs[knobCnt] != null)
                        {
                            Object.DestroyImmediate(node.nodeKnobs[knobCnt], true);
                        }
                    }
                    Object.DestroyImmediate(node, true);
                }
                for (int i = 0; i < prevSave.editorStates.Length; i++)
                {
                    if (prevSave.editorStates[i] != null)
                    {
                        Object.DestroyImmediate(prevSave.editorStates[i], true);
                    }
                }
                // Overwrite main canvas
                OverwriteCanvas(ref prevSave, nodeCanvas);
                canvasSave = prevSave;
            }
            else
            {             // Write main canvas
                UnityEditor.AssetDatabase.CreateAsset(nodeCanvas, path);
            }

            // Write editorStates
            AddSubAssets(nodeCanvas.editorStates, canvasSave);

            // Write nodes + contents
            foreach (Node node in nodeCanvas.nodes)
            {             // Write node and additional scriptable objects
                AddSubAsset(node, canvasSave);
                AddSubAssets(node.GetScriptableObjects(), node);
                foreach (NodeKnob knob in node.nodeKnobs)
                {                 // Write knobs and their additional scriptable objects
                    AddSubAsset(knob, node);
                    AddSubAssets(knob.GetScriptableObjects(), knob);
                }
            }

            //UnityEditor.AssetDatabase.SaveAssets ();
            //UnityEditor.AssetDatabase.Refresh ();
                #else
            // TODO: Node Editor: Need to implement ingame-saving (Resources, AsssetBundles, ... won't work)
                #endif

            NodeEditorCallbacks.IssueOnSaveCanvas(canvasSave);
        }