예제 #1
0
        ///Check if the canvas is close.
        public static int TryDialogTree(NodeEditorFramework.NodeCanvas canvas)
        {
            Node processing = (canvas as DialogNodeEditor.ConversationCanvas).convStartNode;

            //

            TryRecursive(processing, true);

            Debug.Log("Converter:: TryDialogTree:: Try Result: " + tryNodeCount + " nodes," + tryOutputCount + "Outputs");

            return(tryNodeCount);
        }
예제 #2
0
        public static Conversation ConvertToNewConv(NodeEditorFramework.NodeCanvas canvas)
        {
            Conversation conv = Conversation.Create(canvas as DialogNodeEditor.ConversationCanvas);

            Node processing = (canvas as DialogNodeEditor.ConversationCanvas).convStartNode;
            ConversationStartNode currentRef = conv.startNode;

            //
            Recursive(processing, currentRef, conv);

            return(conv);
        }
		public static void IssueOnSaveCanvas (NodeCanvas canvas) 
		{
			if (OnSaveCanvas != null)
				OnSaveCanvas.Invoke (canvas);
			for (int cnt = 0; cnt < receiverCount; cnt++) 
			{
				if (callbackReceiver [cnt] == null)
					callbackReceiver.RemoveAt (cnt--);
				else
					callbackReceiver [cnt].OnSaveCanvas (canvas) ;
			}
		}
예제 #4
0
        public static void Save(string path, NodeEditorFramework.NodeCanvas canvas)
        {
            Conversation tree = ConvertToNewConv(canvas);

            AssetDatabase.CreateAsset(tree, path);
            foreach (BaseDialogNode n in tree.nodes)
            {
                AddSubAsset(n, tree);
            }
            Debug.Log("Converter:: Save:: Created a new dialog tree.");

            AssetDatabase.SaveAssets();
        }
예제 #5
0
        /// <summary>
        /// Begins to transition the passed nodeCanvas from beginNode
        /// </summary>
        public static void BeginTransitioning(NodeCanvas nodeCanvas, Node beginNode)
        {
            if (!nodeCanvas.nodes.Contains (beginNode))
                throw new UnityException ("Node to begin transitioning from has to be associated with the passed NodeEditorState!");

            nodeCanvas.currentNode = beginNode;
            nodeCanvas.currentTransition = null;
            if (!transitioningNodeCanvases.Contains (nodeCanvas))
                transitioningNodeCanvases.Add (nodeCanvas);

            RepaintClients ();

            //			Debug.Log ("Beginning transitioning " + nodeCanvas.name + " from Node " + beginNode.name);
            nodeCanvas.currentNode.OnEnter (null);

            #if UNITY_EDITOR
            NEUpdate -= UpdateTransitions;
            NEUpdate += UpdateTransitions;
            #endif
        }
        /// <summary>
        /// Returns the editorState with the specified name in canvas. If not found it will create a new one with that name.
        /// </summary>
        public static NodeEditorState ExtractEditorState(NodeCanvas canvas, string stateName)
        {
            NodeEditorState state = null;

            if (canvas.editorStates.Length > 0)
            {             // Search for the editorState
                state = canvas.editorStates.First((NodeEditorState s) => s != null && s.name == stateName);
            }
            if (state == null)
            {             // Create editorState
                state        = ScriptableObject.CreateInstance <NodeEditorState> ();
                state.canvas = canvas;
                // Insert into list
                int index = canvas.editorStates.Length;
                System.Array.Resize(ref canvas.editorStates, index + 1);
                canvas.editorStates[index] = state;
                        #if UNITY_EDITOR
                UnityEditor.EditorUtility.SetDirty(canvas);
                        #endif
            }
            state.name = stateName;
            return(state);
        }
예제 #7
0
 /// <summary>
 /// Returns the node at the position in specified canvas space.
 /// </summary>
 public static Node NodeAtPosition(NodeEditorState editorState, NodeCanvas nodeCanvas, Vector2 pos)
 {
     if (!editorState.canvasRect.Contains(pos))
     {
         return(null);
     }
     for (int nodeCnt = nodeCanvas.nodes.Count - 1; nodeCnt >= 0; nodeCnt--)
     {                                                       // Check from top to bottom because of the render order
         Node node = nodeCanvas.nodes [nodeCnt];
         if (CanvasGUIToScreenRect(node.rect).Contains(pos)) // Node Body
         {
             return(node);
         }
         foreach (NodeKnob knob in node.nodeKnobs)
         {                 // Any edge control
             if (knob.GetScreenKnob().Contains(pos))
             {
                 return(node);
             }
         }
     }
     return(null);
 }
예제 #8
0
 public static void SaveSceneNodeCanvas(string saveName, ref NodeCanvas nodeCanvas, bool createWorkingCopy)
 {
     if (string.IsNullOrEmpty(saveName))
     {
         Debug.LogError("Cannot save Canvas to scene: No save name specified!");
     }
     else
     {
         nodeCanvas.livesInScene = true;
         nodeCanvas.name         = saveName;
         NodeCanvasSceneSave nodeCanvasSceneSave = FindSceneSave(saveName);
         if ((UnityEngine.Object)nodeCanvasSceneSave == (UnityEngine.Object)null)
         {
             nodeCanvasSceneSave = sceneSaveHolder.AddComponent <NodeCanvasSceneSave>();
         }
         nodeCanvasSceneSave.savedNodeCanvas = nodeCanvas;
         if (createWorkingCopy)
         {
             nodeCanvasSceneSave.savedNodeCanvas = CreateWorkingCopy(nodeCanvasSceneSave.savedNodeCanvas, true);
             Compress(ref nodeCanvasSceneSave.savedNodeCanvas);
         }
     }
 }
예제 #9
0
        public static NodeCanvas LoadSceneNodeCanvas(string saveName, bool createWorkingCopy)
        {
            if (string.IsNullOrEmpty(saveName))
            {
                Debug.LogError("Cannot load Canvas from scene: No save name specified!");
                return(null);
            }
            NodeCanvasSceneSave nodeCanvasSceneSave = FindSceneSave(saveName);

            if ((UnityEngine.Object)nodeCanvasSceneSave == (UnityEngine.Object)null)
            {
                return(null);
            }
            NodeCanvas nodeCanvas = nodeCanvasSceneSave.savedNodeCanvas;

            nodeCanvas.livesInScene = true;
            if (createWorkingCopy)
            {
                nodeCanvas = CreateWorkingCopy(nodeCanvas, true);
            }
            Uncompress(ref nodeCanvas);
            return(nodeCanvas);
        }
예제 #10
0
        /// <summary>
        /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path
        /// </summary>
        public void LoadNodeCanvas(string path)
        {
            // Else it will be stuck forever
            NodeEditor.StopTransitioning(mainNodeCanvas);

            // Load the NodeCanvas
            mainNodeCanvas = NodeEditorSaveManager.LoadNodeCanvas(path, true);
            if (mainNodeCanvas == null)
            {
                Debug.Log("Error loading NodeCanvas from '" + path + "'!");
                NewNodeCanvas();
                return;
            }

            // Load the associated MainEditorState
            List <NodeEditorState> editorStates = NodeEditorSaveManager.LoadEditorStates(path, true);

            if (editorStates.Count == 0)
            {
                mainEditorState = ScriptableObject.CreateInstance <NodeEditorState> ();
                Debug.LogError("The save file '" + path + "' did not contain an associated NodeEditorState!");
            }
            else
            {
                mainEditorState = editorStates.Find(x => x.name == "MainEditorState");
                if (mainEditorState == null)
                {
                    mainEditorState = editorStates[0];
                }
            }
            mainEditorState.canvas = mainNodeCanvas;

            openedCanvasPath = path;
            NodeEditor.RecalculateAll(mainNodeCanvas);
            SaveCache();
            Repaint();
        }
예제 #11
0
        /// <summary>
        /// Loads the NodeCanvas from the asset file at path and optionally creates a working copy of it before returning
        /// </summary>
        public static NodeCanvas LoadNodeCanvas(string path, bool createWorkingCopy = false)
        {
        #if !UNITY_EDITOR
            throw new System.NotImplementedException();
        #else
            if (string.IsNullOrEmpty(path))
            {
                throw new System.ArgumentNullException("Cannot load Canvas: No path specified!");
            }
            path = ResourceManager.PreparePath(path);

            // Load only the NodeCanvas from the save file
            NodeCanvas nodeCanvas = ResourceManager.LoadResource <NodeCanvas> (path);
            if (nodeCanvas == null)
            {
                throw new UnityException("Cannot load NodeCanvas: The file at the specified path '" + path + "' is no valid save file as it does not contain a NodeCanvas!");
            }

            if (!Application.isPlaying && (nodeCanvas.editorStates == null || nodeCanvas.editorStates.Length == 0))
            {             // Try to load any contained editorStates, as the canvas did not reference any
                nodeCanvas.editorStates = ResourceManager.LoadResources <NodeEditorState> (path);
            }

            // Set the path as the new source of the canvas
            nodeCanvas.UpdateSource(path);

            // Postprocess the loaded canvas
            nodeCanvas.Validate();
            if (createWorkingCopy)
            {
                nodeCanvas = CreateWorkingCopy(nodeCanvas);
            }

            NodeEditorCallbacks.IssueOnLoadCanvas(nodeCanvas);
            return(nodeCanvas);
        #endif
        }
예제 #12
0
        /// <summary>
        /// Stops the transitioning process of the passed nodeCanvas
        /// </summary>
        public static void StopTransitioning(NodeCanvas nodeCanvas)
        {
            if (nodeCanvas == null)
            {
                return;
            }
            if (transitioningNodeCanvases.Contains(nodeCanvas))
            {
                transitioningNodeCanvases.Remove(nodeCanvas);
            }
                #if UNITY_EDITOR
            if (transitioningNodeCanvases.Count == 0)
            {
                NEUpdate -= UpdateTransitions;
            }
                #endif
//			Debug.Log ("Stopped transitioning " + nodeCanvas.name + (nodeCanvas.currentNode != null? (" at Node " + nodeCanvas.currentNode.name) : ""));
            if (nodeCanvas.currentTransition != null)
            {
                nodeCanvas.currentTransition.stopTransition();
                nodeCanvas.currentTransition = null;
            }
            RepaintClients();
        }
예제 #13
0
        /// <summary>
        /// Begins to transition the passed nodeCanvas from beginNode
        /// </summary>
        public static void BeginTransitioning(NodeCanvas nodeCanvas, Node beginNode)
        {
            if (!nodeCanvas.nodes.Contains(beginNode))
            {
                throw new UnityException("Node to begin transitioning from has to be associated with the passed NodeEditorState!");
            }

            nodeCanvas.currentNode       = beginNode;
            nodeCanvas.currentTransition = null;
            if (!transitioningNodeCanvases.Contains(nodeCanvas))
            {
                transitioningNodeCanvases.Add(nodeCanvas);
            }

            RepaintClients();

//			Debug.Log ("Beginning transitioning " + nodeCanvas.name + " from Node " + beginNode.name);
            nodeCanvas.currentNode.OnEnter(null);

                #if UNITY_EDITOR
            NEUpdate -= UpdateTransitions;
            NEUpdate += UpdateTransitions;
                #endif
        }
예제 #14
0
        /// <summary>
        /// Saves the nodeCanvas in the current scene under the specified name along with the specified editorStates or, if specified, their working copies
        /// If also stored as an asset, it will loose the reference to the asset first
        /// </summary>
        public static void SaveSceneNodeCanvas(string saveName, ref NodeCanvas nodeCanvas, bool createWorkingCopy)
        {
            if (string.IsNullOrEmpty(saveName))
            {
                Debug.LogError("Cannot save Canvas to scene: No save name specified!");
                return;
            }
                #if UNITY_EDITOR // Make sure the canvas has no reference to an asset
            if (!createWorkingCopy && UnityEditor.AssetDatabase.Contains(nodeCanvas))
            {
                Debug.LogWarning("Forced to create working copy of '" + saveName + "' when saving to scene because it already exists as an asset!");
                nodeCanvas = CreateWorkingCopy(nodeCanvas, true);
            }
                #endif
            nodeCanvas.livesInScene = true;
            nodeCanvas.name         = saveName;

            // Get the saveHolder and the find the existing stored save or create a new one
            NodeCanvasSceneSave sceneSave = FindSceneSave(saveName);
            if (sceneSave == null)
            {
                sceneSave = sceneSaveHolder.AddComponent <NodeCanvasSceneSave> ();
            }

            // Store the canvas and editor states or optionally their working copies
            sceneSave.savedNodeCanvas = nodeCanvas;
            if (createWorkingCopy)
            {
                sceneSave.savedNodeCanvas = CreateWorkingCopy(sceneSave.savedNodeCanvas, true);
                Compress(ref sceneSave.savedNodeCanvas);
            }

                #if UNITY_EDITOR
            UnityEditor.EditorUtility.SetDirty(sceneSaveHolder);
                #endif
        }
예제 #15
0
        /// <summary>
        /// Extracts the state with the specified name out of the canvas, takes a random different one and renames it or creates a new one with that name if not found
        /// </summary>
        public static NodeEditorState ExtractEditorState(NodeCanvas canvas, string stateName)
        {
            NodeEditorState state = null;

            if (canvas.editorStates.Length > 0)
            {
                state = canvas.editorStates.First((NodeEditorState s) => s.name == stateName);
                if (state == null)
                {
                    state = canvas.editorStates[0];
                }
            }
            if (state == null)
            {
                state               = ScriptableObject.CreateInstance <NodeEditorState> ();
                state.canvas        = canvas;
                canvas.editorStates = new NodeEditorState[] { state };
                        #if UNITY_EDITOR
                UnityEditor.EditorUtility.SetDirty(canvas);
                        #endif
            }
            state.name = stateName;
            return(state);
        }
예제 #16
0
        /// <summary>
        /// Loads the canvas from the cache save file
        /// Called whenever a reload was made
        /// </summary>
        public void LoadCache()
        {
#if CACHE
            if (!useCache)
            {             // Simply create a ne canvas
                NewNodeCanvas();
                return;
            }

            bool skipLoad = false;
            if (cacheMemorySODump)
            {             // Check if a memory dump has been found, if so, load that
                nodeCanvas = ResourceManager.LoadResource <NodeCanvas>(SOMemoryDumpPath);
                if (nodeCanvas != null)
                {
                    skipLoad = true;
                }
            }

            // Try to load the NodeCanvas
            if (!skipLoad &&
                (!File.Exists(lastSessionPath) || (nodeCanvas = NodeEditorSaveManager.LoadNodeCanvas(lastSessionPath, cacheWorkingCopy)) == null) &&                    // Check for asset cache
                (nodeCanvas = NodeEditorSaveManager.LoadSceneNodeCanvas("lastSession", cacheWorkingCopy)) == null)                                                      // Check for scene cache
            {
                NewNodeCanvas();
                return;
            }

            // Fetch the associated MainEditorState
            editorState = NodeEditorSaveManager.ExtractEditorState(nodeCanvas, MainEditorStateIdentifier);
            UpdateCanvasInfo();
            nodeCanvas.Validate();
            nodeCanvas.TraverseAll();
            NodeEditor.RepaintClients();
#endif
        }
예제 #17
0
        /// <summary>
        /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path
        /// 加载一个Canvas
        /// </summary>
        public void LoadNodeCanvas(string path)
        {
            //如果路径一致,说明是同一个canvas
            if (NodeEditor.curEditorState != null && NodeEditor.curEditorState.canvas != null && (NodeEditor.curEditorState.canvas.savePath == path ||
                                                                                                  path.Contains(NodeEditor.curEditorState.canvas.savePath)) && (
                    NodeEditorSaveManager.GetLastCanvasPath() == path || path.Contains(NodeEditorSaveManager.GetLastCanvasPath())))
            {
                this.nodeCanvas = NodeEditor.curEditorState.canvas;
                return;
            }

            //如果不存在路径,则新建一个DefaultCanvas
            if (!File.Exists(path) || (nodeCanvas = NodeEditorSaveManager.LoadNodeCanvas(path)) == null)
            {
                NewNodeCanvas();
                return;
            }

            editorState = NodeEditorSaveManager.ExtractEditorState(nodeCanvas, MainEditorStateIdentifier);
            nodeCanvas.Validate();
            UpdateCanvasInfo();
            NodeEditor.RepaintClients();
            Debug.Log($"加载{path}成功");
        }
예제 #18
0
        public static NodeCanvas LoadNodeCanvas(string path, bool createWorkingCopy)
        {
            if (!File.Exists(path))
            {
                throw new UnityException("Cannot Load NodeCanvas: File '" + path + "' deos not exist!");
            }
            NodeCanvas nodeCanvas = ResourceManager.LoadResource <NodeCanvas>(path);

            if ((UnityEngine.Object)nodeCanvas == (UnityEngine.Object)null)
            {
                throw new UnityException("Cannot Load NodeCanvas: The file at the specified path '" + path + "' is no valid save file as it does not contain a NodeCanvas!");
            }
            if (createWorkingCopy)
            {
                nodeCanvas = CreateWorkingCopy(nodeCanvas, true);
            }
            else
            {
                nodeCanvas.Validate();
            }
            Uncompress(ref nodeCanvas);
            NodeEditorCallbacks.IssueOnLoadCanvas(nodeCanvas);
            return(nodeCanvas);
        }
예제 #19
0
        /// <summary>
        /// Converts the given canvas to the specified type
        /// </summary>
        public static NodeCanvas ConvertCanvasType(NodeCanvas canvas, Type newType)
        {
            NodeCanvas convertedCanvas = canvas;

            if (canvas.GetType() != newType && newType.IsSubclassOf(typeof(NodeCanvas)))
            {
                canvas.Validate();
                canvas                       = NodeEditorSaveManager.CreateWorkingCopy(canvas);
                convertedCanvas              = NodeCanvas.CreateCanvas(newType);
                convertedCanvas.nodes        = canvas.nodes;
                convertedCanvas.groups       = canvas.groups;
                convertedCanvas.editorStates = canvas.editorStates;
                for (int i = 0; i < convertedCanvas.nodes.Count; i++)
                {
                    if (!CheckCanvasCompability(convertedCanvas.nodes[i].GetID, newType))
                    {                     // Check if nodes is even compatible with the canvas, if not delete it
                        convertedCanvas.nodes[i].Delete();
                        i--;
                    }
                }
                convertedCanvas.Validate();
            }
            return(convertedCanvas);
        }
예제 #20
0
        /// <summary>
        /// Loads the nodeCanvas stored in the current scene under the specified name and optionally creates a working copy of it before returning
        /// </summary>
        public static NodeCanvas LoadSceneNodeCanvas(string saveName, bool createWorkingCopy)
        {
            if (string.IsNullOrEmpty(saveName))
            {
                throw new System.ArgumentNullException("Cannot load Canvas from scene: No save name specified!");
            }

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

            // Load SceneSave
            NodeCanvasSceneSave sceneSave = FindSceneSave(saveName);

            if (sceneSave == null || sceneSave.savedNodeCanvas == null)
            {
                return(null);
            }

            // Extract the saved canvas and editorStates
            NodeCanvas savedCanvas = sceneSave.savedNodeCanvas;

            // Set the saveName as the new source of the canvas
            savedCanvas.UpdateSource("SCENE/" + saveName);

            // Postprocess the loaded canvas
            savedCanvas.Validate();
            if (createWorkingCopy)
            {
                savedCanvas = CreateWorkingCopy(savedCanvas);
            }

            NodeEditorCallbacks.IssueOnLoadCanvas(savedCanvas);
            return(savedCanvas);
        }
예제 #21
0
 public static void Uncompress(ref NodeCanvas nodeCanvas)
 {
     for (int i = 0; i < nodeCanvas.nodes.Count; i++)
     {
         Node node = nodeCanvas.nodes[i];
         if (node.Inputs == null || node.Inputs.Count == 0 || node.Outputs == null || node.Outputs.Count == 0)
         {
             node.Inputs  = new List <NodeInput>();
             node.Outputs = new List <NodeOutput>();
             for (int j = 0; j < node.nodeKnobs.Count; j++)
             {
                 NodeKnob nodeKnob = node.nodeKnobs[j];
                 if (nodeKnob is NodeInput)
                 {
                     node.Inputs.Add(nodeKnob as NodeInput);
                 }
                 else if (nodeKnob is NodeOutput)
                 {
                     node.Outputs.Add(nodeKnob as NodeOutput);
                 }
             }
         }
     }
 }
예제 #22
0
        public static NodeEditorState ExtractEditorState(NodeCanvas canvas, string stateName)
        {
            NodeEditorState nodeEditorState = null;

            if (canvas.editorStates.Length > 0)
            {
                nodeEditorState = canvas.editorStates.First((NodeEditorState s) => s.name == stateName);
                if ((UnityEngine.Object)nodeEditorState == (UnityEngine.Object)null)
                {
                    nodeEditorState = canvas.editorStates[0];
                }
            }
            if ((UnityEngine.Object)nodeEditorState == (UnityEngine.Object)null)
            {
                nodeEditorState        = ScriptableObject.CreateInstance <NodeEditorState>();
                nodeEditorState.canvas = canvas;
                canvas.editorStates    = new NodeEditorState[1]
                {
                    nodeEditorState
                };
            }
            nodeEditorState.name = stateName;
            return(nodeEditorState);
        }
예제 #23
0
        /// <summary>
        /// Loads the NodeCanvas from the asset file at path and optionally creates a working copy of it before returning
        /// </summary>
        public static NodeCanvas LoadNodeCanvas(string path, bool createWorkingCopy)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new UnityException("Cannot Load NodeCanvas: No path specified to load the NodeCanvas from!");
            }

            // Fetch all objects in the save file
            ScriptableObject[] objects = ResourceManager.LoadResources <ScriptableObject> (path);
            if (objects == null || objects.Length == 0)
            {
                throw new UnityException("Cannot Load NodeCanvas: The specified path '" + path + "' does not point to a save file!");
            }

            // Filter out the NodeCanvas out of these objects
            NodeCanvas nodeCanvas = objects.Single((ScriptableObject obj) => (obj as NodeCanvas) != null) as NodeCanvas;

            if (nodeCanvas == null)
            {
                throw new UnityException("Cannot Load NodeCanvas: The file at the specified path '" + path + "' is no valid save file as it does not contain a NodeCanvas!");
            }

        #if UNITY_EDITOR // Create a working copy of it
            if (createWorkingCopy)
            {
                CreateWorkingCopy(ref nodeCanvas, false);
                if (nodeCanvas == null)
                {
                    throw new UnityException("Cannot Load NodeCanvas: Failed to create a working copy for the NodeCanvas at path '" + path + "' during the loading process!");
                }
            }
            UnityEditor.AssetDatabase.Refresh();
        #endif
            NodeEditorCallbacks.IssueOnLoadCanvas(nodeCanvas);
            return(nodeCanvas);
        }
예제 #24
0
 /// <summary>
 /// Returns the NodeData for the given canvas
 /// </summary>
 public static NodeCanvasTypeData GetCanvasTypeData(NodeCanvas canvas)
 {
     return(GetCanvasTypeData(canvas.GetType()));
 }
예제 #25
0
 /// <summary>
 /// Creates and opens a new empty node canvas
 /// </summary>
 public void NewNodeCanvas()
 {
     // New NodeCanvas
     mainNodeCanvas = CreateInstance<NodeCanvas> ();
     mainNodeCanvas.nodes = new List<Node> ();
     // New NodeEditorState
     mainEditorState = CreateInstance<NodeEditorState> ();
     mainEditorState.canvas = mainNodeCanvas;
     mainEditorState.name = "MainEditorState";
     // Set some properties
     openedCanvas = "New Canvas";
     openedCanvasPath = "";
 }
예제 #26
0
        /// <summary>
        /// Context Click selection. Here you'll need to register your own using a string identifier
        /// </summary>
        public static void ContextCallback(object obj)
        {
            callbackObject cbObj = obj as callbackObject;
            curNodeCanvas = cbObj.canvas;
            curEditorState = cbObj.editor;

            switch (cbObj.message)
            {
            case "deleteNode":
                if (cbObj.node != null)
                    cbObj.node.Delete ();
                break;

            case "duplicateNode":
                if (cbObj.node != null)
                {
                    ContextCallback (new callbackObject (cbObj.node.GetID, curNodeCanvas, curEditorState));
                    Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1];
                    curEditorState.activeNode = duplicatedNode;
                    curEditorState.dragNode = true;
                }
                break;

            default:
                var createPos = ScreenToGUIPos (mousePos);
                if (cbObj.nodeOutput != null && (curEditorState.connectMousePos - mousePos).sqrMagnitude < 50)
                    createPos = new Vector2(cbObj.nodeOutput.body.rect.xMax+50, cbObj.nodeOutput.body.rect.yMin);

                foreach (Node node in NodeTypes.nodes.Keys)
                {
                    if (node.GetID == cbObj.message)
                    {
                        var newNode = node.Create (createPos);
                        newNode.InitBase ();
                        if (cbObj.nodeOutput != null)
                        { // If nodeOutput is defined, link it to the first input of the same type
                            foreach (var input in newNode.Inputs)
                            {
                                if (Node.CanApplyConnection (cbObj.nodeOutput, input))
                                { // If it can connect (type is equals, it does not cause recursion, ...)
                                    Node.ApplyConnection (cbObj.nodeOutput, input);
                                    break;
                                }
                            }
                        }
                    }
                }
                break;
            }
        }
예제 #27
0
 /// <summary>
 /// Recalculate from every Input Node.
 /// Usually does not need to be called at all, the smart calculation system is doing the job just fine.
 /// Option to not recalculate the inputs, when they are already set manually
 /// </summary>
 public static void RecalculateAll(NodeCanvas nodeCanvas, bool calculateInputs)
 {
     workList = new List<Node> ();
     foreach (Node node in nodeCanvas.nodes)
     {
         if (node.Inputs.Count == 0)
         { // Add all Inputs
             if (calculateInputs)
             {
                 ClearCalculation (node);
                 workList.Add (node);
             }
             else
             {
                 foreach (NodeOutput output in node.Outputs)
                 {
                     for (int conCnt = 0; conCnt < output.connections.Count; conCnt++)
                     {
                         ClearCalculation (output.connections [conCnt].body);
                         workList.Add (output.connections [conCnt].body);
                     }
                 }
             }
         }
     }
     StartCalculation ();
 }
예제 #28
0
		/// <summary>
		/// Returns the node at the position in specified canvas space.
		/// </summary>
		public static Node NodeAtPosition (NodeEditorState editorState, NodeCanvas nodeCanvas, Vector2 pos)
		{	
			if (!editorState.canvasRect.Contains (pos))
				return null;
			for (int nodeCnt = nodeCanvas.nodes.Count-1; nodeCnt >= 0; nodeCnt--) 
			{ // Check from top to bottom because of the render order
				Node node = nodeCanvas.nodes [nodeCnt];
				if (CanvasGUIToScreenRect (node.rect).Contains (pos)) // Node Body
					return node;
				foreach (NodeKnob knob in node.nodeKnobs)
				{ // Any edge control
					if (knob.GetScreenKnob ().Contains (pos))
						return node;
				}
			}
			return null;
		}
예제 #29
0
        /// <summary>
        /// Context Click selection. Here you'll need to register your own using a string identifier
        /// </summary>
        public static void ContextCallback(object obj)
        {
            callbackObject cbObj = obj as callbackObject;
            curNodeCanvas = cbObj.canvas;
            curEditorState = cbObj.editor;

            switch (cbObj.message)
            {
            case "deleteNode":
                if (curEditorState.focusedNode != null)
                    curEditorState.focusedNode.Delete ();
                break;

            case "duplicateNode":
                if (curEditorState.focusedNode != null)
                {
                    ContextCallback (new callbackObject (curEditorState.focusedNode.GetID, curNodeCanvas, curEditorState));
                    Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1];

                    curEditorState.focusedNode = duplicatedNode;
                    curEditorState.dragNode = true;
                    curEditorState.makeTransition = null;
                    curEditorState.connectOutput = null;
                    curEditorState.panWindow = false;
                }
                break;

            case "startTransition":
                if (curEditorState.focusedNode != null)
                {
                    curEditorState.makeTransition = curEditorState.focusedNode;
                    curEditorState.connectOutput = null;
                }
                curEditorState.dragNode = false;
                curEditorState.panWindow = false;

                break;

            default:
                Vector2 createPos = ScreenToGUIPos (mousePos);

                Node node = NodeTypes.getDefaultNode (cbObj.message);
                if (node == null)
                    break;

                bool acceptTransitions = NodeTypes.nodes [node].transitions;

                node = node.Create (createPos);
                node.InitBase ();
                NodeEditorCallbacks.IssueOnAddNode (node);

                if (curEditorState.connectOutput != null)
                { // If nodeOutput is defined, link it to the first input of the same type
                    foreach (NodeInput input in node.Inputs)
                    {
                        if (Node.CanApplyConnection (curEditorState.connectOutput, input))
                        { // If it can connect (type is equals, it does not cause recursion, ...)
                            Node.ApplyConnection (curEditorState.connectOutput, input);
                            break;
                        }
                    }
                }
                else if (acceptTransitions && curEditorState.makeTransition != null)
                {
                    Node.CreateTransition (curEditorState.makeTransition, node);
                }

                curEditorState.makeTransition = null;
                curEditorState.connectOutput = null;
                curEditorState.dragNode = false;
                curEditorState.panWindow = false;

                break;
            }
        }
예제 #30
0
 /// <summary>
 /// Draws the Node Canvas on the screen in the rect specified by editorState. Has to be called out of any GUI Group or area because of zooming.
 /// </summary>
 public static void DrawCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState)
 {
     DrawCanvas (nodeCanvas, editorState, new Rect ());
 }
예제 #31
0
		/// <summary>
		/// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path
		/// </summary>
		public void LoadNodeCanvas (string path) 
		{
			// Load the NodeCanvas
			NodeCanvas nodeCanvas = NodeEditor.LoadNodeCanvas (path);
			if (nodeCanvas == null) 
			{
				NewNodeCanvas ();
				return;
			}
			mainNodeCanvas = nodeCanvas;
			
			// Load the associated MainEditorState
			List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path);
			mainEditorState = editorStates.Find (x => x.name == "MainEditorState");
			if (mainEditorState == null)
				mainEditorState = CreateInstance<NodeEditorState> ();
			
			// Set some editor properties
			openedCanvasPath = path;
			
			NodeEditor.RecalculateAll (mainNodeCanvas);
			Repaint ();
		}
예제 #32
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;
     #if UNITY_EDITOR
     string existingPath = UnityEditor.AssetDatabase.GetAssetPath (nodeCanvas);
     if (!String.IsNullOrEmpty (existingPath))
     {
         if (existingPath != path)
         {
             UnityEditor.AssetDatabase.CopyAsset (existingPath, path);
             UnityEditor.AssetDatabase.SaveAssets ();
             UnityEditor.AssetDatabase.Refresh ();
         }
         return;
     }
     UnityEditor.AssetDatabase.CreateAsset (nodeCanvas, path);
     foreach (NodeEditorState editorState in editorStates)
         UnityEditor.AssetDatabase.AddObjectToAsset (editorState, nodeCanvas);
     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);
         for (int inCnt = 0; inCnt < node.Inputs.Count; inCnt++)
             UnityEditor.AssetDatabase.AddObjectToAsset (node.Inputs [inCnt], node);
         for (int outCnt = 0; outCnt < node.Outputs.Count; outCnt++)
             UnityEditor.AssetDatabase.AddObjectToAsset (node.Outputs [outCnt], node);
         for (int transCnt = 0; transCnt < node.transitions.Count; transCnt++)
             UnityEditor.AssetDatabase.AddObjectToAsset (node.transitions [transCnt], 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);
 }
        public static void BeginEditingCanvas(NodeCanvas canvas)
        {
            NodeEditorState state = canvas.editorStates.Length >= 1? canvas.editorStates[0] : null;

            BeginEditingCanvas(canvas, state);
        }
예제 #34
0
        /// <summary>
        /// Creates and opens a new empty node canvas
        /// </summary>
        public void NewNodeCanvas()
        {
            // Else it will be stuck forever
            NodeEditor.StopTransitioning (mainNodeCanvas);

            // New NodeCanvas
            mainNodeCanvas = CreateInstance<NodeCanvas> ();
            mainNodeCanvas.name = "New Canvas";
            // New NodeEditorState
            mainEditorState = CreateInstance<NodeEditorState> ();
            mainEditorState.canvas = mainNodeCanvas;
            mainEditorState.name = "MainEditorState";

            openedCanvasPath = "";
            SaveCache ();
        }
예제 #35
0
        /// <summary>
        /// Returns the node at the position in specified canvas space.
        /// </summary>
        public static Node NodeAtPosition(NodeEditorState editorState, NodeCanvas nodecanvas, Vector2 pos)
        {
            if (!editorState.canvasRect.Contains (pos))
                return null;

            // Check if we clicked inside a window (or knobSize pixels left or right of it at outputs, for faster knob recognition)
            float KnobSize = (float)NodeEditor.knobSize/editorState.zoom;
            if (editorState.activeNode != null)
            { // active Node is drawn ontop, so we check it first
                Rect NodeRect = new Rect (GUIToScreenRect (editorState.activeNode.rect));
                NodeRect = new Rect (NodeRect.x - KnobSize, NodeRect.y, NodeRect.width + KnobSize*2, NodeRect.height);
                if (NodeRect.Contains (pos))
                    return editorState.activeNode;
            }
            for (int nodeCnt = nodecanvas.nodes.Count-1; nodeCnt >= 0; nodeCnt--)
            { // checked from top to bottom because of the render order
                Rect NodeRect = new Rect (GUIToScreenRect (nodecanvas.nodes [nodeCnt].rect));
                NodeRect = new Rect (NodeRect.x - KnobSize, NodeRect.y, NodeRect.width + KnobSize*2, NodeRect.height);
                if (NodeRect.Contains (pos))
                    return nodecanvas.nodes [nodeCnt];
            }
            return null;
        }
예제 #36
0
			public NodeEditorMenuCallback (string Message, NodeCanvas nodecanvas, NodeEditorState editorState) 
			{
				message = Message;
				canvas = nodecanvas;
				editor = editorState;
				contextClickPos = Event.current.mousePosition;
			}
예제 #37
0
		/// <summary>
		/// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP)
		/// </summary>
		public static void DrawSubCanvas (NodeCanvas nodeCanvas, NodeEditorState editorState)  
		{
			if (!editorState.drawing)
				return;

			// Store and restore later on in case of this being a nested Canvas
			NodeCanvas prevNodeCanvas = curNodeCanvas;
			NodeEditorState prevEditorState = curEditorState;
			
			curNodeCanvas = nodeCanvas;
			curEditorState = editorState;

			if (Event.current.type == EventType.Repaint) 
			{ // Draw Background when Repainting
				GUI.BeginClip (curEditorState.canvasRect);
				
				float width = NodeEditorGUI.Background.width / curEditorState.zoom;
				float height = NodeEditorGUI.Background.height / curEditorState.zoom;
				Vector2 offset = curEditorState.zoomPos + curEditorState.panOffset/curEditorState.zoom;
				offset = new Vector2 (offset.x%width - width, offset.y%height - height);
				int tileX = Mathf.CeilToInt ((curEditorState.canvasRect.width + (width - offset.x)) / width);
				int tileY = Mathf.CeilToInt ((curEditorState.canvasRect.height + (height - offset.y)) / height);
				
				for (int x = 0; x < tileX; x++) 
				{
					for (int y = 0; y < tileY; y++) 
					{
						GUI.DrawTexture (new Rect (offset.x + x*width, 
												   offset.y + y*height, 
												   width, height), 
										 NodeEditorGUI.Background);
					}
				}
				GUI.EndClip ();
			}
			
			// Check the inputs
			InputEvents ();
			if (Event.current.type != EventType.Layout)
				curEditorState.ignoreInput = new List<Rect> ();

			// We're using a custom scale method, as default one is messing up clipping rect
			Rect canvasRect = curEditorState.canvasRect;
			curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale (ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, false);
			//GUILayout.Label ("Scaling is Great!"); -> TODO: Test by changing the last bool parameter

			// ---- BEGIN SCALE ----

			// Some features which require drawing (zoomed)
			if (curEditorState.navigate) 
			{ // Draw a curve to the origin/active node for orientation purposes
				RTEditorGUI.DrawLine ((curEditorState.selectedNode != null? curEditorState.selectedNode.rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust, 
										ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom, 
										Color.black, null, 3); 
				RepaintClients ();
			}
			if (curEditorState.connectOutput != null)
			{ // Draw the currently drawn connection
				NodeOutput output = curEditorState.connectOutput;
				Vector2 startPos = output.GetGUIKnob ().center;
				Vector2 endPos = ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom;
				Vector2 endDir = output.GetDirection ();
				NodeEditorGUI.DrawConnection (startPos, endDir, endPos, 
												NodeEditorGUI.GetSecondConnectionVector (startPos, endPos, endDir), 
												ConnectionTypes.GetTypeData (output.type, true).Color);
				RepaintClients ();
			}
			if (curEditorState.makeTransition != null)
			{ // Draw the currently made transition
				RTEditorGUI.DrawLine (curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust, 
										ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom,
										Color.grey, null, 3); 
				RepaintClients ();
			}

			// Push the active node at the bottom of the draw order.
			if (Event.current.type == EventType.Layout && curEditorState.selectedNode != null)
			{
				curNodeCanvas.nodes.Remove (curEditorState.selectedNode);
				curNodeCanvas.nodes.Add (curEditorState.selectedNode);
			}

			// Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers
			foreach (Node node in curNodeCanvas.nodes)
				node.DrawConnections ();

			// Draw the nodes
			foreach (Node node in curNodeCanvas.nodes)
			{
				node.DrawNode ();
				if (Event.current.type == EventType.Repaint)
					node.DrawKnobs ();
			}

			// ---- END SCALE ----

			// End scaling group
			GUIScaleUtility.EndScale ();
			
			// Check events with less priority than node GUI controls
			LateEvents ();
			
			curNodeCanvas = prevNodeCanvas;
			curEditorState = prevEditorState;
		}
		public virtual void OnLoadCanvas (NodeCanvas canvas) {}
예제 #39
0
		/// <summary>
		/// Evaluates context callbacks previously registered
		/// </summary>
		public static void ContextCallback (object obj)
		{
			NodeEditorMenuCallback callback = obj as NodeEditorMenuCallback;
			if (callback == null)
				throw new UnityException ("Callback Object passed by context is not of type NodeEditorMenuCallback!");
			curNodeCanvas = callback.canvas;
			curEditorState = callback.editor;

			switch (callback.message)
			{
			case "deleteNode": // Delete request
				if (curEditorState.focusedNode != null) 
					curEditorState.focusedNode.Delete ();
				break;
				
			case "duplicateNode": // Duplicate request
				if (curEditorState.focusedNode != null) 
				{
					ContextCallback (new NodeEditorMenuCallback (curEditorState.focusedNode.GetID, curNodeCanvas, curEditorState));
					Node duplicatedNode = curNodeCanvas.nodes [curNodeCanvas.nodes.Count-1];

					curEditorState.focusedNode = duplicatedNode;
					curEditorState.dragNode = true;
					curEditorState.makeTransition = null;
					curEditorState.connectOutput = null;
					curEditorState.panWindow = false;
				}
				break;

			case "startTransition": // Starting a new transition
				if (curEditorState.focusedNode != null) 
				{
					curEditorState.makeTransition = curEditorState.focusedNode;
					curEditorState.connectOutput = null;
				}
				curEditorState.dragNode = false;
				curEditorState.panWindow = false;

				break;

			default: // Node creation request
				Node node = Node.Create (callback.message, ScreenToGUIPos (callback.contextClickPos));

				// Handle auto-connection
				if (curEditorState.connectOutput != null)
				{ // If nodeOutput is defined, link it to the first input of the same type
					foreach (NodeInput input in node.Inputs)
					{
						if (input.CanApplyConnection (curEditorState.connectOutput))
						{ // If it can connect (type is equals, it does not cause recursion, ...)
							input.ApplyConnection (curEditorState.connectOutput);
							break;
						}
					}
				}

				curEditorState.makeTransition = null;
				curEditorState.connectOutput = null;
				curEditorState.dragNode = false;
				curEditorState.panWindow = false;

				break;
			}
			RepaintClients ();
		}
예제 #40
0
 /// <summary>
 /// Recalculate from every Input Node.
 /// Usually does not need to be called at all, the smart calculation system is doing the job just fine
 /// </summary>
 public static void RecalculateAll(NodeCanvas nodeCanvas)
 {
     RecalculateAll (nodeCanvas, true);
 }
예제 #41
0
		/// <summary>
		/// Recalculate from every Input Node.
		/// Usually does not need to be called at all, the smart calculation system is doing the job just fine
		/// </summary>
		public static void RecalculateAll (NodeCanvas nodeCanvas) 
		{
			workList = new List<Node> ();
			foreach (Node node in nodeCanvas.nodes) 
			{
				if (node.isInput ())
				{ // Add all Inputs
					node.ClearCalculation ();
					workList.Add (node);
				}
			}
			StartCalculation ();
		}
 public virtual void OnLoadCanvas(NodeCanvas canvas)
 {
 }
		public virtual void OnSaveCanvas (NodeCanvas canvas) {}
예제 #44
0
 /// <summary>
 /// Stops the transitioning process of the passed nodeCanvas
 /// </summary>
 public static void StopTransitioning(NodeCanvas nodeCanvas)
 {
     if (nodeCanvas == null)
         return;
     if (transitioningNodeCanvases.Contains (nodeCanvas))
         transitioningNodeCanvases.Remove (nodeCanvas);
     #if UNITY_EDITOR
     if (transitioningNodeCanvases.Count == 0)
         NEUpdate -= UpdateTransitions;
     #endif
     //			Debug.Log ("Stopped transitioning " + nodeCanvas.name + (nodeCanvas.currentNode != null? (" at Node " + nodeCanvas.currentNode.name) : ""));
     if (nodeCanvas.currentTransition != null)
     {
         nodeCanvas.currentTransition.stopTransition ();
         nodeCanvas.currentTransition = null;
     }
     RepaintClients ();
 }
예제 #45
0
        /// <summary>
        /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path
        /// </summary>
        public void LoadNodeCanvas(string path)
        {
            // Load the NodeCanvas
            NodeCanvas nodeCanvas = NodeEditor.LoadNodeCanvas (path);
            if (nodeCanvas == null)
                return;
            mainNodeCanvas = nodeCanvas;

            // Load the associated MainEditorState
            List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path);
            mainEditorState = editorStates.Find (x => x.name == "MainEditorState");
            if (mainEditorState == null)
                mainEditorState = CreateInstance<NodeEditorState> ();

            // Set some editor properties
            string[] folders = path.Split (new char[] {'/'}, StringSplitOptions.None);
            openedCanvas = folders [folders.Length-1];
            openedCanvasPath = path;

            NodeEditor.RecalculateAll (mainNodeCanvas);
            Repaint ();
        }
예제 #46
0
        /// <summary>
        /// Creates and opens a new empty node canvas
        /// </summary>
        public void NewNodeCanvas()
        {
            // New NodeCanvas
            mainNodeCanvas = CreateInstance<NodeCanvas> ();
            mainNodeCanvas.name = "New Canvas";
            // New NodeEditorState
            mainEditorState = CreateInstance<NodeEditorState> ();
            mainEditorState.canvas = mainNodeCanvas;
            mainEditorState.name = "MainEditorState";

            openedCanvasPath = "";
            SaveCache ();
        }
예제 #47
0
 private void LoadCache()
 {
     string lastSessionName = EditorPrefs.GetString ("NodeEditorLastSession");
     string path = tempSessionPath + "/LastSession.asset";
     mainNodeCanvas = NodeEditorSaveManager.LoadNodeCanvas (path, false);
     if (mainNodeCanvas == null)
         NewNodeCanvas ();
     else
     {
         mainNodeCanvas.name = lastSessionName;
         List<NodeEditorState> editorStates = NodeEditorSaveManager.LoadEditorStates (path, false);
         if (editorStates == null || editorStates.Count == 0 || (mainEditorState = editorStates.Find (x => x.name == "MainEditorState")) == null )
         { // New NodeEditorState
             mainEditorState = CreateInstance<NodeEditorState> ();
             mainEditorState.canvas = mainNodeCanvas;
             mainEditorState.name = "MainEditorState";
             NodeEditorSaveManager.AddSubAsset (mainEditorState, path);
             AssetDatabase.SaveAssets ();
             AssetDatabase.Refresh ();
         }
     }
 }
예제 #48
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 UNITY_EDITOR
     if (String.IsNullOrEmpty (path))
         return;
     string existingPath = UnityEditor.AssetDatabase.GetAssetPath (nodeCanvas);
     if (!String.IsNullOrEmpty (existingPath))
     {
         if (existingPath != path)
         {
             UnityEditor.AssetDatabase.CopyAsset (existingPath, path);
             UnityEditor.AssetDatabase.SaveAssets ();
             UnityEditor.AssetDatabase.Refresh ();
         }
         return;
     }
     UnityEditor.AssetDatabase.CreateAsset (nodeCanvas, path);
     foreach (NodeEditorState editorState in editorStates)
         UnityEditor.AssetDatabase.AddObjectToAsset (editorState, nodeCanvas);
     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);
         for (int inCnt = 0; inCnt < node.Inputs.Count; inCnt++)
             UnityEditor.AssetDatabase.AddObjectToAsset (node.Inputs [inCnt], node);
         for (int outCnt = 0; outCnt < node.Outputs.Count; outCnt++)
             UnityEditor.AssetDatabase.AddObjectToAsset (node.Outputs [outCnt], node);
     }
     UnityEditor.AssetDatabase.SaveAssets ();
     UnityEditor.AssetDatabase.Refresh ();
     #endif
 }
예제 #49
0
 public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState, Node Node, NodeOutput NodeOutput)
 {
     message = Message;
     canvas = nodecanvas;
     editor = editorState;
     node = Node;
     nodeOutput = NodeOutput;
 }
예제 #50
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);
                }
            }

            nodeCanvas.BeforeSavingCanvas();

            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>
        /// Draws the Node Canvas on the screen in the rect specified by editorState without one-time wrappers like GUISkin and OverlayGUI. Made for nested Canvases (WIP)
        /// </summary>
        private static void DrawSubCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState)
        {
            if (!editorState.drawing)
            {
                return;
            }

            BeginEditingCanvas(nodeCanvas, editorState);

            if (Event.current.type == EventType.Repaint)
            {             // Draw Background when Repainting
                // Offset from origin in tile units
                Vector2 tileOffset = new Vector2(-(curEditorState.zoomPos.x * curEditorState.zoom + curEditorState.panOffset.x) / NodeEditorGUI.Background.width,
                                                 ((curEditorState.zoomPos.y - curEditorState.canvasRect.height) * curEditorState.zoom + curEditorState.panOffset.y) / NodeEditorGUI.Background.height);
                // Amount of tiles
                Vector2 tileAmount = new Vector2(Mathf.Round(curEditorState.canvasRect.width * curEditorState.zoom) / NodeEditorGUI.Background.width,
                                                 Mathf.Round(curEditorState.canvasRect.height * curEditorState.zoom) / NodeEditorGUI.Background.height);
                // Draw tiled background
                GUI.DrawTextureWithTexCoords(curEditorState.canvasRect, NodeEditorGUI.Background, new Rect(tileOffset, tileAmount));
            }

            // Handle input events
            NodeEditorInputSystem.HandleInputEvents(curEditorState);
            if (Event.current.type != EventType.Layout)
            {
                curEditorState.ignoreInput = new List <Rect> ();
            }

            // We're using a custom scale method, as default one is messing up clipping rect
            Rect canvasRect = curEditorState.canvasRect;

            curEditorState.zoomPanAdjust = GUIScaleUtility.BeginScale(ref canvasRect, curEditorState.zoomPos, curEditorState.zoom, NodeEditorGUI.isEditorWindow, false);

            // ---- BEGIN SCALE ----

            // Some features which require zoomed drawing:

            if (curEditorState.navigate)
            {             // Draw a curve to the origin/active node for orientation purposes
                Vector2 startPos = (curEditorState.selectedNode != null? curEditorState.selectedNode.rect.center : curEditorState.panOffset) + curEditorState.zoomPanAdjust;
                Vector2 endPos   = Event.current.mousePosition;
                RTEditorGUI.DrawLine(startPos, endPos, Color.green, null, 3);
                RepaintClients();
            }

            if (curEditorState.connectOutput != null)
            {             // Draw the currently drawn connection
                NodeOutput output   = curEditorState.connectOutput;
                Vector2    startPos = output.GetGUIKnob().center;
                Vector2    startDir = output.GetDirection();
                Vector2    endPos   = Event.current.mousePosition;
                Vector2    endDir   = -startDir;            // NodeEditorGUI.GetSecondConnectionVector (startPos, endPos, startDir); <- causes unpleasant jumping when switching polarity

                NodeEditorGUI.OptimiseBezierDirections(startPos, ref startDir, endPos, ref endDir);
                NodeEditorGUI.DrawConnection(startPos, startDir, endPos, endDir, output.typeData.Color);
                RepaintClients();
            }

            // Draw the groups below everything else
            for (int groupCnt = 0; groupCnt < curNodeCanvas.groups.Count; groupCnt++)
            {
                curNodeCanvas.groups [groupCnt].DrawGroup();
            }

            // Push the active node to the top of the draw order.
            if (Event.current.type == EventType.Layout && curEditorState.selectedNode != null)
            {
                curNodeCanvas.nodes.Remove(curEditorState.selectedNode);
                curNodeCanvas.nodes.Add(curEditorState.selectedNode);
            }

            // Draw the transitions and connections. Has to be drawn before nodes as transitions originate from node centers
            for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++)
            {
                curNodeCanvas.nodes [nodeCnt].DrawConnections();
            }

            // Draw the nodes
            for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++)
            {
                Node node = curNodeCanvas.nodes [nodeCnt];
                node.DrawNode();
                if (Event.current.type == EventType.Repaint)
                {
                    node.DrawKnobs();
                }
            }

            // ---- END SCALE ----

            // End scaling group
            GUIScaleUtility.EndScale();

            // Handle input events with less priority than node GUI controls
            NodeEditorInputSystem.HandleLateInputEvents(curEditorState);

            EndEditingCanvas();
        }
예제 #52
0
 /// <summary>
 /// Creates a working copy of the specified editorStates. Also remains the link of the canvas to these 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>
 private static NodeEditorState[] CreateWorkingCopy(NodeEditorState[] editorStates, NodeCanvas associatedNodeCanvas)
 {
     if (editorStates == null)
     {
         return(new NodeEditorState[0]);
     }
     editorStates = (NodeEditorState[])editorStates.Clone();
     for (int stateCnt = 0; stateCnt < editorStates.Length; stateCnt++)
     {
         if (editorStates[stateCnt] == null)
         {
             continue;
         }
         NodeEditorState state = editorStates[stateCnt] = Clone(editorStates[stateCnt]);
         if (state == null)
         {
             Debug.LogError("Failed to create a working copy for an NodeEditorState during the loading process of " + associatedNodeCanvas.name + "!");
             continue;
         }
         state.canvas = associatedNodeCanvas;
     }
     associatedNodeCanvas.editorStates = editorStates;
     return(editorStates);
 }
 public static void EndEditingCanvas()
 {
     curNodeCanvas  = editCanvasStack.Pop();
     curEditorState = editEditorStateStack.Pop();
 }
예제 #54
0
        /// <summary>
        /// Draws the Node Canvas on the screen in the rect specified by editorState. Has to be called out of any GUI Group or area because of zooming.
        /// </summary>
        public static void DrawCanvas(NodeCanvas nodeCanvas, NodeEditorState editorState, Action repaint)
        {
            if (!editorState.drawing)
                return;

            curNodeCanvas = nodeCanvas;
            curEditorState = editorState;

            if (repaint != null)
                Repaint += repaint;

            //		if (curEditorState.parent != null)
            //			curEditorState.canvasRect.position += curEditorState.parent.zoomPanAdjust;

            if (Event.current.type == EventType.Repaint)
            { // Draw Background when Repainting
                GUI.BeginClip (curEditorState.canvasRect);

                float width = Background.width / curEditorState.zoom;
                float height = Background.height / curEditorState.zoom;
                Vector2 offset = new Vector2 ((curEditorState.panOffset.x / curEditorState.zoom)%width - width,
                                              (curEditorState.panOffset.y / curEditorState.zoom)%height - height);
                int tileX = Mathf.CeilToInt ((curEditorState.canvasRect.width + (width - offset.x)) / width);
                int tileY = Mathf.CeilToInt ((curEditorState.canvasRect.height + (height - offset.y)) / height);

                for (int x = 0; x < tileX; x++)
                {
                    for (int y = 0; y < tileY; y++)
                    {
                        Rect texRect = new Rect (offset.x + x*width,
                                                 offset.y + y*height,
                                                 width, height);

                        GUI.DrawTexture (texRect, Background);
                    }
                }
                GUI.EndClip ();
            }

            //		if (curEditorState.parent != null)
            //			curEditorState.canvasRect.position -= curEditorState.parent.zoomPanAdjust - curEditorState.parent.zoomPos;

            // Fetch all nested nodeEditors and set their canvasRects to be ignored by input,
            // so it can be handled later, and note it down, as it will be drawn later ontop
            List<Rect> ignoreInput = new List<Rect> ();
            for (int childCnt = 0; childCnt < curEditorState.childs.Count; childCnt++)
            {
                if (curEditorState.childs [childCnt].drawing)
                {
                    NodeEditorState nestedEditor = curEditorState.childs [childCnt];
                    ignoreInput.Add (GUIToScreenRect (nestedEditor.canvasRect));
                }
            }

            // Check the inputs
            InputEvents (ignoreInput);

            // We want to scale our nodes, but as GUI.matrix also scales our widnow's clipping group,
            // we have to scale it up first to receive a correct one as a result
            #region Scale Setup

            // End the default clipping group
            GUI.EndGroup ();

            // The Rect of the new clipping group to draw our nodes in
            Rect ScaledCanvasRect = ScaleRect (curEditorState.canvasRect, curEditorState.zoomPos + curEditorState.canvasRect.position, new Vector2 (curEditorState.zoom, curEditorState.zoom));
            ScaledCanvasRect.y += 23; // Header tab height

            if (curNodeCanvas != NodeEditorWindow.MainNodeCanvas)
                GUI.DrawTexture (ScaledCanvasRect, Background);

            // Now continue drawing using the new clipping group
            GUI.BeginGroup (ScaledCanvasRect);
            ScaledCanvasRect.position = Vector2.zero; // Adjust because we entered the new group

            // Because I currently found no way to actually scale to the center of the window rather than (0, 0),
            // I'm going to cheat and just pan it accordingly to let it appear as if it would scroll to the center
            // Note, due to that, other controls are still scaled to (0, 0)
            curEditorState.zoomPanAdjust = ScaledCanvasRect.center - curEditorState.canvasRect.size/2 + curEditorState.zoomPos;

            // Take a matrix backup to restore back later on
            Matrix4x4 GUIMatrix = GUI.matrix;

            // Scale GUI.matrix. After that we have the correct clipping group again.
            GUIUtility.ScaleAroundPivot (new Vector2 (1/curEditorState.zoom, 1/curEditorState.zoom), curEditorState.zoomPanAdjust);

            #endregion

            // Some features which require drawing (zoomed)
            if (curEditorState.navigate)
            { // Draw a curve to the origin/active node for orientation purposes
                DrawLine (curEditorState.activeNode != null? curEditorState.activeNode.rect.center + curEditorState.zoomPanAdjust : curEditorState.panOffset,
                          ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom,
                          Color.black, null, 3);
                if (Repaint != null)
                    Repaint ();
            }
            if (curEditorState.connectOutput != null)
            { // Draw the currently drawn connection
                DrawConnection (curEditorState.connectOutput.GetGUIKnob ().center,
                                ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom,
                                ConnectionTypes.GetTypeData (curEditorState.connectOutput.type).col);
                if (Repaint != null)
                    Repaint ();
            }
            if (curEditorState.makeTransition != null)
            { // Draw the currently made transition
                DrawLine (curEditorState.makeTransition.rect.center + curEditorState.zoomPanAdjust,
                          ScreenToGUIPos (mousePos) + curEditorState.zoomPos * curEditorState.zoom,
                          Color.grey, null, 3);
                if (Repaint != null)
                    Repaint ();
            }

            // Draw the Node connectors; Seperated because of render order
            for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++)
                curNodeCanvas.nodes [nodeCnt].DrawConnections ();
            for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++)
                curNodeCanvas.nodes [nodeCnt].DrawKnobs ();
            for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++)
                curNodeCanvas.nodes [nodeCnt].DrawTransitions ();

            // Draw the nodes
            for (int nodeCnt = 0; nodeCnt < curNodeCanvas.nodes.Count; nodeCnt++)
            {
                Node node = curNodeCanvas.nodes [nodeCnt];
                //if (node != curEditorState.activeNode)
                NodeEditor.DrawNode (node);
            }

            // Draw the active Node ontop
            //		if (editorState.activeNode != null)
            //			NodeEditor.DrawNode (curEditorState.activeNode);

            // Draw any node groups out there. Has to be drawn here, because they still need to scale according to their parents, but they mustn't be drawn inside a GUI group
            for (int editorCnt = 0; editorCnt < curEditorState.childs.Count; editorCnt++)
            {
                if (curEditorState.childs [editorCnt].drawing)
                {
                    NodeEditorState nestedEditor = curEditorState.childs [editorCnt];
                    nestedEditor.canvasRect.position += curEditorState.zoomPanAdjust;
                    //GUI.DrawTexture (nestedEditor.canvasRect, Background);
                    DrawCanvas (nestedEditor.canvas, nestedEditor, Repaint);
                    nestedEditor.canvasRect.position -= curEditorState.zoomPanAdjust;
                }
            }
            curNodeCanvas = nodeCanvas;
            curEditorState = editorState;

            // End scaling group
            // Set default matrix and clipping group for the rest
            GUI.matrix = GUIMatrix;
            GUI.EndGroup ();
            if (curNodeCanvas.parent == null)
            {
                GUI.BeginGroup (new Rect (0, 23, NodeEditorWindow.editor.position.width, NodeEditorWindow.editor.position.height));
            }
            else
            {
                Rect parentGroupRect = ScaleRect (curEditorState.parent.canvasRect, curEditorState.parent.zoomPos + curEditorState.parent.canvasRect.position, new Vector2 (curEditorState.parent.zoom, curEditorState.parent.zoom));
                parentGroupRect.y += 23; // Header tab height
                GUI.BeginGroup (parentGroupRect);
            }
            // Check events with less priority than node GUI controls
            LateEvents (ignoreInput);
        }
예제 #55
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)
        {
            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);
        }
예제 #56
0
		/// <summary>
		/// Draws the Node Canvas on the screen in the rect specified by editorState
		/// </summary>
		public static void DrawCanvas (NodeCanvas nodeCanvas, NodeEditorState editorState)  
		{
			if (!editorState.drawing)
				return;
			checkInit ();

			NodeEditorGUI.StartNodeGUI ();
			OverlayGUI.StartOverlayGUI ();
			DrawSubCanvas (nodeCanvas, editorState);
			OverlayGUI.EndOverlayGUI ();
			NodeEditorGUI.EndNodeGUI ();
		}
예제 #57
0
		/// <summary>
		/// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path
		/// </summary>
		public void LoadNodeCanvas (string path) 
		{
			// Load the NodeCanvas
			mainNodeCanvas = NodeEditor.LoadNodeCanvas (path);
			if (mainNodeCanvas == null) 
			{
				NewNodeCanvas ();
				return;
			}
			
			// Load the associated MainEditorState
			List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path);
			if (editorStates.Count == 0)
				mainEditorState = CreateInstance<NodeEditorState> ();
			else 
			{
				mainEditorState = editorStates.Find (x => x.name == "MainEditorState");
				if (mainEditorState == null) mainEditorState = editorStates[0];
			}
			mainEditorState.Canvas = mainNodeCanvas;

			OpenedCanvasPath = path;
			NodeEditor.RecalculateAll (mainNodeCanvas);
			//SaveCache ();
			Repaint ();
		}
예제 #58
0
 public callbackObject(string Message, NodeCanvas nodecanvas, NodeEditorState editorState)
 {
     message = Message;
     canvas = nodecanvas;
     editor = editorState;
 }
 public virtual void OnSaveCanvas(NodeCanvas canvas)
 {
 }
예제 #60
0
        /// <summary>
        /// Loads the mainNodeCanvas and it's associated mainEditorState from an asset at path
        /// </summary>
        public void LoadNodeCanvas(string path)
        {
            // Load the NodeCanvas
            mainNodeCanvas = NodeEditorSaveManager.LoadNodeCanvas (path, true);
            if (mainNodeCanvas == null)
            {
                Debug.Log ("Error loading NodeCanvas from '" + path + "'!");
                NewNodeCanvas ();
                return;
            }

            // Load the associated MainEditorState
            List<NodeEditorState> editorStates = NodeEditorSaveManager.LoadEditorStates (path, true);
            if (editorStates.Count == 0)
            {
                mainEditorState = ScriptableObject.CreateInstance<NodeEditorState> ();
                Debug.LogError ("The save file '" + path + "' did not contain an associated NodeEditorState!");
            }
            else
            {
                mainEditorState = editorStates.Find (x => x.name == "MainEditorState");
                if (mainEditorState == null) mainEditorState = editorStates[0];
            }
            mainEditorState.canvas = mainNodeCanvas;

            openedCanvasPath = path;
            NodeEditor.RecalculateAll (mainNodeCanvas);
            SaveCache ();
            Repaint ();
        }