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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Custom editor not saving changes made to scriptable objects

Discussion in 'Scripting' started by Lucas6y6, Jun 18, 2022.

  1. Lucas6y6

    Lucas6y6

    Joined:
    Mar 9, 2022
    Posts:
    3
    So i have this scriptable object called Item:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [CreateAssetMenu(fileName = "NewItem", menuName = "Item", order = 1)]
    4. public class Item : ScriptableObject
    5. {
    6.     [SerializeField] string tooltip;
    7.     [SerializeField] Object script;
    8.     [SerializeField] ItemType type;
    9.     public bool stackable;
    10.     [SerializeField] int quantity;
    11.     [SerializeField] Consumable consumableType;
    12.     [SerializeField] Equipable equipableType;
    13. }
    and this ItemEditor script:
    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. [CustomEditor(typeof(Item))]
    4. public class ItemEditor : Editor
    5. {
    6.     public ItemType type;
    7.     public override void OnInspectorGUI()
    8.     {
    9.         serializedObject.Update();
    10.         //base.OnInspectorGUI();
    11.         //Item item = (Item)target;
    12.         DisplayCommonProperties();
    13.         type = (ItemType)EditorGUILayout.EnumPopup("Type of item", type);
    14.         //EditorGUILayout.Space();
    15.         switch (type)
    16.         {
    17.             case ItemType.consumable:
    18.                 DisplayConsumableTypes();
    19.                 break;
    20.             case ItemType.equipable:
    21.                 DisplayEquipableTypes();
    22.                 break;
    23.         }
    24.         serializedObject.ApplyModifiedProperties();
    25.     }
    26.     public void DisplayCommonProperties()
    27.     {
    28.         EditorGUILayout.PropertyField(serializedObject.FindProperty("tooltip"));
    29.         EditorGUILayout.PropertyField(serializedObject.FindProperty("script"));
    30.         EditorGUILayout.PropertyField(serializedObject.FindProperty("stackable"));
    31.     }
    32.     public void DisplayConsumableTypes()
    33.     {
    34.         EditorGUILayout.PropertyField(serializedObject.FindProperty("consumableType"));
    35.         EditorGUILayout.PropertyField(serializedObject.FindProperty("quantity"));
    36.     }
    37.     public void DisplayEquipableTypes()
    38.     {
    39.         EditorGUILayout.PropertyField(serializedObject.FindProperty("equipableType"));
    40.     }
    41. }
    42.  
    I followed this tutorial: https://blog.terresquall.com/2020/07/organising-your-unity-inspector-fields-with-a-dropdown-filter/

    I certainly can edit an Item scriptable object the way I want but as soon as I click away on any other object and come back to my scriptable object, all the changes are gone.
    I've tried everything the internet said to do to this type of error but nothing worked.
    Please help D:
     
  2. Sphinks

    Sphinks

    Joined:
    Apr 6, 2019
    Posts:
    267
    Your Item class needs [Serializable]
     
  3. Lucas6y6

    Lucas6y6

    Joined:
    Mar 9, 2022
    Posts:
    3
    Changed to this:
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. [CreateAssetMenu(fileName = "NewItem", menuName = "Item", order = 1)]
    5. [Serializable]
    6. public class Item : ScriptableObject
    still not working
     
  4. Sphinks

    Sphinks

    Joined:
    Apr 6, 2019
    Posts:
    267
    I think you also need a
    EditorUtility.SetDirty(yourItem);


    and also maybe (but here i´m not sure)
    Code (CSharp):
    1. AssetDatabase.SaveAssets();
    2. AssetDatabase.Refresh();  
     
    brunogattai1996 likes this.
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    The serializable attribute does nothing in this context.

    I believe OP might need to remove
    serializedObject.ApplyModifiedProperties();
    as that is likely continually writing the existing data to the SO.
     
    brunogattai1996 likes this.
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,572
    Nope, MonoBehaviour and ScriptableObjects are serialized by default. You only need the System.Serializable attribute on ordinary C# classes. It doesn't hurt though.

    No, that's not necessary and would probably just mess with the undo system as well. The SerializedObject / SerializedProperty system should handle everything for you as long as you call "ApplyModifiedProperties" at the end.

    @Lucas6y6

    Why does your custom inspector has this field?

    Code (CSharp):
    1. public ItemType type;
    It's part of the editor and of course would not be serialized anywhere. when you close the editor (select something else) the editor is gone and so is this value. Your Item class does also have a type field. Maybe you wanted to use that?

    Are you sure, that the changes you made "to the serialized fields" are lost? Or do you just talk about the item type?. If it's the item type, yes, it is not serialized as it only exists inside the editor.

    So I would recommend to remove any fields from your Editor. Just use the ItemType of the object you're editing. Something like this:

    Code (CSharp):
    1. SerializedProperty itemType = serializedObject.FindProperty("type");
    2. EditorGUILayout.PropertyField(itemType);
    3. ItemType type = (ItemType)itemType.intValue;
     
    Lucas6y6 likes this.
  7. Lucas6y6

    Lucas6y6

    Joined:
    Mar 9, 2022
    Posts:
    3
    Problem solved. Thanks a lot @Bunny83 (and also @Sphinks and @spiney199 for coming up with ideas).
    The problem was the public ItemType type member, which was not updating properly. Its purpose is to show only certain properties of an item based on its value (if type is consumable, show quantity and others, and if it is equipable show gear subtype, etc).
    I'll write down the fixed script and the scriptable object "Item" script for reference.
    Note: I renamed "type" to "itemType" as Bunny83 suggested, changed its variable type from "ItemType" to "SerializedProperty" and moved its declaration inside OnInspectorGUI() method using serializedObject.FindProperty("type"). It is no longer a class member

    Code (CSharp):
    1. using UnityEditor;
    2.  
    3. [CustomEditor(typeof(Item))]
    4. public class ItemEditor : Editor
    5. {
    6.     public override void OnInspectorGUI()
    7.     {
    8.         serializedObject.Update();
    9.  
    10.         DisplayCommonProperties();
    11.      
    12.         SerializedProperty itemType = serializedObject.FindProperty("type");
    13.  
    14.         EditorGUI.BeginChangeCheck();
    15.         EditorGUILayout.PropertyField(itemType);
    16.         if (EditorGUI.EndChangeCheck())
    17.         {
    18.             serializedObject.FindProperty("equipableType").enumValueIndex = 0;
    19.             serializedObject.FindProperty("consumableType").enumValueIndex = 0;
    20.             serializedObject.FindProperty("quantity").intValue = 0;
    21.             serializedObject.FindProperty("stackable").boolValue = ((ItemType)itemType.enumValueIndex == ItemType.consumable);
    22.         }
    23.  
    24.         switch ((ItemType)itemType.enumValueIndex)
    25.         {
    26.             case ItemType.consumable:
    27.                 DisplayConsumableTypes();
    28.                 break;
    29.             case ItemType.equipable:
    30.                 DisplayEquipableTypes();
    31.                 break;
    32.         }
    33.  
    34.         serializedObject.ApplyModifiedProperties();
    35.     }
    36.  
    37.     public void DisplayCommonProperties()
    38.     {
    39.         EditorGUILayout.PropertyField(serializedObject.FindProperty("tooltip"));
    40.         EditorGUILayout.PropertyField(serializedObject.FindProperty("script"));
    41.     }
    42.  
    43.     public void DisplayConsumableTypes()
    44.     {
    45.         EditorGUILayout.PropertyField(serializedObject.FindProperty("consumableType"));
    46.         EditorGUILayout.PropertyField(serializedObject.FindProperty("quantity"));
    47.     }
    48.  
    49.     public void DisplayEquipableTypes()
    50.     {
    51.         EditorGUILayout.PropertyField(serializedObject.FindProperty("equipableType"));
    52.     }
    53. }
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [CreateAssetMenu(fileName = "NewItem", menuName = "Item", order = 1)]
    4. public class Item : ScriptableObject
    5. {
    6.     [SerializeField] string tooltip;
    7.     public string Tooltip
    8.     {
    9.         get { return tooltip; }
    10.     }
    11.  
    12.     [SerializeField] UnityEngine.Object script;
    13.     public string ScriptName
    14.     {
    15.         get { return script.name; }
    16.     }
    17.  
    18.     [SerializeField] ItemType type;
    19.     public ItemType Type
    20.     {
    21.         get { return type; }
    22.     }
    23.  
    24.     [SerializeField] bool stackable;
    25.     public bool Stackable
    26.     {
    27.         get { return stackable; }
    28.         set { stackable = value; }
    29.     }
    30.  
    31.     [SerializeField] int quantity;
    32.     public int Quantity
    33.     {
    34.         get { return quantity; }
    35.         set { quantity = value; }
    36.     }
    37.  
    38.     [SerializeField] Consumable consumableType;
    39.     public Consumable ConsumableType
    40.     {
    41.         get { return consumableType; }
    42.     }
    43.  
    44.     [SerializeField] Equipable equipableType;
    45.     public Equipable EquipableType
    46.     {
    47.         get { return equipableType; }
    48.     }
    49. }
     
    Last edited: Jun 19, 2022
    brunogattai1996 likes this.