Skip to content

Commit 7970287

Browse files
committed
GameList: Fix memcard icon extraction for non-database games
Also fix "Edit Memory Cards" menu option.
1 parent 1bf7431 commit 7970287

File tree

7 files changed

+42
-38
lines changed

7 files changed

+42
-38
lines changed

src/core/fullscreenui_game_list.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,12 +1065,12 @@ GPUTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry, bool fa
10651065
}
10661066

10671067
// because memcard icons are crap res
1068-
if (fallback_to_icon && cover_it->second.empty())
1068+
if (fallback_to_icon && cover_it->second.empty() && !entry->serial.empty() && entry->IsDiscOrDiscSet())
10691069
{
10701070
cover_it = s_game_list_locals.icon_image_map.find(entry->serial);
10711071
if (cover_it == s_game_list_locals.icon_image_map.end())
10721072
{
1073-
std::string icon_path = GameList::GetGameIconPath(entry->serial, entry->path, entry->achievements_game_id);
1073+
std::string icon_path = GameList::GetGameIconPath(entry);
10741074
cover_it = s_game_list_locals.icon_image_map.emplace(entry->serial, std::move(icon_path)).first;
10751075
}
10761076
}

src/core/game_list.cpp

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,28 +2026,29 @@ void GameList::ReloadMemcardTimestampCache()
20262026
entry.serial[sizeof(entry.serial) - 1] = 0;
20272027
}
20282028

2029-
std::string GameList::GetGameIconPath(std::string_view serial, std::string_view path, u32 achievements_game_id)
2029+
std::string GameList::GetGameIconPath(const GameList::Entry* entry)
20302030
{
20312031
std::string ret;
20322032

20332033
std::string fallback_path;
2034-
if (achievements_game_id != 0)
2034+
if (entry->achievements_game_id != 0)
20352035
{
2036-
fallback_path = GetAchievementGameBadgePath(achievements_game_id);
2036+
fallback_path = GetAchievementGameBadgePath(entry->achievements_game_id);
20372037
if (!fallback_path.empty() && PreferAchievementGameBadgesForIcons())
20382038
return (ret = std::move(fallback_path));
20392039
}
20402040

2041-
if (serial.empty())
2041+
if (entry->serial.empty())
20422042
return (ret = std::move(fallback_path));
20432043

20442044
// might exist already, or the user used a custom icon
2045-
ret = Path::Combine(EmuFolders::GameIcons, TinyString::from_format("{}.png", serial));
2045+
ret = Path::Combine(EmuFolders::GameIcons, TinyString::from_format("{}.png", entry->serial));
20462046
if (FileSystem::FileExists(ret.c_str()))
20472047
return ret;
20482048

20492049
MemoryCardType type;
2050-
std::string memcard_path = System::GetGameMemoryCardPath(serial, path, 0, &type);
2050+
std::string memcard_path =
2051+
System::GetGameMemoryCardPath(entry->title, entry->has_custom_title, entry->serial, entry->path, 0, &type);
20512052
FILESYSTEM_STAT_DATA memcard_sd;
20522053
if (memcard_path.empty() || type == MemoryCardType::Shared ||
20532054
!FileSystem::StatFile(memcard_path.c_str(), &memcard_sd))
@@ -2057,33 +2058,33 @@ std::string GameList::GetGameIconPath(std::string_view serial, std::string_view
20572058

20582059
const s64 timestamp = memcard_sd.ModificationTime;
20592060
TinyString index_serial;
2060-
index_serial.assign(
2061-
serial.substr(0, std::min<size_t>(serial.length(), MemcardTimestampCacheEntry::MAX_SERIAL_LENGTH - 1)));
2061+
index_serial.assign(entry->serial.substr(
2062+
0, std::min<size_t>(entry->serial.length(), MemcardTimestampCacheEntry::MAX_SERIAL_LENGTH - 1)));
20622063

2063-
MemcardTimestampCacheEntry* serial_entry = nullptr;
2064-
for (MemcardTimestampCacheEntry& entry : s_state.memcard_timestamp_cache_entries)
2064+
MemcardTimestampCacheEntry* cache_entry = nullptr;
2065+
for (MemcardTimestampCacheEntry& it : s_state.memcard_timestamp_cache_entries)
20652066
{
2066-
if (StringUtil::EqualNoCase(index_serial, entry.serial))
2067+
if (StringUtil::EqualNoCase(index_serial, it.serial))
20672068
{
20682069
// user might've deleted the file, so re-extract it if so
20692070
// otherwise, card hasn't changed, still no icon
2070-
if (entry.memcard_timestamp == timestamp && !entry.icon_was_extracted)
2071+
if (it.memcard_timestamp == timestamp && !it.icon_was_extracted)
20712072
return (ret = std::move(fallback_path));
20722073

2073-
serial_entry = &entry;
2074+
cache_entry = &it;
20742075
break;
20752076
}
20762077
}
20772078

2078-
if (!serial_entry)
2079+
if (!cache_entry)
20792080
{
2080-
serial_entry = &s_state.memcard_timestamp_cache_entries.emplace_back();
2081-
std::memset(serial_entry, 0, sizeof(MemcardTimestampCacheEntry));
2081+
cache_entry = &s_state.memcard_timestamp_cache_entries.emplace_back();
2082+
std::memset(cache_entry, 0, sizeof(MemcardTimestampCacheEntry));
20822083
}
20832084

2084-
serial_entry->memcard_timestamp = timestamp;
2085-
serial_entry->icon_was_extracted = false;
2086-
StringUtil::Strlcpy(serial_entry->serial, index_serial.view(), sizeof(serial_entry->serial));
2085+
cache_entry->memcard_timestamp = timestamp;
2086+
cache_entry->icon_was_extracted = false;
2087+
StringUtil::Strlcpy(cache_entry->serial, index_serial.view(), sizeof(cache_entry->serial));
20872088

20882089
// Try extracting an icon.
20892090
Error error;
@@ -2105,8 +2106,8 @@ std::string GameList::GetGameIconPath(std::string_view serial, std::string_view
21052106
for (size_t i = 0; i < fi.icon_frames.size(); i++)
21062107
image.SetPixels(static_cast<u32>(i), fi.icon_frames[i].pixels, MemoryCardImage::ICON_WIDTH * sizeof(u32));
21072108

2108-
serial_entry->icon_was_extracted = image.SaveToFile(ret.c_str(), AnimatedImage::DEFAULT_SAVE_QUALITY, &error);
2109-
if (serial_entry->icon_was_extracted)
2109+
cache_entry->icon_was_extracted = image.SaveToFile(ret.c_str(), AnimatedImage::DEFAULT_SAVE_QUALITY, &error);
2110+
if (cache_entry->icon_was_extracted)
21102111
return ret;
21112112
else
21122113
ERROR_LOG("Failed to save memory card icon to {}: {}", Path::GetFileName(ret), error.GetDescription());
@@ -2118,7 +2119,7 @@ std::string GameList::GetGameIconPath(std::string_view serial, std::string_view
21182119
ERROR_LOG("Failed to load memory card '{}': {}", Path::GetFileName(memcard_path), error.GetDescription());
21192120
}
21202121

2121-
UpdateMemcardTimestampCache(*serial_entry);
2122+
UpdateMemcardTimestampCache(*cache_entry);
21222123
return (ret = std::move(fallback_path));
21232124
}
21242125

src/core/game_list.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ struct Entry
7676
ALWAYS_INLINE bool IsValid() const { return (type < EntryType::MaxCount); }
7777
ALWAYS_INLINE bool IsDisc() const { return (type == EntryType::Disc); }
7878
ALWAYS_INLINE bool IsDiscSet() const { return (type == EntryType::DiscSet); }
79+
ALWAYS_INLINE bool IsDiscOrDiscSet() const { return (type == EntryType::Disc || type == EntryType::DiscSet); }
7980
ALWAYS_INLINE bool HasCustomLanguage() const { return (custom_language != GameDatabase::Language::MaxCount); }
8081
ALWAYS_INLINE EntryType GetSortType() const { return (type == EntryType::DiscSet) ? EntryType::Disc : type; }
8182
ALWAYS_INLINE const GameDatabase::DiscSetEntry* GetDiscSetEntry() const
@@ -170,7 +171,7 @@ std::optional<DiscRegion> GetCustomRegionForPath(const std::string_view path);
170171
/// The purpose of this cache is to stop us trying to constantly extract memory card icons, when we know a game
171172
/// doesn't have any saves yet. It caches the serial:memcard_timestamp pair, and only tries extraction when the
172173
/// timestamp of the memory card has changed.
173-
std::string GetGameIconPath(std::string_view serial, std::string_view path, u32 achievements_game_id);
174+
std::string GetGameIconPath(const GameList::Entry* entry);
174175
void ReloadMemcardTimestampCache();
175176

176177
/// Updates game list with new achievement unlocks.

src/core/system.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5761,8 +5761,8 @@ void System::DeleteSaveStates(std::string_view serial, bool resume)
57615761
}
57625762
}
57635763

5764-
std::string System::GetGameMemoryCardPath(std::string_view serial, std::string_view path, u32 slot,
5765-
MemoryCardType* out_type)
5764+
std::string System::GetGameMemoryCardPath(std::string_view title, bool is_custom_title, std::string_view serial,
5765+
std::string_view path, u32 slot, MemoryCardType* out_type /* = nullptr */)
57665766
{
57675767
const char* section = "MemoryCards";
57685768
const TinyString type_key = TinyString::from_format("Card{}Type", slot + 1);
@@ -5821,10 +5821,8 @@ std::string System::GetGameMemoryCardPath(std::string_view serial, std::string_v
58215821

58225822
case MemoryCardType::PerGameTitle:
58235823
{
5824-
const std::string custom_title = GameList::GetCustomTitleForPath(path);
58255824
const GameDatabase::Entry* entry = GameDatabase::GetEntryForSerial(serial);
5826-
const std::string_view game_title =
5827-
(!custom_title.empty() || !entry) ? std::string_view(custom_title) : entry->GetSaveTitle();
5825+
const std::string_view game_title = (is_custom_title || !entry) ? title : entry->GetSaveTitle();
58285826

58295827
// Multi-disc game - use disc set name.
58305828
if (entry && entry->disc_set)

src/core/system.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,8 @@ std::optional<ExtendedSaveStateInfo> GetExtendedSaveStateInfo(const char* path);
404404
void DeleteSaveStates(std::string_view serial, bool resume);
405405

406406
/// Returns the path to the memory card for the specified game, considering game settings.
407-
std::string GetGameMemoryCardPath(std::string_view serial, std::string_view path, u32 slot,
408-
MemoryCardType* out_type = nullptr);
407+
std::string GetGameMemoryCardPath(std::string_view title, bool is_custom_title, std::string_view serial,
408+
std::string_view path, u32 slot, MemoryCardType* out_type = nullptr);
409409

410410
/// Returns intended output volume considering fast forwarding.
411411
u8 GetAudioOutputVolume();

src/duckstation-qt/gamelistwidget.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ const QPixmap& GameListModel::getCoverForEntry(const GameList::Entry* ge) const
610610
const QPixmap* GameListModel::lookupIconPixmapForEntry(const GameList::Entry* ge) const
611611
{
612612
// We only do this for discs/disc sets for now.
613-
if (m_show_game_icons && (!ge->serial.empty() && (ge->IsDisc() || ge->IsDiscSet())))
613+
if (m_show_game_icons && !ge->serial.empty() && ge->IsDiscOrDiscSet())
614614
{
615615
QPixmap* item = m_icon_pixmap_cache.Lookup(ge->serial);
616616
if (item)
@@ -621,7 +621,7 @@ const QPixmap* GameListModel::lookupIconPixmapForEntry(const GameList::Entry* ge
621621
else
622622
{
623623
// Assumes game list lock is held.
624-
const std::string path = GameList::GetGameIconPath(ge->serial, ge->path, ge->achievements_game_id);
624+
const std::string path = GameList::GetGameIconPath(ge);
625625
QPixmap pm;
626626
if (!path.empty() && pm.load(QString::fromStdString(path)))
627627
{
@@ -682,7 +682,7 @@ QIcon GameListModel::getIconForGame(const QString& path)
682682

683683
const auto lock = GameList::GetLock();
684684
const GameList::Entry* entry = GameList::GetEntryForPath(path.toStdString());
685-
if (!entry || entry->serial.empty() || (!entry->IsDisc() && !entry->IsDiscSet()))
685+
if (!entry || entry->serial.empty() || !entry->IsDiscOrDiscSet())
686686
return ret;
687687

688688
// Only use the cache if we're not using larger icons. Otherwise they'll get double scaled.
@@ -697,7 +697,7 @@ QIcon GameListModel::getIconForGame(const QString& path)
697697
}
698698
}
699699

700-
const std::string icon_path = GameList::GetGameIconPath(entry->serial, entry->path, entry->achievements_game_id);
700+
const std::string icon_path = GameList::GetGameIconPath(entry);
701701
if (!icon_path.empty())
702702
ret = QIcon(QString::fromStdString(icon_path));
703703

@@ -1535,7 +1535,7 @@ class GameListAnimatedIconDelegate final : public QStyledItemDelegate
15351535
{
15361536
DebugAssert(source_row >= 0);
15371537

1538-
const std::string icon_path = GameList::GetGameIconPath(entry->serial, entry->path, entry->achievements_game_id);
1538+
const std::string icon_path = GameList::GetGameIconPath(entry);
15391539
if (icon_path.empty())
15401540
{
15411541
clearEntry();

src/duckstation-qt/mainwindow.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ void MainWindow::updateGameListRelatedActions()
531531
m_ui.actionViewZoomIn->setDisabled(disable);
532532
m_ui.actionViewZoomOut->setDisabled(disable);
533533
m_ui.actionGridViewRefreshCovers->setDisabled(disable || !game_grid);
534+
m_ui.actionPreferAchievementGameIcons->setDisabled(disable || !game_list);
534535
m_ui.actionChangeGameListBackground->setDisabled(disable);
535536
m_ui.actionClearGameListBackground->setDisabled(disable || !has_background);
536537
}
@@ -909,7 +910,10 @@ void MainWindow::populateGameListContextMenu(const GameList::Entry* entry, QWidg
909910

910911
QString paths[2];
911912
for (u32 i = 0; i < 2; i++)
912-
paths[i] = QString::fromStdString(System::GetGameMemoryCardPath(entry->serial, entry->path, i));
913+
{
914+
paths[i] = QString::fromStdString(
915+
System::GetGameMemoryCardPath(entry->title, entry->has_custom_title, entry->serial, entry->path, i));
916+
}
913917

914918
g_main_window->openMemoryCardEditor(paths[0], paths[1]);
915919
});

0 commit comments

Comments
 (0)