• 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!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Legacy GM [SOLVED] ds_map_secure_save on another device/computer

Qual

Member
Hello! Is there a work around to prevent user to modify manually a map saved with ds_map_secure_save() while keeping the ability to transfer the game folder on another computer ?

Because using ds_map_secure_load() on another device will trigger errors, and a lof of my players have tons of 'recorded best runs' ( It's a speedunning platformer, with a 'ghost' feature to play against other players/your own ghost)

But if an user change his phone, or got a new computer, he will not be able to load these files.

But everything is also tied to an online leaderboard, so that's why I prevent the user to modify manually the file before he upload his run on the leaderboard to avoid cheating)

I now ds_map_secure_save is just a base64 json with some crypted header, but not sure how to find a work around to load it on another device.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
If you don't want encryption to be device-specific, you'll need a custom extension for encrypt/decrypt data, e.g. this one.
 

Ricardo

Member
If true encryption isn't a problem, you can save ds maps easily using json_encode.

new_ds_map_secure_save():
Code:
/// @description new_ds_map_secure_save(map,path)
/// @function new_ds_map_secure_save
/// @param map
/// @param filename

var map = ds_map_create();
ds_map_copy(map,argument[0]);
var path = argument[1];

var t = base64_encode(json_encode(map));
var f = file_text_open_write(path);
if (f != -1) {
    file_text_write_string(f, t);
    file_text_close(f);
    ds_map_destroy(map);
}
else {
    printError("Error in new_ds_map_secure_save. Cant create: " + f);
}
new_ds_map_secure_load():
Code:
/// @description new_ds_map_secure_load (path)
/// @function new_ds_map_secure_load
/// @param path

var path = argument[0];

var f = file_text_open_read(path);
var t = base64_decode(file_text_read_string(f));
file_text_close(f);
var map = json_decode(t);
return map;
Not sophisticated, but that had worked well in a project of mine and the saves aren't device-specific.
 

Qual

Member
If true encryption isn't a problem, you can save ds maps easily using json_encode.

new_ds_map_secure_save():
Code:
/// @description new_ds_map_secure_save(map,path)
/// @function new_ds_map_secure_save
/// @param map
/// @param filename

var map = ds_map_create();
ds_map_copy(map,argument[0]);
var path = argument[1];

var t = base64_encode(json_encode(map));
var f = file_text_open_write(path);
if (f != -1) {
    file_text_write_string(f, t);
    file_text_close(f);
    ds_map_destroy(map);
}
else {
    printError("Error in new_ds_map_secure_save. Cant create: " + f);
}
new_ds_map_secure_load():
Code:
/// @description new_ds_map_secure_load (path)
/// @function new_ds_map_secure_load
/// @param path

var path = argument[0];

var f = file_text_open_read(path);
var t = base64_decode(file_text_read_string(f));
file_text_close(f);
var map = json_decode(t);
return map;
Not sophisticated, but that had worked well in a project of mine and the saves aren't device-specific.

Thank you, I use something similar to save downloaded replays from my server (As I don't care if people mess with them, since they can't upload a downloaded file, I also transform every real in the Json in string so instead of 1.000000 i have only '"1" saved in the file, so the total filezise with hundreds of variable is also divided by almost 3. I don't use base64 as it's trivial to hack it if you want.

If you don't want encryption to be device-specific, you'll need a custom extension for encrypt/decrypt data, e.g. this one.
Interesting for other stuff I may need, but players have already thousands of file saved with ds_map_secure_save, so I was looking for a way to load an already existing ds_map_secure
 

Ricardo

Member
Interesting for other stuff I may need, but players have already thousands of file saved with ds_map_secure_save, so I was looking for a way to load an already existing ds_map_secure
So, I've already faced that problem and I managed to solve it, but my save file was quite simple.

You can open the ds_map_secure_save file as a normal text:
Code:
var t;
    while (!file_text_eof(scriptFile)) {
        t = file_text_read_string(scriptFile);
        file_text_readln(scriptFile);
    }
    file_text_close(scriptFile);

And then create a map: map = json_decode(t);
However, if you see the map data in the debugger, you'll see most of the things are encoded. The "headers", though, should be as plain text, and you can get the data you need using something like this:

Code:
 var nameStr = base64_decode(ds_map_find_value(map,"gameName.344810370.player.dat"));
And then you can use some string_pos to extract the data you need.
Although possible, it's a very tedious and a hard job depending on how much data the file has. So you really need to be sure that spend time "hacking" a ds_map_secure_save file worth it.
 

Dmi7ry

Member
Interesting for other stuff I may need, but players have already thousands of file saved with ds_map_secure_save, so I was looking for a way to load an already existing ds_map_secure
Possible that there is only one way - special "export" option which will strore settings on old device (ds_map_secure_load + platform independent aes save) and then load stored aes on new device. Or it may be a small special programm.
 

Qual

Member
Solved !

Code:
saved_replay = ds_map_secure_load(file)
if saved_replay != -1
{
    // ds_map_secure_load OK, no need to decryt it.
}
else
{
    //  Looking if we already have decrypted the file
    saved_replay = json_decode(file_get_string(file))
    if saved_replay != -1
    {
        // already decrypted file OK
    }
    else
    {
        // TRY TO FIX THE FILE
        ds_map_secure_fix(file)
        saved_replay = json_decode(file_get_string(file))
        if saved_replay != -1
        {
            // decryption OK !
        }

        else
            show_message("Error trying to decrypt file created on another device.")
    }
}

file_get_string()

Code:
//file_get_string(file)
var f,str;
str=""
if (!file_exists(argument0)) return ""
f=file_text_open_read(argument0)
while (!file_text_eof(f)) {
    str+=file_text_read_string(f)
    file_text_readln(f)
}


file_text_close(f)
return str
ds_map_secure_fix()
Code:
var original = argument0;
text = file_get_string(original);
text = base64_decode(text);
text = string_delete(text,1,string_pos('"',text)-1)
text = '{ '+text
file = file_text_open_write(original);
file_text_write_string(file,text);
file_text_close(file);
show_debug_message("done!");

It worked for me on 140/140 files with thousands of entries like :

"25_pY": 413.000000, "25_pI": "sPlayerSideB", "50_pIa": 0.000000, "30_pYs": 1.000000, "20_pI": "sPlayerSideB", "52_tX_explode_2": 960.000000,

So I hope you can get use this as a base to decrypt your own files :)
 
Top