mirror of
https://github.com/stenzek/duckstation.git
synced 2026-07-11 01:24:11 +02:00
Achievements: Swap to sqlite-backed storage
This commit is contained in:
+794
-865
File diff suppressed because it is too large
Load Diff
+12
-15
@@ -33,19 +33,13 @@ enum class LoginRequestReason
|
||||
inline constexpr size_t GAME_HASH_LENGTH = 16;
|
||||
using GameHash = std::array<u8, GAME_HASH_LENGTH>;
|
||||
|
||||
struct HashDatabaseEntry
|
||||
{
|
||||
GameHash hash;
|
||||
u32 game_id;
|
||||
u32 num_achievements;
|
||||
};
|
||||
|
||||
class ProgressDatabase
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
{
|
||||
u32 game_id;
|
||||
u16 num_achievements;
|
||||
u16 num_achievements_unlocked;
|
||||
u16 num_hc_achievements_unlocked;
|
||||
};
|
||||
@@ -55,9 +49,16 @@ public:
|
||||
|
||||
bool Load(Error* error);
|
||||
|
||||
const Entry* LookupGame(u32 game_id) const;
|
||||
const Entry* LookupHash(const GameHash& hash) const;
|
||||
|
||||
private:
|
||||
struct HashEntry
|
||||
{
|
||||
GameHash hash;
|
||||
u32 game_id;
|
||||
};
|
||||
|
||||
std::vector<HashEntry> m_hashes;
|
||||
std::vector<Entry> m_entries;
|
||||
};
|
||||
|
||||
@@ -68,15 +69,15 @@ std::unique_lock<std::recursive_mutex> GetLock();
|
||||
std::optional<GameHash> GetGameHash(CDImage* image);
|
||||
std::optional<GameHash> GetGameHash(const std::string_view executable_name, std::span<const u8> executable_data);
|
||||
|
||||
/// Returns the number of achievements for a given hash.
|
||||
const HashDatabaseEntry* LookupGameHash(const GameHash& hash);
|
||||
|
||||
/// Converts a game hash to a string for display. If the hash is nullopt, returns "[NO HASH]".
|
||||
TinyString GameHashToString(const std::optional<GameHash>& hash);
|
||||
|
||||
/// Updates achievements settings.
|
||||
void UpdateSettings(const Settings& old_config);
|
||||
|
||||
/// Call to refresh the game database.
|
||||
bool RefreshGameList(ProgressCallback* progress, Error* error);
|
||||
|
||||
/// Call to refresh the all-progress database.
|
||||
bool RefreshAllProgressDatabase(ProgressCallback* progress, Error* error);
|
||||
|
||||
@@ -179,10 +180,6 @@ SmallString GetLoggedInUserPointsSummary();
|
||||
/// Returns the URL for the specified game icon, using the game ID.
|
||||
std::string GetGameBadgeURL(u32 game_id);
|
||||
|
||||
/// Downloads game icons from RetroAchievements for all games that have an achievements_game_id.
|
||||
/// This fetches the game badge images that are normally downloaded when a game is opened.
|
||||
bool DownloadGameIcons(ProgressCallback* progress, Error* error);
|
||||
|
||||
/// Returns 0 if pausing is allowed, otherwise the number of frames until pausing is allowed.
|
||||
u32 GetPauseThrottleFrames();
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ static void DrawCoverDownloaderWindow();
|
||||
static void SaveCoverDownloaderURLs();
|
||||
static void DrawAchievementsLoginWindow();
|
||||
static void StartAchievementsProgressRefresh();
|
||||
static void StartAchievementsGameIconDownload();
|
||||
static void ClearWebCache();
|
||||
|
||||
static bool ShouldShowAdvancedSettings();
|
||||
@@ -5278,12 +5277,6 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
|
||||
StartAchievementsProgressRefresh();
|
||||
}
|
||||
|
||||
if (MenuButton(FSUI_ICONVSTR(ICON_FA_DOWNLOAD, "Download Game Icons"),
|
||||
FSUI_VSTR("Downloads icons for all games from RetroAchievements."), enabled))
|
||||
{
|
||||
StartAchievementsGameIconDownload();
|
||||
}
|
||||
|
||||
if (MenuButton(FSUI_ICONVSTR(ICON_FA_TRASH, "Clear Web Cache"),
|
||||
FSUI_VSTR("Clears all cached images in the web cache."), enabled))
|
||||
{
|
||||
@@ -5456,30 +5449,6 @@ void FullscreenUI::StartAchievementsProgressRefresh()
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::StartAchievementsGameIconDownload()
|
||||
{
|
||||
auto progress = OpenModalProgressDialog(FSUI_STR("Download Game Icons"));
|
||||
|
||||
Host::QueueAsyncTask([progress = progress.release()]() {
|
||||
Error error;
|
||||
const bool result = Achievements::DownloadGameIcons(progress, &error);
|
||||
Host::RunOnCoreThread([error = std::move(error), progress, result]() mutable {
|
||||
VideoThread::RunOnThread([error = std::move(error), progress, result]() mutable {
|
||||
delete progress;
|
||||
if (result)
|
||||
{
|
||||
ShowToast(OSDMessageType::Info, {}, FSUI_STR("Game icons downloaded."));
|
||||
}
|
||||
else
|
||||
{
|
||||
FullscreenUI::OpenInfoMessageDialog(ICON_EMOJI_NO_ENTRY_SIGN, FSUI_STR("Download Game Icons"),
|
||||
error.TakeDescription());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void FullscreenUI::ClearWebCache()
|
||||
{
|
||||
Error error;
|
||||
|
||||
+8
-20
@@ -847,23 +847,14 @@ void GameList::SetCustomSerialOnEntry(Entry* entry, std::string serial, bool upd
|
||||
|
||||
void GameList::PopulateEntryAchievements(Entry* entry, const Achievements::ProgressDatabase& achievements_progress)
|
||||
{
|
||||
const Achievements::HashDatabaseEntry* hentry = Achievements::LookupGameHash(entry->achievements_hash);
|
||||
if (!hentry)
|
||||
const Achievements::ProgressDatabase::Entry* aentry = achievements_progress.LookupHash(entry->achievements_hash);
|
||||
if (!aentry)
|
||||
return;
|
||||
|
||||
entry->achievements_game_id = hentry->game_id;
|
||||
entry->num_achievements = Truncate16(hentry->num_achievements);
|
||||
entry->unlocked_achievements = 0;
|
||||
entry->unlocked_achievements_hc = 0;
|
||||
if (entry->num_achievements > 0)
|
||||
{
|
||||
const Achievements::ProgressDatabase::Entry* apd_entry = achievements_progress.LookupGame(hentry->game_id);
|
||||
if (apd_entry)
|
||||
{
|
||||
entry->unlocked_achievements = apd_entry->num_achievements_unlocked;
|
||||
entry->unlocked_achievements_hc = apd_entry->num_hc_achievements_unlocked;
|
||||
}
|
||||
}
|
||||
entry->achievements_game_id = aentry->game_id;
|
||||
entry->num_achievements = Truncate16(aentry->num_achievements);
|
||||
entry->unlocked_achievements = aentry->num_achievements_unlocked;
|
||||
entry->unlocked_achievements_hc = aentry->num_hc_achievements_unlocked;
|
||||
}
|
||||
|
||||
void GameList::UpdateAchievementData(std::span<const u8, 16> hash, u32 game_id, u32 num_achievements, u32 num_unlocked,
|
||||
@@ -1119,11 +1110,8 @@ void GameList::Refresh(bool invalidate_cache, bool only_cache, ProgressCallback*
|
||||
custom_attributes_ini.Load();
|
||||
|
||||
Achievements::ProgressDatabase achievements_progress;
|
||||
if (Achievements::HasSavedCredentials())
|
||||
{
|
||||
if (!achievements_progress.Load(&error))
|
||||
WARNING_LOG("Failed to load achievements progress: {}", error.GetDescription());
|
||||
}
|
||||
if (!achievements_progress.Load(&error))
|
||||
WARNING_LOG("Failed to load achievements progress: {}", error.GetDescription());
|
||||
|
||||
#ifdef __ANDROID__
|
||||
recursive_dirs.push_back(Path::Combine(EmuFolders::DataRoot, "games"));
|
||||
|
||||
@@ -2577,8 +2577,6 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.actionISOBrowser, &QAction::triggered, this, &MainWindow::onToolsISOBrowserTriggered);
|
||||
connect(m_ui.actionControllerTest, &QAction::triggered, g_core_thread, &CoreThread::startControllerTest);
|
||||
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||
connect(m_ui.actionToolsDownloadAchievementGameIcons, &QAction::triggered, this,
|
||||
&MainWindow::onToolsDownloadAchievementGameIconsTriggered);
|
||||
connect(m_ui.actionToolsRefreshAchievementProgress, &QAction::triggered, g_main_window,
|
||||
&MainWindow::refreshAchievementProgress);
|
||||
connect(m_ui.actionMediaCapture, &QAction::triggered, this, &MainWindow::onToolsMediaCaptureTriggered);
|
||||
@@ -3287,7 +3285,6 @@ void MainWindow::onAchievementsLoginSuccess(const QString& username, quint32 poi
|
||||
void MainWindow::onAchievementsActiveChanged(bool active)
|
||||
{
|
||||
m_ui.actionToolsRefreshAchievementProgress->setEnabled(active);
|
||||
m_ui.actionToolsDownloadAchievementGameIcons->setEnabled(active);
|
||||
}
|
||||
|
||||
void MainWindow::onAchievementsHardcoreModeChanged(bool enabled)
|
||||
@@ -3358,23 +3355,6 @@ void MainWindow::onToolsCoverDownloaderTriggered()
|
||||
QtUtils::ShowOrRaiseWindow(m_cover_download_window, this, true);
|
||||
}
|
||||
|
||||
void MainWindow::onToolsDownloadAchievementGameIconsTriggered()
|
||||
{
|
||||
QtAsyncTaskWithProgressDialog::create(
|
||||
this, TRANSLATE_STR("GameListWidget", "Download Game Icons"),
|
||||
TRANSLATE_STR("GameListWidget", "Downloading game icons..."), false, true, 0, 0, 0.0f, true,
|
||||
[](ProgressCallback* progress) {
|
||||
Error error;
|
||||
const bool result = Achievements::DownloadGameIcons(progress, &error);
|
||||
return [error = std::move(error), result]() {
|
||||
if (!result)
|
||||
g_main_window->reportError(tr("Error"), QString::fromStdString(error.GetDescription()));
|
||||
|
||||
g_main_window->m_game_list_widget->getModel()->invalidateColumn(GameListModel::Column_Icon);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
void MainWindow::refreshAchievementProgress()
|
||||
{
|
||||
QtAsyncTaskWithProgressDialog::create(
|
||||
|
||||
@@ -301,7 +301,6 @@ private:
|
||||
void onToolsMemoryScannerTriggered();
|
||||
void onToolsISOBrowserTriggered();
|
||||
void onToolsCoverDownloaderTriggered();
|
||||
void onToolsDownloadAchievementGameIconsTriggered();
|
||||
void onToolsMediaCaptureTriggered(bool checked);
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
void onToolsOpenTextureDirectoryTriggered();
|
||||
|
||||
@@ -259,7 +259,6 @@
|
||||
<addaction name="actionCoverDownloader"/>
|
||||
<addaction name="actionControllerTest"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionToolsDownloadAchievementGameIcons"/>
|
||||
<addaction name="actionToolsRefreshAchievementProgress"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMemoryEditor"/>
|
||||
@@ -1521,21 +1520,6 @@
|
||||
<string>Prioritizes the games badges used for RetroAchievements over memory card icons.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToolsDownloadAchievementGameIcons">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources/duckstation-qt.qrc">
|
||||
<normaloff>:/icons/monochrome/svg/download-2-line.svg</normaloff>:/icons/monochrome/svg/download-2-line.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Download Achievement &Icons</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Downloads icons for all games from RetroAchievements.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewSystemLog">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
Reference in New Issue
Block a user