GMS 2 Decoding a ds map populated with ds lists not working on existing file

I'm having some trouble with my code. I'm trying to set up some basic configs in a .ini file, things like volume, window size, and most importantly, controls. Since my controls are all arrays, I thought it easiest to transfer them into ds_lists, and then add those ds_lists to a ds_map and encode to json to put them all in the .ini, as I read in the documentation. My code:

Code:
var wintrols = ini_open(working_directory + "config.ini");
var hasControls = true;
if(!ini_key_exists("settings", "scale"))
{
   hasControls = false;
   ini_write_real("settings", "scale", 1);
   ini_write_real("settings", "sfx volume", 100);
   ini_write_real("settings", "music volume", 100);

   var k_trl = ds_list_create();
   ds_list_add(k_trl, ord("Z")); //A
   ds_list_add(k_trl, ord("X")); //B
   ds_list_add(k_trl, ord("V")); //X
   ds_list_add(k_trl, ord("C")); //Y
   ds_list_add(k_trl, ord("A")); //L
   ds_list_add(k_trl, ord("S")); //R
   ds_list_add(k_trl, vk_up); //Up
   ds_list_add(k_trl, vk_down); //Down
   ds_list_add(k_trl, vk_left); //Left
   ds_list_add(k_trl, vk_right); //Right
   ds_list_add(k_trl, vk_enter); //Pause

   var p_trl_padnum = ds_list_create();
   var p_trl_control = ds_list_create();
   var p_trl_dir = ds_list_create();

   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);
   ds_list_add(p_trl_padnum, 4);

   ds_list_add(p_trl_control, gp_face2);
   ds_list_add(p_trl_control, gp_face1);
   ds_list_add(p_trl_control, gp_face4);
   ds_list_add(p_trl_control, gp_face3);
   ds_list_add(p_trl_control, gp_shoulderl);
   ds_list_add(p_trl_control, gp_shoulderr);
   ds_list_add(p_trl_control, gp_axislv);
   ds_list_add(p_trl_control, gp_axislv);
   ds_list_add(p_trl_control, gp_axislh);
   ds_list_add(p_trl_control, gp_axislh);
   ds_list_add(p_trl_control, gp_start);

   ds_list_add(p_trl_dir, 0);
   ds_list_add(p_trl_dir, 0);
   ds_list_add(p_trl_dir, 0);
   ds_list_add(p_trl_dir, 0);
   ds_list_add(p_trl_dir, 0);
   ds_list_add(p_trl_dir, 0);
   ds_list_add(p_trl_dir, -1);
   ds_list_add(p_trl_dir, 1);
   ds_list_add(p_trl_dir, -1);
   ds_list_add(p_trl_dir, 1);
   ds_list_add(p_trl_dir, 0);

   var controls = ds_map_create();
   ds_map_add_list(controls, "padaxis", p_trl_dir);
   ds_map_add_list(controls, "padnum", p_trl_padnum);
   ds_map_add_list(controls, "padbutton", p_trl_control);
   ds_map_add_list(controls, "keyboard", k_trl);

   var encode = json_encode(controls);
   ini_write_string("settings", "controls", encode);
   ds_map_destroy(controls);
   ds_list_destroy(k_trl);
   ds_list_destroy(p_trl_padnum);
   ds_list_destroy(p_trl_control);
   ds_list_destroy(p_trl_dir);
}
global.scale = ini_read_real("settings", "scale", 1);
global.sfxvolume = ini_read_real("settings", "sfx volume", 100);
global.musicvolume = ini_read_real("settings", "music volume", 100);

var ctrls = json_decode(ini_read_string("settings", "controls", ""));
var p_trls_axis = ds_map_find_value(ctrls, "padaxis");
var p_trls_num = ds_map_find_value(ctrls, "padnum");
var k_trls = ds_map_find_value(ctrls, "keyboard");
var p_trls_button = ds_map_find_value(ctrls, "padbutton");

for(var i = 0; i < 11; i++)
{
   var pad = global.controls_gamepad[i];
   global.controls_keyboard[i] = ds_list_find_value(k_trls, i);
   pad[0] = ds_list_find_value(p_trls_num, i);
   pad[1] = ds_list_find_value(p_trls_button, i);
   pad[2] = ds_list_find_value(p_trls_axis, i);
   global.controls_gamepad[i] = pad;
}
ds_list_destroy(k_trls);
ds_list_destroy(p_trls_num);
ds_list_destroy(p_trls_button);
ds_list_destroy(p_trls_axis);
ds_map_destroy(ctrls);

ini_close();
All of this works perfectly... when the .ini doesn't exist. When it's created on ini_close() and I reopen the project, suddenly the only key "ctrls" has is "default", which from what I'm told, is not supposed to happen since the json opened with a ds_map object... Odder still, the value for the key "default" is... {. A curly brace is the value of "default", which makes no sense- isn't that supposed to be the opener of the map?? I've looked up info on this, but I'm finding all the information hard to understand. I'm baffled as to why this code works only on first run without the file present, and breaks when the file exists. The .ini's code:

Code:
[settings]
controls="{ "padaxis": [ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, -1.000000, 1.000000, -1.000000, 1.000000, 0.000000 ], "padnum": [ 4.000000, 4.000000, 4.000000, 4.000000, 4.000000, 4.000000, 4.000000, 4.000000, 4.000000, 4.000000, 4.000000 ], "keyboard": [ 90.000000, 88.000000, 86.000000, 67.000000, 65.000000, 83.000000, 38.000000, 40.000000, 37.000000, 39.000000, 13.000000 ], "padbutton": [ 32770.000000, 32769.000000, 32772.000000, 32771.000000, 32773.000000, 32774.000000, 32786.000000, 32786.000000, 32785.000000, 32785.000000, 32778.000000 ] }"
music volume="100.000000"
sfx volume="100.000000"
scale="1.000000"
Is it possible it's interpreting the "{ " as the only string in that key despite the space? Maybe I shouldn't be doing this when I don't fully understand what it is I'm doing, but from all other info I can find, this feels like it should work...
 
Quick update: At the recommendation of a friend, I manually removed the first and last quotes from the "controls" key- and now it works perfectly! Adding them back in and storing the result of ini_read_string to a temp variable says the result of the function is literally "{ ", space included- so the ini genuinely cuts off after the second quotation mark.

So now the question becomes: How on earth do I tell the ini *automatically* to NOT make surround the values in quotation marks, since that's completely screwing up the json store? I want to use a similar system (though not on .ini files) for save data, but 99% of the stuff I want to save is arrays- I can't just tell people "ok when you close the game, make sure to remove the opening and closing quotes around arrays" so the game doesn't break, I need to make it work all on its own without outside input. As it stands right now, with these stupid automatic quotation marks, I'd have to separate everything into its own unique entry, and that's a LOT of data to do that for manually...
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
General options:
- base64_encode/base64_decode
- string_replace_all the quotes with some magic string (e.g. two regular quotes), then back.
- A custom INI reader via file_text_ functions (and then you can make it act like you want), though this is a higher effort for result).
 
General options:
- base64_encode/base64_decode
- string_replace_all the quotes with some magic string (e.g. two regular quotes), then back.
- A custom INI reader via file_text_ functions (and then you can make it act like you want), though this is a higher effort for result).
base64 encoding/decoding didn't work at all- it'd encode, but the decode wouldn't give back the ds_map, only giving "0".
string_replace_all didn't work, either- same result as before: it says the only entry that exists in the ds_map is "default"...which contains the entire string itself.

Is there really no way to make the .ini reader/writer not add its own quotes around the entries? Because that's genuinely THE problem here- if it just did not do that, this would be a good method of storing info, but as it is, I genuinely have to separate an array out into multiple entries to make it work, which just seems silly to me when storing arrays is supposed to be possible.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
base64 encoding/decoding didn't work at all- it'd encode, but the decode wouldn't give back the ds_map, only giving "0".
With both it'd be json_encode -> transformation -> ini_write_string, then ini_read_string -> back transformation -> json_decode. Show write/read code if that doesn't work

Is there really no way to make the .ini reader/writer not add its own quotes around the entries? Because that's genuinely THE problem here- if it just did not do that, this would be a good method of storing info, but as it is, I genuinely have to separate an array out into multiple entries to make it work, which just seems silly to me when storing arrays is supposed to be possible.
I don't think there is with built-in - I made a custom INI extension few years ago (post) specifically because there were various mishaps that I kept running into.
 
With both it'd be json_encode -> transformation -> ini_write_string, then ini_read_string -> back transformation -> json_decode. Show write/read code if that doesn't work


I don't think there is with built-in - I made a custom INI extension few years ago (post) specifically because there were various mishaps that I kept running into.
*facepalm* I forgot it said it takes a string, not an object....whoops.

EDIT: Tested it, that worked!! I'd likely use the text-file functions for save files, where the quotation marks aren't an issue, but this can come in handy still! Thank you so much!
 
Last edited:
Top