• 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!

Reading a nonexistent value as "true"

G

Gabriel

Guest
I just released a new update for my game and it includes a new boolean global variable to define if a new function is on or off.

Once the update is installed, I want that variable to be "true" by default, but here's what happens:

At the start of the game, I run a script to initialize all global variables required with the respective default values. At the end of that script, a saved game (if it exists) is loaded. This saved game is no less than a file containing all of those global variables modified according to the player's current progress.

Now that I am introducing a new global variable (and starting it as "true"), when I tell GameMaker to read it on the "Saved Game" file, it's obvious that it won't find it, so that makes it assume the variable is "false".

I wonder if there is a way to tell GameMaker to read that nonexistent global variable - if, and only if, it is nonexistent - as "true" as I set it by default before.
 
Do you already have a load function? My impression is that you're writing your own.

Because I'm pretty sure if you're doing it the way you describe, it won't assume anything at all about the variable. It should only change the ones listed in the save file. Like you said, "it's obvious that it won't find it", that's true. But if it doesn't find it, how would it know it exists? Unless the old save files are somehow updated to include the new variables?

EDIT: Have you tested this problem already, or you just think they're be a problem later?
 

Llama_Code

Member
If your loading a file, then you should have a process in place to know when a file is being loaded, if that's the case you could check for the existence of the variable, and if it's not there write it and re save.

I always use versions in my save files to check against when loading for cases like this.
 
G

Gabriel

Guest
If your loading a file, then you should have a process in place to know when a file is being loaded, if that's the case you could check for the existence of the variable, and if it's not there write it and re save.

I always use versions in my save files to check against when loading for cases like this.
I know the file is loaded because the game changes according to the values listed in there.
And what is happening is that since GMS won't find this new variable there, it changes it too. Doesn't make much sense.
 

Llama_Code

Member
Your going to do an extra step to initialize that variable. So when your game loads, do something like

if (is_undefined(myvar))
{
myvar=true;
}

As an additional check for legacy save files. It obviously going to have to be appended to your loading procedure to catch if that variable was not created and create it.

How does you load file work, are you assigning them through a loop, or just assigning them with the assumption they are going to be there?
 

TsukaYuriko

☄️
Forum Staff
Moderator
is_undefined can not and is not meant to be used to check if a variable exists.

Since you have full control over your save file, you should be capable of telling whether the save file provided is from an older version or not. One example of ensuring this is saving a version number inside the save file and incrementing it every time the save file format updates. This way, you will be able to add special cases to your save file loading code to ensure compatibility with all save file format versions - at least in the newest version of the game. Since you'll always know how each version of your save file format is structured (you documented that, right?), you'll always know how to treat a save file of the corresponding version.


That's as much detail as I can go into without seeing your code, but I don't think that will be necessary if you follow this approach, anyway.
 
C

Cerno~b

Guest
@TsukaYuriko: Not trying to hijack this thread, could explain what is_undefined is for then? I ran into a similar problem and that function seemed like the way to go, but i kept getting errors, so I gave up on it. Is there a robust way to find out if a variable is undefined? It would save some effort initializing members that are only used in one script.
 

Llama_Code

Member
is_undefined can not and is not meant to be used to check if a variable exists.
I was getting the impression it exists, it's not not getting set, unless I am totally misunderstanding him.

I think, just a guess, he is creating them on the front side, the loading them in to assign them. So his new version creates the variable, but the save file doesent have a value for it. But, like you said, without code it's a guess.
 
G

Gabriel

Guest
Your going to do an extra step to initialize that variable. So when your game loads, do something like

if (is_undefined(myvar))
{
myvar=true;
}

As an additional check for legacy save files. It obviously going to have to be appended to your loading procedure to catch if that variable was not created and create it.

How does you load file work, are you assigning them through a loop, or just assigning them with the assumption they are going to be there?
Unfortunately that method does not work because I checked that when the variable is not specified on the save file, GameMaker makes it 0, and that is not "undefined".

Some variables are assigned through a loop, yes. But that's not the case of this one. If you go a little bit up here you can see my code in one of my replies.

is_undefined can not and is not meant to be used to check if a variable exists.

Since you have full control over your save file, you should be capable of telling whether the save file provided is from an older version or not. One example of ensuring this is saving a version number inside the save file and incrementing it every time the save file format updates. This way, you will be able to add special cases to your save file loading code to ensure compatibility with all save file format versions - at least in the newest version of the game. Since you'll always know how each version of your save file format is structured (you documented that, right?), you'll always know how to treat a save file of the corresponding version.


That's as much detail as I can go into without seeing your code, but I don't think that will be necessary if you follow this approach, anyway.
I should have thought about that at the beginning!
But now it won't do to much, at least with this particular variable, since I did not save the game version previously.
I'll do it from now on, though.

If you want to check my code, go a little bit up this thread and you will find a reply with it, although I guess the proper way to solve this issue must be to create and individual file for this particular variable.

I was getting the impression it exists, it's not not getting set, unless I am totally misunderstanding him.

I think, just a guess, he is creating them on the front side, the loading them in to assign them. So his new version creates the variable, but the save file doesent have a value for it. But, like you said, without code it's a guess.
I posted the code in one of my replies, but for some reason it just disappeared.

So basically, the new variable I'm talking about is "global.xmas".

Here is the end of the code for the script that runs at the very start of the game to initialize all global variables:
Code:
//Control
global.cottoncandy = 0;
global.facebook = 0;
global.xmas = true;

//Load Game
load_game();
Here is the end of the code for "Load Game":
Code:
//Control
global.cottoncandy = file_text_read_real(load);
file_text_readln(load);
global.facebook = file_text_read_real(load);
file_text_readln(load);
global.xmas = file_text_read_real(load);
file_text_readln(load);
 
//Close the file
file_text_close(load);
And here is the code for "Save Game":
Code:
//Control
file_text_write_real(file, global.cottoncandy);
file_text_writeln(file);
file_text_write_real(file, global.facebook);
file_text_writeln(file);
file_text_write_real(file, global.xmas);
file_text_writeln(file);

//Close the file
file_text_close(file);
When I first run the update, the last saved variables are "global.cottoncandy" and "global.facebook". Of course "global.xmas" does not exist there (though it is initialized at the first script as "true") so GameMaker sets it as 0.
 
Last edited by a moderator:

Llama_Code

Member
So, it looks like all your values are on individual lines. What you may need to do then, is when the player chooses to load a game, before the file is loaded, add a part to count the lines in the text file, if it's a line less than expected you know that the entry does not exists, so append it and then load the save file and it will be there.

Kind of a hack way of doing it, but where you didn't pre plan for updates, you do what you can.
 
G

Gabriel

Guest
So, it looks like all your values are on individual lines. What you may need to do then, is when the player chooses to load a game, before the file is loaded, add a part to count the lines in the text file, if it's a line less than expected you know that the entry does not exists, so append it and then load the save file and it will be there.

Kind of a hack way of doing it, but where you didn't pre plan for updates, you do what you can.
Not really sure what to use to count lines, but I'll do some research.
Thanks for the help!

Next time I develop a game I'll keep in mind the updates, haha.
 

Llama_Code

Member
Code:
var lines = 0;
savefile = file_text_open_read( "myfile.txt");
while (!file_text_eof(savefile))
   {
  lines += 1;
  file_text_readln(savefile);
   }
file_text_close(savefile);
 
G

Gabriel

Guest
Code:
var lines = 0;
savefile = file_text_open_read( "myfile.txt");
while (!file_text_eof(savefile))
   {
  lines += 1;
  file_text_readln(savefile);
   }
file_text_close(savefile);
Oh, thank you so much!
I need to get more familiar with this functions because I usually don't work too much with file reading/writing.
 

sylvain_l

Member
IMHO for what you are doing, you should just use the ini_* version to store/retrieve your data.
It'll be much more robust (allow you to check if a key exists in the ini file or not, and define a default value if the ini file doesn't exist or the key isn't in the ini file)

side note; as far as I understand, the read real function just parse the line, guessing the real value in it (even if it's an empty line because your are at eof^^) meaning by default if nothing is there it return 0.(the function always return a real!)
(you should avoid such a function if you want to be able to store a 0 value. Because the function return it as a default/error code, you get in trouble when you get 0, cause you don't know if it's the value in the file or the default/error that's returned.)
 
G

Gabriel

Guest
IMHO for what you are doing, you should just use the ini_* version to store/retrieve your data.
It'll be much more robust (allow you to check if a key exists in the ini file or not, and define a default value if the ini file doesn't exist or the key isn't in the ini file)

side note; as far as I understand, the read real function just parse the line, guessing the real value in it (even if it's an empty line because your are at eof^^) meaning by default if nothing is there it return 0.(the function always return a real!)
(you should avoid such a function if you want to be able to store a 0 value. Because the function return it as a default/error code, you get in trouble when you get 0, cause you don't know if it's the value in the file or the default/error that's returned.)
My game is built for Android devices, so I can't use ini files, I suppose.
 
W

Wraithious

Guest
What you can do is add a version number string to the save file name, (even if the user can name the save file just append the variable to the name) and when you update your game just change this variable number to the new version number before submitting your update to the playstore, plus in your load game script you would parse the load game string and compare the sub string, if it doesn't equal the version in the game version variable throw a message to the user
 
Top