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. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

Custom Editor not saving changes

Discussion in 'Immediate Mode GUI (IMGUI)' started by afonsolfm, Aug 7, 2016.

  1. afonsolfm

    afonsolfm

    Joined:
    Jul 11, 2016
    Posts:
    11
    I have three scripts: Singleton<T>, MapManager and MapManagerEditor

    When I make changes in the *MapManager* script component, after I click to go to other scene and then come back, the values are reset!

    Here is a small example:

    Singleton
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour {
    5.  
    6.     public static T instance { get; private set; }
    7.  
    8.     protected virtual void Awake()
    9.     {
    10.         if (instance == null)
    11.             instance = this as T;
    12.         else
    13.             Destroy(gameObject);
    14.     }
    15.  
    16.     protected virtual void OnDisable()
    17.     {
    18.         instance = null;
    19.     }
    20. }
    21.  
    }

    MapManager
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. [System.Serializable]
    5. public class MapManager : Singleton<MapManager> {
    6.  
    7.     [System.NonSerialized]
    8.     public int lol = 0;
    9. }
    MapManagerEditor
    Code (CSharp):
    1. using UnityEditor;
    2. using System.Collections;
    3. using UnityEditor.SceneManagement;
    4.  
    5. [CustomEditor(typeof(MapManager))]
    6. public class MapManagerEditor : Editor
    7. {
    8.  
    9.     public override void OnInspectorGUI()
    10.     {
    11.         DrawDefaultInspector();
    12.         MapManager mapManager = (MapManager)target;
    13.  
    14.         mapManager.lol = EditorGUILayout.IntField("lol", mapManager.lol);
    15. }
    16. }
    Any idea how to fix this?
     
  2. afonsolfm

    afonsolfm

    Joined:
    Jul 11, 2016
    Posts:
    11
    Fixed the problem, for anyone who has it, here is the real solution:

    Use
    Code (CSharp):
    1. [HideInInspector]
    for every variable you want to change (it also serializes it).

    Use
    Code (CSharp):
    1. [System.Serializable]
    in every class/struct that you are using with your variables.

    Finally add this code on the bottom of OnInspectorGUI

    Code (CSharp):
    1.  
    2. if (GUI.changed)
    3.         {
    4.             EditorUtility.SetDirty(castedTarget);
    5.             EditorSceneManager.MarkSceneDirty(castedTarget.gameObject.scene);
    6.         }
     
  3. MrLucid72

    MrLucid72

    Joined:
    Jan 12, 2016
    Posts:
    887
    FINALLY! This is the 10th article I've read that finally does what it says. You rock, good sir.

    @ Unity, please update your docs on this -__-
     
  4. The_Pied_Shadow

    The_Pied_Shadow

    Joined:
    Jul 25, 2018
    Posts:
    8
    I wanted to add to this. This helped me track down my problem however, the only thing of your solutions I needed to do was add the if(GUI.changed) snippet to my OnInspectorGUI method. However I also had the variables in my class set with default accesors for example
    Code (CSharp):
    1. public float boo { get; set; }
    however I needed to remove those so it was just
    Code (CSharp):
    1. public float boo;
    for some reason they hindered the process. So with those changes alone it solved my problem in case anyone tried the above and still have the issue it may be accesors.
     
    dday1987_unity likes this.
  5. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    372
    For future generations... this is not a good way to get your editors to serialize. I struggled with custom editors for a long time too and did a bunch of hacky garbage just to get things kind of ok. But its not this much work once you know what to focus on.

    The key is to only manipulate SerializedProperties, don't ever operate on the target's data! Here's a simple example...

    Code (csharp):
    1.  
    2. public override void OnInspectorGUI()
    3. {
    4.      //do this first to make sure you have the latest version
    5.      serializedObject.Update();
    6.      
    7.      //for each property you want to draw ....
    8.      EditorGUILayout.PropertyField(serializedObject.FindProperty("boo"));
    9.  
    10.      //if you need to do something cute like use a different input type you can do this kind of thing...
    11.      SerializedProperty specialProp = serializedObject.FindProperty("myFloatThatPretendsItsAnInt");
    12.      specialProp.floatValue = EditorGUILayout.IntField(specialProp.floatValue as int) as float;
    13.  
    14.      //do this last!  it will loop over the properties on your object and apply any it needs to, no if necessary!
    15.      serializedObject.ApplyModifiedProperties();
    16. }
    17.  
    That's all you need.
     
  6. dcarnelutti

    dcarnelutti

    Joined:
    Jul 30, 2018
    Posts:
    4
    Have you tried this with a 2 dimensions array?

    I have a week looking about this and can't find anything.
     
  7. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @dcarnelutti

    Your question doesn't have much to do with topic and it is also bit of a necro post.

    I bet that because you can't serialize a 2D array in standard Inspector, you won't see it in serialized object for that class either. I think you will just see null if you try to do FindProperty("myTwoDeeArray").

    You could try to do a typical Serializable class instead that looks like two dimensional array (class with a list of arrays) and then draw that with your Custom Inspector + serializable object.
     
  8. legoblaster1234

    legoblaster1234

    Joined:
    Aug 7, 2017
    Posts:
    27

    What is "castedTarget"? You don't define it in any of your code. What should it be set to?
     
  9. SixofSwords

    SixofSwords

    Joined:
    Sep 28, 2017
    Posts:
    1
    This should be the first answer, i ran into this problem and this is the easiest/most elegant solution. if anyone runs into this, try this first.
     
    brownboot67 likes this.
  10. Mithrandir01

    Mithrandir01

    Joined:
    Jan 22, 2020
    Posts:
    2
    Last edited: Jan 29, 2021
    brownboot67 likes this.
  11. dginovker

    dginovker

    Joined:
    Sep 25, 2020
    Posts:
    8
    If anyone else is going insane because this isn't working, keep in mind that he uses PropertyField.

    Code (csharp):
    1. EditorGUILayout.PropertyField(serializedObject.FindProperty("boo"));
    For some reason, IntField or any others wouldn't work for me. If you want a label beside the input field, do it like:

    Code (csharp):
    1. EditorGUILayout.PropertyField(serializedObject.FindProperty("myInt"), new GUIContent("Set myInt: "));
     
  12. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    372
    IntField and the other type specific fields return their corresponding type. So you have to do:

    Code (csharp):
    1. myIntProp.intValue = EditorGUILayout.IntField(myIntProp.intValue);
    And you are correct there are lots of optional params for labels and styles and so on, you can read the docs if you want to sort all that out.
     
  13. rcsordas

    rcsordas

    Joined:
    May 20, 2016
    Posts:
    2
    Hey guys, I'm having some difficulty with this.
    I managed to get everything working, but after writing something in the Editor Window and hitting Enter or Tab, the value I've just tiped is erased.

    My functions for loading as saving are working fine.
    I think the problem is on the OnGUI function

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. using System.IO;
    6.  
    7. public class LocalizedTextEditor : EditorWindow
    8. {
    9.    
    10.     public LocalizationData localizationData;
    11.     Vector2 scrollPosition = Vector2.zero;
    12.  
    13.     [MenuItem("Window/Localized Text Editor")]
    14.     static void Init()
    15.     {
    16.        
    17.         EditorWindow.GetWindow(typeof(LocalizedTextEditor)).Show();
    18.     }
    19.  
    20.     private void OnGUI()
    21.     {
    22.         scrollPosition = GUILayout.BeginScrollView(scrollPosition, true, true);
    23.        
    24.        
    25.      
    26.  
    27.      
    28.         if (localizationData != null)
    29.         {
    30.  
    31.             SerializedObject serializedObject = new SerializedObject(this);
    32.             serializedObject.Update();
    33.             SerializedProperty serializedProperty = serializedObject.FindProperty("localizationData");
    34.             EditorGUILayout.PropertyField(serializedProperty);
    35.             serializedObject.ApplyModifiedProperties();
    36.  
    37.             if (GUILayout.Button("Save data"))
    38.             {
    39.                 SaveGameData();
    40.             }
    41.         }
    42.  
    43.         if (GUILayout.Button("Load data"))
    44.         {
    45.             LoadGameData();
    46.         }
    47.  
    48.         if (GUILayout.Button("Create new data"))
    49.         {
    50.             CreateNewData();
    51.         }
    52.        
    53.         GUILayout.EndScrollView();
    54.     }
    55.  
    56.     private void LoadGameData()
    57.     {
    58.         string filePath = EditorUtility.OpenFilePanel("Select localization data file", Application.streamingAssetsPath, "json");
    59.  
    60.         if (!string.IsNullOrEmpty(filePath))
    61.         {
    62.             string dataAsJson = File.ReadAllText(filePath);
    63.  
    64.             localizationData = JsonUtility.FromJson<LocalizationData>(dataAsJson);
    65.         }
    66.     }
    67.  
    68.     private void SaveGameData()
    69.     {
    70.         string filePath = EditorUtility.SaveFilePanel("Save localization data file", Application.streamingAssetsPath, "", "json");
    71.  
    72.         if (!string.IsNullOrEmpty(filePath))
    73.         {
    74.             string dataAsJson = JsonUtility.ToJson(localizationData);
    75.             File.WriteAllText(filePath, dataAsJson);
    76.         }
    77.     }
    78.  
    79.     private void CreateNewData()
    80.     {
    81.         localizationData = new LocalizationData();
    82.     }
    83.  
    84. }



    Code (CSharp):
    1. [System.Serializable]
    2. public class LocalizationData
    3. {
    4.     public LocalizationItem[] items;
    5. }
    6.  
    7. [System.Serializable]
    8. public class LocalizationItem
    9. {
    10.     public string key;
    11.     public string value;
    12. }
     
  14. rcsordas

    rcsordas

    Joined:
    May 20, 2016
    Posts:
    2
    Here are the screenshots
    I typed test for the first field
    And after clicking on the other field, or hitting Tab / Enter it is erased

    upload_2021-5-12_17-39-36.png



    upload_2021-5-12_17-39-51.png
     
  15. davidakaxellos

    davidakaxellos

    Joined:
    Jun 8, 2019
    Posts:
    2

    THANK YOU!!! I tried for hours and didn't get it to work the right way. That was my last attempt and after I changed my Code to your Soloution it worked flawlessly.

    Sorry for bad england.
     
  16. GVSV

    GVSV

    Joined:
    Dec 18, 2020
    Posts:
    6
    Maybe this is a bad idea, but I managed to get this to work:
    Code (CSharp):
    1.  
    2. public static void CopyFromObject(this SerializedObject serializedObject, T target)
    3.     where T : notnull, UnityEngine.Object
    4. {
    5.     var it = new SerializedObject(target).GetIterator();
    6.     it.Next(true);
    7.     while (it.Next(false))
    8.     {
    9.         serializedObject.CopyFromSerializedProperty(it);
    10.     }
    11.  
    12.     serializedObject.ApplyModifiedProperties();
    13. }
    14.  
    The nice thing about this is that it lets me edit the
    target
    object directly, then save those changes back into the
    serializedObject
    without having to go through all the standard
    SerializedObject
    hoops.
     
    Last edited: Jul 7, 2022
  17. B33bo_Astro

    B33bo_Astro

    Joined:
    May 10, 2020
    Posts:
    3
    I think I love you <3
     
    umutcanbagci0215 likes this.