diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 328 |
1 files changed, 79 insertions, 249 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 33756febf..d8b0beadf 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -47,6 +47,7 @@ #include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/set/system_settings_server.h" +#include "frontend_common/content_manager.h" #include "hid_core/frontend/emulated_controller.h" #include "hid_core/hid_core.h" #include "yuzu/multiplayer/state.h" @@ -518,12 +519,21 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk continue; } + int user_arg_idx = ++i; bool argument_ok; - const std::size_t selected_user = args[++i].toUInt(&argument_ok); + std::size_t selected_user = args[user_arg_idx].toUInt(&argument_ok); if (!argument_ok) { - LOG_ERROR(Frontend, "Invalid user argument"); - continue; + // try to look it up by username, only finds the first username that matches. + const std::string user_arg_str = args[user_arg_idx].toStdString(); + const auto user_idx = system->GetProfileManager().GetUserIndex(user_arg_str); + + if (user_idx == std::nullopt) { + LOG_ERROR(Frontend, "Invalid user argument"); + continue; + } + + selected_user = user_idx.value(); } if (!system->GetProfileManager().UserExistsIndex(selected_user)) { @@ -532,6 +542,8 @@ GMainWindow::GMainWindow(std::unique_ptr<QtConfig> config_, bool has_broken_vulk } Settings::values.current_user = static_cast<s32>(selected_user); + + user_flag_cmd_line = true; continue; } @@ -1942,7 +1954,7 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t Settings::LogSettings(); - if (UISettings::values.select_user_on_boot) { + if (UISettings::values.select_user_on_boot && !user_flag_cmd_line) { const Core::Frontend::ProfileSelectParameters parameters{ .mode = Service::AM::Applets::UiMode::UserSelector, .invalid_uid_list = {}, @@ -1954,6 +1966,11 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t } } + // If the user specifies -u (successfully) on the cmd line, don't prompt for a user on first + // game startup only. If the user stops emulation and starts a new one, go back to the expected + // behavior of asking. + user_flag_cmd_line = false; + if (!LoadROM(filename, program_id, program_index, launch_type)) { return; } @@ -2460,10 +2477,8 @@ void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryT } void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { - const auto& fs_controller = system->GetFileSystemController(); - const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) || - fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id); - + const auto res = + ContentManager::RemoveBaseContent(system->GetFileSystemController(), program_id); if (res) { QMessageBox::information(this, tr("Successfully Removed"), tr("Successfully removed the installed base game.")); @@ -2475,11 +2490,7 @@ void GMainWindow::RemoveBaseContent(u64 program_id, InstalledEntryType type) { } void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { - const auto update_id = program_id | 0x800; - const auto& fs_controller = system->GetFileSystemController(); - const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) || - fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id); - + const auto res = ContentManager::RemoveUpdate(system->GetFileSystemController(), program_id); if (res) { QMessageBox::information(this, tr("Successfully Removed"), tr("Successfully removed the installed update.")); @@ -2490,22 +2501,7 @@ void GMainWindow::RemoveUpdateContent(u64 program_id, InstalledEntryType type) { } void GMainWindow::RemoveAddOnContent(u64 program_id, InstalledEntryType type) { - u32 count{}; - const auto& fs_controller = system->GetFileSystemController(); - const auto dlc_entries = system->GetContentProvider().ListEntriesFilter( - FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); - - for (const auto& entry : dlc_entries) { - if (FileSys::GetBaseTitleID(entry.title_id) == program_id) { - const auto res = - fs_controller.GetUserNANDContents()->RemoveExistingEntry(entry.title_id) || - fs_controller.GetSDMCContents()->RemoveExistingEntry(entry.title_id); - if (res) { - ++count; - } - } - } - + const size_t count = ContentManager::RemoveAllDLC(system.get(), program_id); if (count == 0) { QMessageBox::warning(this, GetGameListErrorRemoving(type), tr("There are no DLC installed for this title.")); @@ -2790,16 +2786,6 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { QMessageBox::warning(this, tr("Integrity verification couldn't be performed!"), tr("File contents were not checked for validity.")); }; - const auto Failed = [this] { - QMessageBox::critical(this, tr("Integrity verification failed!"), - tr("File contents may be corrupt.")); - }; - - const auto loader = Loader::GetLoader(*system, vfs->OpenFile(game_path, FileSys::Mode::Read)); - if (loader == nullptr) { - NotImplemented(); - return; - } QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); @@ -2807,30 +2793,26 @@ void GMainWindow::OnGameListVerifyIntegrity(const std::string& game_path) { progress.setAutoClose(false); progress.setAutoReset(false); - const auto QtProgressCallback = [&](size_t processed_size, size_t total_size) { - if (progress.wasCanceled()) { - return false; - } - + const auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { progress.setValue(static_cast<int>((processed_size * 100) / total_size)); - return true; + return progress.wasCanceled(); }; - const auto status = loader->VerifyIntegrity(QtProgressCallback); - if (progress.wasCanceled() || - status == Loader::ResultStatus::ErrorIntegrityVerificationNotImplemented) { + const auto result = + ContentManager::VerifyGameContents(system.get(), game_path, QtProgressCallback); + progress.close(); + switch (result) { + case ContentManager::GameVerificationResult::Success: + QMessageBox::information(this, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + break; + case ContentManager::GameVerificationResult::Failed: + QMessageBox::critical(this, tr("Integrity verification failed!"), + tr("File contents may be corrupt.")); + break; + case ContentManager::GameVerificationResult::NotImplemented: NotImplemented(); - return; } - - if (status == Loader::ResultStatus::ErrorIntegrityVerificationFailed) { - Failed(); - return; - } - - progress.close(); - QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); } void GMainWindow::OnGameListCopyTID(u64 program_id) { @@ -3274,12 +3256,21 @@ void GMainWindow::OnMenuInstallToNAND() { install_progress->setLabelText( tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName())); - QFuture<InstallResult> future; - InstallResult result; + QFuture<ContentManager::InstallResult> future; + ContentManager::InstallResult result; if (file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - - future = QtConcurrent::run([this, &file] { return InstallNSP(file); }); + const auto progress_callback = [this](size_t size, size_t progress) { + emit UpdateInstallProgress(); + if (install_progress->wasCanceled()) { + return true; + } + return false; + }; + future = QtConcurrent::run([this, &file, progress_callback] { + return ContentManager::InstallNSP(system.get(), vfs.get(), file.toStdString(), + progress_callback); + }); while (!future.isFinished()) { QCoreApplication::processEvents(); @@ -3295,16 +3286,16 @@ void GMainWindow::OnMenuInstallToNAND() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); switch (result) { - case InstallResult::Success: + case ContentManager::InstallResult::Success: new_files.append(QFileInfo(file).fileName()); break; - case InstallResult::Overwrite: + case ContentManager::InstallResult::Overwrite: overwritten_files.append(QFileInfo(file).fileName()); break; - case InstallResult::Failure: + case ContentManager::InstallResult::Failure: failed_files.append(QFileInfo(file).fileName()); break; - case InstallResult::BaseInstallAttempted: + case ContentManager::InstallResult::BaseInstallAttempted: failed_files.append(QFileInfo(file).fileName()); detected_base_install = true; break; @@ -3338,96 +3329,7 @@ void GMainWindow::OnMenuInstallToNAND() { ui->action_Install_File_NAND->setEnabled(true); } -InstallResult GMainWindow::InstallNSP(const QString& filename) { - const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, - const FileSys::VirtualFile& dest, std::size_t block_size) { - if (src == nullptr || dest == nullptr) { - return false; - } - if (!dest->Resize(src->GetSize())) { - return false; - } - - std::vector<u8> buffer(CopyBufferSize); - - for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { - if (install_progress->wasCanceled()) { - dest->Resize(0); - return false; - } - - emit UpdateInstallProgress(); - - const auto read = src->Read(buffer.data(), buffer.size(), i); - dest->Write(buffer.data(), read, i); - } - return true; - }; - - std::shared_ptr<FileSys::NSP> nsp; - if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - nsp = std::make_shared<FileSys::NSP>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - if (nsp->IsExtractedType()) { - return InstallResult::Failure; - } - } else { - return InstallResult::Failure; - } - - if (nsp->GetStatus() != Loader::ResultStatus::Success) { - return InstallResult::Failure; - } - const auto res = system->GetFileSystemController().GetUserNANDContents()->InstallEntry( - *nsp, true, qt_raw_copy); - switch (res) { - case FileSys::InstallResult::Success: - return InstallResult::Success; - case FileSys::InstallResult::OverwriteExisting: - return InstallResult::Overwrite; - case FileSys::InstallResult::ErrorBaseInstall: - return InstallResult::BaseInstallAttempted; - default: - return InstallResult::Failure; - } -} - -InstallResult GMainWindow::InstallNCA(const QString& filename) { - const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, - const FileSys::VirtualFile& dest, std::size_t block_size) { - if (src == nullptr || dest == nullptr) { - return false; - } - if (!dest->Resize(src->GetSize())) { - return false; - } - - std::vector<u8> buffer(CopyBufferSize); - - for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { - if (install_progress->wasCanceled()) { - dest->Resize(0); - return false; - } - - emit UpdateInstallProgress(); - - const auto read = src->Read(buffer.data(), buffer.size(), i); - dest->Write(buffer.data(), read, i); - } - return true; - }; - - const auto nca = - std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - const auto id = nca->GetStatus(); - - // Game updates necessary are missing base RomFS - if (id != Loader::ResultStatus::Success && - id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { - return InstallResult::Failure; - } - +ContentManager::InstallResult GMainWindow::InstallNCA(const QString& filename) { const QStringList tt_options{tr("System Application"), tr("System Archive"), tr("System Application Update"), @@ -3448,7 +3350,7 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) { if (!ok || index == -1) { QMessageBox::warning(this, tr("Failed to Install"), tr("The title type you selected for the NCA is invalid.")); - return InstallResult::Failure; + return ContentManager::InstallResult::Failure; } // If index is equal to or past Game, add the jump in TitleType. @@ -3462,15 +3364,15 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) { auto* registered_cache = is_application ? fs_controller.GetUserNANDContents() : fs_controller.GetSystemNANDContents(); - const auto res = registered_cache->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), - true, qt_raw_copy); - if (res == FileSys::InstallResult::Success) { - return InstallResult::Success; - } else if (res == FileSys::InstallResult::OverwriteExisting) { - return InstallResult::Overwrite; - } else { - return InstallResult::Failure; - } + const auto progress_callback = [this](size_t size, size_t progress) { + emit UpdateInstallProgress(); + if (install_progress->wasCanceled()) { + return true; + } + return false; + }; + return ContentManager::InstallNCA(vfs.get(), filename.toStdString(), registered_cache, + static_cast<FileSys::TitleType>(index), progress_callback); } void GMainWindow::OnMenuRecentFile() { @@ -4205,10 +4107,6 @@ void GMainWindow::OnOpenYuzuFolder() { } void GMainWindow::OnVerifyInstalledContents() { - // Declare sizes. - size_t total_size = 0; - size_t processed_size = 0; - // Initialize a progress dialog. QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this); progress.setWindowModality(Qt::WindowModal); @@ -4216,93 +4114,25 @@ void GMainWindow::OnVerifyInstalledContents() { progress.setAutoClose(false); progress.setAutoReset(false); - // Declare a list of file names which failed to verify. - std::vector<std::string> failed; - // Declare progress callback. - auto QtProgressCallback = [&](size_t nca_processed, size_t nca_total) { - if (progress.wasCanceled()) { - return false; - } - progress.setValue(static_cast<int>(((processed_size + nca_processed) * 100) / total_size)); - return true; + auto QtProgressCallback = [&](size_t total_size, size_t processed_size) { + progress.setValue(static_cast<int>((processed_size * 100) / total_size)); + return progress.wasCanceled(); }; - // Get content registries. - auto bis_contents = system->GetFileSystemController().GetSystemNANDContents(); - auto user_contents = system->GetFileSystemController().GetUserNANDContents(); - - std::vector<FileSys::RegisteredCache*> content_providers; - if (bis_contents) { - content_providers.push_back(bis_contents); - } - if (user_contents) { - content_providers.push_back(user_contents); - } - - // Get associated NCA files. - std::vector<FileSys::VirtualFile> nca_files; - - // Get all installed IDs. - for (auto nca_provider : content_providers) { - const auto entries = nca_provider->ListEntriesFilter(); - - for (const auto& entry : entries) { - auto nca_file = nca_provider->GetEntryRaw(entry.title_id, entry.type); - if (!nca_file) { - continue; - } - - total_size += nca_file->GetSize(); - nca_files.push_back(std::move(nca_file)); - } - } - - // Using the NCA loader, determine if all NCAs are valid. - for (auto& nca_file : nca_files) { - Loader::AppLoader_NCA nca_loader(nca_file); - - auto status = nca_loader.VerifyIntegrity(QtProgressCallback); - if (progress.wasCanceled()) { - break; - } - if (status != Loader::ResultStatus::Success) { - FileSys::NCA nca(nca_file); - const auto title_id = nca.GetTitleId(); - std::string title_name = "unknown"; - - const auto control = provider->GetEntry(FileSys::GetBaseTitleID(title_id), - FileSys::ContentRecordType::Control); - if (control && control->GetStatus() == Loader::ResultStatus::Success) { - const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), - *provider}; - const auto [nacp, logo] = pm.ParseControlNCA(*control); - if (nacp) { - title_name = nacp->GetApplicationName(); - } - } - - if (title_id > 0) { - failed.push_back( - fmt::format("{} ({:016X}) ({})", nca_file->GetName(), title_id, title_name)); - } else { - failed.push_back(fmt::format("{} (unknown)", nca_file->GetName())); - } - } - - processed_size += nca_file->GetSize(); - } - + const std::vector<std::string> result = + ContentManager::VerifyInstalledContents(system.get(), provider.get(), QtProgressCallback); progress.close(); - if (failed.size() > 0) { - auto failed_names = QString::fromStdString(fmt::format("{}", fmt::join(failed, "\n"))); + if (result.empty()) { + QMessageBox::information(this, tr("Integrity verification succeeded!"), + tr("The operation completed successfully.")); + } else { + const auto failed_names = + QString::fromStdString(fmt::format("{}", fmt::join(result, "\n"))); QMessageBox::critical( this, tr("Integrity verification failed!"), tr("Verification failed for the following files:\n\n%1").arg(failed_names)); - } else { - QMessageBox::information(this, tr("Integrity verification succeeded!"), - tr("The operation completed successfully.")); } } |