Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

Commit

Permalink
Major WIP Update:
Browse files Browse the repository at this point in the history
- State Behaviour added (WIP/Beta, State node, transition with transition time, no conditions yet due to lack of serializeable funcs, see UnityFunc)
- new Caching system (continuous save, impossible to loose data, longer load times and slightly longer delay when creating nodes)
- moved Save system to seperate script (-> NodeEditorSaveManager)
- added WIP UnityFunc (Missing PropertyDrawer GUI (esp. function picker), intended use for action node and transition conditions)
- added support for additional ScriptableObjects in nodes, nodeKnobs, etc. (see new functions GetScriptableObjects and CopyScriptableObjects)
- improved NodeKnob system (now generic rect on the node, extendable, still more flexibility to come!)
- save overhaul (due to alot of changes (transitions, nodeKnob improvement) save system has been updated. You might experience bugs (even though everything works for me), please send save file and log to me!)
- lot more small things I can't remember;)
Again, much WIP in this commit! :)
  • Loading branch information
Seneral committed Feb 13, 2016
1 parent 7abc635 commit e32476e
Show file tree
Hide file tree
Showing 43 changed files with 2,378 additions and 944 deletions.
Binary file modified Docs/Node Editor Documentation.pdf
Binary file not shown.
Binary file modified Docs/Node Editor Roadmap.pdf
Binary file not shown.
187 changes: 136 additions & 51 deletions Editor/Node_Editor/NodeEditorWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.IO;
using System.Collections.Generic;

using NodeEditorFramework;
using NodeEditorFramework.Utilities;

Expand Down Expand Up @@ -40,8 +41,6 @@ public static void CreateEditor ()
NodeEditor.ClientRepaints += _editor.Repaint;
NodeEditor.initiated = NodeEditor.InitiationError = false;

// Setup Title content
ResourceManager.Init (NodeEditor.editorPath + "Resources/");
iconTexture = ResourceManager.LoadTexture (EditorGUIUtility.isProSkin? "Textures/Icon_Dark.png" : "Textures/Icon_Light.png");
_editor.titleContent = new GUIContent ("Node Editor", iconTexture);
}
Expand All @@ -65,76 +64,59 @@ public static bool AutoOpenCanvas (int instanceID, int line)
public void OnDestroy ()
{
NodeEditor.ClientRepaints -= _editor.Repaint;
SaveCache ();
//SaveCache ();

#if UNITY_EDITOR
// Remove callbacks
EditorLoadingControl.beforeEnteringPlayMode -= SaveCache;
//EditorLoadingControl.beforeEnteringPlayMode -= SaveCache;
EditorLoadingControl.lateEnteredPlayMode -= LoadCache;
EditorLoadingControl.beforeLeavingPlayMode -= SaveCache;
//EditorLoadingControl.beforeLeavingPlayMode -= SaveCache;
EditorLoadingControl.justLeftPlayMode -= LoadCache;
EditorLoadingControl.justOpenedNewScene -= LoadCache;

NodeEditorCallbacks.OnAddNode -= SaveNewNode;
NodeEditorCallbacks.OnAddTransition -= SaveNewTransition;

// TODO: BeforeOpenedScene to save Cache, aswell as assembly reloads...
#endif
}

// Following section is all about caching the last editor session

public void OnEnable ()
private void OnEnable ()
{
tempSessionPath = Path.GetDirectoryName (AssetDatabase.GetAssetPath (MonoScript.FromScriptableObject (this)));
LoadCache ();

#if UNITY_EDITOR
// This makes sure the Node Editor is reinitiated after the Playmode changed
EditorLoadingControl.beforeEnteringPlayMode -= SaveCache;
EditorLoadingControl.beforeEnteringPlayMode += SaveCache;
//EditorLoadingControl.beforeEnteringPlayMode -= SaveCache;
//EditorLoadingControl.beforeEnteringPlayMode += SaveCache;
EditorLoadingControl.lateEnteredPlayMode -= LoadCache;
EditorLoadingControl.lateEnteredPlayMode += LoadCache;

EditorLoadingControl.beforeLeavingPlayMode -= SaveCache;
EditorLoadingControl.beforeLeavingPlayMode += SaveCache;
//EditorLoadingControl.beforeLeavingPlayMode -= SaveCache;
//EditorLoadingControl.beforeLeavingPlayMode += SaveCache;
EditorLoadingControl.justLeftPlayMode -= LoadCache;
EditorLoadingControl.justLeftPlayMode += LoadCache;

EditorLoadingControl.justOpenedNewScene -= LoadCache;
EditorLoadingControl.justOpenedNewScene += LoadCache;

NodeEditorCallbacks.OnAddNode -= SaveNewNode;
NodeEditorCallbacks.OnAddNode += SaveNewNode;
NodeEditorCallbacks.OnAddTransition -= SaveNewTransition;
NodeEditorCallbacks.OnAddTransition += SaveNewTransition;

// TODO: BeforeOpenedScene to save Cache, aswell as assembly reloads...
#endif
}

private void SaveCache ()
{
DeleteCache ();
EditorPrefs.SetString ("NodeEditorLastSession", mainNodeCanvas.name + ".asset");
NodeEditor.SaveNodeCanvas (mainNodeCanvas, tempSessionPath + "/" + mainNodeCanvas.name + ".asset", mainEditorState);
AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
}
private void LoadCache ()
{
string lastSession = EditorPrefs.GetString ("NodeEditorLastSession");
if (String.IsNullOrEmpty (lastSession))
return;
LoadNodeCanvas (tempSessionPath + "/" + lastSession);
NodeEditor.initiated = NodeEditor.InitiationError = false;
}
private void DeleteCache ()
{
string lastSession = EditorPrefs.GetString ("NodeEditorLastSession");
if (!String.IsNullOrEmpty (lastSession))
AssetDatabase.DeleteAsset (tempSessionPath + "/" + lastSession);
AssetDatabase.Refresh ();
EditorPrefs.DeleteKey ("NodeEditorLastSession");
}

#endregion

#region GUI

public void OnGUI ()
private void OnGUI ()
{
// Initiation
NodeEditor.checkInit ();
Expand All @@ -158,9 +140,10 @@ public void OnGUI ()
{
NodeEditor.DrawCanvas (mainNodeCanvas, mainEditorState);
}
catch (UnityException e)
catch (Exception e)
{ // on exceptions in drawing flush the canvas to avoid locking the ui.
NewNodeCanvas ();
NodeEditor.ReInit (true);
Debug.LogError ("Unloaded Canvas due to exception when drawing!");
Debug.LogException (e);
}
Expand All @@ -174,24 +157,30 @@ public void OnGUI ()
NodeEditorGUI.EndNodeGUI ();
}

public void DrawSideWindow ()
private void DrawSideWindow ()
{
GUILayout.Label (new GUIContent ("Node Editor (" + mainNodeCanvas.name + ")", "Opened Canvas path: " + openedCanvasPath), NodeEditorGUI.nodeLabelBold);

if (GUILayout.Button (new GUIContent ("Save Canvas", "Saves the Canvas to a Canvas Save File in the Assets Folder")))
SaveNodeCanvas (EditorUtility.SaveFilePanelInProject ("Save Node Canvas", "Node Canvas", "asset", "", ResourceManager.resourcePath + "Saves/"));

{
string path = EditorUtility.SaveFilePanelInProject ("Save Node Canvas", "Node Canvas", "asset", "", NodeEditor.editorPath + "Resources/Saves/");
if (!string.IsNullOrEmpty (path))
SaveNodeCanvas (path);
}

if (GUILayout.Button (new GUIContent ("Load Canvas", "Loads the Canvas from a Canvas Save File in the Assets Folder")))
{
string path = EditorUtility.OpenFilePanel ("Load Node Canvas", ResourceManager.resourcePath + "Saves/", "asset");
string path = EditorUtility.OpenFilePanel ("Load Node Canvas", NodeEditor.editorPath + "Resources/Saves/", "asset");
if (!path.Contains (Application.dataPath))
{
if (path != String.Empty)
if (!string.IsNullOrEmpty (path))
ShowNotification (new GUIContent ("You should select an asset inside your project folder!"));
return;
}
path = path.Replace (Application.dataPath, "Assets");
LoadNodeCanvas (path);
else
{
path = path.Replace (Application.dataPath, "Assets");
LoadNodeCanvas (path);
}
}

if (GUILayout.Button (new GUIContent ("New Canvas", "Loads an empty Canvas")))
Expand All @@ -203,20 +192,106 @@ public void DrawSideWindow ()
if (GUILayout.Button ("Force Re-Init"))
NodeEditor.ReInit (true);

if (NodeEditor.isTransitioning (mainNodeCanvas) && GUILayout.Button ("Stop Transitioning"))
NodeEditor.StopTransitioning (mainNodeCanvas);

NodeEditorGUI.knobSize = EditorGUILayout.IntSlider (new GUIContent ("Handle Size", "The size of the Node Input/Output handles"), NodeEditorGUI.knobSize, 12, 20);
mainEditorState.zoom = EditorGUILayout.Slider (new GUIContent ("Zoom", "Use the Mousewheel. Seriously."), mainEditorState.zoom, 0.6f, 2);
}

#endregion

#region Cache

private void SaveNewNode (Node node)
{
if (!mainNodeCanvas.nodes.Contains (node))
throw new UnityException ("Cache system: Writing new Node to save file failed as Node is not part of the Cache!");
string path = tempSessionPath + "/LastSession.asset";
if (AssetDatabase.GetAssetPath (mainNodeCanvas) != path)
throw new UnityException ("Cache system error: Current Canvas is not saved as the temporary cache!");
NodeEditorSaveManager.AddSubAsset (node, path);
for (int knobCnt = 0; knobCnt < node.nodeKnobs.Count; knobCnt++)
NodeEditorSaveManager.AddSubAsset (node.nodeKnobs [knobCnt], path);
for (int transCnt = 0; transCnt < node.transitions.Count; transCnt++)
{
if (node.transitions[transCnt].startNode == node)
NodeEditorSaveManager.AddSubAsset (node.transitions [transCnt], path);
}

AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
}

private void SaveNewTransition (Transition transition)
{
if (!mainNodeCanvas.nodes.Contains (transition.startNode) || !mainNodeCanvas.nodes.Contains (transition.endNode))
throw new UnityException ("Cache system: Writing new Transition to save file failed as Node members are not part of the Cache!");
string path = tempSessionPath + "/LastSession.asset";
if (AssetDatabase.GetAssetPath (mainNodeCanvas) != path)
throw new UnityException ("Cache system error: Current Canvas is not saved as the temporary cache!");
NodeEditorSaveManager.AddSubAsset (transition, path);

AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
}

private void SaveCache ()
{
//DeleteCache (); // Delete old cache
string canvasName = mainNodeCanvas.name;
EditorPrefs.SetString ("NodeEditorLastSession", canvasName);
NodeEditorSaveManager.SaveNodeCanvas (tempSessionPath + "/LastSession.asset", false, mainNodeCanvas, mainEditorState);
mainNodeCanvas.name = canvasName;

AssetDatabase.SaveAssets ();
AssetDatabase.Refresh ();
}

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 ();
}
}
}

private void DeleteCache ()
{
string lastSession = EditorPrefs.GetString ("NodeEditorLastSession");
if (!String.IsNullOrEmpty (lastSession))
{
AssetDatabase.DeleteAsset (tempSessionPath + "/" + lastSession);
AssetDatabase.Refresh ();
}
EditorPrefs.DeleteKey ("NodeEditorLastSession");
}

#endregion

#region Save/Load

/// <summary>
/// Saves the mainNodeCanvas and it's associated mainEditorState as an asset at path
/// </summary>
public void SaveNodeCanvas (string path)
{
NodeEditor.SaveNodeCanvas (mainNodeCanvas, path, mainEditorState);
NodeEditorSaveManager.SaveNodeCanvas (path, true, mainNodeCanvas, mainEditorState);
//SaveCache ();
Repaint ();
}
Expand All @@ -226,18 +301,25 @@ public void SaveNodeCanvas (string path)
/// </summary>
public void LoadNodeCanvas (string path)
{
// Else it will be stuck forever
NodeEditor.StopTransitioning (mainNodeCanvas);

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

// Load the associated MainEditorState
List<NodeEditorState> editorStates = NodeEditor.LoadEditorStates (path);
if (editorStates.Count == 0)
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");
Expand All @@ -247,7 +329,7 @@ public void LoadNodeCanvas (string path)

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

Expand All @@ -256,6 +338,9 @@ public void LoadNodeCanvas (string path)
/// </summary>
public void NewNodeCanvas ()
{
// Else it will be stuck forever
NodeEditor.StopTransitioning (mainNodeCanvas);

// New NodeCanvas
mainNodeCanvas = CreateInstance<NodeCanvas> ();
mainNodeCanvas.name = "New Canvas";
Expand All @@ -265,7 +350,7 @@ public void NewNodeCanvas ()
mainEditorState.name = "MainEditorState";

openedCanvasPath = "";
//SaveCache ();
SaveCache ();
}

#endregion
Expand Down
3 changes: 2 additions & 1 deletion Node_Editor/Framework/Canvas Save Objects/NodeCanvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public class NodeCanvas : ScriptableObject
{ // Just contains the nodes and global canvas stuff; an associated NodeEditorState holds the actual state now
public List<Node> nodes = new List<Node> ();

// current node in the state system
// current states in the state system
public Node currentNode;
public Transition currentTransition;
}
}
20 changes: 16 additions & 4 deletions Node_Editor/Framework/Canvas Save Objects/NodeEditorState.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using UnityEngine;
using System;
using System.Collections.Generic;
using NodeEditorFramework;

Expand All @@ -13,24 +14,35 @@ public class NodeEditorState : ScriptableObject
public bool drawing = true; // whether to draw the canvas

// Selection State
public Node focusedNode; // Node under mouse
public Node selectedNode; // selected Node
[NonSerialized]
public Node focusedNode; // Node under mouse

// Current Action
[NonSerialized]
public bool dragNode = false;
[NonSerialized]
public Node makeTransition; // make transition from node
[NonSerialized]
public NodeOutput connectOutput; // connection this output

// Navigation State
public bool navigate = false; // navigation ('N')
public bool panWindow = false; // window panning
public Vector2 panOffset = new Vector2 (); // pan offset
public float zoom = 1; // zoom; Ranges in 0.2er-steps from 0.6-2.0; applied 1/zoom;

// Temporary State variables
// Temporary Navigation State
[NonSerialized]
public bool navigate = false; // navigation ('N')
[NonSerialized]
public bool panWindow = false; // window panning

// Temporary State
[NonSerialized]
public Rect canvasRect; // canvas Rect
public Vector2 zoomPos { get { return canvasRect.size/2; } } // zoom center in canvas space
[NonSerialized]
public Vector2 zoomPanAdjust; // calculated value to offset elements with when zooming
[NonSerialized]
public List<Rect> ignoreInput = new List<Rect> (); // Rects inside the canvas to ignore input in (nested canvases, fE)
}
}
Loading

0 comments on commit e32476e

Please sign in to comment.