I’m trying to make a custom window to create/edit dialogue assets as jsons. Here are the classes that get serialized:
[System.Serializable]
public class Dialogue
{
public List<Node> nodes;
public string startingNodeKey;
}
[System.Serializable]
public class Node
{
public string key
public LocalizedString localizedString;
public string nextNodeKey;
}
Unfortunately, I cant find a way to show the LocalizedString proprerty in my window AND to then use that property to update a local value, that will be then serialized into a json.
Hi,
Can you explain in more detail the problems you are having?
You want to show the property drawer for the LocalizedString?
You want to use a JSON file instead of a StringTable? This may help for that Scripting | Localization | 1.5.2
Sorry if I wasn’t too clear, I didnt post the full code since it also does a lot of other stuff that’s not relevant to the question…
(I edited the scripts in the post tho better explain what I’m doing)
What i wanted to do was creating some sort of dialogue tree. This dialogue tree is composed by different nodes, each one is identified by a key(string), contains the line of dialogue (the LocalizedString) and contains the key to next Node.
Instead of just using a bunch of ScriptableObjects (one for each node, for every dialogue in the game!) I thought of creating a custom Editor Window where i could build this dialogue “tree”, to then save it as a single .json file.
The problem is that even if i found a way to show the LocalizedString property of the nodes, i cant retrieve its value so that i can save it locally to my Dialogue’s list of nodes (before serializing them to json).
You dont need to create each node as a ScriptableObject, you could use SerializeReference instead.
The localized values are not stored in a LocalizedString, they are stored in the StringTable. The LocalizedString only stored the table and entry reference. LocalizationEditorSettings contains some API that may be useful.
Hello @karl_jones,
thanks a lot for pointing me in the right direction, I haven’t used SerializeReferece much yet so I had completely forgot how it works… I think the best and simplest way to proceed right now is to have Dialogue be a Scriptableobject and have its nodes serialized as References as suggested, possibly implementing a custom editor for Dialogue to ease setting up the Nodes.
So thanks again, I will adopt this solution!
With that being said, I still would like to know if what I originally planned to do is possible; the only differences between the two implementations would be that in this one Dialogue isn’t a ScriptableObject (inherits nothing) and instead is a class that gets Serialized into a .json file in order to be saved. Setting up the Dialogue and its nodes would have to be done through an apposite custom editor window, instead of the inspector.
While trying to archieve editing through a window, i have coded the following (for now still use a ScriptableObject dialogue for semplicity, but Dialogue should be read from/wrote to json):
[CreateAssetMenu(fileName = "New Dialogue TEST", menuName = SA.EditorUtilities.Paths.ScriptableObjects.DialogueSystem + "/Dialogue TEST")]
[System.Serializable]
public class DialogueT : ScriptableObject
{
[SerializeReference] public List<NodeT> nodes = new List<NodeT>();
public string startingNodeKey;
}
[System.Serializable]
public class NodeT
{
public string key;
public LocalizedString localizedString;
public string nextNodeKey;
}
public class WindowLocalizedStringTEst : EditorWindow
{
private DialogueT dialogue;
[MenuItem("TEST/Dialogue Tree Builder")]
public static void ShowWindow()
{
EditorWindow.GetWindow(typeof(WindowLocalizedStringTEst));
}
private void CreateGUI()
{
var objField = new ObjectField("Dialogue")
{
objectType = typeof(DialogueT),
allowSceneObjects = false
};
objField.RegisterValueChangedCallback(obj => DialogueSelection(obj));
rootVisualElement.Add(objField);
}
private void DialogueSelection(ChangeEvent<Object> evt)
{
if (evt.previousValue == evt.newValue)
return;
dialogue = (DialogueT)evt.newValue;
if (dialogue == null)
return;
rootVisualElement.Add(new Label("Recieved Dialogue Asset")); //THIS GETS ADDED TO THE WINDOW
var so = new SerializedObject(dialogue);
var sp = so.FindProperty("nodes");
var pf = new PropertyField(sp, "Node");
rootVisualElement.Add(pf);
Repaint(); //not necessary
}
}
For some reason, the object field (line 32) and the Lable (line 42) get added to the window, but the PropertyField (line 47) that should show the list of nodes of Dialogue does’t.
Am I doing something wrong?
I think you need to bind the hierarchy. Passing in the SerializedProperty into the PropertyField doesnt actually bind, it just records the propertyPath for later.
Try doing rootVisualElement.Bind(so) around line 48
It worked, thanks again!
Now to have it so that Dialogue doesn’t inherit from ScriptableObject, and instead is loaded from and saved to json, i did this:
[System.Serializable]
public class DialogueT
{
[SerializeReference] public List<NodeT> nodes = new List<NodeT>();
public string startingNodeKey;
}
[System.Serializable]
public class NodeT
{
public string key;
public LocalizedString localizedString;
public string nextNodeKey;
}
public class ScriptableObjectInstance<T> : ScriptableObject
{
public T data;
}
public class DialogueT_SOInstance : ScriptableObjectInstance<DialogueT> { }
public class WindowLocalizedStringTEst : EditorWindow
{
private DialogueT_SOInstance dialogueInstance;
[MenuItem("TEST/Dialogue Tree Builder")]
public static void ShowWindow()
{
EditorWindow.GetWindow(typeof(WindowLocalizedStringTEst));
}
private void CreateGUI()
{
dialogueInstance = ScriptableObject.CreateInstance(typeof(DialogueT_SOInstance)) as DialogueT_SOInstance;
dialogueInstance.data = LoadDialogueFromJosn();
var so = new SerializedObject(dialogueInstance);
var sp = so.FindProperty("data").FindPropertyRelative("nodes");
var pf = new PropertyField(sp, "Node");
rootVisualElement.Add(pf);
rootVisualElement.Bind(so);
}
private DialogueT LoadDialogueFromJosn()
{
var outPut = new DialogueT(); //here i should set data by deserializing a new DialogueT from the json savefile
outPut.nodes = new List<NodeT> { new NodeT(), new NodeT() }; //for testing
return outPut;
}
private void SaveDialogueToJson()
{
DialogueT toSave = (DialogueT)dialogueInstance.data;
//serialize to json
}
}
It’s a bit hacky… I have 2 new classes, ScriptableObjectInstance<T> and DialogueT_SOInstance in order to create a temporary instance of a ScriptableObject containing the data that i want to show in the window, so that I can create a SerializedObject from that instance (i cant create it directly from Dialogue anymore, it doesn’t inherit from Object).
I would have done it without DialogueT_SOInstance using directly ScriptableObjectInstance<DialogueT>, but apparently you cant instantiate ScriptableObjects classes that are Generics.