- Home /
Saving UnityEngine.Object into ScriptableObject
Hello there, so I've been dealing with ScriptableObject's and saving/loading them as assets for a while. I am able to achieve the saving/loading with a current structure like this:
Class A, Monobehaviour, uses Class B for data usage. ( just like using structs, ClassA holds a list of Class B and reaches the data inside in at runtime )
When I want to save the settings of ClassA, I this this ScriptableObjectA, which also holds a list of Class B, so I save the Class A's current list, into ScriptableObjectA, and save the ScriptableObjectA as an asset. When I want to load saved data, I simple load the asset, and switch the lists. ( ClassA data list = loaded asset data list, which was also saved before by class A)
So I have my structure like this, saving & loading is not done at runtime, I use Custom Editor for Class A and deal with saving / loading through buttons. So far so good, working as expected, both in Play Mode and Unity Exit/Re-Open. (ofcourse using Utilities like SetDirty for it to work, but these are minor details.)
Since ScriptableObjectA holds a list of ClassB inside, it knows what it's going to store inside, so no problem. My problem comes at this point, now I do want to create a Save/Load system for the SCRIPT VARIABLES AND VALUES. Simply, I want to save the values of the monobehaviour into an asset, and when I create another instance of the same monobehaviour, instead of manually writing all values again or using copy component/paste component values, I want to select the asset from the project, press load, and load the previously saved values. I've dealt with it, but could not achieve serializing object, I need a guidence somehow. Here is the current flow:
Assume we have an asset of ScriptableObjectA. Inside that ScriptableObjectA, we have a List of string, and a list of UnityEngine.Object. String list holds the names of the fields on the Monobehaviour ClassA, and object list holds the values of the corresponding keys. (Since variables can be float, integer, LayerMask, Custom Enumerations, other lists, it has to be generic, so it is Object.)
With a same kind of Save/Load logic, when I want to save the variables of the ClassA, I press my button, the script iterates through all the FieldInfo that the script has(ofcourse I check the flags, disposing unnecessary ones) and puts the names of all the fields into the list of ScriptableObjectA, at the same time, puts all the values of these fields, using field.GetValue(targetScript) into the list of objects at the ScriptableObjectA, and then saves the ScriptableObjectA as an asset.
Now when I change a variable from the inspector, and press Load, since the script loads the asset file, finds the corresponding field names from the string list, and matches the stored objects as the current field's value, the loading completes succesfully. An example:
Variable X is 5. Save the asset. Change the X as 10. Load the asset. X is set to 5.
Everything is perfect for now, but when I play the game, or exit/re-open Unity, and press Load, all the variables are set to 0. For what I've learned so far, it is because, the ScriptableObject is able to hold the names of the field via string list, because string is a serializable type by Unity. But it doesn't hold the object list, because it is not serializable. So when I play the game, or exit Unity, all the references to the objects in the ScriptableObjectA's object list, is set to null. And when I try to load the objects as values to variables, all of them becomes 0 since object's are gone.
I need to solve this problem somehow, using SerializableDictionary or some thing like that doesn't help since the object type does not seem like it's serializable itself.
I have one temporary fix, instead of saving values as objects, I can save them as strings too. And when I want to load, I can do like:
if fieldType is "System.Float" float.Parse(savedValueAsString);
but it won't be helpful, since I need to save LayerMasks, Custom Enumerations, Lists of Custom Classes and so far, I can't string-check everything and deserialize saved so-called-object manually.
So I need a guideline, a solution, to save UnityObject, into a ScriptableObject asset. Any ideas? Thanks in advance :)
Answer by paskal007r · Nov 25, 2016 at 09:29 AM
You have your solution right here:
But it doesn't hold the object list, because it is not serializable.
You cannot save stuff with this method that isn't serializable. There's no workaround here. This just isn't something that scriptableObjects can do.
What you may try is to read and write a representation of the object, for instance by using a JSON of it obtained through: https://docs.unity3d.com/ScriptReference/JsonUtility.ToJson.html
But if i use JSON, since I've mentioned, I store list of classes, i wont be able to store them i think, as a list right?
@inan-evin, Of course you'd need to write a serialization utility/function/else to translate that list into something manageable (for example: a list of strings that are in fact JSON representations of objects). You may wanto to learn about OnBeforeSerialize and OnAfterDeserialize callbacks for that. https://docs.unity3d.com/$$anonymous$$anual/script-Serialization.html