• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by MoJoe_Blue_ · Jan 17, 2018 at 10:26 PM · editorinspectorassetserializationscriptableobject

[Solved]Why doesn't my ScriptableObject based asset save using a custom inspector ?

So I made an asset system based on the ScriptableObject. I have several assets made this way and they all save perfectly but one. Some have custom inpector display, some have not.


My problem is that I can't identify why this one does not save. Every time I hit the Play button or change scene in Editor the asset is reset to default.
I tried to use EditorUtility.SetDirty(...), AssetDatabase.SaveAssets(), SerializedObject.ApplyModifiedProperties(), none of them have any effect.


Here is the asset that doesn't save :

 using UnityEngine;
 
 [CreateAssetMenu(fileName = "DefaultMap", menuName = "Terrain/Map")]
 public class FightMapData : ObjectData
 {
     [SerializeField]
     private int height = 1;
     public int  Height { get { return height; } set { height = value; } }
     [SerializeField]
     private int width = 1;
     public int  Width { get { return width; } set { width = value; } }
     
     [SerializeField]
     private TileData[][]    terrain;
     public TileData[][]     Terrain { get { return terrain; } set { terrain = value; } }
 
     public void ResizeTerrain()
     {
         if (terrain == null)
             terrain = new TileData[width][];
         else if (terrain.Length == width && terrain[0] != null && terrain[0].Length == height)
             return;
 
         TileData[][] terrainCopy = new TileData[width][];
 
         for (int i = 0; i < width; i++)
         {
             terrainCopy[i] = new TileData[height];
 
             for (int j = 0; j < height; j++)
             {
                 if (terrain.Length > i && terrain[i] != null && terrain[i].Length > j)
                     terrainCopy[i][j] = terrain[i][j];
                 else
                 {
                     Debug.Log("else,      height : " + height);
                     terrainCopy[i][j] = null;
 
                     if (terrain.Length > i)
                     {
                         if (terrain[i] == null)
                             Debug.Log("null");
                         else
                             Debug.Log("terrain[i].length <= j");
                     }
                     else
                         Debug.Log("terrain.length <= i");
                 }
             }
         }
 
         terrain = new TileData[width][];
 
         for (int i = 0; i < width; i++)
         {
             terrain[i] = new TileData[height];
 
             for (int j = 0; j < height; j++)
             {
                 if (terrainCopy[i][j] == null)
                     terrain[i][j] = null;
                 else
                 {
                     terrain[i][j] = CreateInstance<TileData>();
                     terrain[i][j].Copy(terrainCopy[i][j]);
                 }
             }
         }
     }

  

It's custom inspector :

 using UnityEngine;
 using UnityEditor;
 
 [CustomEditor(typeof(FightMapData))]
 public class FightMapDataEditor : Editor
 {
     private bool mapFoldout = true;
     private Vector2 scrollPosition;
 
     public TileData FillTileData = null;
 
     public override void OnInspectorGUI()
     {
         FightMapData fightMapData = (FightMapData)target;
 
         fightMapData.ResizeTerrain();
 
         EditorGUILayout.Space();
         fightMapData.Id = EditorGUILayout.TextField("Id", fightMapData.Id);
         fightMapData.Name = EditorGUILayout.TextField("Name", fightMapData.Name);
 
         EditorGUILayout.Space();
         fightMapData.Height = EditorGUILayout.IntField("Height", fightMapData.Height);
         fightMapData.Width = EditorGUILayout.IntField("Width", fightMapData.Width);
         
         EditorGUILayout.Space();
         mapFoldout = EditorGUILayout.Foldout(mapFoldout, "Map");
         if (mapFoldout)
         {
             EditorGUILayout.Space();
             FillTileData = (TileData)EditorGUILayout.ObjectField("TileData to fill Map", FillTileData, typeof(TileData), false);
             EditorGUILayout.BeginHorizontal();
             if (GUILayout.Button("Fill"))
                 fightMapData.Fill(FillTileData);
             if (GUILayout.Button("Fill blanks"))
                 fightMapData.FillBlanks(FillTileData);
             EditorGUILayout.EndHorizontal();
 
             EditorGUILayout.Space();
             scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, true, true);
             EditorGUILayout.BeginHorizontal();
             for (int i = 0; i < fightMapData.Terrain.Length; i++)
             {
                 EditorGUILayout.BeginVertical();
                 if (fightMapData.Terrain[i] == null)
                 {
                     EditorGUILayout.EndVertical();
                     continue;
                 }
 
                 for (int j = 0; j < fightMapData.Terrain[i].Length; j++)
                     fightMapData.Terrain[i][j] = (TileData)EditorGUILayout.ObjectField(fightMapData.Terrain[i][j], typeof(TileData), false);
                 EditorGUILayout.EndVertical();
             }
             EditorGUILayout.EndHorizontal();
             EditorGUILayout.EndScrollView();
         }
     }
 }



Here is an example asset that save perfectly :

 using UnityEngine;
 
 [CreateAssetMenu(fileName = "DefaultUnit", menuName = "Unit")]
 public class UnitData : ObjectData
 {
     public enum Classes { None, Soldier }
 
     [SerializeField]
     private Classes _class = 0;
     public Classes   Class { get { return _class; } set { _class = value; } }
 
     [SerializeField]
     private int level = 1;
     public int  Level { get { return level; } set { level = value; } }
 
     [SerializeField]
     private int baseHitPoints = 0;
     public int  BaseHitPoints { get { return baseHitPoints; } set { baseHitPoints = value; } }
     [SerializeField]
     private int strength = 0;
     public int  Strength { get { return strength; } set { strength = value; } }
     [SerializeField]
     private int dexterity = 0;
     public int  Dexterity { get { return dexterity; } set { dexterity = value; } }
     [SerializeField]
     private int luck = 0;
     public int  Luck { get { return luck; } set { luck = value; } }
     [SerializeField]
     private int speed = 0;
     public int  Speed { get { return speed; } set { speed = value; } }
 
     [System.Serializable]
     public struct WeaponRank
     {
         public WeaponData.WeaponType Type;
         public WeaponData.Rank Rank;
         public int Experience;
     }
     [SerializeField]
     private WeaponRank[]    weaponRanks = new WeaponRank[6];
     public WeaponRank[] WeaponRanks { get { return weaponRanks; } set { weaponRanks = value; } }
 
     [SerializeField]
     private bool    canMount = false;
     public bool     CanMount { get { return canMount; } set { canMount = value; } }
     [SerializeField]
     private int movement = 0;
     public int  Movement { get { return movement; } set { movement = value; } }
 
     [SerializeField]
     private ArmorData[] armorPieces = new ArmorData[4];
     public ArmorData[]  ArmorPieces { get { return armorPieces; } set { armorPieces = value; } }
     [SerializeField]
     private WeaponData[]    weapons = new WeaponData[4];
     public WeaponData[]     Weapons { get { return weapons; } set { weapons = value; } }
 
     [SerializeField]
     private HorseData   horse = null;
     public HorseData    Horse { get { return horse; } set { horse = value; } }
 
     [ExecuteInEditMode]
     public void Awake()
     {
         WeaponRanks[0].Type = WeaponData.WeaponType.OneHanded;
         WeaponRanks[1].Type = WeaponData.WeaponType.TwoHanded;
         WeaponRanks[2].Type = WeaponData.WeaponType.Polearms;
         WeaponRanks[3].Type = WeaponData.WeaponType.Archery;
         WeaponRanks[4].Type = WeaponData.WeaponType.Crossbow;
         WeaponRanks[5].Type = WeaponData.WeaponType.Throwing;
     }
 }

  

It's custom inspector :

 using UnityEngine;
 using UnityEditor;
 
 [CustomEditor(typeof(UnitData))]
 public class UnitDataEditor : Editor
 {
     private bool weaponsFoldout = true;
     private bool armorsFoldout = true;
 
     private bool weaponRanksFoldout = true;
 
     public override void OnInspectorGUI()
     {
         UnitData data = (UnitData)target;
 
         EditorGUILayout.Space();
         data.Id = EditorGUILayout.TextField("Id", data.Id);
         data.Name = EditorGUILayout.TextField("Name", data.Name);
 
         EditorGUILayout.Space();
         data.Sprite = (Sprite)EditorGUILayout.ObjectField("Sprite", data.Sprite, typeof(Sprite), false);
 
         EditorGUILayout.Space();
         EditorGUILayout.LabelField("Equipment", EditorStyles.boldLabel);
 
         weaponsFoldout = EditorGUILayout.Foldout(weaponsFoldout, "Weapons");
         if (weaponsFoldout)
         {
             data.Weapons[0] = (WeaponData)EditorGUILayout.ObjectField("Equipped Weapon", data.Weapons[0], typeof(WeaponData), false);
             data.Weapons[1] = (WeaponData)EditorGUILayout.ObjectField("Seond Weapon", data.Weapons[1], typeof(WeaponData), false);
             data.Weapons[2] = (WeaponData)EditorGUILayout.ObjectField("Third Weapon", data.Weapons[2], typeof(WeaponData), false);
             data.Weapons[3] = (WeaponData)EditorGUILayout.ObjectField("Fourth Weapon", data.Weapons[3], typeof(WeaponData), false);
         }
 
         EditorGUILayout.Space();
         armorsFoldout = EditorGUILayout.Foldout(armorsFoldout, "Armors");
         if (armorsFoldout)
         {
             data.ArmorPieces[0] = (ArmorData)EditorGUILayout.ObjectField("Head Armor", data.ArmorPieces[0], typeof(ArmorData), false);
             data.ArmorPieces[1] = (ArmorData)EditorGUILayout.ObjectField("Torso Armor", data.ArmorPieces[1], typeof(ArmorData), false);
             data.ArmorPieces[2] = (ArmorData)EditorGUILayout.ObjectField("Gauntlets", data.ArmorPieces[2], typeof(ArmorData), false);
             data.ArmorPieces[3] = (ArmorData)EditorGUILayout.ObjectField("Boots", data.ArmorPieces[3], typeof(ArmorData), false);
         }
 
         EditorGUILayout.Space();
         data.CanMount = EditorGUILayout.Toggle("Can Mount", data.CanMount);
         if (data.CanMount)
         {
             data.Horse = (HorseData)EditorGUILayout.ObjectField("Horse", data.Horse, typeof(HorseData), false);
             if (data.Horse == null)
                 EditorGUILayout.LabelField("Movement Bonus : 0");
             else
                 EditorGUILayout.LabelField("Movement Bonus : " + data.Horse.MovementBonus);
         }
 
         EditorGUILayout.Space();
         EditorGUILayout.LabelField("Statistics", EditorStyles.boldLabel);
 
         data.Class = (UnitData.Classes)EditorGUILayout.EnumPopup("Class", data.Class);
 
         EditorGUILayout.Space();
         data.Level = EditorGUILayout.IntField("Level", data.Level);
 
         EditorGUILayout.Space();
         data.BaseHitPoints = EditorGUILayout.IntField("Base Hit Points", data.BaseHitPoints);
         data.Strength = EditorGUILayout.IntField("Strength", data.Strength);
         data.Dexterity = EditorGUILayout.IntField("Dexterity", data.Dexterity);
         data.Luck = EditorGUILayout.IntField("Luck", data.Luck);
         data.Speed = EditorGUILayout.IntField("Speed", data.Speed);
         data.Movement = EditorGUILayout.IntField("Movement", data.Movement);
 
         int defense = 0;
         int weight = 0;
 
         for (int i = 0; i < 4; i++)
         {
             if (data.ArmorPieces[i] != null)
             {
                 defense += data.ArmorPieces[i].Defense;
                 weight += data.ArmorPieces[i].Weight;
             }
         }
 
         if (data.Weapons[0] != null)
             weight += data.Weapons[0].Weight;
 
         EditorGUILayout.LabelField("Defense : " + defense);
         EditorGUILayout.LabelField("Weight : " + weight);
 
         EditorGUILayout.Space();
         weaponRanksFoldout = EditorGUILayout.Foldout(weaponRanksFoldout, "Weapon Ranks");
         if (weaponRanksFoldout)
         {
             EditorGUILayout.LabelField("One Handed");
             data.WeaponRanks[0].Rank = (WeaponData.Rank)EditorGUILayout.EnumPopup("Rank", data.WeaponRanks[0].Rank);
             data.WeaponRanks[0].Experience = EditorGUILayout.IntField("Experience", data.WeaponRanks[0].Experience);
             EditorGUILayout.Space();
             EditorGUILayout.LabelField("Two Handed");
             data.WeaponRanks[1].Rank = (WeaponData.Rank)EditorGUILayout.EnumPopup("Rank", data.WeaponRanks[1].Rank);
             data.WeaponRanks[1].Experience = EditorGUILayout.IntField("Experience", data.WeaponRanks[1].Experience);
             EditorGUILayout.Space();
             EditorGUILayout.LabelField("Polearms");
             data.WeaponRanks[2].Rank = (WeaponData.Rank)EditorGUILayout.EnumPopup("Rank", data.WeaponRanks[2].Rank);
             data.WeaponRanks[2].Experience = EditorGUILayout.IntField("Experience", data.WeaponRanks[2].Experience);
             EditorGUILayout.Space();
             EditorGUILayout.LabelField("Archery");
             data.WeaponRanks[3].Rank = (WeaponData.Rank)EditorGUILayout.EnumPopup("Rank", data.WeaponRanks[3].Rank);
             data.WeaponRanks[3].Experience = EditorGUILayout.IntField("Experience", data.WeaponRanks[3].Experience);
             EditorGUILayout.Space();
             EditorGUILayout.LabelField("Crossbows");
             data.WeaponRanks[4].Rank = (WeaponData.Rank)EditorGUILayout.EnumPopup("Rank", data.WeaponRanks[4].Rank);
             data.WeaponRanks[4].Experience = EditorGUILayout.IntField("Experience", data.WeaponRanks[4].Experience);
             EditorGUILayout.Space();
             EditorGUILayout.LabelField("Throwing");
             data.WeaponRanks[5].Rank = (WeaponData.Rank)EditorGUILayout.EnumPopup("Rank", data.WeaponRanks[5].Rank);
             data.WeaponRanks[5].Experience = EditorGUILayout.IntField("Experience", data.WeaponRanks[5].Experience);
         }
     }
 }
Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image pako · Jan 16, 2018 at 07:42 PM 0
Share

@$$anonymous$$oJoe_Blue_ if I understand well, it seems that you've solved your own question:

*EDIT : An array of array (like : ScriptableObject[][] array;) can't be serialize. I fixed my issue using a simple array.

if so, could you post the solution as an answer, rather than an "EDIT" inside the question. It will be more helpful for others having the same problem.

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by MoJoe_Blue_ · Jan 17, 2018 at 10:21 PM

An array of array (like : ScriptableObject[][] array;) can't be serialize. I fixed my issue using a simple array.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image edufireheart · Jul 05, 2020 at 09:32 PM 0
Share

I was searching for a while and people were always telling me to use things like EditorUtility.SetDirty or AssetDatabase.SaveAssets. Even if those are valid propositions for the right cases, all I needed was someone telling me that two dimensional arrays within scriptable objects can't be serialized. Then I could stop searching for convoluted solutions and simply use auxiliary one-dimensional arrays for serialization. Thanks

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

103 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Why doesn't my ScriptableObject save using a custom EditorWindow? 3 Answers

How should I serialize data that is also editable in the Inspector? 2 Answers

Custom Inspector for ScriptableObject 1 Answer

Scriptable Object resets after Unity is closed 2 Answers

Why can't a MonoBehaviour subtype with generic arguments be serialized in a list since Unity 4.5? 0 Answers

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges