From b90e9ed7be8171f4019cb41493f3b1048c37d3f4 Mon Sep 17 00:00:00 2001 From: swurl Date: Wed, 28 May 2025 00:43:11 -0400 Subject: [PATCH] fix add-on loading during startup & refresh Adds an option to PopulateAsync etc. that lets the caller bypass the cache functions. This fixes the ridiculously annoying behavior whereby add-ons would never update during refresh or even on program startup. Signed-off-by: swurl --- src/yuzu/game_list.cpp | 23 ++++++++-- src/yuzu/game_list.h | 3 +- src/yuzu/game_list_worker.cpp | 81 ++++++++++++++++++++++++++--------- src/yuzu/game_list_worker.h | 8 +++- src/yuzu/main.cpp | 6 ++- 5 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 3788249d93..3fec5b7f61 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -854,7 +854,8 @@ QStandardItemModel* GameList::GetModel() const { return item_model; } -void GameList::PopulateAsync(QVector& game_dirs) { +void GameList::PopulateAsync(QVector& game_dirs, const bool cached) +{ tree_view->setEnabled(false); // Update the columns in case UISettings has changed @@ -871,8 +872,13 @@ void GameList::PopulateAsync(QVector& game_dirs) { item_model->removeRows(0, item_model->rowCount()); search_field->clear(); - current_worker = std::make_unique(vfs, provider, game_dirs, compatibility_list, - play_time_manager, system); + current_worker = std::make_unique(vfs, + provider, + game_dirs, + compatibility_list, + play_time_manager, + system, + cached); // Get events from the worker as data becomes available connect(current_worker.get(), &GameListWorker::DataAvailable, this, &GameList::WorkerEvent, @@ -901,7 +907,16 @@ const QStringList GameList::supported_file_extensions = { QStringLiteral("nso"), QStringLiteral("nro"), QStringLiteral("nca"), QStringLiteral("xci"), QStringLiteral("nsp"), QStringLiteral("kip")}; -void GameList::RefreshGameDirectory() { +void GameList::ForceRefreshGameDirectory() +{ + if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { + LOG_INFO(Frontend, "Force-reloading game list per user request."); + PopulateAsync(UISettings::values.game_dirs, false); + } +} + +void GameList::RefreshGameDirectory() +{ if (!UISettings::values.game_dirs.empty() && current_worker != nullptr) { LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); PopulateAsync(UISettings::values.game_dirs); diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 6ca50fac2d..778333dd87 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -94,7 +94,7 @@ public: bool IsEmpty() const; void LoadCompatibilityList(); - void PopulateAsync(QVector& game_dirs); + void PopulateAsync(QVector& game_dirs, const bool cached = true); void SaveInterfaceLayout(); void LoadInterfaceLayout(); @@ -107,6 +107,7 @@ public: static const QStringList supported_file_extensions; public slots: + void ForceRefreshGameDirectory(); void RefreshGameDirectory(); signals: diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp index 4f977b87be..60109769bf 100644 --- a/src/yuzu/game_list_worker.cpp +++ b/src/yuzu/game_list_worker.cpp @@ -191,12 +191,17 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager, return out; } -QList MakeGameListEntry(const std::string& path, const std::string& name, - const std::size_t size, const std::vector& icon, - Loader::AppLoader& loader, u64 program_id, +QList MakeGameListEntry(const std::string& path, + const std::string& name, + const std::size_t size, + const std::vector& icon, + Loader::AppLoader& loader, + u64 program_id, const CompatibilityList& compatibility_list, const PlayTime::PlayTimeManager& play_time_manager, - const FileSys::PatchManager& patch) { + const FileSys::PatchManager& patch, + const bool cached) +{ const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); // The game list uses this as compatibility number for untested games @@ -217,10 +222,17 @@ QList MakeGameListEntry(const std::string& path, const std::stri new GameListItemPlayTime(play_time_manager.GetPlayTime(program_id)), }; - const auto patch_versions = GetGameListCachedObject( - fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { - return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); - }); + QString patch_versions; + + if (cached) { + patch_versions = GetGameListCachedObject( + fmt::format("{:016X}", patch.GetTitleID()), "pv.txt", [&patch, &loader] { + return FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); + }); + } else { + patch_versions = FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable()); + } + list.insert(2, new GameListItem(patch_versions)); return list; @@ -232,10 +244,16 @@ GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_, QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_) - : vfs{std::move(vfs_)}, provider{provider_}, game_dirs{game_dirs_}, - compatibility_list{compatibility_list_}, play_time_manager{play_time_manager_}, system{ - system_} { + Core::System& system_, + const bool cached_) + : vfs{std::move(vfs_)} + , provider{provider_} + , game_dirs{game_dirs_} + , compatibility_list{compatibility_list_} + , play_time_manager{play_time_manager_} + , system{system_} + , cached{cached_} +{ // We want the game list to manage our lifetime. setAutoDelete(false); } @@ -323,13 +341,22 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { const PatchManager patch{program_id, system.GetFileSystemController(), system.GetContentProvider()}; + LOG_INFO(Frontend, "PatchManager initiated for id {:X}", program_id); const auto control = cache.GetEntry(game.title_id, ContentRecordType::Control); if (control != nullptr) { GetMetadataFromControlNCA(patch, *control, icon, name); } - auto entry = MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader, - program_id, compatibility_list, play_time_manager, patch); + auto entry = MakeGameListEntry(file->GetFullPath(), + name, + file->GetSize(), + icon, + *loader, + program_id, + compatibility_list, + play_time_manager, + patch, + cached); RecordEvent([=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); } } @@ -404,9 +431,16 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa const FileSys::PatchManager patch{id, system.GetFileSystemController(), system.GetContentProvider()}; - auto entry = MakeGameListEntry( - physical_name, name, Common::FS::GetSize(physical_name), icon, *loader, - id, compatibility_list, play_time_manager, patch); + auto entry = MakeGameListEntry(physical_name, + name, + Common::FS::GetSize(physical_name), + icon, + *loader, + id, + compatibility_list, + play_time_manager, + patch, + cached); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); @@ -421,9 +455,16 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), system.GetContentProvider()}; - auto entry = MakeGameListEntry( - physical_name, name, Common::FS::GetSize(physical_name), icon, *loader, - program_id, compatibility_list, play_time_manager, patch); + auto entry = MakeGameListEntry(physical_name, + name, + Common::FS::GetSize(physical_name), + icon, + *loader, + program_id, + compatibility_list, + play_time_manager, + patch, + cached); RecordEvent( [=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); diff --git a/src/yuzu/game_list_worker.h b/src/yuzu/game_list_worker.h index d5990fcde8..0afd7c7849 100644 --- a/src/yuzu/game_list_worker.h +++ b/src/yuzu/game_list_worker.h @@ -14,6 +14,8 @@ #include #include "common/thread.h" +#include "core/file_sys/registered_cache.h" +#include "uisettings.h" #include "yuzu/compatibility_list.h" #include "yuzu/play_time_manager.h" @@ -22,6 +24,7 @@ class System; } class GameList; +class GameListDir; class QStandardItem; namespace FileSys { @@ -42,7 +45,8 @@ public: QVector& game_dirs_, const CompatibilityList& compatibility_list_, const PlayTime::PlayTimeManager& play_time_manager_, - Core::System& system_); + Core::System& system_, + const bool cached = true); ~GameListWorker() override; /// Starts the processing of directory tree information. @@ -91,4 +95,6 @@ private: Common::Event processing_completed; Core::System& system; + + const bool cached; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index d7aac5e503..bb588f9db1 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -448,7 +448,8 @@ GMainWindow::GMainWindow(bool has_broken_vulkan) OnCheckFirmwareDecryption(); game_list->LoadCompatibilityList(); - game_list->PopulateAsync(UISettings::values.game_dirs); + // force reload on first load to ensure add-ons get updated + game_list->PopulateAsync(UISettings::values.game_dirs, false); // make sure menubar has the arrow cursor instead of inheriting from this ui->menubar->setCursor(QCursor()); @@ -4493,7 +4494,8 @@ void GMainWindow::OnToggleStatusBar() { void GMainWindow::OnGameListRefresh() { - game_list->RefreshGameDirectory(); + // force reload add-ons etc + game_list->ForceRefreshGameDirectory(); } void GMainWindow::OnAlbum() {