From 81437eda3e9655feeeb51e11b3613079ac335c01 Mon Sep 17 00:00:00 2001 From: AnturK Date: Tue, 22 Feb 2022 10:27:25 +0100 Subject: [PATCH] Hardens painting saving against inconsistent state (#65024) Should help when paintings lists gets zeroed unintentionally during the round for some reason. Now it only deletes the painting file right before it writes the new file to prevent loss of data if anything runtimes or breaks. --- .../subsystem/persistent_paintings.dm | 26 ++++++++++++++++--- code/modules/admin/painting_manager.dm | 1 + 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/code/controllers/subsystem/persistent_paintings.dm b/code/controllers/subsystem/persistent_paintings.dm index f0a1fe83f98..e7ca7510997 100644 --- a/code/controllers/subsystem/persistent_paintings.dm +++ b/code/controllers/subsystem/persistent_paintings.dm @@ -94,6 +94,8 @@ SUBSYSTEM_DEF(persistent_paintings) /// A list of painting frames that this controls var/list/obj/structure/sign/painting/painting_frames = list() + /// Hashes of paintings deleted this round + var/list/deleted_paintings_md5s = list() /// A list of /datum/paintings saved or ready to be saved this round. var/list/paintings = list() @@ -196,10 +198,26 @@ SUBSYSTEM_DEF(persistent_paintings) /// Saves all currently tracked painting data to file /datum/controller/subsystem/persistent_paintings/proc/save_to_file() var/json_file = file("data/paintings.json") - fdel(json_file) - var/list/all_data = list("version" = PAINTINGS_DATA_FORMAT_VERSION) + + var/list/collated_data = list() + if(fexists(json_file)) + var/list/old_data = json_decode(file2text(json_file)) + for(var/list/painting_data as anything in old_data["paintings"]) + collated_data[painting_data["md5"]] = painting_data + var/list/painting_data = list() for(var/datum/painting/painting as anything in paintings) - painting_data += list(painting.to_json()) + collated_data[painting.md5] = painting.to_json() //Current data has priority over old data + + // Remove deleted paintings from the list + collated_data -= deleted_paintings_md5s + + // Flatten the resulting list + for(var/key in collated_data) + painting_data += list(collated_data[key]) + + var/list/all_data = list("version" = PAINTINGS_DATA_FORMAT_VERSION) all_data["paintings"] = painting_data - WRITE_FILE(json_file, json_encode(all_data)) + var/payload = json_encode(all_data) + fdel(json_file) + WRITE_FILE(json_file, payload) diff --git a/code/modules/admin/painting_manager.dm b/code/modules/admin/painting_manager.dm index 37c86b160f1..b3d76de0c19 100644 --- a/code/modules/admin/painting_manager.dm +++ b/code/modules/admin/painting_manager.dm @@ -47,6 +47,7 @@ fdel(png) //Remove entry from paintings list SSpersistent_paintings.paintings -= chosen_painting + SSpersistent_paintings.deleted_paintings_md5s |= chosen_painting.md5 SSpersistent_paintings.save_to_file() // Save now so we don't have broken variations if this round crashes //Delete any painting instances in the current round for(var/obj/structure/sign/painting/painting as anything in SSpersistent_paintings.painting_frames)