Saving Paths Externally

So, currently i'm trying to make a room editor where I need to save the path of an object, but am having trouble. The current system i'm using saves the paths into a separate json encoded ini file from the variables of the objects in my world. I then link them using a path_id variable between both the files. This is okay, but when I delete an object, the paths that are greater than the path_id deleted, will be messed up. I'm trying to figure out a different approach to this problem! Help is appreciated!
1606961437965.png
1606961463385.png
I deleted the middle
 

TsukaYuriko

☄️
Forum Staff
Moderator
I'm not sure what exactly a "json encoded ini file" is, but if you're bringing JSON into the mix, you may as well use a struct. Those are basically JSON objects out of the box - no need to bring a middle man (or two) into the game, as you can save and load those to a file with literal oneliners.

when I delete an object, the paths that are greater than the path_id deleted, will be messed up.
This sounds like you're using some sort of indexed data structure... you could store these in an array (stored within the struct) and use the new array functions such as array_delete to remove elements in the middle of an array without leaving any gaps. No need for separate files, the entire struct can be saved as a single file. (I'm unsure if that's a good thing or a bad thing in your case.)

Does that sound like something that would work? If not, could you please post your current code so we can get a better overview over what you're doing (and what your code does)?
 
@TsukaYuriko I'm using the legacy version of game maker so array_delete isn't a viable option for me.
This is how i load my world objects:
GML:
if (file_exists("world.ini"))
        {
            var worldLoadFile = file_text_open_read("world.ini");
            if (!file_text_eof(worldLoadFile))
            {
                var worldMasterData = file_text_read_string(worldLoadFile);
                var wordArray = scr_string_split(worldMasterData, "|");
                var draggableCount = array_length_1d(wordArray);
              
                if (draggableCount > 0)
                {
                    for (var k = 0; k < draggableCount; k++)
                    {
                        var draggableJson = wordArray[k];
                      
                        var draggableMap = json_decode(draggableJson);
                      
                        var _x1 = ds_map_find_value(draggableMap, "x1");
                        var _y1 = ds_map_find_value(draggableMap, "y1");
                        var _x2 = ds_map_find_value(draggableMap, "x2");
                        var _y2 = ds_map_find_value(draggableMap, "y2");
                        var _path_id = ds_map_find_value(draggableMap, "pathid");
                        var _anchors = ds_map_find_value(draggableMap, "anchors");
                        //var _ribbon = ds_map_find_value(draggableMap, "ribbon");
                        var _v_sprite = ds_map_find_value(draggableMap, "v_sprite");
                        var _object = ds_map_find_value(draggableMap, "object");
                        var _imageIndex = ds_map_find_value(draggableMap, "image_index");
                        var _lightx = ds_map_find_value(draggableMap, "lightx");
                        var _lighty = ds_map_find_value(draggableMap, "lighty");
                        var _lightz = ds_map_find_value(draggableMap, "lightz");
                        var _light_rr = ds_map_find_value(draggableMap, "light_rr");
                        var _light_lr = ds_map_find_value(draggableMap, "light_lr");
                        var _lightrS = ds_map_find_value(draggableMap, "lightrS");
                        var _lightgS = ds_map_find_value(draggableMap, "lightgS");
                        var _lightbS = ds_map_find_value(draggableMap, "lightbS");
                        var _lightrD = ds_map_find_value(draggableMap, "lightrD");
                        var _lightgD = ds_map_find_value(draggableMap, "lightgD");
                        var _lightbD = ds_map_find_value(draggableMap, "lightbD");
                        //path_decode();
                        if _object > 0{
                            var new_obj = instance_create(_x1,_y1,oDraggable);
                            new_obj.x1 = _x1;
                            new_obj.x2 = _x2;
                            new_obj.y1 = _y1;
                            new_obj.y2 = _y2;
                            new_obj.object = _object;
                            new_obj.path_id = _path_id;
                            new_obj.num_anchors = _anchors;
                            //new_obj.ribbon = _ribbon;
                            //show_message(new_obj.ribbon);
                            if object_get_name(_object) = "oLightSample"{
                            new_obj.lightx = _lightx;
                            new_obj.lighty = _lighty;
                            new_obj.lightz = _lightz;
                            new_obj.light_rr = _light_rr;
                            new_obj.light_lr = _light_lr;
                            new_obj.lightrS = _lightrS;
                            new_obj.lightgS = _lightgS;
                            new_obj.lightbS = _lightbS;
                            new_obj.lightrD = _lightrD;
                            new_obj.lightgD = _lightgD;
                            new_obj.lightbD = _lightbD;
                            }
                            if sprite_exists(object_get_sprite(_object)){
                            new_obj.sprite_index = object_get_sprite(_object);
                            }else{new_obj.sprite_index =  sNoSprite;}
                            new_obj.image_index = _imageIndex;
                        }
                        if _object = undefined{
                            var new_obj = instance_create(_x1,_y1,oDraggable);
                            new_obj.x1 = _x1;
                            new_obj.x2 = _x2;
                            new_obj.y1 = _y1;
                            new_obj.y2 = _y2;
                            //new_obj.ribbon = _ribbon;
                            new_obj.vertex_sprite = _v_sprite;
                            new_obj.vertex_created = true;
                            new_obj.tex = sprite_get_texture(new_obj.sprite_index,new_obj.image_index);
                            new_obj.update = true;
                            new_obj.sprite_index = sTiles;
                            new_obj.image_index = _imageIndex;
                            new_obj.path_id = _path_id;
                            new_obj.num_anchors = _anchors;
                        }
                        ds_map_destroy(draggableMap);
                    }
                }
            }
            path_decode();
This is how I am storing my objects:

GML:
var draggableCount = instance_number(oDraggable);
        
if (file_exists("paths.ini"))
{
file_delete("paths.ini");
}
        
var save = file_text_open_write("paths.ini");

for (var k = 0; k < draggableCount; k++){
    var instance = instance_find(oDraggable,k);
            // convert this instance into a ds_map
            
            var pathSaveMap = ds_map_create();
            
            //ds_map_add(pathSaveMap, "index", i);
            ds_map_add(pathSaveMap, "kind", path_get_kind(instance.ribbon));
            ds_map_add(pathSaveMap, "closed", path_get_closed(instance.ribbon));
            ds_map_add(pathSaveMap, "precision", path_get_precision(instance.ribbon));
            ds_map_add(pathSaveMap, "Anchors", path_get_number(instance.ribbon));
            ds_map_add(pathSaveMap, "pathid", instance.path_id);
                
            for(var j = 0; j < path_get_number(instance.ribbon);j++){
                ds_map_add(pathSaveMap, "acnhorX" + string(j), path_get_point_x(instance.ribbon,j));
                ds_map_add(pathSaveMap, "acnhorY" + string(j), path_get_point_y(instance.ribbon,j));
            }
                
            // convert ds_map into JSON
            JsonInstance = json_encode(pathSaveMap);
            //instance.path_id = i;
            file_text_write_string(save, JsonInstance);
            file_text_write_string(save, "|");
            ds_map_destroy(pathSaveMap);
}

file_text_close(save);
This is how I am reading the file:
path_decode():
GML:
var _path_id = 0;
if (file_exists("paths.ini"))
        {
            var worldLoadFile = file_text_open_read("paths.ini");
            if (!file_text_eof(worldLoadFile))
            {
                var worldMasterData = file_text_read_string(worldLoadFile);
                var wordArray = scr_string_split(worldMasterData, "|");
                var draggableCount = array_length_1d(wordArray);
              
                if (draggableCount > 0)
                {

                        for (var k = 0; k < draggableCount; k++){
                            var inst = instance_find(oDraggable,k);
                            var _ptid = path_id;
                            var draggableJson = wordArray[k];

                            var pathMap = json_decode(draggableJson);
                            _path_id= ds_map_find_value(pathMap, "pathid");
                            if instance_exists(inst) && _path_id != undefined{
                            if inst.path_id = k{
                                var _kind = ds_map_find_value(pathMap, "kind");
                                var _closed= ds_map_find_value(pathMap, "closed");
                                var _precision = ds_map_find_value(pathMap, "precision");
                                var _num_anchors = ds_map_find_value(pathMap, "Anchors");
                                var _newpath = path_add();

                                path_clear_points(inst.ribbon);
                                path_set_kind(_newpath,_kind);
                                path_set_precision(_newpath,_precision);
                                path_set_closed(_newpath,_closed);
                                inst.num_anchors = _num_anchors;
                                inst.update = true;
                                //show_message(_num_anchors);
                                for(var j = 0; j < _num_anchors;j++){
                                    var a_x = ds_map_find_value(pathMap, "acnhorX" + string(j));
                                    var a_y = ds_map_find_value(pathMap, "acnhorY" + string(j));
                                    if a_x
                                    path_add_point(_newpath,a_x,a_y,100);
                                }
                                inst.ribbon = path_duplicate(_newpath);
                        } 
                        }
                        ds_map_destroy(pathMap);
                    }
                }   
            }
    file_text_close(worldLoadFile);
}
This is how I am storing my values:
path_encode():
GML:
var draggableCount = instance_number(oDraggable);
      
if (file_exists("paths.ini"))
{
file_delete("paths.ini");
}
      
var save = file_text_open_write("paths.ini");

for (var k = 0; k < draggableCount; k++){
    var instance = instance_find(oDraggable,k);
            // convert this instance into a ds_map
          
            var pathSaveMap = ds_map_create();
          
            //ds_map_add(pathSaveMap, "index", i);
            ds_map_add(pathSaveMap, "kind", path_get_kind(instance.ribbon));
            ds_map_add(pathSaveMap, "closed", path_get_closed(instance.ribbon));
            ds_map_add(pathSaveMap, "precision", path_get_precision(instance.ribbon));
            ds_map_add(pathSaveMap, "Anchors", path_get_number(instance.ribbon));
            ds_map_add(pathSaveMap, "pathid", instance.path_id);
              
            for(var j = 0; j < path_get_number(instance.ribbon);j++){
                ds_map_add(pathSaveMap, "acnhorX" + string(j), path_get_point_x(instance.ribbon,j));
                ds_map_add(pathSaveMap, "acnhorY" + string(j), path_get_point_y(instance.ribbon,j));
            }
              
            // convert ds_map into JSON
            JsonInstance = json_encode(pathSaveMap);
            //instance.path_id = i;
            file_text_write_string(save, JsonInstance);
            file_text_write_string(save, "|");
            ds_map_destroy(pathSaveMap);
}

file_text_close(save);
 
Last edited:

TsukaYuriko

☄️
Forum Staff
Moderator
I'm a bit confused because you said you're using an ini file, but I don't see you using the ini functions anywhere here. Did you mean to say you're using a text file?
Also, did you accidentally post path_encode twice? "This is how I am storing my objects" is followed by path saving code, not world saving code as I'd have imagined it to be. ;)

From what I understand, your game has two save files, one for paths, one for everything else, and removing a path other than the last one causes some sort of issue. I think I can see why, since you're saving a path ID to the path save file... and presumably saving something that links these path IDs to something else in the main save file?

when I delete an object, the paths that are greater than the path_id deleted, will be messed up.
This could be "solved" by going through everything that has anything to do with the paths in both save files and checking the path ID. If it's lower than the ID of the path that was just deleted, keep it. If it's the same, throw it out. If it's higher, decrease it by 1 and keep it.

But since you said you're looking for different approaches, let's see how this could be done differently.

Legacy is an entirely different beast. Rather than structs and arrays, you could use a structure consisting of a map and lists instead. These will translate to clean JSON via json_encode and can subsequently be loaded back via json_decode.

Is there a particular reason why you have two separate save files in the first place? I think this is the primary cause of the issue here, as having two separate files which reference the same hard-coded indices pretty much necessitates keeping them in sync manually. Having them in a single file would get rid of this entirely.

For the sake of illustration, I have two files.
characters.dat:
GML:
{ name: "Sharla", class: "Medic" }|{ name: "Seven", class: "Fighter" }|{ name: "Melia", class: "Mage" }
... and skills.dat:
GML:
{ owner_name: "Sharla", skill_name: "Heal Bullet" }|{ owner_name: "Sharla", skill_name: "Thunder Bullet" }|{ owner_name: "Seven", skill_name: "Sword Drones" }|{ owner_name: "Seven", skill_name: "Shield Drones" }|{ owner_name: "Melia", skill_name: "Summon Bolt" }|{ owner_name: "Melia", skill_name: "Burst End" }
The data here is linked by the character's name - I believe quite similarly to the way your paths are linked, just via a string rather than a number - and stored across two separate files.
While this works, I'll have a problem if, for any reason, I wanted to, say, change Seven's name to something else... I could change characters.dat like this:
GML:
{ name: "Sharla", class: "Medic" }|{ name: "Melia", class: "Mage" }|{ name: "Eight", class: "Fighter" }
... but now skills.dat will still have entries for Seven, not Eight, thus Eight will not have any skills unless I also update the name in that file.

This could be worked around by identifying them via IDs:
characters.dat:
GML:
{ id: 0, name: "Sharla", class: "Medic" }|{ id: 1, name: "Seven", class: "Fighter" }|{ id: 2, name: "Melia", class: "Mage" }
... and skills.dat:
GML:
{ owner_id: 0, skill_name: "Heal Bullet" }|{ owner_id: 0, skill_name: "Thunder Bullet" }|{ owner_id: 1, skill_name: "Sword Drones" }|{ owner_id: 1, skill_name: "Shield Drones" }|{ owner_id: 2, skill_name: "Summon Bolt" }|{ owner_id: 2, skill_name: "Burst End" }|
Now their name can be changed... but if I remove Seven completely, there will be a gap in the IDs (Sharla will be 0, Melia will be 2, 1 is missing). This may or may not cause issues depending on whether my load code cares whether there's an empty index anywhere, so it's game-breaking at worst and a bit awkward at best.

I could solve this by not splitting the two files, but rather storing them as a single file:
GML:
{                                    // Entire save file
    characters:
    [                                    // Character list / array
        {                                    // Sharla's struct
            name: "Sharla",
            skills:
            [                                    // Sharla's skills list / array
                {                                    // One of Sharla's individual skills
                    name: "Heal Bullet",
                },
                {                                    // Another of Sharla's individual skills
                    name: "Thunder Bullet",
                },
            ],
        },
        {                                    // Seven's struct
            name: "Seven",
            skills:
            [                                    // Seven's skills list / array
                {                                    // One of Seven's individual skills
                    name: "Sword Drones",
                },
                {                                    // Another of Seven's individual skills
                    name: "Shield Drones",
                },
            ],
        },
        {                                  // Melia's struct
            name: "Melia",
            skills:
            [                                  // Melia's skills list / array
                {                                  // One of Melia's individual skills
                    name: "Summon Bolt",
                },
                {                                    // Another of Melia's individual skills
                    name: "Burst End",
                },
            ],
        },
    ],
}
(Note: This is not JSON, not a struct, not a map or any other tangible entity - just an outline of the file structure.)

I can change names however I want and remove stuff from the middle of the list with this structure. If I understood your file format correctly, this may be a suitable approach for you too.
 
@TsukaYuriko My file format is exactly like you showed above with the example you gave! I'm splitting the maps with "|". I'll combine the path and world file into one single file, but how would I be able to call and modify stuff in the middle of the list?

This is how my saved file looks like: "world.ini"
I'm just reading the "ini" file as a text file
Code:
{ "lighty": 288.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 496.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 2.000000, "anchors": 0.000000, "x2": 656.000000, "y1": 288.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 0.000000, "lightx": 32.000000, "lightz": 256.000000, "x1": 32.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 48.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 64.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 208.000000, "y1": 48.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 1.000000, "lightx": 192.000000, "lightz": 256.000000, "x1": 192.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 128.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 144.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 176.000000, "y1": 128.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 2.000000, "lightx": 160.000000, "lightz": 256.000000, "x1": 160.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 160.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 176.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 128.000000, "y1": 160.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 3.000000, "lightx": 112.000000, "lightz": 256.000000, "x1": 112.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 224.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 240.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 480.000000, "y1": 224.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 4.000000, "lightx": 464.000000, "lightz": 256.000000, "x1": 464.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 256.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 272.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 304.000000, "y1": 256.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 5.000000, "lightx": 288.000000, "lightz": 256.000000, "x1": 288.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 192.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 208.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 176.000000, "y1": 192.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 6.000000, "lightx": 160.000000, "lightz": 256.000000, "x1": 160.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 208.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 224.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 176.000000, "y1": 208.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 7.000000, "lightx": 160.000000, "lightz": 256.000000, "x1": 160.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 256.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 272.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 64.000000, "y1": 256.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 8.000000, "lightx": 48.000000, "lightz": 256.000000, "x1": 48.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 176.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 192.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 224.000000, "y1": 176.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 9.000000, "lightx": 208.000000, "lightz": 256.000000, "x1": 208.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 48.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 64.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 256.000000, "y1": 48.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 10.000000, "lightx": 240.000000, "lightz": 256.000000, "x1": 240.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 272.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 288.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 48.000000, "y1": 272.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 11.000000, "lightx": 32.000000, "lightz": 256.000000, "x1": 32.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 144.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 160.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 336.000000, "y1": 144.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 12.000000, "lightx": 320.000000, "lightz": 256.000000, "x1": 320.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 256.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 272.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 176.000000, "y1": 256.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 13.000000, "lightx": 160.000000, "lightz": 256.000000, "x1": 160.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 224.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 240.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 336.000000, "y1": 224.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 14.000000, "lightx": 320.000000, "lightz": 256.000000, "x1": 320.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 176.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 192.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 336.000000, "y1": 176.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 15.000000, "lightx": 320.000000, "lightz": 256.000000, "x1": 320.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 240.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 256.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 256.000000, "y1": 240.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 16.000000, "lightx": 240.000000, "lightz": 256.000000, "x1": 240.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 208.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 224.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 320.000000, "y1": 208.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 17.000000, "lightx": 304.000000, "lightz": 256.000000, "x1": 304.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 240.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 256.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 464.000000, "y1": 240.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 18.000000, "lightx": 448.000000, "lightz": 256.000000, "x1": 448.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 256.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 272.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 544.000000, "y1": 256.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 19.000000, "lightx": 528.000000, "lightz": 256.000000, "x1": 528.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 208.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 224.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 4.000000, "x2": 240.000000, "y1": 208.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 20.000000, "lightx": 224.000000, "lightz": 256.000000, "x1": 224.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 128.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 144.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 544.000000, "y1": 128.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 21.000000, "lightx": 528.000000, "lightz": 256.000000, "x1": 528.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 208.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 224.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 400.000000, "y1": 208.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 22.000000, "lightx": 384.000000, "lightz": 256.000000, "x1": 384.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 192.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 208.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 432.000000, "y1": 192.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 23.000000, "lightx": 416.000000, "lightz": 256.000000, "x1": 416.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 112.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 128.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 3.000000, "x2": 416.000000, "y1": 112.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 24.000000, "lightx": 400.000000, "lightz": 256.000000, "x1": 400.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 112.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 128.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 448.000000, "y1": 112.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 25.000000, "lightx": 432.000000, "lightz": 256.000000, "x1": 432.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 32.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 48.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 432.000000, "y1": 32.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 26.000000, "lightx": 416.000000, "lightz": 256.000000, "x1": 416.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|{ "lighty": 160.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 176.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "anchors": 0.000000, "x2": 240.000000, "y1": 160.000000, "lightrS": 1.000000, "lightgS": 1.000000, "pathid": 27.000000, "lightx": 224.000000, "lightz": 256.000000, "x1": 224.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 0.000000 }|
 

TsukaYuriko

☄️
Forum Staff
Moderator
I'm just reading the "ini" file as a text file
Then that is a text file, not an ini file. Or do your pictures suddenly turn into music when you rename them to .mp3? ;P
The extension has no meaning, it's just a part of the file name. There's a huge difference between the file structure of a text file and an ini file, though, so calling it one thing when it's really the other is guaranteed to cause confusion. ;)

@TsukaYuriko My file format is exactly like you showed above with the example you gave! I'm splitting the maps with "|". I'll combine the path and world file into one single file, but how would I be able to call and modify stuff in the middle of the list?

This is how my saved file looks like: "world.ini"
Instead of having a "pathid" attribute for every element, you could instead just store the entire path data. As in, have an attribute "path", and its value is another JSON object containing the path's entire data. As far as I can see, you're not linking the same path to multiple elements, so that shouldn't be a problem. No need for an ID anywhere, so there will also be no problems if you remove stuff in the middle because the order doesn't even matter anymore (from what I can tell).
 
@TsukaYuriko
So i'm saving the whole thing into the world file but i'm currently having trouble reading it:
Code:
{ "precision": 6.000000, "closed": 0.000000, "acnhorY1": 105.000000, "kind": 1.000000, "acnhorX1": 344.000000, "acnhorY2": 189.000000, "acnhorY0": 121.000000, "acnhorX2": 515.000000, "acnhorX0": 145.000000, "Anchors": 3.000000 }?{ "lighty": 161.000000, "object": null, "lightbD": 1.000000, "light_rr": 5.000000, "y2": 160.000000, "lightrD": 1.000000, "lightgD": 1.000000, "image_index": 0.000000, "numanchors": 3.000000, "x2": 208.000000, "y1": 144.000000, "lightrS": 1.000000, "lightgS": 1.000000, "lightx": 273.000000, "lightz": 256.000000, "x1": 192.000000, "light_lr": 5.000000, "lightbS": 1.000000, "v_sprite": 117.000000, "path": 1.000000 }|
I separated the paths and objects with ? and | but i'm having trouble reading the maps since they're now separated by two different strings. The text above shows the save for ONE object
 

TsukaYuriko

☄️
Forum Staff
Moderator
I'd suggest just saving everything as pure JSON rather than inventing your own file format with separators. That avoids any chance of mishaps during parsing of the data (as you no longer need to do it manually, once for saving and once for loading) and additionally replaces your load parsing code with a one-liner (json_decode). The same goes for saving.

I could imagine the format looking sort of like this (for one object + path):
GML:
{
    "object":
    {
        "lighty":161.000000,
        "object":null,
        "lightbD":1.000000,
        ...
    },
    "path":
    {
        "precision":6.000000,
        "closed":0.000000,
        "acnhorY1":105.000000,
        ...
    }
}
You could store multiple such... "entities" (?) by having the main structure be a list:

GML:
{
    "entities":
    [
        {
            "object": {...},
            "path": {...}
        },
        {
            "object": {...},
            "path": {...}
        }
    ]
}
... or even merge "path" into "object" (if every path belongs to exactly one object):

GML:
{
    "entities":
    [
        {
            "lighty":161.000000,
            "object":null,
            "lightbD":1.000000,
            "path":
            {
                "precision":6.000000,
                "closed":0.000000,
                "acnhorY1":105.000000,
                ...
            },
            ...
        },
        {
            "lighty":161.000000,
            "object":null,
            "lightbD":1.000000,
            "path":
            {
                "precision":6.000000,
                "closed":0.000000,
                "acnhorY1":105.000000,
                ...
            },
            ...
        }
    ]
}
On the GML side, everything enclosed by curly braces {} would be a map, and everything enclosed by square brackets [] would be a list.

So a map containing a list of maps that each contain another map. As in, a map (the main structure - just because json_encode expects a map) containing a list (of entities) of maps (an individual entity) that each contain another map (a path).
 
Last edited:
@TsukaYuriko
Yeah this was originally what I going for but wasn't sure how to navigate through JSON so I made a quick saving function to work on something else since it was still suitable for what I had before. I found a tutorial by Shaun Spaulding and was wondering if this was the right direction.
 

TsukaYuriko

☄️
Forum Staff
Moderator
While that seems pretty roundabout from a 2.3.1 user's point of view, that is indeed the way to do this on legacy versions.
 
Top