Quick answer: Write to a temp file first (save.tmp), then rename via file_rename to the final name. Keep a previous-version backup for fallback.
An RPG saves to slot via ds_map_secure_save. A player’s GPU crashes the game mid-save; on relaunch, “Save corrupted, starting new game”. They lose 10 hours of progress.
Atomic Write
function safe_save(filename, data_map) {
var tmp = filename + ".tmp";
ds_map_secure_save(data_map, tmp);
if (file_exists(filename)) file_delete(filename);
file_rename(tmp, filename);
}
Three-step: write to .tmp, delete old, rename .tmp to final. Each step is atomic; if the game dies between, either the old or new file is whole, never half-written.
Keep Previous Save as Backup
function safe_save_with_backup(filename, data_map) {
var tmp = filename + ".tmp";
var bak = filename + ".bak";
ds_map_secure_save(data_map, tmp);
if (file_exists(filename)) {
if (file_exists(bak)) file_delete(bak);
file_rename(filename, bak);
}
file_rename(tmp, filename);
}
Previous save kept as .bak. Two generations recoverable.
Safe Load
function safe_load(filename) {
if (file_exists(filename)) {
var m = ds_map_secure_load(filename);
if (m != -1) return m;
}
// fall back to backup
var bak = filename + ".bak";
if (file_exists(bak)) {
return ds_map_secure_load(bak);
}
return undefined;
}
Try primary; on decryption failure (returns -1), try .bak. Players keep most of their progress.
Flush to Disk
On Steam Deck/Switch, OS may buffer writes. After the rename, force a sync if your build target supports it. GameMaker on PC usually flushes immediately.
Verifying
Save, kill the process mid-game (Task Manager). Reload — previous save loads cleanly. Test repeatedly. Then test mid-write kill: previous file should still load via backup path.
“Atomic write + backup = no torn saves. Players forgive a small rollback; they don’t forgive total loss.”
For Steam Cloud Save users, add a checksum file alongside save.dat — lets you detect cloud corruption on download too.