Skip to content

Commit

Permalink
Qt: Consider per-game overrides for Edit Memory Cards menu
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed May 14, 2024
1 parent cea061f commit c116e5a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 46 deletions.
97 changes: 97 additions & 0 deletions src/core/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4634,6 +4634,103 @@ void System::DeleteSaveStates(const char* serial, bool resume)
}
}

std::string System::GetGameMemoryCardPath(std::string_view serial, std::string_view path, u32 slot)
{
const char* section = "MemoryCards";
const TinyString type_key = TinyString::from_format("Card{}Type", slot + 1);
const MemoryCardType default_type =
(slot == 0) ? Settings::DEFAULT_MEMORY_CARD_1_TYPE : Settings::DEFAULT_MEMORY_CARD_2_TYPE;
const MemoryCardType global_type =
Settings::ParseMemoryCardTypeName(
Host::GetBaseTinyStringSettingValue(section, type_key, Settings::GetMemoryCardTypeName(default_type)))
.value_or(default_type);

MemoryCardType type = global_type;
std::unique_ptr<INISettingsInterface> ini;
if (!serial.empty())
{
std::string game_settings_path = GetGameSettingsPath(serial);
if (FileSystem::FileExists(game_settings_path.c_str()))
{
ini = std::make_unique<INISettingsInterface>(std::move(game_settings_path));
if (!ini->Load())
{
ini.reset();
}
else if (ini->ContainsValue(section, type_key))
{
type = Settings::ParseMemoryCardTypeName(
ini->GetTinyStringValue(section, type_key, Settings::GetMemoryCardTypeName(global_type)))
.value_or(global_type);
}
}
}
else if (type == MemoryCardType::PerGame)
{
// always shared without serial
type = MemoryCardType::Shared;
}

std::string ret;
switch (type)
{
case MemoryCardType::None:
break;

case MemoryCardType::Shared:
{
const TinyString path_key = TinyString::from_format("Card{}Path", slot + 1);
std::string global_path =
Host::GetBaseStringSettingValue(section, path_key, Settings::GetDefaultSharedMemoryCardName(slot + 1).c_str());
if (ini && ini->ContainsValue(section, path_key))
ret = ini->GetStringValue(section, path_key, global_path.c_str());
else
ret = std::move(global_path);

if (!Path::IsAbsolute(ret))
ret = Path::Combine(EmuFolders::MemoryCards, ret);
}
break;

case MemoryCardType::PerGame:
ret = g_settings.GetGameMemoryCardPath(serial, slot);
break;

case MemoryCardType::PerGameTitle:
{
const GameDatabase::Entry* entry = GameDatabase::GetEntryForSerial(serial);
if (entry)
{
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->title), slot);

// Use disc set name if there isn't a per-disc card present.
const bool global_use_playlist_title = Host::GetBaseBoolSettingValue(section, "UsePlaylistTitle", true);
const bool use_playlist_title =
ini ? ini->GetBoolValue(section, "UsePlaylistTitle", global_use_playlist_title) : global_use_playlist_title;
if (entry->disc_set_name.empty() && use_playlist_title && !FileSystem::FileExists(ret.c_str()))
ret = g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->disc_set_name), slot);
}
else
{
ret = g_settings.GetGameMemoryCardPath(
Path::SanitizeFileName(Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path))), slot);
}
}
break;

case MemoryCardType::PerGameFileTitle:
{
ret = g_settings.GetGameMemoryCardPath(
Path::SanitizeFileName(Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path))), slot);
}
break;
default:
break;
}

return ret;
}

std::string System::GetMostRecentResumeSaveStatePath()
{
std::vector<FILESYSTEM_FIND_DATA> files;
Expand Down
3 changes: 3 additions & 0 deletions src/core/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,9 @@ std::optional<ExtendedSaveStateInfo> GetExtendedSaveStateInfo(const char* path);
/// Deletes save states for the specified game code. If resume is set, the resume state is deleted too.
void DeleteSaveStates(const char* serial, bool resume);

/// Returns the path to the memory card for the specified game, considering game settings.
std::string GetGameMemoryCardPath(std::string_view serial, std::string_view path, u32 slot);

/// Returns intended output volume considering fast forwarding.
s32 GetAudioOutputVolume();
void UpdateVolume();
Expand Down
47 changes: 1 addition & 46 deletions src/duckstation-qt/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,52 +809,7 @@ void MainWindow::populateGameListContextMenu(const GameList::Entry* entry, QWidg
connect(open_memory_cards_action, &QAction::triggered, [entry]() {
QString paths[2];
for (u32 i = 0; i < 2; i++)
{
MemoryCardType type = g_settings.memory_card_types[i];
if (entry->serial.empty() && type == MemoryCardType::PerGame)
type = MemoryCardType::Shared;

switch (type)
{
case MemoryCardType::None:
continue;
case MemoryCardType::Shared:
if (g_settings.memory_card_paths[i].empty())
{
paths[i] = QString::fromStdString(g_settings.GetSharedMemoryCardPath(i));
}
else
{
QFileInfo path(QString::fromStdString(g_settings.memory_card_paths[i]));
path.makeAbsolute();
paths[i] = QDir::toNativeSeparators(path.canonicalFilePath());
}
break;
case MemoryCardType::PerGame:
paths[i] = QString::fromStdString(g_settings.GetGameMemoryCardPath(entry->serial, i));
break;
case MemoryCardType::PerGameTitle:
{
paths[i] = QString::fromStdString(g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->title), i));
if (!entry->disc_set_name.empty() && g_settings.memory_card_use_playlist_title && !QFile::exists(paths[i]))
{
paths[i] =
QString::fromStdString(g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(entry->disc_set_name), i));
}
}
break;

case MemoryCardType::PerGameFileTitle:
{
const std::string display_name(FileSystem::GetDisplayNameFromPath(entry->path));
paths[i] = QString::fromStdString(
g_settings.GetGameMemoryCardPath(Path::SanitizeFileName(Path::GetFileTitle(display_name)), i));
}
break;
default:
break;
}
}
paths[i] = QString::fromStdString(System::GetGameMemoryCardPath(entry->serial, entry->path, i));

g_main_window->openMemoryCardEditor(paths[0], paths[1]);
});
Expand Down

0 comments on commit c116e5a

Please sign in to comment.