When I create a Dialogue SO this error pops up in the console: [Worker1] Broken text PPtr in file(Assets/SO/New Dialogue.asset). Local file identifier (3681784713337156196) doesn’t exist!
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
Code:
namespace Dialogue
{
public class DialogueNode : ScriptableObject
{
public string text;
public List<string> children = new List<string>();
public Rect rect = new Rect(0,0, 200, 100);
}
}
namespace Dialogue
{
[CreateAssetMenu(fileName = "New Dialogue", menuName = "Dialogue", order = 0)]
public class Dialogue : ScriptableObject, ISerializationCallbackReceiver
{
[SerializeField]
List<DialogueNode> nodes = new List<DialogueNode>();
Dictionary<string, DialogueNode> nodeLookup = new Dictionary<string, DialogueNode>();
#if UNITY_EDITOR
private void Awake()
{
}
#endif
private void OnValidate()
{
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.name = Guid.NewGuid().ToString();
Undo.RegisterCreatedObjectUndo(newNode, "Created Dialogue Node");
if (parent != null)
{
parent.children.Add(newNode.name);
}
nodes.Add(newNode);
OnValidate();
}
public void DeleteNode(DialogueNode nodeToDelete)
{
nodes.Remove(nodeToDelete);
Undo.DestroyObjectImmediate(nodeToDelete);
OnValidate();
CleanDanglingChildren(nodeToDelete);
}
private void CleanDanglingChildren(DialogueNode nodeToDelete)
{
foreach (DialogueNode node in GetAllNodes())
{
node.children.Remove(nodeToDelete.name);
}
}
public void OnBeforeSerialize()
{
if (nodes.Count == 0)
{
CreateNode(null);
}
if (AssetDatabase.GetAssetPath(this) != "")
{
foreach (DialogueNode node in GetAllNodes())
{
if (AssetDatabase.GetAssetPath(node) == "")
{
AssetDatabase.AddObjectToAsset(node, this);
}
}
}
}
public void OnAfterDeserialize()
{
}
}
}
namespace 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; // cast to check if Dialogue
if(dialogue !=null)
{
ShowEditorWindow();
return true;
}
return false;
}
private void OnEnable()
{
Selection.selectionChanged += OnSelectionChanged; // event
}
private GUIStyle SetNodeGUIStyle()
{
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);
return nodeStyle;
}
private void OnSelectionChanged()
{
Dialogue newDialogue = Selection.activeObject as Dialogue;
if(newDialogue !=null)
{
selectedDialogue = newDialogue;
Repaint(); // updates UI
}
}
private void OnGUI()
{
if (selectedDialogue.GetAllNodes().FirstOrDefault() == null)
{
selectedDialogue.CreateNode(null);
}
else
{
ProcessEvents();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
Rect canvas = GUILayoutUtility.GetRect(canvasSize, canvasSize);
Texture2D backgroundTexture = Resources.Load("background") as Texture2D;
Rect textureCoordinates = new Rect(0, 0, canvasSize / backgroundSize, canvasSize / backgroundSize);
GUI.DrawTextureWithTexCoords(canvas, backgroundTexture, textureCoordinates);
foreach (DialogueNode node in selectedDialogue.GetAllNodes()) // loop through Getter's nodes text
{
DrawConnections(node);
}
foreach (DialogueNode node in selectedDialogue.GetAllNodes()) // loop through Getter's nodes text
{
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 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.blue, null, 5f);
}
}
private void ProcessEvents()
{
if (Event.current.type == EventType.MouseDown && draggingNode == null) // start dragging even
{
draggingNode = GetNodeAtPoint(Event.current.mousePosition + scrollPosition);
if (draggingNode != null)
{
draggingOffset = draggingNode.rect.position - Event.current.mousePosition;
Selection.activeObject = draggingNode;
}
else
{
draggingCanvas = true;
draggingCanvasOffset = Event.current.mousePosition + scrollPosition;
Selection.activeObject = selectedDialogue;
}
}
else if (Event.current.type == EventType.MouseDrag && draggingNode != null)// dragging ongoing
{
Undo.RecordObject(selectedDialogue, "Move Dialogue Node"); // set editor dirty
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) // finish dragging
{
draggingNode = null;
}
else if (Event.current.type == EventType.MouseUp && draggingCanvas)
{
draggingCanvas = false;
}
}
private void DrawNode(DialogueNode node)
{
GUILayout.BeginArea(node.rect, SetNodeGUIStyle());
EditorGUI.BeginChangeCheck(); // start check if any changes have been made to the dialogue data
string newText = EditorGUILayout.TextField(node.text);
if (EditorGUI.EndChangeCheck()) // end check if any changes have been made to the dialogue data
{
Undo.RecordObject(selectedDialogue, "Update Dialogue Text");
node.text = newText;
}
GUILayout.BeginHorizontal();
Color defaultGUIColor = GUI.backgroundColor;
GUI.backgroundColor = Color.green;
if (GUILayout.Button("Add"))
{
creatingNode = node;
}
DrawLinkButtons(node);
GUI.backgroundColor = Color.red;
if (GUILayout.Button("Remove"))
{
deletingNode = node;
}
GUI.backgroundColor = defaultGUIColor;
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
private void DrawLinkButtons(DialogueNode node)
{
GUI.backgroundColor = Color.yellow;
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.name))
{
if (GUILayout.Button("UnLink"))
{
Undo.RecordObject(selectedDialogue, "Remove Dialogue Link");
linkingParentNode.children.Remove(node.name);
linkingParentNode = null;
}
}
else
{
if (GUILayout.Button("Link Child"))
{
Undo.RecordObject(selectedDialogue, "Add Dialogue Link");
linkingParentNode.children.Add(node.name);
linkingParentNode = null;
}
}
}
private DialogueNode GetNodeAtPoint(Vector2 point)
{
DialogueNode foundNode = null;
foreach(DialogueNode node in selectedDialogue.GetAllNodes())
{
if(node.rect.Contains(point))
{
foundNode = node;
}
}
return foundNode;
}
}
}