From 55f53d452323f9710a97a3fa5367fb4d1f7eb1b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sat, 12 Sep 2026 10:56:34 -0600 Subject: [PATCH] Savestate names: read from the cached listing, and tidy up the name files GetSlotCustomName hit the disk for every slot each time the pause screen built its views, almost always for a file that isn't there. Rescan's listing already knows, and HasSaveInSlot - which gates whether the name is even shown - reads the same map, so this can't hide a name the old code would have found. SetSlotCustomName now rescans, so a rename is visible without depending on the pause screen happening to rescan on its way back. Also: clearing a name deletes the file instead of leaving an empty one behind, and the extension is "name.txt" rather than plain "txt", so an unrelated "_.txt" in the savestate folder isn't read as a slot name. Co-Authored-By: Claude Opus 5 (1M context) --- Core/SaveState.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index a0972237e0..1dfa5a86ee 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -66,7 +66,9 @@ constexpr int SCREENSHOT_FAILURE_RETRIES = 6; static const char * const STATE_EXTENSION = "ppst"; static const char * const UNDO_STATE_EXTENSION = "undo.ppst"; static const char * const UNDO_SCREENSHOT_EXTENSION = "undo.jpg"; -static const char * const NAME_EXTENSION = "txt"; +// Namespaced the way UNDO_STATE_EXTENSION is, so a stray "_.txt" someone happened to +// leave in the savestate folder isn't mistaken for a slot's name. +static const char * const NAME_EXTENSION = "name.txt"; static const char * const LOAD_UNDO_NAME = "load_undo.ppst"; @@ -708,14 +710,29 @@ int g_screenshotFailures; } std::string GetSlotCustomName(std::string_view gamePrefix, int slot) { + // Most slots don't have a name file, and this gets called for every slot each time the + // pause screen builds its views - so consult the listing before touching the disk. + if (!SaveStateFileExists(gamePrefix, slot, NAME_EXTENSION)) { + return std::string(); + } Path path = GenerateSaveSlotPath(gamePrefix, slot, NAME_EXTENSION); - std::string result = ""; + std::string result; File::ReadBinaryFileToString(path, &result); return result; } void SetSlotCustomName(std::string_view gamePrefix, int slot, std::string_view new_name){ - File::WriteStringToFile(true, new_name, GenerateSaveSlotPath(gamePrefix, slot, NAME_EXTENSION)); + const Path path = GenerateSaveSlotPath(gamePrefix, slot, NAME_EXTENSION); + if (new_name.empty()) { + // Clearing the name. Leaving an empty file behind would work, but it'd stay in the + // savestate folder for good - a slot with no name shouldn't have a name file. + DeleteIfExists(path); + } else { + File::WriteStringToFile(true, new_name, path); + } + // What we just wrote (or removed) isn't reflected in the listing GetSlotCustomName reads, + // so without this the change wouldn't show up until something else happened to rescan. + Rescan(gamePrefix); } std::vector Flush() {