Saving Scriptable Objects (Inventory)

Hi!

So i`ve been struggling with this for one(!) week now. Been in every corner of the web it feels like but i cant get the hang of this!

I have a list of scriptable objects in my inventory that im trying to save so that the inventory stays the same every time someone closes and reopens the game.

I already have a binary formatter script(DataManagement) that i would like to save the inventory to. But im open to anything that works at this point.

I understand that i cant just add the list of items directly in my DataManagement script and that i may have to create another script/class that is serializable with the scriptable objects information or something like that.
But i dont know how…

This is my current Save/Load script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public class DataManagement : MonoBehaviour
{

    public static DataManagement dataManagement;

    public List<Item> inventory;

    public int currentScore;
    public int highScore;
    public int coinsCollected;
    public int goldGemCollected;
    public int redGemCollected;
    public int greyGemCollected;
    public int level = 1;

    void Awake()
    {
        if (dataManagement == null)
        {
            DontDestroyOnLoad(gameObject);
            dataManagement = this;
        }
        else if (dataManagement != this)
        {
            Destroy(gameObject);
            Debug.LogWarning("More than ine instance of Database found!");
        }
    }

    public void SaveData()
    {
        BinaryFormatter binForm = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "/gameInfo.dat");
        gameData data = new gameData();
        data.highScore = highScore;
        data.coinsCollected = coinsCollected;
        data.goldGemCollected = goldGemCollected;
        data.redGemCollected = redGemCollected;
        data.greyGemCollected = greyGemCollected;
        data.level = level;
        binForm.Serialize(file, data);
        file.Close();
    }

    public void LoadData()
    {
        if (File.Exists(Application.persistentDataPath + "/gameInfo.dat"))
        {
            BinaryFormatter binForm = new BinaryFormatter();
            FileStream file = File.Open(Application.persistentDataPath + "/gameInfo.dat", FileMode.Open);
            gameData data = (gameData)binForm.Deserialize(file);
            file.Close();
            highScore = data.highScore;
            coinsCollected = data.coinsCollected;
            goldGemCollected = data.goldGemCollected;
            redGemCollected = data.redGemCollected;
            greyGemCollected = data.greyGemCollected;
            level = data.level;
        }
    }

    public void Delete()
    {
        File.Delete(Application.persistentDataPath + "/gameInfo.dat");

    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.L))
        {
            SaveData();
            Debug.Log("Saving");
        }
    }
}



[Serializable]
class gameData
{
    public int highScore;
    public int coinsCollected;
    public int goldGemCollected;
    public int redGemCollected;
    public int greyGemCollected;
    public int level;
}

This is my scriptable object script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{
    new public string name = "New Item";
    public Sprite icon = null;
    public ItemType type;
    public int id;

    public virtual void Use()
    {
        Debug.Log("Using " + name);
    }

    public void RemoveFromInventory()
    {
        Inventory.instance.Remove(this);
    }
}

and this is my inventory script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Inventory : MonoBehaviour
{
    #region Singleton

    public static Inventory instance;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if(instance != this)
        {
            Destroy(gameObject);
            Debug.LogWarning("More than ine instance of Inventory found!");
        }

       
    }

    #endregion

    public delegate void OnItemChanged();
    public OnItemChanged onItemChangedCallBack;

    public int space = 20;

    public List<Item> items = new List<Item>();

    public bool Add (Item item)
    {


        if (items.Count >= space)
        {
            Debug.Log("Not enough room!");

            return false;
           
        }

        items.Add(item);

        if (onItemChangedCallBack != null)
            onItemChangedCallBack.Invoke();


        return true;
    }


    public void Remove (Item item)
    {
        items.Remove(item);

        if (onItemChangedCallBack != null)
            onItemChangedCallBack.Invoke();

    }
}

I would be so grateful if somebody could help me with this so i can continue making my game!

You need to save a list of references to the scriptableobjects. There’s three general strategies for this:

  • Save the name of the SO and load it later with Resources.Load. this requires the SO to be in Resources
  • Save the name of the SO and load it later using AssetBundles. This requires the SO to be in an asset bundle.
  • Save the address of the SO and load it later using Unity’s Addressable Assets system.

I have no idea how to do any of that…

There are literally HUNDREDS of youtube tutorials on loading and saving.

The more finer-grained detail you save and load, the more work it is for you to engineer, debug, support, etc.

Start VERY minimalistically: work through two or three separate tutorials on loading saving to see a few approaches, and don’t move on until you understand what they are doing. This is your data, it’s not possible for you to convert it to something that can be stored on disk and then restore it without ACTUALLY understanding what is going on at each step.

I have started small. Saving current level, coins etc. But cant seem to find anything on saving a list of scriptable objects…

Well now you have some stuff to start researching.

1 Like

ScriptableObjects are generally NOT used for saving instance data. You may do so but you are getting no benefit above a regular old class.

ScriptableObjects are for defining predefined fixed data that defines how your game behaves. For instance types of swords that have different characteristics. Each one would be a different SO: Sword, Longsword, Shortsword, etc.

You don’t save the details of the sword itself per se (it’s in the build after all!), but you might save something that says “The player has 7 of these swords in his inventory.”

1 Like

Yes, i know. All of the stats of the item is saved on the scriptable object. The problem is to be able to save what current items the player have in the inventory