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?
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.
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.
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?
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;
}
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.
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)
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());
}
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.
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.
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.