Inventory System breaks after update

Hey there, thank you for helping me in advance.

I have a mobile game with an inventory system. This is a scriptable object base system, so I have a database re populating the items:

public class Inventory : ScriptableObject, ISerializationCallbackReceiver
{
    public string savePath;
    public ItemDatabaseObject database;
    public delegate void OnItemChanged();
    public OnItemChanged OnItemChangedCallback;
   
    public List<InventorySlot> Container = new List<InventorySlot>();

    private void OnEnable()
    {
#if UNITY_EDITOR
        database = (ItemDatabaseObject)AssetDatabase.LoadAssetAtPath("Assets/Resources/ItemDatabase.asset", typeof(ItemDatabaseObject));
#else
    database = Resources.Load<ItemDatabaseObject>("ItemDatabase");   
#endif       
    }

    public void AddItem(ItemObject _item, int _amount)
    {
       for(int i = 0; i < Container.Count; i++)
       {
           if(Container[i].item == _item)
           {
               Container[i].AddAmount(_amount);
                    if (OnItemChangedCallback != null)
                    OnItemChangedCallback.Invoke();
               return;
           }
       }
        Container.Add(new InventorySlot(database.GetId[_item], _item, _amount));
        if (OnItemChangedCallback != null)
            OnItemChangedCallback.Invoke();
    }

    public void OnAfterDeserialize()
    {
        for (int i = 0; i < Container.Count; i++)
        {
            if(database.GetItem.ContainsKey(Container[i].ID))
            Container[i].item = database.GetItem[Container[i].ID];
        }
    }

    public void OnBeforeSerialize()
    {
    }

    public void RemoveItem(ItemObject _item, int _amount)
    {
        for(int i = 0; i < Container.Count; i++)
        {
           if(Container[i].item == _item)
            {
                Container[i].AddAmount(-_amount);
                    if (Container[i].amount == 0)
                    Container.Remove(Container[i]);
                    if (OnItemChangedCallback != null)
                    OnItemChangedCallback.Invoke();
               return;
            }
        }
        if (OnItemChangedCallback != null)
        OnItemChangedCallback.Invoke();
    }

[System.Serializable]
public class InventorySlot
{
    public int ID;
    public ItemObject item;
    public int amount;
    public InventorySlot(int _id, ItemObject _item, int _amount)
    {
        ID = _id;
        item = _item;
        amount = _amount;
    }
    public void AddAmount(int value)
    {
        amount += value;
    }
}

    [ContextMenu("Save")]
    public void Save()
    {
        string saveData = JsonUtility.ToJson(this, true);
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(string.Concat(Application.persistentDataPath, savePath));
        bf.Serialize(file, saveData);
        file.Close();
    }

    [ContextMenu("Load")]
    public void Load()
    {
        if (File.Exists(string.Concat(Application.persistentDataPath, savePath)))
        {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(string.Concat(Application.persistentDataPath, savePath), FileMode.Open);
            JsonUtility.FromJsonOverwrite(bf.Deserialize(file).ToString(), this);
            file.Close();
        }
    }
}

which has the database:

public class ItemDatabaseObject : ScriptableObject, ISerializationCallbackReceiver
{
    public ItemObject[] Items;
    public Dictionary<ItemObject, int> GetId = new Dictionary<ItemObject, int>();
    public Dictionary<int, ItemObject> GetItem = new Dictionary<int, ItemObject>();

    public void OnAfterDeserialize()
    {
        GetId = new Dictionary<ItemObject, int>();
        GetItem = new Dictionary<int, ItemObject>();

        for(int i =0; i<Items.Length; i++)
        {
            GetId.Add(Items[i], i);
            GetItem.Add(i, Items[i]);
        }
    }

    public void OnBeforeSerialize()
    {
    }
}

MY PROBLEM:

Every time I make an update to my game, the game cannot recognise the items afterwards. The reference breaks for the items, and the system doesnt know which ID is which item.

This could be of 2 reasons I believe:
Dictionaries get messed up
resource system doesn’t load the database back.

I tried to research my problem but I have no clue. The system works again once I clear all data of the game.

I haven’t used that serialization callback receiver so I cannot comment on what it is supposed to do.

However if I was given this bug I would start putting breakpoints all over the place, or else Debug.Log() statements in all the relevant functions, then I would reduce my dataset to the smallest possible that shows the problem (one item in the inventory perhaps?) and trigger it, then study what’s going wrong.

Since you are writing it as JSON, you can also pull that up and reason about the JSON with a text editor, which is one of the greatest things about working with JSON versus binary data.

I am having a hard time debugging it on my phone, but you are 100% right, logcat would really tell what’s wrong.

I believe my problem is with the resource system.

Ooh, just noticed: I think you need a [System.Serializable] decorator above your ItemDatabaseObject class…

But I will say I have never serialized something derived from ScriptableObject. I also don’t know who is supposed to call that listener interface, what is expected, etc. Check docs for that.

Every item which is public, gets serialzed anyway so that wouldn’t help.

What helped me is getting rid of the onEnable function and just set the database on inspector.

1 Like