- Home /
Scriptable Object save List
Hello,
I started learning how to code custom editor and i need to save the content into the asset. Saving individual object works great but the problem is that I'm not able to save List of objects. To be more clear here is the code im using (most of it taken from https://blogs.unity3d.com/2012/10/25/unity-serialization/)
MyWindow.cs
public class MyWindow : EditorWindow {
[SerializeField]
private SerializeMe m_SerialziedThing;
[MenuItem("Window/Serialization")]
static void Init() {
GetWindow(typeof(MyWindow));
}
void OnEnable() {
hideFlags = HideFlags.HideAndDontSave;
if (m_SerialziedThing == null)
m_SerialziedThing = new SerializeMe();
}
void OnGUI() {
GUILayout.Label("Serialized Things", EditorStyles.boldLabel);
m_SerialziedThing.OnGUI();
}
}
SerializeMe.cs
[Serializable]
public class SerializeMe : ScriptableObject {
[SerializeField]
private List<BaseClass> m_Instances;
[SerializeField]
private AssetFile myAssetFile;
public void OnEnable() {
hideFlags = HideFlags.HideAndDontSave;
if (m_Instances == null)
m_Instances = new List<BaseClass>();
myAssetFile = (AssetFile)AssetDatabase.LoadAssetAtPath("Assets/MyLists.asset", typeof(AssetFile));
if (!myAssetFile) {
myAssetFile = CreateInstance<AssetFile>();
AssetDatabase.CreateAsset(myAssetFile, "Assets/MyLists.asset");
}
myAssetFile.hideFlags = HideFlags.HideAndDontSave;
}
public void OnGUI() {
foreach (var instance in m_Instances)
instance.OnGUI();
if (GUILayout.Button("Add Base"))
m_Instances.Add(CreateInstance<BaseClass>());
if (GUILayout.Button("Add Child"))
m_Instances.Add(CreateInstance<ChildClass>());
if (GUILayout.Button("Save")) {
myAssetFile.mySavedList = m_Instances;
EditorUtility.SetDirty(myAssetFile);
}
}
}
AssetFile.cs
[Serializable]
public class AssetFile : ScriptableObject {
public List<BaseClass> mySavedList;
void OnEnable() {
mySavedList = new List<BaseClass>();
}
}
BaseClass.cs
[Serializable]
public class BaseClass : ScriptableObject {
[SerializeField]
private int m_IntField;
public virtual void OnGUI() {
m_IntField = EditorGUILayout.IntSlider("IntField", m_IntField, 0, 10);
}
}
ChildClass.cs
[Serializable]
public class ChildClass : BaseClass {
[SerializeField]
private float m_FloatField;
public override void OnGUI() {
m_FloatField = EditorGUILayout.Slider("FloatField", m_FloatField, 0f, 10f);
}
}
So basically to serialize List of BaseClasses or Child Classes I had to create class AsetFile to hold the list itself. Then in SerializeMe.cs im just creating BaseClass / ChildClass objects and adding them to the list. When I save them I get Type missmatch in the asset.
I have tried to convert the list to array but I get the same results. Also when I create only one object the serialization works. So there has to be problem with the list... From what I've red on the web, creating class which contains list of objects should be the way to go. But not in my case it seems. So does anybody know what could I be doing wrong?
Any help would be appreciated, Thank you.
Every ScriptableObject must exist in the filesystem, you can't simply serialize a list of them without each object in the list being its own file. The way you would put them together is with AddObjectToAsset
However, it is more than likely that your list of objects doesn't even need to be ScriptableObjects, just the main asset object.
Hello rob, I've spent a lot of time with this and I'm starting to belive that I really have to make asset for every node in my editor. Although in my editor, every node can have a different amount of properties (which is list again) so then ill end up with enormous amount of scriptable objects, which ill have to connect together anyway .. so maybe it will be better to save it to some json file. But thanks for your reply.
Well another option is you can make a custom data editor and use binary serialization. Then load the objects during runtime through the resources folder. Something like this for your editor window.
public class DataEditor : EditorWindow
{
public ObjectData objectData;
[$$anonymous$$enuItem("Tools/Data Editor")]
public static void startInformer()
{
EditorWindow window = GetWindow<DataEditor>();
window.Show();
}
void OnGUI()
{
string s = "";
if (GUILayout.Button("Choose FIle"))
{
s = EditorUtility.OpenFilePanel("Choose Data", "Assets/", ".asset");
}
if (GUILayout.Button("Create File"))
{
objectData = new ObjectData();
}
if (!string.IsNullOrEmpty(s))
{
objectData = Deserialize(s);
s = "";
}
if (objectData != null)
{
objectData.Name = EditorGUILayout.TextArea(objectData.Name);
// All your object data can be displayed and edited here.
if (GUILayout.Button("Save"))
{
if (!string.IsNullOrEmpty(objectData.Name))
{
Serialize(objectData, objectData.Name);
}
}
}
}
public ObjectData Deserialize(string filepath)
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.FileStream stream = new System.IO.FileStream(filepath, System.IO.File$$anonymous$$ode.Open);
ObjectData data = (ObjectData)formatter.Deserialize(stream);
stream.Close();
return data;
}
public void Serialize(object obj, string fileName)
{
ObjectData od = new ObjectData();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
FileStream fs = new FileStream("Assets/" + fileName + ".asset", File$$anonymous$$ode.Create);
formatter.Serialize(fs, obj);
fs.Close();
}
}
Your answer
Follow this Question
Related Questions
How to work with custom class (ScriptableObject) SerializedProperty? 1 Answer
Why aren't lists editable in ScriptableObjects? 0 Answers
Override Asset Preview Thumbnail 1 Answer
ApplyModifiedProperties returns false 0 Answers
Why is play mode reverting my scriptableobject to a previous serialized state? 2 Answers