Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by Octopoid · Jul 09, 2016 at 11:23 AM · c#serializationscriptableobjectmonobehaviour

ScriptableObject stored in MonoBehaviour lost on quit

This comes from a large complicated project, so I have tried to prepare a shorter code example. However, the provided example works correctly. I've been back and forward over it, and I can't see how it differs, so I'm really just looking for any possible causes of the problem:

  • A field holding an array of ScriptableObject fails to retain data when you quit and reload Unity.


I have an array of ScriptableObject held on a MonoBehaviour. In certain circumstances these are also saved into the AssetDatabase, hence the use of ScriptableObject. For this problem, they are not saved to the database.

A custom editor allows you to create new instances, and edit the data on each item. This works fine, and when you run the game the data is not lost. The data is only lost when you quit and reload Unity.

There is a lot other data held on and under the MonoBehaviour which does not suffer from this problem. However this is the only data which extends from ScriptableObject. What's confusing me mostly is the field holding the array itself seems to be lost rather than the individual items - on load the array is completely empty, rather than being full of null.

The following code I wrote in an attempt to isolate the problem - this should reflect what the main code is doing exactly, but frustratingly this works exactly as expected.


Test001.cs

 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 
 public class Test001 : MonoBehaviour
 {
     [SerializeField]
     private Test001Item[] items;
 
     public IEnumerable<Test001Item> Items
     {
         get
         {
             if (this.items == null) { this.items = new Test001Item[0]; }
             return this.items;
         }
     }
 
     public Test001Item AddItem()
     {
         Test001Item item = ScriptableObject.CreateInstance<Test001Item>();
 
         List<Test001Item> items = this.Items.ToList();
         items.Add(item);
         this.items = items.ToArray();
 
         return item;
     }
 }

Test001Item.cs

 using System;
 using UnityEngine;
 
 [Serializable]
 public class Test001Item : ScriptableObject
 {
     [SerializeField]
     private string data;
 
     public string Data { get { return this.data; } set { this.data = value; } }
 }

Editor/Test001Editor.cs

 using UnityEditor;
 using UnityEngine;
 
 [CustomEditor(typeof(Test001))]
 public class Test001Editor : Editor
 {
     public static void DrawInspector(Test001 test)
     {
         GUI.changed = false;
 
         if (GUILayout.Button("Add")) { test.AddItem(); }
 
         foreach (Test001Item item in test.Items)
         {
             Test001ItemEditor.DrawInspector(item);
         }
 
         if (GUI.changed) { Test001Editor.SaveData(test); }
     }
 
     public override void OnInspectorGUI()
     {
         Test001 test = (Test001)this.target;
         Test001Editor.DrawInspector(test);
     }
 
     private static void SaveData(Test001 test)
     {
         EditorUtility.SetDirty(test);
         foreach (Test001Item item in test.Items)
         {
             EditorUtility.SetDirty(item);
         }
     }
 }

Editor/Test001ItemEditor.cs

 [CustomEditor(typeof(Test001Item))]
 public class Test001ItemEditor : Editor
 {
     public static void DrawInspector(Test001Item item)
     {
         item.Data = EditorGUILayout.TextField(item.Data);
     }
 }


As I say, this does not recreate this issue, but I can't see what the difference is between this and my main code. As such I'm just looking for any possible causes of the problem.

  • Does anyone have any ideas as to why an array of ScriptableObjects would be lost on quit only?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Jul 09, 2016 at 11:59 AM

ScriptableObjects always have to be serialized on their own as asset if you want it to persist. There's no way around using AssetDatabase and store it somewhere as asset. If you want the Item class to be serialized along with the MonoBehaviour you can't derive it from ScriptableObject.

ScriptableObject represent assets and therefore if another serialized object (such as a MonoBehaviour) as a reference to a ScriptableObject, only the assetID will be saved as assetreference, just like one MonoBehaviour references another. Each standalone asset need to be stored somewhere in the project if you want it to persist.

If you use the CreateAssetMenu attribute the user can create an asset of that scriptable object via the create asset menu, If you want to create the instances manually in a custom inspector / EditorWindow you have to care about that yourself. So you have to use the AssetDatabase class to either save it as standalone asset or add it to an existing asset.

edit
Yes, you're partly right ^^. It seems Unity does serialize ScriptableObject instances into the scene (actually as MonoBehaviour without a gameobject parent). However the way you try to save your changes is wrong. SetDirty doesn't work for scene objects as you can read in the documentation. You should read it carefully.

If you implement a manual custom inspector like you did you might want to use EditorSceneManager.MarkSceneDirty or Undo.RecordObject which both would mark the scene as dirty.

It's usually the best to use Undo.RecordObject like this:

 if (GUILayout.Button("Add"))
 {
     Undo.RecordObject(test, "Added new Item");
     test.AddItem();
 }

This should work. "Undo.RecordObject" has to be called before you apply any changes. Unity does compare the state of the object at the end of the inspector call with the recorded state. It also adds the object to the undo stack.

You might also want to use Undo.RegisterCreatedObjectUndo for the newly instantiated ScriptableObject.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Octopoid · Jul 09, 2016 at 12:14 PM 0
Share

Hm, to be honest I really thought that wasn't the case - it was under the impression that any ScriptableObject referenced by a $$anonymous$$onoBehaviour that wasn't saved into the database was saved to the scene ins$$anonymous$$d.

The example code I posted for example allows me to add non-database ScriptableObjects to the $$anonymous$$onoBehaviour, save the scene, quit and reload, and they all persist. This blog post also suggests that's the case.

I can probably refactor it so it requires all data to be saved to assets, but I'd much prefer to work out why this is working in one place and not another - Unities serialization is not good for my blood pressure :P

avatar image Octopoid · Jul 09, 2016 at 02:02 PM 0
Share

Just found this thread where one of the Play$$anonymous$$aker developers was suffering from a similar problem - in his case everything saved correctly as in the example here, but when the GameObject holding the $$anonymous$$onoBehaviour was added to a prefab the array of ScriptableObject was lost.

It certainly looks like whatever support there is for saving them into the scene is sketchy at best. I think I'll just refactor my system to require all inner assets to be saved to the database.

Thanks for your help

avatar image Bunny83 Octopoid · Jul 09, 2016 at 04:56 PM 1
Share

I've edited my answer.

The thread of the Play$$anonymous$$aker developers is way too old now. A lot has changed in Unity. Unity's way how prefabs and prefab instances work has changed completely.

In the past a prefab instance was a normal gameobject but has a reference to the prefab it was created from. Now a prefab instance in the scene doesn't contain the actual gameobjects / components / ... but only a reference to the prefab asset as well as a list of modifications.

avatar image Octopoid Bunny83 · Jul 09, 2016 at 10:49 PM 0
Share

That's amazing, thank you. That makes perfect sense to me, the objects themselves can serialize and deserialize hence nothing is lost when switching to play mode - that was the bit that was throwing me, normally when I get these problems it's play mode that causes the data to be lost. Then the editor doesn't know it needs to update the scene unless you flag it as such hence nothing retained on quit.

In my particular case most instances are only used once. Saving all the one offs as named files was getting really messy. This way I can keep the one offs in the scene, and provide a button to export them and make them reusable.

Woah, it must have been a while since I read the SetDirty documentation. Planned to be deprecated I see!

$$anonymous$$any thanks again for your help. :)

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

173 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Add lines to a script from another script 0 Answers

pass child class to ScriptableObject.CreateInstance<> ? 1 Answer

Custom assets give Missing (Mono Script) 0 Answers

How to serialize a concrete derived class from generic ScriptableObject base 1 Answer

Serialize a list of scriptable objects to Json 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges