Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Custom editor data not persisting (using [Serializable] and [SerializeField])

Discussion in 'Scripting' started by Powdered_sugar, Jul 3, 2014.

  1. Powdered_sugar

    Powdered_sugar

    Joined:
    Aug 23, 2012
    Posts:
    64
    Hello all, I'm having a bit of trouble. I'm creating a custom editor and, while I've gotten the data to persist when playing/stopping the scene, I now need the data to persist if I close and reopen the editor window

    I'm using the tutorials / examples found here:
    (Serialization in-depth with Tim Cooper)
    http://forum.unity3d.com/threads/serialization-best-practices-megapost.155352/ (Associated forum post)
    https://twitter.com/stramit/statuses/336822645414850560 (Example files)

    Here is my code:

    Window Creation:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class MOManagerWindow : EditorWindow
    6. {
    7.  
    8.     [SerializeField]
    9.     private MOManager manager;
    10.  
    11.     [MenuItem("foo/MOManager")]
    12.     static void init (){
    13.         EditorWindow.GetWindow(typeof(MOManagerWindow));
    14.     }
    15.  
    16.     void OnEnable (){
    17.         if (manager == null) {
    18.             manager = CreateInstance<MOManager>();
    19.         }
    20.     }
    21.  
    22.     void OnGUI(){
    23.         GUILayout.Label("Material Options Manager", EditorStyles.boldLabel);
    24.         manager.OnGui();
    25.     }
    26. }
    Manager:
    Code (CSharp):
    1. using System;
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7. /**
    8. * This is the material option manager, it will handle the creation, deletion and storing
    9. * of Material Options in the editor
    10. * */
    11.  
    12. [System.Serializable]
    13. public class MOSingleOption
    14. {
    15.     [SerializeField]
    16.     private string optionName = "New Option";
    17.  
    18.     public void OnGUI(){
    19.         optionName = GUILayout.TextField(optionName, GUILayout.Width(150));
    20.     }
    21. }
    22.  
    23. [Serializable]
    24. public class MOManager : ScriptableObject
    25. {
    26.  
    27.     [SerializeField]
    28.     private List<MOSingleOption> singleOptions;
    29.  
    30.     public void OnEnable ()
    31.     {
    32.         if (singleOptions == null) {
    33.             singleOptions = new List<MOSingleOption> ();
    34.         }
    35.  
    36.         hideFlags = HideFlags.HideAndDontSave;
    37.     }
    38.  
    39.     public void OnGui ()
    40.     {
    41.         foreach (MOSingleOption obj in singleOptions) {
    42.             obj.OnGUI();
    43.             EditorGUILayout.Space();
    44.         }
    45.  
    46.         if (GUILayout.Button ("Add")) {
    47.             singleOptions.Add (new MOSingleOption ());
    48.         }
    49.     }
    50. }
    Every time I close and re-open the window it treats manager as null.

    Thanks for any help you can give me, this has been giving me a massive headache, yet I'm sure it's something minuscule and simple that I've missed.
     
    Last edited: Jul 3, 2014
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    When you close a window, the "Window" object is destroyed. Don't forget you can actually open multiple instance of the same window.

    I would probably put that variable as static.
     
  3. Powdered_sugar

    Powdered_sugar

    Joined:
    Aug 23, 2012
    Posts:
    64
    I didn't think that Unity would serialize statics.

    EDIT: Well, I just tried it, and apparently I was mistaken in that belief. Thank you ^^
     
  4. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    Unity does not serialize static, but serialization is not what you are after in this case.
     
  5. Powdered_sugar

    Powdered_sugar

    Joined:
    Aug 23, 2012
    Posts:
    64
    Hmmm.. well, it was working, but now I'm back to it not working.... This time, it saves through the window being closed and reopened, but not through a play/stop iteration... '-_-

    The Editor Window:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. [System.Serializable]
    6. public class MOManagerWindow : EditorWindow
    7. {
    8.     [SerializeField]
    9.     static MOManagerWindow window;
    10.  
    11.     [SerializeField]
    12.     private static MOManager manager;
    13.  
    14.     [MenuItem("foo/Material Options Manager")]
    15.     static void init (){
    16.         window = (MOManagerWindow)EditorWindow.GetWindow(typeof(MOManagerWindow));
    17.     }
    18.  
    19.     void OnEnable (){
    20.         if (manager == null) {
    21.             manager = CreateInstance<MOManager>();
    22.         }
    23.     }
    24.  
    25.     void OnGUI(){
    26.         GUILayout.Label("Material Options Manager", EditorStyles.boldLabel);
    27.         manager.OnGui();
    28.     }
    29. }
    The Manager:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. /**
    7. * This is the material option manager, it will handle the creation, deletion and storing
    8. * of Material Options in the editor
    9. * */
    10.  
    11. [System.Serializable]
    12. public class MOManager : ScriptableObject
    13. {
    14.  
    15.     //Lists of hte single and group options
    16.     [SerializeField]
    17.     private List<MOSingleOption> singleOptions;
    18.     [SerializeField]
    19.     private List<MOGroupOption> groupOptions;
    20.  
    21.     //Foldouts for the single and group options
    22.     [SerializeField]
    23.     private bool foldS;
    24.     [SerializeField]
    25.     private bool foldG;
    26.  
    27.     //The foldout handlers for the individual options have been moved into the option
    28.     //class for easier modification and storage.
    29.  
    30.     public void OnEnable ()
    31.     {
    32.         if (singleOptions == null) {
    33.             singleOptions = new List<MOSingleOption> ();
    34.         }
    35.  
    36.         hideFlags = HideFlags.HideAndDontSave;
    37.     }
    38.  
    39.     public void OnGui ()
    40.     {
    41.         //Draw the Single-Object Options:
    42.         foldS = EditorGUILayout.Foldout(foldS, "Single Object Options: "
    43.                                         + singleOptions.Count.ToString());
    44.  
    45.         //Call each option's draw command
    46.         if(foldS){
    47.             EditorGUI.indentLevel++;
    48.  
    49.             foreach (MOSingleOption obj in singleOptions) {
    50.                 obj.OnGUI();
    51.             }
    52.  
    53.             EditorGUI.indentLevel--;
    54.  
    55.             if (GUILayout.Button ("Add", GUILayout.Width(175))) {
    56.                 singleOptions.Add (new MOSingleOption ());
    57.             }
    58.         }
    59.     }
    60. }
    The Object:
    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. [System.Serializable]
    6. public class MOSingleOption : ScriptableObject{
    7.  
    8.     //Define and access the option's name
    9.     [SerializeField]
    10.     private string oName = "New Option";
    11.     public string optionName{get{return oName;} set{oName = value;}}
    12.  
    13.     //Define and access the option's fold state
    14.     [SerializeField]
    15.     private bool fold = true;
    16.     public bool isOpen{get{return fold;} set{fold = value;}}
    17.  
    18.     //Define the option's GameObject.  This is not modifiable after creation
    19.  
    20.     public void OnGUI(){
    21.  
    22.         GUILayout.BeginHorizontal();
    23.         isOpen = EditorGUILayout.Foldout(isOpen, optionName);
    24.         GUILayout.EndHorizontal();
    25.  
    26.         if(isOpen){
    27.             EditorGUI.indentLevel+=2;
    28.  
    29.             GUILayout.BeginHorizontal();
    30.             EditorGUILayout.LabelField("Name:", GUILayout.MaxWidth(100));
    31.             optionName = EditorGUILayout.TextField(optionName, GUILayout.Width(150));
    32.             GUILayout.EndHorizontal();
    33.  
    34.         }
    35.     }
    36. }
     
  6. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    Well, only thing I can imagine you would need to survive both a context reload AND a window being destroyed is to actually save your data in a file - ScriptableObject - and retrieve it when the window is opened.
     
  7. Powdered_sugar

    Powdered_sugar

    Joined:
    Aug 23, 2012
    Posts:
    64
    I thought that was what I was doing '-_-

    Both the manager and object inherit ScriptableObject, is there something else I have to do to make them save as scriptable objects?
     
  8. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    Use http://docs.unity3d.com/ScriptReference/AssetDatabase.html to save it to disk and reload it. Also know a ScriptableObject cannot target another unless it is also saved to disk. I'm pretty sure MOSingleOption should not derive from ScriptableObject, unless you plan to save them individually on disk.
     
  9. Powdered_sugar

    Powdered_sugar

    Joined:
    Aug 23, 2012
    Posts:
    64
    Alright, thanks for the help! It's odd, I've built several other similar systems and never run into a problem like this >_> Usually [Serializable] and [SerializeField] field have been enough. Oh well, here's hoping to be able to solve it!