0
\$\begingroup\$

Imagine 50 instances of one type of object and 25 instances of another. Both types of object needs to remember a simple Boolean or int for their own purposes that can be saved to file and reloaded. For the life of me, I cannot find any help on the interwebs regarding the best way to do this. I already know and understand how to use serialization and deserialization, but I cannot figure out how to organize this. I obviously don't want 75 save files but I can't think of a good way to combine their data to one save file--especially since not everything is serializable. Any help??

\$\endgroup\$
  • \$\begingroup\$ Please clarify your question so that we can help you. Which programming language / engine are you using? What sort of objects do you want to save, and how are you trying to do it? What's the problem you are trying to solve - you don't want to have 75 save files? Why don't you just write it into one file? \$\endgroup\$ – jens108 Jun 11 '17 at 14:34
  • \$\begingroup\$ I tried being more descriptive before but got ignored so I tried to cut to the chase this time. As mentioned with example, I'm trying to save a bunch of booleans and ints throughout the game on different objects without each one writing their own file. I'm not sure of a good strategy, in Unity with C#, to have one object reference such a bool as can be saved in one file with a bunch of other bools. I'm looking to attach a script to an object and, in the inspector, say "use and save this bool from THE save file" while selecting a different one for another object with the same script. \$\endgroup\$ – CodeMonkey Jun 11 '17 at 16:31
  • \$\begingroup\$ It's still unclear what you are looking for. Do you know JSON? It looks like you would need to simply make 1 object containing all your data and then convert this object to a JSON string. You would only have one save file and a JSON deserializer would convert that string back to an object on loading. \$\endgroup\$ – Cedric Martens Jun 12 '17 at 17:14
  • \$\begingroup\$ The problem is that I have many objects with the same code which need to dynamically reference a different variable of the "one object" you're referring to. It's all good though. I figured out a method which I'll write up in a bit. \$\endgroup\$ – CodeMonkey Jun 13 '17 at 12:10
0
\$\begingroup\$

After weeks of trying to figure out the best way to save data that is spread out in a ton of objects, I've finally come to a good solution! I've seen lots of other people ask a similar question yet they all remain unanswered for some reason. Hopefully this helps!

First, I created a new data type I called SaveVar. If I want something saved, I use a SaveVar. I made it a template so I could use it for multiple data types. I have to imagine something this basic already exists, but I don't know what it is. The reason I created this new type is so that it can be passed, stored, and monitored as a reference in a SaveData dictionary.

[System.Serializable]
public class SaveVar<T>
{
    T val;

    public SaveVar(T v)
    {
        val = v;
    }

    public T get()
    {
        return val;
    }

    public void set(T v)
    {
        val = v;
    }
}

So once I have a SaveVar anywhere I want in the code, I can "register" it to my save data so that it can be saved and recalled at load. I register my SaveVar with a unique string ID that I can set in the inspector (i.e. "Dungeon1_Room8_Door2"). The door will register that string with an instance of a SaveVar which will be stored in a serializable Dictionary. I couldn't find a way to use only one dictionary and I couldn't seem to create functions that would allow all types of SaveVar. So for now I'm creating unique functions for each type of SaveVar I want to save. Almost defeats the purpose of the template. If someone knows a better way, by all means let me know :-).

[System.Serializable]
public class AllData
{
    private Dictionary<string, SaveVar<bool>> bools = new Dictionary<string, SaveVar<bool>>();
    private Dictionary<string, SaveVar<bool>[]> boolArrays = new Dictionary<string, SaveVar<bool>[]>();

    public void registerBool(string s, SaveVar<bool> sv)
    {
        // if upon registering we find that it exists already (i.e. was loaded) then grab the value and put it in the SaveVar passed in.
        if (bools.ContainsKey(s))
        {
            sv.set(bools[s].get());
            bools[s] = sv;
        }
        else
        {
            bools.Add(s, sv);
        }
    }

    public void registerBoolArray(string s, SaveVar<bool>[] sv)
    {
        // if upon registering we find that it exists already (i.e. was loaded) then grab the value and put it in the SaveVar passed in.
        if (boolArrays.ContainsKey(s))
        {
            SaveVar<bool>[] ba = boolArrays[s];
            for (int i = 0; i < ba.Length; i++)
            {
                sv[i].set(ba[i].get());
            }
            boolArrays[s] = sv;
        }
        else
        {
            boolArrays.Add(s, sv);
        }
    }
}

So my AllData class now contains all the data within my game that I want to save. When I register my SaveVar, I'm effectively loading it as well. So right after registering, I just check its value and "unlock" the door if it is true. When the door unlocks, it will change the value of SaveVar which is already registered so, upon saving, it will already have the updated value. All that's left is the actual saving it and loading it.

Save (upon some event):

    Debug.Log("Saving SaveData");
    BinaryFormatter bf = new BinaryFormatter();
    FileStream file = File.Create(Application.persistentDataPath + "/SaveData.dat");
    bf.Serialize(file, data);
    file.Close();

Load on Awake in a SaveController MonoBehaviour:

    if (File.Exists(Application.persistentDataPath + "/SaveData.dat"))
    {
        Debug.Log("Loading SaveData");
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Open(Application.persistentDataPath + "/SaveData.dat", FileMode.Open);
        data = (AllData)bf.Deserialize(file);
    }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.