0

Whenever saving or loading via the Player script, the inventory always comes up blank on both sides, and I can't figure out where the problem is. The inventory uses the same system that is used in the Intermediate Inventory Tutorial by Unity, which works fine, but the inventory is always blank when loading.

Player

public void Save(){
    Debug.Log ("Saving data (player / inventory)");

    SaveLoadManager.SavePlayer (this); //works fine
    SaveLoadInventory.SaveInventory (inv); //where the issue is
}
public void Load(){
    Debug.Log ("Loading data (player / inventory)");

    float[] loadedStats = SaveLoadManager.LoadPlayer (); //works fine
    Item[] loadedItems = SaveLoadInventory.LoadInventory (); //comes up empty

    inv.items = loadedItems; //try to set the referenced Inventory script array of items equal to the loaded items

    //loadedStats[...] are set to player values and all works good
}

Inventory

public class Inventory : MonoBehaviour {

public Image[] itemImages = new Image[numItemSlots];
public Text[] itemAmountsText = new Text[numItemSlots];
public int[] itemAmounts = new int[numItemSlots];
public Item[] items = new Item[numItemSlots];

public const int numItemSlots = 40;

public void AddItem(Item itemToAdd){
    for (int i = 0; i < items.Length; i++) {
        if(items [i] == itemToAdd){
            if (itemAmounts [i] <= 99) {
                itemAmounts [i]++;
            } else {
                items [i] = itemToAdd;
                itemImages [i].sprite = itemToAdd.itemImage;
                itemImages [i].enabled = true;
            }
            itemAmountsText [i].text = itemAmounts [i] + "";
            return;
        } else if (items [i] == null) {
            itemAmounts [i]++;
            itemAmountsText [i].text = itemAmounts [i] + "";
            items [i] = itemToAdd;
            itemImages [i].sprite = itemToAdd.itemImage;
            itemImages [i].enabled = true;
            return;
        }
    }
}

public void RemoveItem(Item itemToRemove){
    for (int i = 0; i < items.Length; i++) {
        if (items [i] == itemToRemove) {
            items [i] = null;
            itemImages [i].sprite = null;
            itemImages [i].enabled = false;
            return;
        }
    }
}

public void ClearAllItems(){
    for (int i = 0; i < items.Length; i++) {
        items [i] = null;
        itemImages [i].sprite = null;
        itemImages [i].enabled = false;
        return;
    }
}

[Serializable]
public class InventoryData {
    public Image[] itemImages = new Image[numItemSlots];
    public Text[] itemAmountsText = new Text[numItemSlots];
    public int[] itemAmounts = new int[numItemSlots];
    public Item[] items;

    public InventoryData(Inventory inv){
        items = new Item[numItemSlots];

        for (int i = 0; i < items.Length; i++) {
            inv.items[i] = items[i];
            inv.itemAmounts[i] = itemAmounts[i];
            inv.itemAmountsText[i] = itemAmountsText[i];
            inv.itemImages[i] = itemImages[i];
            }
        }
    }
}

SaveLoadInventory

public static class SaveLoadInventory {

    public static void SaveInventory(Inventory inv){

    BinaryFormatter bf = new BinaryFormatter();
    var createdir = Directory.CreateDirectory(Application.persistentDataPath + "/saves");
    String dir = Application.persistentDataPath + "/saves";
    Inventory.InventoryData data = new Inventory.InventoryData (inv);

    DirectoryInfo dir_i = new DirectoryInfo(dir);
    FileInfo[] info = dir_i.GetFiles("*.inv");
    foreach (FileInfo f in info) {
        Debug.Log (f);
    }

    FileStream stream = new FileStream (dir + "/player" + (info.Length + 1) + ".inv", FileMode.Create);

    bf.Serialize (stream, data);
    stream.Close ();

}

    public static Item[] LoadInventory(){
    String dir = Application.persistentDataPath + "/saves";

    DirectoryInfo dir_i = new DirectoryInfo(dir);
    FileInfo[] info = dir_i.GetFiles("*.inv");
    foreach (FileInfo f in info) {
        Debug.Log (f);
    }

    if (info.Length >= 1) {

        BinaryFormatter bf = new BinaryFormatter ();
        var createdir = Directory.CreateDirectory(Application.persistentDataPath + "/saves");
        FileStream stream = new FileStream (dir + "/player" + (info.Length) + ".inv", FileMode.Open);
        Inventory.InventoryData data = bf.Deserialize (stream) as Inventory.InventoryData;

        stream.Close ();
        return data.items;
    } else {
        return null;
    }
}

I honestly would try some combination of Debugging for this and figure it out myself but it all seems too complicated to wrap my head around and have been worried it wouldn't ever work. If you have any help or suggestions that would be greatly appreciated.

Kith M.
  • 111
  • 1
  • 1
  • 10

1 Answers1

2

but the inventory is always blank when loading.

The first problem is the type of variables you want to serialize in your InventoryData class. You can't seriaize the Image and Text components directly because they are UnityEngine.Object type. For the Image component, save the path of the Sprite the Image component is using. For the Text component, save the value of the .text property that holds the text itself.

If you want to serialize more than one property for the Image or Text component, it is better to create a new serialize-able class/wrapper that will hold important data you want to serialize for the Image component and another one for the Text component.

For example, let's say you want to serialize information about a Text component such as the font size, actual text and the color, here is an example simple wrapper:

[Serializable]
public class TextWrapper
{
    public int fontSize;
    public string text;
    public Color color;

    public TextWrapper(Text text)
    {

        //Get Text Info
        fontSize = text.fontSize;
        this.text = text.text;
        color = text.color;
    }
}

The Text component to serialize:

public Text myText;

You can create new instance of TextWrapper from the Text component to serialize:

TextWrapper textWrapper = new TextWrapper(myText);

Now, you can serialize it with the BinaryFormatter in your question. You can put the TextWrapper variable in your InventoryData class and that should serialize too.

Note that TextWrapper must be put in its own .cs file otherwise BinaryFormatter may file to serialize/deserialize it. If you still have problems using ..just use Json. See this post of more information.

Programmer
  • 121,791
  • 22
  • 236
  • 328