Search Unity

Saving/Loading ScriptableObject problem

Discussion in 'Scripting' started by addiem7c5, Aug 9, 2011.

  1. addiem7c5

    addiem7c5

    Joined:
    Aug 4, 2011
    Posts:
    3
    Hello, first time poster long time lurker here.

    I've been working on an editor tool for my game that allows the creation/modification of items. In my editor window script, when the user wants to save the current state of the item manager, I create an asset composed of the item manager (which derives from ScriptableObject) and save in the Resources folder for later use. However, if I try to make a change and re-save it, if I don't call AssetDatabase.DeleteAsset() it tells me that the asset already exists. If I do call AssetDatabase.DeleteAsset(), then when I subsequently call AssetDatabase.CreateAsset() it tells me that the object is null. Also, upon trying to load the asset from file in the editor with AssetDatabase.GetAssetAtPath() or in game with Resources.Load(), the ItemManager variable comes up null.

    Here's some supplemental code that will hopefully help you understand what is going on.

    Code (csharp):
    1.  
    2. void ExportItemList()
    3. {
    4.     GUILayout.Space(50.0f);
    5.     if(GUILayout.Button("Export"))
    6.     {
    7.         string path = EditorUtility.SaveFilePanel("Export Items to Xml", ".", "items", "xml");
    8.         XmlSerializer serializer = new XmlSerializer(typeof(List<Item>));
    9.         TextWriter write = new StreamWriter(path);
    10.         serializer.Serialize(write, itemmanager.Items);
    11.         write.Close();
    12.  
    13.         AssetDatabase.DeleteAsset(@"Assets\Resources\ItemManager.asset");
    14.                 AssetDatabase.CreateAsset(itemmanager, @"Assets\Resources\ItemManager.asset");
    15.  
    16.         AssetDatabase.SaveAssets();
    17.  
    18.     }
    19.  
    20. }
    21.  
    22.    
    23.  
    24. void ImportItemList()
    25. {
    26.     GUILayout.Space(50.0f);
    27.     if(GUILayout.Button("Import"))
    28.     {
    29.         string path = EditorUtility.OpenFilePanel("Import Item Manager", ".", "asset");
    30.  
    31.             itemmanager = (ItemManager)AssetDatabase.LoadAssetAtPath(path, typeof(ItemManager));
    32.  
    33.     }
    34. }
    35.  
    Edit: Bad formatting. Well, it's still pretty bad but I think that's because I went past column 80 in code.
     
    Last edited: Aug 9, 2011
  2. addiem7c5

    addiem7c5

    Joined:
    Aug 4, 2011
    Posts:
    3
    I suppose it's probably a good idea to show you what ItemManager looks like.
    Code (csharp):
    1.  
    2. [Serializable]
    3. public class ItemManager : ScriptableObject
    4. {  
    5.     private List<Item> items;
    6.  
    7.     public List<Item> Items
    8.     {
    9.         get
    10.         {
    11.             return items;
    12.         }
    13.         set
    14.         {
    15.             items = value;
    16.         }
    17.     }
    18.  
    19.     public ItemManager()
    20.     {
    21.         items = new List<Item>();
    22.     }
    23.  
    24.     public void AddItem(Item item)
    25.     {
    26.         items.Add(item);
    27.     }
    28.  
    29.     public void RemoveItem(Item item)
    30.     {
    31.         items.Remove(item);
    32.     }
    33.  
    34.    
    35.     public Item GetItem(ulong id)
    36.     {
    37.         return items.Find(delegate(Item i) { return i.Id == id; });
    38.     }
    39.  
    40.     public void SortById()
    41.     {
    42.         items.Sort(delegate(Item first, Item second) { if(first.Id > second.Id) return 1; else if(first.Id == second.Id) return 0; else return -1; });
    43.     }
    44.  
    45.     public void SortByName()
    46.     {
    47.         items.Sort(delegate(Item first, Item second) { return String.Compare(first.Name, second.Name); });
    48.     }
    49. }
    50.  
    Thanks.
     
  3. addiem7c5

    addiem7c5

    Joined:
    Aug 4, 2011
    Posts:
    3
    So after taking a break, and then coming back to it for a couple hours I realized that some of my classes were not marked [Serializable], and I should've been Saving/Loading the file like this:

    Code (csharp):
    1.  
    2. //This is called when the Editor Window is created
    3.  
    4. itemmanager = (ItemManager)AssetDatabase.LoadAssetAtPath(@"Assets\Resources\ItemManager.asset", typeof(ItemManager));
    5. if(itemmanager == null)
    6. {
    7.     AssetDatabase.CreateAsset(itemmanager, @"Assets\Resources\ItemManager.asset");
    8.     itemmanager = (ItemManager)ScriptableObject.CreateInstance(typeof(ItemManager));
    9. }
    10.  
    11. //And this is called when I want to save
    12.  
    13. if(!AssetDatabase.Contains(itemmanager))
    14.         AssetDatabase.CreateAsset(itemmanager, @"Assets\Resources\ItemManager.asset");
    15. AssetDatabase.SaveAssets();
    16.  
     
  4. nicloay

    nicloay

    Joined:
    Jul 11, 2012
    Posts:
    540
    Also i found that your scriptableobject script must be defined in separated class,
    Otherwise, when you use AssetDatabase.Create, it's create asset well, but lost links to the script.
     
  5. Radivarig

    Radivarig

    Joined:
    May 15, 2013
    Posts:
    121
    In last addiem7c5 code, swap line 8 with 7, otherwise null asset is passed.
     
  6. Dan2013

    Dan2013

    Joined:
    May 24, 2013
    Posts:
    200
    Yes... to fix the "lost link to script" issue, you should make a separated cs file such as MyScriptableObject.cs that contains a class named MyScriptableObjec.
    Code (CSharp):
    1. //in MyScriptableObject.cs
    2. public class MyScriptableObject: ScriptableObject
    3. {
    4.     ... ...
    5. }