- Home /
How to store references between scriptableobject assets
I have a scriptableobject. I would like it to be able to contain a reference to another scriptableobject within it, and for this reference to be stored throughout development. Currently, the reference is being stored during an editor session, but as soon as I close and re-open unity, the reference has disappeared.
Is it not possible to serialise references to other scriptableobjects? And if it is not, is there a way that I can go about achieving the desired connection?
Here's the basic outline of the code:
[System.Serializable]
public class DialogueElement : ScriptableObject
{
[Serializefield]
public DialogueElement outputDialogue;
}
Hi,
By default a ScriptableObject should have no problem referencing other ScriptableObjects, so it must be something else. It could be that some of your code is doing something which is breaking those references in someway. Another possibility is that you are not saving properly.
Ideally when dealing with assets and editor stuff in general, you want to call something like EditorUtility.SetDirty
when you make a change, which will make sure that unity recognizes the changes made. Now I have tried to replicate what you are facing but could not reproduce what is happening, so for now just make sure you are referencing a SO and are saving correctly, otherwise we would need a bit more code to see where things could break.
Edit: do note that in 5.3 and above, EditorUtility.SetDirty
should not be used.
hmm. So when I set the reference in the inspector, there's no issue. The problem occurs when I set the reference in my custom editor that I've built around these assets. It must be something to do with how I'm setting the reference.
Thanks for the response.
Answer by bloeys · Aug 24, 2016 at 04:05 PM
Yes I agree with @Glurth, The private static list is probably the problem, but I can't confirm yet since I'm having errors of missing files with the files you provided. For now try making that one public and see what you get.
Edit: Okay so I was finally able to reproduce what was happening. Now for some reason using serialized objects and applying modified and updating doesn't work, but something else worked. Setting the individual dialogues dirty seems to work. You can loop over your dialogues each OnGUI(not really optimal) and make them dirty, or (best option) is wherever you draw the windows in your code, after each dialogue is drawn check if something on it was changed, if so make it dirty.
Another possiblity (which is also a good solution) is whenever you close the window/change scenes just loop over all the dialogues and make them dirty. This should hopefully fix your problems :)
Oh, this enum is definitely missing, sorry:
public enum NodeWindowSizes { Small, $$anonymous$$edium, Large }
Thanks for trying.
Not at all, though this is not just what is missing, I'm getting errors about these as well(there might be others as well): Dialogue$$anonymous$$ood and DialogueType
Oh, ha. I do love my enums:
public enum Dialogue$$anonymous$$ood { Happy, Sad, Normal, Shocked }
public enum DialogueType { StoryDriver, GeneralChat, Emotive }
You're a hero. SetDirty does the job. I've tried so many things, but it turns out it was that simple. You have my thanks!
You are welcome :) glad that worked! Just please mark this as the answer. All the best!
Answer by MattSawrey · Aug 24, 2016 at 03:49 PM
So, in the Unity inspector, when I create the reference between two instances of this ScriptableObject by dragging and dropping, how is that reference created? Is there some sort of ID created in the background of Unity for each ScriptableObject?
I ask because this because of my current link of thinking:
In my custom dialogue editor window, the DialogueElements are stored in a list:
private static List<DialogueElement> dialogues = new List<DialogueElement>();
Here's a method in that editor for creating a new instance of the DialogueElement (Ignore the random number bit, it's just to create a unique file name for now):
private static void CreateDialogue()
{
DialogueElement dialogueElement = DialogueElement.CreateInstance(new Rect(correctedMousePos.x, correctedMousePos.y, DialogueElement.minWidth, DialogueElement.minHeight));
//TODO - Come up with a naming convention
var randNum = Random.Range(0f, 100f);
string saveFilePath = dialogueAssetPath + sceneNameText + "/" + randNum + ".asset";
AssetDatabase.CreateAsset(dialogueElement, saveFilePath);
AssetDatabase.SaveAssets();
DialogueElement newAsset = AssetDatabase.LoadAssetAtPath<DialogueElement>(saveFilePath);
dialogues.Add(newAsset);
EditorUtility.SetDirty(window);
}
And then I have a button to call the following method to save the dialogues when I've made changes:
private void SaveSceneDialogues()
{
UpdateSceneName();
for (int i = 0; i < dialogues.Count; i++)
{
if (dialogues[i] != null)
{
//Create an asset from the current dialogue
if (!AssetDatabase.Contains(dialogues[i]))
AssetDatabase.CreateAsset(dialogues[i], dialogueAssetPath + sceneNameText + "/" + dialogues[i].windowTitle + ".asset");
else
AssetDatabase.RenameAsset(dialogueAssetPath + sceneNameText + "/" + dialogues[i].windowTitle + ".asset",
dialogues[i].windowTitle);
}
}
AssetDatabase.SaveAssets();
EditorUtility.SetDirty(window);
}
The connections are created with this method that is in the DialogueElement class when an certain event is called from the custom editor window:
public void SetOutputDialogue(DialogueElement outputDialogue, Vector2 clickPos)
{
if (outputDialogue.windowRect.Contains(clickPos))
{
this.outputDialogue = outputDialogue;
}
}
My current thinking is that these references might not be being serialized between Unity sessions because the links are created between the DialogueElements that are in the dialogues list, and not between the actual asset files that are created, even though the links do appear in the asset files that are created, they just disappear between Unity sessions.
That might be nonsense though, but I'm struggling to find information on this.
I'm including the two classes so that anyone awesome enough to help out can try the editor and see it for themselves. If you include the two scripts in a project, you should be able to recreate the issue, providing that you create the following filepath:
Assets/Resources/Dialoguelink text
Thanks in advance for any help!
Matt
$$anonymous$$ay I suggest you append this to your question as an edit, rather than as an answer?
Answer by Glurth · Aug 24, 2016 at 04:02 PM
In my custom dialogue editor window, the DialogueElements are stored in a list:
private static List dialogues = new List();
Ah, I think we were assuming this data was in a monobehvior object somewhere, and thus automatically serialized to disk. A private Editor class member is NOT going to be saved to disk.
For this situation, you may want to take a look at: https://docs.unity3d.com/ScriptReference/AssetDatabase.GUIDToAssetPath.html and https://docs.unity3d.com/ScriptReference/AssetDatabase.AssetPathToGUID.html
These are useful for manually loading and saving particular assets. You'll still need to store the list of GUID's somewhere, I would think. I'm not quite clear on whats going on with the array initialization in your code, so cannot be more specific in my suggestion.
Okay, thanks. I'll look into this and let you know how I get on.
Your answer
Follow this Question
Related Questions
[Solved]How to serialize Dictionary with Unity Serialization System 6 Answers
Difference between assigning a value in inspector and with a custom editor script 1 Answer
Referencing a ScriptableObject asset programatically 0 Answers
ScriptableObject asset loses reference after restarting Unity 1 Answer
Serializing ScriptableObject into scene without writing to asset 1 Answer