# How to Make Saving System Serializable

Hello I’ve been working on a save/load system for my RPG inventory, and I was wondering whether there was a way to make the script use Serialization instead of PlayerPrefs, because I want the player to be able to access their save file. The main issue I run into with this code is how it mixes up the same variable in different itemHolders, causing duplication. Also, I heard that PlayerPrefs is better used for settings or preferences. Here’s my script:

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

public class ItemInformation : MonoBehaviour
{
// These are the assets for the item to change
public Text nameText;
public Text descriptionText;
public Text regenText;
public Text amountText;

// This is the identifier for each item
public string identifier;

// These are the variables that change with the different items
public string itemName;
public string itemDescription;
public float itemRegeneration;
public int itemAmount;

// Starts on awake
void Awake()
{
// Function to change the object's information and such
nameText.text = itemName;
descriptionText.text = itemDescription;
regenText.text = "HEALS " + itemRegeneration + "HP";

}

void Update()
{
amountText.text = "HAVE:" + itemAmount;
}

private void SaveData()
{
string jsonString = JsonUtility.ToJson(this);
PlayerPrefs.SetString(identifier, jsonString);

// Creates file to store variables
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/InvData.dat");
SaveData data = new SaveData();

// Gets the player data
data.itemSave = myItemAmount.itemAmount;

// Writes player data to file and encrypts it
bf.Serialize(file, data);
file.Close();
}

{
{
string jsonInstance = PlayerPrefs.GetString(identifier);
JsonUtility.FromJsonOverwrite(jsonInstance, this);

// Extracts the data from the binary file and reads it
BinaryFormatter bf = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/InvData.dat", FileMode.Open);
SaveData data = (SaveData)bf.Deserialize(file);
file.Close();
myItemAmount.itemAmount = data.itemSave;
}
else
{
SaveData();
}
}
}

// Holds data that is to be saved
[Serializable]
class SaveData
{
// Variables for save file
public int itemSave;
}

• Presumably you considered making a [System.Serializable] container for your save data, and using one of the available serialization libraries to convert it into a text or binary file to write to disc with System.IO? Where specifically did you run into trouble that we can help you solve? Jan 18 '21 at 18:03
• @DMGregory Yes, I originally had one of those and a System and System.IO, but whenever I tried to save the file somewhere, it wouldn’t save into the Appdata folder. Also, I couldn’t load in the information. Jan 18 '21 at 18:05
• Want to edit your question to show that? You were using Application.persistentDataPath, yes? Jan 18 '21 at 18:07
• @DMGregory Ok, I added it in. Jan 18 '21 at 18:15

1. Don't make this a MonoBehaviour. You don't want to mix actual serialized fields and save data. The references won't serialize right. (If you do need to save references to assets, you'll need to figure out the Addressables system, but you don't need that here.)

2. Have one root object that points to the entire set of save data. That way it all goes into the same file.

Here's the gist of the pattern I usually use.

try {
// avoid collisions with other persistent files
string saveFolder = Path.Combine(Application.persistentDataPath, "SaveData");
Directory.CreateDirectory(saveFolder);

string path = Path.Combine(saveFolder, filename);
using (var file = new File(path, FileMode.Create)) {
string jsonString = JsonUtility.ToJson(this);
file.Write(jsonString);
}
return true;
}
catch (Exception e) { // IO can throw all sorts of weird exceptions, for instance Path.Combine can throw ArgumentException
Debug.LogError("Failed to write save data.");
Debug.LogException(e);
return false;
}

• Ah, you changed the question. The answer in this case is that BinaryFormatter isn't a Unity class. You can still use JsonUtility with files as shown here. If your save file ever gets too big for JSON, you can first try using a GzipStream to compress it, and if it's still too big, you can find a Unity plugin to do the serialization or write your own serializer. Jan 18 '21 at 18:24

Here is a basic example for converting an Item/ Spell/ YouKnowWhat to an json string that you could later save plainly if you want user be able to easily edit it (or as binary file if you want to make it harder for them). I'm using a Spell as example.

First we have a helper for loading and saving. The annotation above From and To allows you to execute the methods from the editor.

public class JSONHelper : MonoBehaviour
{
public Inventory myInventory;
public string json;

public void FromClassToJson()
{
json = JsonUtility.ToJson(myInventory);
Debug.Log(json);
}

public void FromJsonToClass()
{
myInventory = JsonUtility.FromJson<Inventory>(json);
}
}


Now we need an actual Inventory that we can save.

[Serializable]
public class Inventory
{
public Item[] items;
}

[Serializable]
public class Item
{
public string itemName;
public ItemType itemType;
public int amount;
}


The example uses a custom ItemType to show that it does not just need to be strings or ints but can be a class as well.

[Serializable]
public class ItemType
{
public EquipSlot slot;
public Category itemCategory;
}


And enums, enums are great for things you use often (they kinda a string) but you can't spell them wrong.

public enum Category
{
WEAPON, QUEST_ITEM, CONSUMABLE, ARMOR
}

public enum EquipSlot
{

Enums are identified by an int value internally that's why you see "slot":0. Don't worry about that, the parsing from json is giving you the HEAD back. This just gives a brief example, how you structure your item or what counts as an item is something you need to figure out based on the needs of your game.