Search Unity

Custom Editor Variables not saving

Discussion in 'Scripting' started by roger0, Jan 20, 2018.

  1. roger0

    roger0

    Joined:
    Feb 3, 2012
    Posts:
    1,195
    I am creating a custom editor. Variables do not seem to save when entering play mode or when recompiling scripts. The unity documentation is very unclear and solutions on the web have been pointing in many directions. Can someone please give us a simple and up to date answer on how to save custom editor variables?
     
  2. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    To be clear, do you mean variables specifically in the custom editor (fields in the class that extends Editor), or variables in the object being edited? In the former case, you can use EditorPrefs if you absolutely need a value to persist between sessions, though I've never seen a situation where that's necessary in a custom editor. The editor object is created when it's being displayed, and destroyed when it's not, so data persistence needs to store the values elsewhere. Even static values wouldn't persist beyond the session. EditorPrefs are easy, but you can make your own ScriptableObject to serve the purpose as well if that doesn't appeal to you.

    In the latter case, you need to actually write the changes back to the serialized object- use EditorGUI.BeginChangeCheck(), then do your property fields, then EditorGUI.EndChangeCheck() and serializedObject.ApplyModifiedProperties() if anything was changed. ApplyModifiedProperties is what actually writes the changes back to the serialized object.
     
    DevPikachu and tatisgordon like this.
  3. roger0

    roger0

    Joined:
    Feb 3, 2012
    Posts:
    1,195
    I just want variables in a custom editor to keep their value when they are being edited when not in play mode. Just like how unity handles it with no custom editor.

    Could you give an example how to save one float variable in a script using a custom editor?
     
  4. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    You don't have to save it, you just assign it in your OnInspectorGUI nethod
    Code (CSharp):
    1.  
    2.     [CustomEditor(typeof(Snapper))]
    3.     public class SnapperEditor : UnityEditor.Editor
    4.     {
    5.         public override void OnInspectorGUI()
    6.         {
    7.             var snapper = (Snapper)target;
    8.             snapper.Offset = EditorGUILayout.FloatField("Offset", snapper.Offset);
    9.         }
    10.     }
    11.  
    12.     public class Snapper : MonoBehaviour
    13.     {
    14.         public float Offset;
    15.     }
    16.  
    Better post your MonoBehaviour and your Editor scrips and we will try to fix it.
     
    Last edited: Jan 20, 2018
  5. roger0

    roger0

    Joined:
    Feb 3, 2012
    Posts:
    1,195
    To think its that simple, but everyone cant find a straight answer. Thanks.

    Although the variable doesn't save when opening a new scene. How do I do that?
     
  6. roger0

    roger0

    Joined:
    Feb 3, 2012
    Posts:
    1,195
    The variable also doesn't save when opening and closing Unity. There must be a couple more steps to do.
     
  7. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    To save scene values permanently you must actually save that scene by clicking menu item File/Save Scenes in Unity Editor.
     
  8. roger0

    roger0

    Joined:
    Feb 3, 2012
    Posts:
    1,195
    I went file/save scenes but it doesn't save. It will only save if I change something else in the scene besides the variable. It wont save if I only change the variable from the inspector. Also if I have the script on a prefab, it wont save when opening and closing Unity.
     
    Last edited: Jan 20, 2018
  9. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    Sorry, I underestimated your question and gave you the code taken from wrong script. Please try this:
    Code (CSharp):
    1. using UnityEditor;
    2.  
    3. [CustomEditor(typeof(Snapper))]
    4. public class SnapperEditor : Editor
    5. {
    6.     public override void OnInspectorGUI()
    7.     {
    8.         var offsetProperty = serializedObject.FindProperty("Offset");
    9.         EditorGUILayout.PropertyField(offsetProperty);
    10.         serializedObject.ApplyModifiedProperties();
    11.     }
    12. }
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Snapper : MonoBehaviour
    4. {
    5.     public float Offset;
    6. }
     
    Alekxss, mhgamework and Oni07R like this.
  10. roger0

    roger0

    Joined:
    Feb 3, 2012
    Posts:
    1,195
    It seems to be permanently saving the the variables now. Thanks alot! There is tons of confusion on how to save variables for custom editors. This thread should be pinned so people can see the clearest solution.
     
  11. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    You are welcome!
     
  12. unity_bpzBq2nO6N3HGQ

    unity_bpzBq2nO6N3HGQ

    Joined:
    Oct 4, 2018
    Posts:
    3
    I've got similar issue, but i've tried generate unique ID for mapObject when adding it on scene. The ids have been generated correctly and i can see it in inspector (but not bold text style in the textfield, thats important), but in playmode all the ids reset to 0.
    In fact the only way that works is declare new SerializedObject, get it's property by FindProperty("mapObjectId"), change this property value (.intValue) and call ApplyModifiedProperties() method. And you really don't need the :Editor class with custom Editor at all.
    Code (CSharp):
    1. var serializedObject = new SerializedObject(GetComponent<MapObjectController>());
    2.       var property = serializedObject.FindProperty("mapObjectId");
    3.       property.intValue = generatedId;
    4.       serializedObject.ApplyModifiedProperties();
     
  13. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    859
    How/where did you get generatedId?
     
  14. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    974
    Try adding this line to the end of OnInspectorGui or OnGui depending on the type of editor window you are working on
    Code (CSharp):
    1. EditorUtility.SetDirty(serializedObject)
     
  15. rahulgameOn

    rahulgameOn

    Joined:
    Oct 17, 2016
    Posts:
    2
    Take a look at this link - https://docs.unity3d.com/2017.3/Documentation/ScriptReference/EditorGUI.BeginChangeCheck.html

    For any GUI Changes, you can force the unity editor to mark itself unsaved so that user needs to save it proceeding to any other scene.
    It's somewhat similar to how normally Unity Works without the custom-editor.

    Code (CSharp):
    1. EditorGUI.BeginChangeCheck ();
    2.  
    3. // Block of code with controls
    4. // that may set GUI.changed to true.
    5.  
    6. if (EditorGUI.EndChangeCheck ()) {
    7.     // This code will unsave the current scene if there's any change in the editor GUI.
    8.     // Hence user would forcefully need to save the scene before changing scene
    9.     EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
    10. }
     
    ZhengzhongSun likes this.
  16. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,593
    This still won't achieve anything if the actual variables (or objects containing them) haven't been marked as changed by the system.

    There are a number of different ways that data in custom editors needs to be persisted, depending on the exact situation (to be honest, I think the whole thing is a bit messy currently).

    The things you need to look at are: Using Serialized Properties (along with the Update and ApplyModifiedProperties methods).

    Or using the Undo system if you are working with the target fields directly. (Undo.RecordObject, Undo.RegisterCompleteObjectUndo etc.)

    Another thing to watch out for is that if the scene object is a prefab instance you also need to call PrefabUtility.RecordPrefabInstancePropertyModifications() after you've made the changes.

    Lastly if you are changing values in the actual prefab itself (in the project window) you'll need to call EditorUtility.SetDirty() on the object.

    I've found that using the above methods where appropriate covers all instances where changes need to be persisted by a custom editor.
     
    Last edited: Dec 16, 2020
  17. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    874
    If none of these above solutions work, (I expect). Try this:

    Code (CSharp):
    1. // Create a script MyClass.cs
    2.  
    3. using UnityEngine;
    4. public class MyClass : MonoBehaviour
    5. {
    6.     // Changes in the Inspector editor should be persistent!
    7.     public float Option1;
    8. }
    9.  
    10.  
    11.  
    12.  
    13. // Create a script in a folder /Editor/MyClassEditor.cs
    14.  
    15. using UnityEditor;
    16.  
    17. [CustomEditor(typeof(MyClass), true)]
    18. public class MyClassEditor : Editor {
    19.  
    20.    // Create a reference to the MyClass script
    21.    MyClass MyClass;
    22.  
    23.    public override void OnInspectorGUI()
    24.    {
    25.        EditorGUI.BeginChangeCheck();
    26.  
    27.        // Make sure we can access the MyClass public variables at any time
    28.        if (MyClass == default) MyClass = (MyClass)target;
    29.  
    30.        // Pass the variable from the editor script into MyClass.
    31.        MyClass.Option1 = EditorGUILayout.Slider("Option1 float Value :", MyClass.Option1, 0, 1);
    32.  
    33.        // Any change sets the serialized properties of MyClass dirty.
    34.        // CTRL+S [Save Scene] will make your changes persistent!
    35.        if (EditorGUI.EndChangeCheck())
    36.        {
    37.            EditorUtility.SetDirty(MyClass);
    38.        }
    39.    }
    40. }
    41.  
    Attach the script MyClass to any game object. Set Option1 in the inspector to any value. Save and exit and restart Unity. The last value of Option1 was successfully saved.
     
    Last edited: Oct 24, 2021
unityunity