From 4ac4388b0856ef1248a6d81d10bac500d2d5d266 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 29 Nov 2023 23:05:27 +1000 Subject: [PATCH] GameDatabase: Fix identification of misnamed-exe games --- src/core/game_database.cpp | 24 ++++++++++++++++--- src/core/game_database.h | 2 +- src/core/game_list.cpp | 2 +- src/core/system.cpp | 2 +- src/duckstation-qt/settingswindow.cpp | 33 ++++++++++++++++++++++----- 5 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/core/game_database.cpp b/src/core/game_database.cpp index 4fe4f531d..7f32445b7 100644 --- a/src/core/game_database.cpp +++ b/src/core/game_database.cpp @@ -41,6 +41,7 @@ enum : u32 }; static Entry* GetMutableEntry(const std::string_view& serial); +static const Entry* GetEntryForId(const std::string_view& code); static bool LoadFromCache(); static bool SaveToCache(); @@ -149,15 +150,32 @@ std::string GameDatabase::GetSerialForPath(const char* path) const GameDatabase::Entry* GameDatabase::GetEntryForDisc(CDImage* image) { std::string id; - System::GetGameDetailsFromImage(image, &id, nullptr); + System::GameHash hash; + System::GetGameDetailsFromImage(image, &id, &hash); + const Entry* entry = GetEntryForGameDetails(id, hash); + if (entry) + return entry; + + Log_WarningPrintf("No entry found for disc '%s'", id.c_str()); + return nullptr; +} + +const GameDatabase::Entry* GameDatabase::GetEntryForGameDetails(const std::string& id, u64 hash) +{ + const Entry* entry; + if (!id.empty()) { - const Entry* entry = GetEntryForId(id); + entry = GetEntryForId(id); if (entry) return entry; } - Log_WarningPrintf("No entry found for disc '%s'", id.c_str()); + // some games with invalid serials use the hash + entry = GetEntryForId(System::GetGameHashId(hash)); + if (entry) + return entry; + return nullptr; } diff --git a/src/core/game_database.h b/src/core/game_database.h index 3433c8d97..a8117206e 100644 --- a/src/core/game_database.h +++ b/src/core/game_database.h @@ -92,7 +92,7 @@ void EnsureLoaded(); void Unload(); const Entry* GetEntryForDisc(CDImage* image); -const Entry* GetEntryForId(const std::string_view& code); +const Entry* GetEntryForGameDetails(const std::string& id, u64 hash); const Entry* GetEntryForSerial(const std::string_view& serial); std::string GetSerialForDisc(CDImage* image); std::string GetSerialForPath(const char* path); diff --git a/src/core/game_list.cpp b/src/core/game_list.cpp index 690763055..6d0d6cc37 100644 --- a/src/core/game_list.cpp +++ b/src/core/game_list.cpp @@ -216,7 +216,7 @@ bool GameList::GetDiscListEntry(const std::string& path, Entry* entry) System::GetGameDetailsFromImage(cdi.get(), &id, &entry->hash); // try the database first - const GameDatabase::Entry* dentry = GameDatabase::GetEntryForId(id); + const GameDatabase::Entry* dentry = GameDatabase::GetEntryForGameDetails(id, entry->hash); if (dentry) { // pull from database diff --git a/src/core/system.cpp b/src/core/system.cpp index 7d3a03834..fc08df79d 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -3346,7 +3346,7 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting) std::string id; GetGameDetailsFromImage(image, &id, &s_running_game_hash); - s_running_game_entry = GameDatabase::GetEntryForId(id); + s_running_game_entry = GameDatabase::GetEntryForGameDetails(id, s_running_game_hash); if (s_running_game_entry) { s_running_game_serial = s_running_game_entry->serial; diff --git a/src/duckstation-qt/settingswindow.cpp b/src/duckstation-qt/settingswindow.cpp index 7b87cf29e..a04588c1c 100644 --- a/src/duckstation-qt/settingswindow.cpp +++ b/src/duckstation-qt/settingswindow.cpp @@ -26,11 +26,15 @@ #include "util/ini_settings_interface.h" #include "common/assert.h" +#include "common/error.h" #include "common/file_system.h" +#include "common/log.h" #include #include +Log_SetChannel(SettingsWindow); + static QList s_open_game_properties_dialogs; SettingsWindow::SettingsWindow() : QWidget() @@ -484,18 +488,35 @@ void SettingsWindow::openGamePropertiesDialog(const std::string& path, const std } } - std::string filename(System::GetGameSettingsPath(serial)); - std::unique_ptr sif = std::make_unique(std::move(filename)); + const GameDatabase::Entry* dentry = nullptr; + if (!System::IsExeFileName(path) && !System::IsPsfFileName(path)) + { + // Need to resolve hash games. + Error error; + std::unique_ptr image = CDImage::Open(path.c_str(), false, &error); + if (image) + dentry = GameDatabase::GetEntryForDisc(image.get()); + else + Log_ErrorFmt("Failed to open '{}' for game properties: {}", path, error.GetDescription()); + + if (!dentry) + { + // Use the serial and hope for the best... + dentry = GameDatabase::GetEntryForSerial(serial); + } + } + + const std::string& real_serial = dentry ? dentry->serial : serial; + std::string ini_filename = System::GetGameSettingsPath(real_serial); + std::unique_ptr sif = std::make_unique(std::move(ini_filename)); if (FileSystem::FileExists(sif->GetFileName().c_str())) sif->Load(); - const GameDatabase::Entry* dentry = GameDatabase::GetEntryForSerial(serial); - const QString window_title(tr("%1 [%2]") .arg(dentry ? QtUtils::StringViewToQString(dentry->title) : QStringLiteral("")) - .arg(QtUtils::StringViewToQString(serial))); + .arg(QtUtils::StringViewToQString(real_serial))); - SettingsWindow* dialog = new SettingsWindow(path, serial, region, dentry, std::move(sif)); + SettingsWindow* dialog = new SettingsWindow(path, real_serial, region, dentry, std::move(sif)); dialog->setWindowTitle(window_title); dialog->show(); }