From 2f9c587622798f1d9bbc9e4e3b76964216e0d7b0 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 8 Aug 2026 18:35:06 +1000 Subject: [PATCH] FullscreenUI: Fix shared memory card selection --- src/core/fullscreenui_settings.cpp | 62 +++++++++++-------- src/core/fullscreenui_strings.h | 1 + src/core/settings.cpp | 16 ++++- src/core/settings.h | 2 +- src/core/system.cpp | 2 +- .../memorycardsettingswidget.cpp | 4 +- 6 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/core/fullscreenui_settings.cpp b/src/core/fullscreenui_settings.cpp index b18b76f0c..0196e90e0 100644 --- a/src/core/fullscreenui_settings.cpp +++ b/src/core/fullscreenui_settings.cpp @@ -4278,10 +4278,9 @@ void FullscreenUI::DrawMemoryCardSettingsPage() .c_str()) .value_or(default_type); const bool is_shared = (effective_type == MemoryCardType::Shared); - std::optional path_value(bsi->GetOptionalSmallStringValue( + std::optional path_value = bsi->GetOptionalSmallStringValue( "MemoryCards", path_keys[i], - IsEditingGameSettings(bsi) ? std::nullopt : - std::optional((i == 0) ? "shared_card_1.mcd" : "shared_card_2.mcd"))); + IsEditingGameSettings(bsi) ? std::nullopt : std::make_optional(Settings::GetDefaultSharedMemoryCardName(i))); TinyString title; title.format("{}##card_name_{}", FSUI_ICONVSTR(ICON_FA_FILE, "Shared Card Name"), i); @@ -4290,12 +4289,11 @@ void FullscreenUI::DrawMemoryCardSettingsPage() { ChoiceDialogOptions options; std::vector names; + bool current_value_added = false; if (IsEditingGameSettings(bsi)) - options.emplace_back("Use Global Setting", !path_value.has_value()); - if (path_value.has_value() && !path_value->empty()) { - options.emplace_back(fmt::format("{} (Current)", path_value.value()), true); - names.emplace_back(path_value.value().view()); + current_value_added |= !path_value.has_value(); + options.emplace_back(FSUI_STR("Use Global Setting"), !path_value.has_value()); } FileSystem::FindResultsArray results; @@ -4305,29 +4303,39 @@ void FullscreenUI::DrawMemoryCardSettingsPage() for (FILESYSTEM_FIND_DATA& ffd : results) { const bool selected = (path_value.has_value() && path_value.value() == ffd.FileName); - options.emplace_back(std::move(ffd.FileName), selected); + current_value_added |= selected; + options.emplace_back(ffd.FileName, selected); + names.push_back(std::move(ffd.FileName)); } - OpenChoiceDialog( - title, false, std::move(options), - [game_settings = IsEditingGameSettings(bsi), i](s32 index, const std::string& title, bool checked) { - if (index < 0) - return; + // add current entry if it's missing, e.g. the file was removed + if (!current_value_added && path_value.has_value() && !path_value->empty()) + { + options.emplace_back(fmt::format(FSUI_FSTR("{0} (Missing)"), Path::GetFileName(path_value.value())), true); + names.emplace_back(path_value.value().view()); + } - const auto lock = Core::GetSettingsLock(); - SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); - if (game_settings && index == 0) - { - bsi->DeleteValue("MemoryCards", path_keys[i]); - } - else - { - if (game_settings) - index--; - bsi->SetStringValue("MemoryCards", path_keys[i], title.c_str()); - } - SetSettingsChanged(bsi); - }); + OpenChoiceDialog(title, false, std::move(options), + [names = std::move(names), i, + game_settings = IsEditingGameSettings(bsi)](s32 index, const std::string& title, bool checked) { + if (index < 0) + return; + + const auto lock = Core::GetSettingsLock(); + SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); + if (game_settings && index == 0) + { + bsi->DeleteValue("MemoryCards", path_keys[i]); + } + else + { + if (game_settings) + index--; + bsi->SetStringValue("MemoryCards", path_keys[i], + Path::MakeRelative(names[index], EmuFolders::MemoryCards).c_str()); + } + SetSettingsChanged(bsi); + }); } } diff --git a/src/core/fullscreenui_strings.h b/src/core/fullscreenui_strings.h index 8f018e176..d10204e15 100644 --- a/src/core/fullscreenui_strings.h +++ b/src/core/fullscreenui_strings.h @@ -932,6 +932,7 @@ TRANSLATE_NOOP("FullscreenUI", "\"PlayStation\" and \"PSX\" are registered trade TRANSLATE_NOOP("FullscreenUI", "change disc"); TRANSLATE_NOOP("FullscreenUI", "restart"); TRANSLATE_NOOP("FullscreenUI", "shut down"); +TRANSLATE_NOOP("FullscreenUI", "{0} (Missing)"); TRANSLATE_NOOP("FullscreenUI", "{0} achievement unlocks have not been confirmed by the server. Continuing to {1} will result in loss of these unlocks. Once network connectivity has been re-established, these unlocks will be confirmed automatically.\n\nDo you want to {1} anyway?"); TRANSLATE_NOOP("FullscreenUI", "{} Frames"); TRANSLATE_NOOP("FullscreenUI", "{} deleted."); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 1d9f17906..f0ff20913 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -2599,9 +2599,19 @@ const char* Settings::GetMemoryCardTypeDisplayName(MemoryCardType type) "MemoryCardType"); } -std::string Settings::GetDefaultSharedMemoryCardName(u32 slot) -{ - return fmt::format("shared_card_{}.mcd", slot + 1); +const char* Settings::GetDefaultSharedMemoryCardName(u32 slot) +{ + static constexpr std::array default_names = {{ + "shared_card_1.mcd", + "shared_card_2.mcd", + "shared_card_3.mcd", + "shared_card_4.mcd", + "shared_card_5.mcd", + "shared_card_6.mcd", + "shared_card_7.mcd", + "shared_card_8.mcd", + }}; + return default_names[std::min(slot, NUM_CONTROLLER_AND_CARD_PORTS - 1)]; } std::string Settings::GetSharedMemoryCardPath(u32 slot) const diff --git a/src/core/settings.h b/src/core/settings.h index 63a68cda4..de2f7daff 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -423,7 +423,7 @@ struct Settings : public GPUSettings bool HasAnyPerGameMemoryCards() const; /// Returns the default path to a memory card. - static std::string GetDefaultSharedMemoryCardName(u32 slot); + static const char* GetDefaultSharedMemoryCardName(u32 slot); std::string GetSharedMemoryCardPath(u32 slot) const; /// Returns the default path to a memory card for a specific game. diff --git a/src/core/system.cpp b/src/core/system.cpp index c448b44d5..fd015298c 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -5817,7 +5817,7 @@ std::string System::GetGameMemoryCardPath(std::string_view custom_title, std::st { const TinyString path_key = TinyString::from_format("Card{}Path", slot + 1); std::string global_path = - Core::GetBaseStringSettingValue(section, path_key, Settings::GetDefaultSharedMemoryCardName(slot + 1).c_str()); + Core::GetBaseStringSettingValue(section, path_key, Settings::GetDefaultSharedMemoryCardName(slot + 1)); if (ini && ini->ContainsValue(section, path_key)) ret = ini->GetStringValue(section, path_key, global_path.c_str()); else diff --git a/src/duckstation-qt/memorycardsettingswidget.cpp b/src/duckstation-qt/memorycardsettingswidget.cpp index f8a8aaaee..3d825fbd0 100644 --- a/src/duckstation-qt/memorycardsettingswidget.cpp +++ b/src/duckstation-qt/memorycardsettingswidget.cpp @@ -309,7 +309,7 @@ void MemoryCardSettingsWidget::onResetMemoryCardPathClicked(u32 index) if (m_dialog->isPerGameSettings()) m_dialog->removeSettingValue("MemoryCards", key); else - m_dialog->setStringSettingValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str()); + m_dialog->setStringSettingValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index)); updateMemoryCardPath(index); } @@ -318,7 +318,7 @@ void MemoryCardSettingsWidget::updateMemoryCardPath(u32 index) { const auto key = TinyString::from_format("Card{}Path", index + 1); std::string path( - m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index).c_str())); + m_dialog->getEffectiveStringValue("MemoryCards", key, Settings::GetDefaultSharedMemoryCardName(index))); if (!Path::IsAbsolute(path)) path = Path::Canonicalize(Path::Combine(EmuFolders::MemoryCards, path));