Non-persistent Dialogue System and saving

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
urrmurrmur
Posts: 60
Joined: Wed May 05, 2021 1:57 pm

Non-persistent Dialogue System and saving

Post by urrmurrmur »

Hi,

I'm currently considering my options for setting up a save system for my game, and would like some advice.

My game is set up with a separate database for each scene, plus a master database which is loaded in every scene. This works fine as long as no saving / loading is needed. Everything that needs to be transferred between scenes is in the master database, all the rest is just loaded along with the scene. Nothing in my game is persistent at the moment, nothing gets transferred between scenes.

Of course, if the user can save and reload the game at any time, the data in my scene-specific databases also needs to be saved somehow. I can think of a hundred ways to approach this, and I've done some reading around the documentation, but I'd like your opinion before making any decisions.

I had a smaller project that used DSFU before, where I set up my own basic save manager that uses

Code: Select all

string s = PersistentDataManager.GetSaveData();
PersistentDataManager.ApplySaveData(s);
Which worked fine, though that project only used a single database. I was considering something similar now, but with one save file per database. That way I can just apply the save data from the current scene, plus the master database, upon scene load. However, I have the impression that this is a nonstandard approach, and that there are no methods to get or apply save data on a per-database basis.

I could of course use the built-in save system, but I gather from the documentation that this doesn't play well with multiple databases:
<The initial database> should include everything that needs to be in a saved game
This implies that everything that's not in the initial (master) database doesn't get saved.

Of course, the nuclear option is to get rid of my multiple databases altogether and just merge everything. Either by making one big database file, or by loading all databases in every scene. In the latter case using GetSaveData may work - though I'm not sure. The save data only seems to contain variable names, not ids, so I don't know what would happen if the same variable name was used in multiple scenes.

Any ideas / opinions? What would you recommend?
User avatar
Tony Li
Posts: 23359
Joined: Thu Jul 18, 2013 1:27 pm

Re: Non-persistent Dialogue System and saving

Post by Tony Li »

Hi,

Sorry if the documentation is unclear. It's fine to use the save system with multiple databases. Some tips:

1. Set a Base ID for each database (e.g., 10000, 20000, etc.) so they're more likely to keep their internal IDs unique from each other.

2. Use the Unique ID Tool at least once to make sure IDs across your databases are unique. Technically if you have a master database and a scene-specific database that's only loaded in the scene, you only need to ensure that each scene's scene-specific database's IDs are different from the master's. In this scenario, it's okay for one scene's database IDs to be the same as another scene's database IDs.

3. Use an Extra Databases component to load the scene-specific database at runtime. When an extra database is loaded at runtime like this, it's temporarily merged into the Dialogue Manager's masterDatabase. It's the masterDatabase that the save system saves, not the Initial Database assigned to the Dialogue Manager.

4. Set the Save System component's Frames To Wait Before Apply Data to 1 so that it waits 1 frame for the Extra Databases component to load the scene-specific database into the masterDatabase.
urrmurrmur
Posts: 60
Joined: Wed May 05, 2021 1:57 pm

Re: Non-persistent Dialogue System and saving

Post by urrmurrmur »

Sorry for the thread necro. I put this aside for a while and just came back to it.

The system as described doesn't work, I believe. Let's take a simple example, where I have three databases, each with a single variable.

Master DB (loaded in each scene)
name: master
id: 0
variable: id: 1, name: var_a, val: true

Scene 1 DB (only loaded in scene 1)
name: scene1
id: 10000
variable: id: 10001, name: var_b , val: false

Scene 2 DB (only loaded in scene2)
name: scene2
id: 20000
variable1: id: 20001, name: var_c, val: 42



Now, if I set up the system as you described, where the master DB is loaded in each scene, and the other DBs are loaded using an Extra Databases component, I get the following behaviour:
  • I save the game in scene 1. This results in a save file that contains the current value for var_a and var_b. var_c is not saved yet. Makes sense, since it is not currenty loaded into the database and never has been before.
  • I switch to scene 2, and save the game again. Now the scene 1 DB is no longer loaded, but the scene 2 DB is. This results in an overwritten save file that contains the values of var_a and var_c. My save file has lost the information of var_b, since this variable is not loaded at the time of saving, and the save just overwrites the previous file instead of trying to merge the two.
Obviously this is unintended behaviour from my POV, since I never have a save file that contains all my information.

Alright, so what if I make sure that ALL my DBs are loaded in every level? Well, then it works fine. Except if I decide to add a new variable to the scene 2 DB and call it var_b (with id 20002). Because not my merged DB contains two variables with the same name (var_b). Sure enough, both these variables have a unique id, but as far as I can see these id's are not saved anywhere in the save file - only the variable names are. So I end up with a save file that has duplicate variable names, and I have no idea which one will be loaded when requested.


Am I missing something? Because it seems like neither approach will behave correctly. Separating the DBs causes some data to be lost at save time, and merging them causes ambiguitiy in the save file if I have identical variable names over multiple DBs.
User avatar
Tony Li
Posts: 23359
Joined: Thu Jul 18, 2013 1:27 pm

Re: Non-persistent Dialogue System and saving

Post by Tony Li »

Hi,

Since it's functioning exactly as designed and as you described above, let's come up with an approach that works for you. How about if you put all of your variables in the Master DB, and sync them to the other DBs? This gives you a single, authoritative, and unique list of variables.
urrmurrmur
Posts: 60
Joined: Wed May 05, 2021 1:57 pm

Re: Non-persistent Dialogue System and saving

Post by urrmurrmur »

Aha, I didn't realize this was the intended behaviour, I assumed the save game was supposed to store everything.

I think I can work around it then. I've already set up the system in such a way that variables that are needed in multiple scenes are stored in the master DB. Which means the only time I'll run into a problem, is if I revisit an earlier scene (e.g., with a scene sequence like A -> B -> A). In that case I'd have to recall the earlier state of scene A, which might have variables stored in the scene-specific DB because it's not data that is necessary in multiple scenes.

However:
  • I don't have many scenes like that, and I was considering redesigning them anyway so B becomes a subscene of A.
  • If I do end up keeping scenes that need to be visited twice, I can just transfer the necessary variables to the master DB, as you suggested.

I have a small unrelated question about the save system though. I'm using an empty GameObject called "PersistentRoot" that I use as the parent object of all my gameObjects that need to persist throughout different scenes. The parent object has a script that essentially just makes it DontDestroyOnLoad. My SaveController object, which contains a number of components, including the DSFU SaveSystem, JsonDataSerializer and DiskSavedGameDataStorer, is a child of this PersistentRoot object.

However, since the DSFU SaveSystem is itself DontDestroyOnLoad, it gets unparented from the PersistentRoot object when running the game. Do you know of a way to remedy this? No big deal if not, everything functions, it's just a bit annoying that it breaks my hierarchy.
User avatar
Tony Li
Posts: 23359
Joined: Thu Jul 18, 2013 1:27 pm

Re: Non-persistent Dialogue System and saving

Post by Tony Li »

Hi,

You're only supposed to call DontDestroyOnLoad on root objects, which is why the Dialogue Manager makes itself a root object if you tick Other Settings > Don't Destroy On Load. Since you're already calling DontDestroyOnLoad on its parent, you can UNtick the Dialogue Manager's checkbox.

For your variables, if you keep your master variables in the master DB and never unload the master DB (i.e., assign it to the Dialogue Manager's Initial Database field), then they'll always be present and will always be saved and restored.
Post Reply