As soon as I create a new dialogue after deleting the 4 dialogues as Sam did and adjust the scripts up until minute 7 of the tutorial.
Where might the error be coming from? A specific script? I will send pictures of it if I can first know where it might originate. Sorry I am pretty lost.
I just went into the repo of project changes and literally copied all the 3 scripts of Dialogues and still shows the same errors. This means I have something wrong inside the unity inspector? As soon as I create a Dialogue scriptable object, it pops up whenever I click wherever within the editor it disappears and the same errors keep popping.
EDIT: Using latest 2022 LTS and I would like to continue with it if possible.
There is an error starting in later versions of Unity2021 through Unity 2022 which is related to our code to create new Dialogues. This is caused by Unity using the jobs system to run parallel code in the Editor. What happens is that when you create a new Dialogue, the system creates a new node (which it’s supposed to), but since the Dialogue doesn’t have a name yet, it’s not really there, at least not from the file system’s perspective. The complicated part is when you actually give the dialogue a name (even if it’s hitting enter and calling it new Dialogue), that node is destroyed (because from the file system’s perspective, it never existed in the first place), and then a new Dialogue is actually created but it doesn’t have the node.
This has generally lead to an annoying error once, but the dialogue creating a new node on the next Editor Frame, but for some, this isn’t the case.
Try adding this to the beginning of OnValidate()
if(nodes.Count==0) CreateNode(null); //create a new node.
I added
if(nodes.Count==0) CreateNode(null);
at the beggining of OnValidate() but it did not work, showing same errors after deleting the dialogues and creating a new one. The thing is I also already had that line of code also in the Awake().
Things I tried:
-deleting whole Awake method (because I thougth it wouldnt work if that line of code was repeated twice) and copying it into the onvalidate method
-copying that line of code in both awake and onvalidate() at the start of the methods
-copying that line of code into onvalidate() at the start of the method
whatever I try it keeps showing the same errors I said. Am I inserting the line of code in the wrong spot? Do i have to delete the whole awake() and insert it in onvalidate() or what is the exact process?
private void OnValidate()
{
if(nodes.Count==0) {CreateNode(null)};
nodeLookup.Clear();
foreach (DialogueNode node in GetAllNodes())
{
nodeLookup[node.uniqueID] = node;
}
That looks correct (except the curly brace should be after the semi-colon, but I’m sure that’s just a typo.
Paste in your whole Dialogue.cs and DialogueEditor.cs scripts and I’ll take a look. Check the link below to see how to format the code in our forum system
- Forum User Guides : How to apply code formatting within your post
DialogueEditor Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Callbacks;
using UnityEditor;
using System;
namespace RPG.Dialogue.Editor
{
public class DialogueEditor : EditorWindow
{
Dialogue selectedDialogue = null;
[NonSerialized]
GUIStyle nodeStyle;
[NonSerialized]
DialogueNode draggingNode = null;
[NonSerialized]
Vector2 draggingOffset;
[NonSerialized]
DialogueNode creatingNode = null;
[NonSerialized]
DialogueNode deletingNode = null;
[NonSerialized]
DialogueNode linkingParentNode = null;
Vector2 scrollPosition;
[NonSerialized]
bool draggingCanvas = false;
[NonSerialized]
Vector2 draggingCanvasOffset;
const float canvasSize = 4000;
const float backgroundSize = 50;
[MenuItem("Window/Dialogue Editor")]
public static void ShowEditorWindow()
{
GetWindow(typeof(DialogueEditor), false, "Dialogue Editor");
}
[OnOpenAsset(1)]
public static bool OnOpenAsset(int instanceID, int line)
{
Dialogue dialogue = EditorUtility.InstanceIDToObject(instanceID) as Dialogue;
if (dialogue != null)
{
ShowEditorWindow();
return true;
}
return false;
}
void OnEnable()
{
Selection.selectionChanged += OnSelectionChanged;
nodeStyle = new GUIStyle();
nodeStyle.normal.background = EditorGUIUtility.Load("node0") as Texture2D;
nodeStyle.padding = new RectOffset(20,20,20,20);
nodeStyle.border = new RectOffset(12,12,12,12);
nodeStyle.normal.textColor = Color.white;
}
void OnSelectionChanged()
{
Dialogue newDialogue = Selection.activeObject as Dialogue;
if (newDialogue != null)
{
selectedDialogue = newDialogue;
Repaint();
}
}
void OnGUI()
{
if (selectedDialogue == null)
{
EditorGUILayout.LabelField("No Dialogue Selected");
}
else
{
ProcessEvents();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
Rect canvas = GUILayoutUtility.GetRect(canvasSize,canvasSize);
Texture2D backgroundText = Resources.Load("background") as Texture2D;
Rect textCoords = new Rect(0,0, canvasSize / backgroundSize, canvasSize / backgroundSize);
GUI.DrawTextureWithTexCoords(canvas, backgroundText, textCoords);
foreach (DialogueNode node in selectedDialogue.GetAllNodes())
{
DrawConnections(node);
}
foreach (DialogueNode node in selectedDialogue.GetAllNodes())
{
DrawNode(node);
}
EditorGUILayout.EndScrollView();
if (creatingNode !=null)
{
Undo.RecordObject(selectedDialogue, "Added Dialogue Node");
selectedDialogue.CreateNode(creatingNode);
creatingNode = null;
}
if(deletingNode !=null)
{
Undo.RecordObject(selectedDialogue, "Deleted Dialogue Node");
selectedDialogue.DeleteNode(deletingNode);
deletingNode = null;
}
}
}
private void ProcessEvents()
{
if(Event.current.type == EventType.MouseDown && draggingNode == null)
{
draggingNode = GetNodeAtPoint(Event.current.mousePosition + scrollPosition);
if (draggingNode !=null)
{
draggingOffset = draggingNode.rect.position - Event.current.mousePosition;
}
else
{
draggingCanvas = true;
draggingCanvasOffset = Event.current.mousePosition + scrollPosition;
}
}
else if(Event.current.type == EventType.MouseDrag && draggingNode !=null)
{
Undo.RecordObject(selectedDialogue, "Move Dialogue Node");
draggingNode.rect.position = Event.current.mousePosition + draggingOffset;
GUI.changed = true;
}
else if(Event.current.type == EventType.MouseDrag && draggingCanvas)
{
scrollPosition = draggingCanvasOffset - Event.current.mousePosition;
GUI.changed = true;
}
else if(Event.current.type == EventType.MouseUp && draggingNode !=null)
{
draggingNode = null;
}
else if(Event.current.type == EventType.MouseUp && draggingCanvas)
{
draggingCanvas = false;
}
}
private void DrawNode(DialogueNode node)
{
GUILayout.BeginArea(node.rect, nodeStyle);
EditorGUI.BeginChangeCheck();
string newText = EditorGUILayout.TextField(node.text);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(selectedDialogue, "Update Dialogue Text");
node.text = newText;
}
GUILayout.BeginHorizontal();
if (GUILayout.Button("+"))
{
creatingNode = node;
}
DrawLinkButtons(node);
if (GUILayout.Button("-"))
{
deletingNode = node;
}
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
private void DrawLinkButtons(DialogueNode node)
{
if (linkingParentNode == null)
{
if (GUILayout.Button("link"))
{
linkingParentNode = node;
}
}
else if (linkingParentNode == node)
{
if (GUILayout.Button("Cancel"))
{
linkingParentNode = null;
}
}
else if (linkingParentNode.children.Contains(node.uniqueID))
{
if (GUILayout.Button("Unlunk"))
{
Undo.RecordObject(selectedDialogue, "Remove Dialogue Link");
linkingParentNode.children.Remove(node.uniqueID);
linkingParentNode = null;
}
}
else {
if (GUILayout.Button("child"))
{
Undo.RecordObject(selectedDialogue, "Add Dialogue Link");
linkingParentNode.children.Add(node.uniqueID);
linkingParentNode = null;
}
}
}
private void DrawConnections(DialogueNode node)
{
Vector3 startPosition = new Vector2(node.rect.xMax, node.rect.center.y);
foreach (DialogueNode childNode in selectedDialogue.GetAllChildren(node))
{
Vector3 endPosition = new Vector2(childNode.rect.xMin, childNode.rect.center.y);
Vector3 controlPointOffset = endPosition - startPosition;
controlPointOffset.y =0;
controlPointOffset.x *= 0.8f;
Handles.DrawBezier(
startPosition, endPosition,
startPosition + controlPointOffset,
endPosition - controlPointOffset,
Color.white,null, 4f);
}
}
private DialogueNode GetNodeAtPoint(Vector2 point)
{
DialogueNode foundNode = null;
foreach(DialogueNode node in selectedDialogue.GetAllNodes())
{
if(node.rect.Contains(point)){
foundNode = node;
}
}
return foundNode;
}
}
}
Dialogue Script
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace RPG.Dialogue
{
[CreateAssetMenu(fileName = " New Dialogue", menuName = "Dialogue", order = 0)]
public class Dialogue : ScriptableObject
{
[SerializeField]
List<DialogueNode> nodes = new List<DialogueNode>();
Dictionary<string, DialogueNode> nodeLookup = new Dictionary<string, DialogueNode>();
#if UNITY_EDITOR
void Awake()
{
if(nodes.Count == 0)
{
CreateNode(null);
}
}
#endif
private void OnValidate()
{
if(nodes.Count==0) {CreateNode(null);}
// Called anytime things change in editor and on startup. Clear and rebuild dictionary by UID and DN.
//! See Awake() below for important addition to this.
nodeLookup.Clear();
foreach (DialogueNode node in GetAllNodes())
{
if(node != null) nodeLookup[node.name] = node;
}
}
public IEnumerable<DialogueNode> GetAllNodes()
{
return nodes;
}
public DialogueNode GetRootNode()
{
return nodes[0];
}
public IEnumerable<DialogueNode> GetAllChildren(DialogueNode parentNode)
{
foreach (string childID in parentNode.children)
{
if (nodeLookup.ContainsKey(childID))
{
yield return (nodeLookup[childID]);
}
}
}
public void CreateNode(DialogueNode parent)
{
DialogueNode newNode = CreateInstance<DialogueNode>();
newNode.uniqueID = Guid.NewGuid().ToString();
if(parent !=null)
{
parent.children.Add(newNode.uniqueID);
}
nodes.Add(newNode);
OnValidate();
}
public void DeleteNode(DialogueNode nodeToDelete)
{
nodes.Remove(nodeToDelete);
OnValidate();
CleanDanglingChildren(nodeToDelete);
}
private void CleanDanglingChildren(DialogueNode nodeToDelete)
{
foreach (DialogueNode node in GetAllNodes())
{
node.children.Remove(nodeToDelete.uniqueID);
}
}
}
}
This looks correct. This may be a different issue with the newer versions of Unity.
Zip up your project and upload it to https://gdev.tv/projectupload and I’ll take a look. Be sure to remove the Library folder to conserve space.
I just uploaded it thanks for the continued support
Edit: Not sure if the code is the same as the one I copied and pasted here. Im using Github for version control and i might have not saved it or something sorry (still relatively new). If its not the same could you copy and paste it into the Dialogue and DialogueEditor scripts? Im sorry I did try with the code I posted in here and the bunch of errors poped up regardless.
I’ll work on it when I get off of work.
I did port the course project to 2022.3.0f, and it seemed to work (aside from the one error, which resolves on the next frame). I’ll see what might be causing this for you.
Thank you I will wait for your input.
Interestingly enough, I wasn’t getting any errors from this, the node simply disappeared with no way to add a new one.
I made a few modifications, and it appears to be creating nodes properly now.
First, I made a couple changes in Dialogue.cs
void Awake()
{
OnValidate();
}
private void OnValidate()
{
nodeLookup.Clear();
foreach (DialogueNode node in GetAllNodes())
{
nodeLookup[node.uniqueID] = node;
}
}
No #if UNITY_EDITOR block for either of those methods. You’ll need Awake() to call OnValidate() in a built game or the Dictionary will never be built.
One more quick change in Dialogue.CreateNode()
public void CreateNode(DialogueNode parent)
{
DialogueNode newNode = new DialogueNode();
newNode.uniqueID = Guid.NewGuid().ToString();
if(parent!=null) parent.children.Add(newNode.uniqueID);
nodes.Add(newNode);
OnValidate();
}
This lets us create a node without a parent using the existing CreateNode() method by calling CreateNode(null)
Finally for the big change, in DialogueEditor.OnGUI. What I did here was first change the if(selectedDialogue==null) method to be a blocking method instead of followed by an else clause. Simply more readable. Then I added a quick bit to detect if there are no nodes and create one if there is not.
Important: You’ll need to add
using System.Linq;
to the top of your usings clause for this to work properly.
void OnGUI()
{
if (selectedDialogue == null)
{
EditorGUILayout.LabelField("No Dialogue Selected");
return;
}
if (selectedDialogue.GetAllNodes().Count() == 0)
{
Debug.Log("No Nodes found, creating new node.");
selectedDialogue.CreateNode(null);
}
ProcessEvents();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
Rect canvas = GUILayoutUtility.GetRect(canvasSize, canvasSize);
Texture2D backgroundText = Resources.Load("background") as Texture2D;
Rect textCoords = new Rect(0, 0, canvasSize / backgroundSize, canvasSize / backgroundSize);
GUI.DrawTextureWithTexCoords(canvas, backgroundText, textCoords);
foreach (DialogueNode node in selectedDialogue.GetAllNodes())
{
DrawConnections(node);
}
foreach (DialogueNode node in selectedDialogue.GetAllNodes())
{
DrawNode(node);
}
EditorGUILayout.EndScrollView();
if (creatingNode != null)
{
Undo.RecordObject(selectedDialogue, "Added Dialogue Node");
selectedDialogue.CreateNode(creatingNode);
creatingNode = null;
}
if (deletingNode != null)
{
Undo.RecordObject(selectedDialogue, "Deleted Dialogue Node");
selectedDialogue.DeleteNode(deletingNode);
deletingNode = null;
}
}
Thank you very much Brian. The problem is fixed and I can continue with the course. You were very nice and dedicated to helping me.
I’m glad I could help.
This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.