• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GML Best way to manage a save system

Whenever I add a new level to my game I dread doing so because my save system is so convoluted. I'm sure there must be a better way than just creating a different variable for every single I save, but never bothered until it gradually became a problem.
Now I'm about to add 30 new levels on top of the existing 30 levels in my game and I want to rewrite my save system otherwise I'll have 60 lines of stuff like this:
ini_write_real("Scores", "PScore", global.scorePdisp ); //score
ini_write_real("Scores", "PScoreH", global.scorePdispH ); //hard mode score
ini_write_real("ScoresK", "KPScore", global.scorePdispK ); //keyboard?
ini_write_real("ScoresP", "PPScore", global.scorePdispP ); //Pasifist?
ini_write_real("ScoresT", "TPScore", global.scorePdispT ); //Time
ini_write_real("ScoresT", "THPScore", global.scorePdispTH ); //Time Hard
in the save screen, load screen, and everywhere else in the game that uses this data.
JSON is the first thing I find when googling ,it looks good to me.
Before I undergo cleaning up all this code I was wondering-
What do you think is the best way to manage save system?
Is there a flat out best way or do you uses different systems based on the needs of your game?
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
In general, I've found that using a DS map is the best way to go when saving information of the type you show above. Simply create a global DS map and then add the keys much as you have to the ini. The benefit of this is that you don't need to constantly keep opening and closing the file, as the map data can be accessed at any time and only saved when it has been changed. Saving is flexible too, as you can convert the map to JSON if required, or write it out as a string (ds_map_write) and then save it to a text file or whatever.
 

Rob

Member
I think you've got a "Data Management" problem rather than a save-system problem and the issues you're having are a symptom of the problem.

I'm guessing but are you having different variables in every level or something?

Using an array/list to store your data would allow you to manipulate it a lot more easily (eg 1 For statement to loop through all of the data stored in the array).

I use .ini to save if I can but I've recently had to learn to use Json because the amount of data I need to store well exceeds the limit that even multiple .ini files can store.

.ini is easier to use and understand (in my opinion) so stick with it if you use it already, just have a better way of storing and accessing the variables you want to save.
 
One way to store simple data for saving is to use an enum and an array.

The benefit of this is as you add more data to the array, you just need to update the enum and its also human readable in code, without having to modify the load and save routines.

When you need to add a new item, just insert it before MAX at the end of the enum.

Code:
// Declare enum at start of game
enum Scores
{
    PScore,
    PScoreH,
    KPScore,
    MAX
}

// Create the array / assign data to array
score_data[Scores.PScore] = 100;
score_data[Scores.PScoreH] = 20;
score_data[Scores.KPScore] = 88;

// Array Saving
ini_open("score.ini")
for ( var i = 0; i < Scores.MAX; ++i)
{
    ini_write_real("Scores", string(i), score_data[i])
}
ini_close()

// Array Loading
ini_open("score.ini")
for ( var i = 0; i < Scores.MAX; ++i)
{
   score_data[i] =  ini_read_real("Scores", string(i), 0)
}
ini_close("score.ini")
For complex saving of multiple variables in instances, I use JSON.

I used the following post as a starting point:

https://forum.yoyogames.com/index.php?threads/saving-an-entire-room-while-ingame.14708/#post-98157

What I did was have an primary parent object, let's call it o_save_me, so that I could just do with (o_save_me) { Saving Code }, then any object with o_save_me as a parent would be saved.

Additional unnecessary info in spoiler:
I've been thinking that you could automate this further with GMS 2, as it has the functions variable_instance_get_names(), which lets you get all the names of an instance, or all the global variable names. (See the manual page for an example)

With this, you could just do a with(all) and save all the variables of every instance (but this might be overkill if you really only need the position and health of an enemy for example).

Edit: One more thing, I would create a script to stream line changing the score value.

Script score_increase(score_enum, amount)
Code:
/// @arg score_type
/// @arg amount

var _score_type = argument0
var _amount = argument1

global.score_data[_score_type] += _amount
This way, in your code you just write:

Code:
score_increase(Scores.PScore, 10)
If you later decide to change storing the score in an array to a ds_map, you can do so easily by just changing a single script, instead of having to update all the places in your code where you modified the score.
 
Last edited:

NightFrost

Member
I'd echo the sentiment about data management problem. Why do you need to save and load constantly? Why do you need to rewrite that code into every screen that uses the data instead of using one script to save and one script to load? If you have generic settings, they should be loaded once at game start (after variables have been filled with default values), and saved when a setting is changed. If you have savestates of game progress, there only should be need to load them once when the player wants to proceed from that save.
 

Joe Ellis

Member
I've made an entire system for handling variables of different types, called "tables", each instance has one or more tables,
a table is a 2d array which contains n number of variables, slot [0, i] holds the name of each variable, slot 1 holds the value, 2 holds the "type" which is an enum index, and 3 holds the text, which is interpreted into the value -using an interpreter script indexed by the type index,
It took quite a while to set up, but now all I have to do when I want to save a table is: table_save(table, buffer_id).
Saving a table basically saves each variable name and the text that is used to make the value, then when loading it loads each text and interprets them into the actual variable values.
You might not need this level of complexity or versatility, I've made this so that everything is editable in my editor, and it might not be needed if your just saving progress in a level or something,
Maybe you could make a separate save script for each object type, and loop through them with "with all" or maybe a more structured order, but in theory you should be able to save every instance's variables and then recreate the instances and load all their variables, unless some of the variables are links to an array, then it'd get complicated
 
Thank you guys so much for all the helpful advice I'll update when I've finished my save file. Since I'm doing a big overhaul it makes me feel much better having such good advice and different perspectives on how to handle organizing the data.

I want to clarify I only load data once at the beginning and then save when I update. I'm sorry for making it sound otherwise. What I meant is the code in the game gets very long in places where things are referenced because everything has a unique variable name. The game was going to originally have only a few levels I wanted to easily be able to debug and as the game kept growing in size I never looked into something better until now.
 
Top