Some organisation about data persistence

Hello forum !
I have looked a bit and couldn’t find a post about my particular problem, although i’m pretty sure it is a common interrogation for beginners.

In my project i have to pass data between two scenes, for that i’m using the classic and very good tutorial here.
However, in my project i have different managers(emptys) that handles main values through specific scripts (ressourcesManager/CharactersManager etc…)
One for ressources that will contain my ressources/objects/items etc… One for my characters that’ll handle my characters stats skill levels health …one for the time season day… and so on.

The problem i have is this one:
When i’m about to switch to a new scene, i need to save all my data to a data file and load that data file into the new scene; But all my variables are scattered among many scripts(i try to keep them all in the managers script and none in other scripts (for that i just use GetVariable() methods so i keep everything organized in the managers only)).
Do i need to make a method that will get all the variables in the managers scripts, to a DataManager script and then save it to the file ? and then when i load it send back one by one all the variables to each managers scripts ?

something like:

GetAllData(){
ressourcesData = ressourcesManager.GetData();
characterData = characterManager.GetData();
seasonsData = seasonsManager.GetData();
}

Then when i’m in the new scene:
LoadDataBack(){
ressourcesManager.LoadData(ressourcesData);
charactersManager.LoadData(characterData);
seasonsManager.LoadData(seasonsData);
}

I know this above is not accurate(C# speaking) but you get the idea :p.

I know, from the data persistence tutorial how to send and get back a data file, but i’m more concerned about how to organize my data/variables in my scene, managers and scripts so i can efficiently get it and move it around between scenes.

Also, how do i manage Json data betwen scenes ? do i need to pass it through a datafile like this ? or is it already persistent between scenes ?(i just thought about this one but i’m pretty sure i can find an answer in the forum.

Thanks!
ps: sorry 'bout my english :p.

Personally, I would have all the save data in one class, which would probably be a static singleton. So when you need it, you just call SaveData.instance.variable from anywhere, or use getters and setters, or have a method to change it, depending on the size of your project. There are tutorials on using singletons on youtube. For scenes, I would make it DontDestroyOnLoad, so you only have to bother saving when the game is quit.

1 Like

Hey! Thanks for your answer :wink:

It’s not my first project so i have quite a few variables i need to handle;
I haven’t checked singleton yet, but i’ll definitely check them now.
So the idea is to basically have all my variables in one script using singletons, then when i need to use/modify the variable i use get/set methods. So i won’t have to pass anything or save anything between scenes, just DontDestroyOnLoad
something like :

//This is from the tutorial, and from what i understood i need to put a GameControl object with that script on it on every scene.

public static GameControl control;
    void Awake () {
        if(control == null){
            DontDestroyOnLoad(gameObject);
            control = this;
        }
        else if(control != this){
            Destroy(gameObject);
        }         
    }
//Save function
//load function

Will this be a problem when saving classes and array of classes ?
It seems a great idea, and easier to manage if all of my variables are in one script.
But is it not too costly if i have to access the static class each time just to get a variable ?

I’ll check singletons anyway and get back here when i know more about this ;).
Thanks!

Okay, i’ve checked singletons, seems a very powerfull tool and i’ll now change all my code to match this logic :p.
I’m probably going to have some problems when trying to make the changes so i’ll let this post open… :wink:
Thanks :wink:

Ok, so the way i’m doing this, is like that :

My character script :(i cut out the unecessary parts)

public class CharacterManager : MonoBehaviour {

    private string charactersPath = "/Data/CharactersJson.json";
    private Character[] characters;
  
    public void LoadData(){
        string filePath = Application.dataPath + charactersPath;//Application.dataPath links to the Assets Folder
        if (File.Exists(filePath))//File.exists check if a file exist, takes a file path as component
        {
            string dataAsJson = File.ReadAllText(filePath);//All the data is transfered to dataAsJson
            dataAsJson = "{\"Items\":" + dataAsJson + "}";//adds --{"Items"}:-- at the begining of the filess
            characters = JsonHelper.FromJson<Character>(dataAsJson);
        }
    }

    public void Initialize(){
        LoadData();
        Manager.instance.characters = characters;
    }

I create everything in the specific managers scripts, then send everything at start(initialize for me) to the main Manager class, which is :

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

public class Manager : MonoBehaviour {
    public static Manager instance = null;
    public Character[] characters;
    public Ressource[] ressources;
    ...//All my variables of my game;


    void Awake () {
        if(instance == null){
            DontDestroyOnLoad(gameObject);
            instance = this;
        }
        else if(instance != this){
            Destroy(gameObject);
        }
        Debug.Log("characters");      
    }

    public void Save(){
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "/playerInfo.dat");
      
        GameData data = new GameData();
        //data.health = health;
        //data.experience = experience;

        bf.Serialize(file, data);
        file.Close();
    }

    public void Load(){
        if(File.Exists(Application.persistentDataPath + "/PlayerInfo.dat")){
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.persistentDataPath + "/PlayerInfo.dat", FileMode.Open);
            GameData data = (GameData)bf.Deserialize(file);
            file.Close();
        }
    }
}

It’s just weird to have so many variables in one script, like, every variable of the game :/.
Is this the correct way ?

I would be careful with singletons. I am surprised others have not already brought up things like IOC or how singletons are evil.

Singletons have their place. But they are not the best answer to eveything.
So make sure you understand their power and the problems they can cause before you go and change eveything to use singletons.

Then when you do use them have a clear design and purpose for them.

1 Like

About your variables question. To the CPU it doesn’t really matter where they are one class or 50 classes.
It’s just memory locations. So don’t worry about acces times etc.

What’s important is how you work with them. And the readability or usefulness of the code.
So it could be fine to have lots of variables all on one class. But if it contains data for 99 levels but you only ever need one level’s data at a time. Then it is probably a bad design.

Or the same you have to load every character in your game into memory even if you only ever need one a time.
But you will have to evaluate based on your code and design.

1 Like

Disclaimer here, I write small games and don’t have to save much data. So, really, I don’t know how it scales up. It works for me.

Thanks for thoses precisions daciongmao. I have indeed seen some controversial ideas about singletons, so i’ll do some digging ;).
Since it’s my first “big” project, and that i have still a lot to learn about coding, i’m just getting too concerned about optimizations and what’s the best way to do some things, i now have to deal with much more scripts, objects, data etc and the organization of the whole project is kind of scary. This is why singleton and the idea of having all my variables in the same place and accessible the same way is really tempting ;).
Thanks again .