Jump to content


Photo

Game_load() And Game_save() Question


  • This topic is locked This topic is locked
29 replies to this topic

#1 Blastoiseiii

Blastoiseiii

    GMC Member

  • GMC Member
  • 322 posts

Posted 24 November 2008 - 01:58 AM

Hi, haven't posted here in a while, but I have been working in Game Maker for a long, long time. Recently I've come across a question that I'd like an answer to.

It's made quite clear in the manual that game_save() and game_load() do NOT save the contents of data structures. However, my question is if calling game_load() will remove the contents of data structures.

To give some context, I'm implementing the Game Over portion of my game, and my current system is to save the current state of the game at specific save points, then reload from those points when you die. I was hoping to be able to just use the built-in game_save()/game_load() functions, but since Data structures are an integral part of my game, I didn't think that was possible. I tried it out anyway, fully expecting it not to work, when I was much surprised that it DID work. All data stored in the data structures seemed to be there just fine!

My hypothesis is this: game_save() doesn't store any information about data structures and game_load() doesn't affect the current data structures system at all. Therefore, whatever the state of the data structures before I called game_load(), that's the state afterwards. Granted, if I called game_save(), shut down the game, started it back up, and called game_load(), I'd have lost the data in the data structures, but in this context that wouldn't occur.

Can anyone confirm that this is the case? I'd really appreciate it!

As a bonus question, does anyone know of a good way to retain data structures after a game_save()/game_load()? By retain I mean retaining the state of the structures from the game_save() point, not the point directly before game_load().
  • 0

#2 Pinpickle

Pinpickle

    Abscure Programmer

  • GMC Member
  • 1353 posts

Posted 24 November 2008 - 04:03 AM

Thats quite right. I have experienced this before using ds_grids. I had my data structure, saved. Loaded my game. The data structure was exactly the same. Exited the game, restarted it, it was wiped completely. So your hypothesis is correct.
For saving and loading data structures, one would use ds_[INSERT DATA STRUCTRE]_write/read. This can be quite slow, and sometimes not work if you are running with big data structures for example 200*200 grids. You might want to save bigger ones to the registry using a for loop. Any way, if you have smaller data structures here are two scripts.

Saving
registry_write_string(GameData,ds_/*data structure type here*/_write(/*Data structure name*/)

Loading
ds_/*data structure type here*/_read(/*Data structure name*/,registry_read_string(GameData))

If you need the for loop for saving grids faster I'll whip up a script for you.
  • 0

#3 xot

xot

    GMC Dismember

  • GMC Elder
  • 4775 posts
  • Version:GM:Studio

Posted 24 November 2008 - 04:11 AM

Please don't abuse the registry in this way. It's for saving a few configuration settings, not for general data storage. Use a file.
  • 1

#4 Blastoiseiii

Blastoiseiii

    GMC Member

  • GMC Member
  • 322 posts

Posted 24 November 2008 - 05:00 AM

Thanks for confirmation about the first part of my question! I love how fast that reply was!

As for the second portion, I wasn't clear. I know how to save data structures; my question is how to make it so that the game knows to load previously saved data structures (saved when I called game_save()) after I call game_load().
  • 0

#5 xot

xot

    GMC Dismember

  • GMC Elder
  • 4775 posts
  • Version:GM:Studio

Posted 24 November 2008 - 05:55 AM

The simplest way I know is to set an alarm in an object designed to recreate and load the structures immediately before you save the game. Presumably you would also destroy said structures immediately after saving them to avoid a potential memory leak. For optimal reliability you would need to design your game in such a way that resources indices can be changed or reassigned mid-game, and further, in a way where it be told to wait for resources to be restored before continuing. I've never actually done this, so this is just theory for me. Maybe there is a better way.
  • 0

#6 Blastoiseiii

Blastoiseiii

    GMC Member

  • GMC Member
  • 322 posts

Posted 24 November 2008 - 06:18 AM

If loading occurs at the end of a step, then wouldn't any alarms/objects created be overwritten when the loading occurs? No data is kept after a game_load(). If I have an alarm that's set to go off the step after being loaded, set before I game_load()ed, won't that alarm be changed after I call game_load()?
  • 0

#7 Dangerous_Dave

Dangerous_Dave

    GMC Member

  • Global Moderators
  • 9413 posts
  • Version:Unknown

Posted 24 November 2008 - 06:29 AM

You set the alarm to go off next step, and in the alarm it loads the data structure, right? Now when you save the game:

alarm[0]=1;
game_save("game.dat");
alarm[0]=-1;

So the game is saved while the alarm is set. Stopping the alarm happens after the game is saved, so when the game is loaded the alarm will not be stopped, and it will count down and execute the alarm. Understand?

Presumably you would also destroy said structures immediately after saving them to avoid a potential memory leak.

If the data structures were destroyed after saving, you wouldn't be able to access them again for the rest of the gaming "session". But I guess you could not call the alarm-cancel like I have above, and it should work out. But calling the alarm-cancel should remove the need for destroying the structures in the first place, right?
  • 0

#8 Blastoiseiii

Blastoiseiii

    GMC Member

  • GMC Member
  • 322 posts

Posted 24 November 2008 - 06:55 AM

Thank you all for your excellent and rapid help! I had forgotten how wonderful this forum is ;)
  • 0

#9 xot

xot

    GMC Dismember

  • GMC Elder
  • 4775 posts
  • Version:GM:Studio

Posted 24 November 2008 - 06:57 AM

The simplest way I know is to set an alarm in an object designed to recreate and load the structures immediately before you save the game.

If loading occurs at the end of a step, then wouldn't any alarms/objects created be overwritten when the loading occurs?

My sentence is kind of a train wreck. Let's try again:

Immediately before you save the game, set a one step alarm in an object designed to recreate and load the structures. When the game is loaded, the alarm should still be set since it was saved after it was set.

If the data structures were destroyed after saving, you wouldn't be able to access them again for the rest of the gaming "session".

They are rebuilt in the next step.

I'm not sure that short-circuiting the alarm would work, but I don't know exactly when in the event engine that games are saved and loaded. If the code block of the event that you've saved with is resumed at the point immediately after the save code, then what you are suggesting won't work. But there maybe something similar that would work which could certainly simplify things.
  • 0

#10 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 24 November 2008 - 06:59 AM

It a lot more tricky that what you may think (from what I have seen from the posts)...

Anyway, here is a working version of game_save and storable ds_list

Download SavedList.gmk


Because you can;t do anything after the game is loaded... Setting an alarm is pointless because after the load is done and the code exits the function/script/event that did the load, everything is reset to the load data (except list data) and the game state is at a weird state.... Oh and list references loeaded may not be valid (current ) list...

You have to set a flag before you load save... and reset it after you save

on create
global.gaveisFROMsaved = false

When saving
global.gaveisFROMsaved = true //when it loads, this will be true
game_save("t.sav")
global.gaveisFROMsaved = false //saved the state, reset false

When loading
game_load("t.sav")
//you can try anything you want here.. it won't work;

you can detect if the game was loaded in a controller object end_step
end step
if(global.gaveisFROMsaved )
{
//refresh data
}

but this is dangerous in this case because, well, other steps may occure before this it caught. I have not found a way to do this smoothly, except from wrapping the ds_function arround a safe function that detects if the ds_list itself is from a saved file everytime you attemp to access the list...

The wrapper is a bunch of ds_equivalent function that remaps the ds reference to an array. The array has states that determin if it was just loaded from file...

Assuming the ds reference starts at 0 to n, it can be used to reference the array (originally). I'm counting that the load_game will reset the ds variable to it's originl value which is also used as an array reference.


You init the array when the game starts

you use sds_create to make the ds list. The result is the populating of the 3 arrays needed for saving and loading detection. The retun is a ds list index (also an arry index) it's the same value.

when you save, you prep the array for saving. This writes the ds to a string array and flags the arrays as FROM FILE (-2), like that example above.
you save the game. NoW the text in the aray is saved
You then unprep the array after the save.

Everytime you sds_find_value or sds_list_size, a check is made to make sure the array is synchronised with any file load that may have occured.


Cheers!

Edited by icuurd12b42, 24 November 2008 - 07:07 AM.

  • 0

#11 xot

xot

    GMC Dismember

  • GMC Elder
  • 4775 posts
  • Version:GM:Studio

Posted 24 November 2008 - 07:05 AM

It a lot more tricky that what you may think (from what I have seen from the posts)...

The phrase "needlessly complicated" comes to mind... ;)
  • 0

#12 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 24 November 2008 - 07:09 AM

It a lot more tricky that what you may think (from what I have seen from the posts)...

The phrase "needlessly complicated" comes to mind... ;)


Don't blame me... If you ever tried to detect a game_load and reset your data at the right time withought having things crash or act up left and right, you know what I'm talking about.
  • 0

#13 xot

xot

    GMC Dismember

  • GMC Elder
  • 4775 posts
  • Version:GM:Studio

Posted 24 November 2008 - 07:10 AM

Believe me, I'm not blaming you. I think we all know who created this issue. Click "About Game Maker..." if you have any doubts.
  • 0

#14 Dangerous_Dave

Dangerous_Dave

    GMC Member

  • Global Moderators
  • 9413 posts
  • Version:Unknown

Posted 24 November 2008 - 07:32 AM

They are rebuilt in the next step.

I'm not sure that short-circuiting the alarm would work, but I don't know exactly when in the event engine that games are saved and loaded. If the code block of the event that you've saved with is resumed at the point immediately after the save code, then what you are suggesting won't work. But there maybe something similar that would work which could certainly simplify things.

The game is saved at that point, not at the end of the step. It's something I like to call the Ragarnak Technique (or RagTag for short). Ok, I just made that up. But that's who I learned the technique from ;). But it works. I have suggested it to quite a few, and all have reported it working correctly.
  • 0

#15 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 24 November 2008 - 09:23 AM

They are rebuilt in the next step.

I'm not sure that short-circuiting the alarm would work, but I don't know exactly when in the event engine that games are saved and loaded. If the code block of the event that you've saved with is resumed at the point immediately after the save code, then what you are suggesting won't work. But there maybe something similar that would work which could certainly simplify things.

The game is saved at that point, not at the end of the step. It's something I like to call the Ragarnak Technique (or RagTag for short). Ok, I just made that up. But that's who I learned the technique from ;). But it works. I have suggested it to quite a few, and all have reported it working correctly.


So, using the alarm set to 1, if the game is saved in the keypress event, will the loaded game resume from the keypress event? so alarm should trigger right away then...

Still there is the interim time where instance may need the data that was just loaded... If they too have an alarm ready to trigger, there is a tiny chance they would access invalid data.



xot, yeah, I understand your sentence now... Too complicated but we have no choice, aside from having our own save system... This was in GM6, no? Personally, I would have liked to see more bug fixes and less unused new feature in GM7...

At this point, one would think that yoyo would at least come up with a patch to fix the obvious bugs and ommisions we have found so far.
  • 0

#16 Dangerous_Dave

Dangerous_Dave

    GMC Member

  • Global Moderators
  • 9413 posts
  • Version:Unknown

Posted 24 November 2008 - 09:29 AM

Maybe the alarm is supposed to be set to 2. Does the alarm get executed when it is 1?
  • 0

#17 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 24 November 2008 - 09:55 AM

Maybe the alarm is supposed to be set to 2. Does the alarm get executed when it is 1?


Yes... but being 1, and being in the keyboard/io events (if assuption is correct), the next thing that will happen is the alarm are decreased,. Those that reach 0 will trigger right away.


So 1 is a good value to use here... 2 would make GM skip a beat... (Alarm triggers next step... Decreases to 1 right away, on the next sequence, it reaches 0)
  • 0

#18 Dangerous_Dave

Dangerous_Dave

    GMC Member

  • Global Moderators
  • 9413 posts
  • Version:Unknown

Posted 24 November 2008 - 09:58 AM

That's what I thought. For some reason, the last time I read your post I thought you were argueing it wouldn't work. Now when I read it, not so much...
  • 0

#19 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 24 November 2008 - 10:08 AM

Yeah, it's a good method. Not fool proof but it's a good method. It's funny I did not see the post about it when I posted my example.
  • 0

#20 th15

th15

    GMC Member

  • GMC Member
  • 1577 posts

Posted 25 November 2008 - 02:04 AM

Uhh, there's a better method for detecting when a game was saved:
global.gameSaved = true;
game_save()
global.gameSaved = false;

Then, at the start of the same event, you just check if global.gameSaved = true and perform your load code there. I've used this method to display "Game Loaded" messages and I think it'll work for this.
  • 0

#21 xDanielx

xDanielx

    GMC Member

  • GMC Member
  • 1002 posts
  • Version:Unknown

Posted 26 November 2008 - 11:28 PM

What th15 describes is the technique I've always used for loading data structures, and it's never given me any trouble....
  • 0

#22 Potnop

Potnop

    GMC Member

  • GMC Member
  • 3102 posts

Posted 27 November 2008 - 12:30 AM

Wow I never knew data structures don't get saved. It's surprising I never had trouble with this before, but then again I only use data structures temporarily most of the time in all my games. I did make a level editor but since I don't use GM's saving mechanism in that I never had trouble with it either. I'm probably gonna make my own saving system anyway. Have you guys ever tried to save inside a large room? It takes like 10 seconds, which was horrible when I was trying to create checkpoints that were supposed to seamlessly save the game. I ended up dividing the room into chunks and making the older chunks unreachable, because making the rooms persistent made the game save very slowly as well.

One thing that's crazy about saving and loading is if you ever deleted a room and load a game from that room, it loads correctly as if the room existed. So apparently the saving saves the entire room data which is unnecessary for my game that I'm making and I can't have it take 10 seconds to save when it can just as easily take about half of one.

Basically all of that was off topic, but what I'm saying is if you're really limited by GM's saving, make your own system.

I haven't gotten around to that yet, but I'm guessing it will be a little similar to saving and loading the level file from the level editor, except it will only save the states of active objects.

Edited by Potnop, 27 November 2008 - 12:32 AM.

  • 0

#23 Markolainen

Markolainen

    GMC Member

  • New Member
  • 426 posts

Posted 27 November 2008 - 07:49 PM

I'm sorry but I haven't read the whole topic. But I did a test and I only needed this code in the step event to get it to work:
if keyboard_check_pressed(vk_f5){
	storestring=ds_list_write(inventory);
	ds_list_clear(inventory);
	game_save("save");}
if keyboard_check_pressed(vk_f6){
	game_load("save");}
if storestring!=""{
	ds_list_read(inventory,storestring);
	storestring="";}
You'd of course have to create the list and set a variable called storestring.

Edit: Fixed a little spelling errors.

Edited by Markolainen, 27 November 2008 - 07:50 PM.

  • 0

#24 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 27 November 2008 - 10:27 PM

I'm sorry but I haven't read the whole topic. But I did a test and I only needed this code in the step event to get it to work:

if keyboard_check_pressed(vk_f5){
	storestring=ds_list_write(inventory);
	ds_list_clear(inventory);
	game_save("save");}
if keyboard_check_pressed(vk_f6){
	game_load("save");}
if storestring!=""{
	ds_list_read(inventory,storestring);
	storestring="";}
You'd of course have to create the list and set a variable called storestring.

Edit: Fixed a little spelling errors.


Have you tried this? I'm 99% sure this does not work... Though the code will run after the load (if storestring)..., the game will reset to the loaded game when it exits the script... So you may actually read in data into a wrong ds_list (potentially). Say the saved game had created a ds_list whose index was 3, the current game, the ds_list is 1... This code will load the read data to list 1... When the code exits the script and the game is reset, the saved game code references to list index 3... It's hard to explain right.

Edited by icuurd12b42, 28 November 2008 - 10:25 AM.

  • 0

#25 Markolainen

Markolainen

    GMC Member

  • New Member
  • 426 posts

Posted 27 November 2008 - 10:43 PM

Have you tried this? I'm 99% sure this does not work... Though the code will run after the load (if storestring)..., the game will reset to the loaded game when it exits the script... So you may actually read in data into a wrong ds_list (potentially). Say the saved game had created a ds_list whose index was 3, the current game, the ds_list is 1... This code will load the read data to list 1... When the code exists the script and the game is reset, the saved game code references to list index 3... It's hard to explain right.


Yes I tried it and it works. Here is the example.
If you find any errors please say so since this was a test engine for my RPG Inventory.

EDIT:
LMB - Adds an item.
RMB - Removes item.
Space - Sorts
Enter - Shuffles

Edited by Markolainen, 27 November 2008 - 10:44 PM.

  • 0

#26 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 28 November 2008 - 02:31 AM

Have you tried this? I'm 99% sure this does not work... Though the code will run after the load (if storestring)..., the game will reset to the loaded game when it exits the script... So you may actually read in data into a wrong ds_list (potentially). Say the saved game had created a ds_list whose index was 3, the current game, the ds_list is 1... This code will load the read data to list 1... When the code exists the script and the game is reset, the saved game code references to list index 3... It's hard to explain right.


Yes I tried it and it works. Here is the example.
If you find any errors please say so since this was a test engine for my RPG Inventory.

EDIT:
LMB - Adds an item.
RMB - Removes item.
Space - Sorts
Enter - Shuffles


But it's not safe at all... As I tried to explain in my other post.

Put this code in your create
puku=0;
storestring="";
ct = 0;
repeat(random(20))
{
ds_list_create();
ct +=1;
}
//Add a potion
//Create inventory
inventory=ds_list_create();

ds_list_add(inventory,"potion");
ds_list_add(inventory,"sword");
ds_list_add(inventory,"armor");

i = 0;
repeat(ct)
{
ds_list_destroy(i);
i+=1;
}


Save, quit, restart, load...
  • 0

#27 th15

th15

    GMC Member

  • GMC Member
  • 1577 posts

Posted 28 November 2008 - 03:53 AM

Yea, Icuurd has a good point, it's not the data in the data structures that are difficult to save, it's the reference to the data structure itself. I suppose that can be solved by building your own map of data structures, essentially hijacking the data structure numbering system.
  • 0

#28 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 28 November 2008 - 10:21 AM

Yea, Icuurd has a good point, it's not the data in the data structures that are difficult to save, it's the reference to the data structure itself. I suppose that can be solved by building your own map of data structures, essentially hijacking the data structure numbering system.


Refer to post #10
  • 0

#29 Markolainen

Markolainen

    GMC Member

  • New Member
  • 426 posts

Posted 28 November 2008 - 12:27 PM

@ icuurd 12b42: Oh I'm sorry I didn't read the whole thread but I get what you mean.
Well the only way to to is to create the the ds_lists in order or to assign a certain id to a certain ds_list (which is not possible as far as I know).
Unless you create a single object for every ds_list maybe? Would that work? And then when you load just reassign them again to each object.
  • 0

#30 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Elder
  • 16048 posts
  • Version:GM:Studio

Posted 28 November 2008 - 12:43 PM

@ icuurd 12b42: Oh I'm sorry I didn't read the whole thread but I get what you mean.
Well the only way to to is to create the the ds_lists in order or to assign a certain id to a certain ds_list (which is not possible as far as I know).
Unless you create a single object for every ds_list maybe? Would that work? And then when you load just reassign them again to each object.


LOL, refer to post #10
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users