Saving and loading a ton of variables, c#

I am creating a game similar to fire emblem. I have a script that I attached to all of my player prefabs that I can edit all of the variables in in inspector. I want to be able to save and load the variables such as stat points and level and assign them to the correct entity of the “CharacterSheet” script. there are going to be about 12 variables to be saved per character and about 40 characters. So in total I need to save and load up to 500 variables and load them to the correct script.

Character sheet script for reference:

using UnityEngine;
using System.Collections;

public class CharacterSheet : Character{

    public string characterClass;

    public int strength
    {
        get { return CurrentClass.Strength + baseStrength; }
    }
    public int magic
    {
        get { return CurrentClass.Magic + baseMagic; }
    }
    public int speed
    {
        get { return CurrentClass.Speed; }
    }
    public int agility
    {
        get { return CurrentClass.Agility + baseAgility; }
    }
    public int defense
    {
        get { return CurrentClass.Defense + baseDefense; }
    }
    public int luck
    {
        get { return CurrentClass.Luck + baseLuck; }
    }
    public int health
    {
        get { return CurrentClass.Health + baseHealth; }
    }


    void Start(){
        if (characterClass == "FighterClass") {
            CurrentClass = new FighterClass ();
        } else if (characterClass == "MageClass") {

        } else if (characterClass == "ArcherClass") {

        } else if (characterClass == "SpearmanClass") {

        }

        //current level and exp
        level = 1;
        exp = 0;
        neededExp = 100;

        //Testing if variables are being assigned and working
        Debug.Log (characterName);
        Debug.Log (CurrentClass.ClassName);
        Debug.Log (CurrentClass.ClassDescription);
        Debug.Log (CurrentClass.ClassWeaponType);
        Debug.Log (CurrentClass.ClassStrength);
        Debug.Log (CurrentClass.ClassWeakness);
        Debug.Log (strength);
        Debug.Log (magic);
        Debug.Log (speed);
        Debug.Log (agility);
        Debug.Log (defense);
        Debug.Log (luck);
        Debug.Log (health);

        AddExp (10000);

    }
    //Calculates and determins if this character levels up and how many times they do when exp is given.
    public static void AddExp(int EXP){
        exp += EXP;
        Debug.Log ( " gained " + EXP + " EXP!");
        while (exp >= neededExp) {
            level ++;
            Debug.Log(" leveled up to " + level);
            exp -= neededExp;
            neededExp += 50;
        }
        Debug.Log (exp);
        Debug.Log (neededExp);
    }

}

What the inspector looks like:
2607364--182768--Screenshot 2016-04-23 10.29.20.png

Have you taken a look at the BinaryFormatter? I suppose it would work well here.

Check out the Unity tutorial here.

Further to the above - you could use the XmlSerializer. Bang all your “CharacterSheets” into a collection and use the xmlserializer to save the whole thing.

Currently I am trying to do BinaryFormatter but I am not sure as to how to grab and assign variable to the correct entity of the script between saving and loading. I cant just say “playerdata.exp = charactersheet.exp” for saving and “charactersheet.exp = playerdata.exp” for loading. Becasue there will be almost 40 different entity’s of “charactersheet”, it will be very hard to reference each of the 40 prefabs and save/load up to 12 variables to each prefab.

How could I? all of the character sheets are named “characterSheet” and all I do is attach it to a object and assign variables in the inspector.

Why can’t you mark the class with Serializable property? That’s what you would use with the BinaryFormatter

How would that work though. let me give an example. I have 3 characters with the CharacterSheet script on them and they all have different values stored in each variable(Example: Character 1 HP: 5, Character 2 HP: 7, Character 3 HP: 11) If I put [Serializable] at the top of the CharacterSheet script, would it save all 3 variables and load them to their respective entity of that script or will it jumble all the numbers up and apply the same variable to all the scripts(Example: Character 1 HP: 5, Character 2 HP: 5, Character 3 HP: 5) .

If you want to go down the xml route - put your characters into a List and call the below to save to disk.

public void SaveCharacters(List<CharacterSheet> characters, string filename)
{
    using (StreamWriter writer = new StreamWriter(Path.Combine(Application.persistentDataPath, filename + ".xml")))
    {
        XmlSerializer serialiser = new XmlSerializer(typeof(List<CharacterSheet>));

        serialiser.Serialize(writer, characters);
    }
}

So I would just put all of my prefabs in a list then save it and load them from the saved list whenever I need them?

Yeah just save the scripts assigned to them

Okay I have the code but where to I put the prefabs? do I need to create another list that appears in the inspector?

those are Models in MVP pattern, (Object that holds data configuration and no logic)

luckily, Unity has a built-in class called “Scriptable Object”,

Also I am getting an error:
InvalidOperationException: To be XML serializable, types which inherit from IEnumerable must have an implementation of Add(System.Object) at all levels of their inheritance hierarchy. UnityEngine.Transform does not implement Add(System.Object).

When you re-instantiate an entity from a save file, you’ll be loading up the saved character sheet data back into the entity, as long as that’s how it was serialized to the file. I’d like to know some reasons why you’d get “jumbled” numbers. One way I can think of is if you use a Dictionary or Set or something, since the order can’t be guaranteed. In this case, you should have at least some unique identifier for the character and its associated character sheet.

There is a string where I assign the characters name in the inspector. would that work as an identifier?

As long as it’s unique. Why not? One reason I can think that they might not be unique is NPCs. If you have a generic NPC, you could have them numbered or something. NPC01, NPC02, etc. The key is to make them unique. You’ll hear that a lot when identifying your item data. Unique Identifiers and Globally Unique Identifiers (guids), etc. This allows you to, well, identify any item in your game. This is especially useful when saving/loading. Because you can’t save references to file. Well, you can, but they won’t mean anything when you deserialize it. But you can save ids to reference an entity to its various data that its related to.

Oh, and one more step to be more pro, is it’s better to store unique ids as integers, rather than names. Storing names will eat up memory and disk usage, and is more error prone if the serialization process resolves the strings to variable length encoding. Better to serialize ids, and then map the ids to names in a different object.

Presumable CharacterSheet inherits from monobehaviour at some point - you don’t want to serialise the whole unity gameobject as it’ll be massive. Instead create a model (just a class) that contains the properties you need to save.

Alright. So any suggestions on how to ID things? If I am using Integers, how would I be able to tell the difference between a character, NPC, Enemy, Weapon, and item? Also how would I keep track of what has what ID?

So I would have to change how I inherited things?

public abstract class Character{

    public ICharacterClass CurrentClass;

    public string characterName;
   
    public static int level;
    public static int exp;
    public static int neededExp;

    public int baseStrength;
    public int baseMagic;
    public string baseSpeed = "DO NOT CHANGE";
    public int baseAgility;
    public int baseDefense;
    public int baseLuck;
    public int baseHealth;
}
public class CharacterSheet : Character{

    public string characterClass;

    public static bool alive = true;

    public static bool characterActive = false;

    public int strength
    {
        get { return CurrentClass.Strength + baseStrength; }
    }
    public int magic
    {
        get { return CurrentClass.Magic + baseMagic; }
    }
    public int speed
    {
        get { return CurrentClass.Speed; }
    }
    public int agility
    {
        get { return CurrentClass.Agility + baseAgility; }
    }
    public int defense
    {
        get { return CurrentClass.Defense + baseDefense; }
    }
    public int luck
    {
        get { return CurrentClass.Luck + baseLuck; }
    }
    public int health
    {
        get { return CurrentClass.Health + baseHealth; }
    }


    void Start(){
        if (characterClass == "FighterClass") {
            CurrentClass = new FighterClass ();
        } else if (characterClass == "MageClass") {

        } else if (characterClass == "ArcherClass") {

        } else if (characterClass == "SpearmanClass") {

        }
    
        //current level and exp
        level = 1;
        exp = 0;
        neededExp = 100;

        //Testing if variables are being assigned and working
        Debug.Log (characterName);
        Debug.Log (CurrentClass.ClassName);
        Debug.Log (CurrentClass.ClassDescription);
        Debug.Log (CurrentClass.ClassWeaponType);
        Debug.Log (CurrentClass.ClassStrength);
        Debug.Log (CurrentClass.ClassWeakness);
        Debug.Log (strength);
        Debug.Log (magic);
        Debug.Log (speed);
        Debug.Log (agility);
        Debug.Log (defense);
        Debug.Log (luck);
        Debug.Log (health);

        AddExp (10000);

    }
    //Calculates and determins if this character levels up and how many times they do when exp is given.
    public static void AddExp(int EXP){
        exp += EXP;
        Debug.Log ( " gained " + EXP + " EXP!");
        while (exp >= neededExp) {
            level ++;
            Debug.Log(" leveled up to " + level);
            exp -= neededExp;
            neededExp += 50;
        }
        Debug.Log (exp);
        Debug.Log (neededExp);
    }

}

Just make another object which contains the properties you need to save, then when you want to save make an instance of it and copy values from CharacterSheet to it.