|
|
@ -233,10 +233,53 @@ GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs_, |
|
|
const PlayTime::PlayTimeManager& play_time_manager_, |
|
|
const PlayTime::PlayTimeManager& play_time_manager_, |
|
|
Core::System& system_) |
|
|
Core::System& system_) |
|
|
: vfs{std::move(vfs_)}, provider{provider_}, game_dirs{game_dirs_}, |
|
|
: vfs{std::move(vfs_)}, provider{provider_}, game_dirs{game_dirs_}, |
|
|
compatibility_list{compatibility_list_}, |
|
|
|
|
|
play_time_manager{play_time_manager_}, system{system_} {} |
|
|
|
|
|
|
|
|
compatibility_list{compatibility_list_}, play_time_manager{play_time_manager_}, system{ |
|
|
|
|
|
system_} { |
|
|
|
|
|
// We want the game list to manage our lifetime.
|
|
|
|
|
|
setAutoDelete(false); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
GameListWorker::~GameListWorker() { |
|
|
|
|
|
this->disconnect(); |
|
|
|
|
|
stop_requested.store(true); |
|
|
|
|
|
processing_completed.Wait(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void GameListWorker::ProcessEvents(GameList* game_list) { |
|
|
|
|
|
while (true) { |
|
|
|
|
|
std::function<void(GameList*)> func; |
|
|
|
|
|
{ |
|
|
|
|
|
// Lock queue to protect concurrent modification.
|
|
|
|
|
|
std::scoped_lock lk(lock); |
|
|
|
|
|
|
|
|
|
|
|
// If we can't pop a function, return.
|
|
|
|
|
|
if (queued_events.empty()) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Pop a function.
|
|
|
|
|
|
func = std::move(queued_events.back()); |
|
|
|
|
|
queued_events.pop_back(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Run the function.
|
|
|
|
|
|
func(game_list); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
template <typename F> |
|
|
|
|
|
void GameListWorker::RecordEvent(F&& func) { |
|
|
|
|
|
{ |
|
|
|
|
|
// Lock queue to protect concurrent modification.
|
|
|
|
|
|
std::scoped_lock lk(lock); |
|
|
|
|
|
|
|
|
GameListWorker::~GameListWorker() = default; |
|
|
|
|
|
|
|
|
// Add the function into the front of the queue.
|
|
|
|
|
|
queued_events.emplace_front(std::move(func)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Data now available.
|
|
|
|
|
|
emit DataAvailable(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { |
|
|
void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { |
|
|
using namespace FileSys; |
|
|
using namespace FileSys; |
|
|
@ -284,9 +327,9 @@ void GameListWorker::AddTitlesToGameList(GameListDir* parent_dir) { |
|
|
GetMetadataFromControlNCA(patch, *control, icon, name); |
|
|
GetMetadataFromControlNCA(patch, *control, icon, name); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader, |
|
|
|
|
|
program_id, compatibility_list, play_time_manager, patch), |
|
|
|
|
|
parent_dir); |
|
|
|
|
|
|
|
|
auto entry = MakeGameListEntry(file->GetFullPath(), name, file->GetSize(), icon, *loader, |
|
|
|
|
|
program_id, compatibility_list, play_time_manager, patch); |
|
|
|
|
|
RecordEvent([=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -360,11 +403,12 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa |
|
|
const FileSys::PatchManager patch{id, system.GetFileSystemController(), |
|
|
const FileSys::PatchManager patch{id, system.GetFileSystemController(), |
|
|
system.GetContentProvider()}; |
|
|
system.GetContentProvider()}; |
|
|
|
|
|
|
|
|
emit EntryReady(MakeGameListEntry(physical_name, name, |
|
|
|
|
|
Common::FS::GetSize(physical_name), icon, |
|
|
|
|
|
*loader, id, compatibility_list, |
|
|
|
|
|
play_time_manager, patch), |
|
|
|
|
|
parent_dir); |
|
|
|
|
|
|
|
|
auto entry = MakeGameListEntry( |
|
|
|
|
|
physical_name, name, Common::FS::GetSize(physical_name), icon, *loader, |
|
|
|
|
|
id, compatibility_list, play_time_manager, patch); |
|
|
|
|
|
|
|
|
|
|
|
RecordEvent( |
|
|
|
|
|
[=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
std::vector<u8> icon; |
|
|
std::vector<u8> icon; |
|
|
@ -376,11 +420,12 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa |
|
|
const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), |
|
|
const FileSys::PatchManager patch{program_id, system.GetFileSystemController(), |
|
|
system.GetContentProvider()}; |
|
|
system.GetContentProvider()}; |
|
|
|
|
|
|
|
|
emit EntryReady(MakeGameListEntry(physical_name, name, |
|
|
|
|
|
Common::FS::GetSize(physical_name), icon, |
|
|
|
|
|
*loader, program_id, compatibility_list, |
|
|
|
|
|
play_time_manager, patch), |
|
|
|
|
|
parent_dir); |
|
|
|
|
|
|
|
|
auto entry = MakeGameListEntry( |
|
|
|
|
|
physical_name, name, Common::FS::GetSize(physical_name), icon, *loader, |
|
|
|
|
|
program_id, compatibility_list, play_time_manager, patch); |
|
|
|
|
|
|
|
|
|
|
|
RecordEvent( |
|
|
|
|
|
[=](GameList* game_list) { game_list->AddEntry(entry, parent_dir); }); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else if (is_dir) { |
|
|
} else if (is_dir) { |
|
|
@ -399,25 +444,34 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void GameListWorker::run() { |
|
|
void GameListWorker::run() { |
|
|
|
|
|
watch_list.clear(); |
|
|
provider->ClearAllEntries(); |
|
|
provider->ClearAllEntries(); |
|
|
|
|
|
|
|
|
|
|
|
const auto DirEntryReady = [&](GameListDir* game_list_dir) { |
|
|
|
|
|
RecordEvent([=](GameList* game_list) { game_list->AddDirEntry(game_list_dir); }); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
for (UISettings::GameDir& game_dir : game_dirs) { |
|
|
for (UISettings::GameDir& game_dir : game_dirs) { |
|
|
|
|
|
if (stop_requested) { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (game_dir.path == QStringLiteral("SDMC")) { |
|
|
if (game_dir.path == QStringLiteral("SDMC")) { |
|
|
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); |
|
|
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SdmcDir); |
|
|
emit DirEntryReady(game_list_dir); |
|
|
|
|
|
|
|
|
DirEntryReady(game_list_dir); |
|
|
AddTitlesToGameList(game_list_dir); |
|
|
AddTitlesToGameList(game_list_dir); |
|
|
} else if (game_dir.path == QStringLiteral("UserNAND")) { |
|
|
} else if (game_dir.path == QStringLiteral("UserNAND")) { |
|
|
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); |
|
|
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::UserNandDir); |
|
|
emit DirEntryReady(game_list_dir); |
|
|
|
|
|
|
|
|
DirEntryReady(game_list_dir); |
|
|
AddTitlesToGameList(game_list_dir); |
|
|
AddTitlesToGameList(game_list_dir); |
|
|
} else if (game_dir.path == QStringLiteral("SysNAND")) { |
|
|
} else if (game_dir.path == QStringLiteral("SysNAND")) { |
|
|
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); |
|
|
auto* const game_list_dir = new GameListDir(game_dir, GameListItemType::SysNandDir); |
|
|
emit DirEntryReady(game_list_dir); |
|
|
|
|
|
|
|
|
DirEntryReady(game_list_dir); |
|
|
AddTitlesToGameList(game_list_dir); |
|
|
AddTitlesToGameList(game_list_dir); |
|
|
} else { |
|
|
} else { |
|
|
watch_list.append(game_dir.path); |
|
|
watch_list.append(game_dir.path); |
|
|
auto* const game_list_dir = new GameListDir(game_dir); |
|
|
auto* const game_list_dir = new GameListDir(game_dir); |
|
|
emit DirEntryReady(game_list_dir); |
|
|
|
|
|
|
|
|
DirEntryReady(game_list_dir); |
|
|
ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), |
|
|
ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), |
|
|
game_dir.deep_scan, game_list_dir); |
|
|
game_dir.deep_scan, game_list_dir); |
|
|
ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), |
|
|
ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), |
|
|
@ -425,12 +479,6 @@ void GameListWorker::run() { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
emit Finished(watch_list); |
|
|
|
|
|
|
|
|
RecordEvent([=](GameList* game_list) { game_list->DonePopulating(watch_list); }); |
|
|
processing_completed.Set(); |
|
|
processing_completed.Set(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void GameListWorker::Cancel() { |
|
|
|
|
|
this->disconnect(); |
|
|
|
|
|
stop_requested.store(true); |
|
|
|
|
|
processing_completed.Wait(); |
|
|
|
|
|
} |
|
|
|