示例#1
0
        /// <summary>
        /// Validates this canvas, checking for any broken nodes or references and cleans them.
        /// </summary>
        public void Validate()
        {
            NodeEditor.checkInit(false);

            // Check Groups
            CheckNodeCanvasList(ref groups, "groups");

            // Check Nodes and their connection ports
            CheckNodeCanvasList(ref nodes, "nodes");
            foreach (Node node in nodes)
            {
                ConnectionPortManager.UpdateConnectionPorts(node);
                foreach (ConnectionPort port in node.connectionPorts)
                {
                    port.Validate(node);
                }
                ConnectionPortManager.UpdatePortLists(node);
                ConnectionPortManager.UpdateRepresentativePortLists(node);
            }

            // Check EditorStates
            if (editorStates == null)
            {
                editorStates = new NodeEditorState[0];
            }
            editorStates = editorStates.Where((NodeEditorState state) => state != null).ToArray();
            foreach (NodeEditorState state in editorStates)
            {
                if (!nodes.Contains(state.selectedNode))
                {
                    state.selectedNode = null;
                }
            }

            // Validate CanvasType-specific stuff
            ValidateSelf();
        }
示例#2
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);
        }
示例#3
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
        }