Custom Editor Variables not saving

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?

1 Like

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.

4 Likes

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?

You don’t have to save it, you just assign it in your OnInspectorGUI nethod

    [CustomEditor(typeof(Snapper))]
    public class SnapperEditor : UnityEditor.Editor
    {
        public override void OnInspectorGUI()
        {
            var snapper = (Snapper)target;
            snapper.Offset = EditorGUILayout.FloatField("Offset", snapper.Offset);
        }
    }

    public class Snapper : MonoBehaviour
    {
        public float Offset;
    }

Better post your MonoBehaviour and your Editor scrips and we will try to fix it.

3 Likes

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?

1 Like

The variable also doesn’t save when opening and closing Unity. There must be a couple more steps to do.

To save scene values permanently you must actually save that scene by clicking menu item File/Save Scenes in Unity Editor.

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.

Sorry, I underestimated your question and gave you the code taken from wrong script. Please try this:

using UnityEditor;

[CustomEditor(typeof(Snapper))]
public class SnapperEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var offsetProperty = serializedObject.FindProperty("Offset");
        EditorGUILayout.PropertyField(offsetProperty);
        serializedObject.ApplyModifiedProperties();
    }
}
using UnityEngine;

public class Snapper : MonoBehaviour
{
    public float Offset;
}
5 Likes

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.

1 Like

You are welcome!

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.

var serializedObject = new SerializedObject(GetComponent<MapObjectController>());
      var property = serializedObject.FindProperty("mapObjectId");
      property.intValue = generatedId;
      serializedObject.ApplyModifiedProperties();

How/where did you get generatedId?

Try adding this line to the end of OnInspectorGui or OnGui depending on the type of editor window you are working on

EditorUtility.SetDirty(serializedObject)
1 Like

Take a look at this link - Unity - Scripting API: EditorGUI.BeginChangeCheck

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.

EditorGUI.BeginChangeCheck ();

// Block of code with controls
// that may set GUI.changed to true.

if (EditorGUI.EndChangeCheck ()) {
    // This code will unsave the current scene if there's any change in the editor GUI. 
    // Hence user would forcefully need to save the scene before changing scene
    EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
1 Like

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.

5 Likes

If none of these above solutions work, (I expect). Try this:

// Create a script MyClass.cs

using UnityEngine;
public class MyClass : MonoBehaviour
{
    // Changes in the Inspector editor should be persistent!
    public float Option1;
}




// Create a script in a folder /Editor/MyClassEditor.cs

using UnityEditor;

[CustomEditor(typeof(MyClass), true)]
public class MyClassEditor : Editor {

   // Create a reference to the MyClass script
   MyClass MyClass;

   public override void OnInspectorGUI()
   {
       EditorGUI.BeginChangeCheck();

       // Make sure we can access the MyClass public variables at any time
       if (MyClass == default) MyClass = (MyClass)target;

       // Pass the variable from the editor script into MyClass.
       MyClass.Option1 = EditorGUILayout.Slider("Option1 float Value :", MyClass.Option1, 0, 1);

       // Any change sets the serialized properties of MyClass dirty.
       // CTRL+S [Save Scene] will make your changes persistent!
       if (EditorGUI.EndChangeCheck())
       {
           EditorUtility.SetDirty(MyClass);
       }
   }
}

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.

3 Likes

The solution from @Quatum1000 is the only one that worked even on prefabs. Unity’s documentation doesn’t show how to write a proper custom inspector, only the community has solved the problem, I can’t believe there is no mention of this at all, I am getting the impression that Unity just doesn’t care anymore about documentation…

Where do the docs go wrong? The docs for UnityEditor.Editor shows two working examples of custom inspectors: https://docs.unity3d.com/ScriptReference/Editor.html

The third example is purposely a ‘bad’ example of the generally incorrect way to write a custom inspector.

The manual on custom inspectors both IMGUI and UI Toolkit both show correct ways to build a custom inspector via the serialised property system.

I am not experience when developing for the inspector, my custom inspectors worked perfectly for non-prfabs, but no matter what I tried the values were always being reset in my custom inspectors for prefab objects whenever I saved the scene. I am not sure why but nowhere is BeginChangeCheck mentioned in that documentation. It solved the issue entirely. For years many of the objects in my assets would sometimes reset after building assetbundles and it was not obvious why, but adding BeginChangeCheck as suggested by Quantum and there’s no issue and the inspector values remain as the values I set in the scene.