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

SOLVED Saving and Loading Arrays (please dont 'dont use arrays, use ds_map' copy pasta me)

A

aristhemage

Guest
Hi, I know, I know, don't use arrays to save, use maps. But the tutorials and help are all implying that the variable that stores the array isn't the core functionality of the game.
I'm making a sandbox game and the way I have it is that there is a variable called world, an array worth about ten thousand values. Everything and I mean everything is linked and wired around this array, so I'd prefer not to change it. Is there an actual way to save arrays? A lot of tutorials and help suggest that you shouldn't not that you can't. I'm working with ini file saving.

Hope to hear from you guys soon!
 
S

SSJCoder

Guest
just try:
Code:
{
    var list = ds_list_create();
    var i=0;
    var e=/*array-length*/;
    while ( i<e ) {
        ds_list_add( list, /*array-name*/[i] );
        i+=1;
    }
   
    // write list to string
    var str = ds_list_write( list );
   
    // free memory
    ds_list_destroy( list );
   
}
 

samspade

Member
Sure. Just loop through the array and save every value individually and then read it back in that way as well. If you're nesting arrays, you'll need to do a check for that and loop through all those arrays too.

For example something like this:

GML:
ini_open("inventory.sav");

for(var i = 0; i  < maxItems; i ++)
{
global.inventory[i] = ini_read_real("Inventory", "Slot" + string(i), -1)
}

ini_close();
GML:
if(file_exists("inventory.sav") file_delete("inventory.sav");

ini_open("inventory.sav");

for(var i = 0; i  < maxItems; i ++)
{
ini_write_real("Inventory", "Slot" + string(i), global.inventory[i])
}

ini_close();
Just extend that with the code you need to loop through your array.

(If that sounds like a major headache, it is and it is why everyone says don't do it. Learn to use lists and maps as those are fast, scale well, and much, much easier to work with.)
 

Evanski

Raccoon Lord
Forum Staff
Moderator
using arrays is a very inefficient way of saving such a thing as a sandbox game, just a heads up to expect very slow loading and saving
 

TheouAegis

Member
How many bytes does each variable in the array take up? You can dump the array into a buffer and then save the buffer. Then you can load the buffer and loop through it, loading the values back into the array. But... If the array is going to be a one-time use, meaning the only time you're going to read the array is at the very beginning of a room when you need to load the layout and everything else and then they become obsolete after that, then you may as well just use the buffer and avoid the array completely.
 
Last edited:
A

aristhemage

Guest
Sure. Just loop through the array and save every value individually and then read it back in that way as well. If you're nesting arrays, you'll need to do a check for that and loop through all those arrays too.

For example something like this:

GML:
ini_open("inventory.sav");

for(var i = 0; i  < maxItems; i ++)
{
global.inventory[i] = ini_read_real("Inventory", "Slot" + string(i), -1)
}

ini_close();
GML:
if(file_exists("inventory.sav") file_delete("inventory.sav");

ini_open("inventory.sav");

for(var i = 0; i  < maxItems; i ++)
{
ini_write_real("Inventory", "Slot" + string(i), global.inventory[i])
}

ini_close();
Just extend that with the code you need to loop through your array.

(If that sounds like a major headache, it is and it is why everyone says don't do it. Learn to use lists and maps as those are fast, scale well, and much, much easier to work with.)
I'm Sorry I forgot to mention that my inventory system is set up like this

GML:
//0: Item ID 1: Amount of item 2: Durabillity (-1 means none) 4: Item Name (9 Slots)
global.inventory = [0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air, 0, 0, -1, block_air]
 

samspade

Member
That doesn't look like 10,000 values. That wouldn't be too difficult to loop through and you could pretty much use the code above just changing the necessary variables name and types.
 
A

aristhemage

Guest
That doesn't look like 10,000 values. That wouldn't be too difficult to loop through and you could pretty much use the code above just changing the necessary variables name and types.
The 10,000 I was referring to is the actual world, every 64 pixels is a number, the world is about 3000x5000 Pixels
as for your suggestion, with some modifications to your code, it works perfectly! Thank you!

If you are curious, here is what the end result for the inventory was:
GML:
ini_open("inventory.sav");

for(var i = 0; i  < 9; i ++)
{
global.inventory[i*4] = ini_read_real("Inventory", "Slot" + string(i), 0)
global.inventory[i*4+1] = ini_read_real("Inventory", "Amount"+string(i), 0)
global.inventory[i*4+3] = ini_read_real("Inventory", "Name"+string(i), string(block_air));
}

ini_close();
GML:
if(file_exists("inventory.sav")){ file_delete("inventory.sav")};

ini_open("inventory.sav");

for(var i = 0; i  < 9; i ++)
{
ini_write_real("Inventory","Slot" + string(i), global.inventory[i*4])
ini_write_real("Inventory","Amount"+ string(i), global.inventory[i*4+1])
ini_write_real("Inventory","Name"+ string(i), string(global.inventory[i*4+3]))
}

ini_close();
 

TheouAegis

Member
Code:
var save_buffer = buffer_create(1,buffer_grow,1);
var i = 0;
repeat array_length_1d(global.inventory) buffer_write(save_buffer,buffer_s16,global.inventory[i++]);
buffer_save(save_buffer, "save.bin");
buffer_delete(save_buffer);
Code:
var save_buffer =  buffer_load("save.bin");
var i = 0;
repeat buffer_get_size(save_buffer)/2 global.inventory[i++] = buffer_read(save_buffer,buffer_s16);
buffer_delete(save_buffer);
 
For posterity sake, the easiest way to save arrays to file, even nested arrays, is as follows:

Note: May not work correctly with the HTML5 Export:
Code:
var my_array = [...], // Or whatever, just and example, can be nested as deep as you want
    temp = ds_list_create();

temp[| 0] = my_array; // Note that you are saving the entire array to the index, not any particular part of the array
save_to_file_somehow(ds_list_write(temp)); // Ie: Save this string however you like
ds_list_destroy(temp);
... And to reload said array:

Code:
var temp = ds_list_create();

ds_list_read(temp, load_the_string_from_a_file_or_whatever());
my_array = temp[| 0];

ds_list_destroy();
Boom. Done. This will also work with a DS Grid, possibly some of the other DS types, but NOT a DS Map, as ds_map_write will only convert the ID of the array and not the contents.
 

chamaeleon

Member
Hi, I know, I know, don't use arrays to save, use maps. But the tutorials and help are all implying that the variable that stores the array isn't the core functionality of the game.
I'm making a sandbox game and the way I have it is that there is a variable called world, an array worth about ten thousand values. Everything and I mean everything is linked and wired around this array, so I'd prefer not to change it. Is there an actual way to save arrays? A lot of tutorials and help suggest that you shouldn't not that you can't. I'm working with ini file saving.

Hope to hear from you guys soon!
Lots of suggestions how to do it that I won't try to add to. I would just like to say that if it was me doing this kind of saving, I would start from the other direction and define what the file format should be like, and then write whatever code is necessary to adhere to that format. Maybe it will be binary, maybe it will be json, maybe it will be space separated values with or without line breaks. Once I know how I want to store it I find a way to implement it using available gms functionality. In any case, I would not want my format to have any dependency on internal gms implementation details.
 

Joe Ellis

Member
While people are dissing arrays, they are the fastest to read and write to out of everything, even buffers. While each slot\index takes up 16 bytes, or more if it's a string, it's the most raw way of handling data. All data structures are basically doing the same thing, but are slower cus it first has to go through certain processes to do with that type of datastructure, and while buffers take up less memory, and are technically the same as a real array in c++, the gm engine handles the data slower for some reason.
If speed is a concern, using arrays is normally always the fastest option, provided that you make an efficient algorithm.

For saving the data in an array, you need to write your own algorithm, this is why most people choose to use ds_maps etc. cus there's a function that does it all for you. But once you learn how to save an array manually, you feel alot better for it, like you've moved on a stage in your level of programming.
You basically need to write each value in the array to a buffer, and save the buffer as a file. However, if the array contains strings and numbers, you need to make something that separates them, something that can tell the script upon loading it whether it needs to load a string or a number. But you can do this with a simple byte before each value specifying what type of data the next value to be read is..
I can go on and on, it's alot of work saving arrays and data manually, but I think it's worth it in the long run
 
Top