• Hey! Guest! The 40th (!!!) GMC Jam will take place between February 25th, 12:00 UTC to March 1st 12:00 UTC. Why not join in this very special anniversary jam! Click here to find out more!

GMS 2.3+ What is the proper way to save a DS Map inside of a grid?

XD005

Member
So, I know it is possible to nest data in GMS 2.3 now.
My game had an issue with memory leakage in GMS2 and now I can rectify this issue with 2.3 and make the code run more efficient.
My game has a grid system where each grid position contains "metadata" regarding what is there, if the player has been there before, etc, etc.
I couldn't find an example on how to set this up. I want to also be able to destroy the entire table of data by simply destroying the ds_grid when done.
So, I have this...


GML:
if (!ds_exists(global.galaxy,ds_type_grid)){
    //Using arbitrary height and width for now...
    global.galaxy = ds_grid_create(3,4);
    global.galaxy[# 0, 0] = ds_map_create();
    global.galaxy[# 0, 0][? "maptest"] = "idk";
  }
Running this in debug mode neither creates the key at 0,0 nor does it create the test string.
What am I doing wrong?

Edit: Nevermind, this is working. Some weirdness with the GMS 2.3 debugger and not showing updated information. Disregard...
 

Neptune

Member
Yeah should be fine. I will say everything about this was possible and functioned the same pre 2.3, except for the accessor chaining.

I don't think you could do grid[]map[]list[] kind of thing without at least making some local vars between.
 

Neptune

Member
However you cannot just destroy the grid and hope your maps also destroy -- the grid is just storing pointers (integers representing the indexes of your map).

So you must loop through the grid, destroy the maps, then destroy the grid...


Unless you're storing read-only strings, which I discussed in detail with you before.
 
Last edited:
So, I know it is possible to nest data in GMS 2.3 now.
Also, this isn't exactly right. Nesting data was always possible, you just had to do some extra steps to extract it pre2.3 i.e. you couldn't chain accessors: my_data[| 0][# "key"]. But this is just a QOL thing, not a change in function.

And pay attention to what @Neptune is saying, just because the map pointer is stored somewhere does not mean destroying that "storage" will destroy the map itself. This is probably the biggest cause of memory leaks with people who are new to dealing with data structures. Mentally managing where you are storing data structures and when you need to delete them is important to making sure you don't have any memory leaks.

Additionally, if you need to actually save a grid to disk and have other data structures in that grid, you'll have to go through each DS, convert it to a string (ds_*_write()) and then create a new structure from that string when you read the save file (ds_*_read()), otherwise all that will be saved in the grid is a number that has no, or an incorrect, corresponding DS.
 

samspade

Member
So, I know it is possible to nest data in GMS 2.3 now.
My game had an issue with memory leakage in GMS2 and now I can rectify this issue with 2.3 and make the code run more efficient.
My game has a grid system where each grid position contains "metadata" regarding what is there, if the player has been there before, etc, etc.
I couldn't find an example on how to set this up. I want to also be able to destroy the entire table of data by simply destroying the ds_grid when done.
So, I have this...


GML:
if (!ds_exists(global.galaxy,ds_type_grid)){
    //Using arbitrary height and width for now...
    global.galaxy = ds_grid_create(3,4);
    global.galaxy[# 0, 0] = ds_map_create();
    global.galaxy[# 0, 0][? "maptest"] = "idk";
  }
Running this in debug mode neither creates the key at 0,0 nor does it create the test string.
What am I doing wrong?

Edit: Nevermind, this is working. Some weirdness with the GMS 2.3 debugger and not showing updated information. Disregard...
The 2.3 Debugger does have some issues right now. I would suggest not using a grid at all for this but using two nested lists especially if your goal is to save it. Unless you are using one of the special ds_grid functions (such as add region), now that you can chain accessors it gets your nothing and adds additional overhead because you have to pull everything out to save it or and so on. If you only use lists and maps, you can use the json structure and just save the top level, and all lower levels will be saved as well. Also, when using lists and maps and marking them as such you only have to destroy a map or list will destroy all nested maps or lists automatically assuming that they have been added as such.
 

FrostyCat

Member
There is no built-in way to save or load nested data structures of mixed types, except the mix of lists and maps (JSON). For your specific case, you would flatten the maps into a string with ds_map_write first, then deposit them into a temporary grid mirroring the live grid, then ds_grid_write the temporary grid.
GML:
function load_grid_of_maps(grid, data) {
    var _width = ds_grid_width(grid);
    var _height = ds_grid_height(grid);
    var _grid = ds_grid_create(_width, _height);
    ds_grid_read(_grid, data);
    for (var i = _width-1; i >= 0; --i) {
        for (var j = _height-1; j >= 0; --j) {
            ds_map_read(grid[# i, j], _grid[# i, j]);
        }
    }
    ds_grid_destroy(_grid);
}

function save_grid_of_maps(grid) {
    var _width = ds_grid_width(grid);
    var _height = ds_grid_height(grid);
    var _grid = ds_grid_create(_width, _height);
    for (var i = _width-1; i >= 0; --i) {
        for (var j = _height-1; j >= 0; --j) {
            _grid[# i, j] = ds_map_write(grid[# i, j]);
        }
    }
    var _gridData = ds_grid_write(_grid);
    ds_grid_destroy(_grid);
    return _gridData;
}
Code:
var saveData = save_grid_of_maps(global.galaxy);
Code:
load_grid_of_maps(global.galaxy, saveData);
This general inability to handle nested data structures is a major unresolved weakness of ds_*. It is just one more reason why I recently stopped using ds_* data structures altogether, and built my own structs-and-arrays-based alternative. My alternative is slower than native speed, but at least it allows arbitrary nesting with zero workarounds, and has saved me inordinate amounts of time otherwise fiddling with read-write functions.
 

Neptune

Member
You either have to do something like what @FrostyCat is doing, or store/manipulate read-onlys if you want to mass delete or mass save.

Basically you could just write a function that writes everything to read-only for saving. And then read your "string data" back into your actual structures at loading.
 
Top